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

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 (307) 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/images-svg.js +33 -0
  16. package/actions/images.js +145 -0
  17. package/actions/navigation.js +190 -0
  18. package/actions/node.js +222 -0
  19. package/actions/notes.js +55 -0
  20. package/actions/plugins.js +36 -0
  21. package/actions/project-make.js +28 -0
  22. package/actions/rag.js +202 -0
  23. package/actions/row-actions.js +262 -0
  24. package/actions/screens.js +270 -0
  25. package/actions/testing.js +121 -0
  26. package/actions/video-edit.js +54 -0
  27. package/ai-inventory.js +182 -0
  28. package/ai-items.js +202 -0
  29. package/assistant-cast.js +176 -0
  30. package/assistant-suggestions.js +91 -0
  31. package/assistant.js +484 -0
  32. package/audio-voice.js +528 -0
  33. package/auth-google.js +260 -0
  34. package/build-ai.js +52 -0
  35. package/build-order-page.js +191 -0
  36. package/build-order.js +313 -0
  37. package/builder-args.js +117 -0
  38. package/changelog.js +302 -0
  39. package/chat-threads.js +134 -0
  40. package/checks.js +105 -0
  41. package/claude-args.js +282 -0
  42. package/claude-sessions.js +129 -0
  43. package/command-author.js +117 -0
  44. package/command-block.js +20 -0
  45. package/commands/defaults.yml +159 -0
  46. package/commands-page.js +460 -0
  47. package/commands.js +568 -0
  48. package/cucumber.js +43 -0
  49. package/ddev-addons-page.js +124 -0
  50. package/ddev-addons.js +154 -0
  51. package/ddev-custom-commands.js +96 -0
  52. package/ddev-domains.js +84 -0
  53. package/ddev-import.js +93 -0
  54. package/ddev-mail-page.js +167 -0
  55. package/ddev-mail.js +110 -0
  56. package/ddev-options.js +145 -0
  57. package/ddev-snapshots.js +126 -0
  58. package/ddev.js +145 -0
  59. package/docs/DEVELOPER-GUIDE.md +224 -0
  60. package/docs/README.md +252 -0
  61. package/docs/REFERENCE.md +684 -0
  62. package/docs/USER-GUIDE.md +697 -0
  63. package/docs/screenshots/assistant/avatar-board.png +0 -0
  64. package/docs/screenshots/assistant/avatar-coffee.png +0 -0
  65. package/docs/screenshots/assistant/avatar-colours.png +0 -0
  66. package/docs/screenshots/assistant/avatar-icons.png +0 -0
  67. package/docs/screenshots/assistant/avatar-moves.png +0 -0
  68. package/docs/screenshots/assistant/avatar-pick-cookieman.png +0 -0
  69. package/docs/screenshots/assistant/avatar-settings-voices.png +0 -0
  70. package/docs/screenshots/assistant/avatar-status.png +0 -0
  71. package/docs/screenshots/create-card/create-card.png +0 -0
  72. package/docs/screenshots/create-card/start-ai.png +0 -0
  73. package/docs/screenshots/guide-clone-address.png +0 -0
  74. package/docs/screenshots/guide-clone-worktree-off.png +0 -0
  75. package/docs/screenshots/guide-clone-worktree-on.png +0 -0
  76. package/docs/screenshots/guide-ddev-menu.png +0 -0
  77. package/docs/screenshots/guide-domains.png +0 -0
  78. package/docs/screenshots/guide-home.png +0 -0
  79. package/docs/screenshots/guide-ide-menu.png +0 -0
  80. package/docs/screenshots/guide-remove-refusal.png +0 -0
  81. package/docs/screenshots/guide-rows-worktree.png +0 -0
  82. package/docs/screenshots/guide-screens.png +0 -0
  83. package/docs/screenshots/guide-settings.png +0 -0
  84. package/docs/screenshots/guide-workspace-page.png +0 -0
  85. package/docs/screenshots/home/card-settings.png +0 -0
  86. package/docs/screenshots/home/drag-reorder.png +0 -0
  87. package/docs/screenshots/home/edit-card.png +0 -0
  88. package/docs/screenshots/images/claude-code-image.png +0 -0
  89. package/docs/screenshots/images/edit-with-ai.png +0 -0
  90. package/docs/screenshots/images/gallery.png +0 -0
  91. package/docs/screenshots/images/generate-description.png +0 -0
  92. package/docs/screenshots/images/generate-plan.png +0 -0
  93. package/docs/screenshots/images/providers.png +0 -0
  94. package/docs/screenshots/images/svg-form.png +0 -0
  95. package/docs/screenshots/images/svg-result.png +0 -0
  96. package/docs/screenshots/images/upload.png +0 -0
  97. package/docs/screenshots/new-folder/2-form.png +0 -0
  98. package/docs/screenshots/new-folder/8-ddev-options.png +0 -0
  99. package/docs/screenshots/new-folder/files-folder.png +0 -0
  100. package/docs/screenshots/projects/ddev-custom-commands.png +0 -0
  101. package/docs/screenshots/projects/state-chip-stop.png +0 -0
  102. package/docs/screenshots/readme/dashboard-dark.png +0 -0
  103. package/docs/screenshots/readme/dashboard-light.png +0 -0
  104. package/docs/screenshots/readme/dev-dark.png +0 -0
  105. package/docs/screenshots/readme/dev-light.png +0 -0
  106. package/docs/screenshots/readme/docs-dark.png +0 -0
  107. package/docs/screenshots/readme/docs-light.png +0 -0
  108. package/docs/screenshots/readme/icons/ai.svg +4 -0
  109. package/docs/screenshots/readme/icons/code.svg +4 -0
  110. package/docs/screenshots/readme/icons/docs.svg +4 -0
  111. package/docs/screenshots/readme/icons/services.svg +4 -0
  112. package/docs/screenshots/readme/icons/sites.svg +4 -0
  113. package/docs/screenshots/readme/test-report-dark.png +0 -0
  114. package/docs/screenshots/readme/test-report-light.png +0 -0
  115. package/docs/screenshots/readme/test-scenarios.png +0 -0
  116. package/docs/screenshots/readme/test-steps.png +0 -0
  117. package/docs/screenshots/readme/videos-dark.png +0 -0
  118. package/docs/screenshots/readme/videos-light.png +0 -0
  119. package/docs/screenshots/screens-menu.png +0 -0
  120. package/docs/screenshots/screens-new.png +0 -0
  121. package/docs/screenshots/settings/auth-google-lists.png +0 -0
  122. package/docs/screenshots/settings/delete-1-row.png +0 -0
  123. package/docs/screenshots/settings/delete-2-confirm.png +0 -0
  124. package/docs/screenshots/settings/delete-3-type-name.png +0 -0
  125. package/docs/screenshots/settings/delete-4-type-yes.png +0 -0
  126. package/event-log.js +59 -0
  127. package/files-browser.js +247 -0
  128. package/folders.js +121 -0
  129. package/format.js +73 -0
  130. package/git-info.js +81 -0
  131. package/github-auth.js +62 -0
  132. package/html.js +10 -0
  133. package/icons.js +83 -0
  134. package/images-ai.js +447 -0
  135. package/images-create.js +226 -0
  136. package/images-page.js +417 -0
  137. package/images-records.js +39 -0
  138. package/images-render.js +36 -0
  139. package/images-svg-core.js +214 -0
  140. package/images-svg-sanitize.js +188 -0
  141. package/images-svg.js +241 -0
  142. package/images.js +270 -0
  143. package/jobs.js +430 -0
  144. package/linger.js +21 -0
  145. package/lists.js +292 -0
  146. package/media-info.js +136 -0
  147. package/navigation-page.js +264 -0
  148. package/navigation.js +394 -0
  149. package/notes.js +0 -0
  150. package/package.json +47 -4
  151. package/palette-index.js +46 -0
  152. package/playwright.config.js +23 -0
  153. package/plugin-install.js +239 -0
  154. package/plugin-loader.js +466 -0
  155. package/plugin-manifest.js +83 -0
  156. package/plugin-settings.js +44 -0
  157. package/plugins/workspace-notes/index.js +59 -0
  158. package/plugins-page.js +103 -0
  159. package/project-make.js +241 -0
  160. package/project-name.js +210 -0
  161. package/public/assistant-avatar-moves.js +646 -0
  162. package/public/assistant-avatar-ui.js +1223 -0
  163. package/public/assistant-avatar.js +530 -0
  164. package/public/avatar/druplicon.vrm +0 -0
  165. package/public/css/base.css +260 -0
  166. package/public/css/components/ai-assistant.css +263 -0
  167. package/public/css/components/assistant-avatar.css +279 -0
  168. package/public/css/components/assistant-views.css +198 -0
  169. package/public/css/components/build-order.css +74 -0
  170. package/public/css/components/clone-as-a-git-worktree.css +30 -0
  171. package/public/css/components/command-palette.css +61 -0
  172. package/public/css/components/commands-center.css +139 -0
  173. package/public/css/components/confirm-dialog.css +40 -0
  174. package/public/css/components/create-card.css +8 -0
  175. package/public/css/components/ddev-menu.css +23 -0
  176. package/public/css/components/deep-chat.css +17 -0
  177. package/public/css/components/density.css +11 -0
  178. package/public/css/components/floating-assistant-workspace-pages.css +55 -0
  179. package/public/css/components/folders.css +5 -0
  180. package/public/css/components/full-height-left-assistant-sidebar-all-pages.css +39 -0
  181. package/public/css/components/full-height-right-actions-rail-pages-that-have-actions.css +267 -0
  182. package/public/css/components/grid-and-list.css +203 -0
  183. package/public/css/components/help-page.css +36 -0
  184. package/public/css/components/hero.css +16 -0
  185. package/public/css/components/images.css +70 -0
  186. package/public/css/components/layout-rhythm-and-spacing-polish.css +139 -0
  187. package/public/css/components/mic-on-any-field-that-wants-typing.css +416 -0
  188. package/public/css/components/modal-fit.css +113 -0
  189. package/public/css/components/page-width.css +23 -0
  190. package/public/css/components/plugins-page.css +9 -0
  191. package/public/css/components/project-cards.css +256 -0
  192. package/public/css/components/project-rows.css +390 -0
  193. package/public/css/components/reordering-the-workspace-cards.css +85 -0
  194. package/public/css/components/responsive-home-and-the-workspace-pages.css +457 -0
  195. package/public/css/components/running-commands-as-toasts.css +327 -0
  196. package/public/css/components/settings-editor-core-config-yml.css +828 -0
  197. package/public/css/components/short-results-as-a-toast-at-the-top.css +203 -0
  198. package/public/css/components/sound-player.css +84 -0
  199. package/public/css/components/suggest-agents-skills-commands.css +112 -0
  200. package/public/css/components/tab-modal.css +142 -0
  201. package/public/css/components/terminals.css +244 -0
  202. package/public/css/components/test-report-media-one-file-per-row-paged.css +144 -0
  203. package/public/css/components/top-toolbar-logo-breadcrumb.css +107 -0
  204. package/public/css/components/video-edit.css +6 -0
  205. package/public/css/components/web-ide-open-with.css +23 -0
  206. package/public/css/components/working-indicators.css +158 -0
  207. package/public/css/components/workspace-cards.css +79 -0
  208. package/public/favicon.ico +0 -0
  209. package/public/favicon.png +0 -0
  210. package/public/htmx.min.js +1 -0
  211. package/public/logo.png +0 -0
  212. package/public/media-player.js +215 -0
  213. package/public/mic.js +255 -0
  214. package/public/narration.js +110 -0
  215. package/public/palette.js +278 -0
  216. package/public/sortable.js +251 -0
  217. package/public/suggest.js +337 -0
  218. package/public/terminal.js +903 -0
  219. package/public/themes/default/theme.css +267 -0
  220. package/public/themes/ember/theme.css +180 -0
  221. package/public/themes/press/theme.css +290 -0
  222. package/public/themes/slate/theme.css +182 -0
  223. package/public/touch-icon.png +0 -0
  224. package/public/ui.js +2721 -0
  225. package/public/vendor/ace/LICENSE.txt +24 -0
  226. package/public/vendor/ace/ace.js +23 -0
  227. package/public/vendor/ace/ext-language_tools.js +8 -0
  228. package/public/vendor/ace/ext-searchbox.js +8 -0
  229. package/public/vendor/ace/mode-css.js +8 -0
  230. package/public/vendor/ace/mode-html.js +8 -0
  231. package/public/vendor/ace/mode-javascript.js +8 -0
  232. package/public/vendor/ace/mode-markdown.js +8 -0
  233. package/public/vendor/ace/mode-sh.js +8 -0
  234. package/public/vendor/ace/mode-yaml.js +8 -0
  235. package/public/vendor/ace/theme-textmate.js +8 -0
  236. package/public/vendor/ace/theme-tomorrow_night.js +8 -0
  237. package/public/vendor/ace/worker-yaml.js +1 -0
  238. package/public/vendor/deep-chat.LICENSE +21 -0
  239. package/public/vendor/deep-chat.bundle.js +1 -0
  240. package/public/vendor/fonts/dm-serif-text-LICENSE.txt +93 -0
  241. package/public/vendor/fonts/dm-serif-text-latin-400-italic.woff2 +0 -0
  242. package/public/vendor/fonts/dm-serif-text-latin-400-normal.woff2 +0 -0
  243. package/public/vendor/fonts/figtree-LICENSE.txt +93 -0
  244. package/public/vendor/fonts/figtree-latin-400-italic.woff2 +0 -0
  245. package/public/vendor/fonts/figtree-latin-400-normal.woff2 +0 -0
  246. package/public/vendor/fonts/figtree-latin-600-italic.woff2 +0 -0
  247. package/public/vendor/fonts/figtree-latin-600-normal.woff2 +0 -0
  248. package/public/vendor/fonts/jetbrains-mono-LICENSE.txt +93 -0
  249. package/public/vendor/fonts/jetbrains-mono-latin-400-normal.woff2 +0 -0
  250. package/public/vendor/fonts/ubuntu-mono-LICENSE.txt +98 -0
  251. package/public/vendor/fonts/ubuntu-mono-latin-wght-normal.woff2 +0 -0
  252. package/public/vendor/tabler-LICENSE.txt +21 -0
  253. package/public/vendor/tabler-sprite.svg +1 -0
  254. package/public/vendor/three/LICENSE +21 -0
  255. package/public/vendor/three/addons/loaders/GLTFLoader.js +4860 -0
  256. package/public/vendor/three/addons/utils/BufferGeometryUtils.js +1501 -0
  257. package/public/vendor/three/addons/utils/SkeletonUtils.js +496 -0
  258. package/public/vendor/three/three.core.min.js +6 -0
  259. package/public/vendor/three/three.module.min.js +6 -0
  260. package/public/vendor/three-vrm/LICENSE +22 -0
  261. package/public/vendor/three-vrm/three-vrm.module.min.js +983 -0
  262. package/public/vendor/uikit-icons.min.js +1 -0
  263. package/public/vendor/uikit.min.css +1 -0
  264. package/public/vendor/uikit.min.js +1 -0
  265. package/public/vendor/webship-icons/ui/bookmark-outlined.svg +1 -0
  266. package/public/vendor/webship-icons/ui/headset.svg +1 -0
  267. package/public/vendor/webship-icons/ui/menu.svg +1 -0
  268. package/public/vendor/webship-icons/ui/pause.svg +1 -0
  269. package/public/vendor/webship-icons/ui/play.svg +1 -0
  270. package/public/vendor/webship-icons/ui/share.svg +1 -0
  271. package/public/vendor/webship-icons/ui/sound-off.svg +1 -0
  272. package/public/vendor/webship-icons/ui/sound-on.svg +1 -0
  273. package/public/vendor/webship-icons/ui/stop.svg +1 -0
  274. package/public/vendor/xterm/addon-fit.js +2 -0
  275. package/public/vendor/xterm/addon-unicode11.js +2 -0
  276. package/public/vendor/xterm/addon-web-links.js +2 -0
  277. package/public/vendor/xterm/xterm.css +218 -0
  278. package/public/vendor/xterm/xterm.js +2 -0
  279. package/rag.js +169 -0
  280. package/reader.js +132 -0
  281. package/repo-blobs.js +66 -0
  282. package/report-pdf.js +337 -0
  283. package/row-layout.js +1439 -0
  284. package/screenrc +37 -0
  285. package/screens.js +1063 -0
  286. package/scripts/code-server-start.sh +190 -0
  287. package/scripts/images-claude-finish.js +107 -0
  288. package/scripts/screen-host.sh +114 -0
  289. package/scripts/screen-runner.js +362 -0
  290. package/scripts/screen-then.js +47 -0
  291. package/scripts/update.sh +350 -0
  292. package/server.js +7923 -0
  293. package/settings-file.js +423 -0
  294. package/speech.js +297 -0
  295. package/tab-modal.js +75 -0
  296. package/test-reports.js +260 -0
  297. package/themes.js +381 -0
  298. package/transcripts.js +168 -0
  299. package/urls.js +13 -0
  300. package/validate.js +18 -0
  301. package/version-check.js +94 -0
  302. package/video-edit.js +588 -0
  303. package/waiting.js +85 -0
  304. package/workspace-card-tools.js +41 -0
  305. package/workspace-delete.js +139 -0
  306. package/workspace-types.js +85 -0
  307. package/workspaces.js +553 -0
