hob-bot 0.0.0-stage → 1.0.3

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.
Files changed (140) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +97 -2
  3. package/README.zh-CN.md +98 -0
  4. package/bin/hob.mjs +7 -0
  5. package/dist/web/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  6. package/dist/web/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  7. package/dist/web/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  8. package/dist/web/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  9. package/dist/web/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  10. package/dist/web/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  11. package/dist/web/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  12. package/dist/web/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  13. package/dist/web/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  14. package/dist/web/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  15. package/dist/web/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  16. package/dist/web/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  17. package/dist/web/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  18. package/dist/web/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  19. package/dist/web/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  20. package/dist/web/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  21. package/dist/web/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  22. package/dist/web/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  23. package/dist/web/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  24. package/dist/web/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  25. package/dist/web/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  26. package/dist/web/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  27. package/dist/web/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  28. package/dist/web/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  29. package/dist/web/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  30. package/dist/web/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  31. package/dist/web/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  32. package/dist/web/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  33. package/dist/web/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  34. package/dist/web/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  35. package/dist/web/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  36. package/dist/web/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  37. package/dist/web/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  38. package/dist/web/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  39. package/dist/web/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  40. package/dist/web/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  41. package/dist/web/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  42. package/dist/web/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  43. package/dist/web/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  44. package/dist/web/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  45. package/dist/web/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  46. package/dist/web/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  47. package/dist/web/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  48. package/dist/web/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  49. package/dist/web/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  50. package/dist/web/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  51. package/dist/web/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  52. package/dist/web/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  53. package/dist/web/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  54. package/dist/web/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  55. package/dist/web/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  56. package/dist/web/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  57. package/dist/web/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  58. package/dist/web/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  59. package/dist/web/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  60. package/dist/web/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  61. package/dist/web/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  62. package/dist/web/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  63. package/dist/web/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  64. package/dist/web/assets/index-C72gAwgN.css +1 -0
  65. package/dist/web/assets/index-Dyw5G8Pg.js +230 -0
  66. package/dist/web/assets/math-C-EwFotM.css +1 -0
  67. package/dist/web/assets/math-zZ4JA8eM.js +257 -0
  68. package/dist/web/favicon.ico +0 -0
  69. package/dist/web/fonts/inter-latin.woff2 +0 -0
  70. package/dist/web/fonts/jetbrains-mono-latin.woff2 +0 -0
  71. package/dist/web/icons/apple-touch-icon-180.png +0 -0
  72. package/dist/web/icons/favicon-32.png +0 -0
  73. package/dist/web/icons/icon-192.png +0 -0
  74. package/dist/web/icons/icon-512.png +0 -0
  75. package/dist/web/icons/icon-maskable-512.png +0 -0
  76. package/dist/web/index.html +32 -0
  77. package/dist/web/manifest.webmanifest +16 -0
  78. package/dist/web/mock/audio.mp3 +0 -0
  79. package/dist/web/mock/video.mp4 +0 -0
  80. package/dist/web/sw.js +131 -0
  81. package/package.json +64 -4
  82. package/server/src/actions.ts +230 -0
  83. package/server/src/boot.ts +85 -0
  84. package/server/src/bus.ts +21 -0
  85. package/server/src/config.ts +123 -0
  86. package/server/src/cron-text.ts +49 -0
  87. package/server/src/delegations.ts +113 -0
  88. package/server/src/files.ts +142 -0
  89. package/server/src/http.ts +802 -0
  90. package/server/src/ids.ts +19 -0
  91. package/server/src/image.ts +218 -0
  92. package/server/src/imports.ts +302 -0
  93. package/server/src/jobs.ts +730 -0
  94. package/server/src/main.ts +69 -0
  95. package/server/src/memory.ts +272 -0
  96. package/server/src/models.ts +358 -0
  97. package/server/src/overview.ts +116 -0
  98. package/server/src/pages.ts +54 -0
  99. package/server/src/password.ts +23 -0
  100. package/server/src/pi.ts +273 -0
  101. package/server/src/prompt.ts +227 -0
  102. package/server/src/providers.ts +532 -0
  103. package/server/src/push.ts +285 -0
  104. package/server/src/router-activity.ts +47 -0
  105. package/server/src/router-tools.ts +549 -0
  106. package/server/src/router.ts +883 -0
  107. package/server/src/routines.ts +129 -0
  108. package/server/src/runtime.ts +104 -0
  109. package/server/src/search.ts +91 -0
  110. package/server/src/secrets.ts +46 -0
  111. package/server/src/settings.ts +453 -0
  112. package/server/src/skills.ts +150 -0
  113. package/server/src/store.ts +324 -0
  114. package/server/src/text.ts +14 -0
  115. package/server/src/time.ts +42 -0
  116. package/server/src/transcript.ts +272 -0
  117. package/server/src/worker-tools.ts +129 -0
  118. package/shared/command.ts +42 -0
  119. package/shared/files.ts +141 -0
  120. package/shared/media.ts +17 -0
  121. package/shared/model-note.ts +32 -0
  122. package/shared/page-shell.ts +108 -0
  123. package/shared/search.ts +19 -0
  124. package/shared/skills.ts +37 -0
  125. package/shared/sprites.ts +439 -0
  126. package/shared/thinking.ts +118 -0
  127. package/shared/types.ts +637 -0
  128. package/vendor/lore-pi-extension/README.md +28 -0
  129. package/vendor/lore-pi-extension/api.ts +140 -0
  130. package/vendor/lore-pi-extension/formatters.ts +204 -0
  131. package/vendor/lore-pi-extension/hooks.ts +195 -0
  132. package/vendor/lore-pi-extension/index.ts +25 -0
  133. package/vendor/lore-pi-extension/package.json +23 -0
  134. package/vendor/lore-pi-extension/skills.ts +447 -0
  135. package/vendor/lore-pi-extension/tools.ts +344 -0
  136. package/vendor/lore-pi-extension/uri.ts +67 -0
  137. package/vendor/lore-pi-extension/vendor/skill-workcopy/index.d.mts +266 -0
  138. package/vendor/lore-pi-extension/vendor/skill-workcopy/index.mjs +1328 -0
  139. package/vendor/lore-pi-extension/vendor/skill-workcopy/skills-sync.d.mts +33 -0
  140. package/vendor/lore-pi-extension/vendor/skill-workcopy/skills-sync.mjs +202 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 FFatTiger
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,98 @@
1
- # Temporary Holding Version
1
+ # Hob
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
+ **A self-hosted personal assistant that actually does the work.** You talk to one main assistant, Hob. It runs real work as background jobs, asks before anything risky, and when a kind of work keeps coming back, it proposes a dedicated assistant for it.
4
+
5
+ [中文说明](README.zh-CN.md) · [Architecture](docs/architecture.md) · MIT License
6
+
7
+ > The interface is currently Chinese-only. Hob is a single-user app you run on your own machine or server.
8
+
9
+ ![Hob: chat with the main assistant, a running job and its live transcript](docs/screenshots/chat.png)
10
+
11
+ ## What you get
12
+
13
+ **One conversation, real work.** Ask in plain language; Hob turns it into a job that runs in the background with its own shell, files and tools. A job card shows progress and elapsed time. Open it to follow every step live, add instructions mid-way, or stop it.
14
+
15
+ **Assistants that grow out of your habits.** When the same kind of request repeats, Hob suggests a dedicated assistant ("写作", "服务器", "记账" …). Each one keeps its own conversation, duties, approval rules, schedules and work log, and you configure all of it in one panel.
16
+
17
+ **Delegation you can see.** Hob hands work to the right assistant and keeps a delegation card in its own chat: status, linked jobs, and any pending question, which you can answer right on the card. When everything finishes, the result comes back to Hob, so you keep talking in one place.
18
+
19
+ **Asks first, then remembers.** Each assistant has "confirm before running" rules. Pick "always allow" once and it becomes a rule, so you won't be asked about that again.
20
+
21
+ **Schedules.** Daily briefs, weekly reports, month-end checks: routines run on cron-style schedules and post results into the assistant's conversation.
22
+
23
+ **Pages instead of walls of text.** For processes, comparisons or research, an assistant can answer with a single-page visual document. It opens in the side panel and renders live while the model is still writing.
24
+
25
+ **Tools that come with it:**
26
+
27
+ - **Web search** across 10 providers (SearXNG, Exa, Tavily, Brave, Serper, Jina, Firecrawl, Perplexity, You.com, Ollama), used in order with automatic fallback.
28
+ - **Skills** from Hob's own skill folder, the shared `~/.agents/skills`, and Lore. You can import skills from Claude Code, Codex and pi.
29
+ - **Long-term memory**, kept locally or in [Lore](https://github.com/FFatTiger/lore).
30
+ - **Image generation** through any OpenAI-compatible image API.
31
+ - **Push notifications** when an assistant needs your decision or a job finishes.
32
+
33
+ **Made for the phone too.** Hob is an installable web app with a mobile layout and Telegram-style gestures: swipe a message to reply, long-press for actions. Light and dark themes follow your system.
34
+
35
+ ![Hob on a phone: assistant list, a delegation card, an approval question](docs/screenshots/mobile.png)
36
+
37
+ ## Quick start
38
+
39
+ You need Node.js 22 or newer and an API key for at least one model provider.
40
+
41
+ ```bash
42
+ npm install -g hob-bot
43
+ HOB_PASSWORD='choose-a-password' hob
44
+ ```
45
+
46
+ Or run it once without installing: `HOB_PASSWORD='choose-a-password' npx hob-bot`.
47
+
48
+ Open <http://127.0.0.1:30148> and sign in with that password. Then:
49
+
50
+ 1. Go to **设置 → 服务商** (Settings → Providers) and add a provider. Built-in ones (Anthropic, OpenAI, Google, DeepSeek, OpenRouter, …) only need an API key; any OpenAI- or Anthropic-compatible endpoint works too.
51
+ 2. Go to **设置 → 模型** (Settings → Models) and pick the models for chat and for jobs.
52
+ 3. Send Hob a message. A reply, or a job card for real work, means you are set.
53
+
54
+ The password is hashed into `~/.hob/config.json` on first start, so later starts don't need `HOB_PASSWORD`. You can change it under **设置 → 通用**.
55
+
56
+ ## Configuration
57
+
58
+ Startup options are environment variables. Everything else, including providers, models, memory, search, skills and notifications, lives in the settings UI and takes effect immediately.
59
+
60
+ | Variable | Default | Purpose |
61
+ | --- | --- | --- |
62
+ | `HOB_HOME` | `~/.hob` | Data directory |
63
+ | `HOB_PORT` | `30148` | HTTP port |
64
+ | `HOB_HOST` | `127.0.0.1` | Listen address |
65
+ | `HOB_PASSWORD` | — | Sign-in password; required on first start unless `password` is set in `config.json` |
66
+
67
+ Hob is self-contained. Conversations, jobs, memory, skills, keys and its engine state all live in `HOB_HOME`, and it never reads or changes other tools' configuration. To reuse providers or a Lore connection you already have on the machine, import them explicitly in settings. **Back up `HOB_HOME` and you have backed up everything.**
68
+
69
+ ## Deploy
70
+
71
+ Hob is a single Node process. Run it with any process manager and put a reverse proxy with TLS in front. Push notifications and installing as an app both need HTTPS. With PM2:
72
+
73
+ ```bash
74
+ pm2 start hob --name hob # after npm install -g hob-bot
75
+ pm2 start deploy/pm2.config.cjs # or from a source checkout: process "hob", port 30148, data in ~/.hob
76
+ ```
77
+
78
+ ## Development
79
+
80
+ ```bash
81
+ git clone https://github.com/FFatTiger/hob.git
82
+ cd hob
83
+ npm install
84
+ npm run build
85
+ npm start # same as the `hob` command, from source
86
+ npm run dev:server # API server with reload, port 30148
87
+ npm run dev:web # Vite dev server; proxies /api to 30148
88
+ npm test # vitest
89
+ npm run typecheck
90
+ ```
91
+
92
+ Add `?mock=1` to the dev URL to run the UI against an in-browser fake backend. No model or server is needed, and the screenshots above were taken that way.
93
+
94
+ Stack: Node 22 + TypeScript, Hono with SSE, Vite + React with hand-written CSS. The agent engine is the [pi](https://github.com/earendil-works/pi) SDK, used in-process. Read [docs/architecture.md](docs/architecture.md) for the design, data layout and tool list (in Chinese).
95
+
96
+ ## License
97
+
98
+ [MIT](LICENSE)
@@ -0,0 +1,98 @@
1
+ # Hob
2
+
3
+ **一个自己部署、真正动手干活的私人助手。** 你只跟主助手 Hob 说话:它把要做的事交给后台任务执行,有风险的操作先问你;同一类活反复出现时,它会提议分出一个专门的助手。
4
+
5
+ [English](README.md) · [架构说明](docs/architecture.md) · MIT 许可证
6
+
7
+ > 目前界面只有中文。Hob 是单用户应用,运行在你自己的电脑或服务器上。
8
+
9
+ ![Hob:与主助手的对话、正在运行的任务和实时执行过程](docs/screenshots/chat.png)
10
+
11
+ ## 能做什么
12
+
13
+ **一条对话,真实干活。** 用平常的话提要求,Hob 会派出任务在后台执行,任务有自己的命令行、文件和工具。任务卡上能看到进度和用时,点开可以实时看每一步,中途补充要求,或者直接停止。
14
+
15
+ **从习惯里长出来的助手。** 同类要求反复出现时,Hob 会提议创建专门的助手,比如「写作」「服务器」「记账」。每个助手有自己的对话、职责、执行前确认规则、定时任务和工作日志,都在同一个面板里设置。
16
+
17
+ **看得见的委派。** Hob 把事交给合适的助手后,在自己的对话里留一张委派卡,上面有状态、关联任务和待确认的问题,问题可以直接在卡上回答。全部完成后结果回到 Hob,你始终只在一个地方说话。
18
+
19
+ **先问,再记住。** 每个助手都有执行前确认规则。选一次「一直允许」就会记成规则,以后同类操作不再问。
20
+
21
+ **定时任务。** 每日简报、周报、月底对账,按 cron 式的时间表运行,结果发到对应助手的对话里。
22
+
23
+ **用页面代替大段文字。** 讲流程、做对比、写调研时,助手可以交一页图文页面。页面在侧栏打开,模型边写边显示。
24
+
25
+ **自带的能力:**
26
+
27
+ - **联网搜索**:支持 10 个服务商(SearXNG、Exa、Tavily、Brave、Serper、Jina、Firecrawl、Perplexity、You.com、Ollama),按顺序使用,失败时自动换下一个。
28
+ - **技能**:读取 Hob 自己的技能目录、通用的 `~/.agents/skills` 和 Lore,可以从 Claude Code、Codex、pi 导入。
29
+ - **长期记忆**:保存在本地,或接入 [Lore](https://github.com/FFatTiger/lore)。
30
+ - **图像生成**:接任意 OpenAI 兼容的图像接口。
31
+ - **推送通知**:助手需要你确认、任务结束时通知你。
32
+
33
+ **手机上也好用。** Hob 可以安装成网页应用,手机上是专门的布局,交互照 Telegram:向左滑动消息即可回复,长按弹出菜单。支持亮色和暗色主题。
34
+
35
+ ![手机上的 Hob:助手列表、委派卡、确认问题](docs/screenshots/mobile.png)
36
+
37
+ ## 快速开始
38
+
39
+ 需要 Node.js 22 或更高版本,以及至少一个模型服务商的 API Key。
40
+
41
+ ```bash
42
+ npm install -g hob-bot
43
+ HOB_PASSWORD='设一个密码' hob
44
+ ```
45
+
46
+ 不想全局安装,也可以直接运行一次:`HOB_PASSWORD='设一个密码' npx hob-bot`。
47
+
48
+ 打开 <http://127.0.0.1:30148>,用这个密码登录,然后:
49
+
50
+ 1. 到 **设置 → 服务商** 添加服务商。内置服务商(Anthropic、OpenAI、Google、DeepSeek、OpenRouter 等)只需填 API Key;OpenAI 或 Anthropic 兼容接口也可以用。
51
+ 2. 到 **设置 → 模型** 选好对话和任务使用的模型。
52
+ 3. 给 Hob 发一条消息。收到回复,或者出现一张任务卡,就说明配置好了。
53
+
54
+ 首次启动时密码会转成哈希写进 `~/.hob/config.json`,之后启动不用再带 `HOB_PASSWORD`。改密码在 **设置 → 通用**。
55
+
56
+ ## 配置
57
+
58
+ 启动项用环境变量设置。服务商、模型、记忆、搜索、技能、通知等其余设置都在界面里,改完立即生效。
59
+
60
+ | 变量 | 默认值 | 作用 |
61
+ | --- | --- | --- |
62
+ | `HOB_HOME` | `~/.hob` | 数据目录 |
63
+ | `HOB_PORT` | `30148` | HTTP 端口 |
64
+ | `HOB_HOST` | `127.0.0.1` | 监听地址 |
65
+ | `HOB_PASSWORD` | — | 登录密码;首次启动必填,除非 `config.json` 里已写了 `password` |
66
+
67
+ Hob 是独立的:对话、任务、记忆、技能、Key 和引擎数据都在 `HOB_HOME` 里,不读也不改本机其他工具的配置。想沿用本机已有的服务商或 Lore 连接,可以在设置里主动导入。**备份 `HOB_HOME` 就备份了全部数据。**
68
+
69
+ ## 部署
70
+
71
+ Hob 是单个 Node 进程。用任意进程管理器运行,前面加一层带 TLS 的反向代理即可。推送通知和安装成应用都需要 HTTPS。用 PM2 的话:
72
+
73
+ ```bash
74
+ pm2 start hob --name hob # npm install -g hob-bot 之后
75
+ pm2 start deploy/pm2.config.cjs # 或者在源码目录里:进程名 hob,端口 30148,数据在 ~/.hob
76
+ ```
77
+
78
+ ## 开发
79
+
80
+ ```bash
81
+ git clone https://github.com/FFatTiger/hob.git
82
+ cd hob
83
+ npm install
84
+ npm run build
85
+ npm start # 从源码运行,等同于 hob 命令
86
+ npm run dev:server # 后端,改动自动重载,端口 30148
87
+ npm run dev:web # Vite 开发服务器,/api 代理到 30148
88
+ npm test # vitest
89
+ npm run typecheck
90
+ ```
91
+
92
+ 开发地址加上 `?mock=1`,界面会使用浏览器内的模拟后端,不需要模型和服务端。上面的截图就是这样拍的。
93
+
94
+ 技术栈:Node 22 + TypeScript,Hono + SSE,Vite + React,CSS 全部手写。智能体引擎是进程内运行的 [pi](https://github.com/earendil-works/pi) SDK。设计、数据布局和工具列表见 [docs/architecture.md](docs/architecture.md)。
95
+
96
+ ## 许可证
97
+
98
+ [MIT](LICENSE)
package/bin/hob.mjs ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ // npm 包的 `hob` 命令:用 tsx 直接跑 TypeScript 源码,和 `npm start` 是同一个入口。
3
+ import { register } from "tsx/esm/api";
4
+
5
+ register();
6
+ const { boot } = await import("../server/src/boot.ts");
7
+ boot();
@@ -0,0 +1 @@
1
+ @font-face{font-family:Inter;src:url(/fonts/inter-latin.woff2) format("woff2");font-weight:100 900;font-style:normal;font-display:swap}@font-face{font-family:JetBrains Mono;src:url(/fonts/jetbrains-mono-latin.woff2) format("woff2");font-weight:400 700;font-style:normal;font-display:swap}*{box-sizing:border-box;margin:0;padding:0}:root{--t-fast: .12s;--t-mid: .18s;--t-slow: .24s;--ease-in: cubic-bezier(.22, 1, .36, 1);--ease-out: cubic-bezier(.4, 0, 1, 1);--bg: #ffffff;--side: #f6f6f4;--sel: #eaeae6;--panel: #fafaf8;--line: #ececea;--text: #18181a;--text2: #6d6d72;--text3: #a4a4a9;--bubble: #f1f1ef;--card: #ffffff;--field: #efefec;--user: #18181a;--utext: #ffffff;--accent: #ff6a2b;--ok: #22a065;--danger: #d92d20;--stage: #ecebe7}.dark{--bg: #151516;--side: #1b1b1d;--sel: #2a2a2d;--panel: #18181a;--line: #262629;--text: #ececed;--text2: #a1a1a7;--text3: #6b6b71;--bubble: #232326;--card: #2c2c30;--field: #232326;--user: #f1f1ef;--utext: #151516;--danger: #ff6b5e;--stage: #0e0e0f}html,body,#root{height:100%}html,body{background:var(--status-background, var(--side));overflow:hidden;overscroll-behavior:none}html{-webkit-text-size-adjust:100%;text-size-adjust:100%;-webkit-tap-highlight-color:transparent}body{touch-action:manipulation;font-family:Inter,Noto Sans CJK SC,PingFang SC,system-ui,sans-serif;color:var(--text);-webkit-font-smoothing:antialiased;font-size:15px}button{font:inherit;color:inherit;background:none;border:0;padding:0;cursor:pointer;text-align:left;transition:transform var(--t-mid) var(--ease-in)}input,textarea{font:inherit;color:inherit;background:none;border:0;outline:none}a{color:inherit}svg.i{display:block;flex:none}.mono{font-family:JetBrains Mono,Noto Sans Mono CJK SC,monospace}.muted{color:var(--text2)}.link{color:var(--text);text-decoration:underline;text-decoration-color:var(--text3);text-underline-offset:3px;cursor:pointer}.app{position:fixed;top:0;right:0;bottom:0;left:0;display:flex;overflow:hidden;background:var(--bg);color:var(--text)}.side{width:296px;flex:none;background:var(--side);border-right:1px solid var(--line);display:flex;flex-direction:column;padding:14px 12px 12px;min-height:0}.side-top{display:flex;gap:6px;align-items:center}.search{flex:1;min-width:0;height:34px;border-radius:10px;background:var(--field);display:flex;align-items:center;gap:8px;padding:0 11px;color:var(--text3);font-size:14px}.search input{flex:1;min-width:0;color:var(--text);font-size:14px}.search input::placeholder{color:var(--text3)}.ib{width:34px;height:34px;border-radius:10px;display:grid;place-items:center;color:var(--text2);flex:none}@media(hover:hover){.ib:hover{background:var(--sel)}}.pins,.mpins{display:flex;flex-wrap:wrap;justify-content:center}.pins{margin:14px 0 4px}.pins>.srow,.mpins>.pin{width:33.333%}.pins.n2>.srow,.mpins.n2>.pin{width:40%}.pins.n1>.srow,.mpins.n1>.pin{width:56%}.n1 .pin .nm,.n2 .pin .nm{font-size:14px}.n1 .pin .sub,.n2 .pin .sub{font-size:12px}.n1 .badge{left:calc(50% + 24px)}.n2 .badge{left:calc(50% + 20px)}.pin{position:relative;display:flex;flex-direction:column;align-items:center;width:100%;min-width:0;padding:12px 6px 10px;border-radius:14px}.pin.sel{background:var(--sel)}@media(hover:hover){.pin:hover{background:var(--sel)}}.pin .nm,.pin .sub{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pin .nm{margin-top:8px;font-size:13px;font-weight:500}.pin .sub{margin-top:1px;font-size:11.5px;color:var(--text3)}.badge{position:absolute;top:11px;left:calc(50% + 15px);width:11px;height:11px;border-radius:50%;background:var(--accent);border:2px solid var(--side)}.pin.sel .badge{border-color:var(--sel)}.pin,.row{-webkit-user-select:none;user-select:none;-webkit-touch-callout:none}.gt{display:flex;justify-content:space-between;font-size:12px;color:var(--text3);padding:14px 8px 6px}.side-scroll{flex:1;min-height:0;overflow-y:auto}.row{display:flex;gap:11px;align-items:center;padding:9px 8px;border-radius:12px;width:100%}.row.sel{background:var(--sel)}@media(hover:hover){.row:hover{background:var(--sel)}}.row .main{flex:1;min-width:0}.row .l1{display:flex;justify-content:space-between;align-items:baseline;gap:8px}.row .nm{font-size:14px;font-weight:500}.row .tm{font-size:12px;color:var(--text3);flex:none}.row .pv{font-size:13px;color:var(--text2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:2px}.row.job{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:baseline;column-gap:11px;row-gap:2px}.row.job>:first-child{grid-area:1 / 1 / span 2 / span 1;align-self:center}.row.job .nm{grid-area:1 / 2;min-width:0}.row.job .tm{grid-area:1 / 3;justify-self:end}.row.job .pv{grid-area:2 / 2;min-width:0;margin-top:0}.row.job .jt-st{grid-area:2 / 3;justify-self:end;display:block;position:relative;padding-left:17px}.row.job .jt-st .i{position:absolute;left:0;top:0;bottom:0;margin:auto 0}.row .new{font-size:11px;color:var(--accent);font-weight:500;margin-left:6px}.fold{display:flex;justify-content:space-between;align-items:center;padding:10px 8px;font-size:13px;color:var(--text3);width:100%}.side-foot{margin-top:auto;padding-top:6px;display:flex;flex-direction:column;gap:2px}.frow{display:flex;align-items:center;gap:10px;padding:8px;border-radius:10px;font-size:14px;color:var(--text2);width:100%}@media(hover:hover){.frow:hover{background:var(--sel)}}.frow .sp{flex:1}.av{display:grid;place-items:center;flex:none;border-radius:50%;background:var(--av-bg)}.av svg{width:78%;height:78%}.av-plain .av{background:none}.av-plain .av svg{width:90%;height:90%}.av-busy{position:relative}.av-busy:after{content:"";position:absolute;right:0;bottom:0;width:8px;height:8px;background:#2fbf71;border:2px solid var(--bg, white);border-radius:50%}.av-motion .av-eyes,.av-motion .av-blink{transform-box:fill-box;transform-origin:center;animation-delay:var(--eye-delay, 0s);animation-iteration-count:infinite;animation-timing-function:cubic-bezier(.3,0,.15,1)}.av-motion .av-blink{animation-name:eye-blink;animation-duration:4.3s}.av-think .av-eyes{animation-name:eye-think;animation-duration:3.6s}.av-work .av-eyes{animation-name:eye-work;animation-duration:2.4s}.av-home .av-eyes{animation-name:eye-home;animation-duration:5.2s}@keyframes eye-blink{0%,92%,to{transform:scaleY(1)}95%{transform:scaleY(.1)}}@keyframes eye-think{0%,18%{transform:translate(0)}22%,44%{transform:translate(.9px,-.9px)}48%,64%{transform:translate(-.9px,-.9px)}68%,82%{transform:translate(.3px,-.9px)}86%,to{transform:translate(0)}}@keyframes eye-work{0%,16%{transform:translate(-1.3px,.8px)}21%,40%{transform:translate(1.3px,.8px)}45%,58%{transform:translateY(.8px)}63%,80%{transform:translate(1.2px,.5px)}85%,to{transform:translate(-1.3px,.8px)}}@keyframes eye-home{0%,20%{transform:translate(0)}23%,42%{transform:translate(-1.3px)}45%,58%{transform:translate(0)}61%,80%{transform:translate(1.3px)}83%,to{transform:translate(0)}}.activity-line{display:flex;align-items:center;gap:10px;margin-top:8px;color:var(--text2);font-size:14px}.activity-line .activity-shimmer{min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.activity-shimmer{background:linear-gradient(100deg,var(--text2) 25%,var(--text) 45%,var(--text2) 65%);background-size:220% 100%;color:transparent;-webkit-background-clip:text;background-clip:text;animation:activity-shimmer 2s linear infinite}@keyframes activity-shimmer{to{background-position:-220% 0}}.boot-loading{display:flex;flex-direction:column;align-items:center;gap:16px}@media(prefers-reduced-motion:reduce){.av-motion .av-eyes,.av-motion .av-blink,.activity-shimmer{animation:none}.activity-shimmer{color:var(--text2)}}.chat{flex:1;min-width:0;display:flex;flex-direction:column;position:relative}.compwrap,.mcomp-wrap{position:absolute;left:0;right:0;bottom:0;pointer-events:none}.comp,.mcomp{pointer-events:auto;background:color-mix(in srgb,var(--field) 80%,transparent);-webkit-backdrop-filter:blur(18px) saturate(1.5);backdrop-filter:blur(18px) saturate(1.5);box-shadow:0 0 0 .5px var(--line),0 8px 28px #00000014}.dark .comp,.dark .mcomp{box-shadow:0 0 0 .5px var(--line),0 8px 28px #00000073}.head{height:54px;flex:none;display:flex;align-items:center;gap:9px;padding:0 18px 0 22px;border-bottom:1px solid var(--line)}.head .nm{font-size:15px;font-weight:500}.head .sp{flex:1}.msgs{flex:1;min-height:0;overflow-y:auto;scrollbar-gutter:stable;display:flex;flex-direction:column;padding-bottom:calc(var(--comp-h, 80px) + 6px)}.msgs .col{margin-top:auto}.msgs .col.mid,.mmsgs .col.mid{margin-bottom:auto}.hello{display:flex;flex-direction:column;align-items:center;text-align:center;padding:24px 0}.hello .t{margin-top:14px;font-size:17px;font-weight:600}.hello .d{margin-top:8px;max-width:420px;text-wrap:pretty;font-size:14px;line-height:1.65;color:var(--text2)}.hello .ex{display:flex;flex-wrap:wrap;justify-content:center;gap:8px;margin-top:20px;max-width:520px}.hello .ex .btn{background:var(--bubble);font-weight:400;color:var(--text2)}.hello .setup{margin-top:20px;padding:14px 16px;max-width:420px;border-radius:14px;background:var(--bubble);font-size:13.5px;line-height:1.6;color:var(--text2);display:flex;flex-direction:column;align-items:center;gap:12px}.col{width:100%;max-width:724px;margin:0 auto;padding:0 34px;display:flex;flex-direction:column}.div{align-self:center;font-size:12px;color:var(--text3);margin:22px 0 12px}.sys{align-self:center;display:flex;align-items:center;gap:6px;font-size:12.5px;color:var(--text3);margin:10px 0;max-width:100%}.b,.u{font-size:15px;line-height:1.62;border-radius:18px;padding:9px 14px;margin-top:8px}.b{align-self:flex-start;max-width:548px;background:var(--bubble);overflow-wrap:anywhere}.u{align-self:flex-end;max-width:500px;background:var(--user);color:var(--utext);overflow-wrap:anywhere}.g{height:12px}.b ul,.fp-md ul{list-style:none}.b li,.fp-md li{display:flex;gap:8px;align-items:flex-start}.b li:before,.fp-md li:before{content:"✓";color:var(--text2);font-size:13px;line-height:1.85;flex:none}.b ol,.fp-md ol{list-style:none;counter-reset:n}.b ol li,.fp-md ol li{counter-increment:n}.b ol li:before,.fp-md ol li:before{content:counter(n) ".";color:var(--text2);font-size:14px;line-height:1.75;width:14px;flex:none}.b p+p,.b ul+p,.b ol+p,.b pre+p,.fp-md p+p,.fp-md ul+p,.fp-md ol+p,.fp-md pre+p{margin-top:6px}.b p+ul,.b p+ol,.fp-md p+ul,.fp-md p+ol{margin-top:4px}.b strong,.fp-md strong{font-weight:600}.b code,.fp-md code{font-family:JetBrains Mono,Noto Sans Mono CJK SC,monospace;font-size:13px;background:var(--field);border-radius:5px;padding:1px 5px}.b pre,.fp-md pre{background:var(--field);border-radius:10px;padding:9px 11px;overflow-x:auto;margin-top:6px}.b pre code,.fp-md pre code{background:none;padding:0;font-size:12.5px;line-height:1.6}.b a,.fp-md a{color:var(--text);text-decoration:underline;text-decoration-color:var(--text3);text-underline-offset:3px}.qt{font-weight:500}.qs{font-size:13.5px;color:var(--text2);margin-top:1px}.opts{margin:10px 0 4px;background:var(--card);border-radius:12px;overflow:hidden}.opt{display:flex;align-items:center;gap:10px;padding:10px 12px;font-size:14.5px;line-height:1.4;border-top:1px solid var(--line);width:100%}.opt:first-child,.optrow:first-child .opt{border-top:0}@media(hover:hover){.opt:hover{background:var(--field)}}.key{width:20px;height:20px;border-radius:6px;background:var(--bubble);color:var(--text3);font-size:11px;font-weight:600;display:grid;place-items:center;flex:none}.opt.chosen{color:var(--text2)}.opt .ck{margin-left:auto;color:var(--text2)}.other{display:flex;align-items:center;gap:4px;border-top:1px solid var(--line);padding:2px 6px 2px 12px}.other input{flex:1;min-width:0;height:34px;border:0;background:transparent;color:var(--text);font-size:14px;outline:none}.other input::placeholder{color:var(--text3)}.other-send{color:var(--accent)}.tt{display:flex;align-items:center;gap:10px;font-weight:500;min-width:min(404px,100%)}.st{margin-left:auto;display:flex;align-items:center;gap:6px;font-size:13px;font-weight:400;color:var(--text2);white-space:nowrap}.st .i{color:var(--accent)}.st.done .i{color:var(--ok)}.st.done{color:var(--text2)}.meta{font-size:13px;color:var(--text2);margin-top:3px}.acts{display:flex;gap:8px;margin:10px 0 3px}.jobcard .acts .btn{height:30px;padding:0 12px;font-size:13px;font-weight:500}.jobcard .job-reply{background:color-mix(in srgb,var(--text) 7%,transparent)}.jobcard .job-reply.selected{background:color-mix(in srgb,var(--text) 11%,transparent)}.jobcard .job-stop{color:var(--danger);background:color-mix(in srgb,var(--danger) 12%,transparent)}@media(hover:hover){.jobcard .job-reply:hover{background:color-mix(in srgb,var(--text) 11%,transparent)}.jobcard .job-stop:hover{background:color-mix(in srgb,var(--danger) 18%,transparent)}}.btn{height:32px;padding:0 13px;border-radius:999px;background:var(--card);font-size:13.5px;font-weight:500;display:inline-flex;align-items:center;gap:6px;color:var(--text);flex:none}@media(hover:hover){.btn:hover{filter:brightness(.97)}}.btn.solid{background:var(--user);color:var(--utext)}.btn.ghost{background:transparent;color:var(--text2);padding:0 6px}.btn:disabled{opacity:.55;cursor:default}.att{display:flex;align-items:center;gap:11px;background:var(--bubble);border-radius:12px;padding:10px 12px;margin:8px 0 3px}.att .ico{width:34px;height:40px;border-radius:7px;background:var(--card);display:grid;place-items:center;color:var(--text2);flex:none}.att .n{font-size:14px;font-weight:500}.att .m{font-size:12.5px;color:var(--text2)}.att.plain{background:var(--bubble);margin-top:4px;width:100%}.filecard{width:340px;max-width:100%;margin-top:4px}.filecard.bad .ico,.filecard.bad .m{color:var(--danger)}.mmsgs .filecard{width:100%;max-width:300px}.col>.filecard,.col>.imgcard{margin:8px 0 0}.col>.media-audio,.col>.media-video{margin:8px 0 0}.code-block{position:relative;margin-top:6px;border-radius:10px;background:var(--field)}.code-block+p{margin-top:6px}.code-head{padding:7px 44px 0 11px;font:11px/16px JetBrains Mono,monospace;color:var(--text3)}.b .code-block pre,.fp-md .code-block pre{margin:0;background:none;padding-right:40px}.b .code-head+pre,.fp-md .code-head+pre{padding-top:3px}.code-copy{position:absolute;top:3px;right:3px;width:30px;height:30px;display:grid;place-items:center;border:0;border-radius:8px;background:none;color:var(--text2);cursor:pointer;opacity:0;transition:opacity .15s}.code-copy:hover{color:var(--text)}.code-block:hover .code-copy,.code-copy:focus-visible{opacity:1}@media(hover:none){.code-copy{opacity:1}}.math-display{overflow-x:auto;overflow-y:hidden;margin:6px 0}.media-audio{display:flex;align-items:center;gap:10px;width:320px;max-width:100%;padding:10px 12px;border-radius:18px;background:var(--bubble);color:var(--text)}.audio-play{flex:none;width:36px;height:36px;display:grid;place-items:center;border:0;border-radius:50%;background:var(--accent);color:#fff;cursor:pointer}.audio-main{flex:1;min-width:0}.audio-name{display:block;max-width:100%;padding:0;border:0;background:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:11px;color:var(--text2);cursor:pointer}.audio-track{position:relative;height:26px;display:flex;align-items:center}.audio-track input{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;opacity:0;cursor:pointer}.audio-bars{width:100%;height:100%;display:flex;align-items:center;gap:2px}.audio-bars i{flex:1;min-width:1px;border-radius:2px;background:var(--text3)}.audio-bars i.played{background:var(--accent)}.audio-line{height:4px;width:100%;background:var(--text3);border-radius:4px}.audio-line i{display:block;height:100%;background:var(--accent);border-radius:4px}.audio-time{font-size:11px;white-space:nowrap;color:var(--text2);font-variant-numeric:tabular-nums}.audio-rate{flex:none;padding:2px 7px;border:0;border-radius:999px;background:var(--field);font-size:11px;color:var(--text2);cursor:pointer}.media-video{width:320px;max-width:100%;overflow:hidden;border-radius:18px;background:var(--bubble)}.media-video video{display:block;width:100%;max-height:360px;background:#000}.media-video button{display:block;width:100%;padding:7px 12px;border:0;background:none;text-align:left;font-size:11px;color:var(--text2);cursor:pointer}.imgcard{display:block;width:320px;max-width:100%;margin:8px 0 3px;padding:0;border:0;background:none;cursor:zoom-in;border-radius:12px;overflow:hidden}.imgcard img{display:block;width:100%;max-height:320px;object-fit:cover;border-radius:12px;background:var(--bubble)}.imgcard.testshot{width:320px;max-width:100%;margin:0}.mmsgs .imgcard{width:100%;max-width:300px}.lightbox{position:fixed;top:0;right:0;bottom:0;left:0;z-index:40;display:grid;place-items:center;padding:24px;background:#000000b8;cursor:zoom-out;animation:enter-fade var(--t-mid) var(--ease-in)}.lightbox img{max-width:100%;max-height:100%;border-radius:10px;box-shadow:0 24px 60px #00000059}.quote{border-left:2px solid currentColor;opacity:.62;padding-left:9px;font-size:13px;line-height:1.5;margin:2px 0 5px}.quote-flash{animation:quote-flash 1s ease-out}@keyframes quote-flash{0%,to{box-shadow:0 0 0 0 transparent}25%{background-color:color-mix(in srgb,var(--accent) 25%,var(--bubble));box-shadow:0 0 0 5px color-mix(in srgb,var(--accent) 45%,transparent)}}.message-row{position:relative;width:100%;display:flex;justify-content:flex-start}.message-row.right{justify-content:flex-end}.message-row .quote{display:block;cursor:pointer}.tag{display:flex;align-items:center;gap:5px;font-size:12px;color:var(--text3);margin:2px 0 0 4px}.hov{position:relative;align-self:flex-start;max-width:548px}.hov.right{align-self:flex-end}.tablecard{max-width:100%;overflow-x:auto;border:1px solid var(--line);border-radius:18px;background:var(--card);-webkit-overflow-scrolling:touch}.hov.msg>.tablecard+.b,.hov.msg>.b+.tablecard,.hov.msg>.tablecard+.tablecard{margin-top:8px}.tablecard table{border-collapse:collapse;min-width:100%;font-size:14px;line-height:1.5}.tablecard th,.tablecard td{padding:11px 16px;min-width:9.5em;max-width:20em;text-align:left;vertical-align:top}.tablecard th{font-weight:600;white-space:nowrap}.tablecard tr+tr td,.tablecard thead+tbody tr td{border-top:1px solid var(--line)}.hov.msg{padding-bottom:26px}.tools{position:absolute;left:0;bottom:0;display:flex;gap:2px;opacity:0;pointer-events:none;transition:opacity var(--t-fast) var(--ease-in)}.hov.right .tools{left:auto;right:0}.hov.msg:focus-within .tools:not(.menu),.tools.menu{opacity:1;pointer-events:auto}.tools button{width:26px;height:26px;display:grid;place-items:center;border-radius:7px;color:var(--text3)}.tools button.copied{color:var(--ok)}.tools button:focus-visible{outline:2px solid var(--accent);outline-offset:1px}@media(min-width:768px){.col{max-width:1040px}.hov{max-width:min(80%,46em)}.hov.right{max-width:min(70%,46em)}.b,.u{max-width:100%}.col>.b{max-width:min(80%,46em)}.col>.b.q,.col>.b.wide,.hov:has(>.b.wide){width:min(80%,46em)}}@media(hover:hover){.hov.msg:hover .tools{opacity:1;pointer-events:auto}.tools button:hover{background:var(--field);color:var(--text2)}}.compwrap{padding:8px 0 20px;overflow-y:hidden;scrollbar-gutter:stable}.comp{display:flex;flex-direction:column;gap:2px;border-radius:26px;padding:6px 8px;min-height:52px;justify-content:center}.comp-main{display:flex;align-items:center;gap:10px}.comp .pl{width:34px;height:34px;border-radius:50%;display:grid;place-items:center;color:var(--text2);flex:none}.comp .sendbtn{width:36px;height:36px;border-radius:50%;background:var(--user);color:var(--utext);display:grid;place-items:center;flex:none}.comp .ta{flex:1;min-width:0;display:block;font-size:15px;line-height:1.5;padding:7px 0;max-height:180px;resize:none;overflow-y:auto}.comp .ta::placeholder{color:var(--text3)}.comp-quote{display:flex;align-items:flex-start;gap:8px;padding:4px 4px 0 10px;font-size:13px;color:var(--text2)}.comp-quote .quote{flex:1;margin:0;max-height:3em;overflow:hidden}.comp-files{display:flex;flex-wrap:wrap;gap:6px;padding:2px 4px 0 8px}.filechip{display:inline-flex;align-items:center;gap:5px;background:var(--bg);border-radius:7px;padding:4px 7px;font-size:12.5px;color:var(--text2)}.cur{display:inline-block;width:7px;height:14px;background:var(--text2);vertical-align:-2px;animation:blink 1s steps(2) infinite}.b.thinking{display:inline-flex;align-items:center;gap:5px;padding:13px 15px}.b.thinking .dot{width:6px;height:6px;border-radius:50%;background:var(--text3);animation:thinking 1.2s ease-in-out infinite}.b.thinking .dot:nth-child(2){animation-delay:.15s}.b.thinking .dot:nth-child(3){animation-delay:.3s}.draft{background:var(--card);border-radius:14px;padding:16px 16px 14px;margin:10px 0 4px}.draft .kv .line{display:block}.draft .top{display:flex;gap:12px;align-items:center;margin-bottom:10px}.draft .dn{font-size:16px;font-weight:600}.draft .ds{font-size:12.5px;color:var(--text3);margin-top:1px}.kv{display:flex;gap:14px;padding:8px 0;border-top:1px solid var(--line);font-size:14px;line-height:1.5}.kv .k{width:5.5em;white-space:nowrap;flex:none;color:var(--text3);font-size:13px;padding-top:1px}.kv .none{color:var(--text3)}.panel{width:344px;flex:none;background:var(--panel);border-left:1px solid var(--line);display:flex;flex-direction:column;padding:0 20px 20px;overflow-y:auto}.phead{height:54px;flex:none;display:flex;align-items:center;gap:4px;margin:0 -8px 6px;color:var(--text2);position:sticky;top:0;background:var(--panel);z-index:2}.phead .t{position:absolute;left:50%;transform:translate(-50%);max-width:calc(100% - 128px);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;pointer-events:none;font-size:14.5px;font-weight:500;color:var(--text)}.screen{background:#141416;border-radius:12px;height:186px;padding:13px 14px;font-size:12px;line-height:1.75;color:#c7c7cc;overflow:hidden;font-family:JetBrains Mono,Noto Sans Mono CJK SC,monospace;flex:none}.dark .screen{background:#0d0d0e;box-shadow:inset 0 0 0 1px #262629}.screen div{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.screen .p{color:#ff8a4c}.screen .d{color:#76767c}.screen .v{display:inline-block;width:3em;color:#76767c}.screen .cur{display:inline-block;width:7px;height:14px;background:#ff8a4c;vertical-align:-2px;animation:blink 1.1s steps(2) infinite}.screen.idle div:not(.end){opacity:.45}.screen.idle .p{color:inherit}.screen .end{color:#76767c}.cap{text-align:center;font-size:12px;color:var(--text3);margin:9px 0 22px}.caprow{display:flex;align-items:baseline;gap:12px;margin:9px 0 22px}.caprow .cap{flex:1;min-width:0;margin:0;text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.caprow .more{flex:none;font-size:12px;color:var(--text2)}.slot.pslot{margin:0 0 22px}.sech{display:flex;justify-content:space-between;align-items:center;font-size:13px;font-weight:500;color:var(--text2);margin-bottom:4px}.rt{display:flex;gap:11px;padding:9px 0;width:100%}@media(hover:hover){.rt:hover .n{color:var(--text)}}.rt .i{color:var(--ok);margin-top:2px}.rt.paused .i{color:var(--text3)}.rt .n{font-size:14px}.rt .s{font-size:12.5px;color:var(--text2);margin-top:1px}.lbl{font-size:12.5px;color:var(--text2);margin:16px 0 6px}.field{background:var(--field);border-radius:10px;padding:9px 12px;font-size:14px;line-height:1.6;display:block;width:100%}.field input,.field textarea{display:block;width:100%;font-size:14px;line-height:1.6;resize:none;overflow:hidden}.ctl{display:flex;align-items:center;gap:10px;margin-top:2px}.tog{width:38px;height:22px;border-radius:999px;background:var(--text);position:relative;flex:none;transition:transform var(--t-mid) var(--ease-in)}.tog:after{content:"";position:absolute;top:3px;left:3px;width:16px;height:16px;border-radius:50%;background:var(--bg);transform:translate(16px);transition:transform var(--t-mid) var(--ease-in)}.tog.off{background:var(--text3)}.tog.off:after{transform:translate(0)}.ctl .sp{flex:1}.pbtn{height:30px;padding:0 12px;border-radius:9px;background:var(--field);font-size:13px;font-weight:500;display:inline-flex;align-items:center;flex:none}@media(hover:hover){.pbtn:hover{filter:brightness(.97)}}.pbtn.solid{background:var(--user);color:var(--utext)}.pbtn:disabled{opacity:.4;cursor:default;filter:none}.when{background:var(--field);border-radius:10px;padding:2px 12px}.when .w{display:flex;align-items:center;gap:8px;padding:8px 0;font-size:14px;width:100%}.when .w+.w{border-top:1px solid var(--line);color:var(--text2);font-size:13px}.run{display:flex;justify-content:space-between;align-items:center;padding:8px 0;font-size:13.5px;border-top:1px solid var(--line);width:100%;color:var(--text)}.run:first-of-type{border-top:0}.run .i{color:var(--ok)}.run.bad .i{color:var(--accent)}.rule{display:flex;align-items:center;justify-content:space-between;padding:8px 0;font-size:14px;border-top:1px solid var(--line);gap:10px}.rule-wrap:first-child .rule{border-top:0}.rule-text,.rule-input{flex:1;min-width:0;text-align:left;overflow-wrap:anywhere}.rule-text,.rule-mode{cursor:pointer}.rule-text:hover,.rule-mode:hover{color:var(--accent)}.rule-confirm{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding-bottom:8px;font-size:12px}.rule-add,.rule-new{border-top:1px solid var(--line);padding:8px 0;width:100%}.rule-add{text-align:left;color:var(--text2);cursor:pointer}.rule-new .rule-input{background:var(--bg);border-radius:8px;padding:6px 10px}.rule-new .ctl{margin-top:8px}.rule .v{font-size:13px;color:var(--text2);display:flex;gap:6px;align-items:center}.phead .t+.ib{margin-left:auto}.rule .del{display:grid;flex:none;width:22px;height:22px;place-items:center;color:var(--text3);cursor:pointer;opacity:.35}.rule:hover .del,.rule:focus-within .del{opacity:1}@media(hover:none){.rule .del,.chip .del{display:grid}}.chips{display:flex;flex-wrap:wrap;gap:6px}.chip{background:var(--field);border-radius:8px;padding:5px 9px;font-size:13px;display:inline-flex;align-items:center;gap:5px}.chip .del{display:none;color:var(--text3);cursor:pointer}.chip:hover .del{display:grid}.note{font-size:12px;color:var(--text3);margin-top:8px}.bigav{display:flex;justify-content:center;margin:4px 0 2px}.bigav .av{cursor:pointer}.sprite-pick{display:flex;flex-wrap:wrap;gap:10px 12px;justify-content:center;max-width:264px;margin:12px auto 0}.sprite-pick button,.sprite-colors button:not(.pbtn){border-radius:50%;outline:2px solid transparent;outline-offset:2px}@media(hover:hover){.sprite-pick button:hover,.sprite-colors button:not(.pbtn):hover{outline-color:var(--line)}}.sprite-pick button.on,.sprite-colors button.on{outline-color:var(--accent)}.sprite-colors{display:flex;align-items:center;justify-content:center;gap:10px;margin-top:14px}.sprite-colors button:not(.pbtn){width:18px;height:18px}.sprite-colors .pbtn{margin-left:6px}.mergebar{display:flex;flex-direction:column;align-items:flex-start;gap:8px;margin-top:18px}.mergeconfirm{background:var(--field);border-radius:10px;padding:10px 12px;font-size:13px;line-height:1.6;color:var(--text2)}.mergeconfirm .acts{display:flex;gap:8px;margin-top:10px}.wl{font-size:12.5px;color:var(--text3);line-height:1.55;display:flex;gap:8px;padding:3px 0}.wl .t{flex:none;color:var(--text3);min-width:84px}.wlgroup{margin-top:22px}.pgroup+.pgroup{margin-top:26px}.pgroup>.sech+.lbl{margin-top:10px}.empty{font-size:13px;color:var(--text3);padding:6px 0}.err{margin:10px 0;padding:10px 12px;border-radius:10px;background:#ff6a2b1a;color:var(--accent);font-size:13px;line-height:1.5}.login{position:fixed;top:0;right:0;bottom:0;left:0;display:grid;place-items:center;background:var(--side)}.login .card{width:340px;background:var(--bg);border:1px solid var(--line);border-radius:18px;padding:24px 22px 20px;display:flex;flex-direction:column;align-items:center}.login .card .nm{font-size:17px;font-weight:600;margin-top:10px}.login .card .ds{font-size:12.5px;color:var(--text3);margin-top:2px}.login .field{margin:18px 0 12px}.login .btn{width:100%;justify-content:center;height:38px;border-radius:11px}.mapp{position:fixed;top:0;right:0;bottom:0;left:0;background:var(--bg);overflow:hidden}.mpane{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;flex-direction:column;min-height:0;background:var(--bg)}.mhead{display:flex;align-items:center;gap:8px;padding:calc(10px + env(safe-area-inset-top,0px)) calc(18px + env(safe-area-inset-right,0px)) 4px calc(18px + env(safe-area-inset-left,0px))}.mhead .sp{flex:1}.me{width:32px;height:32px;border-radius:50%;background:var(--field);display:grid;place-items:center;color:var(--text2)}.mpins{padding:8px 10px 6px}.mpins .pin{padding:10px 4px 8px}.mlist{padding:0 8px;overflow-y:auto;flex:1}.mlist .row{padding:10px}.mlist .gt{padding:18px 10px 4px}.gt .more{font-size:12px;color:var(--text2)}.row .pv .jt-st{margin-right:6px}.slot{margin:2px 10px 0;height:56px;display:grid;place-items:center;border:1.5px dashed color-mix(in srgb,var(--text3) 50%,transparent);border-radius:14px;font-size:12.5px;color:var(--text3)}.mlist .fold{padding:12px 10px}.fold>span:last-child{display:inline-flex;align-items:center;gap:4px}.mchat-head{display:flex;align-items:center;gap:8px;padding:calc(8px + env(safe-area-inset-top,0px)) calc(14px + env(safe-area-inset-right,0px)) 10px calc(14px + env(safe-area-inset-left,0px));border-bottom:1px solid var(--line)}.mchat-head .nm{font-size:16px;font-weight:500}.mchat-head .sp{flex:1}.mmsgs{flex:1;min-height:0;overflow-y:auto;display:flex;flex-direction:column;padding:0 14px calc(var(--comp-h, 80px) + 6px)}.mmsgs .hov{max-width:88%}.mmsgs .hov.right{max-width:80%}.mmsgs .b,.mmsgs .u{font-size:14.5px;max-width:100%}.mmsgs .col>.b.q,.mmsgs .hov:has(>.b.wide){width:88%;max-width:88%}.mmsgs .b.wide{max-width:100%}.mmsgs .draft{width:auto;padding:14px 12px 12px}.mmsgs .kv{gap:10px}.mmsgs .opt{font-size:14px;padding:10px 11px}.mmsgs .col{padding:0;margin-top:auto}.mmsgs .tt{min-width:0}.mcomp-wrap{padding:0 0 calc(22px + env(safe-area-inset-bottom,0px))}.mcomp{display:flex;flex-direction:column;gap:2px;border-radius:23px;margin:6px 12px 0;padding:6px;min-height:46px;justify-content:center}.mcomp .comp-main{display:flex;align-items:center;gap:8px}.mcomp .ta{flex:1;min-width:0;font-size:14.5px;line-height:1.5;padding:6px 0;max-height:120px;resize:none}.mcomp .ta::placeholder{color:var(--text3)}.mcomp .pl{width:32px;height:32px;display:grid;place-items:center;color:var(--text2);flex:none}.mcomp .sendbtn{width:34px;height:34px;border-radius:50%;background:var(--user);color:var(--utext);display:grid;place-items:center;flex:none}.mfull{position:fixed;top:0;right:0;bottom:0;left:0;background:var(--panel);z-index:20;overflow-y:auto}.mfull .panel{width:100%;border-left:0;min-height:100%}.mfull .phead{background:var(--panel);height:auto;min-height:calc(54px + env(safe-area-inset-top,0px));padding-top:env(safe-area-inset-top,0px)}.mtools{display:flex;align-items:center;gap:4px}.msearch{flex:1;height:34px;border-radius:10px;background:var(--field);display:flex;align-items:center;gap:8px;padding:0 11px;color:var(--text3);font-size:14px}.msearch input{flex:1;min-width:0;font-size:14px}@keyframes blink{0%,to{opacity:1}50%{opacity:0}}@keyframes spin{to{transform:rotate(360deg)}}@keyframes thinking{0%,60%,to{opacity:.35;transform:translateY(0)}30%{opacity:1;transform:translateY(-3px)}}.spin{animation:spin 1.1s linear infinite}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-thumb{background:var(--line);border-radius:4px}::-webkit-scrollbar-track{background:transparent}.side-scroll::-webkit-scrollbar-thumb{background:transparent}.side-scroll:hover::-webkit-scrollbar-thumb{background:var(--line)}.u .ufile{display:flex;align-items:center;gap:6px;font-size:13px;opacity:.78;margin-top:4px}.replybox{display:flex;align-items:center;gap:8px;margin-top:8px;background:var(--field);border-radius:999px;padding:4px 6px 4px 14px}.replybox input{flex:1;min-width:0;font-size:13.5px;padding:5px 0}.field textarea{overflow:auto}.sched-edit{flex-wrap:wrap;gap:6px}.sched-edit select,.sched-edit input{height:26px;border-radius:7px;background:var(--card);border:1px solid var(--line);padding:0 6px;font-size:13px}.sched-edit input[type=number]{width:56px}.sched-edit .rawcron{flex:1;min-width:120px;font-family:JetBrains Mono,Noto Sans Mono CJK SC,monospace}.when select,.when input{color:var(--text)}.boot{position:fixed;top:0;right:0;bottom:0;left:0;display:grid;place-items:center;background:var(--side);color:var(--text3);font-size:14px}.boot-card{background:var(--bg);border:1px solid var(--line);border-radius:16px;padding:22px;width:360px;text-align:center}.boot-card .t{font-size:15px;font-weight:600;color:var(--text)}.boot-card .d{font-size:13px;line-height:1.6;margin:8px 0 16px;color:var(--text2);word-break:break-word}.boot-card .btn{margin:0 auto}.boot-card .raw{margin-top:14px;font-size:12px;line-height:1.5;color:var(--text3);word-break:break-word}.toast{position:fixed;left:50%;bottom:calc(26px + env(safe-area-inset-bottom,0px));transform:translate(-50%);background:var(--user);color:var(--utext);font-size:13px;line-height:1.5;border-radius:12px;padding:9px 14px;max-width:520px;box-shadow:0 6px 24px #00000024;z-index:40}.upd{position:fixed;top:calc(58px + env(safe-area-inset-top,0px));left:50%;transform:translate(-50%);background:var(--user);color:var(--utext);font-size:13px;line-height:1.5;border-radius:999px;padding:8px 16px;box-shadow:0 6px 24px #0000002e;z-index:60;white-space:nowrap}@keyframes enter-rise{0%{opacity:0;transform:translateY(6px)}}@keyframes enter-side{0%{opacity:0;transform:translateY(6px)}}@keyframes enter-fade{0%{opacity:0}}@keyframes pick{0%{opacity:.6}to{opacity:1}}@keyframes icon-in{0%{opacity:0;transform:scale(.8)}}@keyframes badge-in{0%{opacity:0;transform:scale(0)}}@keyframes check-pop{0%{transform:scale(.6)}60%{transform:scale(1.08)}to{transform:scale(1)}}@keyframes row-open{0%{grid-template-rows:0fr;opacity:0}}@keyframes unfold{0%{grid-template-rows:0fr;opacity:0}}@keyframes panel-in-right{0%{opacity:0;transform:translate(12px)}}@keyframes panel-in-left{0%{opacity:0;transform:translate(-12px)}}@keyframes page-in{0%{opacity:0;transform:translate(100%)}}@keyframes popup-in{0%{opacity:0;transform:scale(.96)}}@keyframes toast-in{0%{opacity:0;transform:translate(-50%,8px) scale(.96)}}@keyframes drawer-out{to{opacity:0;transform:translate(26px)}}@keyframes sheet-out{to{opacity:0;transform:translateY(40px)}}@keyframes sheet-up{0%{opacity:0;transform:translateY(40px)}}@keyframes drawer-in{0%{transform:translate(26px);opacity:.5}}@keyframes shake{0%,to{transform:translate(0)}16%,50%,83%{transform:translate(-4px)}33%,66%{transform:translate(4px)}}.hov.enter{animation:enter-rise var(--t-mid) var(--ease-in)}.hov.enter-right{animation:enter-side var(--t-mid) var(--ease-in)}.b.enter,.att.enter,.imgcard.enter{animation:enter-rise var(--t-mid) var(--ease-in)}.enter-fade{animation:enter-fade var(--t-mid) var(--ease-in)}.sys.enter-fade .i{animation:icon-in var(--t-mid) var(--ease-in)}.think{animation:enter-fade var(--t-fast) var(--ease-in)}.think.leaving{opacity:0;transition:opacity var(--t-mid) var(--ease-out)}.optrow{display:grid;grid-template-rows:1fr;transition:grid-template-rows var(--t-mid) var(--ease-out),opacity var(--t-mid) var(--ease-out)}.optrow.away{grid-template-rows:0fr;opacity:0}.optclip{overflow:hidden;min-height:0}.opt{transition:transform var(--t-mid) var(--ease-in)}.optrow .opt.chosen{animation:pick var(--t-slow) var(--ease-in)}.optrow .opt.chosen .ck{animation:enter-fade var(--t-fast) var(--ease-in) var(--t-fast) both}.stico{position:relative;width:14px;height:14px;flex:none}.stico .i{position:absolute;top:0;right:0;bottom:0;left:0}.stico .stspin{transition:opacity var(--t-fast) var(--ease-out)}.stspin.off{opacity:0}.stic.anim{animation:enter-fade var(--t-fast) var(--ease-in)}.st.done .stic.anim{animation:check-pop var(--t-slow) var(--ease-in)}.replywrap{display:grid;grid-template-rows:1fr;animation:unfold var(--t-mid) var(--ease-in)}.replywrap.leaving{grid-template-rows:0fr;opacity:0;transition:grid-template-rows var(--t-mid) var(--ease-out),opacity var(--t-mid) var(--ease-out)}.replyclip{overflow:hidden;min-height:0}.acts.swap{display:grid;justify-items:start}.acts.swap>div{grid-area:1 / 1;display:flex;gap:8px;transition:opacity var(--t-mid) var(--ease-in)}.acts.swap>div.off{opacity:0;pointer-events:none}@media(hover:none){.message-row{touch-action:pan-y}.hov.msg>.u,.hov.msg>.b{user-select:none;-webkit-user-select:none;-webkit-touch-callout:none;position:relative;transition:transform .3s var(--ease-out)}.swipe-reply{position:absolute;right:0;top:8px;color:var(--text);pointer-events:none}.swipe-reply-inner{display:grid;place-items:center;width:34px;height:34px;border-radius:50%;background:color-mix(in srgb,var(--text) 12%,transparent)}.swipe-reply.ready .swipe-reply-inner{animation:swipe-pop .24s var(--ease-out)}.hov.msg{padding-bottom:0}.hov.msg>.tools:not(.menu){display:none}.message-popup{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1000;pointer-events:none}.message-shade{position:fixed;background:#0000007a;pointer-events:auto}.message-popup-bubble{position:fixed;pointer-events:none;transform:scale(1.02);filter:drop-shadow(0 6px 14px rgba(0,0,0,.25))}.message-popup-bubble>.u,.message-popup-bubble>.b{width:100%;max-width:none;font-size:14.5px}.message-popup-menu{position:fixed;width:160px;pointer-events:auto}.message-popup-menu .tools.menu{position:static;display:flex;flex-direction:column;gap:0;padding:4px;border:1px solid var(--line);border-radius:14px;background:var(--card);box-shadow:0 6px 24px #0000003d;animation:popup-in var(--t-fast) var(--ease-in)}.message-popup-menu .tools.menu button{display:flex;gap:12px;width:100%;height:40px;padding:0 12px;color:var(--text);white-space:nowrap}}@keyframes swipe-pop{50%{transform:scale(1.12)}}.panelwrap{position:relative;width:344px;flex:none;height:100%}.panelwrap.off{width:0}.panelwrap.detail{width:min(560px,45vw)}.panelwrap .panel{position:absolute;right:0;height:100%;transition:transform var(--t-slow) var(--ease-in),opacity var(--t-slow) var(--ease-in)}.panelwrap.off .panel{transform:translate(100%);opacity:0;pointer-events:none;transition-duration:var(--t-mid);transition-timing-function:var(--ease-out)}.pbody{flex:none}.pbody.from-right{animation:panel-in-right var(--t-mid) var(--ease-in)}.pbody.from-left{animation:panel-in-left var(--t-mid) var(--ease-in)}.screen div.new{animation:enter-fade var(--t-mid) var(--ease-in)}.screen .cur{animation:blink 1s steps(2) infinite}.srow,.rtrow{display:grid;grid-template-rows:1fr}.srow.enter,.rtrow.enter{animation:row-open var(--t-mid) var(--ease-in)}.srow.leave,.rtrow.leave{grid-template-rows:0fr;opacity:0;transition:grid-template-rows var(--t-mid) var(--ease-out),opacity var(--t-mid) var(--ease-out)}.srowclip,.rtclip{overflow:hidden;min-height:0}.badge{animation:badge-in var(--t-mid) var(--ease-in)}.row,.pin,.ib,.frow,.tools button,.btn,.pbtn,.rt,.comp .sendbtn,.mcomp .sendbtn{transition:transform var(--t-mid) var(--ease-in),opacity var(--t-fast) var(--ease-in)}.comp .sendbtn:disabled,.mcomp .sendbtn:disabled{background:var(--sel);color:var(--text3);cursor:default;transform:none}.comp-quote{animation:enter-rise var(--t-mid) var(--ease-in)}.comp-quote.leaving{opacity:0;transform:translateY(6px);transition:opacity var(--t-mid) var(--ease-out),transform var(--t-mid) var(--ease-out)}button:not(:disabled):active{transform:scale(.97);transition-timing-function:var(--ease-out)}.upd:not(:disabled):active{transform:translate(-50%) scale(.97)}.mpane.list,.mpane.chat{will-change:transform}.mpane.list{transition:transform var(--t-slow) var(--ease-in)}.mpane.list.back{transform:translate(-30%)}.mpane.chat{animation:page-in var(--t-slow) var(--ease-in)}.mpane.chat.out{opacity:0;transform:translate(100%);transition:transform var(--t-mid) var(--ease-out),opacity var(--t-mid) var(--ease-out)}.mfull{animation:sheet-up var(--t-slow) var(--ease-in)}.mfull.leaving{pointer-events:none;animation:sheet-out var(--t-mid) var(--ease-out) forwards}.setpage{position:fixed;top:0;right:0;bottom:0;left:0;display:flex;background:var(--bg);animation:page-in var(--t-slow) var(--ease-in)}.setpage.leaving{pointer-events:none;animation:drawer-out var(--t-mid) var(--ease-out) forwards}.setnav{width:216px;flex:none;display:flex;flex-direction:column;gap:2px;padding:22px 12px 16px;border-right:1px solid var(--line)}.setnavtitle{font-size:17px;font-weight:600;padding:0 10px 14px}.setnav .sp{flex:1}.navrow{display:flex;align-items:center;gap:6px;height:34px;padding:0 10px;border-radius:9px;font-size:14px;color:var(--text);background:transparent;text-align:left}@media(hover:hover){.navrow:hover{background:var(--field)}}.navrow.sel{background:var(--field);font-weight:500}.setmain{flex:1;min-width:0;overflow-y:auto;padding:26px 30px 60px}.setmain>*{max-width:640px}.setmain .lbl:first-child{margin-top:0}.setintro{margin-bottom:24px}.setintro .h{font-size:18px;font-weight:600}.setintro .d{margin-top:6px;font-size:13px;line-height:1.65;color:var(--text2)}.group{display:flex;flex-direction:column;gap:8px}.group+.group{margin-top:24px}.group>.lbl,.group>.note,.group>.ctl{margin:0}.group>.lbl:not(:first-child){margin-top:8px}.lbl.sub{font-size:12px;color:var(--text3)}.lblrow{display:flex;align-items:baseline;justify-content:space-between;gap:10px}.lblrow .lbl{margin:0}.lblrow .link{font-size:12.5px;color:var(--text2)}.sline{font-size:13px;color:var(--text2)}.srow{display:flex;flex-direction:column;gap:6px}.formcard{background:var(--field);border-radius:10px;padding:12px}.formcard .field{background:var(--bg)}.formcard .pbtn:not(.solid){background:var(--bg)}.sfoot{display:flex;align-items:center;gap:10px;margin-top:24px}.sfoot .sp{flex:1}.okline{font-size:12.5px;color:var(--ok)}.badline{font-size:12.5px;color:var(--accent)}.savetoast{position:fixed;top:calc(14px + env(safe-area-inset-top,0px));right:18px;z-index:60;padding:6px 12px;border-radius:999px;background:var(--card);box-shadow:0 4px 16px #0000001f;animation:enter-fade var(--t-fast) var(--ease-in)}.setpage.narrow .setintro .h{display:none}.sethead{display:flex;align-items:center;gap:6px;min-height:calc(52px + env(safe-area-inset-top,0px));padding:env(safe-area-inset-top,0px) calc(10px + env(safe-area-inset-right,0px)) 0 calc(10px + env(safe-area-inset-left,0px));border-bottom:1px solid var(--line)}.sethead .t{font-size:15px;font-weight:600}.setpage.narrow{flex-direction:column}.setpage.narrow .sethead{flex:none}.setpage.narrow .setbody,.setpage.narrow .setmain{flex:1;overflow-y:auto;padding:8px 12px 40px}.setitem{display:flex;align-items:center;justify-content:space-between;width:100%;height:46px;padding:0 12px;border-radius:10px;font-size:15px;background:transparent;color:var(--text);text-align:left}@media(hover:hover){.setitem:hover{background:var(--field)}}.setitem svg{color:var(--text3)}.setpage.narrow .setbody{padding:16px 16px 40px}.setpage.narrow .setbody>.setitem{position:relative;height:48px;padding:0 14px 0 16px;border-radius:0;background:var(--field)}.setpage.narrow .setbody>.setitem:first-child{border-radius:12px 12px 0 0}.setpage.narrow .setbody>.setitem:last-child{border-radius:0 0 12px 12px}.setpage.narrow .setbody>.setitem+.setitem:before{content:"";position:absolute;left:16px;right:0;top:0;height:1px;background:var(--line)}.setpage.narrow .setbody>.setitem:active{background:var(--sel)}.dev{display:flex;align-items:center;gap:10px;padding:10px 2px;border-top:1px solid var(--line)}.dev:first-of-type{border-top:0}.dev .n{font-size:14px;font-weight:500}.dev .tm{font-size:12.5px;color:var(--text3)}.dev .sp{flex:1}.dev .del{font-size:12.5px;color:var(--text2)}@media(hover:hover){.dev .del:hover{color:var(--danger)}}.tog:disabled{opacity:.5;cursor:default}.tz{position:relative}.tzlist,.amenu{padding:4px;border-radius:10px;background:var(--bg);box-shadow:0 8px 28px #00000029;border:1px solid var(--line)}.tzlist,.amenu{transform-origin:top left;animation:popup-in var(--t-mid) var(--ease-in)}.toast{animation:toast-in var(--t-mid) var(--ease-in)}.tzlist{position:absolute;z-index:5;top:calc(100% + 4px);left:0;right:0;max-height:240px;overflow-y:auto}.amenu{position:fixed;z-index:50;min-width:160px}.tzlist button,.amenu button{display:block;width:100%;padding:7px 10px;border-radius:7px;font-size:13.5px;text-align:left;background:transparent;color:var(--text)}.tzlist button.sel,.amenu button.sel{background:var(--field)}@media(hover:hover){.tzlist button:hover,.amenu button:hover{background:var(--field)}}.pick{height:32px;min-width:72px;padding:0 10px;border-radius:9px;background-color:var(--field);color:var(--text);font-size:14px;border:none}select.pick{padding-right:28px;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%238e8e93' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 10px center;-webkit-appearance:none;-moz-appearance:none;appearance:none;text-overflow:ellipsis}.setmain .pick{height:40px;border-radius:10px;padding-left:12px}.seg{position:relative;display:inline-grid;grid-template-columns:repeat(var(--seg-count),minmax(0,1fr));align-self:flex-start;max-width:100%;gap:2px;padding:3px;border-radius:10px;background:var(--field)}.seg:before{content:"";position:absolute;top:3px;bottom:3px;left:3px;width:calc((100% - 6px - (var(--seg-count) - 1) * 2px) / var(--seg-count));border-radius:8px;background:var(--card);box-shadow:0 1px 2px #0000001a;transform:translate(calc(var(--seg-index) * (100% + 2px)));transition:transform var(--t-slow) var(--ease-in)}.dark .seg:before{background:#3a3a3e}.seg>button{position:relative;text-align:center;height:34px;padding:0 14px;border-radius:8px;font-size:13.5px;color:var(--text2);white-space:nowrap;transition:transform var(--t-mid) var(--ease-in)}.seg>button.on{color:var(--text);font-weight:500}.seg>button:disabled{cursor:default}.field.ro{color:var(--text2)}.kvcard{background:var(--field);border-radius:12px;padding:0 14px}.kvrow{display:flex;align-items:baseline;justify-content:space-between;gap:16px;padding:12px 0;font-size:14px}.kvrow+.kvrow{border-top:1px solid var(--line)}.kvrow .k{flex:none;color:var(--text2)}.kvrow .v{min-width:0;text-align:right;overflow-wrap:anywhere}.field.mono{font-family:var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);font-size:12.5px;word-break:break-all}.pick.grow{flex:1;min-width:0}.roster{background:var(--field);border-radius:10px;padding:2px 12px}.rrow{display:flex;gap:10px;padding:10px 0;width:100%}.rrow+.rrow{border-top:1px solid var(--line)}.rbtn{text-align:left}.rclamp{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.rrow>.tog,.rrow>.rmove,.rrow>.rorder{align-self:center}.rrow>.rmove{width:28px;height:28px;color:var(--text3)}.rrow>.rmove:disabled{opacity:.35;cursor:default}.rmove .up{transform:rotate(180deg)}.rorder{flex:none;width:20px;height:20px;border-radius:50%;background:var(--bg);color:var(--text2);font-size:11.5px;font-weight:600;display:grid;place-items:center}.rempty{padding:12px 0;font-size:13px;color:var(--text3)}.roster>.rempty+.maddrow{border-top:1px solid var(--line)}.lbl-aside{margin-left:8px;color:var(--text3)}a.lbl-aside{color:var(--accent)}.score-row{margin-top:6px}.score-head{display:flex;justify-content:space-between;font-size:14px}.score-head span{color:var(--text2);font-size:13px;font-variant-numeric:tabular-nums}.score-range{display:block;width:100%;margin:8px 0 0;accent-color:var(--accent)}.score-ticks{position:relative;height:26px;margin:0 8px}.score-ticks button{position:absolute;top:2px;transform:translate(-50%);font-size:12px;color:var(--text3);white-space:nowrap;padding:2px 4px}.score-ticks button.first{transform:translate(-8px)}.score-ticks button.last{transform:translate(calc(-100% + 8px))}.score-ticks button[aria-pressed=true]{color:var(--accent);font-weight:600}.skill-doc h1,.skill-doc h2{font-size:16px;margin:0 0 8px}.skill-doc>:first-child{margin-top:0}.skill-doc{margin-top:16px;padding:16px 18px;border-radius:10px;background:var(--field);font-size:14px}.skill-overwrite{gap:8px;font-size:13.5px;margin-top:4px}.skill-overwrite .rcheck{margin:0}.rrow>.rgo{flex:none;color:var(--text3);margin-top:2px}.roster>.maddrow:not(:first-child){border-top:1px solid var(--line)}.rcheck{flex:none;width:15px;height:15px;margin:4px 0 0;accent-color:var(--accent)}.rrow.gone{opacity:.6}.rremove{flex:none;width:22px;height:22px;margin-top:2px;border-radius:6px;display:grid;place-items:center;color:var(--text3)}@media(hover:hover){.rremove:hover{color:var(--accent);background:var(--bg)}}.rmain{min-width:0;flex:1}.rname{font-size:14px;display:flex;align-items:center;gap:6px;flex-wrap:wrap}.rtags{display:inline-flex;gap:4px;flex-wrap:wrap}.rtag{font-size:11.5px;color:var(--text2);background:var(--bg);border-radius:6px;padding:1px 6px}.rtag.bad{color:var(--accent)}.rprov{display:block;font-size:12px;color:var(--text3);margin-top:2px}.rfoot{display:flex;gap:8px;align-items:center;margin-top:8px}.think-levels{margin-top:10px;background:var(--bg);border-radius:9px;padding:2px 10px 10px}.thinkhead{display:flex;align-items:center;gap:8px;width:100%;padding:8px 0 4px;text-align:left}.thinkhead .lbl{margin:0}.thinkhead .note{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.thinkrows{display:grid;gap:2px}.thinkrow{display:flex;align-items:center;gap:8px}.thinkrow .tname{flex:none;width:40px;font-size:12.5px;color:var(--text2)}.thinkrow .ttext{flex:1;min-width:0;background:var(--field);border-radius:8px;padding:6px 10px;font-size:13px}.thinkrow .rremove{margin-top:0}.thinkrow .rremove.still{cursor:default}.mcard{background:var(--field);border-radius:12px;padding:0 14px}.mcard>*+*{border-top:1px solid var(--line)}.mline{display:flex;align-items:center;justify-content:space-between;gap:16px;min-height:46px;font-size:14px}.mline .k{flex:none}.mrow{display:flex;flex-direction:column;gap:3px;width:100%;padding:11px 0 10px;text-align:left}.mtop{display:flex;align-items:center;gap:8px;min-width:0}.mtop .sp{flex:1}.mtop>.i{flex:none;color:var(--text3)}.mname{min-width:0;font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mrole{display:inline-block;margin-right:6px;padding:0 6px;border-radius:5px;background:var(--bg);font-size:11px;line-height:18px;vertical-align:1px;color:var(--text2)}.mbad{flex:none;font-size:12px;color:var(--accent)}.mprev{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;font-size:13px;line-height:1.5;color:var(--text2)}.model-use-inline{padding:0 16px 16px 32px}.model-use-warning{color:var(--accent);font-size:12px;margin-left:8px}@media(max-width:600px){.model-use-inline{padding-left:16px}}.mrow.gone .mname,.mrow.gone .mprev{color:var(--text3)}.caps{flex:none;display:inline-flex;align-items:center;gap:7px;color:var(--text3)}.caps>span{display:inline-flex}.caps .ctx{font-size:11.5px;font-variant-numeric:tabular-nums}.maddrow{display:flex;align-items:center;gap:8px;width:100%;min-height:46px;font-size:14px}.maddrow .i{color:var(--text2)}.mline .vals{display:flex;align-items:center;justify-content:flex-end;gap:14px;min-width:0}.pbtn.danger{color:var(--accent)}.mline.danger{width:100%;justify-content:center;color:var(--accent)}.mline.danger:disabled{opacity:.4;cursor:default}.subback{display:inline-flex;align-items:center;gap:2px;margin:-6px 0 14px -6px;padding:4px 8px 4px 4px;border-radius:8px;font-size:13px;color:var(--text2)}@media(hover:hover){.subback:hover{background:var(--field)}}.setpage.narrow .subback{display:none}.kvrow .k.kicon{display:inline-flex;align-items:center;gap:6px}.kvrow .k.kicon .i{color:var(--text3)}.mfind{display:flex;align-items:center;gap:8px;height:44px;color:var(--text3)}.mfind input{flex:1;min-width:0;height:100%;border:0;background:transparent;color:var(--text);font-size:14px;outline:none}.mempty{padding:12px 0;font-size:13px;color:var(--text3)}.mgroup{display:flex;align-items:center;gap:8px;width:100%;min-height:44px;font-size:14px;text-align:left}.mgroup .n{flex:1;min-width:0}.mgroup .c{font-size:13px;color:var(--text3)}.mgroup .i{color:var(--text3)}.madd{display:flex;align-items:center;gap:10px;width:100%;padding:11px 0 11px 14px;text-align:left}.madd .mname{flex:1;font-weight:400}.madd .mtog{flex:none;color:var(--text3)}.madd.on .mtog{color:var(--accent)}.madd:disabled{cursor:default}.madd:disabled .mtog{opacity:.5}@media(hover:hover){.mgroup:hover .i,.madd:not(:disabled):hover .mtog{color:var(--text)}.madd.on:not(:disabled):hover .mtog{color:var(--accent)}}.pmctx{width:92px;height:26px;padding:0 8px;border-radius:7px;background:var(--bg);color:var(--text);font-size:12.5px}.testrow{display:flex;align-items:center;flex-wrap:wrap;gap:10px;margin-top:12px}.testout{display:flex;flex-direction:column;gap:8px;min-width:0}.chip.on{background:var(--user);color:var(--utext)}.login .card{animation:enter-rise var(--t-slow) var(--ease-in)}.login .field.shake{animation:shake var(--t-slow) var(--ease-out)}.b.jobcard .tt{display:grid;grid-template-columns:auto minmax(0,1fr);grid-template-areas:"av title" "av st";column-gap:10px;row-gap:2px;align-items:center}.b.jobcard .jav{grid-area:av;display:flex}.b.jobcard .jt{grid-area:title;line-height:1.45}.b.jobcard .tt .st{grid-area:st;margin-left:0;justify-self:start;font-size:12.5px}.b.jobcard{min-width:min(20em,100%);cursor:pointer;transition:transform var(--t-mid) var(--ease-in)}.b.jobcard:active{transform:scale(.99)}@media(hover:hover){.b.jobcard:hover{background:var(--field)}}.b.jobcard:focus-visible{outline:2px solid var(--accent);outline-offset:2px}.meta.bad{color:var(--accent)}button.screen,.cap.jd-open{display:block;width:100%;text-align:left;cursor:pointer}.cap.jd-open{text-align:center}@media(hover:hover){.screen.jd-open:hover{background:#1b1b1e}}@media(hover:hover){.cap.jd-open:hover{color:var(--text2)}}.jd-allrow{display:flex;justify-content:center;margin:-14px 0 18px}.jd-all{display:inline-flex;align-items:center;gap:2px;font-size:12.5px;color:var(--text3)}@media(hover:hover){.jd-all:hover{color:var(--text)}}.expand{display:grid;grid-template-rows:0fr;opacity:0;transition:grid-template-rows var(--t-mid) var(--ease-out),opacity var(--t-mid) var(--ease-out)}.expand.open{grid-template-rows:1fr;opacity:1;transition-timing-function:var(--ease-in)}.expand>div{min-height:0;overflow:hidden}.jd-embedded{height:100%;animation:panel-in-right var(--t-fast) var(--ease-in)}.jd-overlay{position:fixed;top:0;right:0;bottom:0;left:0;z-index:30;display:flex;justify-content:flex-end}.jd{width:100%;height:100%;background:var(--bg);border-left:1px solid var(--line);display:flex;flex-direction:column}.jd-overlay .jd{width:min(560px,55vw);box-shadow:-18px 0 48px #0000001a;animation:drawer-in var(--t-slow) var(--ease-in)}.jd-overlay.leaving,.fpwrap.leaving{pointer-events:none;opacity:0;transition:opacity var(--t-mid) var(--ease-out)}.jd-overlay.leaving .jd,.fpwrap.leaving .fp{animation:drawer-out var(--t-mid) var(--ease-out) forwards}.jdhead{height:54px;flex:none;display:flex;align-items:center;gap:4px;padding:0 12px 0 10px;border-bottom:1px solid var(--line);color:var(--text2)}.jdhead .t{flex:1;text-align:center;font-size:14.5px;font-weight:500;color:var(--text)}.jdbody{flex:1;min-height:0;overflow-y:auto;padding:18px 24px 28px}.jd-title{font-size:19px;font-weight:600;line-height:1.4}.jd-meta{display:flex;flex-wrap:wrap;align-items:center;gap:4px 14px;font-size:13px;color:var(--text2);margin-top:7px}.jd-meta.dim{color:var(--text3);font-size:12.5px}.jd-owner{display:inline-flex;align-items:center;gap:5px}.jt-st{display:inline-flex;align-items:center;gap:4px;font-size:12.5px;color:var(--text2);white-space:nowrap}.jt-st .i{color:var(--text3)}.jt-st.live .i{color:var(--accent)}.jt-st.ok .i{color:var(--ok)}.jt-st.bad,.jt-st.bad .i{color:var(--accent)}.jd-reason{font-size:13.5px;color:var(--accent);margin-top:6px}.jd-instruction{font-size:14px;line-height:1.62;color:var(--text2);background:var(--bubble);border-radius:12px;padding:9px 12px;margin-top:12px;white-space:pre-wrap;overflow-wrap:anywhere}.jd-timeline{display:flex;flex-direction:column;gap:2px;margin-top:16px}.lbl+.jd-instruction,.lbl+.jd-timeline{margin-top:0}.jd-timeline>.jd-text,.jd-timeline>.jd-textrow{margin:6px 0}.jd-text{font-size:15px;line-height:1.62;overflow-wrap:anywhere}.jd-mine{align-self:flex-end;max-width:86%;background:var(--field);border-radius:12px;padding:6px 11px;font-size:14px;line-height:1.55;white-space:pre-wrap;overflow-wrap:anywhere}.jd-think>button,.jd-tool-head{display:flex;align-items:center;gap:9px;width:calc(100% + 16px);margin:0 -8px;padding:7px 8px;border-radius:8px;font-size:13.5px;line-height:1.4;color:var(--text2);text-align:left;transition:transform var(--t-mid) var(--ease-in)}.jd-think>button{color:var(--text3)}.jd-think-head{display:flex;align-items:center;gap:6px;font-size:12.5px;line-height:1.4;color:var(--text3);text-align:left}.jd-think-head .ico{display:grid;place-items:center;width:14px;flex:none}@media(hover:hover){.jd-think-head:hover{color:var(--text2)}}.jd-tool-head .blb{flex:none;display:grid;place-items:center;color:var(--text3)}.jd-think-body{font-size:13px;line-height:1.6;color:var(--text2);border-left:2px solid var(--line);padding:2px 0 2px 14px;margin:2px 0 6px 6px;white-space:pre-wrap;overflow-wrap:anywhere}.jd-textrow .jd-think-in{margin-bottom:4px}.jd-tool{border-radius:10px}@media(hover:hover){.jd-think>button:hover,.jd-tool-head:hover{background:var(--bubble)}}.jd-think .ico,.jd-tool .ico{display:grid;place-items:center;width:14px;color:var(--text3);flex:none}.jd-tool.bad .ico{color:var(--accent)}.jd-think .tt,.jd-tool-head .tt{display:block;flex:1;min-width:0;font-weight:400;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.jd-tool-head .mono{font-size:12.5px}.jd-tool-head .tt>span+.mono{margin-left:3px}.jd-tool-head .tm{flex:none;font-size:12px;color:var(--text3)}.jd-tool.open .jd-tool-body{padding:2px 0 8px 23px;display:flex;flex-direction:column;gap:6px}.jd-arg,.jd-out{background:var(--field);border-radius:8px;padding:8px 10px;font-size:12.5px;line-height:1.6;overflow:auto;white-space:pre-wrap;overflow-wrap:anywhere}.jd-out{color:var(--text2)}.jd-kv{display:flex;gap:10px;font-size:12.5px;color:var(--text2)}.jd-kv.jd-path{align-self:flex-start;max-width:100%;text-decoration:underline;text-decoration-color:var(--text3);text-underline-offset:3px;overflow-wrap:anywhere}.jd-kv.jd-path:hover{color:var(--text)}.jd-kv-wrap{display:flex;align-items:baseline;gap:10px;font-size:12.5px;color:var(--text2)}.jd-kv-len{flex:none}.jd-diff{background:var(--field);border-radius:8px;padding:6px 0;overflow:hidden}.jd-diff .dl{display:flex;gap:5px;padding:0 10px;font-size:12.5px;line-height:1.55;white-space:pre-wrap;overflow-wrap:anywhere}.jd-diff .sg{flex:none;width:8px;color:var(--text3);font-family:JetBrains Mono,monospace}.jd-diff .del{background:#e5484d1f}.jd-diff .del .sg{color:#c33236}.jd-diff .add{background:#22a06524}.jd-diff .add .sg{color:var(--ok)}.jd-more{font-size:12.5px;color:var(--text2);padding:3px 0 0}@media(hover:hover){.jd-more:hover{color:var(--text)}}.jd-file{display:inline-flex;align-items:center;gap:5px;font-size:12.5px;color:var(--text2);text-decoration:underline;text-decoration-color:var(--text3);text-underline-offset:3px}.jd-report{font-size:14px;line-height:1.65;overflow-wrap:anywhere}.jd-report h1,.jd-report h2,.jd-report h3{font-size:14px;font-weight:600;margin:12px 0 4px}.jd-report p+p,.jd-report ul+p,.jd-report pre+p{margin-top:6px}.jd-report ul,.jd-report ol{padding-left:18px;margin-top:4px}.jd-report code{font-family:JetBrains Mono,monospace;font-size:12.5px;background:var(--field);border-radius:5px;padding:1px 5px}.jd-report pre{background:var(--field);border-radius:10px;padding:9px 11px;overflow-x:auto;margin-top:6px}.jd-report pre code{background:none;padding:0}.jd-report a{text-decoration:underline;text-decoration-color:var(--text3);text-underline-offset:3px}.jd-foot{flex:none;display:flex;align-items:center;gap:8px;padding:12px 24px 18px;border-top:1px solid var(--line)}.jd-foot input{flex:1;min-width:0;height:34px;border-radius:10px;background:var(--field);padding:0 12px;font-size:14px}.jd-filters{display:flex;align-items:center;gap:8px;margin-bottom:12px}.jd-filters .sp{flex:1}.jd-filters .pick{height:30px;font-size:13px}.jd-filters .dim{font-size:12.5px;color:var(--text3)}.jd-rows{display:grid;grid-template-columns:26px minmax(0,1fr) auto auto auto;column-gap:10px}.jd-row{grid-column:1 / -1;display:grid;grid-template-columns:subgrid;align-items:center;gap:10px;padding:9px 8px;border-radius:10px;border-top:1px solid var(--line);transition:transform var(--t-mid) var(--ease-in)}.jd-row:first-child{border-top:0}@media(hover:hover){.jd-row:hover{background:var(--bubble)}}.jd-row .n{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.jd-row .tm,.jd-row .du{font-size:12.5px;color:var(--text3);white-space:nowrap}.jd-row .du{min-width:52px;text-align:right}.jd-morebtn{margin-top:14px}.fpwrap{position:fixed;top:0;right:0;bottom:0;left:0;z-index:40;display:flex;justify-content:flex-end;background:transparent;animation:enter-fade var(--t-mid) var(--ease-in)}.fp{width:55%;min-width:520px;max-width:920px;height:100%;background:var(--bg);border-left:1px solid var(--line);box-shadow:-18px 0 48px #0000001a;display:flex;flex-direction:column;animation:drawer-in var(--t-slow) var(--ease-in)}.fp.full{width:100%;max-width:none}.fphead{height:54px;flex:none;display:flex;align-items:center;gap:2px;padding:0 10px;border-bottom:1px solid var(--line)}.fp-file-icon{flex:none;color:var(--text2);margin:0 8px}.fphead .fpt{flex:1;min-width:0}.fphead .n{font-size:14px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.fphead .m{font-size:12px;color:var(--text2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:1px}.fp-act{color:var(--text2)}.fp-body{flex:1;min-height:0;overflow-y:auto;padding:14px 18px 24px;display:flex;flex-direction:column;gap:10px}.fp-body.center,.fp-center{align-items:center;justify-content:center;flex:1}.fp-nofile{display:flex;flex-direction:column;align-items:center;gap:10px;color:var(--text2);font-size:13.5px;text-align:center;padding:28px 12px}.fp-note{flex:none;font-size:12.5px;color:var(--text2);background:var(--bubble);border-radius:8px;padding:6px 10px}.fp-img{display:flex;justify-content:center}.fp-img button{max-width:100%}.fp-img img{display:block;max-width:100%;height:auto;border-radius:8px}.fp-frame{flex:1;width:100%;border:1px solid var(--line);border-radius:10px;background:var(--panel)}.fp-md{font-size:14px;line-height:1.65;overflow-wrap:anywhere}.fp-codebar{flex:none;display:flex;align-items:center;gap:10px;font-size:12.5px}.fp-codebar .pbtn{height:24px;padding:0 10px;font-size:12px}.fp-code{flex:none;font-size:12.5px;line-height:1.6;background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:8px 0;overflow-x:auto}.fp-code .cl{display:flex;align-items:flex-start}.fp-code .ln{flex:none;width:44px;text-align:right;padding-right:10px;color:var(--text3);-webkit-user-select:none;user-select:none;font-variant-numeric:tabular-nums}.fp-code .ct{white-space:pre;min-width:0;padding-right:12px}.fp-code.wrap .ct{white-space:pre-wrap;overflow-wrap:break-word}.fp-table-wrap{flex:none;min-width:0;overflow:auto;border:1px solid var(--line);border-radius:10px;max-height:100%}.fp-table{width:100%;border-collapse:collapse;font-size:12.5px;white-space:nowrap}.fp-table th,.fp-table td{border-bottom:1px solid var(--line);padding:5px 12px;text-align:left}.fp-table th{position:sticky;top:0;background:var(--panel);color:var(--text2);font-weight:500}.fp-table td{font-family:JetBrains Mono,Noto Sans Mono CJK SC,monospace}.fp-table .numeric{text-align:right}@media(max-width:767px){.jd-overlay{background:var(--bg)}.jd-overlay .jd{width:100%;min-width:0;max-width:none;border-left:0;box-shadow:none;animation:sheet-up var(--t-slow) var(--ease-in)}.jdbody{padding:14px 16px 26px}.jdhead{height:auto;min-height:calc(54px + env(safe-area-inset-top,0px));padding-top:env(safe-area-inset-top,0px)}.jdhead .t{text-align:left;font-size:15px;font-weight:600}.fpwrap{background:var(--bg)}.fp{width:100%;min-width:0;max-width:none;border-left:0;box-shadow:none;animation:sheet-up var(--t-slow) var(--ease-in)}.jd-overlay.leaving .jd,.fpwrap.leaving .fp{animation:sheet-out var(--t-mid) var(--ease-out) forwards}.fp-wide-btn{display:none}.fphead{height:auto;min-height:calc(54px + env(safe-area-inset-top,0px));padding-top:env(safe-area-inset-top,0px)}.fp-body{padding:12px 14px 22px}.jd-foot{padding:10px 14px calc(16px + env(safe-area-inset-bottom,0px))}.jd-rows{grid-template-columns:26px minmax(0,1fr) auto}.jd-row{row-gap:2px}.jd-row .tm,.jd-row .du{grid-column:2 / 4}.setmain .pbtn{height:36px;padding:0 14px;border-radius:10px}}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation:none!important;transition-property:opacity!important;transition-duration:var(--t-fast)!important;transition-timing-function:linear!important;transition-delay:0s!important}button:not(:disabled):active,.b.jobcard:active,.message-popup-bubble{transform:none}.upd:not(:disabled):active{transform:translate(-50%)}.mpane.chat:not(.out),.setpage:not(.leaving),.mfull:not(.leaving),.jd-overlay:not(.leaving) .jd,.jd-embedded,.fpwrap:not(.leaving) .fp,.tools.menu,.amenu,.tzlist,.toast,.hov.enter,.hov.enter-right,.b.enter,.att.enter,.imgcard.enter{animation:enter-fade var(--t-fast) linear!important}.spin{animation:spin 1.1s linear infinite!important}}.delegation-card .delegation-text{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;color:var(--text2);margin-top:10px;line-height:1.55;overflow-wrap:anywhere;width:100%}.delegation-card .delegation-text.expanded{display:block;white-space:pre-wrap}.delegation-card .delegation-job{display:flex;align-items:center;gap:8px;width:100%;margin-top:10px;padding:9px 12px;border-radius:10px;background:var(--card);color:var(--text);font-size:13.5px;text-align:left}.delegation-card .delegation-job>span{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.delegation-card .delegation-job>svg{flex:none;color:var(--text3)}.delegation-card .delegation-job.running>svg:first-child{color:var(--accent)}.delegation-card .delegation-job.done>svg:first-child{color:var(--ok)}.delegation-card .delegation-job.waiting>svg:first-child{color:var(--accent)}.delegation-card .delegation-job:is(.stuck,.failed)>svg:first-child{color:var(--danger)}.delegation-card .b.q{width:100%;margin-top:10px;padding:12px;background:var(--card)}.delegation-actions{display:flex;flex-wrap:wrap;gap:16px;margin-top:12px;color:var(--accent);font-size:13px}.delegation-card .st.bad{color:var(--danger)}.forward-label{display:flex;align-items:center;gap:5px;color:var(--accent);font-size:12px;font-weight:600;margin-bottom:5px}.delegation-panel{display:flex;align-items:center;gap:6px;width:100%;padding:10px 4px;color:var(--text2);font-size:13px;border-bottom:1px solid var(--line)}.side-scroll,.msgs,.comp .ta,.panel,.mlist,.mmsgs,.mfull,.setmain,.tzlist,.jdbody{overscroll-behavior:contain}.msgs,.mmsgs{overflow-x:hidden}