@visuno/angular 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +24 -0
- package/README.md +56 -2
- package/account-table/account-table.component.d.ts +72 -0
- package/action-log/action-log.component.d.ts +41 -0
- package/activity-heatmap/activity-heatmap.component.d.ts +67 -0
- package/agent-inbox/agent-inbox.component.d.ts +75 -0
- package/agent-lanes/agent-lanes.component.d.ts +152 -0
- package/agent-phases/agent-phases.component.d.ts +62 -0
- package/agent-run-timeline/agent-run-timeline.component.d.ts +113 -0
- package/agent-tree/agent-tree.component.d.ts +80 -0
- package/answer-action-bar/answer-action-bar.component.d.ts +110 -0
- package/artifact-card/artifact-card.component.d.ts +145 -0
- package/attachment-tray/attachment-tray.component.d.ts +84 -0
- package/badge/badge.component.d.ts +25 -0
- package/bar-chart/bar-chart.component.d.ts +87 -0
- package/browser-session/browser-session.component.d.ts +70 -0
- package/buttons/buttons.component.d.ts +63 -0
- package/card/card.component.d.ts +21 -0
- package/change-review/change-review.component.d.ts +97 -0
- package/citation-hover-card/citation-hover-card.component.d.ts +95 -0
- package/code-viewer/code-viewer.component.d.ts +86 -0
- package/composer/composer.component.d.ts +114 -0
- package/context-meter/context-meter.component.d.ts +60 -0
- package/core/icon.component.d.ts +10 -0
- package/core/reduced-motion.service.d.ts +15 -0
- package/decision-prompt/decision-prompt.component.d.ts +56 -0
- package/design-review/design-review.component.d.ts +108 -0
- package/design-tuner/design-tuner.component.d.ts +75 -0
- package/details-panel/details-panel.component.d.ts +150 -0
- package/donut-chart/donut-chart.component.d.ts +63 -0
- package/draft-review/draft-review.component.d.ts +128 -0
- package/error-recovery/error-recovery.component.d.ts +59 -0
- package/esm2022/account-table/account-table.component.mjs +399 -0
- package/esm2022/action-log/action-log.component.mjs +177 -0
- package/esm2022/activity-heatmap/activity-heatmap.component.mjs +285 -0
- package/esm2022/agent-inbox/agent-inbox.component.mjs +284 -0
- package/esm2022/agent-lanes/agent-lanes.component.mjs +600 -0
- package/esm2022/agent-phases/agent-phases.component.mjs +300 -0
- package/esm2022/agent-run-timeline/agent-run-timeline.component.mjs +412 -0
- package/esm2022/agent-tree/agent-tree.component.mjs +393 -0
- package/esm2022/answer-action-bar/answer-action-bar.component.mjs +636 -0
- package/esm2022/artifact-card/artifact-card.component.mjs +916 -0
- package/esm2022/attachment-tray/attachment-tray.component.mjs +402 -0
- package/esm2022/badge/badge.component.mjs +97 -0
- package/esm2022/bar-chart/bar-chart.component.mjs +300 -0
- package/esm2022/browser-session/browser-session.component.mjs +352 -0
- package/esm2022/buttons/buttons.component.mjs +215 -0
- package/esm2022/card/card.component.mjs +107 -0
- package/esm2022/change-review/change-review.component.mjs +398 -0
- package/esm2022/citation-hover-card/citation-hover-card.component.mjs +360 -0
- package/esm2022/code-viewer/code-viewer.component.mjs +291 -0
- package/esm2022/composer/composer.component.mjs +743 -0
- package/esm2022/context-meter/context-meter.component.mjs +275 -0
- package/esm2022/core/icon.component.mjs +111 -0
- package/esm2022/core/reduced-motion.service.mjs +34 -0
- package/esm2022/decision-prompt/decision-prompt.component.mjs +259 -0
- package/esm2022/design-review/design-review.component.mjs +428 -0
- package/esm2022/design-tuner/design-tuner.component.mjs +341 -0
- package/esm2022/details-panel/details-panel.component.mjs +537 -0
- package/esm2022/donut-chart/donut-chart.component.mjs +240 -0
- package/esm2022/draft-review/draft-review.component.mjs +549 -0
- package/esm2022/error-recovery/error-recovery.component.mjs +231 -0
- package/esm2022/eval-results/eval-results.component.mjs +368 -0
- package/esm2022/feedback-sheet/feedback-sheet.component.mjs +411 -0
- package/esm2022/field-extraction/field-extraction.component.mjs +368 -0
- package/esm2022/funnel-chart/funnel-chart.component.mjs +258 -0
- package/esm2022/grid/grid.component.mjs +66 -0
- package/esm2022/health-score/health-score.component.mjs +420 -0
- package/esm2022/human-handoff/human-handoff.component.mjs +676 -0
- package/esm2022/image-generation/image-generation.component.mjs +1028 -0
- package/esm2022/inline-text-diff/inline-text-diff.component.mjs +390 -0
- package/esm2022/launch-checklist/launch-checklist.component.mjs +229 -0
- package/esm2022/line-chart/line-chart.component.mjs +417 -0
- package/esm2022/live-answer/live-answer.component.mjs +411 -0
- package/esm2022/metric-insight/metric-insight.component.mjs +511 -0
- package/esm2022/modal/modal.component.mjs +202 -0
- package/esm2022/model-picker/model-picker.component.mjs +491 -0
- package/esm2022/permission-gate/permission-gate.component.mjs +498 -0
- package/esm2022/plan-review/plan-review.component.mjs +432 -0
- package/esm2022/progress/progress.component.mjs +503 -0
- package/esm2022/prompt-library/prompt-library.component.mjs +453 -0
- package/esm2022/prompt-starters/prompt-starters.component.mjs +272 -0
- package/esm2022/proposal-card/proposal-card.component.mjs +402 -0
- package/esm2022/public-api.mjs +88 -0
- package/esm2022/radar-chart/radar-chart.component.mjs +500 -0
- package/esm2022/radial-goals/radial-goals.component.mjs +418 -0
- package/esm2022/reasoning-trail/reasoning-trail.component.mjs +284 -0
- package/esm2022/response-versions/response-versions.component.mjs +288 -0
- package/esm2022/rewrite-toolbar/rewrite-toolbar.component.mjs +397 -0
- package/esm2022/rich-text-editor/rich-text-editor.component.mjs +1755 -0
- package/esm2022/run-cost/run-cost.component.mjs +215 -0
- package/esm2022/run-queue/run-queue.component.mjs +481 -0
- package/esm2022/run-summary/run-summary.component.mjs +331 -0
- package/esm2022/scatter-chart/scatter-chart.component.mjs +705 -0
- package/esm2022/score-breakdown/score-breakdown.component.mjs +460 -0
- package/esm2022/segmented-control/segmented-control.component.mjs +180 -0
- package/esm2022/source-stack/source-stack.component.mjs +245 -0
- package/esm2022/stat-cards/stat-cards.component.mjs +258 -0
- package/esm2022/status-pill/status-pill.component.mjs +305 -0
- package/esm2022/steering/steering.component.mjs +343 -0
- package/esm2022/step-loader/step-loader.component.mjs +209 -0
- package/esm2022/task-table/task-table.component.mjs +534 -0
- package/esm2022/terminal-stream/terminal-stream.component.mjs +583 -0
- package/esm2022/thinking/thinking.component.mjs +276 -0
- package/esm2022/thinking-states/thinking-states.component.mjs +333 -0
- package/esm2022/thread-panel/thread-panel.component.mjs +271 -0
- package/esm2022/toast/toast.component.mjs +195 -0
- package/esm2022/toast-stack/toast-stack.component.mjs +301 -0
- package/esm2022/tool-call/tool-call.component.mjs +273 -0
- package/esm2022/tooltip/tooltip.component.mjs +417 -0
- package/esm2022/top-pages/top-pages.component.mjs +240 -0
- package/esm2022/trace-view/trace-view.component.mjs +440 -0
- package/esm2022/visuno-angular.mjs +5 -0
- package/esm2022/voice-capture/voice-capture.component.mjs +650 -0
- package/esm2022/voice-orb/voice-orb.component.mjs +538 -0
- package/esm2022/web-search/web-search.component.mjs +374 -0
- package/eval-results/eval-results.component.d.ts +67 -0
- package/feedback-sheet/feedback-sheet.component.d.ts +74 -0
- package/fesm2022/visuno-angular.mjs +31992 -0
- package/fesm2022/visuno-angular.mjs.map +1 -0
- package/field-extraction/field-extraction.component.d.ts +82 -0
- package/funnel-chart/funnel-chart.component.d.ts +70 -0
- package/grid/grid.component.d.ts +22 -0
- package/health-score/health-score.component.d.ts +87 -0
- package/human-handoff/human-handoff.component.d.ts +125 -0
- package/image-generation/image-generation.component.d.ts +253 -0
- package/index.d.ts +5 -0
- package/inline-text-diff/inline-text-diff.component.d.ts +76 -0
- package/launch-checklist/launch-checklist.component.d.ts +46 -0
- package/line-chart/line-chart.component.d.ts +89 -0
- package/live-answer/live-answer.component.d.ts +110 -0
- package/metric-insight/metric-insight.component.d.ts +110 -0
- package/modal/modal.component.d.ts +37 -0
- package/model-picker/model-picker.component.d.ts +97 -0
- package/package.json +51 -4
- package/permission-gate/permission-gate.component.d.ts +100 -0
- package/plan-review/plan-review.component.d.ts +86 -0
- package/progress/progress.component.d.ts +91 -0
- package/prompt-library/prompt-library.component.d.ts +121 -0
- package/prompt-starters/prompt-starters.component.d.ts +65 -0
- package/proposal-card/proposal-card.component.d.ts +101 -0
- package/public-api.d.ts +82 -0
- package/radar-chart/radar-chart.component.d.ts +110 -0
- package/radial-goals/radial-goals.component.d.ts +90 -0
- package/reasoning-trail/reasoning-trail.component.d.ts +73 -0
- package/response-versions/response-versions.component.d.ts +54 -0
- package/rewrite-toolbar/rewrite-toolbar.component.d.ts +92 -0
- package/rich-text-editor/rich-text-editor.component.d.ts +180 -0
- package/run-cost/run-cost.component.d.ts +43 -0
- package/run-queue/run-queue.component.d.ts +93 -0
- package/run-summary/run-summary.component.d.ts +81 -0
- package/scatter-chart/scatter-chart.component.d.ts +139 -0
- package/score-breakdown/score-breakdown.component.d.ts +107 -0
- package/segmented-control/segmented-control.component.d.ts +44 -0
- package/source-stack/source-stack.component.d.ts +60 -0
- package/stat-cards/stat-cards.component.d.ts +86 -0
- package/status-pill/status-pill.component.d.ts +64 -0
- package/steering/steering.component.d.ts +75 -0
- package/step-loader/step-loader.component.d.ts +40 -0
- package/styles.css +424 -0
- package/task-table/task-table.component.d.ts +114 -0
- package/terminal-stream/terminal-stream.component.d.ts +110 -0
- package/thinking/thinking.component.d.ts +63 -0
- package/thinking-states/thinking-states.component.d.ts +51 -0
- package/thread-panel/thread-panel.component.d.ts +75 -0
- package/toast/toast.component.d.ts +56 -0
- package/toast-stack/toast-stack.component.d.ts +72 -0
- package/tokens.css +424 -0
- package/tool-call/tool-call.component.d.ts +61 -0
- package/tooltip/tooltip.component.d.ts +89 -0
- package/top-pages/top-pages.component.d.ts +75 -0
- package/trace-view/trace-view.component.d.ts +95 -0
- package/voice-capture/voice-capture.component.d.ts +103 -0
- package/voice-orb/voice-orb.component.d.ts +78 -0
- package/web-search/web-search.component.d.ts +77 -0
package/styles.css
ADDED
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
/* @visuno/angular design tokens — self-contained.
|
|
2
|
+
* Dark mode: <html data-theme="dark"> Soft style: <html data-style="soft">
|
|
3
|
+
* Import once globally: @import '@visuno/angular/styles.css';
|
|
4
|
+
*/
|
|
5
|
+
/* Visuno shared core: tokens for Blueprint (default) and Soft (data-style="soft" on <html> or on any element around the components), light and dark (<html data-theme="dark">) */
|
|
6
|
+
:where([data-c]) [hidden]{display:none!important}
|
|
7
|
+
/* hold(): an end state centred in the height its component had */
|
|
8
|
+
.held{display:flex;flex-direction:column;justify-content:center}
|
|
9
|
+
/* the glide starts fast in both styles, so the field is on its way up before an opening list reaches the stage's edge */
|
|
10
|
+
.glide{transform:translateY(var(--vo-gy,0px));transition:transform var(--vo-t) cubic-bezier(.22,1,.36,1)}
|
|
11
|
+
/* and a list that opens under a gliding field fades in a beat after it starts to move */
|
|
12
|
+
.glide>.csx-pop.open{transition-delay:.08s}
|
|
13
|
+
.glide>.msc-pop.open{transition-delay:.08s,.08s,.08s,0s}
|
|
14
|
+
/* Soft 2: one quiet surface per object, grey type for finished work, motion only on what is happening now */
|
|
15
|
+
:root,[data-style="soft"]{
|
|
16
|
+
--vo-motion:soft;
|
|
17
|
+
--vo-page:#f7f7f7; --vo-stage:#fafafa; --vo-surface:#ffffff; --vo-raised:#ffffff;
|
|
18
|
+
--vo-fg:#171717; --vo-fg2:#525252; --vo-muted:#6a6a6a; --vo-faint:#c4c4c4; --vo-rail:#d4d4d4; --vo-line:#e8e8e8; --vo-field-line:#d4d4d4; --vo-line-strong:#858585; --vo-field-line-strong:#b3b3b3;
|
|
19
|
+
--vo-chip:#f3f3f3; --vo-hover:#ebebeb; --vo-press:#e3e3e3; --vo-wash:#f9f9f9; --vo-row:#fafafa;
|
|
20
|
+
--vo-soft:#ececec; --vo-soft-h:#e3e3e3; --vo-soft-ring:inset 0 0 0 1px rgba(0,0,0,.03),inset 0 1px 0 rgba(255,255,255,.7); --vo-dis:#a6a6a6;
|
|
21
|
+
/* disabled: text and icons take --vo-dis; a control with a fill swaps it for --vo-dis-fill (Blueprint hatches it) */
|
|
22
|
+
--vo-dis-fill:var(--vo-soft); --vo-dis-hatch:none;
|
|
23
|
+
--vo-shadow-lift:0 0 0 1px rgba(0,0,0,.05),0 2px 4px rgba(0,0,0,.04),0 16px 32px -10px rgba(0,0,0,.16);
|
|
24
|
+
/* the accent has three roles: --vo-accent fills (with --vo-on-accent on top, 4.5:1), --vo-accent-fg is text and icons in the accent
|
|
25
|
+
(4.5:1 on the surface, and on the chips and tints it sits on) and --vo-accent-mark is lines, rings and chart marks (3:1). A
|
|
26
|
+
light accent like lime keeps its fills and gets a darker mark and ink-coloured text on a light page */
|
|
27
|
+
--vo-accent:#116ff8; --vo-on-accent:#ffffff; --vo-accent-fg:#0f5fd5; --vo-accent-mark:#116ff8; --vo-sel:color-mix(in srgb,var(--vo-accent) 6%,transparent);
|
|
28
|
+
/* fields (text fields, textareas, search fields, dropdown triggers) have a dimmed grey edge, --vo-field-line, that steps up
|
|
29
|
+
a little, to --vo-field-line-strong, while they have the focus. The keyboard's focus ring on every other control is 2px of
|
|
30
|
+
a stronger grey (--vo-line-strong, as --vo-focus), as an outline offset 2px, or as a 2px box-shadow ring where an outline would be clipped. Never
|
|
31
|
+
the accent and never black, and only from the keyboard (:focus-visible), so a click or a tap never shows one */
|
|
32
|
+
--vo-focus:var(--vo-line-strong);
|
|
33
|
+
--vo-ink:#1b1b1b; --vo-on-ink:#ffffff;
|
|
34
|
+
--vo-ok:#0a7034; --vo-ok-bg:#cff5db; --vo-ok-mark:#4cbb17; --vo-warn:#9a4704; --vo-warn-bg:#ffe5b8; --vo-warn-mark:#f76700; --vo-bad:#b81d23; --vo-bad-bg:#ffe8e8;
|
|
35
|
+
--vo-merge:#7c4cd4; --vo-merge-bg:#f2ecfd; --vo-add:#187633; --vo-del:#c7212c;
|
|
36
|
+
--vo-pb:#1460d0; --vo-pb-bg:#eaf2ff; --vo-pl:#6b47d6; --vo-pl-bg:#f2edff; --vo-pm:#10754a; --vo-pm-bg:#e7f8f0; --vo-pp:#994c0b; --vo-pp-bg:#fff2e6;
|
|
37
|
+
--vo-pr:#bf314d; --vo-pr-bg:#ffeef1; --vo-py:#856404; --vo-py-bg:#fffae3; --vo-pk:#b92e75; --vo-pk-bg:#fff0f7; --vo-pt:#0e747d; --vo-pt-bg:#e6f9fa;
|
|
38
|
+
/* avatars have colours of their own, the same in every style and theme: a bright fill and the initials' ink on it (4.5:1,
|
|
39
|
+
APCA Lc 60). Blue, violet, red and pink are deep enough for white; green, teal, yellow and orange are too light for white
|
|
40
|
+
and take a dark ink of their own hue. An avatar given one of these, var(--vo-av-l), takes its ink, var(--vo-av-l-ink), on its own */
|
|
41
|
+
--vo-av-b:#126fe6; --vo-av-b-ink:#ffffff; --vo-av-l:#834ff5; --vo-av-l-ink:#ffffff; --vo-av-r:#d73341; --vo-av-r-ink:#ffffff; --vo-av-k:#cf3288; --vo-av-k-ink:#ffffff;
|
|
42
|
+
--vo-av-m:#27cf86; --vo-av-m-ink:#052616; --vo-av-t:#28c9d8; --vo-av-t-ink:#042428; --vo-av-y:#e9ac1a; --vo-av-y-ink:#2a1d03; --vo-av-p:#fda154; --vo-av-p-ink:#301804;
|
|
43
|
+
--vo-ts:#2c6cb2; --vo-react:#0a738b;
|
|
44
|
+
/* every raised surface carries its own hairline edge, so nothing needs a separate ring */
|
|
45
|
+
/* soft, layered shadows: a hairline, a contact shadow and two wide, faint ones, with a faint highlight on the top edge */
|
|
46
|
+
--vo-shadow:0 0 0 1px rgba(0,0,0,.03),0 1px 1px rgba(0,0,0,.025),0 2px 4px -1px rgba(0,0,0,.03),0 8px 16px -6px rgba(0,0,0,.05),0 20px 36px -14px rgba(0,0,0,.08),inset 0 1px 0 rgba(255,255,255,.75);
|
|
47
|
+
--vo-shadow-pop:0 0 0 1px rgba(0,0,0,.035),0 1px 2px rgba(0,0,0,.03),0 4px 10px -4px rgba(0,0,0,.05),0 14px 28px -10px rgba(0,0,0,.08),0 32px 56px -24px rgba(0,0,0,.12),inset 0 1px 0 rgba(255,255,255,.75);
|
|
48
|
+
--vo-shadow-toast:0 0 0 1px rgba(0,0,0,.03),0 4px 12px rgba(0,0,0,.08);
|
|
49
|
+
--vo-hl:#fdeb9a; --vo-hl-ok:#d3f1df;
|
|
50
|
+
/* Soft is plush: every corner is scaled by --vo-rk, and larger still where the browser draws true squircles (below) */
|
|
51
|
+
--vo-rk:1.25;
|
|
52
|
+
--vo-r-card:calc(16px * var(--vo-rk));
|
|
53
|
+
/* spacing runs on a 4px scale, and corners on a small set of radii; values off the scale are still written out */
|
|
54
|
+
--vo-s-1:4px; --vo-s-2:8px; --vo-s-3:12px; --vo-s-4:16px; --vo-s-5:20px; --vo-s-6:24px; --vo-s-8:32px; --vo-r-xs:calc(4px * var(--vo-rk)); --vo-r-lg:calc(20px * var(--vo-rk)); --vo-r-in:calc(12px * var(--vo-rk)); --vo-r-sm:calc(8px * var(--vo-rk)); --vo-r-pill:999px;
|
|
55
|
+
/* fields and tags have slightly rounded corners, never pills: --vo-r-field for one-line fields and dropdown triggers, --vo-r-box
|
|
56
|
+
for boxes you write several lines in, --vo-r-tag for tags. Where the browser smooths corners (corner-shape: squircle) a
|
|
57
|
+
corner looks smaller, so each takes the larger -sq radius there to look the same size. Fields share one height and,
|
|
58
|
+
where a component is a single field, one width */
|
|
59
|
+
--vo-r-field:10px; --vo-r-field-sq:16px; --vo-r-box:14px; --vo-r-box-sq:22px; --vo-r-tag:7px; --vo-r-tag-sq:12px;
|
|
60
|
+
--vo-field-h:40px; --vo-field-w:320px;
|
|
61
|
+
--vo-sans:"Inter",ui-sans-serif,system-ui,-apple-system,"Segoe UI",sans-serif;
|
|
62
|
+
--vo-mono:"JetBrains Mono",ui-monospace,SFMono-Regular,Menlo,monospace;
|
|
63
|
+
--vo-ease:cubic-bezier(.22,1,.36,1); --vo-ease-io:cubic-bezier(.65,0,.35,1);
|
|
64
|
+
--vo-t-fast:.22s; --vo-t:.45s; --vo-t-slow:.7s;
|
|
65
|
+
}
|
|
66
|
+
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]),:root:not([data-theme="light"]) [data-style="soft"]{
|
|
67
|
+
--vo-page:#111111; --vo-stage:#1c1c1c; --vo-surface:#262626; --vo-raised:#2c2c2c;
|
|
68
|
+
--vo-fg:#f2f2f2; --vo-fg2:#c9c9c9; --vo-muted:#c0c0c0; --vo-faint:#555555; --vo-rail:#414141; --vo-line:#333333; --vo-field-line:#424242; --vo-line-strong:#808080; --vo-field-line-strong:#808080;
|
|
69
|
+
--vo-chip:#303030; --vo-hover:#373737; --vo-press:#3f3f3f; --vo-wash:#2c2c2c; --vo-row:color-mix(in srgb,var(--vo-fg) 5.5%,transparent);
|
|
70
|
+
--vo-soft:#323232; --vo-soft-h:#3a3a3a; --vo-soft-ring:inset 0 0 0 1px rgba(255,255,255,.035),inset 0 1px 0 rgba(255,255,255,.05); --vo-dis:#737373;
|
|
71
|
+
--vo-shadow-lift:0 0 0 1px rgba(255,255,255,.08),0 2px 4px rgba(0,0,0,.3),0 16px 32px -10px rgba(0,0,0,.6);
|
|
72
|
+
--vo-accent:#116ff8; --vo-on-accent:#ffffff; --vo-accent-fg:#9dc4ff; --vo-accent-mark:#3d8bff; --vo-sel:color-mix(in srgb,var(--vo-accent) 9%,transparent);
|
|
73
|
+
--vo-ink:#f2f2f2; --vo-on-ink:#161616;
|
|
74
|
+
--vo-ok:#4ee28a; --vo-ok-bg:rgba(34,214,110,.2); --vo-ok-mark:#4cbb17; --vo-warn:#ffc247; --vo-warn-bg:rgba(255,184,40,.2); --vo-warn-mark:#ffa940; --vo-bad:#ff8a8a; --vo-bad-bg:rgba(255,90,90,.14);
|
|
75
|
+
--vo-merge:#cbb8ff; --vo-merge-bg:rgba(169,139,255,.15); --vo-add:#63d998; --vo-del:#ffa9ae;
|
|
76
|
+
--vo-pb:#a0c5ff; --vo-pb-bg:rgba(90,150,255,.18); --vo-pl:#cbb9ff; --vo-pl-bg:rgba(155,125,255,.18); --vo-pm:#6ad9a7; --vo-pm-bg:rgba(70,205,150,.16); --vo-pp:#ffb57a; --vo-pp-bg:rgba(255,155,80,.17);
|
|
77
|
+
--vo-pr:#ffadbb; --vo-pr-bg:rgba(255,105,130,.17); --vo-py:#f0cd5a; --vo-py-bg:rgba(240,200,60,.15); --vo-pk:#ffa8d4; --vo-pk-bg:rgba(255,100,175,.16); --vo-pt:#5fd8df; --vo-pt-bg:rgba(60,200,210,.16);
|
|
78
|
+
--vo-ts:#8fbcff; --vo-react:#3dd0ee;
|
|
79
|
+
--vo-shadow:0 0 0 1px rgba(255,255,255,.045),0 1px 2px rgba(0,0,0,.28),0 6px 14px -6px rgba(0,0,0,.36),0 20px 36px -14px rgba(0,0,0,.45),inset 0 1px 0 rgba(255,255,255,.06); --vo-shadow-pop:0 0 0 1px rgba(255,255,255,.055),0 2px 4px rgba(0,0,0,.3),0 12px 24px -8px rgba(0,0,0,.45),0 32px 56px -20px rgba(0,0,0,.55),inset 0 1px 0 rgba(255,255,255,.07); --vo-shadow-toast:0 0 0 1px rgba(255,255,255,.05),0 4px 12px rgba(0,0,0,.4); --vo-hl:rgba(240,200,60,.3); --vo-hl-ok:rgba(60,207,126,.24); color-scheme:dark}}
|
|
80
|
+
:root[data-theme="dark"],:root[data-theme="dark"] [data-style="soft"]{
|
|
81
|
+
--vo-page:#111111; --vo-stage:#1c1c1c; --vo-surface:#262626; --vo-raised:#2c2c2c;
|
|
82
|
+
--vo-fg:#f2f2f2; --vo-fg2:#c9c9c9; --vo-muted:#c0c0c0; --vo-faint:#555555; --vo-rail:#414141; --vo-line:#333333; --vo-field-line:#424242; --vo-line-strong:#808080; --vo-field-line-strong:#808080;
|
|
83
|
+
--vo-chip:#303030; --vo-hover:#373737; --vo-press:#3f3f3f; --vo-wash:#2c2c2c; --vo-row:color-mix(in srgb,var(--vo-fg) 5.5%,transparent);
|
|
84
|
+
--vo-soft:#323232; --vo-soft-h:#3a3a3a; --vo-soft-ring:inset 0 0 0 1px rgba(255,255,255,.035),inset 0 1px 0 rgba(255,255,255,.05); --vo-dis:#737373;
|
|
85
|
+
--vo-shadow-lift:0 0 0 1px rgba(255,255,255,.08),0 2px 4px rgba(0,0,0,.3),0 16px 32px -10px rgba(0,0,0,.6);
|
|
86
|
+
--vo-accent:#116ff8; --vo-on-accent:#ffffff; --vo-accent-fg:#9dc4ff; --vo-accent-mark:#3d8bff; --vo-sel:color-mix(in srgb,var(--vo-accent) 9%,transparent);
|
|
87
|
+
--vo-ink:#f2f2f2; --vo-on-ink:#161616;
|
|
88
|
+
--vo-ok:#4ee28a; --vo-ok-bg:rgba(34,214,110,.2); --vo-ok-mark:#4cbb17; --vo-warn:#ffc247; --vo-warn-bg:rgba(255,184,40,.2); --vo-warn-mark:#ffa940; --vo-bad:#ff8a8a; --vo-bad-bg:rgba(255,90,90,.14);
|
|
89
|
+
--vo-merge:#cbb8ff; --vo-merge-bg:rgba(169,139,255,.15); --vo-add:#63d998; --vo-del:#ffa9ae;
|
|
90
|
+
--vo-pb:#a0c5ff; --vo-pb-bg:rgba(90,150,255,.18); --vo-pl:#cbb9ff; --vo-pl-bg:rgba(155,125,255,.18); --vo-pm:#6ad9a7; --vo-pm-bg:rgba(70,205,150,.16); --vo-pp:#ffb57a; --vo-pp-bg:rgba(255,155,80,.17);
|
|
91
|
+
--vo-pr:#ffadbb; --vo-pr-bg:rgba(255,105,130,.17); --vo-py:#f0cd5a; --vo-py-bg:rgba(240,200,60,.15); --vo-pk:#ffa8d4; --vo-pk-bg:rgba(255,100,175,.16); --vo-pt:#5fd8df; --vo-pt-bg:rgba(60,200,210,.16);
|
|
92
|
+
--vo-ts:#8fbcff; --vo-react:#3dd0ee;
|
|
93
|
+
--vo-shadow:0 0 0 1px rgba(255,255,255,.045),0 1px 2px rgba(0,0,0,.28),0 6px 14px -6px rgba(0,0,0,.36),0 20px 36px -14px rgba(0,0,0,.45),inset 0 1px 0 rgba(255,255,255,.06); --vo-shadow-pop:0 0 0 1px rgba(255,255,255,.055),0 2px 4px rgba(0,0,0,.3),0 12px 24px -8px rgba(0,0,0,.45),0 32px 56px -20px rgba(0,0,0,.55),inset 0 1px 0 rgba(255,255,255,.07); --vo-shadow-toast:0 0 0 1px rgba(255,255,255,.05),0 4px 12px rgba(0,0,0,.4); --vo-hl:rgba(240,200,60,.3); --vo-hl-ok:rgba(60,207,126,.24); color-scheme:dark}
|
|
94
|
+
|
|
95
|
+
/* the accent's hover fill (--vo-accent-2) and tint (--vo-accent-bg) are worked out from the accent, in every style and theme, so a
|
|
96
|
+
picked accent brings its own. Hovering a filled button moves its fill away from its text colour: darker under white text,
|
|
97
|
+
lighter under dark text, so the label keeps its contrast in every style, theme and accent */
|
|
98
|
+
:root,[data-style="soft"]{--vo-accent-2:color-mix(in srgb,var(--vo-accent) 86%,#000);--vo-accent-bg:color-mix(in srgb,var(--vo-accent) 9%,transparent)}
|
|
99
|
+
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]),:root:not([data-theme="light"]) [data-style="soft"]{--vo-accent-2:color-mix(in srgb,var(--vo-accent) 84%,#fff);--vo-accent-bg:color-mix(in srgb,var(--vo-accent) 13%,transparent)}}
|
|
100
|
+
:root[data-theme="dark"],:root[data-theme="dark"] [data-style="soft"]{--vo-accent-2:color-mix(in srgb,var(--vo-accent) 84%,#fff);--vo-accent-bg:color-mix(in srgb,var(--vo-accent) 13%,transparent)}
|
|
101
|
+
@supports (color:rgb(from red r g b)){:root,[data-style="soft"],:root:not([data-theme="light"]),:root:not([data-theme="light"]) [data-style="soft"],:root[data-theme="dark"],:root[data-theme="dark"] [data-style="soft"]{--vo-accent-2:color-mix(in srgb,var(--vo-accent) 86%,rgb(from var(--vo-on-accent) calc(255 - r) calc(255 - g) calc(255 - b)))}}
|
|
102
|
+
@supports not (color:rgb(from red r g b)){:root,[data-style="soft"],:root:not([data-theme="light"]),:root:not([data-theme="light"]) [data-style="soft"],:root[data-theme="dark"],:root[data-theme="dark"] [data-style="soft"]{--vo-accent-2:color-mix(in srgb,var(--vo-accent) 86%,#000)}:root:not([data-style="soft"]),:root:not([data-style="soft"]):not([data-theme="light"]),:root:not([data-style="soft"])[data-theme="dark"]{--vo-accent-2:color-mix(in srgb,var(--vo-accent) 86%,#fff)}}
|
|
103
|
+
/* picked things (chips, options, cards in a picker) are white tiles with a dimmed grey edge, and the picked one's edge
|
|
104
|
+
is a light step stronger, never a dark or black outline */
|
|
105
|
+
:root,[data-style="soft"]{--vo-pick-line:var(--vo-rail);--vo-pick-on:var(--vo-faint)}
|
|
106
|
+
|
|
107
|
+
/* Soft is plush: corners are drawn as squircles where the browser can (corner-shape), and since a squircle's corner
|
|
108
|
+
reads smaller than a round one of the same radius, the radii grow with it. Circles (spinners, loader rings, avatars,
|
|
109
|
+
dots) stay round; pills, chips, buttons and switchers are squircles too. Blueprint stays square (its corners are 0) */
|
|
110
|
+
@supports (corner-shape:squircle){
|
|
111
|
+
:root,[data-style="soft"]{--vo-rk:1.7}
|
|
112
|
+
:root:not([data-style="soft"]){--vo-rk:1}
|
|
113
|
+
:where([data-c]) *,:where([data-c]) *::before,:where([data-c]) *::after{corner-shape:squircle}
|
|
114
|
+
.acx-n .s,.afx-pen,.afx-r b,.agx-now i,.alg-ph-pg,.alg-sc-knob,.alg-sc-ld,.alg-sc-n,.aln-cw-tr b,.aln-pk,.asx-lp-stop,.asx-lp-th,.asx-lp-th i,.asx-tb-dot,.atx-cmp-ok,.atx-cmp-send,.atx-cmp-x,.av,.bdg-dot,.bdg-x,.bdg-x:focus-visible,.btx-live,.bws-dots i,.ccx-fl .flag,.ccx-sw,.cmx-go,.cmx-pin,.cpx-att .fchip .rt,.cpx-att .fchip .x,.cpx-dot,.cpx-send,.ctb-n .s,.dot,.drv-ag,.drv-ring,.dtx-sl .k,.ecx-days b,.ecx-dh.t b,.erx-o i,.evr-dot,.evr-jg-arc .tr,.evr-jg-arc i,.fxp-n .ag,.hox-av,.ib,.lcx-ring,.lnx-k i,.lnx-pt,.mix-dot,.msc-c button,.ntx-n .u,.obx .obx-rw .obx-rk,.obx-ck,.obx-rk,.plx-s .n,.psx-go,.pulse,.rq-wk-c .rq-ic,.rq-wk-ring .h i,.rq-wk-ring .tr,.rq-wk-stack i,.rsu-g,.rsu-rc-nd,.rsu-rc-ok,.rsu-rc-ok i,.rsu-rp-ok,.rxx-add,.sgc-wr .e i,.spin,.ssx-ics span,.ste-go,.stx-conf i.d,.stx-st .n,.tcx[data-d="inline"] .tcb-wire i,.think i,.thp-send,.thp[data-d] .tpx-dots i,.thp[data-d] .tpx-send,.thp[data-d] .tpx-st,.tk-st .mk,.tsk-c .g,.tst-t .g,.ttp-av,.vcx-dot,.vor .vor-orb i,.vor-dot,.vor-gl,.vor-orb i,.cxm-av,.crs-dots button,.rdx-lg i,.scx-lg i.c,.cvq-lg i.c,.rgx-r i,.cpk-k,.wsx-marks span,.igx-steps i,.ths-dg i,.ths-mtx i{corner-shape:round}
|
|
115
|
+
.aln-det div::before{corner-shape:round}
|
|
116
|
+
.asx-lp-rg::-moz-range-thumb{corner-shape:round}
|
|
117
|
+
.asx-lp-rg::-webkit-slider-thumb{corner-shape:round}
|
|
118
|
+
.btx-live::after{corner-shape:round}
|
|
119
|
+
.dpk-d.t::after{corner-shape:round}
|
|
120
|
+
.ecx-now::before{corner-shape:round}
|
|
121
|
+
.fxp-tree::-webkit-scrollbar-thumb{corner-shape:round}
|
|
122
|
+
.hand::before{corner-shape:round}
|
|
123
|
+
.hnx-t .ic::after{corner-shape:round}
|
|
124
|
+
.ksx-s .ic::after{corner-shape:round}
|
|
125
|
+
.pulse::after{corner-shape:round}
|
|
126
|
+
.radar::after{corner-shape:round}
|
|
127
|
+
.radar::before{corner-shape:round}
|
|
128
|
+
.sgc-mo .d.e::after{corner-shape:round}
|
|
129
|
+
.shx-r .ic::after{corner-shape:round}
|
|
130
|
+
.stx-ok::after{corner-shape:round}
|
|
131
|
+
.tmx-body::-webkit-scrollbar-thumb{corner-shape:round}
|
|
132
|
+
.toggle::after{corner-shape:round}
|
|
133
|
+
.afx-desk::before{corner-shape:round}
|
|
134
|
+
}
|
|
135
|
+
/* ---------- page shell ---------- */
|
|
136
|
+
:where([data-c]) *{box-sizing:border-box}
|
|
137
|
+
:where([data-c]) button,:where([data-c]) input,:where([data-c]) textarea,:where([data-c]) select{font:inherit;color:inherit}
|
|
138
|
+
:where([data-c]) button{background:none;border:0;padding:0;cursor:pointer}
|
|
139
|
+
/* one weight for emphasis: medium, never bold */
|
|
140
|
+
:where([data-c]) b,:where([data-c]) strong{font-weight:500}
|
|
141
|
+
:where([data-c]) :focus-visible{outline:2px solid var(--vo-focus);outline-offset:2px;border-radius:calc(6px * var(--vo-rk))}
|
|
142
|
+
/* a field shows the focus with its own edge, which steps up to --vo-field-line-strong, so it never takes the ring as well */
|
|
143
|
+
:where([data-c]) :focus-visible:is(input:not([type="checkbox"],[type="radio"],[type="range"],[type="file"],[type="button"],[type="submit"],[type="reset"]),textarea,select,[contenteditable]:not([contenteditable="false"])){outline:0}
|
|
144
|
+
.stage-in{width:100%;max-width:440px;min-width:0;position:relative;container-type:inline-size}
|
|
145
|
+
.card.wide .stage-in{max-width:720px}
|
|
146
|
+
|
|
147
|
+
/* ---------- icons ---------- */
|
|
148
|
+
.i{width:16px;height:16px;flex:none;display:inline-block;vertical-align:-3px;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
|
|
149
|
+
.i.s{width:14px;height:14px}.i.xs{width:12px;height:12px}.i.l{width:18px;height:18px}
|
|
150
|
+
.brand{width:16px;height:16px;display:block;flex:none}
|
|
151
|
+
.flag{width:20px;height:15px;border-radius:3px;object-fit:cover;display:block;flex:none;box-shadow:0 0 0 1px rgba(0,0,0,.08)}
|
|
152
|
+
|
|
153
|
+
/* ---------- primitives ---------- */
|
|
154
|
+
.mono{font-family:var(--vo-mono)}
|
|
155
|
+
.sp{flex:1}
|
|
156
|
+
.num{font-variant-numeric:tabular-nums}
|
|
157
|
+
.muted{color:var(--vo-muted)}.fg2{color:var(--vo-fg2)}
|
|
158
|
+
.panel{background:var(--vo-surface);border-radius:var(--vo-r-card);box-shadow:var(--vo-shadow);position:relative}
|
|
159
|
+
.ib{width:30px;height:30px;border-radius:50%;display:inline-grid;place-items:center;color:var(--vo-fg2);transition:background var(--vo-t-fast),color var(--vo-t-fast),transform .15s}
|
|
160
|
+
@media (hover:hover) and (pointer:fine){.ib:hover{background:var(--vo-row);color:var(--vo-fg)}}
|
|
161
|
+
.ib:active{transform:scale(.94)}
|
|
162
|
+
.ib.fill{background:var(--vo-soft);box-shadow:var(--vo-soft-ring)}
|
|
163
|
+
@media (hover:hover) and (pointer:fine){.ib.fill:hover{background:var(--vo-soft-h)}}
|
|
164
|
+
.ib.on{background:var(--vo-accent-bg);color:var(--vo-accent-fg,var(--vo-accent))}
|
|
165
|
+
.chip{display:inline-flex;align-items:center;gap:6px;height:30px;padding:0 var(--vo-s-3);border-radius:var(--vo-r-pill);font-size:13px;color:var(--vo-fg2);background:var(--vo-chip);white-space:nowrap;transition:background var(--vo-t-fast),color var(--vo-t-fast),box-shadow var(--vo-t-fast)}
|
|
166
|
+
@media (hover:hover) and (pointer:fine){.chip:hover{background:var(--vo-hover);color:var(--vo-fg)}}
|
|
167
|
+
.chip.on{background:var(--vo-surface);color:var(--vo-fg);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--vo-pick-on) 50%,transparent)}
|
|
168
|
+
.chip.sm{height:24px;padding:0 9px;font-size:12px}
|
|
169
|
+
.pill{display:inline-flex;align-items:center;justify-content:center;gap:7px;height:32px;padding:0 14px;border-radius:var(--vo-r-pill);font-size:13px;font-weight:500;white-space:nowrap;transition:background var(--vo-t-fast),color var(--vo-t-fast),opacity var(--vo-t-fast),transform .15s}
|
|
170
|
+
.pill:active{transform:scale(.97)}
|
|
171
|
+
/* the primary action is the accent, with --vo-on-accent on it, so it follows the accent and stays readable in any colour */
|
|
172
|
+
.pill.primary{background:var(--vo-accent);color:var(--vo-on-accent)}
|
|
173
|
+
@media (hover:hover) and (pointer:fine){.pill.primary:hover{background:var(--vo-accent-2)}}
|
|
174
|
+
.pill.accent{background:var(--vo-accent);color:var(--vo-on-accent)}
|
|
175
|
+
.pill.accent.hl{background:var(--vo-accent-2)}
|
|
176
|
+
@media (hover:hover) and (pointer:fine){.pill.accent:hover{background:var(--vo-accent-2)}}
|
|
177
|
+
.pill.soft{background:var(--vo-soft);color:var(--vo-fg);box-shadow:var(--vo-soft-ring)}
|
|
178
|
+
@media (hover:hover) and (pointer:fine){.pill.soft:hover{background:var(--vo-soft-h)}}
|
|
179
|
+
.pill.line{background:var(--vo-surface);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--vo-line) 50%,transparent);color:var(--vo-fg)}
|
|
180
|
+
.pill.ghost{color:var(--vo-fg2)}@media (hover:hover) and (pointer:fine){.pill.ghost:hover{background:var(--vo-row);color:var(--vo-fg)}}
|
|
181
|
+
/* one disabled look for every control: nothing fades; its text and icons take --vo-dis, a control with a fill swaps the fill
|
|
182
|
+
for --vo-dis-fill with its quiet edge (hatched in Blueprint), one without keeps no fill, and the pointer says not-allowed */
|
|
183
|
+
.pill[disabled]{opacity:1;color:var(--vo-dis);background:none;cursor:not-allowed;transform:none}
|
|
184
|
+
@media (hover:hover) and (pointer:fine){.pill[disabled]:hover{opacity:1;color:var(--vo-dis);background:none;cursor:not-allowed;transform:none}}
|
|
185
|
+
:where([data-c]) button:disabled{cursor:not-allowed}
|
|
186
|
+
.pill:is(.accent,.primary,.soft,.line)[disabled]{background:var(--vo-dis-hatch),var(--vo-dis-fill);color:var(--vo-dis);box-shadow:var(--vo-soft-ring)}
|
|
187
|
+
@media (hover:hover) and (pointer:fine){.pill:is(.accent,.primary,.soft,.line)[disabled]:hover{background:var(--vo-dis-hatch),var(--vo-dis-fill);color:var(--vo-dis);box-shadow:var(--vo-soft-ring)}}
|
|
188
|
+
.pill[disabled] .kbd{background:var(--vo-chip);color:inherit}
|
|
189
|
+
.pill.sm{height:28px;padding:0 11px;font-size:12.5px}
|
|
190
|
+
.tag{display:inline-flex;align-items:center;gap:5px;height:20px;padding:0 7px;border-radius:var(--vo-r-tag);font-size:11.5px;font-weight:500;white-space:nowrap;background:var(--vo-chip);color:var(--vo-fg2)}
|
|
191
|
+
.tag.b{background:var(--vo-pb-bg);color:var(--vo-pb)}.tag.l{background:var(--vo-pl-bg);color:var(--vo-pl)}.tag.m{background:var(--vo-pm-bg);color:var(--vo-pm)}.tag.p{background:var(--vo-pp-bg);color:var(--vo-pp)}
|
|
192
|
+
.tag.r{background:var(--vo-pr-bg);color:var(--vo-pr)}.tag.y{background:var(--vo-py-bg);color:var(--vo-py)}.tag.k{background:var(--vo-pk-bg);color:var(--vo-pk)}.tag.t{background:var(--vo-pt-bg);color:var(--vo-pt)}
|
|
193
|
+
.tag.ok{background:var(--vo-ok-bg);color:var(--vo-ok)}.tag.warn{background:var(--vo-warn-bg);color:var(--vo-warn)}.tag.bad{background:var(--vo-bad-bg);color:var(--vo-bad)}
|
|
194
|
+
@supports (corner-shape:squircle){.tag{corner-shape:squircle;border-radius:var(--vo-r-tag-sq)}}
|
|
195
|
+
.dot{width:6px;height:6px;border-radius:50%;background:currentColor;flex:none;display:inline-block}
|
|
196
|
+
.fchip{display:inline-flex;align-items:center;gap:6px;height:26px;padding:0 10px 0 var(--vo-s-2);border-radius:var(--vo-r-pill);background:var(--vo-surface);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--vo-line) 50%,transparent);font-size:12.5px;color:var(--vo-fg);white-space:nowrap}
|
|
197
|
+
.fchip.lnk{cursor:pointer;transition:background var(--vo-t-fast),box-shadow var(--vo-t-fast)}
|
|
198
|
+
@media (hover:hover) and (pointer:fine){.fchip.lnk:hover{background:var(--vo-row);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--vo-rail) 50%,transparent)}}
|
|
199
|
+
.ft{font-family:var(--vo-sans);font-size:9.5px;font-weight:500;color:var(--vo-ts);letter-spacing:.02em}
|
|
200
|
+
.ft.re{color:var(--vo-react)}.ft.fg{color:var(--vo-pl)}.ft.pdf{color:var(--vo-pr)}.ft.csv{color:var(--vo-pm)}
|
|
201
|
+
.kbd{font-family:inherit;font-size:11px;padding:1px 5px;border-radius:5px;background:var(--vo-chip);color:var(--vo-fg2)}
|
|
202
|
+
/* on a row that is hovered, highlighted or picked, the row turns grey, so its shortcut chips turn white to stay visible */
|
|
203
|
+
@media (hover:hover) and (pointer:fine){:is(.mi,.cpl-i,[role="option"],[role="menuitem"],[role="menuitemradio"],[role="menuitemcheckbox"]):is(:hover,.hl,.on,[aria-selected="true"]) .kbd{background:var(--vo-surface)}}
|
|
204
|
+
@media (hover:hover) and (pointer:fine){.pill.ghost:hover .kbd{background:var(--vo-surface)}}
|
|
205
|
+
.pill .kbd{display:inline-grid;place-items:center;min-width:18px;height:18px;padding:0 var(--vo-s-1);margin-right:-6px}
|
|
206
|
+
/* a key hint on a filled button sits on a slightly darker well of the fill, so white text keeps its contrast */
|
|
207
|
+
.pill.primary .kbd,.pill.accent .kbd{background:color-mix(in srgb,var(--vo-accent) 80%,#000);color:inherit}
|
|
208
|
+
code.c{font-family:var(--vo-mono);font-size:12.5px;background:var(--vo-chip);padding:1px 5px;border-radius:5px}
|
|
209
|
+
.av{width:22px;height:22px;border-radius:50%;display:inline-grid;place-items:center;font-size:10px;font-weight:500;color:#fff;flex:none}
|
|
210
|
+
.hr{height:1px;background:var(--vo-line);border:0;margin:0}
|
|
211
|
+
/* an off switch and an empty box are drawn in a grey that holds 3:1 against the surface; an accent fill keeps a hairline of the
|
|
212
|
+
accent's mark, so a light accent like lime still has an edge */
|
|
213
|
+
.toggle{width:30px;height:18px;border-radius:calc(9px * var(--vo-rk));background:color-mix(in srgb,var(--vo-muted) 80%,var(--vo-surface));position:relative;flex:none;transition:background var(--vo-t-fast)}
|
|
214
|
+
.toggle::after{content:"";position:absolute;top:2px;left:2px;width:14px;height:14px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,.2);transition:transform var(--vo-t) var(--vo-ease)}
|
|
215
|
+
.toggle[aria-checked="true"]{background:var(--vo-accent);box-shadow:inset 0 0 0 1px var(--vo-accent-mark,var(--vo-accent))}
|
|
216
|
+
.toggle[aria-checked="true"]::after{transform:translateX(12px);background:var(--vo-on-accent)}
|
|
217
|
+
/* on a touch screen every control gets a tap area of at least 40px square, centred on it, without changing how it looks or
|
|
218
|
+
where anything sits: a clear ::before (or ::after, where a component draws with its ::before) over and around it. Where
|
|
219
|
+
two controls sit closer than that, the core script (fitHits) shrinks both areas evenly, so each tap still lands on the
|
|
220
|
+
control nearest to it. Everything here weighs nothing (:where), so a component's own position or pseudo-element wins.
|
|
221
|
+
The build checks that every selector drawing with a ::before or ::after is in the lists below */
|
|
222
|
+
@media (pointer:coarse){
|
|
223
|
+
:where([data-c]) :where(button,a[href],summary,[role="button"],[role="switch"],[role="checkbox"],[role="radio"],[role="tab"],[role="option"],[role="menuitem"],[role="menuitemradio"],[role="menuitemcheckbox"],[role="slider"],label:has(input[type="checkbox"],input[type="radio"])){position:relative;--vo-hit-w:40px;--vo-hit-h:40px}
|
|
224
|
+
:where([data-c]) :where(button,a[href],summary,[role="button"],[role="switch"],[role="checkbox"],[role="radio"],[role="tab"],[role="option"],[role="menuitem"],[role="menuitemradio"],[role="menuitemcheckbox"],[role="slider"],label:has(input[type="checkbox"],input[type="radio"])):not(:where(.radar,.hand,.rtr-li:not(:last-child),.atr-kids,.bws-nav b,.rc-cap,.erx-row:not(:last-child),.rte-body.empty,.rte-hint,.afx-desk,.dtx-sl,.crx-l.add .c,.crx-l.del .c,.crx-l.ctx .c,.crx-hk.kept .crx-l.add .c,.crx-hk.undone .crx-l.del .c,.ahx-bot,.ecx-now,.ssi-or,.cmx-th>.cmx-c:first-child:has(+ .cmx-rp),.cmx-rp,.aln-ct,.aln-rows>*,.aln-av,.aln-det div,.aln-pk,.trv-r[data-k="agent"] .trv-b i,.tk-st:not(:last-child),.tmx-blk,.atx-ic))::before,:where([data-c]) :where(button,a[href],summary,[role="button"],[role="switch"],[role="checkbox"],[role="radio"],[role="tab"],[role="option"],[role="menuitem"],[role="menuitemradio"],[role="menuitemcheckbox"],[role="slider"],label:has(input[type="checkbox"],input[type="radio"])):where(.radar,.hand,.rtr-li:not(:last-child),.atr-kids,.bws-nav b,.rc-cap,.erx-row:not(:last-child),.rte-body.empty,.rte-hint,.afx-desk,.dtx-sl,.crx-l.add .c,.crx-l.del .c,.crx-l.ctx .c,.crx-hk.kept .crx-l.add .c,.crx-hk.undone .crx-l.del .c,.ahx-bot,.ecx-now,.ssi-or,.cmx-th>.cmx-c:first-child:has(+ .cmx-rp),.cmx-rp):not(:where(.aln-lane,.trv-g i.el,.trv-r.run:not([data-k="agent"]) .trv-b i,.trv-r[data-k="agent"] .trv-b i,.trv-b,.trv-sc,.tk-st.done:not(:last-child),.tmx-h,.tmx.live .tmx-body,.atx-ic,.toggle,.radar,.pulse,.stl-track i,.stx-ok,.aln-tr i,.afx-card .afx-open,.plx-s.edited .t,.vor-mute,.mix-mk,.hnx-t .ic,.ksx-s .ic,.shx-r .ic,.dpk-d.t,.sgc-mo .d.e,.agx-now,.btx-ask,.btx-live,.ssi-or,.rxx-r,.bdg.live .bdg-dot,.thp[data-d="deck"] .tpb-card,.crs-pv,.crs-pic,.hmx-sc))::after{content:"";position:absolute;inset:min(0px,(100% - var(--vo-hit-h)) / 2) min(0px,(100% - var(--vo-hit-w)) / 2);--vo-hit:1}
|
|
225
|
+
}
|
|
226
|
+
.seg2{display:inline-flex;padding:2px;background:var(--vo-chip);border-radius:var(--vo-r-pill);position:relative}
|
|
227
|
+
.seg2 button{position:relative;z-index:1;height:26px;padding:0 11px;border-radius:var(--vo-r-pill);font-size:12.5px;color:var(--vo-fg2);transition:color var(--vo-t-fast)}
|
|
228
|
+
.seg2 button[aria-pressed="true"]{color:var(--vo-fg)}
|
|
229
|
+
.seg2 .knob{position:absolute;top:2px;bottom:2px;border-radius:var(--vo-r-pill);background:var(--vo-surface);box-shadow:0 1px 2px rgba(0,0,0,.08);transition:left var(--vo-t) var(--vo-ease),width var(--vo-t) var(--vo-ease)}
|
|
230
|
+
.seg2 button:focus-visible{outline-offset:-2px;border-radius:var(--vo-r-pill)}
|
|
231
|
+
/* demo stages: the component sits centred, the variant switcher sits at the foot of the stage under it */
|
|
232
|
+
.stage-in:has(>.dm){align-self:stretch;display:flex}
|
|
233
|
+
.dm{width:100%;min-height:328px;display:flex;flex-direction:column;align-items:center;gap:var(--vo-s-8)}
|
|
234
|
+
.dm>.vo-main{margin-block:auto;width:100%;display:flex;flex-direction:column;align-items:center}
|
|
235
|
+
.dm>.demo{flex:none;display:flex;justify-content:center}
|
|
236
|
+
|
|
237
|
+
.bub{align-self:flex-end;max-width:85%;background:var(--vo-hover);border-radius:var(--vo-r-card);padding:9px 13px;font-size:14px;line-height:1.45}
|
|
238
|
+
.msg{margin:0;font-size:14px;line-height:1.65}
|
|
239
|
+
|
|
240
|
+
/* ---------- status glyphs ---------- */
|
|
241
|
+
.spin{width:12px;height:12px;border-radius:50%;border:1.5px solid currentColor;border-right-color:transparent;animation:rot .8s linear infinite;flex:none;display:inline-block}
|
|
242
|
+
@keyframes rot{to{transform:rotate(360deg)}}
|
|
243
|
+
.radar{position:relative;width:13px;height:13px;flex:none;display:inline-block}
|
|
244
|
+
.radar::before{content:"";position:absolute;inset:3.5px;border-radius:50%;background:currentColor}
|
|
245
|
+
.radar::after{content:"";position:absolute;inset:0;border-radius:50%;border:1.3px solid currentColor;border-right-color:transparent;animation:rot .9s linear infinite}
|
|
246
|
+
/* the rotating thinking mark from Soft 1, four dots turning */
|
|
247
|
+
.think{width:14px;height:14px;position:relative;flex:none;display:inline-block}
|
|
248
|
+
.think i{position:absolute;width:3.4px;height:3.4px;border-radius:50%;background:currentColor;left:50%;top:50%;margin:-1.7px}
|
|
249
|
+
.think i:nth-child(1){transform:translate(-3.6px,-3.6px)}.think i:nth-child(2){transform:translate(3.6px,-3.6px)}.think i:nth-child(3){transform:translate(3.6px,3.6px)}.think i:nth-child(4){transform:translate(-3.6px,3.6px)}
|
|
250
|
+
.think.on{animation:thinkrot 1.6s var(--vo-ease-io) infinite}
|
|
251
|
+
.think.on i{animation:thinkpulse 1.6s var(--vo-ease-io) infinite}
|
|
252
|
+
.think.on i:nth-child(2){animation-delay:.2s}.think.on i:nth-child(3){animation-delay:.4s}.think.on i:nth-child(4){animation-delay:.6s}
|
|
253
|
+
@keyframes thinkrot{0%{transform:rotate(0)}50%{transform:rotate(90deg)}100%{transform:rotate(180deg)}}
|
|
254
|
+
@keyframes thinkpulse{0%,100%{opacity:1}50%{opacity:.35}}
|
|
255
|
+
/* the step that is happening now in a trace: a quiet grey dot with a soft ping */
|
|
256
|
+
.pulse{position:relative;width:6px;height:6px;border-radius:50%;background:var(--vo-muted);flex:none;display:inline-block}
|
|
257
|
+
.pulse::after{content:"";position:absolute;inset:0;border-radius:50%;background:inherit;animation:ping 1.8s var(--vo-ease) infinite}
|
|
258
|
+
@keyframes ping{0%{transform:scale(1);opacity:.45}80%,100%{transform:scale(2.8);opacity:0}}
|
|
259
|
+
|
|
260
|
+
/* ---------- motion ---------- */
|
|
261
|
+
.shim{background:linear-gradient(90deg,var(--vo-fg) 0%,var(--vo-fg) 38%,var(--vo-faint) 50%,var(--vo-fg) 62%,var(--vo-fg) 100%);background-size:260% 100%;-webkit-background-clip:text;background-clip:text;color:transparent;animation:shim 2.2s linear infinite}
|
|
262
|
+
@keyframes shim{from{background-position:100% 0}to{background-position:-160% 0}}
|
|
263
|
+
.enter{animation:enter var(--vo-t-slow) var(--vo-ease) backwards}
|
|
264
|
+
@keyframes enter{from{opacity:0;transform:translateY(6px);filter:blur(4px)}to{opacity:1;transform:none;filter:blur(0)}}
|
|
265
|
+
/* the person in a preview's story: a pointer that glides to what it uses and presses it */
|
|
266
|
+
.hand{position:absolute;left:0;top:0;width:18px;height:18px;z-index:30;pointer-events:none;opacity:0;color:var(--vo-fg);transition:transform .42s var(--vo-ease),opacity .16s;filter:drop-shadow(0 1px 1.5px rgba(0,0,0,.22))}
|
|
267
|
+
.hand.on{opacity:1}
|
|
268
|
+
.hand svg{display:block;width:18px;height:18px;transform-origin:3px 2px;transition:transform .16s var(--vo-ease)}
|
|
269
|
+
.hand svg path{fill:currentColor;stroke:var(--vo-surface);stroke-width:1.4;stroke-linejoin:round}
|
|
270
|
+
.hand.down svg{transform:scale(.82)}
|
|
271
|
+
.hand::before{content:"";position:absolute;left:-8px;top:-9px;width:22px;height:22px;border-radius:50%;background:var(--vo-accent);opacity:0;pointer-events:none}
|
|
272
|
+
.hand.down::before{animation:handtap .5s var(--vo-ease)}
|
|
273
|
+
@keyframes handtap{from{opacity:.3;transform:scale(.3)}to{opacity:0;transform:scale(1.3)}}
|
|
274
|
+
.pop-in{animation:popin .5s var(--vo-ease) backwards}
|
|
275
|
+
@keyframes popin{from{opacity:0;transform:scale(.96);filter:blur(3px)}to{opacity:1;transform:none;filter:blur(0)}}
|
|
276
|
+
.leave{animation:leave .35s var(--vo-ease) both}
|
|
277
|
+
@keyframes leave{to{opacity:0;transform:translateY(-6px);filter:blur(4px)}}
|
|
278
|
+
.sw{display:inline-block;transition:opacity .2s var(--vo-ease),filter .2s var(--vo-ease),transform .25s var(--vo-ease)}
|
|
279
|
+
.sw.out{opacity:0;filter:blur(3px);transform:translateY(3px)}
|
|
280
|
+
.fold{display:grid;grid-template-rows:1fr;transition:grid-template-rows var(--vo-t) var(--vo-ease),opacity var(--vo-t) var(--vo-ease)}
|
|
281
|
+
.fold>*{overflow:hidden;min-height:0}
|
|
282
|
+
/* shadows inside an open fold aren't cut off: the clip leaves room round its edge (a shut fold is invisible anyway) */
|
|
283
|
+
.fold{grid-template-columns:minmax(0,1fr)}
|
|
284
|
+
.fold>*{overflow:clip;overflow-clip-margin:12px;min-width:0}
|
|
285
|
+
/* a shut fold is hidden as well as clear once it has folded, so Tab passes over what is inside it */
|
|
286
|
+
.fold.shut{grid-template-rows:0fr;opacity:0;visibility:hidden;transition:grid-template-rows var(--vo-t) var(--vo-ease),opacity var(--vo-t) var(--vo-ease),visibility 0s var(--vo-t)}
|
|
287
|
+
|
|
288
|
+
/* ---------- tooltip and popover ---------- */
|
|
289
|
+
.tip{position:fixed;z-index:1000;pointer-events:none;background:var(--vo-ink);color:var(--vo-on-ink);font-size:12px;line-height:1.35;padding:6px 9px;border-radius:var(--vo-r-sm);max-width:240px;opacity:0;transform:translateY(4px);filter:blur(2px);transition:opacity .18s var(--vo-ease),transform .25s var(--vo-ease),filter .18s}
|
|
290
|
+
.tip.show{opacity:1;transform:none;filter:none}
|
|
291
|
+
.copied{color:var(--vo-ok)!important}
|
|
292
|
+
@media (hover:hover) and (pointer:fine){.copied:hover{color:var(--vo-ok)!important}}
|
|
293
|
+
.tip .kbd{background:rgba(255,255,255,.14);color:inherit;margin-left:6px}
|
|
294
|
+
:root[data-theme="dark"] .tip .kbd{background:rgba(0,0,0,.1)}
|
|
295
|
+
:root[data-theme="dark"] .ssx-ics span{color:#0d0d0d!important}
|
|
296
|
+
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]) .ssx-ics span{color:#0d0d0d!important}}
|
|
297
|
+
/* a closed popover is hidden as well as clear, so Tab and screen readers pass over it: it shows at once as it opens, so the
|
|
298
|
+
focus can go into it, and hides once it has faded out */
|
|
299
|
+
.pop{position:absolute;z-index:50;min-width:200px;background:var(--vo-raised);border-radius:calc(14px * var(--vo-rk));box-shadow:var(--vo-shadow-pop);padding:6px;opacity:0;visibility:hidden;pointer-events:none;transform:translateY(6px) scale(.98);transform-origin:var(--vo-origin,top left);filter:blur(3px);transition:opacity .2s var(--vo-ease),transform .35s var(--vo-ease),filter .2s var(--vo-ease),visibility 0s .2s}
|
|
300
|
+
.pop.open{opacity:1;visibility:visible;pointer-events:auto;transform:none;filter:none;transition-property:opacity,transform,filter}
|
|
301
|
+
.pop .ph{padding:6px var(--vo-s-2) var(--vo-s-1);font-size:11.5px;color:var(--vo-muted)}
|
|
302
|
+
.mi{display:flex;align-items:center;gap:10px;width:100%;padding:7px var(--vo-s-2);border-radius:calc(9px * var(--vo-rk));font-size:13px;text-align:left;color:var(--vo-fg);transition:background var(--vo-t-fast)}
|
|
303
|
+
.mi.hl{background:var(--vo-row)}
|
|
304
|
+
@media (hover:hover) and (pointer:fine){.mi:hover{background:var(--vo-row)}}
|
|
305
|
+
/* the rows of a menu or list stand 2px apart, so two highlighted rows never touch */
|
|
306
|
+
.mi+.mi,.cpl-i+.cpl-i,.six-it+.six-it{margin-top:2px}
|
|
307
|
+
.mi .i{color:var(--vo-fg2)}
|
|
308
|
+
.mi .d{display:block;font-size:12px;color:var(--vo-muted)}
|
|
309
|
+
/* on a hovered or picked row's tint the line under an item steps up, so it keeps 4.5:1 in dark mode */
|
|
310
|
+
@media (hover:hover) and (pointer:fine){.mi:is(:hover,.hl,[aria-checked="true"]) .d{color:var(--vo-fg2)}}
|
|
311
|
+
.mi .r{margin-left:auto;color:var(--vo-muted);font-size:12px}
|
|
312
|
+
.mi .ck{margin-left:auto;color:var(--vo-accent-fg,var(--vo-accent));opacity:0;transition:opacity var(--vo-t-fast)}
|
|
313
|
+
.mi[aria-checked="true"] .ck{opacity:1}
|
|
314
|
+
.mi[aria-checked="true"]{background:var(--vo-row);font-weight:500}
|
|
315
|
+
.pop .sep{height:1px;background:var(--vo-line);margin:var(--vo-s-1) 2px}
|
|
316
|
+
/* every list row hovers with --vo-row; an icon chip or track inside a hovered row lifts above it (white in light mode, one step lighter in dark) */
|
|
317
|
+
@media (hover:hover) and (pointer:fine){:root[data-theme="dark"] :is(.alg-it:hover .alg-ic,.plx-s:hover .n,.tpx-r:hover .tr){background:var(--vo-hover)}}
|
|
318
|
+
@media (prefers-color-scheme:dark){@media (hover:hover) and (pointer:fine){:root:not([data-theme="light"]) :is(.alg-it:hover .alg-ic,.plx-s:hover .n,.tpx-r:hover .tr){background:var(--vo-hover)}}}
|
|
319
|
+
|
|
320
|
+
@media (prefers-reduced-motion:reduce){:where([data-c]) *,:where([data-c]) *::before,:where([data-c]) *::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}.shim{color:var(--vo-fg);background:none}}
|
|
321
|
+
|
|
322
|
+
/* bare: components that live in the chat stream sit on the chat surface, no card */
|
|
323
|
+
.card.bare .stage-in .panel:not(.keep){background:none;box-shadow:none;padding-left:0;padding-right:0;border-radius:0}
|
|
324
|
+
/* chart palette, saturated */
|
|
325
|
+
:root,[data-style="soft"]{--vo-c1:var(--vo-accent-mark,var(--vo-accent));--vo-c2:#7c4dff;--vo-c3:#4cbb17;--vo-c4:#f76700;--vo-c5:#ff4d6d;--vo-c6:#00a2bf}
|
|
326
|
+
/* the accent as a ramp, for charts whose parts are shares of one thing: full strength, then lighter steps toward the surface */
|
|
327
|
+
:root,[data-style="soft"]{--vo-a1:var(--vo-c1);--vo-a2:color-mix(in oklab,var(--vo-c1) 72%,var(--vo-surface));--vo-a3:color-mix(in oklab,var(--vo-c1) 50%,var(--vo-surface));--vo-a4:color-mix(in oklab,var(--vo-c1) 32%,var(--vo-surface))}
|
|
328
|
+
:root[data-theme="dark"],:root[data-theme="dark"] [data-style="soft"]{--vo-c1:var(--vo-accent-mark,var(--vo-accent));--vo-c2:#9b7bff;--vo-c3:#5fcb2a;--vo-c4:#ffa033;--vo-c5:#ff6b85;--vo-c6:#22cce8}
|
|
329
|
+
@media (prefers-color-scheme: dark){:root:not([data-theme="light"]),:root:not([data-theme="light"]) [data-style="soft"]{--vo-c1:var(--vo-accent-mark,var(--vo-accent));--vo-c2:#9b7bff;--vo-c3:#5fcb2a;--vo-c4:#ffa033;--vo-c5:#ff6b85;--vo-c6:#22cce8}}
|
|
330
|
+
|
|
331
|
+
/* ---------- Blueprint 2 ---------- */
|
|
332
|
+
/* Blueprint 2: the same components drawn as a technical sheet. Square corners, hairline edges instead of shadows,
|
|
333
|
+
a lime accent, and motion that wipes and ticks into place in short, hard beats instead of blurring in */
|
|
334
|
+
:root:not([data-style="soft"]){
|
|
335
|
+
--vo-motion:bp;
|
|
336
|
+
--vo-page:#f3f3f0; --vo-stage:#fafaf8; --vo-surface:#ffffff; --vo-raised:#ffffff;
|
|
337
|
+
--vo-fg:#121212; --vo-fg2:#4a4a46; --vo-muted:#666660; --vo-faint:#bdbdb6; --vo-rail:#d2d2cb; --vo-line:#e3e3dd; --vo-field-line:#d2d2cb; --vo-line-strong:#858580; --vo-field-line-strong:#b0b0a9;
|
|
338
|
+
--vo-chip:#f1f1ed; --vo-hover:#e8e8e3; --vo-press:#dededa; --vo-wash:#f6f6f3; --vo-row:#fafaf8;
|
|
339
|
+
--vo-soft:#ebebe6; --vo-soft-h:#e1e1db; --vo-soft-ring:inset 0 0 0 1px rgba(20,20,12,.045); --vo-dis:#a3a39c;
|
|
340
|
+
--vo-accent:#d4f84a; --vo-on-accent:#121212; --vo-accent-fg:var(--vo-fg); --vo-accent-mark:#4cbb17; --vo-sel:color-mix(in srgb,var(--vo-accent) 7%,transparent);
|
|
341
|
+
--vo-ink:#121212; --vo-on-ink:#ffffff;
|
|
342
|
+
--vo-shadow:0 0 0 1px color-mix(in srgb,var(--vo-line) 50%,transparent);
|
|
343
|
+
--vo-shadow-pop:0 0 0 1px color-mix(in srgb,var(--vo-rail) 50%,transparent),0 12px 28px -14px rgba(20,20,12,.22);
|
|
344
|
+
--vo-shadow-toast:0 0 0 1px color-mix(in srgb,var(--vo-rail) 50%,transparent),0 10px 24px -14px rgba(20,20,12,.24);
|
|
345
|
+
--vo-shadow-lift:0 0 0 1px color-mix(in srgb,var(--vo-fg) 50%,transparent);
|
|
346
|
+
--vo-grid:rgba(20,20,12,.09); --vo-tick:#b5b5ad;
|
|
347
|
+
--vo-dis-hatch:repeating-linear-gradient(135deg,transparent 0 4px,var(--vo-grid) 4px 5px);
|
|
348
|
+
--vo-ease:cubic-bezier(.65,0,.25,1); --vo-ease-io:cubic-bezier(.65,0,.25,1);
|
|
349
|
+
--vo-t-fast:.14s; --vo-t:.3s; --vo-t-slow:.44s;
|
|
350
|
+
}
|
|
351
|
+
@media (prefers-color-scheme:dark){:root:not([data-style="soft"]):not([data-theme="light"]){
|
|
352
|
+
--vo-page:#111111; --vo-stage:#1c1c1c; --vo-surface:#262626; --vo-raised:#2c2c2c;
|
|
353
|
+
--vo-fg:#f2f2f2; --vo-fg2:#c9c9c9; --vo-muted:#c0c0c0; --vo-faint:#555555; --vo-rail:#414141; --vo-line:#333333; --vo-field-line:#424242; --vo-line-strong:#80807a; --vo-field-line-strong:#808080;
|
|
354
|
+
--vo-chip:#303030; --vo-hover:#373737; --vo-press:#3f3f3f; --vo-wash:#2c2c2c; --vo-row:color-mix(in srgb,var(--vo-fg) 5.5%,transparent);
|
|
355
|
+
--vo-soft:#323232; --vo-soft-h:#3a3a3a; --vo-soft-ring:inset 0 0 0 1px rgba(255,255,255,.04); --vo-dis:#737373;
|
|
356
|
+
--vo-accent:#d4f84a; --vo-on-accent:#121212; --vo-accent-fg:#d4f84a; --vo-accent-mark:#d4f84a; --vo-sel:color-mix(in srgb,var(--vo-accent) 10%,transparent);
|
|
357
|
+
--vo-ink:#f2f2f2; --vo-on-ink:#161616;
|
|
358
|
+
--vo-shadow:0 0 0 1px color-mix(in srgb,var(--vo-line) 50%,transparent);
|
|
359
|
+
--vo-shadow-pop:0 0 0 1px color-mix(in srgb,var(--vo-rail) 50%,transparent),0 16px 32px -14px rgba(0,0,0,.7);
|
|
360
|
+
--vo-shadow-toast:0 0 0 1px color-mix(in srgb,var(--vo-rail) 50%,transparent),0 12px 28px -14px rgba(0,0,0,.7);
|
|
361
|
+
--vo-shadow-lift:0 0 0 1px color-mix(in srgb,var(--vo-fg2) 50%,transparent);
|
|
362
|
+
--vo-grid:rgba(255,255,255,.07); --vo-tick:#55554f;
|
|
363
|
+
--vo-dis-hatch:repeating-linear-gradient(135deg,transparent 0 4px,var(--vo-grid) 4px 5px);
|
|
364
|
+
--vo-ease:cubic-bezier(.65,0,.25,1); --vo-ease-io:cubic-bezier(.65,0,.25,1);
|
|
365
|
+
--vo-t-fast:.14s; --vo-t:.3s; --vo-t-slow:.44s}}
|
|
366
|
+
:root:not([data-style="soft"])[data-theme="dark"]{
|
|
367
|
+
--vo-page:#111111; --vo-stage:#1c1c1c; --vo-surface:#262626; --vo-raised:#2c2c2c;
|
|
368
|
+
--vo-fg:#f2f2f2; --vo-fg2:#c9c9c9; --vo-muted:#c0c0c0; --vo-faint:#555555; --vo-rail:#414141; --vo-line:#333333; --vo-field-line:#424242; --vo-line-strong:#80807a; --vo-field-line-strong:#808080;
|
|
369
|
+
--vo-chip:#303030; --vo-hover:#373737; --vo-press:#3f3f3f; --vo-wash:#2c2c2c; --vo-row:color-mix(in srgb,var(--vo-fg) 5.5%,transparent);
|
|
370
|
+
--vo-soft:#323232; --vo-soft-h:#3a3a3a; --vo-soft-ring:inset 0 0 0 1px rgba(255,255,255,.04); --vo-dis:#737373;
|
|
371
|
+
--vo-accent:#d4f84a; --vo-on-accent:#121212; --vo-accent-fg:#d4f84a; --vo-accent-mark:#d4f84a; --vo-sel:color-mix(in srgb,var(--vo-accent) 10%,transparent);
|
|
372
|
+
--vo-ink:#f2f2f2; --vo-on-ink:#161616;
|
|
373
|
+
--vo-shadow:0 0 0 1px color-mix(in srgb,var(--vo-line) 50%,transparent);
|
|
374
|
+
--vo-shadow-pop:0 0 0 1px color-mix(in srgb,var(--vo-rail) 50%,transparent),0 16px 32px -14px rgba(0,0,0,.7);
|
|
375
|
+
--vo-shadow-toast:0 0 0 1px color-mix(in srgb,var(--vo-rail) 50%,transparent),0 12px 28px -14px rgba(0,0,0,.7);
|
|
376
|
+
--vo-shadow-lift:0 0 0 1px color-mix(in srgb,var(--vo-fg2) 50%,transparent);
|
|
377
|
+
--vo-grid:rgba(255,255,255,.07); --vo-tick:#55554f;
|
|
378
|
+
--vo-dis-hatch:repeating-linear-gradient(135deg,transparent 0 4px,var(--vo-grid) 4px 5px);
|
|
379
|
+
--vo-ease:cubic-bezier(.65,0,.25,1); --vo-ease-io:cubic-bezier(.65,0,.25,1);
|
|
380
|
+
--vo-t-fast:.14s; --vo-t:.3s; --vo-t-slow:.44s}
|
|
381
|
+
|
|
382
|
+
/* every corner is square, only the turning loaders stay round */
|
|
383
|
+
:root:not([data-style="soft"]) :where([data-c],[data-c] *,.tip,.tip *,.kbx-k.ghost,.kbx-k.ghost *):not(:where([data-style="soft"],[data-style="soft"] *)),:root:not([data-style="soft"]) :where([data-c],[data-c] *,.tip,.tip *,.kbx-k.ghost,.kbx-k.ghost *):not(:where([data-style="soft"],[data-style="soft"] *))::before,:root:not([data-style="soft"]) :where([data-c],[data-c] *,.tip,.tip *,.kbx-k.ghost,.kbx-k.ghost *):not(:where([data-style="soft"],[data-style="soft"] *))::after{border-radius:0!important}
|
|
384
|
+
:root:not([data-style="soft"]) .spin:not(:where([data-style="soft"],[data-style="soft"] *)),:root:not([data-style="soft"]) .radar:not(:where([data-style="soft"],[data-style="soft"] *))::before,:root:not([data-style="soft"]) .radar:not(:where([data-style="soft"],[data-style="soft"] *))::after{border-radius:50%!important}
|
|
385
|
+
:root:not([data-style="soft"]) :where([data-c],.tip,.kbx-k.ghost) svg:not(.i):not(.brand) rect:not(:where([data-style="soft"],[data-style="soft"] *)){rx:0;ry:0}
|
|
386
|
+
:root:not([data-style="soft"]) :where([data-c],.tip,.kbx-k.ghost) svg:not(.i):not(.brand) :is(path,line,polyline,circle):not(:where([data-style="soft"],[data-style="soft"] *)){stroke-linecap:butt}
|
|
387
|
+
/* no blur anywhere: things wipe in or cut, they never soften */
|
|
388
|
+
:root:not([data-style="soft"]) :where([data-c],[data-c] *,.tip,.tip *,.kbx-k.ghost,.kbx-k.ghost *):not(:where([data-style="soft"],[data-style="soft"] *)),:root:not([data-style="soft"]) :where([data-c],[data-c] *,.tip,.tip *,.kbx-k.ghost,.kbx-k.ghost *):not(:where([data-style="soft"],[data-style="soft"] *))::before,:root:not([data-style="soft"]) :where([data-c],[data-c] *,.tip,.tip *,.kbx-k.ghost,.kbx-k.ghost *):not(:where([data-style="soft"],[data-style="soft"] *))::after{filter:none!important}
|
|
389
|
+
|
|
390
|
+
/* the sheet: cards share their hairlines, every stage is drafting paper with crop marks in the corners */
|
|
391
|
+
:root:not([data-style="soft"]) .seg2 .knob:not(:where([data-style="soft"],[data-style="soft"] *)){box-shadow:0 0 0 1px color-mix(in srgb,var(--vo-rail) 50%,transparent)}
|
|
392
|
+
|
|
393
|
+
/* parts: mono labels, hairline controls, hatched when disabled */
|
|
394
|
+
:root:not([data-style="soft"]) .tag:not(:where([data-style="soft"],[data-style="soft"] *)){font-size:10.5px;font-weight:500;letter-spacing:.03em;text-transform:uppercase;height:19px;padding:0 6px}
|
|
395
|
+
:root:not([data-style="soft"]) .kbd:not(:where([data-style="soft"],[data-style="soft"] *)){box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--vo-line) 50%,transparent)}
|
|
396
|
+
:root:not([data-style="soft"]) .pill.line:not(:where([data-style="soft"],[data-style="soft"] *)){box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--vo-rail) 50%,transparent)}
|
|
397
|
+
@media (hover:hover) and (pointer:fine){:root:not([data-style="soft"]) .pill.line:hover:not(:where([data-style="soft"],[data-style="soft"] *)){background:var(--vo-wash);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--vo-faint) 50%,transparent)}}
|
|
398
|
+
:root:not([data-style="soft"]) .pill:active:not(:where([data-style="soft"],[data-style="soft"] *)),:root:not([data-style="soft"]) .ib:active:not(:where([data-style="soft"],[data-style="soft"] *)){transform:translateY(1px)}
|
|
399
|
+
:root:not([data-style="soft"]) .chip.on:not(:where([data-style="soft"],[data-style="soft"] *)){box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--vo-pick-on) 50%,transparent)}
|
|
400
|
+
:root:not([data-style="soft"]) .bub:not(:where([data-style="soft"],[data-style="soft"] *)){background:var(--vo-chip);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--vo-line) 50%,transparent)}
|
|
401
|
+
:root:not([data-style="soft"]) .tip:not(:where([data-style="soft"],[data-style="soft"] *)){box-shadow:none}
|
|
402
|
+
|
|
403
|
+
/* motion: a top-down wipe that settles on a hard ease, stepped loaders, a blinking cursor instead of a soft ping */
|
|
404
|
+
@keyframes bpin{0%{opacity:0;clip-path:inset(0 0 100% 0);transform:translateY(4px)}30%{opacity:1}100%{opacity:1;clip-path:inset(0 0 0 0);transform:none}}
|
|
405
|
+
@keyframes bpout{to{opacity:0;clip-path:inset(0 0 100% 0)}}
|
|
406
|
+
@keyframes bpblink{0%,55%{opacity:1}56%,100%{opacity:.2}}
|
|
407
|
+
:root:not([data-style="soft"]) .enter:not(:where([data-style="soft"],[data-style="soft"] *)),:root:not([data-style="soft"]) .pop-in:not(:where([data-style="soft"],[data-style="soft"] *)){animation-name:bpin;animation-duration:var(--vo-t-slow);animation-timing-function:var(--vo-ease);animation-fill-mode:backwards}
|
|
408
|
+
:root:not([data-style="soft"]) .leave:not(:where([data-style="soft"],[data-style="soft"] *)){animation:bpout .26s var(--vo-ease) both}
|
|
409
|
+
:root:not([data-style="soft"]) .chx-card.show:not(:where([data-style="soft"],[data-style="soft"] *)){animation:bpin .34s var(--vo-ease) backwards}
|
|
410
|
+
:root:not([data-style="soft"]) .sw.out:not(:where([data-style="soft"],[data-style="soft"] *)){transform:translateY(-3px)}
|
|
411
|
+
:root:not([data-style="soft"]) .pop:not(:where([data-style="soft"],[data-style="soft"] *)){transform:translateY(4px);transition-duration:.16s}
|
|
412
|
+
:root:not([data-style="soft"]) .pop.open:not(:where([data-style="soft"],[data-style="soft"] *)){transform:none}
|
|
413
|
+
:root:not([data-style="soft"]) .spin:not(:where([data-style="soft"],[data-style="soft"] *)){animation:rot .9s steps(8) infinite}
|
|
414
|
+
:root:not([data-style="soft"]) .radar:not(:where([data-style="soft"],[data-style="soft"] *))::after{animation:rot 1s steps(8) infinite}
|
|
415
|
+
:root:not([data-style="soft"]) .pulse:not(:where([data-style="soft"],[data-style="soft"] *)){animation:bpblink 1.1s steps(1,end) infinite}
|
|
416
|
+
:root:not([data-style="soft"]) .pulse:not(:where([data-style="soft"],[data-style="soft"] *))::after{display:none}
|
|
417
|
+
:root:not([data-style="soft"]) .btx-ask:not(:where([data-style="soft"],[data-style="soft"] *))::after{background:linear-gradient(90deg,transparent 0 40%,rgba(255,255,255,.38) 40% 46%,transparent 46%)}
|
|
418
|
+
@media (hover:hover) and (pointer:fine){:root:not([data-style="soft"]) .btx-ask:hover:not(:where([data-style="soft"],[data-style="soft"] *))::after{transition:transform .5s steps(10)}}
|
|
419
|
+
:root:not([data-style="soft"]) .btx-live:not(:where([data-style="soft"],[data-style="soft"] *))::after{display:none}
|
|
420
|
+
:root:not([data-style="soft"]) .btx-live:not(:where([data-style="soft"],[data-style="soft"] *)){animation:bpblink 1.1s steps(1,end) infinite}
|
|
421
|
+
|
|
422
|
+
/* a component card: the template renders into .stage-in */
|
|
423
|
+
[data-c]{width:440px;max-width:100%;font-family:var(--vo-sans);font-size:14px;line-height:1.5;color:var(--vo-fg);-webkit-font-smoothing:antialiased}
|
|
424
|
+
[data-c].wide{width:720px}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { AfterViewInit, ElementRef, EventEmitter, OnChanges, OnDestroy, SimpleChanges } from '@angular/core';
|
|
2
|
+
import { type VoIconName } from '../core/icon.component';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
export type TaskStatus = 'running' | 'failed' | 'queued' | 'paused' | 'done';
|
|
5
|
+
/** The agent on a task, shown as a small avatar and a name. */
|
|
6
|
+
export interface TaskAgent {
|
|
7
|
+
name: string;
|
|
8
|
+
initials: string;
|
|
9
|
+
/** The avatar colour, like 'var(--vo-av-b)'. Takes its own ink. */
|
|
10
|
+
color: string;
|
|
11
|
+
}
|
|
12
|
+
/** One task row. */
|
|
13
|
+
export interface Task {
|
|
14
|
+
id: string;
|
|
15
|
+
/** What the agent is doing, like "Audit pricing contrast". */
|
|
16
|
+
name: string;
|
|
17
|
+
status: TaskStatus;
|
|
18
|
+
agent: TaskAgent;
|
|
19
|
+
/** In dollars, shown as $0.42. */
|
|
20
|
+
cost: number;
|
|
21
|
+
/** Minutes since it last changed, shown as "14m ago", or "Just now" at 0. */
|
|
22
|
+
updated: number;
|
|
23
|
+
}
|
|
24
|
+
export type TaskSortKey = 'name' | 'status' | 'agent' | 'cost' | 'updated';
|
|
25
|
+
export interface TaskSort {
|
|
26
|
+
key: TaskSortKey;
|
|
27
|
+
desc?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export type TaskAction = 'pause' | 'retry' | 'cancel';
|
|
30
|
+
interface StatusStyle {
|
|
31
|
+
label: string;
|
|
32
|
+
rank: number;
|
|
33
|
+
tone: string;
|
|
34
|
+
icon: VoIconName | null;
|
|
35
|
+
}
|
|
36
|
+
export declare class TaskTableComponent implements OnChanges, AfterViewInit, OnDestroy {
|
|
37
|
+
tasks: Task[];
|
|
38
|
+
/** The name in the header. */
|
|
39
|
+
title: string;
|
|
40
|
+
/** The quiet line beside the name. Defaults to a count of tasks and how many are running. */
|
|
41
|
+
summary?: string;
|
|
42
|
+
/** Ids of the selected tasks. Leave it out to let the checkboxes and rows drive it. */
|
|
43
|
+
selected?: string[];
|
|
44
|
+
defaultSelected: string[];
|
|
45
|
+
selectedChange: EventEmitter<string[]>;
|
|
46
|
+
/** The column the rows are sorted by. Leave it out to let the headers set it. */
|
|
47
|
+
sort?: TaskSort;
|
|
48
|
+
defaultSort: TaskSort;
|
|
49
|
+
sortChange: EventEmitter<TaskSort>;
|
|
50
|
+
/** A button in the header while tasks are selected. The selection clears after it. */
|
|
51
|
+
action: EventEmitter<{
|
|
52
|
+
action: TaskAction;
|
|
53
|
+
ids: string[];
|
|
54
|
+
}>;
|
|
55
|
+
/** The bold line of the empty state. */
|
|
56
|
+
emptyTitle: string;
|
|
57
|
+
/** The quieter line of the empty state. */
|
|
58
|
+
emptyNote: string;
|
|
59
|
+
/** A button under the empty note, like { label: 'Bring them back', onClick }. */
|
|
60
|
+
emptyAction?: {
|
|
61
|
+
label: string;
|
|
62
|
+
onClick: () => void;
|
|
63
|
+
};
|
|
64
|
+
panelRef: ElementRef<HTMLElement>;
|
|
65
|
+
bodyRef: ElementRef<HTMLElement>;
|
|
66
|
+
emptyCellRef?: ElementRef<HTMLElement>;
|
|
67
|
+
private readonly motion;
|
|
68
|
+
readonly columns: {
|
|
69
|
+
key: TaskSortKey;
|
|
70
|
+
label: string;
|
|
71
|
+
right?: boolean;
|
|
72
|
+
}[];
|
|
73
|
+
readonly actions: {
|
|
74
|
+
key: TaskAction;
|
|
75
|
+
label: string;
|
|
76
|
+
icon: VoIconName;
|
|
77
|
+
}[];
|
|
78
|
+
sel: string[];
|
|
79
|
+
by: TaskSort;
|
|
80
|
+
leaving: string[];
|
|
81
|
+
/** The header keeps its count while it slides back to the title. */
|
|
82
|
+
shown: number;
|
|
83
|
+
pad?: {
|
|
84
|
+
top: number;
|
|
85
|
+
bottom: number;
|
|
86
|
+
};
|
|
87
|
+
private was;
|
|
88
|
+
private fullHeight?;
|
|
89
|
+
private timers;
|
|
90
|
+
ngOnChanges(changes: SimpleChanges): void;
|
|
91
|
+
ngAfterViewInit(): void;
|
|
92
|
+
/** The tasks sorted by the active column. */
|
|
93
|
+
get rows(): Task[];
|
|
94
|
+
/** The selected ids that still exist and are not on their way out. */
|
|
95
|
+
get picked(): string[];
|
|
96
|
+
get allState(): 'true' | 'false' | 'mixed';
|
|
97
|
+
get line(): string;
|
|
98
|
+
status(t: Task): StatusStyle;
|
|
99
|
+
ago(m: number): string;
|
|
100
|
+
inkFor(color: string): string | null;
|
|
101
|
+
toggle(id: string): void;
|
|
102
|
+
toggleAll(): void;
|
|
103
|
+
clear(): void;
|
|
104
|
+
sortBy(key: TaskSortKey): void;
|
|
105
|
+
act(a: TaskAction): void;
|
|
106
|
+
runEmptyAction(e: Event): void;
|
|
107
|
+
private commitSel;
|
|
108
|
+
private flip;
|
|
109
|
+
private measureFull;
|
|
110
|
+
ngOnDestroy(): void;
|
|
111
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<TaskTableComponent, never>;
|
|
112
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<TaskTableComponent, "vo-task-table", never, { "tasks": { "alias": "tasks"; "required": false; }; "title": { "alias": "title"; "required": false; }; "summary": { "alias": "summary"; "required": false; }; "selected": { "alias": "selected"; "required": false; }; "defaultSelected": { "alias": "defaultSelected"; "required": false; }; "sort": { "alias": "sort"; "required": false; }; "defaultSort": { "alias": "defaultSort"; "required": false; }; "emptyTitle": { "alias": "emptyTitle"; "required": false; }; "emptyNote": { "alias": "emptyNote"; "required": false; }; "emptyAction": { "alias": "emptyAction"; "required": false; }; }, { "selectedChange": "selectedChange"; "sortChange": "sortChange"; "action": "action"; }, never, never, true, never>;
|
|
113
|
+
}
|
|
114
|
+
export {};
|