@webship.co/workspace 0.0.0-stage → 1.0.0-alpha1

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 (311) hide show
  1. package/PLUGINS.md +249 -0
  2. package/README.md +379 -2
  3. package/WORKSPACES.md +69 -0
  4. package/actions/ai-items.js +293 -0
  5. package/actions/audio.js +48 -0
  6. package/actions/build-order.js +79 -0
  7. package/actions/checks.js +95 -0
  8. package/actions/claude-session.js +104 -0
  9. package/actions/commands-center.js +258 -0
  10. package/actions/composer.js +267 -0
  11. package/actions/ddev-addons.js +90 -0
  12. package/actions/ddev-mail.js +80 -0
  13. package/actions/ddev.js +237 -0
  14. package/actions/folders.js +165 -0
  15. package/actions/graphs.js +107 -0
  16. package/actions/images-svg.js +33 -0
  17. package/actions/images.js +145 -0
  18. package/actions/navigation.js +190 -0
  19. package/actions/node.js +222 -0
  20. package/actions/notes.js +55 -0
  21. package/actions/obsidian.js +59 -0
  22. package/actions/plugins.js +36 -0
  23. package/actions/project-make.js +28 -0
  24. package/actions/rag.js +202 -0
  25. package/actions/row-actions.js +262 -0
  26. package/actions/screens.js +270 -0
  27. package/actions/testing.js +121 -0
  28. package/actions/video-edit.js +54 -0
  29. package/ai-inventory.js +182 -0
  30. package/ai-items.js +202 -0
  31. package/assistant-cast.js +176 -0
  32. package/assistant-suggestions.js +91 -0
  33. package/assistant.js +484 -0
  34. package/audio-voice.js +528 -0
  35. package/auth-google.js +260 -0
  36. package/build-ai.js +52 -0
  37. package/build-order-page.js +191 -0
  38. package/build-order.js +313 -0
  39. package/builder-args.js +117 -0
  40. package/changelog.js +302 -0
  41. package/chat-threads.js +134 -0
  42. package/checks.js +105 -0
  43. package/claude-args.js +282 -0
  44. package/claude-sessions.js +129 -0
  45. package/command-author.js +117 -0
  46. package/command-block.js +20 -0
  47. package/commands/defaults.yml +159 -0
  48. package/commands-page.js +460 -0
  49. package/commands.js +568 -0
  50. package/cucumber.js +43 -0
  51. package/ddev-addons-page.js +124 -0
  52. package/ddev-addons.js +154 -0
  53. package/ddev-custom-commands.js +96 -0
  54. package/ddev-domains.js +84 -0
  55. package/ddev-import.js +93 -0
  56. package/ddev-mail-page.js +167 -0
  57. package/ddev-mail.js +110 -0
  58. package/ddev-options.js +145 -0
  59. package/ddev-snapshots.js +126 -0
  60. package/ddev.js +145 -0
  61. package/docs/DEVELOPER-GUIDE.md +224 -0
  62. package/docs/README.md +252 -0
  63. package/docs/REFERENCE.md +684 -0
  64. package/docs/USER-GUIDE.md +697 -0
  65. package/docs/screenshots/assistant/avatar-board.png +0 -0
  66. package/docs/screenshots/assistant/avatar-coffee.png +0 -0
  67. package/docs/screenshots/assistant/avatar-colours.png +0 -0
  68. package/docs/screenshots/assistant/avatar-icons.png +0 -0
  69. package/docs/screenshots/assistant/avatar-moves.png +0 -0
  70. package/docs/screenshots/assistant/avatar-pick-cookieman.png +0 -0
  71. package/docs/screenshots/assistant/avatar-settings-voices.png +0 -0
  72. package/docs/screenshots/assistant/avatar-status.png +0 -0
  73. package/docs/screenshots/create-card/create-card.png +0 -0
  74. package/docs/screenshots/create-card/start-ai.png +0 -0
  75. package/docs/screenshots/guide-clone-address.png +0 -0
  76. package/docs/screenshots/guide-clone-worktree-off.png +0 -0
  77. package/docs/screenshots/guide-clone-worktree-on.png +0 -0
  78. package/docs/screenshots/guide-ddev-menu.png +0 -0
  79. package/docs/screenshots/guide-domains.png +0 -0
  80. package/docs/screenshots/guide-home.png +0 -0
  81. package/docs/screenshots/guide-ide-menu.png +0 -0
  82. package/docs/screenshots/guide-remove-refusal.png +0 -0
  83. package/docs/screenshots/guide-rows-worktree.png +0 -0
  84. package/docs/screenshots/guide-screens.png +0 -0
  85. package/docs/screenshots/guide-settings.png +0 -0
  86. package/docs/screenshots/guide-workspace-page.png +0 -0
  87. package/docs/screenshots/home/card-settings.png +0 -0
  88. package/docs/screenshots/home/drag-reorder.png +0 -0
  89. package/docs/screenshots/home/edit-card.png +0 -0
  90. package/docs/screenshots/images/claude-code-image.png +0 -0
  91. package/docs/screenshots/images/edit-with-ai.png +0 -0
  92. package/docs/screenshots/images/gallery.png +0 -0
  93. package/docs/screenshots/images/generate-description.png +0 -0
  94. package/docs/screenshots/images/generate-plan.png +0 -0
  95. package/docs/screenshots/images/providers.png +0 -0
  96. package/docs/screenshots/images/svg-form.png +0 -0
  97. package/docs/screenshots/images/svg-result.png +0 -0
  98. package/docs/screenshots/images/upload.png +0 -0
  99. package/docs/screenshots/new-folder/2-form.png +0 -0
  100. package/docs/screenshots/new-folder/8-ddev-options.png +0 -0
  101. package/docs/screenshots/new-folder/files-folder.png +0 -0
  102. package/docs/screenshots/projects/ddev-custom-commands.png +0 -0
  103. package/docs/screenshots/projects/state-chip-stop.png +0 -0
  104. package/docs/screenshots/readme/dashboard-dark.png +0 -0
  105. package/docs/screenshots/readme/dashboard-light.png +0 -0
  106. package/docs/screenshots/readme/dev-dark.png +0 -0
  107. package/docs/screenshots/readme/dev-light.png +0 -0
  108. package/docs/screenshots/readme/docs-dark.png +0 -0
  109. package/docs/screenshots/readme/docs-light.png +0 -0
  110. package/docs/screenshots/readme/icons/ai.svg +4 -0
  111. package/docs/screenshots/readme/icons/code.svg +4 -0
  112. package/docs/screenshots/readme/icons/docs.svg +4 -0
  113. package/docs/screenshots/readme/icons/services.svg +4 -0
  114. package/docs/screenshots/readme/icons/sites.svg +4 -0
  115. package/docs/screenshots/readme/test-report-dark.png +0 -0
  116. package/docs/screenshots/readme/test-report-light.png +0 -0
  117. package/docs/screenshots/readme/test-scenarios.png +0 -0
  118. package/docs/screenshots/readme/test-steps.png +0 -0
  119. package/docs/screenshots/readme/videos-dark.png +0 -0
  120. package/docs/screenshots/readme/videos-light.png +0 -0
  121. package/docs/screenshots/screens-menu.png +0 -0
  122. package/docs/screenshots/screens-new.png +0 -0
  123. package/docs/screenshots/settings/auth-google-lists.png +0 -0
  124. package/docs/screenshots/settings/delete-1-row.png +0 -0
  125. package/docs/screenshots/settings/delete-2-confirm.png +0 -0
  126. package/docs/screenshots/settings/delete-3-type-name.png +0 -0
  127. package/docs/screenshots/settings/delete-4-type-yes.png +0 -0
  128. package/event-log.js +59 -0
  129. package/files-browser.js +247 -0
  130. package/folders.js +121 -0
  131. package/format.js +73 -0
  132. package/git-info.js +81 -0
  133. package/github-auth.js +62 -0
  134. package/graphs.js +104 -0
  135. package/html.js +10 -0
  136. package/icons.js +83 -0
  137. package/images-ai.js +447 -0
  138. package/images-create.js +226 -0
  139. package/images-page.js +417 -0
  140. package/images-records.js +39 -0
  141. package/images-render.js +36 -0
  142. package/images-svg-core.js +214 -0
  143. package/images-svg-sanitize.js +188 -0
  144. package/images-svg.js +241 -0
  145. package/images.js +270 -0
  146. package/jobs.js +430 -0
  147. package/linger.js +21 -0
  148. package/lists.js +292 -0
  149. package/media-info.js +136 -0
  150. package/navigation-page.js +264 -0
  151. package/navigation.js +394 -0
  152. package/notes.js +0 -0
  153. package/obsidian.js +405 -0
  154. package/package.json +47 -4
  155. package/palette-index.js +46 -0
  156. package/playwright.config.js +23 -0
  157. package/plugin-install.js +239 -0
  158. package/plugin-loader.js +448 -0
  159. package/plugin-manifest.js +83 -0
  160. package/plugin-settings.js +44 -0
  161. package/plugins/workspace-notes/index.js +59 -0
  162. package/plugins-page.js +103 -0
  163. package/project-make.js +241 -0
  164. package/project-name.js +210 -0
  165. package/public/assistant-avatar-moves.js +646 -0
  166. package/public/assistant-avatar-ui.js +1223 -0
  167. package/public/assistant-avatar.js +530 -0
  168. package/public/avatar/druplicon.vrm +0 -0
  169. package/public/css/base.css +260 -0
  170. package/public/css/components/ai-assistant.css +263 -0
  171. package/public/css/components/assistant-avatar.css +279 -0
  172. package/public/css/components/assistant-views.css +198 -0
  173. package/public/css/components/build-order.css +74 -0
  174. package/public/css/components/clone-as-a-git-worktree.css +30 -0
  175. package/public/css/components/command-palette.css +61 -0
  176. package/public/css/components/commands-center.css +139 -0
  177. package/public/css/components/confirm-dialog.css +40 -0
  178. package/public/css/components/create-card.css +8 -0
  179. package/public/css/components/ddev-menu.css +23 -0
  180. package/public/css/components/deep-chat.css +17 -0
  181. package/public/css/components/density.css +11 -0
  182. package/public/css/components/floating-assistant-workspace-pages.css +55 -0
  183. package/public/css/components/folders.css +5 -0
  184. package/public/css/components/full-height-left-assistant-sidebar-all-pages.css +39 -0
  185. package/public/css/components/full-height-right-actions-rail-pages-that-have-actions.css +267 -0
  186. package/public/css/components/grid-and-list.css +203 -0
  187. package/public/css/components/help-page.css +36 -0
  188. package/public/css/components/hero.css +16 -0
  189. package/public/css/components/images.css +70 -0
  190. package/public/css/components/layout-rhythm-and-spacing-polish.css +139 -0
  191. package/public/css/components/mic-on-any-field-that-wants-typing.css +416 -0
  192. package/public/css/components/modal-fit.css +113 -0
  193. package/public/css/components/page-width.css +23 -0
  194. package/public/css/components/plugins-page.css +9 -0
  195. package/public/css/components/project-cards.css +256 -0
  196. package/public/css/components/project-rows.css +390 -0
  197. package/public/css/components/reordering-the-workspace-cards.css +85 -0
  198. package/public/css/components/responsive-home-and-the-workspace-pages.css +457 -0
  199. package/public/css/components/running-commands-as-toasts.css +327 -0
  200. package/public/css/components/settings-editor-core-config-yml.css +828 -0
  201. package/public/css/components/short-results-as-a-toast-at-the-top.css +203 -0
  202. package/public/css/components/sound-player.css +84 -0
  203. package/public/css/components/suggest-agents-skills-commands.css +112 -0
  204. package/public/css/components/tab-modal.css +142 -0
  205. package/public/css/components/terminals.css +244 -0
  206. package/public/css/components/test-report-media-one-file-per-row-paged.css +144 -0
  207. package/public/css/components/top-toolbar-logo-breadcrumb.css +107 -0
  208. package/public/css/components/video-edit.css +6 -0
  209. package/public/css/components/web-ide-open-with.css +23 -0
  210. package/public/css/components/working-indicators.css +158 -0
  211. package/public/css/components/workspace-cards.css +79 -0
  212. package/public/favicon.ico +0 -0
  213. package/public/favicon.png +0 -0
  214. package/public/htmx.min.js +1 -0
  215. package/public/logo.png +0 -0
  216. package/public/media-player.js +215 -0
  217. package/public/mic.js +255 -0
  218. package/public/narration.js +110 -0
  219. package/public/palette.js +278 -0
  220. package/public/sortable.js +251 -0
  221. package/public/suggest.js +337 -0
  222. package/public/terminal.js +903 -0
  223. package/public/themes/default/theme.css +267 -0
  224. package/public/themes/ember/theme.css +180 -0
  225. package/public/themes/press/theme.css +290 -0
  226. package/public/themes/slate/theme.css +182 -0
  227. package/public/touch-icon.png +0 -0
  228. package/public/ui.js +2721 -0
  229. package/public/vendor/ace/LICENSE.txt +24 -0
  230. package/public/vendor/ace/ace.js +23 -0
  231. package/public/vendor/ace/ext-language_tools.js +8 -0
  232. package/public/vendor/ace/ext-searchbox.js +8 -0
  233. package/public/vendor/ace/mode-css.js +8 -0
  234. package/public/vendor/ace/mode-html.js +8 -0
  235. package/public/vendor/ace/mode-javascript.js +8 -0
  236. package/public/vendor/ace/mode-markdown.js +8 -0
  237. package/public/vendor/ace/mode-sh.js +8 -0
  238. package/public/vendor/ace/mode-yaml.js +8 -0
  239. package/public/vendor/ace/theme-textmate.js +8 -0
  240. package/public/vendor/ace/theme-tomorrow_night.js +8 -0
  241. package/public/vendor/ace/worker-yaml.js +1 -0
  242. package/public/vendor/deep-chat.LICENSE +21 -0
  243. package/public/vendor/deep-chat.bundle.js +1 -0
  244. package/public/vendor/fonts/dm-serif-text-LICENSE.txt +93 -0
  245. package/public/vendor/fonts/dm-serif-text-latin-400-italic.woff2 +0 -0
  246. package/public/vendor/fonts/dm-serif-text-latin-400-normal.woff2 +0 -0
  247. package/public/vendor/fonts/figtree-LICENSE.txt +93 -0
  248. package/public/vendor/fonts/figtree-latin-400-italic.woff2 +0 -0
  249. package/public/vendor/fonts/figtree-latin-400-normal.woff2 +0 -0
  250. package/public/vendor/fonts/figtree-latin-600-italic.woff2 +0 -0
  251. package/public/vendor/fonts/figtree-latin-600-normal.woff2 +0 -0
  252. package/public/vendor/fonts/jetbrains-mono-LICENSE.txt +93 -0
  253. package/public/vendor/fonts/jetbrains-mono-latin-400-normal.woff2 +0 -0
  254. package/public/vendor/fonts/ubuntu-mono-LICENSE.txt +98 -0
  255. package/public/vendor/fonts/ubuntu-mono-latin-wght-normal.woff2 +0 -0
  256. package/public/vendor/tabler-LICENSE.txt +21 -0
  257. package/public/vendor/tabler-sprite.svg +1 -0
  258. package/public/vendor/three/LICENSE +21 -0
  259. package/public/vendor/three/addons/loaders/GLTFLoader.js +4860 -0
  260. package/public/vendor/three/addons/utils/BufferGeometryUtils.js +1501 -0
  261. package/public/vendor/three/addons/utils/SkeletonUtils.js +496 -0
  262. package/public/vendor/three/three.core.min.js +6 -0
  263. package/public/vendor/three/three.module.min.js +6 -0
  264. package/public/vendor/three-vrm/LICENSE +22 -0
  265. package/public/vendor/three-vrm/three-vrm.module.min.js +983 -0
  266. package/public/vendor/uikit-icons.min.js +1 -0
  267. package/public/vendor/uikit.min.css +1 -0
  268. package/public/vendor/uikit.min.js +1 -0
  269. package/public/vendor/webship-icons/ui/bookmark-outlined.svg +1 -0
  270. package/public/vendor/webship-icons/ui/headset.svg +1 -0
  271. package/public/vendor/webship-icons/ui/menu.svg +1 -0
  272. package/public/vendor/webship-icons/ui/pause.svg +1 -0
  273. package/public/vendor/webship-icons/ui/play.svg +1 -0
  274. package/public/vendor/webship-icons/ui/share.svg +1 -0
  275. package/public/vendor/webship-icons/ui/sound-off.svg +1 -0
  276. package/public/vendor/webship-icons/ui/sound-on.svg +1 -0
  277. package/public/vendor/webship-icons/ui/stop.svg +1 -0
  278. package/public/vendor/xterm/addon-fit.js +2 -0
  279. package/public/vendor/xterm/addon-unicode11.js +2 -0
  280. package/public/vendor/xterm/addon-web-links.js +2 -0
  281. package/public/vendor/xterm/xterm.css +218 -0
  282. package/public/vendor/xterm/xterm.js +2 -0
  283. package/rag.js +169 -0
  284. package/reader.js +132 -0
  285. package/repo-blobs.js +66 -0
  286. package/report-pdf.js +337 -0
  287. package/row-layout.js +1440 -0
  288. package/screenrc +37 -0
  289. package/screens.js +1063 -0
  290. package/scripts/code-server-start.sh +190 -0
  291. package/scripts/images-claude-finish.js +107 -0
  292. package/scripts/screen-host.sh +114 -0
  293. package/scripts/screen-runner.js +362 -0
  294. package/scripts/screen-then.js +47 -0
  295. package/scripts/update.sh +350 -0
  296. package/server.js +8140 -0
  297. package/settings-file.js +423 -0
  298. package/speech.js +297 -0
  299. package/tab-modal.js +75 -0
  300. package/test-reports.js +260 -0
  301. package/themes.js +381 -0
  302. package/transcripts.js +168 -0
  303. package/urls.js +13 -0
  304. package/validate.js +18 -0
  305. package/version-check.js +94 -0
  306. package/video-edit.js +588 -0
  307. package/waiting.js +85 -0
  308. package/workspace-card-tools.js +41 -0
  309. package/workspace-delete.js +139 -0
  310. package/workspace-types.js +85 -0
  311. package/workspaces.js +557 -0