@@ -0,0 +1,203 @@
1
+ /* ---------- Short results, as a toast at the top ---------- */
2
+
3
+ .flash-toasts {
4
+ position: fixed;
5
+ top: 4.25rem; /* clear of the toolbar */
6
+ left: 50%;
7
+ transform: translateX(-50%);
8
+ z-index: 1015; /* over the rails and the job stack */
9
+ display: flex;
10
+ flex-direction: column;
11
+ gap: 0.375rem;
12
+ /* 40rem wrapped a single sentence onto eight lines on a wide screen, which made a
13
+ transient result look like a message block demanding attention. A toast is read at a
14
+ glance or not at all, so it gets the width to be one or two lines — still bounded, so
15
+ it never spans a 2500px display end to end. */
16
+ width: min(64rem, calc(100vw - 3rem));
17
+ pointer-events: none;
18
+ }
19
+
20
+ .flash-toasts > * { pointer-events: auto; }
21
+
22
+ /* An alert, not a terminal: an icon says what happened before the sentence is read, the tint
23
+ carries it at a glance, and a countdown bar shows it is going to leave on its own. Deliberately
24
+ unlike the job toasts at the bottom, which are output to watch rather than a result to read. */
25
+ .flash-toast {
26
+ margin: 0 !important;
27
+ position: relative;
28
+ display: flex;
29
+ align-items: flex-start;
30
+ gap: 0.625rem;
31
+ padding: 0.75rem 2.25rem 0.75rem 0.875rem !important;
32
+ /* A pale tint on a pale page needs a stated edge, not a hint of one: the 1px pale-green hairline
33
+ disappeared against the toolbar and the card behind it, so the toast read as floating text.
34
+ A 2px border in the status colour plus a ring and a deeper shadow give it a definite edge in
35
+ both themes. */
36
+ border: 2px solid var(--ok);
37
+ border-left-width: 4px;
38
+ border-radius: 0.5rem;
39
+ background: var(--ok-soft) !important;
40
+ color: var(--ok-ink) !important;
41
+ box-shadow: 0 0 0 1px var(--toast-ring), var(--shadow-toast);
42
+ overflow: hidden;
43
+ animation: flash-in .18s ease-out;
44
+ }
45
+
46
+ /* The mark, sized so a one-line and a three-line message both look deliberate. */
47
+ .flash-toast::before {
48
+ content: '✓';
49
+ flex: 0 0 1.25rem;
50
+ width: 1.25rem;
51
+ height: 1.25rem;
52
+ margin-top: 0.0625rem;
53
+ border-radius: 50%;
54
+ background: var(--ok);
55
+ color: var(--text-inverse);
56
+ font-size: 0.78rem;
57
+ line-height: 1.25rem;
58
+ text-align: center;
59
+ font-weight: 700;
60
+ }
61
+
62
+ .flash-toast.error {
63
+ border-color: var(--danger);
64
+ background: var(--danger-soft) !important;
65
+ color: var(--danger-ink) !important;
66
+ }
67
+
68
+ .flash-toast.error::before { content: '!'; background: var(--danger); }
69
+
70
+ /* How long it has left. Pauses with the timer when the pointer is over it. */
71
+ .flash-toast::after {
72
+ content: '';
73
+ position: absolute;
74
+ left: 0;
75
+ bottom: 0;
76
+ height: 2px;
77
+ width: 100%;
78
+ background: var(--ok);
79
+ opacity: .55;
80
+ transform-origin: left;
81
+ animation: flash-countdown var(--flash-ms, 6000ms) linear forwards;
82
+ }
83
+
84
+ .flash-toast.error::after { background: var(--danger); }
85
+ .flash-toast.is-held::after { animation-play-state: paused; }
86
+
87
+ @keyframes flash-countdown {
88
+ from { transform: scaleX(1); }
89
+ to { transform: scaleX(0); }
90
+ }
91
+
92
+ .flash-toast-close {
93
+ position: absolute;
94
+ top: 0.375rem;
95
+ right: 0.5rem;
96
+ background: none;
97
+ border: 0;
98
+ padding: 0.125rem;
99
+ cursor: pointer;
100
+ color: inherit;
101
+ opacity: .6;
102
+ line-height: 1;
103
+ }
104
+
105
+ .flash-toast-close:hover { opacity: 1; }
106
+
107
+ @keyframes flash-in {
108
+ from { opacity: 0; transform: translateY(-0.375rem); }
109
+ to { opacity: 1; transform: none; }
110
+ }
111
+
112
+ @media (max-width: 47.9375em) {
113
+ .flash-toasts { top: 3.5rem; width: calc(100vw - 1rem); }
114
+ }
115
+
116
+ /* The machine name beside the readable one: still needed — it is what you invoke, and what
117
+ --fetch and --install take — but secondary to the name a person reads. */
118
+ .item-machine {
119
+ font-family: var(--font-code);
120
+ font-size: 0.72rem;
121
+ font-weight: 400;
122
+ /* No opacity: .uk-text-meta is already the quiet colour, and fading it again took this 11px code
123
+ name to 4.08:1 — under AA, on the one string you have to read character by character to type it.
124
+ Secondary is said by the size and the monospace, which is what the eye reads here anyway. */
125
+ }
126
+
127
+ /* The controls read as three jobs, not eight widgets: find it, order it, narrow it. One bar, with
128
+ a hairline between the groups — before this the search field, two buttons, a checkbox, a sort
129
+ and a state filter sat in one undifferentiated row. */
130
+ .list-controls {
131
+ border: 1px solid var(--line);
132
+ border-radius: 0.5rem;
133
+ padding: 0.5rem 0.625rem;
134
+ background: var(--surface);
135
+ gap: 0;
136
+ }
137
+
138
+ .list-controls { flex-wrap: wrap; row-gap: 0.5rem; }
139
+
140
+ .lc-group {
141
+ display: flex;
142
+ align-items: center;
143
+ /* A group never breaks internally: Reset and Auto belong beside the field they act on. The BAR
144
+ wraps between groups instead, which is why the search field can shrink but the buttons cannot
145
+ be orphaned onto their own line. */
146
+ flex-wrap: nowrap;
147
+ gap: 0.375rem;
148
+ padding: 0 0.625rem;
149
+ border-left: 1px solid var(--line);
150
+ }
151
+
152
+ .lc-group:first-child { padding-left: 0; border-left: 0; }
153
+
154
+ /* The find row owns a line of its own — field, Search, Reset, in that order, with the field
155
+ absorbing the slack. Sort, the filters and the auto-search preference sit on the line below,
156
+ where they do not compete with it for width. */
157
+ .lc-find { flex: 1 1 100%; min-width: 0; }
158
+
159
+ .lc-rest {
160
+ display: flex;
161
+ align-items: center;
162
+ flex-wrap: wrap;
163
+ gap: 0;
164
+ row-gap: 0.5rem;
165
+ flex: 1 1 100%;
166
+ }
167
+
168
+ .lc-rest .lc-group:first-child { padding-left: 0; border-left: 0; }
169
+
170
+ /* Whether the dividers make sense depends on the width of the LIST, not of the window: the
171
+ assistant rail takes 400px, so a 1250px window leaves this bar about 630px and the groups
172
+ already stack. A container query asks the right question. */
173
+ #webship-workspace-projects,
174
+ #webship-workspace-backups { container-type: inline-size; }
175
+
176
+ @container (max-width: 44rem) {
177
+ .lc-group { border-left: 0; padding: 0; }
178
+ /* Without the dividers the groups need their own gap to stay apart. */
179
+ .lc-rest { gap: 0.75rem; }
180
+ }
181
+
182
+ /* No container support: fall back to the window, erring towards stacked. */
183
+ @supports not (container-type: inline-size) {
184
+ @media (max-width: 74.9375em) {
185
+ .lc-group { border-left: 0; padding: 0; }
186
+ }
187
+ }
188
+
189
+ /* The head's buttons stay clickable over the top grips that run beneath them. */
190
+ .job-toast-btn { position: relative; z-index: 4; }
191
+
192
+ /* The row reads name → what it is called and its state → what it does. The machine name, the
193
+ timestamp and the labels used to trail the readable name on one line, where the name a person
194
+ looks for was the shortest thing on a long line of small print. */
195
+ .item-meta-line {
196
+ display: flex;
197
+ align-items: center;
198
+ flex-wrap: wrap;
199
+ gap: 0.375rem;
200
+ margin-top: 0.125rem;
201
+ }
202
+
203
+ .item-meta-line .uk-label { line-height: 1.4; }
@@ -0,0 +1,84 @@
1
+ /* The sound player in the editor modal: the browser's own audio controls, then speed and loop. */
2
+ .sound-player {
3
+ display: block;
4
+ width: 100%;
5
+ margin-top: 0.5rem;
6
+ }
7
+ .sound-loop {
8
+ display: inline-flex;
9
+ align-items: center;
10
+ gap: 0.375rem;
11
+ }
12
+
13
+ /* Generate a voice: one row per engine, its options below. */
14
+ .voice-engines { display: grid; gap: 0.5rem; margin-bottom: 0.75rem; }
15
+ .voice-engine { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.5rem; }
16
+ .voice-engine.is-off { opacity: 0.65; }
17
+
18
+ /* A voiceover script under its video: the words, a section at a time. */
19
+ .transcript-details { margin-top: 0.75rem; }
20
+ .transcript-details > summary { cursor: pointer; font-weight: 600; }
21
+ .transcript-body { max-height: 40vh; overflow: auto; padding-right: 0.5rem; }
22
+ .transcript-section h5 { margin: 0.75rem 0 0.25rem; display: flex; gap: 0.5rem; align-items: baseline; }
23
+ .transcript-section p { margin: 0 0 0.35rem; }
24
+ .transcript-section p.is-optional { font-style: italic; opacity: 0.8; }
25
+ .transcript-time, .transcript-seek { font-variant-numeric: tabular-nums; font-size: 0.8rem; }
26
+ .transcript-seek {
27
+ border: 1px solid var(--brand-primary); background: transparent; color: var(--brand-primary);
28
+ border-radius: 500px; padding: 0 0.5rem; cursor: pointer;
29
+ }
30
+ .transcript-seek:hover { background: var(--brand-primary); color: var(--text-inverse); }
31
+
32
+ /* How a sound was made: a line of facts above its text. */
33
+ .sound-record { display: flex; flex-wrap: wrap; gap: 0.25rem 1rem; margin: 0 0 0.5rem; }
34
+ .sound-fact .uk-text-meta { margin-right: 0.25rem; }
35
+
36
+ /* Every quarter step of speed, wrapping rather than scrolling. */
37
+
38
+
39
+ /* The player: a dark stage, then the controls a streaming site has, in one quiet row. */
40
+ .media-card .media-stage { background: var(--brand-dark); border-radius: 0.6rem; overflow: hidden; }
41
+ .media-card .media-stage .video-player { border-radius: 0; max-height: 62vh; }
42
+ .media-card .media-stage.is-sound { background: linear-gradient(135deg, var(--subtle-brand), var(--subtle-accent)); padding: 1rem; }
43
+ .media-card .media-stage.is-sound .sound-player { margin: 0; }
44
+ .media-meta { margin-bottom: 0.5rem; }
45
+ .player-controls { display: flex; flex-wrap: wrap; align-items: center; gap: 0.75rem; margin: 0.6rem 0 0.25rem; }
46
+ .player-nav { margin-left: auto; display: inline-flex; gap: 0.25rem; }
47
+ .player-keys { flex-basis: 100%; font-size: 0.72rem; }
48
+ .speed-menu .uk-dropdown { padding: 0.6rem; width: 21rem; }
49
+ .sound-speeds { display: flex; flex-wrap: wrap; gap: 0.25rem; }
50
+ .sound-speeds .uk-button { padding: 0 0.6rem; }
51
+ .sound-speeds .uk-button.is-active { background: var(--brand-primary); border-color: var(--brand-primary); color: var(--text-inverse); }
52
+ .chapter-bar { display: flex; gap: 3px; height: 0.5rem; margin: 0.5rem 0 0.25rem; }
53
+ .chapter-bar:empty { display: none; }
54
+ .chapter-seg {
55
+ flex: 1 1 0; min-width: 4px; border: 0; padding: 0; border-radius: 2px; cursor: pointer;
56
+ background: color-mix(in srgb, var(--brand-primary) 18%, var(--surface-muted)); transition: height 0.12s;
57
+ }
58
+ .chapter-seg.is-past { background: color-mix(in srgb, var(--brand-primary) 55%, transparent); }
59
+ .chapter-seg.is-current { background: var(--brand-primary); }
60
+ .chapter-seg:hover { height: 0.75rem; margin-top: -0.125rem; }
61
+ .player-chapter { font-weight: 600; margin: 0 0 0.25rem; }
62
+ .transcript-section.is-current { background: var(--subtle-brand); border-radius: 0.3rem; box-shadow: -3px 0 0 var(--brand-primary); padding: 0.1rem 0.5rem; }
63
+
64
+ /* A card, the way a streaming site draws it: the length in a corner, CC when there are words, a preview. */
65
+ .fx-thumb { position: relative; }
66
+ .fx-duration, .fx-cc {
67
+ position: absolute; bottom: 0.4rem; z-index: 2; background: color-mix(in srgb, var(--brand-dark) 78%, transparent); color: var(--text-inverse);
68
+ font-size: 0.72rem; font-weight: 600; line-height: 1.45; padding: 0 0.4rem; border-radius: 0.25rem;
69
+ font-variant-numeric: tabular-nums;
70
+ }
71
+ .fx-duration { right: 0.4rem; }
72
+ .fx-cc { left: 0.4rem; letter-spacing: 0.04em; }
73
+ .fx-thumb .fx-play { z-index: 1; transition: opacity 0.2s; }
74
+ .fx-preview { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0; transition: opacity 0.25s; z-index: 1; }
75
+ .fx-thumb.is-previewing .fx-preview { opacity: 1; }
76
+ .fx-thumb.is-previewing .fx-play { opacity: 0; }
77
+
78
+ /* Generating, inside the modal: working, ready, or not made. */
79
+ .voice-progress p, .voice-done p, .voice-failed p { margin: 0 0 0.4rem; }
80
+ .voice-log {
81
+ margin: 0.25rem 0 0.5rem; padding: 0.5rem 0.75rem; max-height: 8rem; overflow: auto; white-space: pre-wrap;
82
+ background: var(--surface-muted); border-radius: 0.4rem; font-family: var(--font-code); font-size: 0.75rem;
83
+ }
84
+ .voice-done .sound-player, .voice-done .video-player { width: 100%; margin: 0.5rem 0; }
@@ -0,0 +1,112 @@
1
+ /* The "@" / "/" suggestion popup.
2
+ *
3
+ * Painted with the theme tokens only — the palette has no attention colour, and the rule
4
+ * in CLAUDE.md is to paint with the tokens rather than introduce a hex. So the active row
5
+ * is the brand fill it already has, and everything else is surface, line and text.
6
+ *
7
+ * On <body> and positioned by script, because the composer's field lives inside
8
+ * deep-chat's shadow root: a popup rendered there inherits that component's overflow and
9
+ * stacking, and gets clipped by the panel. z-index sits above the modal backdrop so the
10
+ * list still works in the New screen dialog. */
11
+
12
+ .ws-suggest {
13
+ position: fixed;
14
+ z-index: 1030; /* above UIKit's modal (1010) and its dialog */
15
+ overflow-y: auto;
16
+ overscroll-behavior: contain;
17
+ background: var(--surface-card);
18
+ color: var(--text-default);
19
+ border: 1px solid var(--line);
20
+ border-radius: 12px;
21
+ box-shadow: var(--shadow-float);
22
+ padding: 4px;
23
+ font-size: .8125rem;
24
+ line-height: 1.35;
25
+ }
26
+
27
+ .ws-suggest[hidden] { display: none !important; }
28
+
29
+ .ws-suggest-row {
30
+ display: grid;
31
+ grid-template-columns: 1.25rem minmax(0, auto) auto 1fr;
32
+ grid-template-areas:
33
+ 'icon name kind where'
34
+ '. desc desc desc';
35
+ gap: 1px .5rem;
36
+ align-items: baseline;
37
+ padding: .375rem .5rem;
38
+ border-radius: 8px;
39
+ cursor: pointer;
40
+ }
41
+
42
+ .ws-suggest-row + .ws-suggest-row { margin-top: 1px; }
43
+
44
+ /* The sprite's own stroke and colour come from .tabler-icon in base.css; this only has
45
+ * to sit the glyph on the text baseline it shares with the name. */
46
+ .ws-suggest-icon {
47
+ grid-area: icon;
48
+ display: inline-flex;
49
+ align-items: center;
50
+ justify-content: center;
51
+ height: 1.1em;
52
+ }
53
+
54
+ .ws-suggest-icon .tabler-icon { color: var(--brand-primary); }
55
+ .ws-suggest-row.is-active .ws-suggest-icon .tabler-icon { color: var(--text-inverse); }
56
+
57
+ /* The name is what is being chosen, so it is never truncated: a 47-character name cut
58
+ * to "upsun-webship-sandbox-1-play…" is indistinguishable from its siblings. It wraps
59
+ * instead, which costs a second line only on the few names that long. */
60
+ .ws-suggest-name {
61
+ grid-area: name;
62
+ font-family: var(--font-code, ui-monospace, monospace);
63
+ font-weight: 600;
64
+ overflow-wrap: anywhere;
65
+ }
66
+
67
+ .ws-suggest-kind {
68
+ grid-area: kind;
69
+ font-size: .6875rem;
70
+ text-transform: uppercase;
71
+ letter-spacing: .04em;
72
+ color: var(--text-subtle);
73
+ }
74
+
75
+ .ws-suggest-where {
76
+ grid-area: where;
77
+ justify-self: end;
78
+ font-size: .6875rem;
79
+ color: var(--text-subtle);
80
+ white-space: nowrap;
81
+ }
82
+
83
+ /* Two lines at most: a Claude Code description is a paragraph written for a model to
84
+ * choose on, and the whole list has to stay scannable. The full text is the title. */
85
+ .ws-suggest-desc {
86
+ grid-area: desc;
87
+ color: var(--text-subtle);
88
+ display: -webkit-box;
89
+ -webkit-line-clamp: 2;
90
+ -webkit-box-orient: vertical;
91
+ overflow: hidden;
92
+ }
93
+
94
+ .ws-suggest-row.is-active {
95
+ background: var(--brand-primary);
96
+ color: var(--text-inverse);
97
+ }
98
+
99
+ .ws-suggest-row.is-active .ws-suggest-kind,
100
+ .ws-suggest-row.is-active .ws-suggest-where,
101
+ .ws-suggest-row.is-active .ws-suggest-desc { color: var(--text-inverse); }
102
+
103
+ @media (max-width: 47.9375em) {
104
+ /* A phone has no room for the provenance column, and the description is what tells
105
+ * two similarly named skills apart — so the label goes, not the sentence. */
106
+ .ws-suggest-where { display: none; }
107
+ .ws-suggest-row { grid-template-columns: 1.25rem minmax(0, auto) auto; }
108
+ }
109
+
110
+ @media (prefers-reduced-motion: reduce) {
111
+ .ws-suggest { scroll-behavior: auto; }
112
+ }
@@ -0,0 +1,142 @@
1
+ /* ---------- A modal with its sections as tabs down the left ---------- */
2
+
3
+ /* The dialog gives the tabs the width and the height; the body hands over its padding so the column
4
+ runs edge to edge and the two halves scroll on their own. */
5
+ #editor-modal .uk-modal-dialog:has(.tabmodal) { width: min(94vw, 70rem); }
6
+ #editor-modal .uk-modal-body:has(.tabmodal) {
7
+ display: flex;
8
+ padding: 0;
9
+ overflow: hidden;
10
+ }
11
+
12
+ .tabmodal {
13
+ flex: 1 1 auto;
14
+ display: grid;
15
+ grid-template-columns: 15.5rem minmax(0, 1fr);
16
+ min-height: 0;
17
+ height: min(46rem, calc(100dvh - 9rem));
18
+ }
19
+
20
+ .tabmodal-nav {
21
+ display: flex;
22
+ flex-direction: column;
23
+ min-height: 0;
24
+ padding: 1.125rem 0.75rem 0.75rem;
25
+ background: var(--surface);
26
+ border-right: 1px solid var(--line);
27
+ }
28
+ .tabmodal-title { padding: 0 0.625rem 0.5rem; }
29
+ .tabmodal-title h2 { margin: 0; font-size: 1.0625rem; line-height: 1.3; }
30
+ .tabmodal-filter.uk-input { flex: none; height: 2.25rem; margin: 0 0 0.5rem; padding: 0 0.75rem; border-radius: 0.5rem; font-size: 0.875rem; }
31
+ .tabmodal-tabs { flex: 1 1 auto; min-height: 0; overflow-y: auto; scrollbar-width: thin; padding-bottom: 0.5rem; }
32
+ .tabmodal-group + .tabmodal-group { margin-top: 0.875rem; }
33
+ .tabmodal-group[hidden] { display: none; }
34
+ .tabmodal-group-label {
35
+ margin: 0 0 0.25rem;
36
+ padding: 0 0.625rem;
37
+ font-size: 0.6875rem;
38
+ font-weight: 700;
39
+ letter-spacing: 0.06em;
40
+ text-transform: uppercase;
41
+ color: var(--text-subtle);
42
+ }
43
+
44
+ .tabmodal-back {
45
+ align-self: flex-start;
46
+ margin: 0 0 0.5rem;
47
+ padding: 0.25rem 0.625rem;
48
+ border: 0;
49
+ border-radius: 0.5rem;
50
+ background: transparent;
51
+ color: var(--text-subtle);
52
+ font: inherit;
53
+ font-size: 0.8125rem;
54
+ cursor: pointer;
55
+ }
56
+ .tabmodal-back:hover { background: var(--subtle-brand); color: var(--link); }
57
+
58
+ .tabmodal-tab {
59
+ display: flex;
60
+ align-items: center;
61
+ gap: 0.625rem;
62
+ width: 100%;
63
+ min-height: 2.25rem;
64
+ margin: 0 0 0.125rem;
65
+ padding: 0.25rem 0.625rem;
66
+ border: 0;
67
+ border-radius: 0.5rem;
68
+ background: transparent;
69
+ color: var(--text-default);
70
+ font: inherit;
71
+ font-size: 0.875rem;
72
+ text-align: left;
73
+ cursor: pointer;
74
+ }
75
+ .tabmodal-tab[hidden] { display: none; }
76
+ .tabmodal-tab .tabler-icon { flex: none; color: var(--text-subtle); }
77
+ .tabmodal-tab-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
78
+ .tabmodal-tab:hover { background: color-mix(in srgb, var(--text-subtle) 12%, transparent); }
79
+ .tabmodal-tab.is-selected { background: var(--subtle-brand); color: var(--link); font-weight: 600; }
80
+ .tabmodal-tab.is-selected .tabler-icon { color: var(--link); }
81
+ .tabmodal-tab:focus-visible { outline: 2px solid var(--brand-primary); outline-offset: -2px; }
82
+ .tabmodal-badge {
83
+ flex: none;
84
+ min-width: 1.25rem;
85
+ padding: 0 0.375rem;
86
+ border-radius: 999px;
87
+ background: var(--line);
88
+ color: var(--text-default);
89
+ font-size: 0.75rem;
90
+ line-height: 1.25rem;
91
+ text-align: center;
92
+ }
93
+
94
+ .tabmodal-main { display: flex; flex-direction: column; min-width: 0; min-height: 0; }
95
+ .tabmodal-head {
96
+ flex: none;
97
+ padding: 1.125rem 3rem 0.75rem 1.5rem;
98
+ border-bottom: 1px solid var(--line);
99
+ }
100
+ .tabmodal-heading { margin: 0; font-size: 1.125rem; line-height: 1.3; }
101
+ .tabmodal-sub { display: block; min-height: 1.25rem; }
102
+ .tabmodal-pane { flex: 1 1 auto; min-height: 0; overflow-x: hidden; overflow-y: auto; padding: 1.25rem 1.5rem 0; overscroll-behavior: contain; }
103
+ .tabmodal-pane::after { content: ""; display: block; height: 1.5rem; }
104
+ .tabmodal-pane:focus-visible { outline: 2px solid var(--brand-primary); outline-offset: -2px; }
105
+
106
+ /* A form that pins its own actions runs to the foot of the pane, and its title is the pane's heading. */
107
+ .tabmodal-pane .modal-head { position: static; margin: 0 0 1rem; padding: 0 0 0.75rem; border-bottom: 0; }
108
+ .tabmodal-pane .modal-head > h3:first-child { display: none; }
109
+
110
+ /* A page that was written to fill a page does not need its own frame inside a pane. */
111
+ .tabmodal-pane .settings-back { display: none; }
112
+ .tabmodal-pane .editor-card,
113
+ .tabmodal-pane .uk-card-default { box-shadow: none; border: 0; padding: 0; background: transparent; }
114
+ .tabmodal-pane .uk-card-body { padding: 0; }
115
+ /* The pinned save bar was written for the modal body's padding; the pane's is a little smaller. */
116
+ .tabmodal-pane form > :last-child:has(button[type="submit"]),
117
+ .tabmodal-pane .nav-save,
118
+ .tabmodal-pane .modal-actions { margin-inline: -1.5rem; padding-inline: 1.5rem; }
119
+
120
+ @media (max-width: 59.9375em) {
121
+ .tabmodal { grid-template-columns: 1fr; grid-template-rows: auto minmax(0, 1fr); }
122
+ .tabmodal-nav { max-height: 11rem; border-right: 0; border-bottom: 1px solid var(--line); }
123
+ }
124
+
125
+ /* ---------- The editor modal's own frame, for every modal ---------- */
126
+
127
+ #editor-modal .uk-modal-dialog { border-radius: 0.875rem; overflow: hidden; }
128
+ #editor-modal .uk-modal-close-default {
129
+ top: 0.75rem;
130
+ right: 0.75rem;
131
+ width: 2rem;
132
+ height: 2rem;
133
+ padding: 0;
134
+ display: flex;
135
+ align-items: center;
136
+ justify-content: center;
137
+ border-radius: 0.5rem;
138
+ z-index: 6;
139
+ }
140
+ #editor-modal .uk-modal-close-default:hover { background: color-mix(in srgb, var(--text-subtle) 14%, transparent); }
141
+ #editor-modal .uk-modal-close-default:focus-visible { outline: 2px solid var(--brand-primary); outline-offset: 2px; }
142
+