nastechai-desktop 18.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (546) hide show
  1. package/.prettierrc +11 -0
  2. package/DESIGN.md +167 -0
  3. package/README.md +141 -0
  4. package/assets/icon.icns +0 -0
  5. package/assets/icon.ico +0 -0
  6. package/assets/icon.png +0 -0
  7. package/components.json +21 -0
  8. package/electron/backend-env.cjs +112 -0
  9. package/electron/backend-env.test.cjs +111 -0
  10. package/electron/backend-probes.cjs +106 -0
  11. package/electron/backend-probes.test.cjs +82 -0
  12. package/electron/backend-ready.cjs +66 -0
  13. package/electron/bootstrap-platform.cjs +91 -0
  14. package/electron/bootstrap-platform.test.cjs +111 -0
  15. package/electron/bootstrap-runner.cjs +720 -0
  16. package/electron/bootstrap-runner.test.cjs +138 -0
  17. package/electron/connection-config.cjs +254 -0
  18. package/electron/connection-config.test.cjs +329 -0
  19. package/electron/dashboard-token.cjs +99 -0
  20. package/electron/dashboard-token.test.cjs +142 -0
  21. package/electron/desktop-uninstall.cjs +232 -0
  22. package/electron/desktop-uninstall.test.cjs +246 -0
  23. package/electron/entitlements.mac.inherit.plist +14 -0
  24. package/electron/entitlements.mac.plist +14 -0
  25. package/electron/fs-read-dir.cjs +109 -0
  26. package/electron/fs-read-dir.test.cjs +364 -0
  27. package/electron/gateway-ws-probe.cjs +188 -0
  28. package/electron/gateway-ws-probe.test.cjs +122 -0
  29. package/electron/git-root.cjs +54 -0
  30. package/electron/git-root.test.cjs +40 -0
  31. package/electron/git-worktrees.cjs +174 -0
  32. package/electron/hardening.cjs +184 -0
  33. package/electron/hardening.test.cjs +116 -0
  34. package/electron/main.cjs +5762 -0
  35. package/electron/oauth-net-request.cjs +20 -0
  36. package/electron/oauth-net-request.test.cjs +34 -0
  37. package/electron/preload.cjs +135 -0
  38. package/electron/session-windows.cjs +99 -0
  39. package/electron/session-windows.test.cjs +177 -0
  40. package/electron/update-remote.cjs +56 -0
  41. package/electron/update-remote.test.cjs +78 -0
  42. package/electron/vscode-marketplace.cjs +331 -0
  43. package/electron/vscode-marketplace.test.cjs +113 -0
  44. package/electron/windows-child-process.test.cjs +57 -0
  45. package/electron/windows-user-env.cjs +76 -0
  46. package/electron/windows-user-env.test.cjs +90 -0
  47. package/electron/workspace-cwd.cjs +38 -0
  48. package/electron/workspace-cwd.test.cjs +45 -0
  49. package/eslint.config.mjs +122 -0
  50. package/index.html +17 -0
  51. package/package.json +254 -0
  52. package/pr-assets/session-source-folders.png +0 -0
  53. package/preview-demo.html +65 -0
  54. package/public/apple-touch-icon.png +0 -0
  55. package/public/ds-assets/filler-bg0.jpg +0 -0
  56. package/public/nastech-frames/nastech-frame-0.png +0 -0
  57. package/public/nastech-frames/nastech-frame-1.png +0 -0
  58. package/public/nastech-frames/nastech-frame-2.png +0 -0
  59. package/public/nastech-frames/nastech-frame-3.png +0 -0
  60. package/public/nastech-frames/nastech-frame-4.png +0 -0
  61. package/public/nastech-frames/nastech-frame-5.png +0 -0
  62. package/public/nastech-frames/nastech-frame-6.png +0 -0
  63. package/public/nastech-frames/nastech-frame-7.png +0 -0
  64. package/public/nastech-girl.jpg +0 -0
  65. package/public/nastech-sprite.png +0 -0
  66. package/public/nastech.png +0 -0
  67. package/scripts/after-pack.cjs +41 -0
  68. package/scripts/assert-dist-built.cjs +70 -0
  69. package/scripts/assert-dist-built.test.cjs +84 -0
  70. package/scripts/assert-root-install.cjs +13 -0
  71. package/scripts/before-build.cjs +11 -0
  72. package/scripts/before-pack.cjs +78 -0
  73. package/scripts/before-pack.test.cjs +53 -0
  74. package/scripts/click-session.mjs +51 -0
  75. package/scripts/dev-no-hmr.mjs +22 -0
  76. package/scripts/diag-jump.mjs +115 -0
  77. package/scripts/diag-scroll-reset.mjs +229 -0
  78. package/scripts/eval.mjs +21 -0
  79. package/scripts/leak-typing.mjs +222 -0
  80. package/scripts/measure-jump.mjs +108 -0
  81. package/scripts/measure-latency.mjs +184 -0
  82. package/scripts/measure-real-stream.mjs +252 -0
  83. package/scripts/measure-submit.mjs +179 -0
  84. package/scripts/measure-synthetic-stream.mjs +322 -0
  85. package/scripts/notarize-artifact.cjs +77 -0
  86. package/scripts/notarize.cjs +100 -0
  87. package/scripts/patch-electron-builder-mac-binary.cjs +59 -0
  88. package/scripts/probe-renderer.mjs +38 -0
  89. package/scripts/probe-thread.mjs +40 -0
  90. package/scripts/profile-long-stream.mjs +191 -0
  91. package/scripts/profile-real-stream.mjs +137 -0
  92. package/scripts/profile-synth-stream.mjs +103 -0
  93. package/scripts/profile-typing-lag.md +381 -0
  94. package/scripts/profile-typing.mjs +260 -0
  95. package/scripts/reload-renderer.mjs +25 -0
  96. package/scripts/reload.mjs +36 -0
  97. package/scripts/set-exe-identity.cjs +94 -0
  98. package/scripts/stage-native-deps.cjs +159 -0
  99. package/scripts/test-desktop.mjs +425 -0
  100. package/scripts/write-build-stamp.cjs +126 -0
  101. package/src/app/agents/index.tsx +398 -0
  102. package/src/app/artifacts/index.test.ts +62 -0
  103. package/src/app/artifacts/index.tsx +906 -0
  104. package/src/app/chat/chat-drop-overlay.tsx +48 -0
  105. package/src/app/chat/chat-swap-overlay.tsx +47 -0
  106. package/src/app/chat/composer/attachments.tsx +114 -0
  107. package/src/app/chat/composer/completion-drawer.tsx +63 -0
  108. package/src/app/chat/composer/context-menu.tsx +172 -0
  109. package/src/app/chat/composer/controls.tsx +289 -0
  110. package/src/app/chat/composer/drop-affordance.ts +2 -0
  111. package/src/app/chat/composer/enter-submit-dom-race.test.tsx +218 -0
  112. package/src/app/chat/composer/focus.ts +134 -0
  113. package/src/app/chat/composer/help-hint.tsx +59 -0
  114. package/src/app/chat/composer/hooks/use-at-completions.ts +141 -0
  115. package/src/app/chat/composer/hooks/use-live-completion-adapter.ts +119 -0
  116. package/src/app/chat/composer/hooks/use-mic-recorder.ts +291 -0
  117. package/src/app/chat/composer/hooks/use-slash-completions.ts +114 -0
  118. package/src/app/chat/composer/hooks/use-voice-conversation.ts +390 -0
  119. package/src/app/chat/composer/hooks/use-voice-recorder.ts +116 -0
  120. package/src/app/chat/composer/ime-composition-dom-repro.test.tsx +108 -0
  121. package/src/app/chat/composer/index.tsx +1611 -0
  122. package/src/app/chat/composer/inline-refs.ts +138 -0
  123. package/src/app/chat/composer/model-pill.tsx +86 -0
  124. package/src/app/chat/composer/queue-panel.tsx +130 -0
  125. package/src/app/chat/composer/rich-editor.test.ts +18 -0
  126. package/src/app/chat/composer/rich-editor.ts +165 -0
  127. package/src/app/chat/composer/skin-slash-popover.tsx +61 -0
  128. package/src/app/chat/composer/slash-nav-dom-repro.test.tsx +186 -0
  129. package/src/app/chat/composer/status-stack/index.tsx +202 -0
  130. package/src/app/chat/composer/status-stack/status-row.tsx +155 -0
  131. package/src/app/chat/composer/text-utils.test.ts +77 -0
  132. package/src/app/chat/composer/text-utils.ts +107 -0
  133. package/src/app/chat/composer/trigger-popover.test.tsx +42 -0
  134. package/src/app/chat/composer/trigger-popover.tsx +116 -0
  135. package/src/app/chat/composer/types.ts +64 -0
  136. package/src/app/chat/composer/url-dialog.tsx +82 -0
  137. package/src/app/chat/composer/voice-activity.tsx +252 -0
  138. package/src/app/chat/hooks/use-composer-actions.test.ts +57 -0
  139. package/src/app/chat/hooks/use-composer-actions.ts +525 -0
  140. package/src/app/chat/hooks/use-file-drop-zone.ts +118 -0
  141. package/src/app/chat/index.tsx +390 -0
  142. package/src/app/chat/perf-probe.tsx +269 -0
  143. package/src/app/chat/right-rail/index.ts +1 -0
  144. package/src/app/chat/right-rail/preview-console-state.ts +82 -0
  145. package/src/app/chat/right-rail/preview-console.tsx +290 -0
  146. package/src/app/chat/right-rail/preview-file.tsx +559 -0
  147. package/src/app/chat/right-rail/preview-pane.test.tsx +43 -0
  148. package/src/app/chat/right-rail/preview-pane.tsx +657 -0
  149. package/src/app/chat/right-rail/preview.tsx +171 -0
  150. package/src/app/chat/scroll-to-bottom-button.test.tsx +67 -0
  151. package/src/app/chat/scroll-to-bottom-button.tsx +74 -0
  152. package/src/app/chat/sidebar/cron-jobs-section.tsx +325 -0
  153. package/src/app/chat/sidebar/index.tsx +1219 -0
  154. package/src/app/chat/sidebar/load-more-row.tsx +30 -0
  155. package/src/app/chat/sidebar/order.test.ts +21 -0
  156. package/src/app/chat/sidebar/order.ts +17 -0
  157. package/src/app/chat/sidebar/profile-switcher.tsx +516 -0
  158. package/src/app/chat/sidebar/session-actions-menu.tsx +264 -0
  159. package/src/app/chat/sidebar/session-row.tsx +257 -0
  160. package/src/app/chat/sidebar/virtual-session-list.tsx +154 -0
  161. package/src/app/chat/sidebar/workspace-groups.test.ts +149 -0
  162. package/src/app/chat/sidebar/workspace-groups.ts +326 -0
  163. package/src/app/chat/thread-loading.test.ts +34 -0
  164. package/src/app/chat/thread-loading.ts +26 -0
  165. package/src/app/command-center/index.tsx +654 -0
  166. package/src/app/command-palette/index.tsx +513 -0
  167. package/src/app/command-palette/marketplace-theme-page.tsx +157 -0
  168. package/src/app/cron/index.tsx +942 -0
  169. package/src/app/cron/job-state.ts +29 -0
  170. package/src/app/desktop-controller.tsx +938 -0
  171. package/src/app/floating-hud.ts +22 -0
  172. package/src/app/gateway/hooks/use-gateway-boot.test.tsx +265 -0
  173. package/src/app/gateway/hooks/use-gateway-boot.ts +387 -0
  174. package/src/app/gateway/hooks/use-gateway-request.ts +138 -0
  175. package/src/app/hooks/use-keybinds.ts +186 -0
  176. package/src/app/hooks/use-refresh-hotkey.ts +45 -0
  177. package/src/app/hooks/use-route-enum-param.ts +38 -0
  178. package/src/app/index.tsx +1 -0
  179. package/src/app/layout-constants.ts +13 -0
  180. package/src/app/messaging/index.tsx +648 -0
  181. package/src/app/messaging/platform-icon.tsx +93 -0
  182. package/src/app/model-picker-overlay.tsx +42 -0
  183. package/src/app/model-visibility-overlay.tsx +31 -0
  184. package/src/app/overlays/overlay-chrome.tsx +66 -0
  185. package/src/app/overlays/overlay-search-input.tsx +33 -0
  186. package/src/app/overlays/overlay-split-layout.tsx +130 -0
  187. package/src/app/overlays/overlay-view.tsx +91 -0
  188. package/src/app/page-search-shell.tsx +75 -0
  189. package/src/app/profiles/create-profile-dialog.tsx +154 -0
  190. package/src/app/profiles/delete-profile-dialog.tsx +65 -0
  191. package/src/app/profiles/index.tsx +671 -0
  192. package/src/app/profiles/rename-profile-dialog.tsx +125 -0
  193. package/src/app/right-sidebar/files/dnd-manager.ts +27 -0
  194. package/src/app/right-sidebar/files/ipc.test.ts +100 -0
  195. package/src/app/right-sidebar/files/ipc.ts +161 -0
  196. package/src/app/right-sidebar/files/remote-picker.tsx +177 -0
  197. package/src/app/right-sidebar/files/tree.tsx +224 -0
  198. package/src/app/right-sidebar/files/use-project-tree.test.ts +190 -0
  199. package/src/app/right-sidebar/files/use-project-tree.ts +268 -0
  200. package/src/app/right-sidebar/index.test.tsx +75 -0
  201. package/src/app/right-sidebar/index.tsx +395 -0
  202. package/src/app/right-sidebar/store.ts +15 -0
  203. package/src/app/right-sidebar/terminal/buffer.ts +65 -0
  204. package/src/app/right-sidebar/terminal/index.tsx +98 -0
  205. package/src/app/right-sidebar/terminal/persistent.tsx +122 -0
  206. package/src/app/right-sidebar/terminal/selection.ts +75 -0
  207. package/src/app/right-sidebar/terminal/use-terminal-session.ts +504 -0
  208. package/src/app/routes.ts +88 -0
  209. package/src/app/session/hooks/use-context-suggestions.ts +58 -0
  210. package/src/app/session/hooks/use-cwd-actions.ts +109 -0
  211. package/src/app/session/hooks/use-message-stream.ts +957 -0
  212. package/src/app/session/hooks/use-model-controls.test.tsx +198 -0
  213. package/src/app/session/hooks/use-model-controls.ts +106 -0
  214. package/src/app/session/hooks/use-nastech-config.ts +74 -0
  215. package/src/app/session/hooks/use-preview-routing.test.tsx +168 -0
  216. package/src/app/session/hooks/use-preview-routing.ts +223 -0
  217. package/src/app/session/hooks/use-prompt-actions.test.tsx +316 -0
  218. package/src/app/session/hooks/use-prompt-actions.ts +1030 -0
  219. package/src/app/session/hooks/use-route-resume.test.tsx +136 -0
  220. package/src/app/session/hooks/use-route-resume.ts +115 -0
  221. package/src/app/session/hooks/use-session-actions.test.tsx +119 -0
  222. package/src/app/session/hooks/use-session-actions.ts +885 -0
  223. package/src/app/session/hooks/use-session-state-cache.test.tsx +118 -0
  224. package/src/app/session/hooks/use-session-state-cache.ts +191 -0
  225. package/src/app/session-picker-overlay.tsx +32 -0
  226. package/src/app/session-switcher.tsx +107 -0
  227. package/src/app/settings/about-settings.tsx +173 -0
  228. package/src/app/settings/appearance-settings.tsx +162 -0
  229. package/src/app/settings/config-settings.tsx +384 -0
  230. package/src/app/settings/constants.ts +545 -0
  231. package/src/app/settings/credential-key-ui.tsx +373 -0
  232. package/src/app/settings/env-credentials.tsx +198 -0
  233. package/src/app/settings/env-var-actions-menu.tsx +136 -0
  234. package/src/app/settings/field-copy.ts +56 -0
  235. package/src/app/settings/gateway-settings.tsx +620 -0
  236. package/src/app/settings/helpers.test.ts +138 -0
  237. package/src/app/settings/helpers.ts +151 -0
  238. package/src/app/settings/index.tsx +237 -0
  239. package/src/app/settings/keys-settings.tsx +96 -0
  240. package/src/app/settings/mcp-settings.tsx +271 -0
  241. package/src/app/settings/model-settings.test.tsx +157 -0
  242. package/src/app/settings/model-settings.tsx +559 -0
  243. package/src/app/settings/notifications-settings.tsx +150 -0
  244. package/src/app/settings/primitives.tsx +115 -0
  245. package/src/app/settings/providers-settings.test.tsx +100 -0
  246. package/src/app/settings/providers-settings.tsx +258 -0
  247. package/src/app/settings/sessions-settings.tsx +276 -0
  248. package/src/app/settings/toolset-config-panel.test.tsx +289 -0
  249. package/src/app/settings/toolset-config-panel.tsx +449 -0
  250. package/src/app/settings/types.ts +42 -0
  251. package/src/app/settings/uninstall-section.tsx +185 -0
  252. package/src/app/settings/use-deep-link-highlight.ts +60 -0
  253. package/src/app/shell/app-shell.tsx +167 -0
  254. package/src/app/shell/gateway-menu-panel.tsx +150 -0
  255. package/src/app/shell/hooks/use-overlay-routing.ts +71 -0
  256. package/src/app/shell/hooks/use-status-snapshot.ts +57 -0
  257. package/src/app/shell/hooks/use-statusbar-items.tsx +403 -0
  258. package/src/app/shell/keybind-panel.tsx +220 -0
  259. package/src/app/shell/model-edit-submenu.test.tsx +84 -0
  260. package/src/app/shell/model-edit-submenu.tsx +245 -0
  261. package/src/app/shell/model-menu-panel.tsx +295 -0
  262. package/src/app/shell/sidebar-label.tsx +22 -0
  263. package/src/app/shell/statusbar-controls.tsx +185 -0
  264. package/src/app/shell/titlebar-controls.tsx +244 -0
  265. package/src/app/shell/titlebar.test.ts +26 -0
  266. package/src/app/shell/titlebar.ts +45 -0
  267. package/src/app/shell/use-group-registry.ts +39 -0
  268. package/src/app/skills/index.test.tsx +103 -0
  269. package/src/app/skills/index.tsx +371 -0
  270. package/src/app/types.ts +99 -0
  271. package/src/app/updates-overlay.tsx +369 -0
  272. package/src/components/Backdrop.tsx +114 -0
  273. package/src/components/assistant-ui/ansi-text.tsx +34 -0
  274. package/src/components/assistant-ui/clarify-tool.tsx +281 -0
  275. package/src/components/assistant-ui/directive-text.test.ts +39 -0
  276. package/src/components/assistant-ui/directive-text.tsx +389 -0
  277. package/src/components/assistant-ui/markdown-text.test.ts +204 -0
  278. package/src/components/assistant-ui/markdown-text.tsx +497 -0
  279. package/src/components/assistant-ui/message-render-boundary.test.tsx +80 -0
  280. package/src/components/assistant-ui/message-render-boundary.tsx +48 -0
  281. package/src/components/assistant-ui/streaming.test.tsx +739 -0
  282. package/src/components/assistant-ui/thread-list.tsx +307 -0
  283. package/src/components/assistant-ui/thread-virtualizer.tsx +512 -0
  284. package/src/components/assistant-ui/thread.tsx +1474 -0
  285. package/src/components/assistant-ui/todo-tool.tsx +109 -0
  286. package/src/components/assistant-ui/tool-approval-group.test.tsx +158 -0
  287. package/src/components/assistant-ui/tool-approval.test.tsx +81 -0
  288. package/src/components/assistant-ui/tool-approval.tsx +209 -0
  289. package/src/components/assistant-ui/tool-fallback-model.test.ts +66 -0
  290. package/src/components/assistant-ui/tool-fallback-model.ts +1368 -0
  291. package/src/components/assistant-ui/tool-fallback.tsx +466 -0
  292. package/src/components/assistant-ui/tooltip-icon-button.tsx +33 -0
  293. package/src/components/assistant-ui/user-message-edit.test.tsx +141 -0
  294. package/src/components/assistant-ui/user-message-text.tsx +150 -0
  295. package/src/components/boot-failure-overlay.tsx +246 -0
  296. package/src/components/boot-failure-reauth.test.ts +100 -0
  297. package/src/components/boot-failure-reauth.ts +81 -0
  298. package/src/components/brand-mark.tsx +19 -0
  299. package/src/components/chat/activity-timer-text.tsx +24 -0
  300. package/src/components/chat/activity-timer.test.tsx +43 -0
  301. package/src/components/chat/activity-timer.ts +64 -0
  302. package/src/components/chat/code-card.tsx +78 -0
  303. package/src/components/chat/compact-markdown.tsx +113 -0
  304. package/src/components/chat/composer-dock.ts +31 -0
  305. package/src/components/chat/diff-lines.tsx +54 -0
  306. package/src/components/chat/disclosure-row.tsx +63 -0
  307. package/src/components/chat/generated-image-context.tsx +19 -0
  308. package/src/components/chat/generated-image-result.tsx +174 -0
  309. package/src/components/chat/image-generation-placeholder.tsx +279 -0
  310. package/src/components/chat/intro-copy.jsonl +75 -0
  311. package/src/components/chat/intro.tsx +182 -0
  312. package/src/components/chat/preview-attachment.tsx +125 -0
  313. package/src/components/chat/shiki-highlighter.tsx +107 -0
  314. package/src/components/chat/status-row.tsx +70 -0
  315. package/src/components/chat/status-section.tsx +42 -0
  316. package/src/components/chat/terminal-output.tsx +50 -0
  317. package/src/components/chat/zoomable-image.tsx +177 -0
  318. package/src/components/desktop-install-overlay.tsx +595 -0
  319. package/src/components/desktop-onboarding-overlay.test.tsx +100 -0
  320. package/src/components/desktop-onboarding-overlay.tsx +1286 -0
  321. package/src/components/error-boundary.tsx +77 -0
  322. package/src/components/gateway-connecting-overlay.test.tsx +143 -0
  323. package/src/components/gateway-connecting-overlay.tsx +183 -0
  324. package/src/components/haptics-provider.tsx +19 -0
  325. package/src/components/language-switcher.test.tsx +53 -0
  326. package/src/components/language-switcher.tsx +175 -0
  327. package/src/components/model-picker.tsx +340 -0
  328. package/src/components/model-visibility-dialog.tsx +155 -0
  329. package/src/components/notifications.tsx +196 -0
  330. package/src/components/page-loader.tsx +34 -0
  331. package/src/components/pane-shell/context.ts +14 -0
  332. package/src/components/pane-shell/index.ts +4 -0
  333. package/src/components/pane-shell/pane-shell.test.tsx +333 -0
  334. package/src/components/pane-shell/pane-shell.tsx +330 -0
  335. package/src/components/prompt-overlays.tsx +234 -0
  336. package/src/components/session-picker.tsx +108 -0
  337. package/src/components/status-dot.tsx +26 -0
  338. package/src/components/ui/action-status.tsx +25 -0
  339. package/src/components/ui/alert.tsx +53 -0
  340. package/src/components/ui/badge.tsx +35 -0
  341. package/src/components/ui/braille-spinner.tsx +61 -0
  342. package/src/components/ui/button.tsx +81 -0
  343. package/src/components/ui/checkbox.tsx +27 -0
  344. package/src/components/ui/codicon.tsx +20 -0
  345. package/src/components/ui/command.tsx +111 -0
  346. package/src/components/ui/confirm-dialog.tsx +109 -0
  347. package/src/components/ui/context-menu.tsx +141 -0
  348. package/src/components/ui/control.ts +25 -0
  349. package/src/components/ui/copy-button.test.tsx +36 -0
  350. package/src/components/ui/copy-button.tsx +229 -0
  351. package/src/components/ui/dialog.tsx +152 -0
  352. package/src/components/ui/disclosure-caret.tsx +20 -0
  353. package/src/components/ui/dropdown-menu.tsx +291 -0
  354. package/src/components/ui/error-state.tsx +50 -0
  355. package/src/components/ui/fade-text.tsx +110 -0
  356. package/src/components/ui/glyph-spinner.tsx +63 -0
  357. package/src/components/ui/input.tsx +22 -0
  358. package/src/components/ui/kbd.tsx +37 -0
  359. package/src/components/ui/loader.tsx +558 -0
  360. package/src/components/ui/log-view.tsx +17 -0
  361. package/src/components/ui/pagination.tsx +114 -0
  362. package/src/components/ui/popover.tsx +44 -0
  363. package/src/components/ui/scroll-area.tsx +43 -0
  364. package/src/components/ui/search-field.tsx +80 -0
  365. package/src/components/ui/segmented-control.tsx +51 -0
  366. package/src/components/ui/select.tsx +92 -0
  367. package/src/components/ui/separator.tsx +26 -0
  368. package/src/components/ui/sheet.tsx +116 -0
  369. package/src/components/ui/sidebar.tsx +674 -0
  370. package/src/components/ui/skeleton.tsx +7 -0
  371. package/src/components/ui/switch.tsx +49 -0
  372. package/src/components/ui/tabs.tsx +36 -0
  373. package/src/components/ui/text-tab.tsx +43 -0
  374. package/src/components/ui/textarea.tsx +11 -0
  375. package/src/components/ui/tool-icon.tsx +65 -0
  376. package/src/components/ui/tooltip.tsx +69 -0
  377. package/src/fonts/JetBrainsMono-Bold.woff2 +0 -0
  378. package/src/fonts/JetBrainsMono-Italic.woff2 +0 -0
  379. package/src/fonts/JetBrainsMono-Regular.woff2 +0 -0
  380. package/src/global.d.ts +457 -0
  381. package/src/hooks/use-image-download.ts +85 -0
  382. package/src/hooks/use-media-query.ts +24 -0
  383. package/src/hooks/use-mobile.ts +3 -0
  384. package/src/hooks/use-resize-observer.ts +38 -0
  385. package/src/hooks/use-worktree-info.ts +68 -0
  386. package/src/i18n/catalog.ts +12 -0
  387. package/src/i18n/context.test.tsx +232 -0
  388. package/src/i18n/context.tsx +183 -0
  389. package/src/i18n/define-locale.ts +41 -0
  390. package/src/i18n/en.ts +1779 -0
  391. package/src/i18n/index.ts +20 -0
  392. package/src/i18n/ja.ts +1890 -0
  393. package/src/i18n/languages.test.ts +43 -0
  394. package/src/i18n/languages.ts +86 -0
  395. package/src/i18n/runtime.test.ts +75 -0
  396. package/src/i18n/runtime.ts +53 -0
  397. package/src/i18n/types.ts +1452 -0
  398. package/src/i18n/zh-hant.ts +1849 -0
  399. package/src/i18n/zh.ts +1923 -0
  400. package/src/lib/ansi.test.ts +123 -0
  401. package/src/lib/ansi.ts +175 -0
  402. package/src/lib/chat-messages.test.ts +708 -0
  403. package/src/lib/chat-messages.ts +885 -0
  404. package/src/lib/chat-runtime.test.ts +18 -0
  405. package/src/lib/chat-runtime.ts +335 -0
  406. package/src/lib/clipboard.ts +28 -0
  407. package/src/lib/commit-changelog.test.ts +114 -0
  408. package/src/lib/commit-changelog.ts +177 -0
  409. package/src/lib/completion-sound.ts +519 -0
  410. package/src/lib/desktop-fs.test.ts +116 -0
  411. package/src/lib/desktop-fs.ts +113 -0
  412. package/src/lib/desktop-slash-commands.test.ts +126 -0
  413. package/src/lib/desktop-slash-commands.ts +286 -0
  414. package/src/lib/embedded-images.test.ts +35 -0
  415. package/src/lib/embedded-images.ts +60 -0
  416. package/src/lib/external-link.test.tsx +168 -0
  417. package/src/lib/external-link.tsx +303 -0
  418. package/src/lib/gateway-events.test.ts +27 -0
  419. package/src/lib/gateway-events.ts +49 -0
  420. package/src/lib/gateway-ws-url.test.ts +78 -0
  421. package/src/lib/gateway-ws-url.ts +91 -0
  422. package/src/lib/generated-images.test.ts +97 -0
  423. package/src/lib/generated-images.ts +116 -0
  424. package/src/lib/haptics.ts +129 -0
  425. package/src/lib/icons.ts +203 -0
  426. package/src/lib/incremental-external-store-runtime.ts +188 -0
  427. package/src/lib/katex-memo.ts +260 -0
  428. package/src/lib/keybinds/actions.ts +125 -0
  429. package/src/lib/keybinds/combo.test.ts +86 -0
  430. package/src/lib/keybinds/combo.ts +169 -0
  431. package/src/lib/local-preview.ts +126 -0
  432. package/src/lib/markdown-code.test.ts +23 -0
  433. package/src/lib/markdown-code.ts +195 -0
  434. package/src/lib/markdown-preprocess.ts +386 -0
  435. package/src/lib/media.remote.test.ts +58 -0
  436. package/src/lib/media.ts +111 -0
  437. package/src/lib/model-status-label.test.ts +31 -0
  438. package/src/lib/model-status-label.ts +103 -0
  439. package/src/lib/mutable-ref.ts +6 -0
  440. package/src/lib/preview-targets.test.ts +27 -0
  441. package/src/lib/preview-targets.ts +63 -0
  442. package/src/lib/profile-color.ts +58 -0
  443. package/src/lib/provider-setup-errors.test.ts +26 -0
  444. package/src/lib/provider-setup-errors.ts +12 -0
  445. package/src/lib/query-client.ts +13 -0
  446. package/src/lib/remend-tail.test.ts +105 -0
  447. package/src/lib/remend-tail.ts +108 -0
  448. package/src/lib/runtime-readiness.test.ts +65 -0
  449. package/src/lib/runtime-readiness.ts +147 -0
  450. package/src/lib/session-export.ts +57 -0
  451. package/src/lib/session-search.test.ts +58 -0
  452. package/src/lib/session-search.ts +19 -0
  453. package/src/lib/session-source.ts +62 -0
  454. package/src/lib/speech-text.ts +35 -0
  455. package/src/lib/statusbar.ts +91 -0
  456. package/src/lib/storage.test.ts +25 -0
  457. package/src/lib/storage.ts +107 -0
  458. package/src/lib/todos.test.ts +35 -0
  459. package/src/lib/todos.ts +51 -0
  460. package/src/lib/tool-result-summary.test.ts +106 -0
  461. package/src/lib/tool-result-summary.ts +467 -0
  462. package/src/lib/update-copy.test.ts +38 -0
  463. package/src/lib/update-copy.ts +44 -0
  464. package/src/lib/use-enter-animation.ts +100 -0
  465. package/src/lib/utils.ts +6 -0
  466. package/src/lib/voice-playback.ts +128 -0
  467. package/src/lib/yolo-session.ts +26 -0
  468. package/src/main.tsx +43 -0
  469. package/src/nastech.test.ts +49 -0
  470. package/src/nastech.ts +718 -0
  471. package/src/store/activity.ts +100 -0
  472. package/src/store/boot.ts +91 -0
  473. package/src/store/clarify.test.ts +81 -0
  474. package/src/store/clarify.ts +69 -0
  475. package/src/store/command-palette.ts +20 -0
  476. package/src/store/compaction.test.ts +53 -0
  477. package/src/store/compaction.ts +38 -0
  478. package/src/store/completion-sound.ts +32 -0
  479. package/src/store/composer-input-history.test.ts +147 -0
  480. package/src/store/composer-input-history.ts +158 -0
  481. package/src/store/composer-queue.test.ts +148 -0
  482. package/src/store/composer-queue.ts +239 -0
  483. package/src/store/composer-status.test.ts +99 -0
  484. package/src/store/composer-status.ts +277 -0
  485. package/src/store/composer.test.ts +106 -0
  486. package/src/store/composer.ts +184 -0
  487. package/src/store/cron.ts +19 -0
  488. package/src/store/gateway.ts +290 -0
  489. package/src/store/haptics.ts +17 -0
  490. package/src/store/keybinds.ts +139 -0
  491. package/src/store/layout.ts +176 -0
  492. package/src/store/model-presets.test.ts +51 -0
  493. package/src/store/model-presets.ts +86 -0
  494. package/src/store/model-visibility.test.ts +37 -0
  495. package/src/store/model-visibility.ts +108 -0
  496. package/src/store/native-notifications.test.ts +192 -0
  497. package/src/store/native-notifications.ts +203 -0
  498. package/src/store/notifications.ts +165 -0
  499. package/src/store/onboarding.test.ts +372 -0
  500. package/src/store/onboarding.ts +866 -0
  501. package/src/store/panes.test.ts +146 -0
  502. package/src/store/panes.ts +145 -0
  503. package/src/store/preview.test.ts +135 -0
  504. package/src/store/preview.ts +466 -0
  505. package/src/store/profile.test.ts +89 -0
  506. package/src/store/profile.ts +365 -0
  507. package/src/store/prompts.test.ts +121 -0
  508. package/src/store/prompts.ts +115 -0
  509. package/src/store/session-switcher.test.ts +115 -0
  510. package/src/store/session-switcher.ts +128 -0
  511. package/src/store/session-sync.ts +25 -0
  512. package/src/store/session.test.ts +131 -0
  513. package/src/store/session.ts +255 -0
  514. package/src/store/subagents.test.ts +111 -0
  515. package/src/store/subagents.ts +260 -0
  516. package/src/store/thread-scroll.ts +46 -0
  517. package/src/store/todos.test.ts +47 -0
  518. package/src/store/todos.ts +64 -0
  519. package/src/store/tool-diffs.ts +23 -0
  520. package/src/store/tool-dismiss.ts +45 -0
  521. package/src/store/tool-view.ts +91 -0
  522. package/src/store/translucency.ts +38 -0
  523. package/src/store/updates.test.ts +77 -0
  524. package/src/store/updates.ts +315 -0
  525. package/src/store/voice-playback.ts +24 -0
  526. package/src/store/windows.test.ts +143 -0
  527. package/src/store/windows.ts +77 -0
  528. package/src/styles.css +1235 -0
  529. package/src/themes/color.ts +142 -0
  530. package/src/themes/context.tsx +339 -0
  531. package/src/themes/index.ts +3 -0
  532. package/src/themes/install.test.ts +119 -0
  533. package/src/themes/install.ts +95 -0
  534. package/src/themes/presets.test.ts +33 -0
  535. package/src/themes/presets.ts +293 -0
  536. package/src/themes/profile-theme.test.ts +41 -0
  537. package/src/themes/types.ts +66 -0
  538. package/src/themes/use-skin-command.ts +60 -0
  539. package/src/themes/user-themes.test.ts +63 -0
  540. package/src/themes/user-themes.ts +122 -0
  541. package/src/themes/vscode.test.ts +171 -0
  542. package/src/themes/vscode.ts +343 -0
  543. package/src/types/nastech.ts +646 -0
  544. package/src/vite-env.d.ts +1 -0
  545. package/tsconfig.json +25 -0
  546. package/vite.config.ts +56 -0