@@ -0,0 +1,260 @@
1
+ /**
2
+ * The base layer: the brand typefaces, the resets, and the rules that belong to no single
3
+ * component. No colour is named here — every value comes from the theme's tokens, which is what
4
+ * lets a theme change the whole dashboard without touching a component.
5
+ */
6
+ /* Small overrides on top of UIKit (vendor/uikit.min.css) — layout and
7
+ * components come from UIKit; this file adds the brand palette, chat
8
+ * bubbles, working indicators, and the floating assistant. */
9
+
10
+ /* The brand typefaces, from the brand tokens's typeface collection: Primary
11
+ Figtree (Regular, SemiBold, Italic), Secondary DM Serif Text (Regular, Italic),
12
+ and JetBrains Mono for code. All three were NAMED in the tokens below but never
13
+ loaded — no @font-face existed anywhere — so every page has been rendering in
14
+ Helvetica and Georgia while claiming to be on brand.
15
+ Vendored as woff2 (latin, 148KB for all seven faces), because everything here is
16
+ served locally: a Google Fonts link would not survive an offline DDEV box and is
17
+ blocked outright by the artifact CSP. OFL-1.1, licences beside the files.
18
+ font-display: swap — text must be readable before the font arrives. */
19
+ @font-face {
20
+ font-family: 'Figtree';
21
+ font-style: normal;
22
+ font-weight: 400;
23
+ font-display: swap;
24
+ src: url('/vendor/fonts/figtree-latin-400-normal.woff2') format('woff2');
25
+ }
26
+ @font-face {
27
+ font-family: 'Figtree';
28
+ font-style: italic;
29
+ font-weight: 400;
30
+ font-display: swap;
31
+ src: url('/vendor/fonts/figtree-latin-400-italic.woff2') format('woff2');
32
+ }
33
+ @font-face {
34
+ font-family: 'Figtree';
35
+ font-style: normal;
36
+ font-weight: 600;
37
+ font-display: swap;
38
+ src: url('/vendor/fonts/figtree-latin-600-normal.woff2') format('woff2');
39
+ }
40
+ @font-face {
41
+ font-family: 'Figtree';
42
+ font-style: italic;
43
+ font-weight: 600;
44
+ font-display: swap;
45
+ src: url('/vendor/fonts/figtree-latin-600-italic.woff2') format('woff2');
46
+ }
47
+ @font-face {
48
+ font-family: 'DM Serif Text';
49
+ font-style: normal;
50
+ font-weight: 400;
51
+ font-display: swap;
52
+ src: url('/vendor/fonts/dm-serif-text-latin-400-normal.woff2') format('woff2');
53
+ }
54
+ @font-face {
55
+ font-family: 'DM Serif Text';
56
+ font-style: italic;
57
+ font-weight: 400;
58
+ font-display: swap;
59
+ src: url('/vendor/fonts/dm-serif-text-latin-400-italic.woff2') format('woff2');
60
+ }
61
+ @font-face {
62
+ font-family: 'JetBrains Mono';
63
+ font-style: normal;
64
+ font-weight: 400;
65
+ font-display: swap;
66
+ src: url('/vendor/fonts/jetbrains-mono-latin-400-normal.woff2') format('woff2');
67
+ }
68
+ /* The terminal's face: Ubuntu Mono, the one the Ubuntu terminal draws with. One variable file serves
69
+ regular and bold. Ubuntu Font Licence 1.0, beside the file. */
70
+ @font-face {
71
+ font-family: 'Ubuntu Mono';
72
+ font-style: normal;
73
+ font-weight: 400 700;
74
+ font-display: swap;
75
+ src: url('/vendor/fonts/ubuntu-mono-latin-wght-normal.woff2') format('woff2');
76
+ }
77
+
78
+ /* UIKit, fed the Webship tokens.
79
+ *
80
+ * UIKit's own stylesheet (vendor/uikit.min.css) is untouched — these rules
81
+ * re-point its colours at the theme's tokens, once, so that the dark half is a
82
+ * different set of VALUES rather than a second set of RULES. Every declaration
83
+ * below reads a token; none of them names a colour. That is the whole contract:
84
+ * a component that says var(--surface-card) is right in any theme and in either
85
+ * half, and one that says a colour outright is right in exactly one.
86
+ *
87
+ * The text ladder is Webship's, darkest to quietest: --text-default for headings,
88
+ * --text-subtle-2 for body and controls, --text-subtle for meta. UIKit's own greys
89
+ * were lighter than the design system asks for, and lighter than WCAG AA wants on a
90
+ * tinted surface.
91
+ */
92
+
93
+ /* The ROOT carries the page colour too, not just the body.
94
+ *
95
+ * <html> was left at the browser's white while <body> went dark, so every gap showed it: the strip
96
+ * under a page whose content is shorter than the window, and the overscroll bounce at the top and
97
+ * bottom of a long one. A white flash on a dark dashboard, from the one element nobody had painted.
98
+ *
99
+ * min-height on both, so a short page still fills the window rather than ending in a band of
100
+ * whatever is behind it — /products with two rows, /videos with none. */
101
+ html { background: var(--surface); min-height: 100%; }
102
+ html.dark { color-scheme: dark; }
103
+ body { min-height: 100vh; }
104
+ body.uk-background-muted { background: var(--surface) !important; color: var(--text-subtle-2); }
105
+
106
+ /* Gradient headline + brand buttons */
107
+ .hero h1 {
108
+ background: var(--brand-grad);
109
+ -webkit-background-clip: text;
110
+ background-clip: text;
111
+ color: transparent;
112
+ font-weight: 700;
113
+ }
114
+
115
+ .uk-button-primary {
116
+ background: var(--brand-grad);
117
+ border: none;
118
+ color: var(--text-inverse);
119
+ }
120
+
121
+ .uk-button-primary:hover { filter: brightness(1.08); background: var(--brand-grad); }
122
+
123
+ .uk-button-default {
124
+ background: var(--surface-card);
125
+ color: var(--text-subtle-2);
126
+ border-color: var(--line-strong);
127
+ }
128
+
129
+ .uk-button-default:hover,
130
+ .uk-button-default:focus { background: var(--surface-muted); color: var(--text-default); }
131
+
132
+ .uk-button-secondary { background: var(--brand-secondary); color: var(--text-inverse); }
133
+
134
+ .uk-button-danger { background: var(--danger); }
135
+ .uk-badge, .uk-label { background: var(--chip-bg); color: var(--chip-ink); }
136
+
137
+ /* Status, from the brand tokens's Alert Colors: the solid colour, its subtle tint, and the ink that reads on the
138
+ tint. UIKit's own green, orange and pink were none of those, and white on its green label was 2.6:1. */
139
+ .uk-label-success { background: var(--ok); color: var(--text-inverse); }
140
+ /* Dark text on the yellow in both halves: --warning-ink lightens after dark, for the dark tint, not for this. */
141
+ .uk-label-warning { background: var(--warning); color: var(--brand-dark); }
142
+ .uk-label-danger { background: var(--danger); color: var(--text-inverse); }
143
+ .uk-text-success { color: var(--ok-ink) !important; }
144
+ .uk-text-warning { color: var(--warning-ink) !important; }
145
+ .uk-text-danger { color: var(--danger-text) !important; }
146
+ .uk-text-primary { color: var(--link) !important; }
147
+ /* UIKit colours emphasis pink; in running text emphasis is the sentence's own colour, in italics. */
148
+ em { color: inherit; }
149
+ .uk-alert-primary { background: var(--busy-soft); color: var(--busy-ink); }
150
+ .uk-alert-success { background: var(--ok-soft); color: var(--ok-ink); }
151
+ .uk-alert-warning { background: var(--warning-soft); color: var(--warning-ink); }
152
+ .uk-alert-danger { background: var(--danger-soft); color: var(--danger-ink); }
153
+
154
+ .uk-card-default {
155
+ background: var(--surface-card);
156
+ color: var(--text-subtle-2);
157
+ border: 1px solid var(--line);
158
+ box-shadow: var(--shadow-card);
159
+ }
160
+
161
+ .uk-card-hover:hover { box-shadow: var(--shadow-card-hover); border-color: var(--line-strong); }
162
+
163
+ /* The classes too: UIKit colours .uk-h3 itself, and a class outranks a tag, so "Build a new project" (an h2 with
164
+ .uk-h3) stayed UIKit's dark grey on the dark page. */
165
+ h1, h2, h3, h4, h5, h6, .uk-h1, .uk-h2, .uk-h3, .uk-h4, .uk-h5, .uk-h6, .uk-card-default .uk-card-title { color: var(--text-default); }
166
+ .uk-text-meta, .uk-text-lead { color: var(--text-subtle) !important; }
167
+
168
+ /* Form controls. The select needs UIKit's own selector — `.uk-select` alone is
169
+ (0,1,0) against UIKit's `.uk-select:not([multiple]):not([size])` at (0,3,0), so
170
+ the shorter one never won and every dropdown stayed unstyled. `background-color`,
171
+ not the `background` shorthand: the shorthand would drop the arrow, which UIKit
172
+ draws as a background-image in that same rule. */
173
+ .uk-input, .uk-textarea {
174
+ background: var(--surface-input);
175
+ color: var(--text-subtle-2);
176
+ border-color: var(--line);
177
+ }
178
+
179
+ .uk-select:not([multiple]):not([size]) {
180
+ background-color: var(--surface-input);
181
+ color: var(--text-subtle-2);
182
+ border-color: var(--line);
183
+ }
184
+
185
+ .uk-input:focus, .uk-textarea:focus, .uk-select:focus {
186
+ border-color: var(--link);
187
+ box-shadow: 0 0 0 .1875rem var(--focus-ring);
188
+ }
189
+
190
+ .uk-input::placeholder, .uk-textarea::placeholder { color: var(--text-subtle); }
191
+
192
+ a, .uk-link { color: var(--link); }
193
+
194
+ /* Menus. UIKit paints a dropdown white with grey links and dark headers whatever the page is, so every row menu
195
+ (DDEV, GIT, COMPOSER…) stayed a white panel after dark, and its links were 2.8:1 in light. */
196
+ .uk-dropdown { background: var(--surface-card); color: var(--text-subtle-2); border: 1px solid var(--line); box-shadow: var(--shadow-float); }
197
+ .uk-dropdown-nav > li > a, .uk-nav-default > li > a,
198
+ .uk-dropdown-nav .uk-nav-sub a, .uk-nav-default .uk-nav-sub a { color: var(--text-subtle-2); }
199
+ .uk-dropdown-nav > li > a:hover, .uk-dropdown-nav > li.uk-active > a,
200
+ .uk-nav-default > li > a:hover, .uk-nav-default > li.uk-active > a,
201
+ .uk-dropdown-nav .uk-nav-sub a:hover, .uk-nav-default .uk-nav-sub a:hover { color: var(--link); }
202
+ .uk-dropdown-nav .uk-nav-header, .uk-nav-default .uk-nav-header, .uk-nav-header { color: var(--text-default); }
203
+ .uk-dropdown-nav .uk-nav-divider, .uk-nav-default .uk-nav-divider, .uk-nav-divider { border-top-color: var(--line); }
204
+
205
+ /* Tab switchers (Commands → Buttons: Rows, Activity, Definition). UIKit's blue is not Webship blue, and its grey
206
+ tabs were 2.8:1. */
207
+ .uk-subnav > * > :first-child { color: var(--text-subtle); }
208
+ .uk-subnav > * > a:hover, .uk-subnav > .uk-active > a { color: var(--text-default); }
209
+ .uk-subnav-pill > * > a:hover { background-color: var(--surface-muted); color: var(--text-default); }
210
+ .uk-subnav-pill > .uk-active > a { background-color: var(--brand-primary); color: var(--text-inverse); }
211
+
212
+ /* Code. Inline code reads as part of its sentence: a quiet tint and the accent ink, in both halves. UIKit's pink
213
+ on near-white was 3.2:1, and stayed a light box on the dark page. A block of code is the code surface in both
214
+ halves, as the terminal and the job output already are. */
215
+ :not(pre) > code, :not(pre) > kbd, :not(pre) > samp { background: var(--surface-muted); color: var(--accent-ink); }
216
+ pre { background: var(--code-bg); color: var(--code-ink); border-color: var(--line); }
217
+ pre code { color: inherit; }
218
+
219
+ footer.uk-section, footer.uk-section a { color: var(--text-subtle); }
220
+
221
+
222
+ /* ---------- Keyboard focus, everywhere ----------
223
+ *
224
+ * There was no global focus style, so most of the interface fell back to the browser's own — a 2px
225
+ * DOTTED outline in near-black, which on a dark page over a dark panel is all but invisible, and on a
226
+ * light one is a 1996 dotted box. A keyboard user could not see where they were.
227
+ *
228
+ * :focus-visible, not :focus, so a mouse click does not draw a ring the pointer user did not ask for.
229
+ * The tokens do the theming, so both halves follow with no second copy of the rule. */
230
+ :where(a, button, [role="button"], input, select, textarea, summary, [tabindex]:not([tabindex="-1"])):focus-visible {
231
+ outline: 2px solid var(--brand-primary);
232
+ outline-offset: 2px;
233
+ border-radius: 0.25rem;
234
+ }
235
+
236
+ /* On a brand-coloured surface the brand ring disappears into it; light is what reads there. */
237
+ .assistant-head :where(a, button):focus-visible,
238
+ .uk-button-primary:focus-visible,
239
+ .uk-button-secondary:focus-visible,
240
+ .uk-button-danger:focus-visible {
241
+ outline-color: var(--text-inverse);
242
+ outline-offset: 1px;
243
+ }
244
+
245
+ /* A link inside a block of text has to be told apart from that text by something other than colour
246
+ (WCAG 1.4.1): brand blue against the meta grey is 1.08:1 to a colour-blind reader and on a printout.
247
+ Scoped to prose — paragraphs, list items and the meta lines — so the buttons, the project rows and
248
+ the rails, where a link is already a shape, are left alone. */
249
+ p a:not(.uk-button):not(.uk-link-reset),
250
+ li a:not(.uk-button):not(.uk-link-reset),
251
+ .uk-text-meta a:not(.uk-button):not(.uk-link-reset) {
252
+ text-decoration: underline;
253
+ text-decoration-thickness: 1px;
254
+ text-underline-offset: 2px;
255
+ }
256
+
257
+ /* UIKit paints a link inside .uk-text-meta the same grey as the meta text — 2.84:1 on white,
258
+ and indistinguishable from the words around it. The link token is the readable one; the extra
259
+ :not() is what outranks UIKit's own two-class rule without touching the vendored file. */
260
+ .uk-text-meta a:not(.uk-button):not(.uk-link-reset) { color: var(--link); }
@@ -0,0 +1,263 @@
1
+ /* ---------- AI Assistant ---------- */
2
+
3
+ .assistant-panel {
4
+ border-radius:0.75rem;
5
+ overflow: hidden;
6
+ box-shadow: 0 8px 28px rgba(30, 135, 240, .12);
7
+ }
8
+
9
+ .assistant-head {
10
+ background: var(--brand-grad);
11
+ color: var(--text-inverse);
12
+ padding:1rem 1.25rem;
13
+ }
14
+
15
+ .assistant-head-row { gap:0.75rem; }
16
+
17
+ .assistant-avatar {
18
+ width:2.875rem;
19
+ height:2.875rem;
20
+ min-width:2.875rem;
21
+ border-radius: 50%;
22
+ background: rgba(255, 255, 255, .2);
23
+ display: flex;
24
+ align-items: center;
25
+ justify-content: center;
26
+ font-size:1.5rem;
27
+ }
28
+
29
+ .assistant-head-text { flex: 1; min-width: 0; }
30
+ .assistant-head-text h3 { color: var(--text-inverse); font-size:1.0625rem; line-height: 1.2; }
31
+ .assistant-head-text .uk-text-small { color: rgba(255, 255, 255, .8); }
32
+
33
+ .assistant-badge {
34
+ background: rgba(255, 255, 255, .22);
35
+ color: var(--text-inverse);
36
+ border-radius:62.4375rem;
37
+ white-space: nowrap;
38
+ }
39
+
40
+ .assistant-body { padding:1.125rem 1.25rem 1.25rem; }
41
+
42
+ /* Chat log */
43
+
44
+ .chat-log {
45
+ background: var(--subtle-light);
46
+ border: 1px solid var(--line);
47
+ border-radius:0.75rem;
48
+ padding:0.875rem;
49
+ min-height:13.75rem;
50
+ max-height:clamp(15rem, 42vh, 26.25rem);
51
+ overflow-y: auto;
52
+ font-size:0.875rem;
53
+ line-height: 1.5;
54
+ }
55
+
56
+ .chat-log .msg {
57
+ position: relative;
58
+ margin-bottom:0.875rem;
59
+ max-width: 88%;
60
+ }
61
+
62
+ .chat-log .msg:last-child { margin-bottom: 0; }
63
+ .chat-log .msg p { margin:0.25rem 0; }
64
+
65
+ .chat-log .msg.assistant,
66
+ .chat-log .msg.error {
67
+ background: var(--surface-card);
68
+ border: 1px solid var(--line);
69
+ border-radius:0.25rem 0.875rem 0.875rem 0.875rem;
70
+ padding:0.625rem 0.875rem 0.625rem 0.875rem;
71
+ margin-left:2.125rem;
72
+ box-shadow: 0 2px 6px rgba(20, 30, 60, .05);
73
+ }
74
+
75
+ .chat-log .msg.assistant::before,
76
+ .chat-log .msg.error::before {
77
+ content: '';
78
+ position: absolute;
79
+ left:-2.125rem;
80
+ top: 0;
81
+ width:1.625rem;
82
+ height:1.625rem;
83
+ border-radius: 50%;
84
+ background: var(--brand-grad);
85
+ background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='white'%3E%3Cpath%20d='M10.5%202l1.9%206.1%206.1%201.9-6.1%201.9-1.9%206.1-1.9-6.1L2.5%2010l6.1-1.9L10.5%202z'/%3E%3Cpath%20d='M18.5%2013.5l1%203%203%201-3%201-1%203-1-3-3-1%203-1%201-3z'/%3E%3C/svg%3E"), var(--brand-grad);
86
+ background-size: 15px 15px, cover;
87
+ background-position: center, center;
88
+ background-repeat: no-repeat;
89
+ }
90
+
91
+ .chat-log .msg.user {
92
+ background: var(--brand-grad);
93
+ color: var(--text-inverse);
94
+ border-radius:0.875rem 0.25rem 0.875rem 0.875rem;
95
+ padding:0.625rem 0.875rem;
96
+ margin-left: auto;
97
+ margin-right:2.125rem;
98
+ box-shadow: 0 3px 10px rgba(30, 135, 240, .25);
99
+ }
100
+
101
+ .chat-log .msg.user::after {
102
+ content: '👤';
103
+ position: absolute;
104
+ right:-2.125rem;
105
+ top: 0;
106
+ width:1.625rem;
107
+ height:1.625rem;
108
+ border-radius: 50%;
109
+ background: var(--line);
110
+ display: flex;
111
+ align-items: center;
112
+ justify-content: center;
113
+ font-size:0.875rem;
114
+ }
115
+
116
+ .chat-log .msg.error {
117
+ border-color: var(--danger);
118
+ color: var(--danger-ink);
119
+ }
120
+
121
+ #webship-workspace-output .msg.error {
122
+ background: var(--danger-soft);
123
+ border: 1px solid var(--danger);
124
+ color: var(--danger-ink);
125
+ border-radius:0.375rem;
126
+ padding:0.5rem 0.75rem;
127
+ margin-top:1rem;
128
+ }
129
+
130
+ #webship-workspace-output .msg.assistant {
131
+ background: var(--surface-card);
132
+ border: 1px solid var(--line);
133
+ border-radius:0.375rem;
134
+ padding:0.75rem;
135
+ margin-top:1rem;
136
+ }
137
+
138
+ .chat-log pre,
139
+ #webship-workspace-output pre {
140
+ background: var(--code-bg);
141
+ color: var(--code-ink);
142
+ padding:0.625rem;
143
+ border-radius:0.5rem;
144
+ overflow-x: auto;
145
+ font-size:0.75rem;
146
+ max-height:16.25rem;
147
+ margin:0.5rem 0 0;
148
+ }
149
+
150
+ /* Chat input */
151
+
152
+ /* A composer box, not a one-line field: the prompt sits in a bordered card
153
+ with the text on its own row and the controls on a toolbar underneath —
154
+ the shape Drupal CMS uses for its AI prompt. */
155
+ .chat-input {
156
+ display: flex;
157
+ flex-direction: column;
158
+ gap:0.5rem;
159
+ margin-top:0.875rem;
160
+ padding:0.625rem 0.75rem;
161
+ background: var(--surface-card);
162
+ border: 1px solid var(--line);
163
+ border-radius:0.875rem;
164
+ box-shadow: 0 1px 2px rgba(43, 68, 124, .06);
165
+ transition: border-color .15s ease, box-shadow .15s ease;
166
+ }
167
+
168
+ .chat-input:focus-within {
169
+ border-color: var(--brand-primary);
170
+ box-shadow: 0 0 0 3px var(--subtle-brand);
171
+ }
172
+
173
+ /* UIKit pins .uk-input to a 40px height, so the composer overrides height
174
+ itself — min-height alone loses to it. */
175
+ .chat-input .uk-input {
176
+ border: 0;
177
+ background: transparent;
178
+ border-radius: 0;
179
+ box-shadow: none;
180
+ flex: 1;
181
+ min-width: 0;
182
+ height: auto;
183
+ min-height:4.75rem;
184
+ padding:0.375rem 0.125rem;
185
+ font-size:0.9375rem;
186
+ line-height: 1.5;
187
+ }
188
+
189
+ .chat-input .uk-input:focus { border: 0; box-shadow: none; background: transparent; }
190
+
191
+ .chat-input .chat-tools {
192
+ display: flex;
193
+ align-items: center;
194
+ justify-content: flex-end;
195
+ gap:0.5rem;
196
+ }
197
+
198
+
199
+ .chat-input .mic-btn,
200
+ .chat-input .send-btn {
201
+ border-radius:31.25rem;
202
+ display: inline-flex;
203
+ align-items: center;
204
+ gap:0.25rem;
205
+ padding:0 0.875rem;
206
+ }
207
+
208
+ /* Responsive: stack quick actions, icon-only buttons on narrow screens */
209
+
210
+ @media (max-width: 40em) {
211
+ .assistant-body { padding:0.875rem; }
212
+ .assistant-head { padding:0.75rem 0.875rem; }
213
+ .chat-log .msg { max-width: 100%; }
214
+ .send-btn .qa-label { display: none; }
215
+ .assistant-badge .uk-label-text { display: none; }
216
+ }
217
+
218
+ /* Until ui.js moves the prompt-mode select into deep-chat's toolbar, it lives in
219
+ its own row above the composer — visible and usable, never missing. */
220
+ .assistant-body > .chat-tools { display: flex; margin-bottom: .5rem; }
221
+ .assistant-body > .chat-tools .command-picker { width: 100%; }
222
+
223
+ /* "New chat" in the panel header. Labelled rather than an icon alone — a bare glyph in a chat
224
+ header could as easily mean reload or retry, and this one ends the conversation.
225
+
226
+ It sits ON the brand gradient, so it cannot be a default button: that one is a light outline with
227
+ dark ink, which put near-black text on a blue gradient (2.06:1 against the light end of it, 1.00:1
228
+ against the dark end — invisible). White ink on a hairline of white, no fill, is legible over both
229
+ ends: 4.59:1 on brand/primary and 9.46:1 on brand/secondary (measured).
230
+
231
+ The selector has to out-specify UIKit's own .uk-button-default. A single class ties with it, and
232
+ uikit.min.css is linked after the assembled stylesheet, so the tie went to UIKit and none of this
233
+ applied — which is exactly what the black label was. Never fork the vendored CSS; win on
234
+ specificity instead. The hover fill is black rather than white for the same reason as the ink:
235
+ lightening the ground under white text is what would take the contrast back down. */
236
+ .assistant-head-row { gap: 0.5rem; }
237
+ .assistant-head-text { flex: 1; min-width: 0; }
238
+
239
+ .assistant-head .uk-button.assistant-new {
240
+ flex: none;
241
+ white-space: nowrap;
242
+ padding: 0 0.7rem;
243
+ line-height: 1.75rem;
244
+ font-size: 0.8125rem;
245
+ color: var(--text-inverse);
246
+ background: transparent;
247
+ border: 1px solid rgba(255, 255, 255, .55);
248
+ border-radius: 62.4375rem;
249
+ box-shadow: none;
250
+ }
251
+
252
+ .assistant-head .uk-button.assistant-new:hover,
253
+ .assistant-head .uk-button.assistant-new:focus {
254
+ color: var(--text-inverse);
255
+ background: rgba(0, 0, 0, .18);
256
+ border-color: rgba(255, 255, 255, .85);
257
+ }
258
+
259
+ /* The page's focus ring is a brand blue, which disappears into the gradient. */
260
+ .assistant-head .uk-button.assistant-new:focus-visible {
261
+ outline: 2px solid rgba(255, 255, 255, .9);
262
+ outline-offset: 2px;
263
+ }