@vitex/nook 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,249 @@
1
- # Temporary Holding Version
1
+ # Nook
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ 给 Pi coding agent 用的轻量 Web 界面。前端 Vue 3 + Vite,后端 Node。
4
+
5
+ ## 结构
6
+
7
+ ```text
8
+ src/frontend/ Vue 3 + Vite 前端
9
+ src/backend/ Node 后端、Pi SDK、CLI、launchd 服务
10
+ bin/nook.js CLI 入口
11
+ scripts/build.js 构建脚本
12
+ dist/ build 产物
13
+ ```
14
+
15
+ 前后端各自有独立的 `package.json`,可以单独启动、单独维护。
16
+
17
+ ## 安装
18
+
19
+ ```bash
20
+ npm install
21
+ ```
22
+
23
+ ## 开发
24
+
25
+ 前后端分开启动:
26
+
27
+ ```bash
28
+ # 终端 A:后端 API
29
+ npm run dev:backend
30
+
31
+ # 终端 B:前端 Vite
32
+ npm run dev:frontend
33
+ ```
34
+
35
+ 默认地址:
36
+
37
+ - 后端:`http://127.0.0.1:4317`
38
+ - 前端:`http://localhost:5173`(5173 被占用时会自动用 5174)
39
+ - Vite 会把 `/api` 代理到后端
40
+
41
+ 也可以直接进入各自目录:
42
+
43
+ ```bash
44
+ cd src/backend && npm run dev
45
+ cd src/frontend && npm run dev
46
+ ```
47
+
48
+ 如果后台服务已经占用了 4317:
49
+
50
+ ```bash
51
+ nook service stop
52
+ ```
53
+
54
+ 或者换端口启动:
55
+
56
+ ```bash
57
+ NOOK_PORT=4320 npm run dev:backend
58
+ NOOK_BACKEND=http://127.0.0.1:4320 npm run dev:frontend
59
+ ```
60
+
61
+ 只想单独启动前端、后端直接用正在运行的服务时:
62
+
63
+ ```bash
64
+ NOOK_BACKEND=http://100.x.x.x:4317 npm run dev:frontend
65
+ ```
66
+
67
+ 地址可以用 `nook status` 查看。
68
+
69
+ 从其他设备预览 Vite 时,用终端里打印的 Network 地址,例如 `http://192.168.x.x:5173`。
70
+
71
+ ## 构建
72
+
73
+ ```bash
74
+ npm run build
75
+ ```
76
+
77
+ 产物:
78
+
79
+ ```text
80
+ dist/frontend/ 构建后的前端
81
+ dist/backend/ 后端副本
82
+ dist/nook 最终可执行命令
83
+ ```
84
+
85
+ 运行构建后的版本:
86
+
87
+ ```bash
88
+ ./dist/nook start --host 127.0.0.1 --port 4317
89
+ ```
90
+
91
+ 也可以用它管理后台服务:
92
+
93
+ ```bash
94
+ ./dist/nook service install
95
+ ./dist/nook service status
96
+ ./dist/nook service restart
97
+ ```
98
+
99
+ ## 访问方式
100
+
101
+ Nook 只按传入的 `host` / `port` 监听,不依赖任何特定网络服务。
102
+
103
+ ```bash
104
+ nook start --host 127.0.0.1 --port 4317 # 只本机
105
+ nook start --host 0.0.0.0 --port 4317 # 所有网卡
106
+ nook start --host 192.168.1.10 --port 4317 # 指定网卡 IP
107
+ ```
108
+
109
+ `nook status` 会给出一个访问地址。页面本身没有登录,请只在可信网络里使用。
110
+
111
+ 后台服务同样接受这两个参数:
112
+
113
+ ```bash
114
+ nook service install --host 0.0.0.0 --port 4317
115
+ ```
116
+
117
+ ## CLI
118
+
119
+ ```bash
120
+ nook start 前台启动
121
+ nook status 查看运行状态
122
+ nook service install 安装并启动后台服务
123
+ nook service uninstall 卸载后台服务
124
+ nook service start 启动后台服务
125
+ nook service stop 停止后台服务
126
+ nook service restart 重启后台服务
127
+ nook service status 查看后台服务状态
128
+ nook help
129
+ ```
130
+
131
+ ## 后台服务
132
+
133
+ macOS 使用 launchd,Linux 使用 systemd 用户服务(Ubuntu 24.04+)。
134
+
135
+ ```bash
136
+ nook service install
137
+ nook service status
138
+ nook service restart # 改完后端代码后重启
139
+ ```
140
+
141
+ 服务直接使用当前仓库目录,不复制代码;服务文件里的路径由安装时的环境动态生成,不依赖固定位置。
142
+
143
+ Linux 下请直接用当前用户运行,不要加 `sudo`。安装时会尝试启用 linger,让服务在未登录时也能运行。如果提示失败,可以手动执行:
144
+
145
+ ```bash
146
+ sudo loginctl enable-linger "$USER"
147
+ ```
148
+
149
+ 前端改动后需要重新构建,服务才会在 4317 端口展示新页面:
150
+
151
+ ```bash
152
+ npm run build:frontend
153
+ nook service restart
154
+ ```
155
+
156
+ 开发时更推荐用 Vite dev server,带热更新。
157
+
158
+ ### macOS 权限提示
159
+
160
+ 如果某个项目目录位于 `~/Desktop`、`~/Documents` 或 `~/Downloads`,后台服务里的 agent 可能没有权限读写(macOS 隐私保护)。遇到这种情况,可以:
161
+
162
+ - 用 `nook start` 在当前终端前台运行(继承终端的权限),或
163
+ - 在「系统设置 → 隐私与安全性 → 完全磁盘访问权限」里给 Node 可执行文件授权。
164
+
165
+ 服务日志:
166
+
167
+ - macOS:`~/.nook/logs/stdout.log`、`~/.nook/logs/stderr.log`
168
+ - Linux:`journalctl --user -u com.nook.server -f`
169
+
170
+ ## Agent
171
+
172
+ - 底层使用 `@earendil-works/pi-coding-agent` SDK
173
+ - 模型完全由 Pi 设置决定,Nook 不指定默认模型
174
+ - 内置工具:Pi 默认的 `read` / `bash` / `edit` / `write`,外加 `server_time`
175
+ - 思考、工具调用参数、工具结果、重试/压缩状态通过 SSE 实时推送
176
+
177
+ ### 运行中的消息:插话 / 跟进
178
+
179
+ Agent 运行时输入框仍然可用,发送前可以切换两种模式:
180
+
181
+ - **插话**(`steer`):等当前工具调用结束后插入,改变接下来的方向
182
+ - **跟进**(`followUp`):等这一轮所有工作结束、Agent 停下来后再处理
183
+
184
+ 排队中的消息显示在输入框上方,可以点「取回」放回输入框。点「停止」会中止当前运行,并把排队消息一起放回输入框。
185
+
186
+ 桌面键盘:`Enter` 发送当前模式,`Alt+Enter` 直接发送跟进。
187
+
188
+ ## 会话
189
+
190
+ Nook 直接读 Pi 的 session 文件,不另存格式,也不再扫描项目目录里的旧会话目录:
191
+
192
+ `~/.pi/agent/sessions/` 下当前项目的历史会话(Pi CLI `pi -r` 也能看到 Nook 新建的会话)
193
+
194
+ 项目本身只是 `{ name, path }` 记录,存在 `~/.nook/projects.json`。删除项目不会删除目录或会话文件。
195
+
196
+ ## 数据
197
+
198
+ Nook 是 Pi 的 Web 包装层,不保存自己的模型或服务配置,只保存管理的项目索引:
199
+
200
+ ```text
201
+ ~/.nook/projects.json 项目索引
202
+ ~/.nook/logs macOS 服务日志
203
+ ```
204
+
205
+ 模型、密钥等配置由 Pi 自己管理(`~/.pi`)。Nook 不写入 `.env`,也没有初始化命令。
206
+
207
+ ## 运行参数
208
+
209
+ | 变量 | 说明 |
210
+ | --- | --- |
211
+ | `NOOK_PORT` | 端口,默认 `4317` |
212
+ | `NOOK_HOST` | 监听地址,默认 `127.0.0.1`;`0.0.0.0` 表示所有网卡 |
213
+ | `NOOK_WEB_DIR` | 自定义构建后前端目录 |
214
+ | `NOOK_ALLOW_PROTECTED` | macOS:设为 `1` 允许后台服务访问桌面/文稿/下载 |
215
+
216
+ ## PWA / 添加到桌面
217
+
218
+ 前端已包含:
219
+
220
+ - `manifest.webmanifest`:fullscreen、start_url、scope、图标
221
+ - 192 / 512 普通图标,192 / 512 maskable 图标
222
+ - `apple-touch-icon` 180
223
+ - `sw.js`:缓存页面壳和静态资源,不缓存 `/api/` 和 SSE
224
+
225
+ 安装和 Service Worker 需要安全上下文(HTTPS 或 localhost)。直接通过 `http://100.x.x.x:4317` 打开时可以正常使用页面,但不会注册 Service Worker,Chrome 也不会出现安装入口。
226
+
227
+ 本机可以用 `http://localhost:4317` 测试。要在手机上安装,建议用 Tailscale Serve 提供 HTTPS:
228
+
229
+ ```bash
230
+ tailscale serve --bg --https=443 http://127.0.0.1:4317
231
+ ```
232
+
233
+ 然后打开:
234
+
235
+ ```text
236
+ https://<machine>.<tailnet>.ts.net/
237
+ ```
238
+
239
+ Service Worker 只负责页面壳和静态资源;API 和 SSE 始终走网络。
240
+
241
+ ## Android App
242
+
243
+ 不想折腾 HTTPS / PWA 的话,`android/` 里有一个原生 WebView 壳,直接把页面打成 APK:
244
+
245
+ ```bash
246
+ ./android/build.sh # 产物:dist/nook.apk
247
+ ```
248
+
249
+ 安装后填一次服务地址(`http://电脑IP:4317`)即可,支持明文 http,外链走系统浏览器,返回键按网页栈后退。细节见 [android/README.md](android/README.md)。
package/bin/nook.js ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ import { fileURLToPath } from 'node:url';
3
+
4
+ process.env.NOOK_LAUNCHER = fileURLToPath(import.meta.url);
5
+
6
+ const { main } = await import('../src/backend/index.js');
7
+
8
+ main(process.argv.slice(2)).then((code) => {
9
+ process.exitCode = code ?? 0;
10
+ }).catch((err) => {
11
+ console.error(err?.stack || String(err));
12
+ process.exitCode = 1;
13
+ });
@@ -0,0 +1 @@
1
+ :root{color-scheme:light;--font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;--mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;--ease: cubic-bezier(.2, .8, .2, 1);--ease-out: cubic-bezier(.16, 1, .3, 1);--dur: .22s;--r-sm: 8px;--r-md: 12px;--r-lg: 18px;--r-xl: 26px}*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}html{height:100%}body{min-height:100%;margin:0;background:var(--bg);color:var(--text);font-family:var(--font);font-size:16px;line-height:1.5;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}::selection{background:var(--accent);color:var(--accent-ink)}button,input,textarea{font:inherit;color:inherit}button{background:none;border:0;padding:0;cursor:pointer;touch-action:manipulation}a{color:inherit}svg{display:block}:focus{outline:none}:focus-visible{outline:2px solid var(--accent);outline-offset:2px}input,textarea{caret-color:var(--text)}.page{min-height:100dvh;display:flex;flex-direction:column;animation:page-in .2s var(--ease-out) both}.topbar{position:sticky;top:0;z-index:30;padding-top:env(safe-area-inset-top);background:var(--header-bg);backdrop-filter:blur(22px) saturate(1.5);-webkit-backdrop-filter:blur(22px) saturate(1.5);border-bottom:1px solid var(--line)}.topbar-inner{width:100%;max-width:760px;margin:0 auto;height:56px;padding:0 12px;display:flex;align-items:center;gap:4px}.topbar-actions{flex:none;display:flex;align-items:center;gap:2px}.icon{display:inline-flex;align-items:center;justify-content:center}.topbar h1{flex:1;min-width:0;margin:0;font-size:15.5px;font-weight:600;letter-spacing:-.015em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.brand{flex:1;display:flex;align-items:center;gap:6px;font-size:20px;font-weight:700;letter-spacing:-.045em}.brand .dot{width:6px;height:6px;border-radius:50%;background:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}.icon-btn{width:38px;height:38px;flex:none;display:grid;place-items:center;border-radius:50%;color:var(--text);transition:background .16s var(--ease),color .16s var(--ease),transform .12s var(--ease)}.icon-btn:active{background:var(--surface-2);transform:scale(.94)}.icon-btn.muted{color:var(--muted)}.text-btn{flex:none;padding:8px;border-radius:9px;color:var(--muted);font-size:13.5px;transition:background .16s var(--ease),color .16s var(--ease)}.text-btn:active{background:var(--surface-2);color:var(--text)}.text-btn.danger{color:var(--danger)}.content{flex:1;width:100%;max-width:760px;margin:0 auto;padding:10px 16px calc(32px + env(safe-area-inset-bottom))}.list{display:flex;flex-direction:column}.row{width:100%;min-height:66px;padding:12px 6px;display:flex;align-items:center;gap:13px;border-bottom:1px solid var(--line);border-radius:10px;text-align:left;transition:background .16s var(--ease),border-color .16s var(--ease)}.row[role=button]{cursor:pointer}.row:last-child{border-bottom-color:transparent}.row:active{background:var(--surface-2)}.row-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}.row-title{display:flex;align-items:center;gap:7px;min-width:0;color:var(--text);font-size:15.5px;font-weight:500;letter-spacing:-.012em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.row-title .label{min-width:0;overflow:hidden;text-overflow:ellipsis}.row-sub{color:var(--muted);font-size:12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-variant-numeric:tabular-nums}.row-mark{flex:none;width:36px;height:36px;display:grid;place-items:center;border-radius:11px;background:var(--surface);box-shadow:inset 0 0 0 1px var(--line);color:var(--muted);font-size:13px;font-weight:600;letter-spacing:0}.row-chevron{flex:none;color:var(--faint)}.running-dot{flex:none;width:6px;height:6px;border-radius:50%;background:var(--accent);animation:pulse 1.8s var(--ease) infinite}.row .trash-btn{flex:none;width:38px;height:38px;display:grid;place-items:center;border-radius:50%;color:var(--muted);transition:background .16s var(--ease),color .16s var(--ease)}.row .trash-btn:active{background:var(--surface-2);color:var(--danger)}.row.editing{cursor:default}.empty{flex:1;display:grid;place-items:center;min-height:58vh}.empty-add{width:72px;height:72px;display:grid;place-items:center;border:1px solid var(--line);border-radius:50%;background:var(--surface);color:var(--muted);box-shadow:var(--shadow-sm);transition:transform .18s var(--ease),box-shadow .18s var(--ease),color .18s var(--ease)}.empty-add:active{transform:scale(.95);color:var(--text)}.loading{min-height:58vh;display:grid;place-items:center;color:var(--muted)}.spinner{width:18px;height:18px;border:2px solid var(--line-strong);border-top-color:var(--accent);border-radius:50%;animation:spin .7s linear infinite}.chat-page{height:100dvh;display:flex;flex-direction:column;overflow:hidden}.chat-scroll{flex:1;overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;scrollbar-width:thin;scrollbar-color:var(--line-strong) transparent;mask-image:linear-gradient(to bottom,transparent 0,#000 18px,#000 100%);-webkit-mask-image:linear-gradient(to bottom,transparent 0,#000 18px,#000 100%)}.chat-scroll::-webkit-scrollbar{width:8px}.chat-scroll::-webkit-scrollbar-thumb{background:var(--line-strong);border-radius:4px}.chat-inner{width:100%;max-width:760px;margin:0 auto;padding:24px 16px 36px}.msg{margin:0 0 26px}.msg.enter{animation:msg-in .24s var(--ease-out) both}.msg.user{display:flex;justify-content:flex-end}.msg.user .bubble{max-width:min(84%,560px);padding:11px 15px;border-radius:18px 18px 6px;background:var(--user-bubble);color:var(--user-ink);font-size:15.5px;line-height:1.55;white-space:pre-wrap;word-break:break-word;text-wrap:pretty}.msg.assistant{display:block;max-width:700px}.msg.assistant .blocks>:last-child{margin-bottom:0}.markdown{color:var(--text);font-size:15.5px;line-height:1.7;word-break:break-word;overflow-wrap:anywhere}.markdown>:first-child{margin-top:0}.markdown>:last-child{margin-bottom:0}.markdown p{margin:0 0 .85em;text-wrap:pretty}.markdown h1,.markdown h2,.markdown h3,.markdown h4,.markdown h5,.markdown h6{margin:1.2em 0 .45em;font-weight:600;line-height:1.3;letter-spacing:-.02em}.markdown h1{font-size:1.36em}.markdown h2{font-size:1.2em}.markdown h3{font-size:1.07em}.markdown h4,.markdown h5,.markdown h6{font-size:1em}.markdown ul,.markdown ol{margin:.15em 0 .9em;padding-left:1.4em}.markdown li{margin:.18em 0;padding-left:.1em}.markdown li::marker{color:var(--muted)}.markdown li>ul,.markdown li>ol{margin:.12em 0 .18em}.markdown blockquote{margin:.6em 0 .95em;padding:.08em 0 .08em 13px;border-left:2px solid var(--line-strong);color:var(--muted)}.markdown hr{margin:1.3em 0;border:0;border-top:1px solid var(--line)}.markdown strong{font-weight:600}.markdown a{text-decoration:underline;text-underline-offset:3px;text-decoration-color:color-mix(in srgb,var(--accent) 75%,transparent)}.markdown code{padding:.14em .36em;border-radius:6px;background:var(--code-bg);font-family:var(--mono);font-size:.88em}.markdown pre{margin:.8em 0 1.05em;padding:13px 15px;border:1px solid var(--line);border-radius:var(--r-md);background:var(--code-bg);overflow-x:auto;scrollbar-width:thin}.markdown pre code{padding:0;background:none;font-size:12.5px;line-height:1.6;white-space:pre}.markdown table{display:block;max-width:100%;margin:.6em 0 1.1em;border-collapse:collapse;overflow-x:auto;scrollbar-width:thin;font-size:13.5px}.markdown th,.markdown td{padding:6px 10px;border:1px solid var(--line-strong);text-align:left;white-space:nowrap}.markdown th{background:var(--surface-2);font-weight:600}details>summary{list-style:none}details>summary::-webkit-details-marker{display:none}.block-think{margin:0 0 12px;padding-left:13px;border-left:1.5px solid var(--line-strong);color:var(--muted);font-size:13px}.block-think summary{display:flex;align-items:center;gap:6px;width:fit-content;color:var(--muted);font-size:12px;letter-spacing:.01em;-webkit-user-select:none;user-select:none;cursor:pointer;transition:color .16s var(--ease)}.block-think summary .chev{opacity:.72;transition:transform .2s var(--ease)}.block-think[open] summary .chev{transform:rotate(90deg)}details[open]>.think-body,details[open]>.tool-body{animation:fade .16s var(--ease) both}.block-think .think-body{margin-top:7px;padding-bottom:2px;line-height:1.68;white-space:pre-wrap;word-break:break-word;text-wrap:pretty;opacity:.95}.block-tool{margin:10px 0;border:1px solid var(--line);border-radius:13px;background:var(--surface);overflow:hidden;transition:border-color .16s var(--ease),box-shadow .16s var(--ease)}.block-tool summary{display:flex;align-items:baseline;gap:8px;padding:9px 12px;cursor:pointer;font-family:var(--mono);font-size:11.8px;line-height:1.45}.block-tool .tool-icon{flex:none;width:16px;text-align:center;font-size:11.5px;color:var(--muted)}.block-tool .tool-name{flex:none;color:var(--text);font-weight:600;letter-spacing:-.01em}.block-tool .tool-args{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--muted)}.block-tool .tool-meta{flex:none;color:var(--faint);font-size:10px;letter-spacing:.02em}.block-tool .tool-body{border-top:1px solid var(--line);padding:10px 12px 12px;background:color-mix(in srgb,var(--bg) 55%,var(--surface));color:var(--muted);font-family:var(--mono);font-size:11.3px;line-height:1.6}.block-tool .tool-body pre{margin:0;max-height:260px;overflow:auto;white-space:pre-wrap;word-break:break-word;scrollbar-width:thin}.block-tool .tool-label{margin:9px 0 5px;color:var(--faint);font-family:var(--font);font-size:9.5px;letter-spacing:.1em;text-transform:uppercase}.block-tool .tool-label:first-child{margin-top:0}.block-tool.is-error{border-color:color-mix(in srgb,var(--danger) 32%,var(--line))}.block-tool.is-error .tool-body{color:var(--danger);background:var(--danger-soft)}.block-error{margin:10px 0;padding:10px 12px;border:1px solid color-mix(in srgb,var(--danger) 30%,var(--line));border-radius:var(--r-md);background:var(--danger-soft);color:var(--danger);font-size:13px;line-height:1.6;white-space:pre-wrap;word-break:break-word}.msg.live .blocks>.markdown:last-child:after{content:"";display:inline-block;width:2px;height:1.05em;margin-left:2px;border-radius:1px;background:var(--accent);vertical-align:-.16em;animation:blink 1s steps(1,end) infinite}.run-status{max-width:760px;width:100%;margin:0 auto;padding:0 18px 8px;display:flex;align-items:center;justify-content:space-between;gap:10px;color:var(--muted);font-size:12.5px;letter-spacing:.01em;font-variant-numeric:tabular-nums}.run-status[hidden]{display:none}.run-status #run-status-text{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.stop-btn{flex:none;padding:3px 9px;border:1px solid var(--line);border-radius:999px;color:var(--muted);font-size:11.5px;transition:color .16s var(--ease),border-color .16s var(--ease),background .16s var(--ease)}.stop-btn:active{background:var(--surface-2);color:var(--text)}.stop-btn:disabled{opacity:.4}.queue{max-width:760px;width:100%;margin:0 auto;padding:0 18px 7px;animation:fade .18s var(--ease) both}.queue[hidden]{display:none}.queue-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:3px;color:var(--faint);font-size:10.5px;letter-spacing:.06em;text-transform:uppercase}.queue-clear{padding:2px 5px;border-radius:6px;color:var(--muted);font-size:11px;letter-spacing:0;text-transform:none}.queue-clear:active{color:var(--text);background:var(--surface-2)}.queue-items{max-height:112px;overflow-y:auto;scrollbar-width:thin}.queue-item{display:flex;align-items:baseline;gap:8px;padding:2px 0;color:var(--muted);font-size:12.5px;font-variant-numeric:tabular-nums}.queue-mode{flex:none;padding:0 4px;border:1px solid var(--line);border-radius:5px;color:var(--muted);font-size:9.5px;line-height:1.6}.queue-text{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.composer-wrap{position:relative;z-index:20;padding:6px 12px calc(10px + env(safe-area-inset-bottom));background:linear-gradient(to bottom,transparent 0%,var(--bg) 30%,var(--bg) 100%)}.composer{width:100%;max-width:760px;margin:0 auto;display:flex;align-items:flex-end;gap:8px;padding:6px 7px 6px 15px;border:1px solid var(--line-strong);border-radius:var(--r-xl);background:var(--surface);box-shadow:var(--shadow-sm),0 10px 30px var(--shadow-color-1);transition:border-color .18s var(--ease),box-shadow .18s var(--ease)}.composer:focus-within{border-color:color-mix(in srgb,var(--text) 22%,var(--line-strong));box-shadow:0 0 0 3px var(--accent-soft),var(--shadow-md)}.composer textarea{flex:1;min-height:36px;max-height:132px;padding:7px 0;border:0;outline:0;resize:none;background:none;font-size:16px;line-height:1.45}.composer textarea::placeholder{color:var(--faint)}.composer textarea:disabled{opacity:.55}.send-btn{flex:none;width:38px;height:38px;display:grid;place-items:center;border-radius:50%;background:var(--accent);color:var(--accent-ink);box-shadow:0 1px 0 var(--shadow-color-1);transition:transform .12s var(--ease),opacity .16s var(--ease),background .16s var(--ease)}.send-btn:disabled{opacity:.28}.send-btn:active:not(:disabled){transform:scale(.92)}.mode-switch{flex:none;display:flex;gap:2px;padding:2px;border:1px solid var(--line);border-radius:999px;background:var(--bg)}.mode-switch[hidden]{display:none}.mode-switch button{height:28px;padding:0 7px;border-radius:999px;color:var(--muted);font-size:11.5px;line-height:28px;transition:background .16s var(--ease),color .16s var(--ease),box-shadow .16s var(--ease)}.mode-switch button.active{background:var(--surface);color:var(--text);box-shadow:var(--shadow-sm)}.jump-btn{position:absolute;left:50%;bottom:calc(100% + 2px);z-index:25;width:38px;height:38px;display:grid;place-items:center;transform:translate(-50%);border:1px solid var(--line);border-radius:50%;background:var(--surface);color:var(--muted);box-shadow:var(--shadow-md);transition:transform .12s var(--ease),opacity .16s var(--ease)}.jump-btn[hidden]{display:none}.jump-btn:active{transform:translate(-50%) scale(.92)}.sheet-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:60;display:flex;align-items:flex-end;justify-content:center;background:var(--overlay);backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px);animation:fade .16s var(--ease) both}.sheet{width:100%;max-width:520px;padding:18px 18px calc(20px + env(safe-area-inset-bottom));border-radius:24px 24px 0 0;background:var(--surface);box-shadow:var(--shadow-lg);animation:sheet-up .28s var(--ease-out) both}.sheet:before{content:"";display:block;width:34px;height:4px;margin:-6px auto 16px;border-radius:999px;background:var(--line-strong)}.sheet h2{margin:0 0 14px;font-size:18px;font-weight:600;letter-spacing:-.02em}.field{display:flex;flex-direction:column;gap:7px;margin-bottom:14px}.field label{color:var(--muted);font-size:11.5px;letter-spacing:.02em}.field input{width:100%;padding:12px 13px;border:1px solid var(--line);border-radius:13px;outline:none;background:var(--bg);font-size:16px;transition:border-color .16s var(--ease),box-shadow .16s var(--ease)}.field input:focus{border-color:var(--line-strong);box-shadow:0 0 0 3px var(--accent-soft)}.sheet-error{min-height:17px;margin:2px 0 0;color:var(--danger);font-size:12.5px}.sheet-actions{display:flex;justify-content:flex-end;gap:6px;margin-top:16px}.btn{padding:10px 16px;border-radius:13px;font-size:14px;font-weight:500;transition:transform .12s var(--ease),opacity .16s var(--ease),background .16s var(--ease),color .16s var(--ease)}.btn:disabled{opacity:.4}.btn:active:not(:disabled){transform:scale(.97)}.btn-ghost{color:var(--muted)}.btn-primary{background:var(--text);color:var(--bg)}.toast{position:fixed;top:calc(14px + env(safe-area-inset-top));left:50%;z-index:100;max-width:calc(100vw - 32px);padding:10px 15px;transform:translate(-50%);border-radius:999px;background:var(--text);color:var(--bg);font-size:12.5px;box-shadow:var(--shadow-md);animation:toast-in .2s var(--ease-out) both}.toast[hidden]{display:none}.dir-field{display:flex;align-items:center;gap:6px}.dir-trigger{flex:1;min-width:0;height:46px;padding:0 12px;display:flex;align-items:center;gap:9px;border:1px solid var(--line);border-radius:13px;background:var(--bg);text-align:left;transition:background .16s var(--ease),border-color .16s var(--ease)}.dir-trigger:active{background:var(--surface-2)}.dir-trigger-icon{flex:none;color:var(--muted)}.dir-trigger-label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14.5px}.dir-trigger-chevron{flex:none;color:var(--faint)}.dir-reset{flex:none;padding:8px 5px;color:var(--muted);font-size:12px}.dir-reset:active{color:var(--text)}.dir-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:80;display:flex;justify-content:center;background:var(--bg);animation:fade .12s var(--ease) both}.dir-panel{width:100%;max-width:680px;height:100dvh;display:flex;flex-direction:column;background:var(--bg)}.dir-head{flex:none;height:calc(56px + env(safe-area-inset-top));padding:env(safe-area-inset-top) 10px 0;display:flex;align-items:center;gap:6px;border-bottom:1px solid var(--line);background:var(--header-bg);backdrop-filter:blur(22px) saturate(1.5);-webkit-backdrop-filter:blur(22px) saturate(1.5)}.dir-title{flex:1;font-size:16px;font-weight:600;letter-spacing:-.015em}.dir-location{flex:none;display:flex;align-items:center;gap:7px;padding:12px 16px 8px}.dir-up{flex:none;width:34px;height:34px;display:grid;place-items:center;border-radius:50%;color:var(--muted);transition:background .16s var(--ease),opacity .16s var(--ease)}.dir-up:disabled{opacity:.25}.dir-path{flex:1;min-width:0;padding:7px 10px;border-radius:9px;background:var(--surface-2);color:var(--muted);font-family:var(--mono);font-size:11.5px;line-height:1.4;white-space:nowrap;overflow-x:auto;scrollbar-width:none}.dir-path::-webkit-scrollbar{display:none}.dir-mkdir{flex:none;display:flex;gap:8px;padding:0 16px 12px}.dir-mkdir[hidden]{display:none}.dir-mkdir input{flex:1;min-width:0;padding:10px 12px;border:1px solid var(--line);border-radius:11px;outline:none;background:var(--bg);font-size:15px;transition:border-color .16s var(--ease),box-shadow .16s var(--ease)}.dir-mkdir input:focus{border-color:var(--line-strong);box-shadow:0 0 0 3px var(--accent-soft)}.dir-mkdir .btn{flex:none}.dir-list{flex:1;overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;padding:0 8px 8px;scrollbar-width:thin}.dir-row{width:100%;min-height:50px;padding:10px 12px;display:flex;align-items:center;gap:11px;border-radius:11px;text-align:left;transition:background .16s var(--ease)}.dir-row:active{background:var(--surface-2)}.dir-row-icon{flex:none;color:var(--muted)}.dir-row-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14.5px}.dir-row-chevron{flex:none;color:var(--faint)}.dir-empty{min-height:30vh;padding:40px 20px;display:grid;place-items:center;color:var(--muted);font-size:13px;text-align:center}.dir-more{padding:10px;color:var(--faint);font-size:11.5px;text-align:center}.dir-actions{flex:none;display:flex;align-items:center;justify-content:space-between;gap:8px;padding:12px 16px calc(12px + env(safe-area-inset-bottom));border-top:1px solid var(--line);background:var(--bg)}.dir-actions .btn-primary{min-width:132px}@keyframes spin{to{transform:rotate(360deg)}}@keyframes fade{0%{opacity:0}to{opacity:1}}@keyframes page-in{0%{opacity:.6}to{opacity:1}}@keyframes msg-in{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}@keyframes sheet-up{0%{opacity:.4;transform:translateY(32px)}to{opacity:1;transform:none}}@keyframes toast-in{0%{opacity:0;transform:translate(-50%) translateY(-6px)}to{opacity:1;transform:translate(-50%) translateY(0)}}@keyframes blink{0%,55%{opacity:1}56%,to{opacity:0}}@keyframes pulse{0%,to{opacity:1;box-shadow:0 0 0 0 var(--accent-soft)}50%{opacity:.72;box-shadow:0 0 0 5px transparent}}@media(hover:hover){.row:hover{background:color-mix(in srgb,var(--surface-2) 55%,transparent)}.icon-btn:hover{background:var(--surface-2)}.text-btn:hover{color:var(--text)}.empty-add:hover{color:var(--text);box-shadow:0 0 0 8px var(--accent-soft),var(--shadow-sm)}.stop-btn:hover{color:var(--text);border-color:var(--line-strong)}.queue-clear:hover,.btn-ghost:hover{color:var(--text)}.dir-trigger:hover,.dir-row:hover{background:var(--surface-2)}.block-tool:hover{border-color:var(--line-strong);box-shadow:var(--shadow-sm)}.block-think summary:hover{color:var(--text)}}@media(min-width:720px){.topbar-inner{padding:0 20px}.content{padding-top:16px}.chat-inner{padding-top:32px}.sheet-backdrop{align-items:center;padding:24px}.sheet{max-width:480px;padding-bottom:20px;border-radius:22px}.sheet:before{display:none}.dir-backdrop{align-items:center;padding:24px;background:var(--overlay);backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px)}.dir-panel{height:min(760px,88dvh);border-radius:18px;overflow:hidden;box-shadow:var(--shadow-lg)}.dir-head{height:56px;padding-top:0;border-radius:18px 18px 0 0}}@media(max-width:380px){.row-mark{width:32px;height:32px;border-radius:10px}.msg.user .bubble{max-width:88%}.mode-switch button{padding:0 5px;font-size:11px}.composer{padding-left:12px}.chat-inner{padding-left:14px;padding-right:14px}}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important}}:root{color-scheme:light;--porcelain: #F4F6F8;--cobalt: #2456A6;--ink: #182026;--emerald: #1F7A6B;--bg: var(--porcelain);--page-gutter: 16px;--surface: #FFFFFF;--surface-2: #EDF1F4;--surface-3: #E5EBEF;--surface-4: #F7F9FA;--surface-hover: #F0F4F6;--text: var(--ink);--text-strong: #11171C;--text-2: #5B6773;--muted: #7E8A95;--faint: #A8B3BD;--on-primary: #F7FAFF;--code-ink: #3B4B59;--primary: var(--cobalt);--primary-press: #1B437F;--primary-soft: #E7EFFA;--primary-soft-2: #F0F5FD;--primary-soft-3: #F6F9FE;--primary-line: #C8D8F0;--primary-glow: rgba(36, 86, 166, .24);--focus-ring: rgba(36, 86, 166, .16);--accent: var(--emerald);--accent-press: #176153;--accent-soft: #E1F2ED;--accent-soft-2: #EEF8F5;--accent-ink: #176153;--accent-line: #C6E6DD;--line: #E9EDF1;--line-soft: #F1F4F7;--line-strong: #DFE5EA;--line-ink: rgba(24, 32, 38, .08);--success: #1F9D7A;--success-ink: #176153;--success-soft: #E1F2ED;--success-line: #C6E6DD;--danger: #C4453C;--danger-press: #A63830;--danger-soft: #F9E9E7;--danger-soft-2: #FCF3F2;--danger-line: #EAC7C3;--outgoing: #E3F5EF;--outgoing-ink: #16352E;--outgoing-time: #4F8B7A;--outgoing-line: rgba(31, 122, 107, .14);--avatar-1-bg: #E8EFFA;--avatar-1-fg: #2C5B9E;--avatar-2-bg: #E3F4EF;--avatar-2-fg: #1F7A6B;--avatar-3-bg: #ECEFF3;--avatar-3-fg: #4A5A6A;--avatar-4-bg: #EEEAF8;--avatar-4-fg: #665A92;--overlay: rgba(16, 24, 32, .42);--overlay-strong: rgba(16, 24, 32, .52);--overlay-solid: #101820;--shadow-color-1: rgba(16, 24, 32, .05);--shadow-color-2: rgba(16, 24, 32, .08);--shadow-color-3: rgba(16, 24, 32, .12);--shadow-color-4: rgba(16, 24, 32, .18);--elev-1: 0 0 0 0 transparent;--elev-2: 0 0 0 0 transparent;--elev-3: 0 0 0 0 transparent;--elev-4: 0 0 0 0 transparent;--white-90: rgba(255, 255, 255, .92);--white-85: rgba(255, 255, 255, .86);--white-80: rgba(255, 255, 255, .82);--white-70: rgba(255, 255, 255, .72);--white-58: rgba(255, 255, 255, .6);--white-50: rgba(255, 255, 255, .52);--composer-fade: rgba(244, 246, 248, .75);--composer-fade-0: rgba(244, 246, 248, 0);--text-soft: var(--text-2);--code-bg: #EDF1F4;--user-bubble: var(--outgoing);--user-ink: var(--outgoing-ink);--header-bg: rgba(255, 255, 255, .86);--shadow-sm: var(--elev-1);--shadow-md: var(--elev-2);--shadow-lg: var(--elev-4)}.tg{position:fixed;top:0;right:0;bottom:0;left:0;height:auto;display:flex;flex-direction:column;overflow:hidden;background:var(--bg);color:var(--text);font-family:-apple-system,BlinkMacSystemFont,SF Pro Text,Inter,PingFang SC,Helvetica Neue,sans-serif;font-feature-settings:"tnum" 1;-webkit-font-smoothing:antialiased}.tg-masthead{flex:none;padding:calc(18px + env(safe-area-inset-top)) var(--page-gutter) 14px;background:transparent}.tg-masthead h1{margin:0;color:var(--primary);font-size:28px;line-height:1;font-weight:700;letter-spacing:-.045em}.tg-new{flex:none;width:32px;height:32px;display:grid;place-items:center;border-radius:0;border:1px solid var(--primary-line);background:var(--primary-soft);color:var(--primary);font-size:19px;font-weight:400;line-height:1;box-shadow:var(--elev-2);transition:background .15s,transform .12s}.tg-new:active{background:var(--primary-soft);transform:scale(.94)}.tg-list.sessions{padding:0 var(--page-gutter) calc(24px + env(safe-area-inset-bottom));gap:8px}.tg-project-scroll{flex:1;min-height:0;overflow-y:auto;padding:2px var(--page-gutter) calc(24px + env(safe-area-inset-bottom));scrollbar-width:none}.tg-project-scroll::-webkit-scrollbar{display:none}.tg-project-grid{display:flex;flex-direction:column;gap:10px}.tg-project-card{min-height:0;padding:12px 14px;display:flex;flex-direction:row;align-items:center;gap:12px;border:1px solid var(--line);border-radius:0;background:var(--surface);box-shadow:var(--elev-2);text-align:left;transition:transform .14s,box-shadow .14s,border-color .14s}.tg-project-card:active{transform:scale(.985);box-shadow:var(--elev-1);border-color:var(--line)}.tg-avatar.card-avatar{width:40px;height:40px;font-size:14px}.tg-card-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:3px}.tg-card-date{flex:none;align-self:flex-start;padding-top:2px;color:var(--faint);font-size:9px;white-space:nowrap}.tg-card-name{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text);font-size:14px;font-weight:600;letter-spacing:-.015em}.tg-card-path{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--muted);font-size:9.5px}.tg-project-card.new{justify-content:flex-start;border-style:dashed;border-color:var(--line-strong);background:var(--surface-2);box-shadow:none;color:var(--muted)}.tg-new-card-icon{flex:none;width:32px;height:32px;display:grid;place-items:center;border-radius:0;background:var(--primary-soft);color:var(--primary);font-size:18px}.tg-new-card-main{display:flex;flex-direction:column;gap:2px}.tg-new-card-title{font-size:11px;font-weight:600;color:var(--text-2)}.tg-new-card-sub{font-size:9px;color:var(--muted)}.tg-list{flex:1;min-height:0;overflow-y:auto;display:flex;flex-direction:column;padding:4px 0 0;scrollbar-width:none}.tg-list::-webkit-scrollbar{display:none}.tg-row{position:relative;width:100%;display:flex;align-items:center;gap:12px;padding:9px var(--page-gutter);text-align:left;transition:background .12s}.tg-row:active{background:var(--surface-2)}.tg-row:after{content:"";position:absolute;left:74px;right:0;bottom:0;height:1px;background:var(--line-soft)}.tg-row:last-of-type:after{display:none}.tg-avatar{flex:none;width:46px;height:46px;display:grid;place-items:center;border-radius:0;font-size:15px;font-weight:600;letter-spacing:-.01em}.tg-avatar.small{width:36px;height:36px;font-size:13px}.tg-row-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:3px}.tg-row-title{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:600;letter-spacing:-.012em;color:var(--text)}.tg-row-end{flex:none;margin-left:2px;color:var(--muted);font-size:9.5px;white-space:nowrap}.tg-row-sub{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:11px;line-height:1.3;color:var(--muted)}.tg-empty{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:5px;padding:40px 20px;text-align:center}.tg-empty-icon{width:52px;height:52px;display:grid;place-items:center;margin-bottom:6px;border-radius:0;background:var(--primary-soft-3);color:var(--primary);font-size:22px}.tg-empty b{font-size:13px;font-weight:600;color:var(--text)}.tg-empty span{color:var(--muted);font-size:10.5px}.tg-empty-btn{margin-top:8px;padding:7px 13px;border-radius:0;background:var(--primary);color:var(--on-primary);font-size:10px;font-weight:600}.tg-pagehead{flex:none;min-height:56px;padding:calc(8px + env(safe-area-inset-top)) var(--page-gutter) 8px;display:flex;align-items:center;gap:9px;background:transparent}.tg-circle{flex:none;width:30px;height:30px;display:grid;place-items:center;border-radius:0;background:var(--surface-2);color:var(--text-2);font-size:13px;transition:background .14s}.tg-circle:active{background:var(--surface-3)}.tg-pagehead-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}.tg-pagehead-main h1{margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text);font-size:16px;font-weight:600;letter-spacing:-.025em}.tg-pagehead-main p{margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--muted);font-size:10px}.tg-pagehead .tg-new{width:32px;height:32px;font-size:18px}.tg-pagehead .tg-avatar-button{border:1px solid var(--line);box-shadow:var(--elev-2)}.tg-session-search{flex:none;display:flex;align-items:center;gap:8px;height:36px;margin:8px var(--page-gutter) 10px;padding:0 10px;border:1px solid var(--line);background:var(--surface);color:var(--muted);box-shadow:var(--elev-2)}.tg-session-search:focus-within{border-color:var(--primary-line);box-shadow:0 0 0 2px var(--focus-ring),var(--elev-2)}.tg-session-search svg{flex:none}.tg-session-search input{flex:1;min-width:0;border:0;outline:0;background:transparent;color:var(--text);font-family:inherit;font-size:11.5px}.tg-session-search input::placeholder{color:var(--faint)}.tg-session-search input::-webkit-search-cancel-button{display:none}.tg-row.session{padding:11px 12px;background:var(--surface);border:1px solid var(--line);box-shadow:var(--elev-1);transition:background .14s,border-color .14s,box-shadow .14s}.tg-row.session:after{display:none}.tg-row.session .tg-row-end{align-self:flex-start;padding-top:3px}.tg-row-sub.live{color:var(--success-ink)}.tg-wall{position:absolute;top:0;right:0;bottom:0;left:0;background:var(--bg)}.tg-wall:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;background-image:radial-gradient(var(--white-85) .7px,transparent .7px);background-size:13px 13px;opacity:.5}.tg-chat-back{position:absolute;top:calc(8px + env(safe-area-inset-top));left:12px;z-index:7}.tg-circle.glass{width:32px;height:32px;border:1px solid var(--line);background:var(--white-90);box-shadow:var(--elev-2)}.tg-circle.glass:active{background:var(--white-80);transform:scale(.94)}.tg-chatscroll{position:relative;z-index:2;flex:1;min-height:0;overflow-y:auto;overscroll-behavior:none;overflow-anchor:none;-webkit-overflow-scrolling:touch;scrollbar-width:none}.tg-chatscroll::-webkit-scrollbar{display:none}.tg-chatbody{padding:calc(52px + env(safe-area-inset-top)) 12px calc(84px + env(safe-area-inset-bottom))}.tg-date{display:flex;justify-content:center;margin:2px 0 10px}.tg-date span{padding:3px 9px;border-radius:0;background:var(--white-58);color:var(--muted);font-size:9px;box-shadow:var(--elev-1)}.tg-msg{display:flex;flex-direction:column;margin-bottom:7px}.tg-msg.user{align-items:flex-end}.tg-msg.assistant{align-items:flex-start}.tg-bubble{position:relative;max-width:85%;padding:8px 11px 6px;border-radius:0;box-shadow:var(--elev-1)}.tg-bubble.in{background:var(--surface);border:1px solid var(--line-soft);border-bottom-left-radius:0}.tg-bubble.out{background:var(--outgoing);border:1px solid var(--outgoing-line);border-bottom-right-radius:0}.tg-bubble.in:before,.tg-bubble.out:before{content:"";position:absolute;bottom:0;width:8px;height:10px;background:inherit}.tg-bubble.in:before{left:-4px;clip-path:polygon(100% 0,100% 100%,0 100%)}.tg-bubble.out:before{right:-4px;clip-path:polygon(0 0,100% 100%,0 100%)}.tg-bubble p{margin:0;color:var(--text);font-size:12.5px;line-height:1.55;white-space:pre-wrap;word-break:break-word}.tg-msg-time{margin-top:4px;color:var(--faint);font-size:8.5px;line-height:1;white-space:nowrap}.tg-bubble.out p{color:var(--outgoing-ink)}.rich{color:var(--text);font-size:13px;line-height:1.66}:deep(.rich p){margin:0 0 .55em}:deep(.rich > :last-child){margin-bottom:0}:deep(.rich ul){margin:.1em 0 .55em;padding-left:1.1em}:deep(.rich li){margin:.18em 0}:deep(.rich li::marker){color:var(--primary)}:deep(.rich code){padding:1px 3px;border-radius:0;background:var(--surface-2);color:var(--code-ink);font-family:SF Mono,Menlo,Consolas,monospace;font-size:.86em}:deep(.rich strong){font-weight:600}.tg-think{width:fit-content;max-width:88%;margin-bottom:5px;padding:5px 9px;border-radius:0;background:var(--white-58);color:var(--muted);-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px)}.tg-think summary{display:flex;align-items:center;gap:4px;list-style:none;color:var(--muted);font-size:9.5px;cursor:pointer}.tg-think summary::-webkit-details-marker{display:none}.tg-chev{font-size:10px;transition:transform .18s}.tg-think[open] .tg-chev{transform:rotate(90deg)}.tg-think p{margin:4px 0 1px;color:var(--muted);font-size:10px;line-height:1.6;white-space:pre-wrap}.tg-tool{width:88%;margin-bottom:5px;border:1px solid var(--line);border-radius:0;background:var(--surface);box-shadow:var(--elev-1);overflow:hidden}.tg-tool summary{display:flex;align-items:center;gap:8px;padding:7px 9px;list-style:none;cursor:pointer}.tg-tool summary::-webkit-details-marker{display:none}.tg-tool-icon{flex:none;width:26px;height:26px;display:grid;place-items:center;border-radius:0;background:var(--primary-soft-2);color:var(--primary);font-family:SF Mono,Menlo,monospace;font-size:9px}.tg-tool-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}.tg-tool-main b{color:var(--text);font-size:9.5px;font-weight:600}.tg-tool-main span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--muted);font-family:SF Mono,Menlo,monospace;font-size:9px}.tg-tool-state{flex:none;color:var(--success-ink);font-size:8.5px;white-space:nowrap}.tg-tool-chev{flex:none;color:var(--faint);font-size:11px;transition:transform .18s}.tg-tool[open] .tg-tool-chev{transform:rotate(90deg)}.tg-tool-body{padding:0 9px 8px;border-top:1px solid var(--line-soft);background:var(--surface-2)}.tg-tool-label{margin:7px 0 3px;color:var(--faint);font-size:8px;letter-spacing:.08em;text-transform:uppercase}.tg-tool-body pre{margin:0;max-height:78px;overflow:auto;color:var(--muted);font-family:SF Mono,Menlo,Consolas,monospace;font-size:8px;line-height:1.6;white-space:pre-wrap;word-break:break-word}.tg-tool.running{border-color:var(--accent-line)}.tg-tool.running .tg-tool-icon{background:var(--accent-soft);color:var(--accent-ink);animation:tg-pulse 1.3s infinite}.tg-tool.error{border-color:var(--danger-line)}.tg-tool.error .tg-tool-icon{background:var(--danger-soft);color:var(--danger)}.tg-tool.error .tg-tool-main b{color:var(--danger)}.tg-error{max-width:85%;margin-bottom:5px;padding:8px 10px;border:1px solid var(--danger-line);border-radius:0;background:var(--danger-soft-2);color:var(--danger);font-size:10.5px;line-height:1.55;white-space:pre-wrap;word-break:break-word}.tg-caret{display:inline-block;width:5px;height:11px;margin:2px 0 0 8px;border-radius:0;background:var(--primary);animation:tg-blink 1s steps(2) infinite}.tg-bottom-dock{position:absolute;left:0;right:0;bottom:0;z-index:5;display:flex;flex-direction:column;pointer-events:none}.tg-bottom-dock>*{pointer-events:auto}.tg-queue{position:relative;z-index:4;flex:none;margin:0 10px 4px;padding:7px 9px;border:1px solid var(--white-70);border-radius:0;background:var(--white-80);box-shadow:var(--elev-2);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}.tg-queue-head{display:flex;align-items:center;justify-content:space-between;color:var(--muted);font-size:9px}.tg-queue-head button{color:var(--primary);font-size:8.5px}.tg-queue-row{display:flex;align-items:center;gap:6px;margin-top:4px}.tg-queue-mode{flex:none;padding:1px 5px;border-radius:0;background:var(--primary-soft);color:var(--primary);font-size:8px}.tg-queue-text{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text-2);font-size:10px}.tg-queue-row button{flex:none;color:var(--muted);font-size:8.5px}.tg-run{position:relative;z-index:4;flex:none;display:flex;align-items:center;gap:6px;margin:0 12px 5px;padding:4px 9px;border:1px solid var(--white-70);border-radius:0;background:var(--white-80);box-shadow:var(--elev-2);color:var(--text-2);font-size:9.5px;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}.tg-spinner{flex:none;width:6px;height:6px;background:var(--primary);border-radius:0;animation:tg-pulse 1.2s infinite}.tg-run-time{margin-left:auto;color:var(--muted);font-variant-numeric:tabular-nums}.tg-run button{flex:none;color:var(--danger);font-size:8.5px}.tg-composer{position:relative;z-index:4;flex:none;padding:2px 10px calc(10px + env(safe-area-inset-bottom));background:linear-gradient(to top,var(--composer-fade),var(--composer-fade-0))}.tg-inputbar{display:flex;align-items:flex-end;gap:5px;padding:4px 4px 4px 11px;border:1px solid var(--line);border-radius:0;background:var(--surface);box-shadow:var(--elev-2);transition:border-color .16s,box-shadow .16s}.tg-inputbar:focus-within{border-color:var(--primary-line);box-shadow:0 0 0 2px var(--focus-ring),var(--elev-2)}.tg-inputbar textarea{flex:1;min-height:28px;max-height:80px;padding:6px 0;border:0;outline:0;resize:none;overflow-y:hidden;background:transparent;color:var(--text);font-family:inherit;font-size:13px;line-height:1.45}.tg-inputbar textarea::placeholder{color:var(--faint)}.tg-mode{flex:none;display:flex;gap:1px;padding:2px;border-radius:0;background:var(--surface-2);margin-bottom:3px}.tg-mode button{height:22px;padding:0 6px;border-radius:0;color:var(--muted);font-size:9px;line-height:22px;transition:background .14s,color .14s}.tg-mode button.active{background:var(--surface);color:var(--primary);box-shadow:var(--elev-1)}.tg-send{flex:none;width:31px;height:31px;display:grid;place-items:center;margin-bottom:1px;border-radius:0;background:var(--primary);color:var(--on-primary);font-size:15px;font-weight:500;box-shadow:var(--elev-2);transition:opacity .15s,transform .12s}.tg-send:disabled{opacity:.3;box-shadow:none}.tg-send:active:not(:disabled){transform:scale(.94)}@keyframes tg-spin{to{transform:rotate(360deg)}}@keyframes tg-blink{50%{opacity:0}}@keyframes tg-pulse{50%{opacity:.45}}.tg-msg.enter{animation:tg-msg-in .18s ease-out both}.tg-loading{min-height:50vh;display:grid;place-items:center}.tg-loading .spinner{width:18px;height:18px;border:2px solid var(--line);border-top-color:var(--primary);border-radius:0;animation:tg-spin .7s linear infinite}.tg-jump{position:absolute;left:50%;bottom:calc(100% + 6px);transform:translate(-50%);width:32px;height:32px;display:grid;place-items:center;border:1px solid var(--line);background:var(--white-90);color:var(--text-2);box-shadow:var(--elev-2);z-index:6}.tg-jump:active{background:var(--white-80);transform:translate(-50%) scale(.94)}@keyframes tg-msg-in{0%{opacity:0;transform:translateY(5px)}to{opacity:1;transform:none}}*,*:before,*:after{border-radius:0!important}.sheet-backdrop{background:var(--overlay)}.sheet{background:var(--surface);color:var(--text);border:1px solid var(--line);padding:18px;max-width:420px;box-shadow:var(--elev-4)}.sheet:before{display:none}.sheet h2{color:var(--text);font-size:18px;font-weight:600;letter-spacing:-.02em}.field label{color:var(--muted);font-size:10px}.field input{border:1px solid var(--line);background:var(--surface-2);color:var(--text);font-size:15px}.field input:focus{border-color:var(--primary-line);box-shadow:0 0 0 2px var(--focus-ring)}.sheet-error{color:var(--danger)}.btn{border-radius:0}.btn-primary{background:var(--primary);color:var(--on-primary)}.btn-primary:active{background:var(--primary-press)}.btn-ghost{color:var(--text-2)}.dir-trigger{border:1px solid var(--line);background:var(--surface-2);color:var(--text)}.dir-trigger.placeholder .dir-trigger-label{color:var(--faint)}.dir-trigger-icon,.dir-trigger-chevron{color:var(--muted)}.dir-reset{color:var(--primary)}.dir-backdrop{background:var(--overlay-solid)}.dir-panel{background:var(--surface);color:var(--text)}.dir-head{background:var(--surface);border-bottom:1px solid var(--line)}.dir-title{color:var(--text)}.dir-path{background:var(--surface-2);color:var(--text-2)}.dir-row{color:var(--text)}.dir-row-icon,.dir-row-chevron{color:var(--muted)}.dir-mkdir input{background:var(--surface-2);border-color:var(--line);color:var(--text)}.dir-actions{background:var(--surface);border-top:1px solid var(--line)}.dir-empty{color:var(--muted)}.dir-up{color:var(--text-2)}.toast{background:var(--text);color:var(--on-primary)}.spinner{border-top-color:var(--primary)}.tg-masthead{display:flex;align-items:center;justify-content:space-between;gap:12px}.tg-edit{flex:none;color:var(--muted);font-size:10px;padding:4px 0}.tg-card-delete{flex:none;align-self:flex-start;color:var(--danger);font-size:9px;padding:4px 0}.tg-row.session .tg-card-delete{align-self:flex-start;padding-top:3px}.tg-run-text{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dir-head .icon-btn{color:var(--text-2)}.dir-head .icon-btn:active,.dir-row:active,.dir-trigger:active{background:var(--surface-2)}.dir-mkdir input:focus{border-color:var(--primary-line);box-shadow:0 0 0 2px var(--focus-ring)}.rich{overflow-wrap:anywhere}.rich>:first-child{margin-top:0}.rich>:last-child{margin-bottom:0}.rich h1,.rich h2,.rich h3,.rich h4,.rich h5,.rich h6{margin:1.1em 0 .4em;font-weight:600;line-height:1.3;letter-spacing:-.015em}.rich h1{font-size:1.3em}.rich h2{font-size:1.18em}.rich h3{font-size:1.06em}.rich h4,.rich h5,.rich h6{font-size:1em}.rich ol{margin:.1em 0 .55em;padding-left:1.25em}.rich li::marker{color:var(--primary)}.rich pre{margin:.7em 0 .8em;padding:9px 10px;border:1px solid var(--line);background:var(--surface-2);overflow-x:auto;overscroll-behavior-x:contain;-webkit-overflow-scrolling:touch;scrollbar-width:thin}.rich pre code{padding:0;background:none;border:0;color:var(--code-ink);font-size:10.5px;line-height:1.6;white-space:pre}.rich blockquote{margin:.6em 0 .7em;padding:.1em 0 .1em 10px;border-left:2px solid var(--line-strong);color:var(--muted)}.rich hr{margin:1em 0;border:0;border-top:1px solid var(--line)}.rich a{color:var(--primary);text-decoration:underline;text-underline-offset:2px}.rich table{display:block;max-width:100%;margin:.5em 0 .8em;border-collapse:collapse;overflow-x:auto;font-size:10.5px}.rich th,.rich td{padding:5px 8px;border:1px solid var(--line);text-align:left;white-space:nowrap}.rich th{background:var(--surface-2);font-weight:600}@media(max-width:899px){.tg-bubble.in.has-code{max-width:100%}.rich pre{scrollbar-width:none;-ms-overflow-style:none}.rich pre::-webkit-scrollbar{display:none;width:0;height:0}}:root{color-scheme:light}::selection{background:var(--primary-soft-2);color:var(--text)}:focus-visible{outline:2px solid var(--primary);outline-offset:2px}input::placeholder,textarea::placeholder{color:var(--faint)}.dir-more{color:var(--muted)}.tg-project-card[role=button],.tg-row[role=button]{cursor:pointer;touch-action:manipulation}.dir-up:active:not(:disabled){background:var(--surface-2)}.btn-ghost:active{background:var(--surface-2)}.tg-project-card{-webkit-user-select:none;user-select:none;-webkit-touch-callout:none}.tg-menu-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:300;display:flex;align-items:center;justify-content:center;padding:16px;background:var(--overlay);animation:tg-fade .14s ease-out both}.tg-menu{width:100%;max-width:420px;padding:6px;border:1px solid var(--line);background:var(--surface);box-shadow:var(--elev-4);animation:tg-menu-in .16s ease-out both}.tg-menu-item{width:100%;padding:12px 10px;border-bottom:1px solid var(--line-soft);text-align:left;color:var(--text);font-size:13px}.tg-menu-item:last-child{border-bottom:0}.tg-menu-item:active{background:var(--surface-2)}.tg-menu-item.danger{color:var(--danger)}@keyframes tg-fade{0%{opacity:0}to{opacity:1}}@keyframes tg-menu-in{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}.sheet-backdrop{align-items:center;justify-content:center;padding:16px}.sheet{width:100%;max-width:420px;animation:tg-dialog-in .16s ease-out both}@keyframes tg-dialog-in{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}.tg-avatar-button{cursor:pointer}.tg-avatar-button:active{opacity:.65}.tg-row{-webkit-user-select:none;user-select:none;-webkit-touch-callout:none}body{overscroll-behavior:none}html,body{touch-action:pan-x pan-y}.tg-logo{flex:none;width:32px;height:32px;display:block;box-shadow:var(--elev-2)}.tg-logo svg{width:100%;height:100%}@media(hover:hover){.tg-project-card:hover{border-color:var(--line-strong);box-shadow:var(--elev-3)}.tg-row.session:hover{border-color:var(--line-strong);box-shadow:var(--elev-2)}.tg-new:hover{background:var(--primary-soft-2)}.tg-circle.glass:hover,.tg-jump:hover{background:var(--white-85)}.tg-mode button:hover{color:var(--text-2)}.tg-mode button.active:hover{color:var(--primary)}}.tg-masthead,.tg-project-scroll{width:100%;max-width:none;margin:0}.tg-project-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:12px}.tg-project-card{width:100%;min-width:0;min-height:70px}.tg-project-console{background:var(--bg)}.tg-console-head{flex:none;width:100%;max-width:none;margin:0;padding:calc(14px + env(safe-area-inset-top)) var(--page-gutter) 14px;display:flex;align-items:center;gap:12px}.tg-logo-button{cursor:pointer;transition:transform .12s,opacity .12s}.tg-logo-button:active{transform:scale(.94);opacity:.8}.tg-console-meta{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.tg-console-meta h1{margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text);font-size:17px;line-height:1.2;font-weight:600;letter-spacing:-.025em}.tg-console-meta p{margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--muted);font-size:10.5px}.tg-console-body{flex:1;min-height:0;width:100%;max-width:none;margin:0;display:flex;flex-direction:column;overflow:hidden}.tg-session-pane{flex:1;min-height:0;display:flex;flex-direction:column;overflow:hidden}.tg-session-pane-top{flex:none;padding:2px var(--page-gutter) 0}.tg-session-pane .tg-session-search{margin:6px 0}.tg-session-pane .tg-list.sessions{padding:0 var(--page-gutter) calc(20px + env(safe-area-inset-bottom));scrollbar-width:none;-ms-overflow-style:none}.tg-session-pane .tg-list.sessions::-webkit-scrollbar{width:0;height:0;display:none}.tg-row.session.active{border-color:var(--primary-line);background:var(--primary-soft-3)}.tg-row.session.active:before{content:"";position:absolute;left:0;top:9px;bottom:9px;width:2px;background:var(--primary)}.tg-row.session.active .tg-row-title{color:var(--primary)}.tg-chat-pane{flex:1;min-height:0;display:none;position:relative;overflow:hidden}.tg-project-console.has-session .tg-session-pane{display:none}.tg-project-console.has-session .tg-chat-pane{display:flex}.tg-chat-panel{position:relative;flex:1;min-height:0;display:flex;flex-direction:column;overflow:hidden;background:var(--bg)}@media(min-width:900px){.tg-console-head{padding:10px 16px 8px;gap:8px}.tg-console-meta h1{font-size:14px}.tg-console-meta p{font-size:10px}.tg-session-pane .tg-console-head .tg-logo{width:26px;height:26px}.tg-session-pane .tg-console-head .tg-new{width:26px;height:26px;font-size:15px}.tg-console-body{flex-direction:row;padding:0}.tg-session-pane{flex:0 0 340px;width:340px;display:flex!important;border:1px solid var(--line);border-right:0;background:var(--surface)}.tg-chat-pane{display:flex!important;border:1px solid var(--line);background:var(--bg)}.tg-session-pane-top{padding:2px 16px 0}.tg-session-pane .tg-list.sessions{padding:0 16px 18px}.tg-session-pane .tg-session-search{margin:10px 0 6px}.tg-session-pane .tg-session-search input{font-size:12.5px}.tg-session-pane .tg-row.session{padding:10px 12px}.tg-session-pane .tg-row-title{font-size:13px}.tg-session-pane .tg-row-sub{font-size:10.5px}.tg-session-pane .tg-row.session .tg-row-end{font-size:9.5px}.tg-chat-back{display:none}.tg-chatbody{width:100%;max-width:948px;margin:0 auto;padding:22px 24px 90px}.tg-composer{padding:4px 24px 20px}.tg-composer>.tg-inputbar{width:100%;max-width:900px;margin:0 auto}.tg-composer .tg-jump{bottom:calc(100% + 4px)}.tg-queue{width:calc(100% - 48px);max-width:900px;margin:0 auto 6px}.tg-bubble p{font-size:14px}.tg-bubble{max-width:78%;padding:10px 13px 8px}.rich{font-size:14px;line-height:1.7}.tg-think{max-width:82%}.tg-think p{font-size:12px}.tg-tool{width:82%}.tg-tool-main b{font-size:11px}.tg-tool-main span{font-size:10px}.tg-tool-body pre{font-size:10.5px;max-height:220px}.tg-error{font-size:12.5px;max-width:78%}.tg-date span{font-size:10.5px}.tg-msg{margin-bottom:10px}.tg-inputbar textarea{font-size:14px;max-height:180px}.tg-send{width:34px;height:34px}.tg-mode button{height:24px;padding:0 8px;font-size:10px;line-height:24px}.tg-project-card{min-height:76px;padding:14px 16px}.tg-card-name{font-size:15px}.tg-card-path{font-size:11px}.tg-card-date{font-size:10.5px}.tg-row-title{font-size:14.5px}.tg-row-sub{font-size:11.5px}}@media(hover:hover){.tg-logo-button:hover{opacity:.82}.tg-row.session.active:hover{border-color:var(--primary);background:var(--primary-soft-2)}}input:focus,input:focus-visible,textarea:focus,textarea:focus-visible{outline:none}.tg-inputbar:focus-within,.tg-session-search:focus-within,.field input:focus,.dir-mkdir input:focus{border-color:var(--line);box-shadow:none}