@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.
- package/PLUGINS.md +249 -0
- package/README.md +379 -2
- package/WORKSPACES.md +69 -0
- package/actions/ai-items.js +293 -0
- package/actions/audio.js +48 -0
- package/actions/build-order.js +79 -0
- package/actions/checks.js +95 -0
- package/actions/claude-session.js +104 -0
- package/actions/commands-center.js +258 -0
- package/actions/composer.js +267 -0
- package/actions/ddev-addons.js +90 -0
- package/actions/ddev-mail.js +80 -0
- package/actions/ddev.js +237 -0
- package/actions/folders.js +165 -0
- package/actions/images-svg.js +33 -0
- package/actions/images.js +145 -0
- package/actions/navigation.js +190 -0
- package/actions/node.js +222 -0
- package/actions/notes.js +55 -0
- package/actions/plugins.js +36 -0
- package/actions/project-make.js +28 -0
- package/actions/rag.js +202 -0
- package/actions/row-actions.js +262 -0
- package/actions/screens.js +270 -0
- package/actions/testing.js +121 -0
- package/actions/video-edit.js +54 -0
- package/ai-inventory.js +182 -0
- package/ai-items.js +202 -0
- package/assistant-cast.js +176 -0
- package/assistant-suggestions.js +91 -0
- package/assistant.js +484 -0
- package/audio-voice.js +528 -0
- package/auth-google.js +260 -0
- package/build-ai.js +52 -0
- package/build-order-page.js +191 -0
- package/build-order.js +313 -0
- package/builder-args.js +117 -0
- package/changelog.js +302 -0
- package/chat-threads.js +134 -0
- package/checks.js +105 -0
- package/claude-args.js +282 -0
- package/claude-sessions.js +129 -0
- package/command-author.js +117 -0
- package/command-block.js +20 -0
- package/commands/defaults.yml +159 -0
- package/commands-page.js +460 -0
- package/commands.js +568 -0
- package/cucumber.js +43 -0
- package/ddev-addons-page.js +124 -0
- package/ddev-addons.js +154 -0
- package/ddev-custom-commands.js +96 -0
- package/ddev-domains.js +84 -0
- package/ddev-import.js +93 -0
- package/ddev-mail-page.js +167 -0
- package/ddev-mail.js +110 -0
- package/ddev-options.js +145 -0
- package/ddev-snapshots.js +126 -0
- package/ddev.js +145 -0
- package/docs/DEVELOPER-GUIDE.md +224 -0
- package/docs/README.md +252 -0
- package/docs/REFERENCE.md +684 -0
- package/docs/USER-GUIDE.md +697 -0
- package/docs/screenshots/assistant/avatar-board.png +0 -0
- package/docs/screenshots/assistant/avatar-coffee.png +0 -0
- package/docs/screenshots/assistant/avatar-colours.png +0 -0
- package/docs/screenshots/assistant/avatar-icons.png +0 -0
- package/docs/screenshots/assistant/avatar-moves.png +0 -0
- package/docs/screenshots/assistant/avatar-pick-cookieman.png +0 -0
- package/docs/screenshots/assistant/avatar-settings-voices.png +0 -0
- package/docs/screenshots/assistant/avatar-status.png +0 -0
- package/docs/screenshots/create-card/create-card.png +0 -0
- package/docs/screenshots/create-card/start-ai.png +0 -0
- package/docs/screenshots/guide-clone-address.png +0 -0
- package/docs/screenshots/guide-clone-worktree-off.png +0 -0
- package/docs/screenshots/guide-clone-worktree-on.png +0 -0
- package/docs/screenshots/guide-ddev-menu.png +0 -0
- package/docs/screenshots/guide-domains.png +0 -0
- package/docs/screenshots/guide-home.png +0 -0
- package/docs/screenshots/guide-ide-menu.png +0 -0
- package/docs/screenshots/guide-remove-refusal.png +0 -0
- package/docs/screenshots/guide-rows-worktree.png +0 -0
- package/docs/screenshots/guide-screens.png +0 -0
- package/docs/screenshots/guide-settings.png +0 -0
- package/docs/screenshots/guide-workspace-page.png +0 -0
- package/docs/screenshots/home/card-settings.png +0 -0
- package/docs/screenshots/home/drag-reorder.png +0 -0
- package/docs/screenshots/home/edit-card.png +0 -0
- package/docs/screenshots/images/claude-code-image.png +0 -0
- package/docs/screenshots/images/edit-with-ai.png +0 -0
- package/docs/screenshots/images/gallery.png +0 -0
- package/docs/screenshots/images/generate-description.png +0 -0
- package/docs/screenshots/images/generate-plan.png +0 -0
- package/docs/screenshots/images/providers.png +0 -0
- package/docs/screenshots/images/svg-form.png +0 -0
- package/docs/screenshots/images/svg-result.png +0 -0
- package/docs/screenshots/images/upload.png +0 -0
- package/docs/screenshots/new-folder/2-form.png +0 -0
- package/docs/screenshots/new-folder/8-ddev-options.png +0 -0
- package/docs/screenshots/new-folder/files-folder.png +0 -0
- package/docs/screenshots/projects/ddev-custom-commands.png +0 -0
- package/docs/screenshots/projects/state-chip-stop.png +0 -0
- package/docs/screenshots/readme/dashboard-dark.png +0 -0
- package/docs/screenshots/readme/dashboard-light.png +0 -0
- package/docs/screenshots/readme/dev-dark.png +0 -0
- package/docs/screenshots/readme/dev-light.png +0 -0
- package/docs/screenshots/readme/docs-dark.png +0 -0
- package/docs/screenshots/readme/docs-light.png +0 -0
- package/docs/screenshots/readme/icons/ai.svg +4 -0
- package/docs/screenshots/readme/icons/code.svg +4 -0
- package/docs/screenshots/readme/icons/docs.svg +4 -0
- package/docs/screenshots/readme/icons/services.svg +4 -0
- package/docs/screenshots/readme/icons/sites.svg +4 -0
- package/docs/screenshots/readme/test-report-dark.png +0 -0
- package/docs/screenshots/readme/test-report-light.png +0 -0
- package/docs/screenshots/readme/test-scenarios.png +0 -0
- package/docs/screenshots/readme/test-steps.png +0 -0
- package/docs/screenshots/readme/videos-dark.png +0 -0
- package/docs/screenshots/readme/videos-light.png +0 -0
- package/docs/screenshots/screens-menu.png +0 -0
- package/docs/screenshots/screens-new.png +0 -0
- package/docs/screenshots/settings/auth-google-lists.png +0 -0
- package/docs/screenshots/settings/delete-1-row.png +0 -0
- package/docs/screenshots/settings/delete-2-confirm.png +0 -0
- package/docs/screenshots/settings/delete-3-type-name.png +0 -0
- package/docs/screenshots/settings/delete-4-type-yes.png +0 -0
- package/event-log.js +59 -0
- package/files-browser.js +247 -0
- package/folders.js +121 -0
- package/format.js +73 -0
- package/git-info.js +81 -0
- package/github-auth.js +62 -0
- package/html.js +10 -0
- package/icons.js +83 -0
- package/images-ai.js +447 -0
- package/images-create.js +226 -0
- package/images-page.js +417 -0
- package/images-records.js +39 -0
- package/images-render.js +36 -0
- package/images-svg-core.js +214 -0
- package/images-svg-sanitize.js +188 -0
- package/images-svg.js +241 -0
- package/images.js +270 -0
- package/jobs.js +430 -0
- package/linger.js +21 -0
- package/lists.js +292 -0
- package/media-info.js +136 -0
- package/navigation-page.js +264 -0
- package/navigation.js +394 -0
- package/notes.js +0 -0
- package/package.json +47 -4
- package/palette-index.js +46 -0
- package/playwright.config.js +23 -0
- package/plugin-install.js +239 -0
- package/plugin-loader.js +466 -0
- package/plugin-manifest.js +83 -0
- package/plugin-settings.js +44 -0
- package/plugins/workspace-notes/index.js +59 -0
- package/plugins-page.js +103 -0
- package/project-make.js +241 -0
- package/project-name.js +210 -0
- package/public/assistant-avatar-moves.js +646 -0
- package/public/assistant-avatar-ui.js +1223 -0
- package/public/assistant-avatar.js +530 -0
- package/public/avatar/druplicon.vrm +0 -0
- package/public/css/base.css +260 -0
- package/public/css/components/ai-assistant.css +263 -0
- package/public/css/components/assistant-avatar.css +279 -0
- package/public/css/components/assistant-views.css +198 -0
- package/public/css/components/build-order.css +74 -0
- package/public/css/components/clone-as-a-git-worktree.css +30 -0
- package/public/css/components/command-palette.css +61 -0
- package/public/css/components/commands-center.css +139 -0
- package/public/css/components/confirm-dialog.css +40 -0
- package/public/css/components/create-card.css +8 -0
- package/public/css/components/ddev-menu.css +23 -0
- package/public/css/components/deep-chat.css +17 -0
- package/public/css/components/density.css +11 -0
- package/public/css/components/floating-assistant-workspace-pages.css +55 -0
- package/public/css/components/folders.css +5 -0
- package/public/css/components/full-height-left-assistant-sidebar-all-pages.css +39 -0
- package/public/css/components/full-height-right-actions-rail-pages-that-have-actions.css +267 -0
- package/public/css/components/grid-and-list.css +203 -0
- package/public/css/components/help-page.css +36 -0
- package/public/css/components/hero.css +16 -0
- package/public/css/components/images.css +70 -0
- package/public/css/components/layout-rhythm-and-spacing-polish.css +139 -0
- package/public/css/components/mic-on-any-field-that-wants-typing.css +416 -0
- package/public/css/components/modal-fit.css +113 -0
- package/public/css/components/page-width.css +23 -0
- package/public/css/components/plugins-page.css +9 -0
- package/public/css/components/project-cards.css +256 -0
- package/public/css/components/project-rows.css +390 -0
- package/public/css/components/reordering-the-workspace-cards.css +85 -0
- package/public/css/components/responsive-home-and-the-workspace-pages.css +457 -0
- package/public/css/components/running-commands-as-toasts.css +327 -0
- package/public/css/components/settings-editor-core-config-yml.css +828 -0
- package/public/css/components/short-results-as-a-toast-at-the-top.css +203 -0
- package/public/css/components/sound-player.css +84 -0
- package/public/css/components/suggest-agents-skills-commands.css +112 -0
- package/public/css/components/tab-modal.css +142 -0
- package/public/css/components/terminals.css +244 -0
- package/public/css/components/test-report-media-one-file-per-row-paged.css +144 -0
- package/public/css/components/top-toolbar-logo-breadcrumb.css +107 -0
- package/public/css/components/video-edit.css +6 -0
- package/public/css/components/web-ide-open-with.css +23 -0
- package/public/css/components/working-indicators.css +158 -0
- package/public/css/components/workspace-cards.css +79 -0
- package/public/favicon.ico +0 -0
- package/public/favicon.png +0 -0
- package/public/htmx.min.js +1 -0
- package/public/logo.png +0 -0
- package/public/media-player.js +215 -0
- package/public/mic.js +255 -0
- package/public/narration.js +110 -0
- package/public/palette.js +278 -0
- package/public/sortable.js +251 -0
- package/public/suggest.js +337 -0
- package/public/terminal.js +903 -0
- package/public/themes/default/theme.css +267 -0
- package/public/themes/ember/theme.css +180 -0
- package/public/themes/press/theme.css +290 -0
- package/public/themes/slate/theme.css +182 -0
- package/public/touch-icon.png +0 -0
- package/public/ui.js +2721 -0
- package/public/vendor/ace/LICENSE.txt +24 -0
- package/public/vendor/ace/ace.js +23 -0
- package/public/vendor/ace/ext-language_tools.js +8 -0
- package/public/vendor/ace/ext-searchbox.js +8 -0
- package/public/vendor/ace/mode-css.js +8 -0
- package/public/vendor/ace/mode-html.js +8 -0
- package/public/vendor/ace/mode-javascript.js +8 -0
- package/public/vendor/ace/mode-markdown.js +8 -0
- package/public/vendor/ace/mode-sh.js +8 -0
- package/public/vendor/ace/mode-yaml.js +8 -0
- package/public/vendor/ace/theme-textmate.js +8 -0
- package/public/vendor/ace/theme-tomorrow_night.js +8 -0
- package/public/vendor/ace/worker-yaml.js +1 -0
- package/public/vendor/deep-chat.LICENSE +21 -0
- package/public/vendor/deep-chat.bundle.js +1 -0
- package/public/vendor/fonts/dm-serif-text-LICENSE.txt +93 -0
- package/public/vendor/fonts/dm-serif-text-latin-400-italic.woff2 +0 -0
- package/public/vendor/fonts/dm-serif-text-latin-400-normal.woff2 +0 -0
- package/public/vendor/fonts/figtree-LICENSE.txt +93 -0
- package/public/vendor/fonts/figtree-latin-400-italic.woff2 +0 -0
- package/public/vendor/fonts/figtree-latin-400-normal.woff2 +0 -0
- package/public/vendor/fonts/figtree-latin-600-italic.woff2 +0 -0
- package/public/vendor/fonts/figtree-latin-600-normal.woff2 +0 -0
- package/public/vendor/fonts/jetbrains-mono-LICENSE.txt +93 -0
- package/public/vendor/fonts/jetbrains-mono-latin-400-normal.woff2 +0 -0
- package/public/vendor/fonts/ubuntu-mono-LICENSE.txt +98 -0
- package/public/vendor/fonts/ubuntu-mono-latin-wght-normal.woff2 +0 -0
- package/public/vendor/tabler-LICENSE.txt +21 -0
- package/public/vendor/tabler-sprite.svg +1 -0
- package/public/vendor/three/LICENSE +21 -0
- package/public/vendor/three/addons/loaders/GLTFLoader.js +4860 -0
- package/public/vendor/three/addons/utils/BufferGeometryUtils.js +1501 -0
- package/public/vendor/three/addons/utils/SkeletonUtils.js +496 -0
- package/public/vendor/three/three.core.min.js +6 -0
- package/public/vendor/three/three.module.min.js +6 -0
- package/public/vendor/three-vrm/LICENSE +22 -0
- package/public/vendor/three-vrm/three-vrm.module.min.js +983 -0
- package/public/vendor/uikit-icons.min.js +1 -0
- package/public/vendor/uikit.min.css +1 -0
- package/public/vendor/uikit.min.js +1 -0
- package/public/vendor/webship-icons/ui/bookmark-outlined.svg +1 -0
- package/public/vendor/webship-icons/ui/headset.svg +1 -0
- package/public/vendor/webship-icons/ui/menu.svg +1 -0
- package/public/vendor/webship-icons/ui/pause.svg +1 -0
- package/public/vendor/webship-icons/ui/play.svg +1 -0
- package/public/vendor/webship-icons/ui/share.svg +1 -0
- package/public/vendor/webship-icons/ui/sound-off.svg +1 -0
- package/public/vendor/webship-icons/ui/sound-on.svg +1 -0
- package/public/vendor/webship-icons/ui/stop.svg +1 -0
- package/public/vendor/xterm/addon-fit.js +2 -0
- package/public/vendor/xterm/addon-unicode11.js +2 -0
- package/public/vendor/xterm/addon-web-links.js +2 -0
- package/public/vendor/xterm/xterm.css +218 -0
- package/public/vendor/xterm/xterm.js +2 -0
- package/rag.js +169 -0
- package/reader.js +132 -0
- package/repo-blobs.js +66 -0
- package/report-pdf.js +337 -0
- package/row-layout.js +1439 -0
- package/screenrc +37 -0
- package/screens.js +1063 -0
- package/scripts/code-server-start.sh +190 -0
- package/scripts/images-claude-finish.js +107 -0
- package/scripts/screen-host.sh +114 -0
- package/scripts/screen-runner.js +362 -0
- package/scripts/screen-then.js +47 -0
- package/scripts/update.sh +350 -0
- package/server.js +7923 -0
- package/settings-file.js +423 -0
- package/speech.js +297 -0
- package/tab-modal.js +75 -0
- package/test-reports.js +260 -0
- package/themes.js +381 -0
- package/transcripts.js +168 -0
- package/urls.js +13 -0
- package/validate.js +18 -0
- package/version-check.js +94 -0
- package/video-edit.js +588 -0
- package/waiting.js +85 -0
- package/workspace-card-tools.js +41 -0
- package/workspace-delete.js +139 -0
- package/workspace-types.js +85 -0
- package/workspaces.js +553 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/* The screen terminals: floating windows, arranged as a list or a grid.
|
|
2
|
+
*
|
|
3
|
+
* They are windows and not a modal, and that is the whole design. A modal is one thing at a time, in
|
|
4
|
+
* the middle, with the page behind it out of reach — the opposite of what watching a terminal is for:
|
|
5
|
+
* you open one to keep half an eye on it while you do something else, and two to watch two agents. So
|
|
6
|
+
* each floats, is dragged by its title bar, resizes from its corner, remembers where it was put, and
|
|
7
|
+
* the bar in the corner tidies them all at once.
|
|
8
|
+
*
|
|
9
|
+
* Geometry is set by public/terminal.js as inline styles, because it belongs to the browser that put
|
|
10
|
+
* the window there. Everything here is what a window LOOKS like, never where it is.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
#term-windows {
|
|
14
|
+
position: fixed;
|
|
15
|
+
inset: 0;
|
|
16
|
+
z-index: 1010; /* over the page and the rails; under UIkit's modal, which is 1010+ */
|
|
17
|
+
pointer-events: none; /* the layer itself is not a surface — only its windows are */
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
#term-windows > * { pointer-events: auto; }
|
|
21
|
+
|
|
22
|
+
/* The bar lives in the top bar, beside Screens: one about the sessions running on this machine, one
|
|
23
|
+
about the terminals open in this browser. It is hidden until there is something to say, so the top
|
|
24
|
+
bar carries no control for a thing that is not there. */
|
|
25
|
+
#term-bar {
|
|
26
|
+
display: inline-flex;
|
|
27
|
+
align-items: center;
|
|
28
|
+
gap: 0.25rem;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
#term-bar[hidden] { display: none; }
|
|
32
|
+
|
|
33
|
+
#term-bar .term-count {
|
|
34
|
+
white-space: nowrap;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* The two arrange buttons are a pair, and read as one control rather than two loose glyphs. */
|
|
38
|
+
#term-bar .term-arrange { padding: 0 0.45rem; }
|
|
39
|
+
|
|
40
|
+
.term-window {
|
|
41
|
+
position: fixed;
|
|
42
|
+
/* The declared width IS the footprint. UIkit sets border-box on its own components but not on a
|
|
43
|
+
bare <section> — the same trap the rails hit — so without this every drag re-applied the measured
|
|
44
|
+
rectangle as a content width and the window grew by its padding and border, 18px at a time. */
|
|
45
|
+
box-sizing: border-box;
|
|
46
|
+
display: flex;
|
|
47
|
+
flex-direction: column;
|
|
48
|
+
gap: 0;
|
|
49
|
+
min-width: 26rem;
|
|
50
|
+
min-height: 13rem;
|
|
51
|
+
padding: 0 0 0.35rem;
|
|
52
|
+
border: 1px solid var(--term-bar, var(--line));
|
|
53
|
+
border-radius: 0.6rem;
|
|
54
|
+
/* The window wears the terminal's own palette, set by terminal.js as custom properties: the title
|
|
55
|
+
bar, the screen and the hints under it are one object, as they are in a real terminal. */
|
|
56
|
+
background: var(--term-bg, var(--code-bg));
|
|
57
|
+
color: var(--term-fg, var(--code-ink));
|
|
58
|
+
box-shadow: var(--shadow-float);
|
|
59
|
+
overflow: hidden;
|
|
60
|
+
container: term / inline-size;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* Which terminal takes your keystrokes, said twice over: the one in front, and the one with focus.
|
|
64
|
+
With four windows open and one cursor blinking in each, nothing else answers it. */
|
|
65
|
+
.term-window.is-front { border-color: var(--brand-primary); }
|
|
66
|
+
.term-window:focus-within { border-color: var(--brand-primary); box-shadow: var(--shadow-card-hover); }
|
|
67
|
+
|
|
68
|
+
.term-window.is-dragging { user-select: none; }
|
|
69
|
+
|
|
70
|
+
.term-window-head {
|
|
71
|
+
display: flex;
|
|
72
|
+
flex-wrap: wrap; /* a narrow window wraps its controls instead of clipping them */
|
|
73
|
+
align-items: center;
|
|
74
|
+
gap: 0.25rem 0.5rem;
|
|
75
|
+
min-width: 0;
|
|
76
|
+
padding: 0.35rem 0.5rem;
|
|
77
|
+
background: var(--term-bar, var(--surface));
|
|
78
|
+
color: var(--term-bar-ink, var(--text-default));
|
|
79
|
+
cursor: grab; /* the title bar is the handle */
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.term-window.is-dragging .term-window-head { cursor: grabbing; }
|
|
83
|
+
|
|
84
|
+
.term-title {
|
|
85
|
+
flex: 1 1 8rem;
|
|
86
|
+
font-weight: 600;
|
|
87
|
+
font-size: 0.875rem;
|
|
88
|
+
white-space: nowrap;
|
|
89
|
+
overflow: hidden;
|
|
90
|
+
text-overflow: ellipsis;
|
|
91
|
+
min-width: 0;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.term-window .term-status { white-space: nowrap; font-size: 0.75rem; color: inherit; opacity: 0.7; }
|
|
95
|
+
.term-verbs { margin-left: auto; display: flex; flex-wrap: wrap; justify-content: flex-end; align-items: center; gap: 0.2rem; }
|
|
96
|
+
|
|
97
|
+
/* The window's buttons sit on the title bar, so they take its ink and show a button only on hover,
|
|
98
|
+
as the controls of a header bar do. They are square at every width and grow when there is room. */
|
|
99
|
+
.term-window .term-verbs button.uk-button:not([data-term-font]),
|
|
100
|
+
.term-window .term-verbs a.uk-button {
|
|
101
|
+
display: inline-flex;
|
|
102
|
+
align-items: center;
|
|
103
|
+
justify-content: center;
|
|
104
|
+
width: 1.75rem;
|
|
105
|
+
height: 1.75rem;
|
|
106
|
+
min-width: 0;
|
|
107
|
+
padding: 0;
|
|
108
|
+
border-color: transparent;
|
|
109
|
+
border-radius: 0.4rem;
|
|
110
|
+
background: transparent;
|
|
111
|
+
color: inherit;
|
|
112
|
+
box-shadow: none;
|
|
113
|
+
}
|
|
114
|
+
.term-window .term-verbs button.uk-button:not([data-term-font]):hover,
|
|
115
|
+
.term-window .term-verbs a.uk-button:hover,
|
|
116
|
+
.term-window .term-verbs .uk-button:focus-visible {
|
|
117
|
+
background: color-mix(in srgb, currentColor 16%, transparent);
|
|
118
|
+
color: inherit;
|
|
119
|
+
}
|
|
120
|
+
.term-window .term-verbs .uk-button:focus-visible { outline: 2px solid var(--brand-primary); outline-offset: 1px; }
|
|
121
|
+
.term-window .term-verbs .uk-button svg { width: 1rem; height: 1rem; }
|
|
122
|
+
@container term (min-width: 56rem) {
|
|
123
|
+
.term-window .term-verbs button.uk-button:not([data-term-font]),
|
|
124
|
+
.term-window .term-verbs a.uk-button { width: 2rem; height: 2rem; }
|
|
125
|
+
.term-window .term-verbs .uk-button svg { width: 1.125rem; height: 1.125rem; }
|
|
126
|
+
}
|
|
127
|
+
@container term (max-width: 32rem) {
|
|
128
|
+
.term-window .term-status { display: none; }
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/* The window's controls are not the session's: a hairline says which side of it a button is on, so
|
|
132
|
+
"close this terminal" and "kill this session" are not two adjacent glyphs of the same weight. */
|
|
133
|
+
.term-verbs-sep {
|
|
134
|
+
width: 1px;
|
|
135
|
+
align-self: stretch;
|
|
136
|
+
margin: 0.15rem 0.2rem;
|
|
137
|
+
background: var(--line);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* The two that end something get the colour of what they do, on hover only — a row of red buttons
|
|
141
|
+
reads as a warning about the terminal itself. */
|
|
142
|
+
.term-window .term-interrupt:hover, .term-window .term-kill:hover { color: var(--danger-text); background: color-mix(in srgb, var(--danger) 20%, transparent); }
|
|
143
|
+
|
|
144
|
+
.term-screen {
|
|
145
|
+
flex: 1 1 auto;
|
|
146
|
+
min-height: 0; /* a flex child must be allowed to be shorter than its content */
|
|
147
|
+
padding: 0.35rem 0.6rem;
|
|
148
|
+
overflow: hidden;
|
|
149
|
+
background: var(--term-bg, var(--code-bg));
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/* The scrollback is screen's, reached with the wheel and the scroll-back button, so xterm's own bar
|
|
153
|
+
would be a track with nothing to scroll and a pale stripe down the side of a dark screen. */
|
|
154
|
+
.term-screen .xterm-viewport { scrollbar-width: none; }
|
|
155
|
+
.term-screen .xterm-viewport::-webkit-scrollbar { display: none; }
|
|
156
|
+
|
|
157
|
+
.term-cli-hint { flex: none; margin: 0.15rem 0.6rem 0; }
|
|
158
|
+
/* The dashboard forces the meta ink with !important for contrast on a page surface. Here the surface
|
|
159
|
+
is the terminal's, so the text takes the terminal's ink, and says so with the same weight. */
|
|
160
|
+
.term-window .uk-text-meta { color: inherit !important; }
|
|
161
|
+
.term-window .term-cli-hint .uk-text-meta,
|
|
162
|
+
.term-window .term-cli-hint summary { opacity: 0.85; }
|
|
163
|
+
/* The disclosure reads as a control: a pill with a chevron that turns when it is open, not a line of
|
|
164
|
+
text. The terminal's own ink, so it works on every style. */
|
|
165
|
+
.term-window .term-cli-hint summary {
|
|
166
|
+
display: inline-flex; align-items: center; gap: 0.4rem; list-style: none; cursor: pointer;
|
|
167
|
+
padding: 0.1rem 0.65rem 0.1rem 0.5rem; border: 1px solid color-mix(in srgb, currentColor 35%, transparent);
|
|
168
|
+
border-radius: 999px; opacity: 1; user-select: none;
|
|
169
|
+
}
|
|
170
|
+
.term-cli-hint summary::-webkit-details-marker { display: none; }
|
|
171
|
+
.term-cli-hint summary::before {
|
|
172
|
+
content: ""; width: 0.4rem; height: 0.4rem; margin-left: 0.1rem;
|
|
173
|
+
border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
|
|
174
|
+
transform: rotate(-45deg); transition: transform 0.15s ease;
|
|
175
|
+
}
|
|
176
|
+
.term-cli-hint[open] summary::before { transform: rotate(45deg); }
|
|
177
|
+
.term-window .term-cli-hint summary:hover { background: color-mix(in srgb, currentColor 16%, transparent); }
|
|
178
|
+
.term-cli-hint summary:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
|
|
179
|
+
.term-cli-hint[open] summary { margin-bottom: 0.3rem; }
|
|
180
|
+
@media (prefers-reduced-motion: reduce) { .term-cli-hint summary::before { transition: none; } }
|
|
181
|
+
.term-window .term-cli-hint code { background: color-mix(in srgb, currentColor 14%, transparent); color: inherit; }
|
|
182
|
+
|
|
183
|
+
/* The menu: size, text size and style, in one place so the title bar stays a title and a few icons. */
|
|
184
|
+
/* base.css underlines every link in a list item; a menu entry is not a link in a paragraph. */
|
|
185
|
+
.term-look-menu li a:not(.uk-button):not(.uk-link-reset) { text-decoration: none; }
|
|
186
|
+
.term-look-menu .term-font-row { display: flex; align-items: center; gap: 0.35rem; padding: 0.15rem 0.9rem; }
|
|
187
|
+
.term-look-menu .term-font-size { min-width: 3.25rem; text-align: center; font-variant-numeric: tabular-nums; }
|
|
188
|
+
.term-look-menu [data-term-style] { display: flex; align-items: center; gap: 0.5rem; }
|
|
189
|
+
.term-look-menu [data-term-style].is-on { font-weight: 600; color: var(--brand-primary); }
|
|
190
|
+
.term-swatch {
|
|
191
|
+
flex: none;
|
|
192
|
+
display: inline-block;
|
|
193
|
+
width: 1.5rem;
|
|
194
|
+
height: 1rem;
|
|
195
|
+
border: 1px solid var(--line-strong);
|
|
196
|
+
border-radius: 0.25rem;
|
|
197
|
+
background: linear-gradient(90deg, var(--sw-ink, var(--brand-primary)) 0 30%, var(--sw-bg, var(--code-bg)) 30%);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/* The corner grip. The CSS resize property needs a scroll container and drags the element's own box,
|
|
201
|
+
which fights an absolutely placed window — so the drag is terminal.js's and this is its handle. */
|
|
202
|
+
.term-resize {
|
|
203
|
+
position: absolute;
|
|
204
|
+
right: 0;
|
|
205
|
+
bottom: 0;
|
|
206
|
+
width: 1.1rem;
|
|
207
|
+
height: 1.1rem;
|
|
208
|
+
cursor: nwse-resize;
|
|
209
|
+
background:
|
|
210
|
+
linear-gradient(135deg, transparent 50%, var(--line-strong) 50%, var(--line-strong) 62%, transparent 62%),
|
|
211
|
+
linear-gradient(135deg, transparent 72%, var(--line-strong) 72%, var(--line-strong) 84%, transparent 84%);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.term-window.is-full {
|
|
215
|
+
inset: 0 !important;
|
|
216
|
+
width: 100% !important;
|
|
217
|
+
height: 100% !important;
|
|
218
|
+
border: 0;
|
|
219
|
+
border-radius: 0;
|
|
220
|
+
padding: 0.3rem;
|
|
221
|
+
}
|
|
222
|
+
.term-window.is-full .term-cli-hint,
|
|
223
|
+
.term-window.is-full .term-resize { display: none; }
|
|
224
|
+
|
|
225
|
+
/* Asking for a terminal that is already open raises it rather than opening a second; this is what
|
|
226
|
+
says so. */
|
|
227
|
+
.term-window.is-flash { animation: term-flash .6s ease-out; }
|
|
228
|
+
@keyframes term-flash {
|
|
229
|
+
from { box-shadow: 0 0 0 3px var(--brand-primary); }
|
|
230
|
+
to { box-shadow: var(--shadow-float); }
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/* The session's own tab (/terminal/<name>): one terminal, filling it. Nothing floats, nothing is
|
|
234
|
+
dragged, and the button that opens a tab has nothing to offer. */
|
|
235
|
+
body.is-terminal-page #term-windows { position: static; }
|
|
236
|
+
body.is-terminal-page #term-bar { display: none; }
|
|
237
|
+
body.is-terminal-page .term-window {
|
|
238
|
+
position: static;
|
|
239
|
+
width: auto !important;
|
|
240
|
+
height: calc(100vh - 7rem) !important;
|
|
241
|
+
box-shadow: none;
|
|
242
|
+
}
|
|
243
|
+
body.is-terminal-page .term-newtab,
|
|
244
|
+
body.is-terminal-page .term-resize { display: none; }
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/* ---------- Test-report media: one file per row, paged ---------- */
|
|
2
|
+
|
|
3
|
+
.test-media-list {
|
|
4
|
+
list-style: none;
|
|
5
|
+
margin: 0;
|
|
6
|
+
padding: 0;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.test-media-row {
|
|
10
|
+
display: flex;
|
|
11
|
+
align-items: center;
|
|
12
|
+
gap: 0.5rem;
|
|
13
|
+
padding: 0.3125rem 0.25rem;
|
|
14
|
+
border-bottom: 1px solid var(--line);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.test-media-row:last-child { border-bottom: 0; }
|
|
18
|
+
|
|
19
|
+
/* The name is the row's action: it opens the viewer, so it reads as a link, and it truncates
|
|
20
|
+
rather than wrapping — a webship-js recording name easily runs to 120 characters. */
|
|
21
|
+
.test-media-name {
|
|
22
|
+
flex: 1 1 auto;
|
|
23
|
+
min-width: 0;
|
|
24
|
+
display: flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
gap: 0.375rem;
|
|
27
|
+
background: none;
|
|
28
|
+
border: 0;
|
|
29
|
+
padding: 0;
|
|
30
|
+
text-align: left;
|
|
31
|
+
font: inherit;
|
|
32
|
+
font-size: 0.82rem;
|
|
33
|
+
color: var(--brand-primary);
|
|
34
|
+
cursor: pointer;
|
|
35
|
+
overflow: hidden;
|
|
36
|
+
text-overflow: ellipsis;
|
|
37
|
+
white-space: nowrap;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.test-media-name:hover { text-decoration: underline; }
|
|
41
|
+
|
|
42
|
+
.test-media-meta { flex: 0 0 auto; white-space: nowrap; }
|
|
43
|
+
.test-media-actions { flex: 0 0 auto; display: flex; gap: 0.25rem; }
|
|
44
|
+
|
|
45
|
+
.test-media-pager {
|
|
46
|
+
display: flex;
|
|
47
|
+
align-items: center;
|
|
48
|
+
justify-content: center;
|
|
49
|
+
gap: 0.625rem;
|
|
50
|
+
margin-top: 0.5rem;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* The viewer's image: the modal's width, never wider, on its own row. */
|
|
54
|
+
.test-view-image {
|
|
55
|
+
display: block;
|
|
56
|
+
width: 100%;
|
|
57
|
+
height: auto;
|
|
58
|
+
max-height: 70vh;
|
|
59
|
+
object-fit: contain;
|
|
60
|
+
border: 1px solid var(--line);
|
|
61
|
+
border-radius: 0.5rem;
|
|
62
|
+
background: var(--subtle-light);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* Screenshots: three thumbnails to a row. The thumbnail is the button that opens the viewer. */
|
|
66
|
+
.test-shot-grid {
|
|
67
|
+
list-style: none;
|
|
68
|
+
margin: 0;
|
|
69
|
+
padding: 0;
|
|
70
|
+
display: grid;
|
|
71
|
+
grid-template-columns: repeat(3, 1fr);
|
|
72
|
+
gap: 0.75rem;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.test-shot-card { min-width: 0; display: flex; flex-direction: column; gap: 0.25rem; }
|
|
76
|
+
|
|
77
|
+
.test-shot-thumb {
|
|
78
|
+
display: block;
|
|
79
|
+
padding: 0;
|
|
80
|
+
border: 1px solid var(--line);
|
|
81
|
+
border-radius: 0.5rem;
|
|
82
|
+
background: var(--subtle-light);
|
|
83
|
+
cursor: zoom-in;
|
|
84
|
+
overflow: hidden;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.test-shot-thumb img {
|
|
88
|
+
display: block;
|
|
89
|
+
width: 100%;
|
|
90
|
+
aspect-ratio: 16 / 9;
|
|
91
|
+
object-fit: cover;
|
|
92
|
+
transition: transform .12s ease;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.test-shot-thumb:hover img { transform: scale(1.03); }
|
|
96
|
+
|
|
97
|
+
.test-shot-caption {
|
|
98
|
+
overflow: hidden;
|
|
99
|
+
text-overflow: ellipsis;
|
|
100
|
+
white-space: nowrap;
|
|
101
|
+
font-size: 0.72rem;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.test-shot-meta { font-size: 0.7rem; display: flex; align-items: center; gap: 0.375rem; flex-wrap: wrap; }
|
|
105
|
+
|
|
106
|
+
@media (max-width: 47.9375em) {
|
|
107
|
+
.test-shot-grid { grid-template-columns: repeat(2, 1fr); }
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* Deleting test evidence: the button is small and sits with the file's own metadata, because it
|
|
111
|
+
belongs to that file — not to the report. The bulk row is above the list, where you look before
|
|
112
|
+
you start scrolling through 300 thumbnails. */
|
|
113
|
+
.test-media-bulk {
|
|
114
|
+
display: flex;
|
|
115
|
+
align-items: center;
|
|
116
|
+
flex-wrap: wrap;
|
|
117
|
+
gap: 0.5rem;
|
|
118
|
+
margin-bottom: 0.5rem;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.test-shot-meta .test-media-del,
|
|
122
|
+
.test-media-actions .test-media-del { padding: 0 0.4rem; line-height: 1.6; }
|
|
123
|
+
|
|
124
|
+
.test-media-flash { margin-bottom: 0.5rem; }
|
|
125
|
+
|
|
126
|
+
/* A menu that carries a state word — Graph, RAG, Tests — captions it UNDER the button.
|
|
127
|
+
The caption sits in an OUTER wrapper, never inside the .uk-inline element: UIkit positions the
|
|
128
|
+
dropdown panel against that element, and making it a flex column turned the panel into a flex
|
|
129
|
+
item, which laid it out in flow and stopped the menus opening. */
|
|
130
|
+
.act-with-status {
|
|
131
|
+
display: inline-flex;
|
|
132
|
+
flex-direction: column;
|
|
133
|
+
align-items: center;
|
|
134
|
+
gap: 0.1rem;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.act-with-status .act-status {
|
|
138
|
+
font-size: 0.625rem;
|
|
139
|
+
line-height: 1;
|
|
140
|
+
letter-spacing: .02em;
|
|
141
|
+
color: var(--text-subtle);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.project-actions { align-items: flex-start; }
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/* ---------- Top toolbar (logo) ---------- */
|
|
2
|
+
|
|
3
|
+
/* `.uk-navbar-container.toolbar`, not `.toolbar`: UIKit paints this element with
|
|
4
|
+
`.uk-navbar-container:not(.uk-navbar-transparent)`, which is (0,2,0) — a lone
|
|
5
|
+
`.toolbar` at (0,1,0) never won, and the toolbar kept UIKit's own near-white in
|
|
6
|
+
both halves. It went unseen in the light half, where near-white and white differ
|
|
7
|
+
by almost nothing; in the dark half it was a white bar over a dark page. */
|
|
8
|
+
.uk-navbar-container.toolbar {
|
|
9
|
+
background: var(--surface-card);
|
|
10
|
+
border-bottom: 1px solid var(--line);
|
|
11
|
+
position: sticky;
|
|
12
|
+
top: 0;
|
|
13
|
+
z-index: 40;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.toolbar-logo {
|
|
17
|
+
gap:0.5rem;
|
|
18
|
+
font-weight: 700;
|
|
19
|
+
color: var(--ink) !important;
|
|
20
|
+
font-size:1.0625rem;
|
|
21
|
+
text-transform: none;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.toolbar-logo img { border-radius:0.5rem; }
|
|
25
|
+
|
|
26
|
+
.toolbar-logo span { font-size:1.25rem; }
|
|
27
|
+
|
|
28
|
+
/* Compact page heading under the toolbar */
|
|
29
|
+
.page-heading { gap:0.75rem; margin-bottom:1.125rem; }
|
|
30
|
+
|
|
31
|
+
.page-heading-icon {
|
|
32
|
+
width:2.875rem;
|
|
33
|
+
height:2.875rem;
|
|
34
|
+
min-width:2.875rem;
|
|
35
|
+
border-radius:0.75rem;
|
|
36
|
+
background: var(--subtle-brand);
|
|
37
|
+
color: var(--brand-1);
|
|
38
|
+
display: flex;
|
|
39
|
+
align-items: center;
|
|
40
|
+
justify-content: center;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* The page title takes the H2 role rather than a size of its own: a dashboard heading over a
|
|
44
|
+
project table should not be the landing page's 62px h1, but it should still come from the
|
|
45
|
+
scale. A hardcoded 1.625rem here is how a heading stops tracking the design. */
|
|
46
|
+
.page-heading h1 { font: var(--type-h2); letter-spacing: var(--tracking-h2); }
|
|
47
|
+
|
|
48
|
+
/* The light/dark switch in the toolbar.
|
|
49
|
+
*
|
|
50
|
+
* These rules used to live in the default theme's file, which meant the only theme that styled
|
|
51
|
+
* the toggle was the default one: on Ember or Slate the button fell back to UIKit's own button
|
|
52
|
+
* chrome and the sun/moon swap still worked but looked borrowed. A theme is a palette — the
|
|
53
|
+
* control belongs to the toolbar, so it lives here and reads tokens like everything else. */
|
|
54
|
+
.theme-toggle {
|
|
55
|
+
background: none;
|
|
56
|
+
border: none;
|
|
57
|
+
cursor: pointer;
|
|
58
|
+
color: var(--ink);
|
|
59
|
+
padding: 0 0.375rem;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.theme-toggle:hover { color: var(--link); }
|
|
63
|
+
|
|
64
|
+
/* One icon at a time: the sun is the way OUT of dark, so it only shows there. */
|
|
65
|
+
.theme-icon-sun { display: none; }
|
|
66
|
+
html.dark .theme-icon-sun { display: inline; }
|
|
67
|
+
html.dark .theme-icon-moon { display: none; }
|
|
68
|
+
|
|
69
|
+
/* The Webship lockup.
|
|
70
|
+
*
|
|
71
|
+
* One rule, in the component that owns the toolbar: the height was set in two other components at
|
|
72
|
+
* two different values (2rem and 1.375rem), so which one applied depended on the order the sheet
|
|
73
|
+
* was assembled in. `object-fit: contain` is the guard — UIKit's reset puts `object-fit: cover` on
|
|
74
|
+
* every img, which crops rather than scales the moment the box and the artwork disagree by a
|
|
75
|
+
* fraction, and a cropped logo is a brand error rather than a layout one. `width: auto` keeps the
|
|
76
|
+
* ratio the artwork's own. */
|
|
77
|
+
.brand-logo {
|
|
78
|
+
display: block;
|
|
79
|
+
height: 2.25rem;
|
|
80
|
+
width: auto;
|
|
81
|
+
max-width: 100%;
|
|
82
|
+
object-fit: contain;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/* UIKit gives .uk-logo a system font stack and its own grey. The lockup beside it is the brand's,
|
|
86
|
+
so the word next to it is set in the brand face and the theme's ink. */
|
|
87
|
+
.toolbar-logo, .toolbar-logo:hover { font-family: var(--font-primary); color: var(--text-default); }
|
|
88
|
+
|
|
89
|
+
/* The release, beside the product name. Quiet by default — it is reference, not navigation —
|
|
90
|
+
* and explicitly marked when it cannot be told, because a missing version must read as
|
|
91
|
+
* missing rather than as nothing at all. */
|
|
92
|
+
/* The exposure banner. Deliberately the danger colour and deliberately not dismissible: it
|
|
93
|
+
* appears only when the machine has stopped being loopback-only, and the dashboard has no
|
|
94
|
+
* login to protect what is then reachable. */
|
|
95
|
+
.exposure-banner {
|
|
96
|
+
background: var(--danger-soft);
|
|
97
|
+
color: var(--danger-ink);
|
|
98
|
+
border: 1px solid var(--danger);
|
|
99
|
+
border-radius: 10px;
|
|
100
|
+
padding: .6rem .85rem;
|
|
101
|
+
margin: 0 0 1rem;
|
|
102
|
+
font-size: .8125rem;
|
|
103
|
+
line-height: 1.45;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.exposure-banner strong { display: block; margin-bottom: .25rem; color: var(--danger); }
|
|
107
|
+
.exposure-banner code { background: transparent; }
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/* Edit a video: a tab per kind of change, then the fields of that tab. */
|
|
2
|
+
.video-edit-tabs { margin: 0.25rem 0 0.75rem; flex-wrap: wrap; gap: 0.25rem; }
|
|
3
|
+
.video-edit-side { border: 1px solid var(--line); border-radius: 0.5rem; padding: 0.75rem; margin: 0 0 0.75rem; }
|
|
4
|
+
.video-edit-side legend { padding: 0 0.375rem; }
|
|
5
|
+
.video-edit-sections { max-height: 12rem; overflow: auto; margin: 0 0 1rem; }
|
|
6
|
+
.video-edit-sections label { display: flex; align-items: baseline; gap: 0.5rem; }
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/* The "Codebase" / "Files" menu: the Web IDE here, or an editor on the viewer's machine.
|
|
2
|
+
*
|
|
3
|
+
* Painted with tokens only — a unit test enforces that (a literal cannot be themed). */
|
|
4
|
+
|
|
5
|
+
/* The unavailable note is a sentence with two commands in it, not a menu item, so it must
|
|
6
|
+
* be allowed to wrap inside the dropdown instead of stretching it to the width of the
|
|
7
|
+
* longest command. */
|
|
8
|
+
.ide-unavailable {
|
|
9
|
+
display: block;
|
|
10
|
+
max-width: 22rem;
|
|
11
|
+
padding: .25rem .5rem .4rem;
|
|
12
|
+
white-space: normal;
|
|
13
|
+
line-height: 1.4;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.ide-unavailable code {
|
|
17
|
+
white-space: nowrap;
|
|
18
|
+
word-break: keep-all;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* On a files workspace the control sits under the heading rather than in a row, so it
|
|
22
|
+
* needs the row's spacing of its own. */
|
|
23
|
+
.items-open-with { display: flex; gap: .5rem; align-items: center; }
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/* ---------- Working indicators ---------- */
|
|
2
|
+
|
|
3
|
+
/* Thin animated bar across the top + a floating pill, shown while ANY
|
|
4
|
+
* HTMX request is in flight (ui.js toggles html.htmx-busy). */
|
|
5
|
+
.global-working { display: none; }
|
|
6
|
+
|
|
7
|
+
html.htmx-busy .global-working { display: block; }
|
|
8
|
+
|
|
9
|
+
.global-working-bar {
|
|
10
|
+
position: fixed;
|
|
11
|
+
top: 0;
|
|
12
|
+
left: 0;
|
|
13
|
+
right: 0;
|
|
14
|
+
height:0.1875rem;
|
|
15
|
+
z-index: 50;
|
|
16
|
+
background: var(--brand-grad);
|
|
17
|
+
background-size: 200% 100%;
|
|
18
|
+
animation: working-slide 1.2s linear infinite;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@keyframes working-slide {
|
|
22
|
+
from { background-position: 200% 0; }
|
|
23
|
+
to { background-position: 0 0; }
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.global-working-pill {
|
|
27
|
+
position: fixed;
|
|
28
|
+
right:1.125rem;
|
|
29
|
+
bottom:1.125rem;
|
|
30
|
+
z-index: 50;
|
|
31
|
+
background: var(--surface-card);
|
|
32
|
+
border: 1px solid var(--line);
|
|
33
|
+
border-radius:62.4375rem;
|
|
34
|
+
padding:0.5rem 1rem;
|
|
35
|
+
font-size:0.8125rem;
|
|
36
|
+
font-weight: 600;
|
|
37
|
+
/* --busy-ink, not the brand navy: the pill sits on the card surface, and in dark mode that navy on
|
|
38
|
+
a dark card measured below AA. The busy token is the one that moves with the theme. */
|
|
39
|
+
color: var(--busy-ink);
|
|
40
|
+
box-shadow: 0 8px 22px rgba(35, 41, 70, .18);
|
|
41
|
+
display: flex;
|
|
42
|
+
align-items: center;
|
|
43
|
+
gap:0.5rem;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* Chat "assistant is thinking…" indicator (shown via hx-indicator) */
|
|
47
|
+
.chat-typing {
|
|
48
|
+
display: none;
|
|
49
|
+
align-items: center;
|
|
50
|
+
gap:0.3125rem;
|
|
51
|
+
margin-top:0.625rem;
|
|
52
|
+
padding:0.5rem 0.875rem;
|
|
53
|
+
background: var(--surface-card);
|
|
54
|
+
border: 1px solid var(--line);
|
|
55
|
+
border-radius:0.75rem;
|
|
56
|
+
width: fit-content;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.chat-typing.htmx-request { display: flex; }
|
|
60
|
+
|
|
61
|
+
.chat-typing .dot {
|
|
62
|
+
width:0.4375rem;
|
|
63
|
+
height:0.4375rem;
|
|
64
|
+
border-radius: 50%;
|
|
65
|
+
background: var(--brand-2);
|
|
66
|
+
animation: typing-bounce 1.2s infinite;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.chat-typing .dot:nth-child(2) { animation-delay: .18s; }
|
|
70
|
+
.chat-typing .dot:nth-child(3) { animation-delay: .36s; }
|
|
71
|
+
|
|
72
|
+
@keyframes typing-bounce {
|
|
73
|
+
0%, 60%, 100% { transform: translateY(0); opacity: .45; }
|
|
74
|
+
30% { transform: translateY(-5px); opacity: 1; }
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.chat-typing-label {
|
|
78
|
+
font-size:0.75rem;
|
|
79
|
+
color: var(--brand-2);
|
|
80
|
+
font-weight: 600;
|
|
81
|
+
margin-left:0.25rem;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
/* Assistant sparkle logo mark */
|
|
86
|
+
.assistant-avatar .ai-mark { width:1.5rem; height:1.5rem; display: block; }
|
|
87
|
+
|
|
88
|
+
.assistant-launcher {
|
|
89
|
+
display: flex;
|
|
90
|
+
align-items: center;
|
|
91
|
+
justify-content: center;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.assistant-launcher .ai-mark { width:1.75rem; height:1.75rem; }
|
|
95
|
+
|
|
96
|
+
/* Small backups indicator on workspace cards (home page) */
|
|
97
|
+
.workspace-card { position: relative; }
|
|
98
|
+
|
|
99
|
+
.ws-backups {
|
|
100
|
+
position: absolute;
|
|
101
|
+
top:0.625rem;
|
|
102
|
+
right:0.75rem;
|
|
103
|
+
z-index: 2;
|
|
104
|
+
text-decoration: none;
|
|
105
|
+
display: inline-flex;
|
|
106
|
+
align-items: center;
|
|
107
|
+
gap:0.1875rem;
|
|
108
|
+
font-size:0.6875rem;
|
|
109
|
+
font-weight: 700;
|
|
110
|
+
color: var(--accent-ink);
|
|
111
|
+
background: var(--accent-soft);
|
|
112
|
+
border-radius:62.4375rem;
|
|
113
|
+
padding:0.125rem 0.5rem;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.ws-backups:hover { background: var(--brand-2); color: var(--text-inverse); text-decoration: none; }
|
|
117
|
+
|
|
118
|
+
/* Live terminal output boxes */
|
|
119
|
+
.terminal .terminal-pre {
|
|
120
|
+
background: var(--code-bg);
|
|
121
|
+
color: var(--terminal-ink);
|
|
122
|
+
font-family: 'SF Mono', Menlo, Consolas, monospace;
|
|
123
|
+
max-height:20rem;
|
|
124
|
+
overflow-y: auto;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* VDO drop logo on the home hero */
|
|
128
|
+
.site-logo {
|
|
129
|
+
display: block;
|
|
130
|
+
margin: 0 auto;
|
|
131
|
+
width:6rem;
|
|
132
|
+
height:6rem;
|
|
133
|
+
filter: drop-shadow(0 8px 18px rgba(35, 41, 70, .25));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/* The assistant while it works on an answer: the avatar pulses and a light sweeps along the header. */
|
|
137
|
+
.assistant-panel[data-working] .assistant-head { position: relative; }
|
|
138
|
+
.assistant-panel[data-working] .assistant-head::after {
|
|
139
|
+
content: "";
|
|
140
|
+
position: absolute;
|
|
141
|
+
left: 0;
|
|
142
|
+
right: 0;
|
|
143
|
+
bottom: 0;
|
|
144
|
+
height: 0.1875rem;
|
|
145
|
+
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .9), transparent) -40% 0 / 40% 100% no-repeat;
|
|
146
|
+
animation: assistant-sweep 1.4s linear infinite;
|
|
147
|
+
}
|
|
148
|
+
.assistant-panel[data-working] .assistant-avatar { animation: assistant-pulse 1.4s ease-in-out infinite; }
|
|
149
|
+
|
|
150
|
+
@keyframes assistant-sweep { to { background-position: 140% 0; } }
|
|
151
|
+
@keyframes assistant-pulse {
|
|
152
|
+
50% { transform: scale(1.08); box-shadow: 0 0 0 0.375rem rgba(255, 255, 255, .18); }
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
@media (prefers-reduced-motion: reduce) {
|
|
156
|
+
.assistant-panel[data-working] .assistant-head::after,
|
|
157
|
+
.assistant-panel[data-working] .assistant-avatar { animation: none; }
|
|
158
|
+
}
|