@ljwei-stak/dsh-model-route-bot 0.66.4 → 0.67.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.
Files changed (271) hide show
  1. package/.dsh-plugin/bot-product.mjs +81 -5
  2. package/.dsh-plugin/client.js +17490 -1791
  3. package/README.i18n.yaml +4 -4
  4. package/README.md +409 -364
  5. package/README.zh.md +409 -364
  6. package/apps/integration-client/README.md +31 -7
  7. package/apps/integration-client/api.mjs +14 -3
  8. package/apps/integration-client/binding-editor.jsx +308 -109
  9. package/apps/integration-client/binding-model.mjs +262 -0
  10. package/apps/integration-client/binding.css +144 -0
  11. package/apps/integration-client/bot-model-status.mjs +18 -0
  12. package/apps/integration-client/bot-profile-identity.jsx +197 -0
  13. package/apps/integration-client/bot-profile.css +57 -0
  14. package/apps/integration-client/bot-profile.mjs +97 -0
  15. package/apps/integration-client/bot-settings-dialog.css +18 -0
  16. package/apps/integration-client/bot-settings-dialog.jsx +111 -0
  17. package/apps/integration-client/bot-thread-header-bridge.css +20 -0
  18. package/apps/integration-client/bot-thread-header.jsx +278 -0
  19. package/apps/integration-client/bot-threads-panel.jsx +378 -0
  20. package/apps/integration-client/bot-threads.css +169 -0
  21. package/apps/integration-client/chat-design.mjs +250 -0
  22. package/apps/integration-client/chat-ui.jsx +175 -0
  23. package/apps/integration-client/chat.css +477 -0
  24. package/apps/integration-client/composer-draft-binding.mjs +50 -0
  25. package/apps/integration-client/composer-draft-bound.jsx +14 -0
  26. package/apps/integration-client/composer-draft-host.jsx +142 -0
  27. package/apps/integration-client/composer-draft-session.jsx +287 -0
  28. package/apps/integration-client/composer-draft-witness.mjs +115 -0
  29. package/apps/integration-client/composer-draft.css +4 -0
  30. package/apps/integration-client/composer-draft.mjs +322 -0
  31. package/apps/integration-client/contact-attention.jsx +54 -0
  32. package/apps/integration-client/data-panel.jsx +439 -0
  33. package/apps/integration-client/data.css +69 -0
  34. package/apps/integration-client/desktop-bridge.mjs +1 -0
  35. package/apps/integration-client/desktop-http-socket.mjs +49 -0
  36. package/apps/integration-client/desktop-keyboard.mjs +32 -0
  37. package/apps/integration-client/desktop-pane.jsx +99 -30
  38. package/apps/integration-client/desktop-stream.mjs +13 -3
  39. package/apps/integration-client/desktop-tools.jsx +19 -0
  40. package/apps/integration-client/desktop-touch.mjs +27 -0
  41. package/apps/integration-client/desktop.css +41 -0
  42. package/apps/integration-client/independent-chat-controller.mjs +224 -0
  43. package/apps/integration-client/independent-chat-entry.jsx +61 -0
  44. package/apps/integration-client/independent-chat-navigation.mjs +21 -0
  45. package/apps/integration-client/independent-chat-page.jsx +148 -0
  46. package/apps/integration-client/independent-chat-rich.jsx +64 -0
  47. package/apps/integration-client/independent-chat-rich.mjs +30 -0
  48. package/apps/integration-client/independent-chat.css +73 -0
  49. package/apps/integration-client/index.jsx +24 -16
  50. package/apps/integration-client/library-panel.jsx +4 -1
  51. package/apps/integration-client/licenses/jsqr-1.4.0-LICENSE.txt +202 -0
  52. package/apps/integration-client/main-route-editor.jsx +94 -0
  53. package/apps/integration-client/main-route-model.mjs +100 -0
  54. package/apps/integration-client/model-picker.css +37 -0
  55. package/apps/integration-client/model-picker.jsx +83 -0
  56. package/apps/integration-client/native-activity.css +141 -0
  57. package/apps/integration-client/native-activity.jsx +276 -0
  58. package/apps/integration-client/native-activity.mjs +384 -0
  59. package/apps/integration-client/notifications-panel.jsx +186 -0
  60. package/apps/integration-client/notifications.css +126 -0
  61. package/apps/integration-client/pairing-qr.jsx +79 -0
  62. package/apps/integration-client/panels.jsx +126 -115
  63. package/apps/integration-client/product-slots.jsx +46 -0
  64. package/apps/integration-client/routine-recorder.mjs +23 -2
  65. package/apps/integration-client/secure-pairing.jsx +84 -0
  66. package/apps/integration-client/tasks-panel.jsx +32 -10
  67. package/apps/integration-client/ui-icons.jsx +17 -0
  68. package/apps/integration-client/usage-explorer.jsx +43 -0
  69. package/apps/integration-client/usage-report.mjs +71 -0
  70. package/apps/integration-client/usage.css +34 -0
  71. package/apps/integration-client/web-panel-model.mjs +140 -0
  72. package/apps/integration-client/web-panel-page.jsx +221 -0
  73. package/apps/integration-client/web-panel-pins-live.jsx +28 -0
  74. package/apps/integration-client/web-panel.css +139 -0
  75. package/apps/integration-client/workspace-model.mjs +67 -0
  76. package/apps/integration-client/workspace-navigation.mjs +56 -0
  77. package/apps/integration-client/workspace-ui.jsx +173 -0
  78. package/apps/integration-client/workspace.css +332 -0
  79. package/modules/bot-runtime/SOURCE.json +176 -50
  80. package/modules/bot-runtime/index.mjs +169 -13
  81. package/modules/bot-runtime/product-overlay/OVERLAY.json +128 -2
  82. package/modules/bot-runtime/product-overlay/base/src/client/header.js +244 -0
  83. package/modules/bot-runtime/product-overlay/base/src/client/learning-card.js +202 -0
  84. package/modules/bot-runtime/product-overlay/base/src/client/model-menu.js +371 -0
  85. package/modules/bot-runtime/product-overlay/base/src/client/secret-card.js +363 -0
  86. package/modules/bot-runtime/product-overlay/base/src/client/sources.js +68 -0
  87. package/modules/bot-runtime/product-overlay/base/src/client/turn-error.js +260 -0
  88. package/modules/bot-runtime/product-overlay/base/src/host/channel.js +647 -0
  89. package/modules/bot-runtime/product-overlay/base/src/host/memory.js +2050 -0
  90. package/modules/bot-runtime/product-overlay/base/src/host/models.js +314 -0
  91. package/modules/bot-runtime/product-overlay/base/src/host/parts.js +1473 -0
  92. package/modules/bot-runtime/product-overlay/base/src/host/privacy.js +368 -0
  93. package/modules/bot-runtime/product-overlay/base/src/host/roster.js +776 -0
  94. package/modules/bot-runtime/product-overlay/base/src/host/store.js +512 -0
  95. package/modules/bot-runtime/product-overlay/base/src/host/usage.js +653 -0
  96. package/modules/bot-runtime/product-overlay/patches/src/client/details-drawer.js.patch +48 -2
  97. package/modules/bot-runtime/product-overlay/patches/src/client/header.js.patch +41 -0
  98. package/modules/bot-runtime/product-overlay/patches/src/client/index.js.patch +33 -1
  99. package/modules/bot-runtime/product-overlay/patches/src/client/learning-card.js.patch +20 -0
  100. package/modules/bot-runtime/product-overlay/patches/src/client/model-menu.js.patch +24 -0
  101. package/modules/bot-runtime/product-overlay/patches/src/client/secret-card.js.patch +25 -0
  102. package/modules/bot-runtime/product-overlay/patches/src/client/sources.js.patch +52 -0
  103. package/modules/bot-runtime/product-overlay/patches/src/client/turn-error.js.patch +23 -0
  104. package/modules/bot-runtime/product-overlay/patches/src/host/channel.js.patch +46 -0
  105. package/modules/bot-runtime/product-overlay/patches/src/host/memory.js.patch +11 -0
  106. package/modules/bot-runtime/product-overlay/patches/src/host/models.js.patch +16 -0
  107. package/modules/bot-runtime/product-overlay/patches/src/host/parts.js.patch +95 -0
  108. package/modules/bot-runtime/product-overlay/patches/src/host/privacy.js.patch +11 -0
  109. package/modules/bot-runtime/product-overlay/patches/src/host/roster.js.patch +145 -0
  110. package/modules/bot-runtime/product-overlay/patches/src/host/store.js.patch +68 -0
  111. package/modules/bot-runtime/product-overlay/patches/src/host/usage.js.patch +11 -0
  112. package/modules/bot-runtime/read-model.mjs +19 -4
  113. package/modules/bot-runtime/vendor/ds-bot/src/client/details-drawer.js +15 -5
  114. package/modules/bot-runtime/vendor/ds-bot/src/client/header.js +9 -2
  115. package/modules/bot-runtime/vendor/ds-bot/src/client/index.js +9 -2
  116. package/modules/bot-runtime/vendor/ds-bot/src/client/learning-card.js +2 -2
  117. package/modules/bot-runtime/vendor/ds-bot/src/client/model-menu.js +5 -3
  118. package/modules/bot-runtime/vendor/ds-bot/src/client/secret-card.js +3 -3
  119. package/modules/bot-runtime/vendor/ds-bot/src/client/sources.js +25 -2
  120. package/modules/bot-runtime/vendor/ds-bot/src/client/turn-error.js +3 -2
  121. package/modules/bot-runtime/vendor/ds-bot/src/host/channel.js +14 -2
  122. package/modules/bot-runtime/vendor/ds-bot/src/host/memory.js +1 -1
  123. package/modules/bot-runtime/vendor/ds-bot/src/host/models.js +7 -0
  124. package/modules/bot-runtime/vendor/ds-bot/src/host/parts.js +26 -9
  125. package/modules/bot-runtime/vendor/ds-bot/src/host/privacy.js +1 -1
  126. package/modules/bot-runtime/vendor/ds-bot/src/host/roster.js +112 -3
  127. package/modules/bot-runtime/vendor/ds-bot/src/host/store.js +34 -1
  128. package/modules/bot-runtime/vendor/ds-bot/src/host/usage.js +1 -1
  129. package/modules/independent-runtime/index.mjs +152 -62
  130. package/modules/independent-runtime/remote-tools.mjs +8 -5
  131. package/modules/openmaus-protocol/NOTICE +10 -0
  132. package/modules/openmaus-protocol/README.md +15 -0
  133. package/modules/openmaus-protocol/SOURCE.json +68 -0
  134. package/modules/openmaus-protocol/dist/protocol.mjs +1203 -0
  135. package/modules/openmaus-protocol/index.mjs +1 -0
  136. package/modules/openmaus-protocol/transport.mjs +77 -0
  137. package/modules/openmaus-protocol/vendor/LICENSE +202 -0
  138. package/modules/openmaus-protocol/vendor/companion/src/e2e/README.md +405 -0
  139. package/modules/openmaus-protocol/vendor/companion/src/e2e/credentials.ts +128 -0
  140. package/modules/openmaus-protocol/vendor/companion/src/e2e/descriptor.ts +84 -0
  141. package/modules/openmaus-protocol/vendor/companion/src/e2e/noise.ts +456 -0
  142. package/modules/openmaus-protocol/vendor/companion/src/e2e/phone.ts +104 -0
  143. package/modules/openmaus-protocol/vendor/companion/src/e2e/session.ts +417 -0
  144. package/modules/openmaus-protocol/vendor/companion/src/e2e/vectors/v1.json +2565 -0
  145. package/modules/openmaus-protocol/vendor/companion/src/e2e/vectors/v1.sha256 +1 -0
  146. package/modules/openmaus-protocol/vendor/companion/src/e2e/yamux.ts +335 -0
  147. package/package.json +18 -6
  148. package/packages/bot-acp/README.md +156 -0
  149. package/packages/bot-acp/licenses/LICENSE-OpenMausBot +202 -0
  150. package/packages/bot-acp/licenses/NOTICE.md +27 -0
  151. package/packages/bot-acp/src/acp-adapter.mjs +795 -0
  152. package/packages/bot-acp/src/acp-host.mjs +148 -0
  153. package/packages/bot-acp/src/native-launch.mjs +121 -0
  154. package/packages/bot-acp/src/permission-policy.mjs +283 -0
  155. package/packages/bot-acp/src/rpc-codec.mjs +265 -0
  156. package/packages/bot-acp/src/session-core.mjs +581 -0
  157. package/packages/bot-acp/src/stdio-rpc.mjs +329 -0
  158. package/packages/bot-engines/README.md +281 -0
  159. package/packages/bot-engines/licenses/LICENSE-OpenMausBot +202 -0
  160. package/packages/bot-engines/licenses/NOTICE.md +32 -0
  161. package/packages/bot-engines/src/claude-engine.mjs +772 -0
  162. package/packages/bot-engines/src/claude-llm-adapter.mjs +797 -0
  163. package/packages/bot-engines/src/claude-llm-turn.mjs +292 -0
  164. package/packages/bot-engines/src/claude-permission-broker.mjs +130 -0
  165. package/packages/bot-engines/src/claude-permission-proxy.mjs +87 -0
  166. package/packages/bot-engines/src/claude-protocol.mjs +177 -0
  167. package/packages/bot-engines/src/driver-catalog.mjs +334 -0
  168. package/packages/bot-engines/src/host-loop-request.mjs +95 -0
  169. package/packages/bot-engines/src/host-registrations.mjs +105 -0
  170. package/packages/capability-broker/src/cli-bootstrap.mjs +86 -16
  171. package/packages/capability-broker/src/cli-bridge-response.mjs +80 -0
  172. package/packages/capability-broker/src/cli-stdio-bridge.mjs +21 -8
  173. package/packages/cli-runtime/src/codex-session-core.mjs +4 -0
  174. package/packages/cli-runtime/src/native-cli-output.mjs +57 -0
  175. package/packages/cli-runtime/src/native-peer.ps1 +51 -3
  176. package/packages/cli-runtime/src/native-process.mjs +77 -14
  177. package/packages/model-router-plugin/package.json +1 -1
  178. package/packages/orchestration/src/binding-product.mjs +19 -0
  179. package/packages/orchestration/src/bot-data-actions.mjs +45 -0
  180. package/packages/orchestration/src/bot-data-chart.mjs +109 -0
  181. package/packages/orchestration/src/bot-data-context.mjs +44 -0
  182. package/packages/orchestration/src/bot-data-engine.mjs +809 -0
  183. package/packages/orchestration/src/bot-data-io.mjs +186 -0
  184. package/packages/orchestration/src/bot-data-sql.mjs +195 -0
  185. package/packages/orchestration/src/bot-data-surface.mjs +144 -0
  186. package/packages/orchestration/src/bot-data-tools.mjs +68 -0
  187. package/packages/orchestration/src/bot-data-worker.mjs +228 -0
  188. package/packages/orchestration/src/bot-independent-execution.mjs +195 -0
  189. package/packages/orchestration/src/bot-independent-stream.mjs +74 -0
  190. package/packages/orchestration/src/bot-loop.mjs +152 -19
  191. package/packages/orchestration/src/bot-notifications.mjs +159 -0
  192. package/packages/orchestration/src/bot-policy.mjs +43 -4
  193. package/packages/orchestration/src/bot-profile.mjs +171 -0
  194. package/packages/orchestration/src/bot-routine.mjs +4 -4
  195. package/packages/orchestration/src/bot-runtime-assembly.mjs +255 -8
  196. package/packages/orchestration/src/bot-runtime-switch.mjs +13 -2
  197. package/packages/orchestration/src/bot-serving.mjs +164 -0
  198. package/packages/orchestration/src/bot-session-store.mjs +105 -9
  199. package/packages/orchestration/src/bot-settings.mjs +50 -11
  200. package/packages/orchestration/src/bot-thread-admission.mjs +84 -0
  201. package/packages/orchestration/src/bot-thread-host.mjs +187 -0
  202. package/packages/orchestration/src/bot-threads.mjs +790 -0
  203. package/packages/orchestration/src/data-product-access.mjs +37 -0
  204. package/packages/orchestration/src/data-tool-contract.mjs +291 -0
  205. package/packages/orchestration/src/desktop-http-carrier.mjs +120 -0
  206. package/packages/orchestration/src/desktop-proxy.mjs +311 -0
  207. package/packages/orchestration/src/desktop-sessions.mjs +43 -9
  208. package/packages/orchestration/src/ds-lifecycle.mjs +31 -4
  209. package/packages/orchestration/src/grant-refresh-queue.mjs +17 -0
  210. package/packages/orchestration/src/independent-chat-page.mjs +39 -0
  211. package/packages/orchestration/src/independent-chat-service.mjs +308 -0
  212. package/packages/orchestration/src/independent-context-state.mjs +44 -0
  213. package/packages/orchestration/src/independent-message-wire.mjs +84 -0
  214. package/packages/orchestration/src/independent-tool-catalog.mjs +175 -0
  215. package/packages/orchestration/src/independent-tool-families.mjs +73 -0
  216. package/packages/orchestration/src/independent-tool-host.mjs +344 -0
  217. package/packages/orchestration/src/main-bot-grant.mjs +15 -0
  218. package/packages/orchestration/src/main-model-routes.mjs +208 -0
  219. package/packages/orchestration/src/model-accounting.mjs +99 -35
  220. package/packages/orchestration/src/model-auxiliary-dispatch.mjs +187 -0
  221. package/packages/orchestration/src/model-loop-frame.mjs +179 -0
  222. package/packages/orchestration/src/model-prepared-generation.mjs +175 -0
  223. package/packages/orchestration/src/model-request-bounds.mjs +111 -0
  224. package/packages/orchestration/src/native-activity-contract.mjs +491 -0
  225. package/packages/orchestration/src/native-activity-service.mjs +102 -0
  226. package/packages/orchestration/src/native-activity-store.mjs +249 -0
  227. package/packages/orchestration/src/native-conversation-tools.mjs +78 -0
  228. package/packages/orchestration/src/native-data-tools.mjs +100 -0
  229. package/packages/orchestration/src/native-remote-actions.mjs +742 -0
  230. package/packages/orchestration/src/native-team-tools.mjs +73 -0
  231. package/packages/orchestration/src/pairing-invite.mjs +37 -0
  232. package/packages/orchestration/src/product-composition.mjs +1559 -1001
  233. package/packages/orchestration/src/remote-machines.mjs +82 -14
  234. package/packages/orchestration/src/routine-execution.mjs +5 -3
  235. package/packages/orchestration/src/routine-session.mjs +19 -13
  236. package/packages/orchestration/src/secure-pairing-host.mjs +112 -0
  237. package/packages/orchestration/src/task-journal.mjs +29 -0
  238. package/packages/orchestration/src/task-product.mjs +17 -0
  239. package/packages/orchestration/src/team-assignment-store.mjs +120 -0
  240. package/packages/orchestration/src/team-bridge.mjs +282 -0
  241. package/packages/orchestration/src/team-scheduler.mjs +83 -0
  242. package/packages/orchestration/src/team-sdk-tools.mjs +84 -0
  243. package/packages/orchestration/src/team-tool-contract.mjs +284 -0
  244. package/packages/orchestration/src/ui-host-namespace.mjs +23 -0
  245. package/packages/orchestration/src/web-panel-actions.mjs +103 -0
  246. package/packages/orchestration/src/web-panel-framing.mjs +227 -0
  247. package/packages/orchestration/src/web-panel-store.mjs +206 -0
  248. package/remote-computer-agent/README.md +39 -29
  249. package/remote-computer-agent/build.mjs +3 -0
  250. package/remote-computer-agent/dist/OPENMAUSBOT_LICENSE +202 -0
  251. package/remote-computer-agent/dist/OPENMAUSBOT_NOTICE +10 -0
  252. package/remote-computer-agent/dist/OPENMAUSBOT_SOURCE.json +68 -0
  253. package/remote-computer-agent/dist/cli-stdio-bridge.mjs +215 -25
  254. package/remote-computer-agent/dist/cli-stdio-bridge.mjs.map +4 -4
  255. package/remote-computer-agent/dist/cli.mjs +1688 -168
  256. package/remote-computer-agent/dist/cli.mjs.map +4 -4
  257. package/remote-computer-agent/dist/index.mjs +1579 -122
  258. package/remote-computer-agent/dist/index.mjs.map +4 -4
  259. package/remote-computer-agent/dist/native-peer.ps1 +51 -3
  260. package/remote-computer-agent/package-lock.json +308 -2
  261. package/remote-computer-agent/package.json +2 -1
  262. package/remote-computer-agent/pair-device.ps1 +20 -0
  263. package/remote-computer-agent/setup.ps1 +38 -16
  264. package/remote-computer-agent/src/cli.ts +24 -3
  265. package/remote-computer-agent/src/desktop-session.ts +11 -3
  266. package/remote-computer-agent/src/e2e-server.ts +81 -0
  267. package/remote-computer-agent/src/pairing-page.ts +35 -0
  268. package/remote-computer-agent/src/protocol.ts +25 -25
  269. package/remote-computer-agent/src/secure-pairing.ts +105 -0
  270. package/remote-computer-agent/src/store.ts +20 -5
  271. package/remote-computer-agent/src/transport.ts +39 -15