package/src/styles.css ADDED
@@ -0,0 +1,1235 @@
1
+ @import 'tailwindcss';
2
+ @plugin '@tailwindcss/typography';
3
+ @import 'tw-shimmer';
4
+ @import 'katex/dist/katex.min.css';
5
+ @import '@vscode/codicons/dist/codicon.css';
6
+ @custom-variant dark (&:is(.dark *));
7
+
8
+ @font-face {
9
+ font-family: 'Collapse';
10
+ font-style: normal;
11
+ font-weight: 700;
12
+ font-display: swap;
13
+ src: url('../../../node_modules/@nastech-ai/ui/dist/fonts/Collapse-Bold.woff2') format('woff2');
14
+ }
15
+
16
+ @theme inline {
17
+ --color-background: var(--dt-background);
18
+ --color-foreground: var(--dt-foreground);
19
+ --color-card: var(--dt-card);
20
+ --color-card-foreground: var(--dt-card-foreground);
21
+ --color-muted: var(--dt-muted);
22
+ --color-muted-foreground: var(--dt-muted-foreground);
23
+ --color-popover: var(--dt-popover);
24
+ --color-popover-foreground: var(--dt-popover-foreground);
25
+ --color-primary: var(--dt-primary);
26
+ --color-primary-foreground: var(--dt-primary-foreground);
27
+ --color-secondary: var(--dt-secondary);
28
+ --color-secondary-foreground: var(--dt-secondary-foreground);
29
+ --color-accent: var(--dt-accent);
30
+ --color-accent-foreground: var(--dt-accent-foreground);
31
+ --color-border: var(--dt-border);
32
+ --color-input: var(--dt-input);
33
+ --color-ring: var(--dt-ring);
34
+ --color-destructive: var(--dt-destructive);
35
+ --color-destructive-foreground: var(--dt-destructive-foreground);
36
+
37
+ --color-midground: var(--dt-midground);
38
+ --color-midground-foreground: var(--dt-midground-foreground);
39
+
40
+ --font-sans: var(--dt-font-sans);
41
+ --font-mono: var(--dt-font-mono);
42
+
43
+ --spacing-mul: var(--dt-spacing-mul, 1);
44
+
45
+ --radius-xs: calc(var(--radius-scalar) * 0.125rem);
46
+ --radius-sm: calc(var(--radius-scalar) * 0.5rem);
47
+ --radius-md: calc(var(--radius-scalar) * 0.625rem);
48
+ --radius-lg: calc(var(--radius-scalar) * 0.75rem);
49
+ --radius-xl: calc(var(--radius-scalar) * 1rem);
50
+ --radius-2xl: calc(var(--radius-scalar) * 1.5rem);
51
+ --radius-3xl: calc(var(--radius-scalar) * 2rem);
52
+ --radius-4xl: calc(var(--radius-scalar) * 2.5rem);
53
+
54
+ --color-sidebar-ring: var(--sidebar-ring);
55
+ --color-sidebar-border: var(--sidebar-border);
56
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
57
+ --color-sidebar-accent: var(--sidebar-accent);
58
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
59
+ --color-sidebar-primary: var(--sidebar-primary);
60
+ --color-sidebar-foreground: var(--sidebar-foreground);
61
+ --color-sidebar: var(--sidebar);
62
+
63
+ --shadow-xs: 0 0.0625rem 0.125rem color-mix(in srgb, #000 5%, transparent);
64
+ --shadow-sm:
65
+ 0 0 0 0.0625rem color-mix(in srgb, var(--dt-foreground) 6%, transparent),
66
+ 0 0.125rem 0.5rem color-mix(in srgb, #000 4%, transparent);
67
+ --shadow-md:
68
+ 0 0 0 0.0625rem color-mix(in srgb, var(--dt-foreground) 8%, transparent),
69
+ 0 0.25rem 1rem color-mix(in srgb, #000 8%, transparent),
70
+ 0 1rem 2rem -1.5rem color-mix(in srgb, #000 18%, transparent);
71
+ /* Soft floating shadow for borderless modals/overlays. Single top light
72
+ source: every layer is centered (x=0) and cast downward, with negative
73
+ spread that grows with the blur so each layer is pulled horizontally inward
74
+ — the shadow pools below the panel instead of bleeding out every side.
75
+ Layered (contact → ambient) for a smooth, natural falloff. */
76
+ --shadow-nastech:
77
+ 0 0.125rem 0.25rem -0.125rem color-mix(in srgb, #000 7%, transparent),
78
+ 0 0.5rem 0.75rem -0.375rem color-mix(in srgb, #000 6%, transparent),
79
+ 0 1.25rem 1.75rem -0.875rem color-mix(in srgb, #000 6%, transparent),
80
+ 0 2.25rem 3rem -1.75rem color-mix(in srgb, #000 0%, transparent);
81
+ /* Hairline border paired with --shadow-nastech on borderless overlays.
82
+ currentColor resolves per-element, so it adapts to text color/theme. */
83
+ --stroke-nastech: color-mix(in srgb, currentColor 3%, transparent);
84
+ --shadow-lg:
85
+ inset 0 0.0625rem 0 color-mix(in srgb, #fff 28%, transparent),
86
+ 0 0 0 0.0625rem color-mix(in srgb, var(--dt-foreground) 8%, transparent),
87
+ 0 0.75rem 2rem color-mix(in srgb, #000 12%, transparent);
88
+ --shadow-composer: 0 0.0625rem 0.125rem color-mix(in srgb, #000 5%, transparent);
89
+ }
90
+
91
+ @layer base {
92
+ :root {
93
+ color-scheme: light;
94
+
95
+ --theme-foreground: #17171a;
96
+ --theme-primary: #0053fd;
97
+ --theme-secondary: color-mix(in srgb, #0053fd 7%, #ffffff);
98
+ --theme-accent-soft: color-mix(in srgb, #0053fd 10%, #ffffff);
99
+ --theme-midground: #0053fd;
100
+ --theme-warm: #cf806d;
101
+ --theme-background-seed: #f8faff;
102
+ --theme-sidebar-seed: #f3f7ff;
103
+ --theme-card-seed: #ffffff;
104
+ --theme-elevated-seed: #ffffff;
105
+ --theme-bubble-seed: color-mix(in srgb, #0053fd 6%, #ffffff);
106
+ --theme-neutral-chrome: #f3f3f3;
107
+ --theme-neutral-sidebar: #f3f3f3;
108
+ --theme-neutral-card: #fcfcfc;
109
+ --theme-mix-chrome: 92%;
110
+ --theme-mix-sidebar: 100%;
111
+ --theme-mix-card: 22%;
112
+ --theme-mix-elevated: 28%;
113
+ --theme-mix-bubble: 0%;
114
+ --theme-fill-primary-accent-mix: 16%;
115
+ --theme-fill-secondary-accent-mix: 11%;
116
+ --theme-fill-tertiary-accent-mix: 8%;
117
+ --theme-fill-quaternary-accent-mix: 5%;
118
+ --theme-fill-quinary-accent-mix: 3%;
119
+ --theme-stroke-primary-accent-mix: 24%;
120
+ --theme-stroke-secondary-accent-mix: 16%;
121
+ --theme-stroke-tertiary-accent-mix: 10%;
122
+ --theme-stroke-quaternary-accent-mix: 6%;
123
+ --theme-row-hover-accent-mix: 4%;
124
+ --theme-row-active-accent-mix: 8%;
125
+ --theme-control-hover-accent-mix: 6%;
126
+ --theme-control-active-accent-mix: 8%;
127
+
128
+ --ui-base: var(--theme-foreground);
129
+ --ui-accent: var(--theme-midground);
130
+ --ui-accent-secondary: var(--theme-primary);
131
+ --ui-warm: var(--theme-warm);
132
+ --ui-red: #cf2d56;
133
+ --ui-orange: #db704b;
134
+ --ui-yellow: #c08532;
135
+ --ui-green: #1f8a65;
136
+ --ui-cyan: #4c7f8c;
137
+ --ui-blue: #0053fd;
138
+ --ui-purple: #9e94d5;
139
+ --ui-bg-chrome: color-mix(
140
+ in srgb,
141
+ var(--theme-background-seed) var(--theme-mix-chrome),
142
+ var(--theme-neutral-chrome)
143
+ );
144
+ --ui-bg-sidebar: color-mix(
145
+ in srgb,
146
+ var(--theme-sidebar-seed) var(--theme-mix-sidebar),
147
+ var(--theme-neutral-sidebar)
148
+ );
149
+ --ui-bg-editor: color-mix(in srgb, var(--theme-card-seed) var(--theme-mix-card), var(--theme-neutral-card));
150
+ --ui-bg-elevated: color-mix(
151
+ in srgb,
152
+ var(--theme-elevated-seed) var(--theme-mix-elevated),
153
+ var(--theme-neutral-card)
154
+ );
155
+ --ui-bg-card: color-mix(in srgb, var(--ui-accent) 4%, color-mix(in srgb, var(--ui-base) 4%, transparent));
156
+ --ui-bg-input: #fcfcfc;
157
+ --ui-bg-primary: color-mix(
158
+ in srgb,
159
+ var(--ui-accent) var(--theme-fill-primary-accent-mix),
160
+ color-mix(in srgb, var(--ui-base) 10%, transparent)
161
+ );
162
+ --ui-bg-secondary: color-mix(
163
+ in srgb,
164
+ var(--ui-accent) var(--theme-fill-secondary-accent-mix),
165
+ color-mix(in srgb, var(--ui-base) 7%, transparent)
166
+ );
167
+ --ui-bg-tertiary: color-mix(
168
+ in srgb,
169
+ var(--ui-accent) var(--theme-fill-tertiary-accent-mix),
170
+ color-mix(in srgb, var(--ui-base) 5%, transparent)
171
+ );
172
+ --ui-bg-quaternary: color-mix(
173
+ in srgb,
174
+ var(--ui-accent) var(--theme-fill-quaternary-accent-mix),
175
+ color-mix(in srgb, var(--ui-base) 4%, transparent)
176
+ );
177
+ --ui-bg-quinary: color-mix(
178
+ in srgb,
179
+ var(--ui-accent) var(--theme-fill-quinary-accent-mix),
180
+ color-mix(in srgb, var(--ui-base) 3%, transparent)
181
+ );
182
+ --ui-row-hover-background: color-mix(
183
+ in srgb,
184
+ var(--ui-accent) var(--theme-row-hover-accent-mix),
185
+ color-mix(in srgb, var(--ui-base) 3%, transparent)
186
+ );
187
+ --ui-row-active-background: color-mix(
188
+ in srgb,
189
+ var(--ui-accent) var(--theme-row-active-accent-mix),
190
+ color-mix(in srgb, var(--ui-base) 5%, transparent)
191
+ );
192
+ --ui-control-hover-background: color-mix(
193
+ in srgb,
194
+ var(--ui-accent) var(--theme-control-hover-accent-mix),
195
+ color-mix(in srgb, var(--ui-base) 4%, transparent)
196
+ );
197
+ --ui-control-active-background: color-mix(
198
+ in srgb,
199
+ var(--ui-accent) var(--theme-control-active-accent-mix),
200
+ color-mix(in srgb, var(--ui-base) 5%, transparent)
201
+ );
202
+ --ui-text-primary: color-mix(in srgb, var(--ui-base) 94%, transparent);
203
+ --ui-text-secondary: color-mix(in srgb, var(--ui-base) 74%, transparent);
204
+ --ui-text-tertiary: color-mix(in srgb, var(--ui-base) 54%, transparent);
205
+ --ui-text-quaternary: color-mix(in srgb, var(--ui-base) 36%, transparent);
206
+ --ui-stroke-primary: color-mix(
207
+ in srgb,
208
+ var(--ui-accent) var(--theme-stroke-primary-accent-mix),
209
+ color-mix(in srgb, var(--ui-base) 10%, transparent)
210
+ );
211
+ --ui-stroke-secondary: color-mix(
212
+ in srgb,
213
+ var(--ui-accent) var(--theme-stroke-secondary-accent-mix),
214
+ color-mix(in srgb, var(--ui-base) 7%, transparent)
215
+ );
216
+ --ui-stroke-tertiary: color-mix(
217
+ in srgb,
218
+ var(--ui-accent) var(--theme-stroke-tertiary-accent-mix),
219
+ color-mix(in srgb, var(--ui-base) 5%, transparent)
220
+ );
221
+ --ui-stroke-quaternary: color-mix(
222
+ in srgb,
223
+ var(--ui-accent) var(--theme-stroke-quaternary-accent-mix),
224
+ color-mix(in srgb, var(--ui-base) 3%, transparent)
225
+ );
226
+ --ui-sash-hover-border: color-mix(in srgb, var(--ui-accent) 18%, var(--ui-stroke-tertiary));
227
+ --ui-sash-hover-background: color-mix(in srgb, var(--ui-accent) 6%, transparent);
228
+ --ui-surface-background: var(--ui-bg-editor);
229
+ --ui-sidebar-surface-background: var(--ui-bg-sidebar);
230
+ --ui-chat-surface-background: var(--ui-bg-chrome);
231
+ --ui-editor-surface-background: var(--ui-bg-chrome);
232
+ --ui-chat-bubble-background: color-mix(
233
+ in srgb,
234
+ var(--theme-bubble-seed) var(--theme-mix-bubble),
235
+ var(--theme-neutral-card)
236
+ );
237
+ --ui-chat-bubble-opaque-background: var(--ui-bg-editor);
238
+ --ui-inline-code-background: color-mix(in srgb, #141414 5%, transparent);
239
+ --ui-inline-code-border: color-mix(in srgb, #141414 8%, transparent);
240
+ --ui-inline-code-foreground: color-mix(in srgb, #141414 88%, transparent);
241
+ --ui-selection-background: color-mix(in srgb, #ffd24a 55%, transparent);
242
+
243
+ --dt-background: var(--ui-bg-chrome);
244
+ --dt-foreground: var(--ui-text-primary);
245
+ --dt-card: var(--ui-bg-editor);
246
+ --dt-card-foreground: var(--ui-text-primary);
247
+ --dt-muted: var(--ui-bg-tertiary);
248
+ --dt-muted-foreground: var(--ui-text-tertiary);
249
+ --dt-popover: color-mix(in srgb, var(--ui-bg-elevated) 96%, transparent);
250
+ --dt-popover-foreground: var(--ui-text-primary);
251
+ --dt-primary: var(--theme-primary);
252
+ --dt-primary-foreground: #fcfcfc;
253
+ --dt-secondary: var(--theme-secondary);
254
+ --dt-secondary-foreground: var(--ui-text-secondary);
255
+ --dt-accent: var(--theme-accent-soft);
256
+ --dt-accent-foreground: var(--ui-text-primary);
257
+ --dt-border: var(--ui-stroke-secondary);
258
+ --dt-input: var(--ui-stroke-primary);
259
+ --dt-ring: var(--ui-stroke-primary);
260
+ --dt-midground: var(--theme-midground);
261
+ --dt-composer-ring: var(--ui-base);
262
+ --dt-destructive: #cf2d56;
263
+ --dt-destructive-foreground: #ffffff;
264
+ --dt-sidebar-bg: var(--ui-bg-sidebar);
265
+ --dt-sidebar-border: var(--ui-stroke-secondary);
266
+ --dt-user-bubble: var(--ui-chat-bubble-background);
267
+ --dt-user-bubble-border: var(--ui-stroke-tertiary);
268
+
269
+ --dt-font-sans: 'Segoe WPC', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'SF Pro Text', system-ui, sans-serif,
270
+ 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji', emoji;
271
+ --dt-font-mono: 'Cascadia Code', 'JetBrains Mono', 'SF Mono', ui-monospace, Menlo, Consolas, monospace,
272
+ 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji', emoji;
273
+ --dt-base-size: 1rem;
274
+ --dt-line-height: 1.5;
275
+ --dt-letter-spacing: 0;
276
+ --dt-spacing-mul: 1;
277
+
278
+ --radius: 0.75rem;
279
+ --radius-scalar: 0.6;
280
+
281
+ /* Space under last message vs overlay composer — driven by the measured composer height (see composer/index.tsx). */
282
+ --thread-last-message-clearance: calc(var(--composer-measured-height) + 2rem);
283
+
284
+ --composer-shell-pad-block-end: 0.625rem;
285
+ --message-text-indent: 0.75rem;
286
+ --conversation-text-font-size: 0.8125rem;
287
+ --conversation-tool-font-size: 0.6875rem;
288
+ --conversation-caption-font-size: 0.75rem;
289
+ --conversation-line-height: 1.125rem;
290
+ --conversation-caption-line-height: 1rem;
291
+ --conversation-turn-gap: 0.375rem;
292
+ /* Gap between top-level turn blocks (prose ↔ tools ↔ thinking) — enough air
293
+ that scaffolding reads as separate from the reply, not crammed into it. */
294
+ --turn-block-gap: 0.75rem;
295
+ /* Tight gap between tool rows inside a single action group, so a back-to-back
296
+ run still reads as one cohesive sequence. */
297
+ --tool-row-gap: 0.375rem;
298
+ /* Paragraph spacing — vertical gap between prose paragraphs, both inside a
299
+ markdown block and between consecutive prose parts. Single knob; tweak
300
+ freely. */
301
+ --paragraph-gap: 0.45rem;
302
+ --sticky-human-top: 0.23rem;
303
+ --file-tree-row-height: 1.375rem;
304
+
305
+ --composer-width: 48.75rem;
306
+ --composer-control-size: 1.75rem;
307
+ --composer-control-primary-size: 1.875rem;
308
+ --composer-control-gap: 0.25rem;
309
+ --composer-row-gap: 0.25rem;
310
+ --composer-ring-strength: 1;
311
+ --composer-surface-pad-x: 0.5rem;
312
+ --composer-surface-pad-y: 0.3125rem;
313
+ --composer-input-min-height: 1.625rem;
314
+ --composer-input-max-height: 9.375rem;
315
+ --composer-input-inline-min-width: 8rem;
316
+ --composer-fallback-height: 2.75rem;
317
+ --composer-measured-height: calc(0.5rem + var(--composer-shell-pad-block-end) + var(--composer-fallback-height));
318
+ --composer-surface-measured-height: var(--composer-fallback-height);
319
+ --thread-viewport-height: max(
320
+ 0rem,
321
+ calc(100% - var(--composer-measured-height) + var(--composer-surface-measured-height))
322
+ );
323
+ --vsq: min(0.5vh, 0.5vw);
324
+ --image-preview-max-width: 34rem;
325
+ --image-preview-height: clamp(16.25rem, calc(var(--vsq) * 100), 26.25rem);
326
+
327
+ --sidebar-width: 14.8125rem;
328
+ --chat-min-width: 28rem;
329
+ --titlebar-control-size: 1.25rem;
330
+ --titlebar-control-height: 1.375rem;
331
+ --sidebar-content-inline-padding: 1rem;
332
+
333
+ --sidebar: var(--dt-sidebar-bg);
334
+ --sidebar-foreground: var(--dt-foreground);
335
+ --sidebar-primary: var(--dt-primary);
336
+ --sidebar-primary-foreground: var(--dt-primary-foreground);
337
+ --sidebar-accent: var(--ui-control-active-background);
338
+ --sidebar-accent-foreground: var(--dt-accent-foreground);
339
+ --sidebar-border: var(--dt-sidebar-border);
340
+ --sidebar-ring: var(--dt-ring);
341
+ --sidebar-edge-border: color-mix(in srgb, var(--ui-base) 7.5%, transparent);
342
+ --chrome-action-hover: var(--ui-control-hover-background);
343
+
344
+ --midground: var(--dt-midground);
345
+ --background: var(--dt-background);
346
+ --foreground: var(--dt-foreground);
347
+
348
+ --warm-glow: color-mix(in srgb, var(--ui-warm) 32%, color-mix(in srgb, var(--ui-accent) 6%, transparent));
349
+ /* `--noise-opacity-mul` is set per-mode by `applyTheme()`. */
350
+ --noise-opacity-mul: 1;
351
+ --backdrop-invert-mul: 1;
352
+ }
353
+
354
+ :root.dark {
355
+ /* Per-mode mix knobs — overridden inline by `applyTheme()` per skin. */
356
+ --theme-mix-chrome: 74%;
357
+ --theme-mix-card: 38%;
358
+ --theme-mix-elevated: 46%;
359
+ --theme-mix-bubble: 46%;
360
+ --theme-neutral-chrome: #0d0d0e;
361
+ --theme-neutral-sidebar: #0a0a0b;
362
+ --theme-neutral-card: #161618;
363
+
364
+ /* Dark-only accent palette overrides. */
365
+ --ui-red: #e75e78;
366
+ --ui-green: #55a583;
367
+ --ui-cyan: #6f9ba6;
368
+
369
+ --sidebar-edge-border: color-mix(in srgb, var(--ui-base) 12%, transparent);
370
+ --composer-ring-strength: 1.3;
371
+ --backdrop-invert-mul: 0;
372
+
373
+ --ui-inline-code-background: color-mix(in srgb, #ffffff 7%, transparent);
374
+ --ui-inline-code-border: color-mix(in srgb, #ffffff 10%, transparent);
375
+ --ui-inline-code-foreground: color-mix(in srgb, #ffffff 88%, transparent);
376
+ --ui-selection-background: color-mix(in srgb, #ffd24a 38%, transparent);
377
+ }
378
+
379
+ * {
380
+ box-sizing: border-box;
381
+ border-color: var(--dt-border);
382
+ }
383
+
384
+ html,
385
+ body,
386
+ #root {
387
+ height: 100%;
388
+ }
389
+
390
+ html {
391
+ font-size: var(--dt-base-size, 0.875rem);
392
+ }
393
+
394
+ body {
395
+ margin: 0;
396
+ background: var(--ui-chat-surface-background);
397
+ color: var(--dt-foreground);
398
+ font-family: var(--dt-font-sans);
399
+ font-size: 0.8125rem;
400
+ line-height: var(--dt-line-height, 1.55);
401
+ letter-spacing: var(--dt-letter-spacing, 0);
402
+ overflow: hidden;
403
+ -webkit-user-select: none;
404
+ user-select: none;
405
+ -webkit-font-smoothing: antialiased;
406
+ }
407
+
408
+ button,
409
+ textarea {
410
+ font: inherit;
411
+ }
412
+
413
+ :where(
414
+ a,
415
+ .underline,
416
+ [class~='hover:underline'],
417
+ [class~='focus:underline'],
418
+ [class~='focus-visible:underline'],
419
+ [class~='group-hover:underline'],
420
+ [class~='peer-hover:underline']
421
+ ) {
422
+ text-decoration-color: color-mix(in srgb, currentColor 20%, transparent);
423
+ text-underline-offset: 0.25rem;
424
+ }
425
+
426
+ *::selection {
427
+ background: var(--ui-selection-background);
428
+ color: inherit;
429
+ }
430
+ }
431
+
432
+ .dither {
433
+ background: repeating-conic-gradient(currentColor 0% 25%, transparent 0% 50%) 0 0 / 0.125rem 0.125rem;
434
+ }
435
+
436
+ :root:not([style*='--theme-asset-bg:']) .theme-default-filler {
437
+ display: block;
438
+ }
439
+
440
+ :root[style*='--theme-asset-bg:'] .theme-default-filler {
441
+ display: none;
442
+ }
443
+
444
+ /* Primitive-level pointer cursor for every interactive control (buttons,
445
+ selects, menu items, switches, tabs, summaries). Keeps individual
446
+ components from having to hardcode `cursor-pointer`; explicit cursor
447
+ utilities (cursor-grab, cursor-default, disabled:cursor-*) still win since
448
+ they live in the utilities layer. */
449
+ @layer base {
450
+ button:not(:disabled):not([aria-disabled='true']),
451
+ summary,
452
+ [role='button']:not([aria-disabled='true']),
453
+ [role='menuitem']:not([aria-disabled='true']),
454
+ [role='menuitemradio']:not([aria-disabled='true']),
455
+ [role='menuitemcheckbox']:not([aria-disabled='true']),
456
+ [role='option']:not([aria-disabled='true']),
457
+ [role='switch']:not([aria-disabled='true']),
458
+ [role='tab']:not([aria-disabled='true']) {
459
+ cursor: pointer;
460
+ }
461
+ }
462
+
463
+ @layer utilities {
464
+ [class*='rounded-full'],
465
+ [class*=':rounded-full'] {
466
+ border-radius: calc(var(--radius-scalar) * 9999rem);
467
+ }
468
+ }
469
+
470
+ @keyframes arc-border {
471
+ 0% {
472
+ background-position: 15% 15%;
473
+ }
474
+ 100% {
475
+ background-position: 75% 75%;
476
+ }
477
+ }
478
+
479
+ .arc-border {
480
+ --arc-c0: color-mix(in srgb, var(--dt-foreground) 0%, transparent);
481
+ --arc-c1: var(--dt-midground);
482
+ --arc-c2: var(--dt-background);
483
+ --arc-angle: 160deg;
484
+ --arc-width: 0.078125rem;
485
+ --arc-inset: -0.125rem;
486
+ --arc-duration: 2.23s;
487
+
488
+ pointer-events: none;
489
+ position: absolute;
490
+ overflow: hidden;
491
+ border-radius: inherit;
492
+ inset: var(--arc-inset);
493
+ padding: var(--arc-width);
494
+ mask:
495
+ linear-gradient(#000 0 0) content-box,
496
+ linear-gradient(#000 0 0);
497
+ -webkit-mask-composite: xor;
498
+ mask-composite: exclude;
499
+ }
500
+
501
+ :root.dark .arc-border {
502
+ --arc-c1: var(--dt-foreground);
503
+ }
504
+
505
+ /* Quest-style "needs you" pulse for a clarify-blocked session's dot —
506
+ a soft amber glow that breathes so the row draws the eye without a toast. */
507
+ @keyframes quest-glow {
508
+ 0%,
509
+ 100% {
510
+ transform: scale(1);
511
+ box-shadow:
512
+ 0 0 0.1875rem color-mix(in srgb, var(--color-amber-500, #f59e0b) 70%, transparent),
513
+ 0 0 0.5rem color-mix(in srgb, var(--color-amber-500, #f59e0b) 45%, transparent);
514
+ }
515
+ 50% {
516
+ transform: scale(1.18);
517
+ box-shadow:
518
+ 0 0 0.3125rem color-mix(in srgb, var(--color-amber-500, #f59e0b) 90%, transparent),
519
+ 0 0 0.875rem color-mix(in srgb, var(--color-amber-500, #f59e0b) 65%, transparent);
520
+ }
521
+ }
522
+
523
+ .quest-glow {
524
+ animation: quest-glow 1.8s ease-in-out infinite;
525
+ }
526
+
527
+ @media (prefers-reduced-motion: reduce) {
528
+ .quest-glow {
529
+ animation: none;
530
+ box-shadow:
531
+ 0 0 0.25rem color-mix(in srgb, var(--color-amber-500, #f59e0b) 80%, transparent),
532
+ 0 0 0.625rem color-mix(in srgb, var(--color-amber-500, #f59e0b) 55%, transparent);
533
+ }
534
+ }
535
+
536
+ /* Command-palette deep-link: briefly flash the targeted settings row. */
537
+ @keyframes setting-field-flash {
538
+ 0% {
539
+ background-color: color-mix(in srgb, var(--dt-primary, #f59e0b) 22%, transparent);
540
+ }
541
+ 100% {
542
+ background-color: transparent;
543
+ }
544
+ }
545
+
546
+ .setting-field-highlight {
547
+ animation: setting-field-flash 1.6s ease-out;
548
+ }
549
+
550
+ @media (prefers-reduced-motion: reduce) {
551
+ .setting-field-highlight {
552
+ animation: none;
553
+ }
554
+ }
555
+
556
+ .arc-border::before {
557
+ content: '';
558
+ position: absolute;
559
+ inset: 0;
560
+ border-radius: inherit;
561
+ background: linear-gradient(
562
+ var(--arc-angle),
563
+ transparent 0%,
564
+ var(--arc-c0) 15%,
565
+ var(--arc-c1) 20%,
566
+ var(--arc-c2) 25%,
567
+ transparent 35%,
568
+ transparent 40%,
569
+ var(--arc-c0) 55%,
570
+ var(--arc-c1) 60%,
571
+ var(--arc-c2) 65%,
572
+ transparent 75%,
573
+ transparent 80%,
574
+ var(--arc-c0) 95%,
575
+ var(--arc-c1) 100%
576
+ );
577
+ background-size: 300% 300%;
578
+ animation: arc-border var(--arc-duration) linear infinite;
579
+ }
580
+
581
+ /* Flip the arc's travel direction (e.g. the NasTech Portal hero row). */
582
+ .arc-border.arc-reverse::before {
583
+ animation-direction: reverse;
584
+ }
585
+
586
+ /* NasTech Portal hero: slower, blue → orange arc. */
587
+ .arc-border.arc-nastech,
588
+ :root.dark .arc-border.arc-nastech {
589
+ --arc-c1: #4f8cff;
590
+ --arc-c2: #ff8c42;
591
+ --arc-duration: 3.27s;
592
+ }
593
+
594
+ @media (prefers-reduced-motion: reduce) {
595
+ .arc-border::before {
596
+ animation: none;
597
+ }
598
+ }
599
+
600
+ /* No focus rings, anywhere. Kills the native outline plus Tailwind's
601
+ `focus-visible:ring-*` (a box-shadow driven by --tw-ring-*). Unlayered so it
602
+ beats the utilities layer without !important on the outline. The composer /
603
+ .desktop-input-chrome focus glow is untouched — those set `box-shadow`
604
+ directly rather than through the ring vars. */
605
+ *:focus,
606
+ *:focus-visible {
607
+ outline: none;
608
+ }
609
+
610
+ *:focus-visible {
611
+ --tw-ring-shadow: 0 0 #0000 !important;
612
+ --tw-ring-offset-shadow: 0 0 #0000 !important;
613
+ }
614
+
615
+ button {
616
+ -webkit-app-region: no-drag;
617
+ }
618
+
619
+ /* Button variant styling lives entirely in the cva in components/ui/button.tsx
620
+ (the single source of truth). Don't re-add [data-slot='button'] rules here —
621
+ attribute selectors out-specify the Tailwind utilities and silently override
622
+ the variants. */
623
+
624
+ [data-slot='dropdown-menu-content'],
625
+ [data-slot='select-content'],
626
+ [data-slot='dialog-content'] {
627
+ border-color: var(--ui-stroke-secondary);
628
+ background: color-mix(in srgb, var(--ui-bg-elevated) 96%, transparent);
629
+ box-shadow: var(--shadow-md);
630
+ backdrop-filter: blur(0.75rem) saturate(1.08);
631
+ -webkit-backdrop-filter: blur(0.75rem) saturate(1.08);
632
+ }
633
+
634
+ [data-slot='dropdown-menu-item']:focus,
635
+ [data-slot='dropdown-menu-checkbox-item']:focus,
636
+ [data-slot='dropdown-menu-radio-item']:focus {
637
+ background: var(--ui-bg-tertiary);
638
+ color: var(--ui-text-primary);
639
+ }
640
+
641
+ input,
642
+ textarea,
643
+ [contenteditable]:not([contenteditable='false']),
644
+ [data-slot='aui_user-message-root'],
645
+ [data-slot='aui_assistant-message-content'],
646
+ [data-selectable-text='true'],
647
+ [data-selectable-text='true'] * {
648
+ -webkit-user-select: text;
649
+ user-select: text;
650
+ }
651
+
652
+ button,
653
+ [role='button'] {
654
+ -webkit-user-select: none;
655
+ user-select: none;
656
+ }
657
+
658
+ img,
659
+ picture,
660
+ video,
661
+ canvas,
662
+ svg {
663
+ -webkit-user-select: none;
664
+ user-select: none;
665
+ }
666
+
667
+ img,
668
+ video,
669
+ canvas {
670
+ -webkit-user-drag: none;
671
+ }
672
+
673
+ /* Shared input chrome — mirrors composer hover/focus FX. Unlayered to beat Tailwind utilities. */
674
+ .desktop-input-chrome {
675
+ --ring-pct: 18%;
676
+ --ring-fall: var(--dt-input);
677
+ background: color-mix(in srgb, var(--dt-card) 68%, transparent);
678
+ border-color: color-mix(
679
+ in srgb,
680
+ var(--dt-composer-ring) calc(var(--ring-pct) * var(--composer-ring-strength)),
681
+ var(--ring-fall)
682
+ );
683
+ box-shadow: none;
684
+ transition:
685
+ background-color 200ms ease-out,
686
+ border-color 200ms ease-out;
687
+ }
688
+
689
+ .desktop-input-chrome:hover {
690
+ --ring-pct: 30%;
691
+ background: color-mix(in srgb, var(--dt-card) 86%, transparent);
692
+ }
693
+
694
+ .desktop-input-chrome:focus {
695
+ --ring-pct: 45%;
696
+ --ring-fall: transparent;
697
+ background: var(--dt-card);
698
+ box-shadow: none;
699
+ outline: none;
700
+ }
701
+
702
+ .desktop-input-chrome[aria-invalid='true'] {
703
+ border-color: var(--dt-destructive);
704
+ }
705
+
706
+ @layer components {
707
+ .scrollbar-dt,
708
+ .scrollbar-dt * {
709
+ scrollbar-width: thin;
710
+ scrollbar-color: color-mix(in srgb, var(--dt-midground) 18%, transparent) transparent;
711
+ }
712
+
713
+ .scrollbar-dt::-webkit-scrollbar,
714
+ .scrollbar-dt *::-webkit-scrollbar {
715
+ width: 0.5rem;
716
+ height: 0.5rem;
717
+ }
718
+
719
+ .scrollbar-dt::-webkit-scrollbar-track,
720
+ .scrollbar-dt::-webkit-scrollbar-corner,
721
+ .scrollbar-dt *::-webkit-scrollbar-track,
722
+ .scrollbar-dt *::-webkit-scrollbar-corner {
723
+ background: transparent;
724
+ }
725
+
726
+ .scrollbar-dt::-webkit-scrollbar-thumb,
727
+ .scrollbar-dt *::-webkit-scrollbar-thumb {
728
+ background: color-mix(in srgb, var(--dt-midground) 18%, transparent);
729
+ border-radius: 9999rem;
730
+ border: 0.125rem solid transparent;
731
+ background-clip: padding-box;
732
+ }
733
+
734
+ .scrollbar-dt::-webkit-scrollbar-thumb:hover,
735
+ .scrollbar-dt *::-webkit-scrollbar-thumb:hover {
736
+ background: color-mix(in srgb, var(--dt-midground) 40%, transparent);
737
+ background-clip: padding-box;
738
+ }
739
+
740
+ .scrollbar-dt::-webkit-scrollbar-button,
741
+ .scrollbar-dt *::-webkit-scrollbar-button {
742
+ display: none;
743
+ }
744
+
745
+ /* Variant for portaled overlays (Radix DropdownMenu, Popover, etc.) that
746
+ render under document.body, outside the `.scrollbar-dt` scope on
747
+ #root. Same visual treatment, applied directly to the overlay
748
+ container so its (and only its) internal scrollbar is themed. */
749
+ .dt-portal-scrollbar {
750
+ scrollbar-width: thin;
751
+ scrollbar-color: color-mix(in srgb, var(--dt-midground) 28%, transparent) transparent;
752
+ }
753
+
754
+ .dt-portal-scrollbar::-webkit-scrollbar {
755
+ width: 0.375rem;
756
+ height: 0.375rem;
757
+ }
758
+
759
+ .dt-portal-scrollbar::-webkit-scrollbar-track,
760
+ .dt-portal-scrollbar::-webkit-scrollbar-corner {
761
+ background: transparent;
762
+ }
763
+
764
+ .dt-portal-scrollbar::-webkit-scrollbar-thumb {
765
+ background: color-mix(in srgb, var(--dt-midground) 28%, transparent);
766
+ border-radius: 9999rem;
767
+ border: 0.0625rem solid transparent;
768
+ background-clip: padding-box;
769
+ }
770
+
771
+ .dt-portal-scrollbar::-webkit-scrollbar-thumb:hover {
772
+ background: color-mix(in srgb, var(--dt-midground) 50%, transparent);
773
+ background-clip: padding-box;
774
+ }
775
+
776
+ .dt-portal-scrollbar::-webkit-scrollbar-button {
777
+ display: none;
778
+ }
779
+ }
780
+
781
+ /* Bottom clearance lives on [data-slot='aui_composer-clearance'] —
782
+ virtualized items unmount, so :nth-last-child can't fire reliably. */
783
+
784
+ [data-slot='aui_assistant-message-content'] {
785
+ padding-left: var(--message-text-indent);
786
+ font-size: var(--conversation-text-font-size);
787
+ line-height: 1.5;
788
+ }
789
+
790
+ [data-slot='aui_assistant-message-root'] {
791
+ width: 100%;
792
+ }
793
+
794
+ [data-slot='aui_assistant-message-content'] .aui-md,
795
+ [data-slot='aui_assistant-message-content'] .aui-md :where(p, li, blockquote, table, pre) {
796
+ font-size: inherit;
797
+ }
798
+
799
+ /* Tailwind Typography sets `.prose :where(p) { margin: 1.25em }` (~16px). That
800
+ selector ties our `my-*` utility on specificity and wins on source order, so
801
+ paragraph spacing must be reclaimed here at higher specificity. One tight
802
+ top-margin (bottom zeroed to avoid doubling), first child reset to flush. */
803
+ [data-slot='aui_assistant-message-content'] .aui-md :where(p) {
804
+ margin-block: var(--paragraph-gap) 0;
805
+ }
806
+
807
+ /* First rendered element of a prose block is flush — the block-level gap above
808
+ (tool / paragraph) already provides the separation. Reach one level deep too:
809
+ Streamdown wraps blocks in a `div.space-y-*`, so the real first line is the
810
+ first child's first child. */
811
+ [data-slot='aui_assistant-message-content'] .aui-md > :first-child,
812
+ [data-slot='aui_assistant-message-content'] .aui-md > :first-child > :first-child {
813
+ margin-top: 0;
814
+ }
815
+
816
+ /* Prose, tools, todos, and thinking all share one left edge (the message
817
+ content's --message-text-indent). No extra prose indent — a single gutter
818
+ reads cleaner than a ragged tool-vs-reply column. */
819
+
820
+ [data-slot='aui_user-message-root'] {
821
+ top: var(--sticky-human-top);
822
+ }
823
+
824
+ [data-slot='aui_user-message-root'],
825
+ [data-slot='aui_edit-composer-root'] {
826
+ font-size: var(--conversation-text-font-size);
827
+ }
828
+
829
+ /* Sticky human bubbles clamp to ~2 lines with a soft bottom fade so a long
830
+ prompt doesn't dominate the viewport. The clamp lifts on focus only (clicking
831
+ opens the edit composer, which shows the full text) — not on hover, so the
832
+ bubble doesn't jump as the pointer passes over it. --human-msg-full is the
833
+ measured content height (set in UserMessage) so it animates to the real
834
+ height instead of overshooting the cap. */
835
+ .sticky-human-clamp {
836
+ cursor: pointer;
837
+ max-height: calc(2 * var(--dt-line-height) * var(--conversation-text-font-size) + 0.15rem);
838
+ overflow: hidden;
839
+ transition: max-height 0.08s cubic-bezier(0.4, 0, 0.2, 1);
840
+ }
841
+
842
+ .sticky-human-clamp[data-clamped='true'] {
843
+ -webkit-mask-image: linear-gradient(to bottom, #000 55%, transparent);
844
+ mask-image: linear-gradient(to bottom, #000 55%, transparent);
845
+ }
846
+
847
+ .composer-human-message:focus-within .sticky-human-clamp {
848
+ max-height: min(var(--human-msg-full, 24rem), 24rem);
849
+ overflow-y: auto;
850
+ -webkit-mask-image: none;
851
+ mask-image: none;
852
+ }
853
+
854
+ /* The thread renders items in natural document flow (padding spacers, not
855
+ transforms) and @tanstack/react-virtual already adjusts scrollTop itself
856
+ when an off-screen turn is measured and its real height differs from the
857
+ 220px estimate. The browser's native scroll anchoring (overflow-anchor:
858
+ auto) would adjust scrollTop for that SAME size delta, so the two
859
+ double-correct and the view lurches — most visibly on Windows mouse wheels,
860
+ whose coarse notches mount/measure several under-estimated turns per tick.
861
+ Opt out of native anchoring so only the virtualizer compensates. */
862
+ [data-slot='aui_thread-viewport'] {
863
+ overflow-anchor: none;
864
+ }
865
+
866
+ [data-slot='aui_thread-content'] {
867
+ max-width: var(--composer-width);
868
+ padding-inline: 1.5rem;
869
+ }
870
+
871
+ [data-slot='aui_intro'] {
872
+ align-items: center;
873
+ justify-content: center;
874
+ padding-bottom: var(--composer-measured-height);
875
+ text-align: center;
876
+ }
877
+
878
+ [data-slot='aui_intro'] > div {
879
+ max-width: min(var(--composer-width), 82vw);
880
+ }
881
+
882
+ [data-slot='aui_intro'] p:last-child {
883
+ max-width: 34rem;
884
+ margin-inline: auto;
885
+ color: var(--ui-text-tertiary);
886
+ font-size: 0.875rem;
887
+ line-height: 1.45;
888
+ }
889
+
890
+ .fit-text {
891
+ display: flex;
892
+ font-size: var(--fit-text-min, 1rem);
893
+ container-type: inline-size;
894
+ --captured-length: initial;
895
+ --support-sentinel: var(--captured-length, 9999px);
896
+ }
897
+
898
+ .fit-text > [aria-hidden='true'] {
899
+ visibility: hidden;
900
+ }
901
+
902
+ .fit-text > :not([aria-hidden='true']) {
903
+ flex-grow: 1;
904
+ container-type: inline-size;
905
+ --captured-length: 100cqi;
906
+ --available-space: var(--captured-length);
907
+ }
908
+
909
+ .fit-text > :not([aria-hidden='true']) > * {
910
+ display: block;
911
+ inline-size: var(--available-space);
912
+ line-height: var(--fit-text-line-height, 1);
913
+ --support-sentinel: inherit;
914
+ --captured-length: 100cqi;
915
+ --ratio: tan(atan2(var(--available-space), var(--available-space) - var(--captured-length)));
916
+ --font-size: clamp(
917
+ var(--fit-text-min, 1em),
918
+ 1em * var(--ratio),
919
+ var(--fit-text-max, infinity * 1px) - var(--support-sentinel)
920
+ );
921
+ font-size: var(--font-size);
922
+ }
923
+
924
+ @container (inline-size > 0) {
925
+ .fit-text > :not([aria-hidden='true']) > * {
926
+ white-space: nowrap;
927
+ }
928
+ }
929
+
930
+ @property --captured-length {
931
+ syntax: '<length>';
932
+ initial-value: 0px;
933
+ inherits: true;
934
+ }
935
+
936
+ @property --captured-length2 {
937
+ syntax: '<length>';
938
+ initial-value: 0px;
939
+ inherits: true;
940
+ }
941
+
942
+ [data-slot='composer-root'] {
943
+ width: min(var(--composer-width), calc(100% - 2rem));
944
+ padding-bottom: var(--composer-shell-pad-block-end);
945
+ }
946
+
947
+ [data-slot='composer-root'] > .pointer-events-none {
948
+ background: linear-gradient(
949
+ to bottom,
950
+ transparent,
951
+ color-mix(in srgb, var(--ui-chat-surface-background) 88%, transparent)
952
+ ) !important;
953
+ }
954
+
955
+ [data-slot='composer-surface'] {
956
+ border-color: var(--ui-stroke-secondary) !important;
957
+ }
958
+
959
+ [data-slot='composer-fade'] {
960
+ min-height: 2.375rem;
961
+ }
962
+
963
+ [data-slot='composer-rich-input'] {
964
+ color: var(--ui-text-primary);
965
+ font-size: 0.8125rem;
966
+ }
967
+
968
+ [data-slot='composer-rich-input']:empty::before {
969
+ color: var(--ui-text-tertiary) !important;
970
+ }
971
+
972
+ [data-slot='composer-root']:focus-within [data-slot='composer-surface'] > [aria-hidden='true'] {
973
+ background: var(--ui-chat-bubble-background) !important;
974
+ }
975
+
976
+ /* Tool/thinking blocks now live at message-text alignment (no leading
977
+ chevron column to escape into), so their headers and bodies share a
978
+ common left edge with the model's text. */
979
+ [data-slot='aui_assistant-message-content'] > [data-slot='tool-block'],
980
+ [data-slot='aui_assistant-message-content'] > [data-slot='aui_thinking-disclosure'] {
981
+ width: 100%;
982
+ max-width: 100%;
983
+ }
984
+
985
+ [data-slot='aui_assistant-message-content'] .aui-md [data-streamdown='code-block'] code {
986
+ max-width: none;
987
+ font-family: inherit;
988
+ font-size: inherit;
989
+ padding: 0;
990
+ border-radius: 0;
991
+ background: transparent;
992
+ color: inherit;
993
+ overflow-x: visible;
994
+ overflow-wrap: inherit;
995
+ vertical-align: baseline;
996
+ word-break: inherit;
997
+ white-space: inherit;
998
+ }
999
+
1000
+ /* Streamdown's adapter wraps code fences in a `data-streamdown="code-block"`
1001
+ container with its own card chrome. We render our own <CodeCard>, so this
1002
+ strips the upstream chrome down to a layout-only passthrough. */
1003
+ [data-slot='aui_assistant-message-content'] .aui-md [data-streamdown='code-block'] {
1004
+ contain: none;
1005
+ overflow: visible;
1006
+ margin-block: var(--paragraph-gap) 0 !important;
1007
+ padding: 0 !important;
1008
+ gap: 0 !important;
1009
+ border: 0 !important;
1010
+ border-radius: 0 !important;
1011
+ background: transparent !important;
1012
+ color: inherit;
1013
+ }
1014
+
1015
+ [data-slot='aui_assistant-message-content'] .aui-md [data-streamdown='code-block']:has(.aui-prose-fence) {
1016
+ margin-block: 0 !important;
1017
+ }
1018
+
1019
+ [data-slot='aui_assistant-message-content'] .aui-md [data-slot='code-card'] {
1020
+ /* Streamdown nests blocks, so the container's child-combinator rhythm can't
1021
+ reach the card. Carry the paragraph gap on the card itself (top-owned);
1022
+ collapses cleanly with the wrapper's margin when one is present, and the
1023
+ first-child reset still flushes a leading code block. */
1024
+ margin-block: var(--paragraph-gap) 0;
1025
+ position: relative;
1026
+ transition:
1027
+ border-color 180ms ease-out,
1028
+ box-shadow 180ms ease-out,
1029
+ background-color 180ms ease-out;
1030
+ }
1031
+
1032
+ [data-slot='aui_assistant-message-content'] .aui-md [data-slot='code-card'][data-streaming='true'] {
1033
+ animation:
1034
+ code-card-stream-enter 180ms cubic-bezier(0.16, 1, 0.3, 1) both,
1035
+ code-card-stream-glow 1.8s ease-in-out 180ms infinite alternate;
1036
+ border-color: color-mix(in srgb, var(--dt-ring) 24%, var(--ui-stroke-tertiary));
1037
+ box-shadow:
1038
+ 0 0 0 0.0625rem color-mix(in srgb, var(--dt-ring) 10%, transparent),
1039
+ 0 0.625rem 1.75rem color-mix(in srgb, var(--dt-ring) 8%, transparent);
1040
+ }
1041
+
1042
+ [data-slot='aui_assistant-message-content']
1043
+ .aui-md
1044
+ [data-slot='code-card'][data-streaming='true']
1045
+ [data-slot='code-card-body'] {
1046
+ -webkit-mask-image: linear-gradient(to bottom, black 0%, black calc(100% - 1.5rem), rgb(0 0 0 / 64%) 100%);
1047
+ mask-image: linear-gradient(to bottom, black 0%, black calc(100% - 1.5rem), rgb(0 0 0 / 64%) 100%);
1048
+ }
1049
+
1050
+ [data-slot='aui_assistant-message-content'] .aui-md :not(pre) > code {
1051
+ border: 0.0625rem solid var(--ui-inline-code-border);
1052
+ background: var(--ui-inline-code-background);
1053
+ color: var(--ui-inline-code-foreground);
1054
+ }
1055
+
1056
+ [data-slot='aui_assistant-message-content'] .aui-md :where(.aui-shiki, .aui-shiki > pre) {
1057
+ margin: 0 !important;
1058
+ }
1059
+
1060
+ [data-slot='aui_assistant-message-content'] .aui-md .aui-md-table {
1061
+ border-spacing: 0;
1062
+ }
1063
+
1064
+ [data-slot='aui_assistant-message-content'] .aui-md .aui-md-table > table,
1065
+ [data-slot='aui_assistant-message-content'] .aui-md .aui-md-table thead,
1066
+ [data-slot='aui_assistant-message-content'] .aui-md .aui-md-table tbody,
1067
+ [data-slot='aui_assistant-message-content'] .aui-md .aui-md-table tr,
1068
+ [data-slot='aui_assistant-message-content'] .aui-md .aui-md-table th,
1069
+ [data-slot='aui_assistant-message-content'] .aui-md .aui-md-table td {
1070
+ margin: 0 !important;
1071
+ margin-block-start: 0 !important;
1072
+ margin-block-end: 0 !important;
1073
+ }
1074
+
1075
+ /* Tool / thinking blocks are scaffolding around the model's reply, so we
1076
+ keep them transparent and fade them slightly. The reading column (prose)
1077
+ stays at full strength; scaffolding lifts back to full opacity on
1078
+ hover/focus so it stays legible when the user actually wants to read it. */
1079
+ [data-slot='tool-block'],
1080
+ [data-slot='aui_thinking-disclosure'] {
1081
+ background: transparent !important;
1082
+ }
1083
+
1084
+ [data-slot='aui_assistant-message-content'] > :is([data-slot='tool-block'], [data-slot='aui_thinking-disclosure']) {
1085
+ opacity: 0.67;
1086
+ transition: opacity 120ms ease-out;
1087
+ }
1088
+
1089
+ [data-slot='aui_assistant-message-content']
1090
+ > :is([data-slot='tool-block'], [data-slot='aui_thinking-disclosure']):is(:hover, :focus-within) {
1091
+ opacity: 1;
1092
+ }
1093
+
1094
+ /* Conversation block rhythm. assistant-ui renders each range as a direct child
1095
+ of the message content with no per-part wrapper, so adjacency rules cover
1096
+ every pairing — first block needs no reset, nested tool rows are untouched.
1097
+ Two tiers: scaffolding (tool / thinking) gets a roomy block gap so it reads
1098
+ as separate from the reply; consecutive prose collapses to a tight paragraph
1099
+ rhythm so split-out text parts don't look like a big gap. */
1100
+ /* Scaffolding adjacent to anything → roomy block gap. */
1101
+ [data-slot='aui_assistant-message-content']
1102
+ > :is([data-slot='tool-block'], [data-slot='aui_thinking-disclosure'])
1103
+ + :is([data-slot='tool-block'], [data-slot='aui_thinking-disclosure'], .aui-md),
1104
+ [data-slot='aui_assistant-message-content']
1105
+ > .aui-md
1106
+ + :is([data-slot='tool-block'], [data-slot='aui_thinking-disclosure']) {
1107
+ margin-top: var(--turn-block-gap);
1108
+ }
1109
+
1110
+ /* Prose ↔ prose → tight paragraph rhythm, matching in-block paragraph spacing. */
1111
+ [data-slot='aui_assistant-message-content'] > .aui-md + .aui-md {
1112
+ margin-top: var(--paragraph-gap);
1113
+ }
1114
+
1115
+ /* Message action bars — flat icon hits with default dim; only the hovered/focused control is full-strength. */
1116
+ [data-slot='aui_msg-actions'] button {
1117
+ border: 0;
1118
+ border-radius: 0;
1119
+ background: transparent;
1120
+ box-shadow: none;
1121
+ padding: 0;
1122
+ gap: 0;
1123
+ height: auto;
1124
+ width: auto;
1125
+ min-height: 0;
1126
+ min-width: 0;
1127
+ flex-shrink: 0;
1128
+ cursor: pointer;
1129
+ color: var(--color-muted-foreground);
1130
+ opacity: 0.5;
1131
+ }
1132
+
1133
+ [data-slot='aui_msg-actions'] button:disabled {
1134
+ cursor: default;
1135
+ }
1136
+
1137
+ [data-slot='aui_msg-actions'] button:hover {
1138
+ background: transparent;
1139
+ color: var(--color-foreground);
1140
+ opacity: 1;
1141
+ }
1142
+
1143
+ [data-slot='aui_msg-actions'] button:active {
1144
+ background: transparent;
1145
+ }
1146
+
1147
+ [data-slot='aui_msg-actions'] button:focus-visible {
1148
+ opacity: 1;
1149
+ }
1150
+
1151
+ [data-slot='aui_msg-actions'] button svg {
1152
+ width: 0.875rem;
1153
+ height: 0.875rem;
1154
+ }
1155
+
1156
+ /* Live thinking preview window. Pairs with the ResizeObserver in
1157
+ ThinkingDisclosure that pins scrollTop to the bottom — older lines fade
1158
+ into the top mask while the latest tokens settle in below. */
1159
+ .thinking-preview {
1160
+ -webkit-mask-image: linear-gradient(to bottom, transparent 0%, black 28%, black 100%);
1161
+ mask-image: linear-gradient(to bottom, transparent 0%, black 28%, black 100%);
1162
+ }
1163
+
1164
+ @keyframes code-card-stream-enter {
1165
+ from {
1166
+ opacity: 0.74;
1167
+ transform: translateY(0.375rem);
1168
+ }
1169
+
1170
+ to {
1171
+ opacity: 1;
1172
+ transform: translateY(0);
1173
+ }
1174
+ }
1175
+
1176
+ @keyframes code-card-stream-glow {
1177
+ from {
1178
+ border-color: color-mix(in srgb, var(--dt-ring) 18%, var(--ui-stroke-tertiary));
1179
+ box-shadow:
1180
+ 0 0 0 0.0625rem color-mix(in srgb, var(--dt-ring) 6%, transparent),
1181
+ 0 0.5rem 1.5rem color-mix(in srgb, var(--dt-ring) 5%, transparent);
1182
+ }
1183
+
1184
+ to {
1185
+ border-color: color-mix(in srgb, var(--dt-ring) 32%, var(--ui-stroke-tertiary));
1186
+ box-shadow:
1187
+ 0 0 0 0.0625rem color-mix(in srgb, var(--dt-ring) 12%, transparent),
1188
+ 0 0.75rem 2rem color-mix(in srgb, var(--dt-ring) 10%, transparent);
1189
+ }
1190
+ }
1191
+
1192
+ @media (prefers-reduced-motion: reduce) {
1193
+ [data-slot='aui_assistant-message-content'] .aui-md [data-slot='code-card'][data-streaming='true'] {
1194
+ animation: none;
1195
+ }
1196
+ }
1197
+
1198
+ /* ── Keybind panel / edit overlay: small key chips ──────────────────────────
1199
+ A quiet `kbd`-style chip shared by the shortcuts panel and the on-screen
1200
+ editor so both read as the same control. No animation, no glow. */
1201
+ .kbd-cap {
1202
+ display: inline-grid;
1203
+ place-items: center;
1204
+ min-width: 1.5rem;
1205
+ height: 1.4rem;
1206
+ padding: 0 0.4rem;
1207
+ border-radius: 0.375rem;
1208
+ font-family: var(--dt-font-mono, ui-monospace, monospace);
1209
+ font-size: 0.72rem;
1210
+ font-weight: 500;
1211
+ line-height: 1;
1212
+ color: color-mix(in srgb, var(--dt-foreground) 82%, transparent);
1213
+ background: color-mix(in srgb, var(--ui-bg-elevated) 70%, transparent);
1214
+ border: 1px solid var(--ui-stroke-secondary);
1215
+ box-shadow: inset 0 -1px 0 color-mix(in srgb, var(--ui-stroke-tertiary) 50%, transparent);
1216
+ }
1217
+
1218
+ /* Unbound slot: a hollow dashed chip inviting a binding. */
1219
+ .kbd-cap--ghost {
1220
+ color: color-mix(in srgb, var(--dt-foreground) 42%, transparent);
1221
+ background: none;
1222
+ border-style: dashed;
1223
+ border-color: var(--ui-stroke-tertiary);
1224
+ box-shadow: none;
1225
+ font-style: italic;
1226
+ }
1227
+
1228
+ /* Waiting for a keypress: solid accent, no motion. */
1229
+ .kbd-capturing {
1230
+ color: var(--theme-primary);
1231
+ border-color: color-mix(in srgb, var(--theme-primary) 55%, var(--ui-stroke-secondary)) !important;
1232
+ border-style: solid;
1233
+ background: color-mix(in srgb, var(--theme-primary) 9%, var(--ui-bg-elevated));
1234
+ box-shadow: none;
1235
+ }