@@ -0,0 +1,173 @@
1
+ import React, { useEffect, useId, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react'
2
+ import { modelName, TASK_STATES } from './api.mjs'
3
+ import { taskIdOf, taskKey, taskTitle } from './task-progress.mjs'
4
+ import { workspaceOverview, workspaceSearch } from './workspace-model.mjs'
5
+ import { UiIcon } from './ui-icons.jsx'
6
+
7
+ const APPEARANCE_KEY = 'dsh.bot.workspace.appearance.v1'
8
+ const appearanceStores = new WeakMap()
9
+ const defaults = Object.freeze({ appearance: 'host', density: 'comfortable', chatWidth: 'standard', colorUserBubbles: true, saved: true })
10
+ const normalizeAppearance = value => ({ appearance: ['host', 'light', 'dark'].includes(value?.appearance) ? value.appearance : 'host',
11
+ density: value?.density === 'compact' ? 'compact' : 'comfortable',
12
+ chatWidth: ['standard', 'wide', 'full'].includes(value?.chatWidth) ? value.chatWidth : 'standard',
13
+ colorUserBubbles: value?.colorUserBubbles !== false, saved: true })
14
+
15
+ export function workspaceAppearance(win = window) {
16
+ if (appearanceStores.has(win)) return appearanceStores.get(win)
17
+ let value = defaults
18
+ const read = () => { try { return normalizeAppearance(JSON.parse(win.localStorage.getItem(APPEARANCE_KEY))) } catch { return defaults } }
19
+ value = read()
20
+ const listeners = new Set()
21
+ const publish = () => { for (const listener of listeners) listener() }
22
+ const store = Object.freeze({
23
+ getSnapshot: () => value,
24
+ subscribe(listener) { listeners.add(listener); return () => listeners.delete(listener) },
25
+ set(patch) {
26
+ value = normalizeAppearance({ ...value, ...patch })
27
+ try { win.localStorage.setItem(APPEARANCE_KEY, JSON.stringify({ appearance: value.appearance, density: value.density,
28
+ chatWidth: value.chatWidth, colorUserBubbles: value.colorUserBubbles })) }
29
+ catch { value = { ...value, saved: false } }
30
+ publish()
31
+ },
32
+ reload() { value = read(); publish() },
33
+ })
34
+ appearanceStores.set(win, store)
35
+ return store
36
+ }
37
+
38
+ export function installWorkspaceAppearance(win = window) {
39
+ const body = win.document.body, store = workspaceAppearance(win)
40
+ const attributes = ['data-bp-appearance', 'data-bp-density', 'data-bp-chat-width', 'data-bp-user-bubbles']
41
+ const previous = attributes.map(name => body.getAttribute(name))
42
+ const paint = () => {
43
+ const value = store.getSnapshot()
44
+ body.setAttribute(attributes[0], value.appearance); body.setAttribute(attributes[1], value.density)
45
+ body.setAttribute(attributes[2], value.chatWidth); body.setAttribute(attributes[3], value.colorUserBubbles ? 'colored' : 'neutral')
46
+ }
47
+ const onStorage = event => { if (event.key === APPEARANCE_KEY || event.key === null) store.reload() }
48
+ const unsubscribe = store.subscribe(paint)
49
+ paint(); win.addEventListener('storage', onStorage)
50
+ return () => {
51
+ unsubscribe(); win.removeEventListener('storage', onStorage)
52
+ attributes.forEach((name, index) => previous[index] === null ? body.removeAttribute(name) : body.setAttribute(name, previous[index]))
53
+ }
54
+ }
55
+
56
+ export function AppearanceControls() {
57
+ const store = workspaceAppearance(), value = useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot)
58
+ return <details className="bp-appearance"><summary aria-label="外观与显示" title="外观与显示"><UiIcon name="sun" size={17} /></summary>
59
+ <div className="bp-appearance-menu"><strong>外观与显示</strong>
60
+ <fieldset><legend>颜色</legend><div className="bp-segmented">{[['host', '跟随宿主'], ['light', '浅色'], ['dark', '深色']].map(([key, label]) => <button key={key} type="button" aria-pressed={value.appearance === key} onClick={() => store.set({ appearance: key })}>{label}</button>)}</div></fieldset>
61
+ <fieldset><legend>信息密度</legend><div className="bp-segmented">{[['comfortable', '舒适'], ['compact', '紧凑']].map(([key, label]) => <button key={key} type="button" aria-pressed={value.density === key} onClick={() => store.set({ density: key })}>{label}</button>)}</div></fieldset>
62
+ <fieldset><legend>聊天宽度</legend><div className="bp-segmented">{[['standard', '标准'], ['wide', '宽屏'], ['full', '铺满']].map(([key, label]) => <button key={key} type="button" aria-pressed={value.chatWidth === key} onClick={() => store.set({ chatWidth: key })}>{label}</button>)}</div></fieldset>
63
+ <fieldset><legend>我的消息气泡</legend><div className="bp-segmented">{[[true, '彩色'], [false, '素色']].map(([enabled, label]) => <button key={label} type="button" aria-pressed={value.colorUserBubbles === enabled} onClick={() => store.set({ colorUserBubbles: enabled })}>{label}</button>)}</div></fieldset>
64
+ {!value.saved && <p role="status">已应用到此窗口,浏览器暂不能保存偏好。</p>}
65
+ </div>
66
+ </details>
67
+ }
68
+
69
+ export function WorkspaceToolbar({ title, onHome, onSearch }) {
70
+ return <div className="bp-workspace-bar"><div className="bp-workspace-location"><button type="button" className="bp-workspace-brand" onClick={onHome} aria-label="返回工作空间总览"><UiIcon name="spark" size={18} /><span>DSH WORKSPACE</span></button><span className="bp-workspace-divider" aria-hidden="true">/</span><span className="bp-workspace-current">{title}</span></div>
71
+ <div className="bp-workspace-bar-actions"><button type="button" className="bp-workspace-search" onClick={onSearch} aria-label="搜索工作空间"><UiIcon name="search" size={16} /><span>查找任务、伙伴、电脑</span><kbd>Ctrl K</kbd></button><AppearanceControls /></div>
72
+ </div>
73
+ }
74
+
75
+ export function WorkspaceCommandPalette({ open, onClose, snapshot, onNavigate, openSession }) {
76
+ const [query, setQuery] = useState(''), [cursor, setCursor] = useState(0)
77
+ const input = useRef(null), close = useRef(null), selected = useRef(null)
78
+ const listId = useId(), titleId = useId()
79
+ const results = useMemo(() => workspaceSearch(snapshot, query), [snapshot, query])
80
+ const position = results.items.length ? Math.min(cursor, results.items.length - 1) : 0
81
+ useLayoutEffect(() => {
82
+ if (!open) return undefined
83
+ const previous = document.activeElement
84
+ setQuery(''); setCursor(0); input.current?.focus()
85
+ return () => { if (previous?.isConnected) previous.focus() }
86
+ }, [open])
87
+ useEffect(() => { selected.current?.scrollIntoView?.({ block: 'nearest' }) }, [position, query, open])
88
+ if (!open) return null
89
+ const activate = row => {
90
+ onClose()
91
+ if (row.kind === 'bot' && row.sessionId && typeof openSession === 'function') openSession(row.sessionId)
92
+ else onNavigate(row.target)
93
+ }
94
+ const onKeyDown = event => {
95
+ if (event.nativeEvent.isComposing || event.nativeEvent.keyCode === 229) { event.stopPropagation(); return }
96
+ if (event.key === 'Escape') { event.preventDefault(); event.stopPropagation(); onClose() }
97
+ else if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
98
+ event.preventDefault()
99
+ const length = results.items.length
100
+ setCursor(length ? (position + (event.key === 'ArrowDown' ? 1 : -1) + length) % length : 0)
101
+ } else if (event.key === 'Enter' && event.target !== close.current) {
102
+ event.preventDefault(); if (results.items[position]) activate(results.items[position])
103
+ } else if (event.key === 'Tab') {
104
+ event.preventDefault(); if (document.activeElement === input.current) close.current?.focus(); else input.current?.focus()
105
+ }
106
+ }
107
+ return <div className="bp-palette-backdrop" onMouseDown={event => { if (event.target === event.currentTarget) onClose() }} onKeyDown={onKeyDown}>
108
+ <section className="bp-palette" role="dialog" aria-modal="true" aria-labelledby={titleId}><h2 id={titleId} className="bp-sr-only">搜索工作空间</h2>
109
+ <div className="bp-palette-input"><UiIcon name="search" size={20} /><input ref={input} role="combobox" aria-autocomplete="list" aria-expanded="true" aria-controls={listId} aria-activedescendant={results.items.length ? `${listId}-${position}` : undefined} value={query} onChange={event => { setQuery(event.target.value); setCursor(0) }} placeholder="搜索任务、Bot、模型或操作编号…" aria-label="搜索任务、Bot 和电脑" autoComplete="off" /><button ref={close} type="button" aria-label="关闭搜索" onClick={onClose}><UiIcon name="close" size={18} /></button></div>
110
+ <p className="bp-palette-caption">当前工作空间 · 仅搜索已加载记录{snapshot?.tasks?.truncated ? `(任务已加载 ${snapshot.tasks.items?.length ?? 0} / ${snapshot.tasks.total ?? '未知'} 条)` : ''}</p>
111
+ <div className="bp-palette-results" id={listId} role="listbox" aria-label="搜索结果">{results.items.map((row, index) => <button key={row.id} id={`${listId}-${index}`} role="option" aria-selected={index === position} tabIndex={-1} type="button" ref={index === position ? selected : undefined} onMouseMove={() => setCursor(index)} onClick={() => activate(row)}>
112
+ <span className="bp-result-icon"><UiIcon name={row.icon} size={19} /></span><span className="bp-result-copy"><strong>{row.label}</strong><small>{row.detail}</small></span><span className="bp-result-kind">{{ page: '页面', bot: 'Bot', task: '任务', machine: '电脑' }[row.kind]}</span><UiIcon name="chevron" size={14} />
113
+ </button>)}{!results.items.length && <p className="bp-search-empty">没有匹配的记录。试试名称、模型或完整任务编号。</p>}</div>
114
+ <footer className="bp-palette-footer"><span><kbd>↑ ↓</kbd> 选择 <kbd>Enter</kbd> 打开 <kbd>Esc</kbd> 关闭</span><span role="status">{results.total} 项{results.truncated ? `,显示前 ${results.items.length} 项` : ''}</span></footer>
115
+ </section>
116
+ </div>
117
+ }
118
+
119
+ const STAGES = { reconcile: ['收据待核对', 'clock'], approve: ['等待审批', 'lock'], 'remote-unknown': ['结果待确认', 'clock'], budget: ['等待预算', 'chart'], failed: ['执行失败', 'activity'], blocked: ['需要协助', 'inbox'] }
120
+ const when = value => value && Number.isFinite(new Date(value).getTime()) ? new Date(value).toLocaleString('zh-CN', { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }) : '时间未提供'
121
+ const destinationFor = row => ({ section: 'tasks', botId: row.botId, taskId: taskIdOf(row) })
122
+
123
+ export function WorkspaceInbox({ snapshot, onNavigate, openSession, preview = false }) {
124
+ const { progress, tasksAvailable } = useMemo(() => workspaceOverview(snapshot), [snapshot])
125
+ const [stage, setStage] = useState('all')
126
+ const rows = progress.attention.filter(row => stage === 'all' || row.stage === stage)
127
+ const visible = preview ? rows.slice(0, 4) : rows
128
+ return <section className={`bp-inbox${preview ? ' bp-inbox-preview' : ''}`} aria-label="任务待办">
129
+ <div className="bp-section-heading"><div><p className="bp-section-kicker">NEEDS YOUR ATTENTION</p><h2>需要你处理 <span className="bp-count">{tasksAvailable ? progress.attention.length : '—'}</span></h2></div>{preview && progress.attention.length > 0 && <button className="bp-text-button" type="button" onClick={() => onNavigate({ section: 'inbox' })}>查看全部<UiIcon name="chevron" size={14} /></button>}</div>
130
+ {!tasksAvailable ? <div className="bp-empty-work"><UiIcon name="inbox" size={28} /><p>{snapshot.tasks?.reason ?? '任务状态暂不可用。'}</p>{snapshot.tasks?.nextAction && <small>{snapshot.tasks.nextAction}</small>}</div> : <>
131
+ {snapshot.tasks.truncated && <p className="bp-muted">待办来自已加载的 {progress.items.length} / {snapshot.tasks.total ?? '未知'} 条任务。</p>}
132
+ {!preview && progress.attention.length > 0 && <div className="bp-inbox-filters" aria-label="按待办类型筛选"><button type="button" aria-pressed={stage === 'all'} onClick={() => setStage('all')}>全部 {progress.attention.length}</button>{Object.entries(STAGES).filter(([key]) => progress.attention.some(row => row.stage === key)).map(([key, [label]]) => <button type="button" key={key} aria-pressed={stage === key} onClick={() => setStage(key)}>{label} {progress.attention.filter(row => row.stage === key).length}</button>)}</div>}
133
+ {!progress.attention.length ? <div className="bp-empty-work"><span className="bp-calm-mark"><UiIcon name="check" size={26} /></span><h3>暂时没有需要你介入的任务</h3><p>团队的任务进展会在这里汇集。</p><button type="button" onClick={() => onNavigate({ section: 'tasks' })}>查看团队任务<UiIcon name="arrow" size={14} /></button></div> : <div className="bp-inbox-rows">{visible.map(row => {
134
+ const task = progress.items.find(item => taskKey(item) === taskKey(row))
135
+ const bot = snapshot.bots?.find(item => item.id === row.botId)
136
+ const [label, icon] = STAGES[row.stage] ?? ['需要处理', 'inbox']
137
+ return <article key={taskKey(row)} className="bp-inbox-item" data-stage={row.stage}><span className="bp-inbox-icon"><UiIcon name={icon} size={18} /></span><div className="bp-inbox-copy"><span className="bp-state-label">{label}</span><h3><button type="button" className="bp-text-button" onClick={() => onNavigate(destinationFor(row))}>{task ? taskTitle(task) : row.title}</button></h3><p>{row.detail}</p><small>{bot?.name ?? row.botId ?? '归属未提供'}</small></div><div className="bp-inbox-actions"><button type="button" onClick={() => onNavigate(destinationFor(row))}>查看任务<UiIcon name="chevron" size={13} /></button>{row.stage === 'approve' && bot?.sessionId && openSession && <button type="button" onClick={() => openSession(bot.sessionId)}>打开审批会话</button>}</div></article>
138
+ })}{!visible.length && <p className="bp-muted">该类型暂无待办。</p>}</div>}
139
+ </>}
140
+ </section>
141
+ }
142
+
143
+ export function WorkspaceHome({ snapshot, onNavigate, openSession, disabled }) {
144
+ const overview = useMemo(() => workspaceOverview(snapshot), [snapshot])
145
+ const [goal, setGoal] = useState('')
146
+ const { progress, bots, machines, recent, tasksAvailable } = overview
147
+ const canCompose = snapshot.availableActions?.includes('botRoutingInspect')
148
+ const main = bots.find(bot => bot.main)
149
+ const submit = event => { event.preventDefault(); if (!goal.trim() || disabled) return; onNavigate({ section: 'tasks', compose: true, draft: goal.trim() }); setGoal('') }
150
+ return <div className="bp-home">
151
+ <section className="bp-home-intro"><div><p className="bp-section-kicker">YOUR TEAM, IN MOTION</p><h1>下一件事,<br /><span>和团队一起完成。</span></h1><p>{bots.length ? `${bots.length} 位 Bot 伙伴,与目标、资料和工具在一个工作空间里。` : '从第一位 Bot 开始,组建适合你的工作团队。'}</p></div><div className="bp-home-orbit" aria-hidden="true"><span><UiIcon name="bot" size={35} /></span><i className="bp-orbit-node bp-orbit-one"><UiIcon name="file" size={20} /></i><i className="bp-orbit-node bp-orbit-two"><UiIcon name="computer" size={20} /></i><i className="bp-orbit-node bp-orbit-three"><UiIcon name="check" size={20} /></i></div></section>
152
+ <div className="bp-home-stats" aria-label="已加载任务概览">{[['active', '进行中的任务', 'activity'], ['attention', '需要你处理', 'inbox'], ['finished', '已结束的任务', 'check']].map(([filter, label, icon]) => <button key={filter} type="button" onClick={() => onNavigate({ section: filter === 'attention' ? 'inbox' : 'tasks', filter })}><span className="bp-stat-icon"><UiIcon name={icon} size={18} /></span><span><strong>{tasksAvailable ? progress.counts[filter] : '—'}</strong><small>{label}</small></span><UiIcon name="arrow" size={15} /></button>)}<button type="button" onClick={() => onNavigate({ section: 'machines' })}><span className="bp-stat-icon"><UiIcon name="computer" size={18} /></span><span><strong>{snapshot.machines?.status === 'available' ? overview.onlineMachines : '—'}<em> / {snapshot.machines?.status === 'available' ? machines.length : '—'}</em></strong><small>在线电脑</small></span><UiIcon name="arrow" size={15} /></button></div>
153
+ {overview.tasksTruncated && <p className="bp-loaded-note">任务统计仅包含已加载的 {progress.items.length} / {snapshot.tasks.total ?? '未知'} 条记录。</p>}
154
+ <div className="bp-home-main"><div className="bp-home-primary"><section className="bp-goal-card"><div className="bp-section-heading"><div><p className="bp-section-kicker">START SOMETHING</p><h2>你想完成什么?</h2></div><span className="bp-goal-symbol"><UiIcon name="spark" size={21} /></span></div>
155
+ {canCompose ? <form onSubmit={submit}><label className="bp-sr-only" htmlFor="bp-workspace-goal">任务目标</label><textarea id="bp-workspace-goal" value={goal} onChange={event => setGoal(event.target.value)} maxLength={20_000} rows={3} placeholder="描述你的目标,例如:检查这个项目,整理需要改进的地方…" /><div className="bp-goal-footer"><span><UiIcon name="lock" size={13} />先预览方案,再确认执行</span><button className="bp-button-primary" type="submit" disabled={disabled || !goal.trim()}>准备任务<UiIcon name="arrow" size={15} /></button></div></form> : <div className="bp-start-chat"><p>把目标告诉团队协调 Bot,或者在任务页查看已有工作。</p>{main?.sessionId && openSession ? <button className="bp-button-primary" type="button" onClick={() => openSession(main.sessionId)}>和 {main.name} 聊聊<UiIcon name="arrow" size={15} /></button> : <button type="button" onClick={() => onNavigate({ section: 'bindings' })}>查看团队<UiIcon name="arrow" size={15} /></button>}</div>}
156
+ </section><WorkspaceInbox snapshot={snapshot} onNavigate={onNavigate} openSession={openSession} preview /></div>
157
+ <aside className="bp-home-secondary"><section className="bp-recent"><div className="bp-section-heading"><div><p className="bp-section-kicker">RECENT WORK</p><h2>最近的工作</h2></div><button className="bp-text-button" type="button" onClick={() => onNavigate({ section: 'tasks' })} aria-label="查看全部任务"><UiIcon name="arrow" size={16} /></button></div>
158
+ {!tasksAvailable ? <p className="bp-muted">任务记录暂不可用。</p> : recent.length ? <ol className="bp-recent-list">{recent.map(task => <li key={taskKey(task)}><span className="bp-recent-dot" data-state={progress.category(task)} aria-hidden="true" /><button type="button" className="bp-text-button" onClick={() => onNavigate(destinationFor(task))}><strong>{taskTitle(task)}</strong><small>{snapshot.bots?.find(bot => bot.id === task.botId)?.name ?? task.botId} · {TASK_STATES[task.state] ?? task.state}</small><time>{when(task.updatedAt ?? task.createdAt)}</time></button></li>)}</ol> : <div className="bp-empty-work"><UiIcon name="tasks" size={25} /><p>新的任务会出现在这里。</p></div>}
159
+ </section><section className="bp-resource-links"><p className="bp-section-kicker">MAKE IT YOURS</p>{[['library', 'folder', '准备好资料', '把背景文件交给你的 Bot'], ['routine', 'repeat', '少做一次重复工作', '保存演示过的操作步骤']].map(([section, icon, title, detail]) => <button type="button" key={section} onClick={() => onNavigate({ section })}><UiIcon name={icon} size={19} /><span><strong>{title}</strong><small>{detail}</small></span><UiIcon name="chevron" size={14} /></button>)}</section></aside></div>
160
+ <section className="bp-home-team"><div className="bp-section-heading"><div><p className="bp-section-kicker">PEOPLE TO WORK WITH</p><h2>你的 Bot 团队</h2></div><button type="button" className="bp-text-button" onClick={() => onNavigate({ section: 'bindings' })}>管理团队<UiIcon name="chevron" size={14} /></button></div>
161
+ {bots.length ? <div className="bp-home-team-grid">{bots.slice(0, 8).map(bot => <button type="button" className="bp-home-person" key={bot.id} onClick={() => onNavigate({ section: 'bindings', botId: bot.id })}><span className="bp-team-avatar"><UiIcon name={bot.main ? 'spark' : 'bot'} size={24} /></span><span className="bp-home-person-copy"><strong>{bot.name}{bot.main && <span className="bp-main-label">协调</span>}</strong><small>{bot.role || '尚未填写职责'}</small><span className="bp-person-state" data-state={bot.state}>{bot.state === 'attention' ? `${bot.work.attention} 项待处理` : bot.state === 'active' ? `${bot.work.active} 项进行中` : '暂无进行中任务'}</span></span><UiIcon name="chevron" size={14} /></button>)}</div> : <p className="bp-muted">在侧栏新建 Bot 后,可在这里管理团队与工作配置。</p>}
162
+ {bots.length > 8 && <button className="bp-text-button" type="button" onClick={() => onNavigate({ section: 'bindings' })}>查看全部 {bots.length} 位伙伴</button>}
163
+ </section>
164
+ </div>
165
+ }
166
+
167
+ export function TeamDirectory({ snapshot, selected, onSelect }) {
168
+ const [query, setQuery] = useState('')
169
+ const { bots } = useMemo(() => workspaceOverview(snapshot), [snapshot])
170
+ const terms = query.trim().toLocaleLowerCase().split(/\s+/u).filter(Boolean)
171
+ const rows = bots.filter(bot => terms.every(term => `${bot.name} ${bot.role ?? ''} ${modelName(bot.model)}`.toLocaleLowerCase().includes(term)))
172
+ return <section className="bp-team-directory" aria-label="Bot 列表"><label className="bp-team-search"><UiIcon name="search" size={16} /><input aria-label="搜索团队成员" value={query} onChange={event => setQuery(event.target.value)} placeholder="搜索伙伴、职责、模型" type="search" /></label><div className="bp-team-directory-count">{rows.length} 位伙伴</div><div className="bp-team-directory-list">{rows.map(bot => <button type="button" key={bot.id} className="bp-team-member" aria-current={selected === bot.id ? 'true' : undefined} onClick={() => onSelect(bot.id)}><span className="bp-team-avatar"><UiIcon name={bot.main ? 'spark' : 'bot'} size={22} /></span><span><strong>{bot.name}{bot.main && <span className="bp-main-label">协调</span>}</strong><small>{bot.role || '尚未填写职责'}</small><span className="bp-team-model">{modelName(bot.model)}</span><span className="bp-person-state" data-state={bot.state}>{bot.state === 'attention' ? `${bot.work.attention} 项待处理` : bot.state === 'active' ? `${bot.work.active} 项进行中` : '暂无进行中任务'}</span></span></button>)}</div>{!rows.length && <p className="bp-muted">没有匹配的团队成员。</p>}</section>
173
+ }
@@ -0,0 +1,332 @@
1
+ html body[data-bot-product-ui] {
2
+ --bp-bg: #f7f8f5;
3
+ --bp-sidebar: #eef1ec;
4
+ --bp-surface: #ffffff;
5
+ --bp-subtle: #f1f4ef;
6
+ --bp-hover: #e7ece5;
7
+ --bp-border: #dfe5dc;
8
+ --bp-ink: #24332a;
9
+ --bp-muted: #657269;
10
+ --bp-quiet: #8b978e;
11
+ --bp-solid: #285c45;
12
+ --bp-on-solid: #ffffff;
13
+ --bp-focus: #33765a;
14
+ --bp-accent-soft: #e4eee5;
15
+ --bp-warning: #8d6226;
16
+ --bp-warning-bg: #faf1df;
17
+ --bp-danger: #a8483f;
18
+ --bp-danger-bg: #f8eae6;
19
+ --bp-mono: "Cascadia Code", "SFMono-Regular", Consolas, monospace;
20
+ --bt-user: #285c45;
21
+ --bt-user-ink: #ffffff;
22
+ }
23
+ html body[data-bot-product-ui][data-ds-dark-theme]:not([data-bp-appearance=light]),
24
+ html body[data-bot-product-ui][data-bp-appearance=dark] {
25
+ --bp-bg: #111915;
26
+ --bp-sidebar: #152019;
27
+ --bp-surface: #1b261f;
28
+ --bp-subtle: #202e25;
29
+ --bp-hover: #2a3b2f;
30
+ --bp-border: #344339;
31
+ --bp-ink: #e5eee6;
32
+ --bp-muted: #a3b4a7;
33
+ --bp-quiet: #819588;
34
+ --bp-solid: #b4d4b8;
35
+ --bp-on-solid: #15251b;
36
+ --bp-focus: #a6d4ae;
37
+ --bp-accent-soft: #293e2e;
38
+ --bp-warning: #e1bd7e;
39
+ --bp-warning-bg: #392f20;
40
+ --bp-danger: #f2aaa0;
41
+ --bp-danger-bg: #3b2824;
42
+ --bt-user: #b4d4b8;
43
+ --bt-user-ink: #15251b;
44
+ }
45
+ html body[data-bot-product-ui][data-bp-appearance=light] {
46
+ --bp-bg: #f7f8f5; --bp-sidebar: #eef1ec; --bp-surface: #fff;
47
+ --bp-subtle: #f1f4ef; --bp-hover: #e7ece5; --bp-border: #dfe5dc;
48
+ --bp-ink: #24332a; --bp-muted: #657269; --bp-quiet: #8b978e;
49
+ --bp-solid: #285c45; --bp-on-solid: #fff; --bp-focus: #33765a;
50
+ --bp-accent-soft: #e4eee5; --bp-warning: #8d6226; --bp-warning-bg: #faf1df;
51
+ --bp-danger: #a8483f; --bp-danger-bg: #f8eae6;
52
+ --bt-user: #285c45; --bt-user-ink: #fff;
53
+ }
54
+ html body[data-bot-product-ui][data-bp-appearance] {
55
+ --bt-main: var(--bp-bg); --bt-sidebar: var(--bp-sidebar); --bt-card: var(--bp-surface);
56
+ --bt-bubble: var(--bp-surface); --bt-ink: var(--bp-ink); --bt-ink-2: var(--bp-muted); --bt-ink-3: var(--bp-muted);
57
+ --bt-line: var(--bp-border); --bt-line-2: var(--bp-border); --bt-hover: var(--bp-hover); --bt-active: var(--bp-accent-soft);
58
+ --bt-accent: var(--bp-solid); --bt-accent-ink: var(--bp-on-solid); --bt-tag-bg: var(--bp-subtle); --bt-tag-ink: var(--bp-muted);
59
+ }
60
+ .bp-workspace { display: flex; flex-direction: column; height: 100%; min-height: 0; min-width: 0; color: var(--bp-ink); background: var(--bp-bg); font: 13px/1.6 var(--bp-font, system-ui); }
61
+ .bp-workspace *, .bp-palette * { box-sizing: border-box; }
62
+ .bp-workspace button, .bp-workspace input, .bp-workspace textarea { font-family: inherit; }
63
+ .bp-workspace-bar { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-shrink: 0; height: 60px; padding: 0 30px; border-bottom: 1px solid var(--bp-border); background: var(--bp-surface); }
64
+ .bp-workspace-location, .bp-workspace-bar-actions { display: flex; align-items: center; gap: 15px; min-width: 0; }
65
+ .bp-workspace-bar button { display: inline-flex; align-items: center; gap: 9px; padding: 7px 10px; color: var(--bp-ink); background: none; border: 1px solid transparent; border-radius: 7px; cursor: pointer; }
66
+ .bp-workspace-bar button:hover { background: var(--bp-subtle); }
67
+ .bp-workspace-brand { flex-shrink: 0; font-size: 10px; font-weight: 650; letter-spacing: .12em; }
68
+ .bp-workspace-brand > svg { color: var(--bp-solid); }
69
+ .bp-workspace-divider { color: var(--bp-border); font-size: 20px; font-weight: 300; }
70
+ .bp-workspace-current { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--bp-muted); font-size: 12px; }
71
+ .bp-workspace-bar .bp-workspace-search { min-width: 260px; color: var(--bp-muted); background: var(--bp-bg); border-color: var(--bp-border); font-size: 11px; }
72
+ .bp-workspace-search kbd { margin-left: auto; font-size: 10px; color: var(--bp-muted); }
73
+ .bp-appearance { position: relative; flex-shrink: 0; }
74
+ .bp-appearance > summary { display: grid; place-items: center; width: 34px; height: 34px; cursor: pointer; list-style: none; border-radius: 7px; color: var(--bp-muted); }
75
+ .bp-appearance > summary::-webkit-details-marker { display: none; }
76
+ .bp-appearance > summary:hover { background: var(--bp-subtle); }
77
+ .bp-appearance-menu { position: absolute; top: 43px; right: 0; z-index: 50; width: min(265px, calc(100vw - 24px)); max-height: calc(100dvh - 80px); overflow: auto; padding: 20px; border: 1px solid var(--bp-border); border-radius: 12px; color: var(--bp-ink); background: var(--bp-surface); box-shadow: 0 12px 40px #1223181a; }
78
+ .bp-appearance-menu > strong { font-size: 13px; font-weight: 600; }
79
+ .bp-appearance-menu fieldset { border: 0; padding: 0; margin: 17px 0 0; }
80
+ .bp-appearance-menu legend { font-size: 11px; color: var(--bp-muted); padding: 0 0 7px; }
81
+ .bp-appearance-menu p { font-size: 11px; color: var(--bp-muted); }
82
+ .bp-workspace .bp-page { flex: 1; height: auto; min-height: 0; padding: 30px clamp(20px, 4vw, 58px); }
83
+ .bp-workspace .bp-page-inner { max-width: 1180px; }
84
+ .bp-workspace .bp-page-header { margin-bottom: 24px; padding-bottom: 24px; }
85
+ .bp-workspace .bp-page h1 { font-weight: 650; letter-spacing: -.04em; font-size: 27px; }
86
+ .bp-workspace .bp-page h2 { font-size: 15px; letter-spacing: -.015em; }
87
+ .bp-workspace .bp-page-description { color: var(--bp-muted); max-width: 680px; }
88
+ .bp-workspace .bp-card { padding: 24px; border-radius: 12px; box-shadow: none; }
89
+ .bp-workspace .bp-selected-resource { border-color: var(--bp-solid); }
90
+ .bp-workspace .bp-page button { font-weight: 500; }
91
+ .bp-workspace .bp-page .bp-text-button { padding: 0; background: none; border: 0; box-shadow: none; text-align: left; min-height: 0; color: inherit; }
92
+ .bp-workspace .bp-page .bp-text-button:hover { color: var(--bp-solid); background: none; text-decoration: none; }
93
+ .bp-workspace .bp-page .bp-text-button:focus-visible { outline-offset: 4px; }
94
+ .bp-workspace .bp-page .bp-home-header { margin-bottom: 22px; padding: 0; border: 0; align-items: center; }
95
+ .bp-live-dot { display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: var(--bp-solid); }
96
+ .bp-page .bp-section-kicker { color: var(--bp-muted); font-size: 9px; line-height: 1.5; font-weight: 600; letter-spacing: .13em; margin: 0 0 7px; }
97
+ .bp-section-heading { display: flex; align-items: center; justify-content: space-between; gap: 14px; margin-bottom: 20px; }
98
+ .bp-section-heading > div { min-width: 0; }
99
+ .bp-section-heading h2 { display: flex; align-items: center; gap: 9px; }
100
+ .bp-count { font-size: 11px; font-weight: 500; padding: 1px 6px; border: 1px solid var(--bp-border); border-radius: 5px; color: var(--bp-muted); }
101
+ .bp-home-intro { display: flex; justify-content: space-between; align-items: center; gap: 28px; padding: 2px 0 30px; }
102
+ .bp-home .bp-home-intro h1 { margin: 0 0 17px; font-size: clamp(28px, 3.2vw, 40px); line-height: 1.4; letter-spacing: -.045em; font-weight: 650; }
103
+ .bp-home-intro h1 > span { color: var(--bp-solid); }
104
+ .bp-home-intro > div > p:last-child { color: var(--bp-muted); font-size: 12px; margin: 0; }
105
+ .bp-home-orbit { position: relative; width: 190px; height: 135px; flex-shrink: 0; margin: 0 45px 0 10px; border: 1px solid var(--bp-border); border-radius: 50%; transform: rotate(-14deg); }
106
+ .bp-home-orbit > span { display: grid; place-items: center; position: absolute; inset: 24px 52px; border: 1px solid var(--bp-border); border-radius: 24px; background: var(--bp-accent-soft); color: var(--bp-solid); transform: rotate(14deg); }
107
+ .bp-orbit-node { position: absolute; display: grid; place-items: center; width: 40px; height: 40px; border: 1px solid var(--bp-border); border-radius: 12px; color: var(--bp-muted); background: var(--bp-surface); transform: rotate(14deg); }
108
+ .bp-orbit-one { top: 4px; left: -3px; }
109
+ .bp-orbit-two { bottom: 7px; right: -6px; }
110
+ .bp-orbit-three { top: -14px; right: 25px; color: var(--bp-solid); }
111
+ .bp-home-stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); border-top: 1px solid var(--bp-border); border-bottom: 1px solid var(--bp-border); margin-bottom: 30px; }
112
+ .bp-home-stats > button { justify-content: flex-start; gap: 13px; border: 0; border-radius: 0; background: none; padding: 21px 16px; min-width: 0; }
113
+ .bp-home-stats > button:first-child { padding-left: 0; }
114
+ .bp-home-stats > button:not(:first-child) { border-left: 1px solid var(--bp-border); }
115
+ .bp-home-stats > button:hover { background: var(--bp-subtle); border: 0; }
116
+ .bp-home-stats > button:hover:not(:first-child) { border-left: 1px solid var(--bp-border); }
117
+ .bp-home-stats > button > .bp-icon:last-child { margin-left: auto; color: var(--bp-muted); }
118
+ .bp-stat-icon { display: grid; place-items: center; width: 34px; height: 34px; border: 1px solid var(--bp-border); border-radius: 10px; color: var(--bp-muted); background: var(--bp-surface); }
119
+ .bp-home-stats > button > span { text-align: left; }
120
+ .bp-home-stats strong { display: block; font-size: 25px; line-height: 1.2; font-weight: 550; font-variant-numeric: tabular-nums; }
121
+ .bp-home-stats strong em { font-style: normal; color: var(--bp-muted); font-size: 13px; }
122
+ .bp-home-stats small { margin-top: 6px; font-size: 10px; }
123
+ .bp-loaded-note { margin-top: -21px; margin-bottom: 24px; font-size: 11px; color: var(--bp-muted); }
124
+ .bp-home-main { display: grid; grid-template-columns: minmax(0, 1.8fr) minmax(235px, 1fr); gap: 34px; }
125
+ .bp-home-primary, .bp-home-secondary { min-width: 0; }
126
+ .bp-goal-card { padding: 24px; border: 1px solid var(--bp-border); border-radius: 13px; background: var(--bp-surface); margin-bottom: 32px; }
127
+ .bp-goal-symbol { color: var(--bp-solid); }
128
+ .bp-goal-card .bp-section-heading { margin-bottom: 16px; }
129
+ .bp-goal-card textarea { display: block; width: 100%; min-height: 94px; max-height: 300px; resize: vertical; font-size: 13px; border: 0 !important; padding: 4px 0 !important; box-shadow: none !important; border-radius: 0 !important; background: transparent !important; line-height: 1.8; }
130
+ .bp-goal-card textarea:focus-visible { outline-offset: 3px; }
131
+ .bp-goal-footer { display: flex; justify-content: space-between; align-items: center; gap: 12px; padding-top: 16px; border-top: 1px solid var(--bp-border); margin-top: 13px; }
132
+ .bp-goal-footer > span { display: flex; align-items: center; gap: 5px; font-size: 10px; color: var(--bp-muted); }
133
+ .bp-goal-footer button { flex-shrink: 0; }
134
+ .bp-start-chat > p { color: var(--bp-muted); margin: 10px 0 18px; }
135
+ .bp-home-secondary { border-left: 1px solid var(--bp-border); padding-left: 30px; }
136
+ .bp-recent { padding-top: 3px; }
137
+ .bp-recent-list { list-style: none; margin: 0; padding: 0; }
138
+ .bp-recent-list > li { display: flex; gap: 12px; position: relative; min-width: 0; padding-bottom: 24px; }
139
+ .bp-recent-list > li:not(:last-child)::after { content: ''; position: absolute; top: 13px; left: 3px; bottom: 0; width: 1px; background: var(--bp-border); }
140
+ .bp-recent-dot { width: 7px; height: 7px; border: 1px solid var(--bp-quiet); border-radius: 50%; flex-shrink: 0; margin-top: 6px; position: relative; z-index: 1; background: var(--bp-bg); }
141
+ .bp-recent-dot[data-state=active] { background: var(--bp-solid); border-color: var(--bp-solid); }
142
+ .bp-recent-dot[data-state=attention] { background: var(--bp-warning-bg); border-color: var(--bp-warning); }
143
+ .bp-recent-list .bp-text-button { display: block; width: 100%; overflow-wrap: anywhere; }
144
+ .bp-recent-list strong { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; font-size: 12px; font-weight: 500; line-height: 1.7; }
145
+ .bp-recent-list time { display: block; font-size: 10px; color: var(--bp-muted); margin-top: 5px; }
146
+ .bp-recent-list small { font-size: 10px; }
147
+ .bp-resource-links { border-top: 1px solid var(--bp-border); padding-top: 20px; margin-top: 4px; }
148
+ .bp-resource-links > button { display: flex; width: 100%; text-align: left; justify-content: flex-start; padding: 11px 0; border: 0; border-radius: 0; background: none; gap: 12px; }
149
+ .bp-resource-links > button > svg { color: var(--bp-muted); }
150
+ .bp-resource-links > button > svg:last-child { margin-left: auto; }
151
+ .bp-resource-links strong { font-size: 12px; font-weight: 500; }
152
+ .bp-resource-links small { font-size: 10px; }
153
+ .bp-inbox { min-width: 0; }
154
+ .bp-inbox-rows { border-top: 1px solid var(--bp-border); }
155
+ .bp-inbox-item { display: flex; align-items: flex-start; gap: 14px; padding: 21px 0; border-bottom: 1px solid var(--bp-border); }
156
+ .bp-inbox-icon { width: 32px; height: 32px; flex-shrink: 0; display: grid; place-items: center; border-radius: 9px; background: var(--bp-warning-bg); color: var(--bp-warning); margin-top: 2px; }
157
+ .bp-inbox-item[data-stage=approve] .bp-inbox-icon { color: var(--bp-solid); background: var(--bp-accent-soft); }
158
+ .bp-inbox-copy { flex: 1; min-width: 0; }
159
+ .bp-inbox-copy .bp-state-label { font-size: 10px; color: var(--bp-muted); }
160
+ .bp-inbox-copy h3 { font-size: 13px; margin: 4px 0 6px; }
161
+ .bp-inbox-copy h3 > button { font-weight: 550; line-height: 1.7; overflow-wrap: anywhere; }
162
+ .bp-inbox-copy > p { color: var(--bp-muted); font-size: 11px; line-height: 1.8; margin: 0; }
163
+ .bp-inbox-copy > small { font-size: 10px; margin-top: 8px; }
164
+ .bp-inbox-actions { display: flex; flex-direction: column; gap: 8px; margin-left: auto; flex-shrink: 0; padding-top: 5px; }
165
+ .bp-inbox-actions > button { min-height: 29px; font-size: 11px; padding: 5px 9px; }
166
+ .bp-inbox-preview .bp-inbox-item { gap: 11px; }
167
+ .bp-inbox-preview .bp-inbox-actions > button { font-size: 10px; }
168
+ .bp-inbox-filters { display: flex; flex-wrap: wrap; gap: 7px; margin-bottom: 20px; }
169
+ .bp-inbox-filters button { font-size: 12px; }
170
+ .bp-inbox-filters button[aria-pressed=true] { color: var(--bp-solid); background: var(--bp-accent-soft); border-color: var(--bp-solid); }
171
+ .bp-empty-work { padding: 30px 16px; text-align: center; color: var(--bp-muted); }
172
+ .bp-empty-work > svg { margin-bottom: 8px; }
173
+ .bp-empty-work h3 { margin: 12px 0 6px; color: var(--bp-ink); }
174
+ .bp-empty-work p { font-size: 12px; margin: 8px 0; }
175
+ .bp-empty-work button { margin-top: 12px; }
176
+ .bp-calm-mark { display: inline-grid; place-items: center; width: 50px; height: 50px; border: 1px solid var(--bp-border); border-radius: 50%; color: var(--bp-solid); background: var(--bp-accent-soft); }
177
+ .bp-home-team { border-top: 1px solid var(--bp-border); padding-top: 28px; margin-top: 34px; }
178
+ .bp-home-team-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
179
+ .bp-home-team-grid > .bp-home-person { justify-content: flex-start; padding: 17px; gap: 13px; text-align: left; border: 1px solid var(--bp-border); border-radius: 10px; background: var(--bp-surface); min-width: 0; }
180
+ .bp-team-avatar { display: inline-grid; place-items: center; width: 42px; height: 42px; flex-shrink: 0; background: var(--bp-accent-soft); color: var(--bp-solid); border: 1px solid var(--bp-border); border-radius: 13px; }
181
+ .bp-home-person-copy { min-width: 0; }
182
+ .bp-home-person-copy > strong { display: flex; align-items: center; gap: 9px; font-size: 13px; font-weight: 550; }
183
+ .bp-home-person-copy > small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11px; }
184
+ .bp-home-person > .bp-icon:last-child { color: var(--bp-muted); margin-left: auto; }
185
+ .bp-main-label { display: inline-block; font-size: 9px; font-weight: 500; color: var(--bp-solid); background: var(--bp-accent-soft); border-radius: 4px; padding: 1px 5px; }
186
+ .bp-person-state { display: flex; align-items: center; gap: 5px; font-size: 10px; color: var(--bp-muted); margin-top: 8px; }
187
+ .bp-person-state::before { content: ''; width: 4px; height: 4px; border-radius: 50%; background: var(--bp-quiet); }
188
+ .bp-person-state[data-state=active]::before { background: var(--bp-solid); }
189
+ .bp-person-state[data-state=attention]::before { background: var(--bp-warning); }
190
+ .bp-workspace .bp-team-layout { grid-template-columns: minmax(210px, 270px) minmax(0, 1fr); gap: 24px; }
191
+ .bp-team-directory { min-width: 0; }
192
+ .bp-team-search { display: flex; align-items: center; gap: 9px; padding: 0 11px; border: 1px solid var(--bp-border); border-radius: 8px; color: var(--bp-muted); background: var(--bp-surface); }
193
+ .bp-team-search input { flex: 1; width: 100%; border: 0 !important; background: none !important; box-shadow: none !important; padding-left: 0 !important; font-size: 12px !important; }
194
+ .bp-team-directory-count { font-size: 10px; color: var(--bp-muted); margin: 14px 0 9px 4px; }
195
+ .bp-team-directory-list { display: flex; flex-direction: column; gap: 8px; }
196
+ .bp-team-directory .bp-team-member { display: flex; align-items: flex-start; justify-content: flex-start; text-align: left; width: 100%; padding: 15px 12px; gap: 11px; border: 1px solid transparent; background: none; border-radius: 10px; }
197
+ .bp-team-member[aria-current=true] { background: var(--bp-surface) !important; border-color: var(--bp-border) !important; }
198
+ .bp-team-member > span:last-child { min-width: 0; }
199
+ .bp-team-member strong { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; font-size: 13px; font-weight: 600; }
200
+ .bp-team-member small { font-size: 11px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
201
+ .bp-team-model { display: block; color: var(--bp-muted); font-size: 10px; font-family: var(--bp-mono); overflow-wrap: anywhere; margin-top: 8px; }
202
+ .bp-team-member .bp-team-avatar { width: 34px; height: 34px; border-radius: 10px; }
203
+ .bp-workspace .bp-task-overview { background: none; border: 0; padding: 0; }
204
+ .bp-workspace .bp-task-counts { gap: 0; border: 1px solid var(--bp-border); border-radius: 10px; background: var(--bp-surface); overflow: hidden; }
205
+ .bp-workspace .bp-task-counts button { border: 0; border-radius: 0; padding: 16px; }
206
+ .bp-workspace .bp-task-counts button + button { border-left: 1px solid var(--bp-border); }
207
+ .bp-workspace .bp-task-counts button[aria-pressed=true] { background: var(--bp-accent-soft); color: var(--bp-solid); }
208
+ .bp-segmented { display: flex; align-items: center; padding: 3px; border: 1px solid var(--bp-border); border-radius: 8px; background: var(--bp-subtle); gap: 2px; }
209
+ .bp-workspace .bp-segmented button { font-size: 11px; min-height: 27px; border: 1px solid transparent; background: none; padding: 4px 9px; border-radius: 5px; }
210
+ .bp-workspace .bp-segmented button[aria-pressed=true] { border-color: var(--bp-border); background: var(--bp-surface); color: var(--bp-ink); }
211
+ .bp-board { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(220px, 1fr); gap: 13px; overflow-x: auto; margin-top: 20px; padding-bottom: 12px; }
212
+ .bp-board-lane { min-width: 0; border-radius: 8px; background: var(--bp-subtle); padding: 11px; }
213
+ .bp-board-lane > h3 { display: flex; align-items: center; gap: 7px; margin: 0 0 14px; padding: 0 2px; font-size: 11px; font-weight: 550; }
214
+ .bp-board-lane > h3 > span { margin-left: auto; color: var(--bp-muted); font-size: 10px; }
215
+ .bp-board-lane[data-lane=attention] > h3 { color: var(--bp-warning); }
216
+ .bp-board-items { display: flex; flex-direction: column; gap: 10px; }
217
+ .bp-board-card { min-width: 0; border: 1px solid var(--bp-border); background: var(--bp-surface); border-radius: 8px; padding: 13px; }
218
+ .bp-board-state { display: block; font-size: 9px; color: var(--bp-muted); margin-bottom: 8px; }
219
+ .bp-board-card > button { font-size: 12px; font-weight: 550 !important; line-height: 1.8; overflow-wrap: anywhere; }
220
+ .bp-board-card > p { font-size: 10px; color: var(--bp-muted); margin: 10px 0 0; }
221
+ .bp-board-card > small { font-size: 10px; }
222
+ .bp-board-card > footer { border-top: 1px solid var(--bp-border); margin-top: 13px; padding-top: 9px; }
223
+ .bp-board-card time { font-size: 9px; color: var(--bp-muted); }
224
+ .bp-board-card .bp-actions { margin-top: 8px; }
225
+ .bp-board-card .bp-actions:empty { display: none; }
226
+ .bp-board-card .bp-actions button { font-size: 10px; min-height: 25px; padding: 3px 8px; }
227
+ .bp-board-empty { font-size: 11px; color: var(--bp-muted); padding: 20px 0; text-align: center; }
228
+ .bp-workspace .bp-task-records { padding: 21px; }
229
+ .bp-palette-backdrop { position: fixed; inset: 0; z-index: 10000; display: flex; align-items: flex-start; justify-content: center; padding: min(14vh, 120px) 20px 30px; background: #0c1a1459; backdrop-filter: blur(3px); font: 13px/1.6 var(--bp-font, system-ui); }
230
+ .bp-palette { width: min(620px, 100%); max-height: min(680px, 76vh); display: flex; flex-direction: column; overflow: hidden; color: var(--bp-ink); background: var(--bp-surface); border: 1px solid var(--bp-border); border-radius: 14px; box-shadow: 0 24px 90px #07150f40; }
231
+ .bp-palette button { font: inherit; color: inherit; cursor: pointer; }
232
+ .bp-palette-input { display: flex; align-items: center; gap: 13px; border-bottom: 1px solid var(--bp-border); padding: 17px 18px; color: var(--bp-muted); }
233
+ .bp-palette-input > input { flex: 1; min-width: 0; border: 0; background: none; font: 14px var(--bp-font, system-ui); color: var(--bp-ink); outline: none; }
234
+ .bp-palette-input > input::placeholder { color: var(--bp-muted); }
235
+ .bp-palette-input > button { display: grid; place-items: center; padding: 5px; border: 0; border-radius: 5px; background: none; }
236
+ .bp-palette-input > button:hover { background: var(--bp-subtle); }
237
+ .bp-palette-caption { margin: 11px 18px 5px; font-size: 10px; color: var(--bp-muted); }
238
+ .bp-palette-results { overflow: auto; min-height: 0; padding: 8px; }
239
+ .bp-palette-results > button { display: flex; width: 100%; align-items: center; gap: 12px; text-align: left; padding: 12px; border: 1px solid transparent; border-radius: 8px; background: none; }
240
+ .bp-palette-results > button[aria-selected=true] { background: var(--bp-accent-soft); }
241
+ .bp-result-icon { display: grid; place-items: center; flex-shrink: 0; width: 32px; height: 32px; background: var(--bp-surface); border: 1px solid var(--bp-border); border-radius: 8px; color: var(--bp-muted); }
242
+ .bp-result-copy { min-width: 0; flex: 1; }
243
+ .bp-result-copy > strong { display: block; font-size: 12px; font-weight: 550; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
244
+ .bp-result-copy > small { display: block; color: var(--bp-muted); font-size: 10px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; margin-top: 3px; }
245
+ .bp-result-kind { font-size: 10px; color: var(--bp-muted); }
246
+ .bp-palette-footer { display: flex; flex-shrink: 0; justify-content: space-between; gap: 12px; color: var(--bp-muted); border-top: 1px solid var(--bp-border); padding: 11px 17px; font-size: 9px; }
247
+ .bp-palette-footer kbd { font: inherit; padding: 1px 4px; border: 1px solid var(--bp-border); border-radius: 3px; margin: 0 3px; }
248
+ .bp-search-empty { padding: 30px 12px; color: var(--bp-muted); font-size: 12px; text-align: center; }
249
+ .bp-sr-only { position: absolute; width: 1px; height: 1px; margin: -1px !important; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; padding: 0; border: 0; }
250
+ .bp-workspace :is(button, summary):focus-visible, .bp-palette button:focus-visible { outline: 2px solid var(--bp-focus); outline-offset: 3px; }
251
+ body[data-bot-product-ui] .bt-side { display: flex; flex-direction: column; }
252
+ body[data-bot-product-ui] .bt-side-top, body[data-bot-product-ui] .bt-rail-top { order: 0; flex-shrink: 0; }
253
+ body[data-bot-product-ui] .bp-nav { order: 1; flex-shrink: 0; max-height: 54%; overflow-y: auto; border-top: 0; border-bottom: 1px solid var(--bp-border); padding: 8px 10px 13px; margin: 0 4px 7px; display: flex; flex-direction: column; gap: 0; }
254
+ body[data-bot-product-ui] .bt-list { order: 2; min-height: 60px; flex: 1; }
255
+ body[data-bot-product-ui] .bt-leftcol-foot { order: 3; flex-shrink: 0; }
256
+ .bp-nav-group { display: flex; flex-direction: column; gap: 2px; }
257
+ .bp-nav .bp-nav-label { padding: 0 10px; margin: 14px 0 7px; font-size: 10px; font-weight: 500; letter-spacing: .02em; }
258
+ .bp-nav button { min-height: 33px; padding: 7px 10px; gap: 11px; font-size: 12px; border-radius: 7px; }
259
+ .bp-nav button[aria-current=page] { color: var(--bp-solid); background: var(--bp-accent-soft); font-weight: 600; }
260
+ .bp-nav .bp-nav-search { border: 1px solid var(--bp-border); background: var(--bp-surface); color: var(--bp-muted); margin: 2px 0 3px; }
261
+ body[data-bot-product-ui] .bt-side .bt-list { padding-top: 8px; }
262
+ body[data-bot-product-ui] .bt-row-preview { font-size: 11px; }
263
+ body[data-bot-product-ui] .bt-side-top .bt-brand { color: var(--bp-solid); }
264
+ body[data-bp-density=compact] .bp-workspace .bp-page { padding-top: 20px; }
265
+ body[data-bp-density=compact] .bp-workspace .bp-card { padding: 17px; margin-bottom: 14px; }
266
+ body[data-bp-density=compact] .bp-workspace .bp-page :is(td, th) { padding-top: 8px; padding-bottom: 8px; }
267
+ body[data-bp-density=compact] .bp-inbox-item { padding-top: 14px; padding-bottom: 14px; }
268
+ body[data-bp-density=compact] .bp-team-directory .bp-team-member { padding-top: 10px; padding-bottom: 10px; }
269
+ @container (max-width: 850px) {
270
+ .bp-home-main { grid-template-columns: minmax(0, 1fr) minmax(210px, .7fr); gap: 22px; }
271
+ .bp-home-secondary { padding-left: 20px; }
272
+ .bp-home-stats > button { gap: 8px; padding: 17px 11px; }
273
+ .bp-home-stats .bp-stat-icon { display: none; }
274
+ .bp-home-orbit { margin-right: 10px; width: 165px; height: 120px; }
275
+ .bp-home-orbit > span { inset: 20px 42px; }
276
+ .bp-inbox-preview .bp-inbox-actions { display: none; }
277
+ }
278
+ @container (max-width: 650px) {
279
+ .bp-home-main { grid-template-columns: 1fr; }
280
+ .bp-home-secondary { border-left: 0; border-top: 1px solid var(--bp-border); padding: 24px 0 0; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 25px; }
281
+ .bp-resource-links { margin-top: 0; border-top: 0; padding-top: 0; }
282
+ .bp-home-orbit { display: none; }
283
+ .bp-workspace .bp-team-layout { grid-template-columns: 1fr; }
284
+ .bp-team-directory-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); max-height: 340px; overflow-y: auto; }
285
+ .bp-inbox-item { flex-wrap: wrap; }
286
+ .bp-inbox-actions { flex-direction: row; width: 100%; margin-left: 46px; }
287
+ .bp-home-stats > button { padding: 16px 12px; }
288
+ .bp-home-stats > button > .bp-icon:last-child { display: none; }
289
+ }
290
+ @container (max-width: 440px) {
291
+ .bp-home-team-grid, .bp-home-secondary, .bp-team-directory-list { grid-template-columns: 1fr; }
292
+ .bp-home-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
293
+ .bp-home-stats > button:first-child { padding-left: 12px; }
294
+ .bp-home-stats > button:nth-child(3) { border-left: 0 !important; border-top: 1px solid var(--bp-border); }
295
+ .bp-home-stats > button:nth-child(4) { border-top: 1px solid var(--bp-border); }
296
+ .bp-goal-card { padding: 18px; }
297
+ .bp-goal-footer > span { max-width: 110px; font-size: 9px; }
298
+ .bp-home-intro { padding-bottom: 22px; }
299
+ }
300
+ @container workspace-navigation (max-width: 130px) {
301
+ .bp-nav-group { gap: 1px; }
302
+ .bp-nav .bp-nav-label { display: none; }
303
+ .bp-nav-group + .bp-nav-group { border-top: 1px solid var(--bp-border); padding-top: 6px; margin-top: 6px; }
304
+ }
305
+ @media (max-width: 1000px) { .bp-workspace-search > span, .bp-workspace-search kbd { display: none; } .bp-workspace-bar .bp-workspace-search { min-width: 0; background: none; border-color: transparent; } }
306
+ @media (max-width: 600px) {
307
+ .bp-workspace-bar { padding: 0 13px; height: 49px; gap: 8px; }
308
+ .bp-workspace-location, .bp-workspace-bar-actions { gap: 7px; }
309
+ .bp-workspace-brand > span { display: none; }
310
+ .bp-workspace .bp-page { padding: 20px 17px; }
311
+ .bp-palette-backdrop { padding: 18px 10px; }
312
+ .bp-palette { max-height: calc(100dvh - 40px); }
313
+ .bp-palette-footer > span:first-child { display: none; }
314
+ .bp-appearance-menu { right: -4px; }
315
+ }
316
+ @media (pointer: coarse) {
317
+ .bp-workspace button, .bp-workspace .bp-page button, .bp-nav button { min-height: 40px; }
318
+ .bp-workspace .bp-page .bp-text-button { min-height: 28px; }
319
+ .bp-appearance > summary { width: 40px; height: 40px; }
320
+ .bp-workspace :is(input, textarea), .bp-palette-input > input { font-size: 16px !important; }
321
+ }
322
+ @media (prefers-reduced-motion: reduce) { .bp-workspace *, .bp-palette * { transition: none !important; animation: none !important; scroll-behavior: auto !important; } }
323
+ .bp-pairing-identity { display: grid; gap: 8px; min-width: 0; padding: 14px; border: 1px solid var(--bp-border); border-radius: 12px; background: var(--bp-subtle); }
324
+ .bp-pairing-identity code { display: block; white-space: normal; overflow-wrap: anywhere; font-size: 12px; }
325
+ .bp-pairing-identity p { margin: 0; }
326
+ .bp-secure-pairing > summary { display: flex; align-items: center; gap: 8px; cursor: pointer; }
327
+ .bp-pairing-file { position: absolute; width: 1px !important; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
328
+ .bp-pairing-camera-overlay { position: fixed; inset: 0; z-index: 10002; display: grid; place-items: center; padding: 16px; background: #101e18b3; }
329
+ .bp-pairing-camera { width: min(540px,100%); padding: 18px; border: 1px solid var(--bp-border); border-radius: 16px; background: var(--bp-surface); color: var(--bp-ink); }
330
+ .bp-pairing-camera header { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 12px; margin-bottom: 12px; }
331
+ .bp-pairing-camera video { display: block; width: 100%; aspect-ratio: 4/3; background: #0d1411; border-radius: 12px; object-fit: cover; }
332
+ body[data-bot-product-ui] .bp-task-timeline li[data-focused-attempt] { background:var(--bp-hover);border-radius:8px; }