@w6w/ui 0.0.0-stage → 0.1.1
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/CHANGELOG.md +68 -0
- package/LICENSE +21 -0
- package/README.md +275 -2
- package/dist/ActionTestForm.d.ts +76 -0
- package/dist/AddConnectionModal.d.ts +24 -0
- package/dist/AppPicker.d.ts +83 -0
- package/dist/CodeBlock-CZu4TFSi.cjs +15 -0
- package/dist/CodeBlock-CZu4TFSi.cjs.map +1 -0
- package/dist/CodeBlock-Dot3Pd7P.js +2889 -0
- package/dist/CodeBlock-Dot3Pd7P.js.map +1 -0
- package/dist/CodeBlock.d.ts +65 -0
- package/dist/CodeEditor.d.ts +42 -0
- package/dist/ConfirmModal-8avl9Nv8.cjs +11 -0
- package/dist/ConfirmModal-8avl9Nv8.cjs.map +1 -0
- package/dist/ConfirmModal-CD-P8mhN.js +6335 -0
- package/dist/ConfirmModal-CD-P8mhN.js.map +1 -0
- package/dist/Copyable-1niV9gUa.js +771 -0
- package/dist/Copyable-1niV9gUa.js.map +1 -0
- package/dist/Copyable-CYZU1o4X.cjs +2 -0
- package/dist/Copyable-CYZU1o4X.cjs.map +1 -0
- package/dist/JsonEditor.d.ts +60 -0
- package/dist/NodeConfigForm.d.ts +70 -0
- package/dist/ParamsForm.d.ts +56 -0
- package/dist/PropertyEntryForm.d.ts +56 -0
- package/dist/RetryPolicyFields.d.ts +18 -0
- package/dist/StepBuilderModal.d.ts +375 -0
- package/dist/TriggerFillForm.d.ts +52 -0
- package/dist/WaitEditor.d.ts +6 -0
- package/dist/WorkflowFlowEditor.d.ts +119 -0
- package/dist/YamlEditor.d.ts +46 -0
- package/dist/app-categories.d.ts +38 -0
- package/dist/app-pages.d.ts +111 -0
- package/dist/code.cjs +2 -0
- package/dist/code.cjs.map +1 -0
- package/dist/code.d.ts +29 -0
- package/dist/code.mjs +8 -0
- package/dist/code.mjs.map +1 -0
- package/dist/components/ApiCallsPanel.d.ts +41 -0
- package/dist/components/AppIcon.d.ts +25 -0
- package/dist/components/AuthFieldsForm.d.ts +22 -0
- package/dist/components/Combobox.d.ts +24 -0
- package/dist/components/ConfirmModal.d.ts +33 -0
- package/dist/components/Copyable.d.ts +51 -0
- package/dist/components/CopyableText.d.ts +40 -0
- package/dist/components/DeleteButton.d.ts +16 -0
- package/dist/components/EditButton.d.ts +10 -0
- package/dist/components/ExecutionDetail.d.ts +70 -0
- package/dist/components/ExecutionFilters.d.ts +59 -0
- package/dist/components/ExecutionList.d.ts +60 -0
- package/dist/components/ExecutionLogPanel.d.ts +98 -0
- package/dist/components/ExecutionStats.d.ts +47 -0
- package/dist/components/ExpressionEditorModal.d.ts +42 -0
- package/dist/components/ExpressionInput.d.ts +36 -0
- package/dist/components/ExpressionOptions.d.ts +185 -0
- package/dist/components/HealthStatusPill.d.ts +25 -0
- package/dist/components/HistoryTimeline.d.ts +56 -0
- package/dist/components/Icon.d.ts +34 -0
- package/dist/components/IconButton.d.ts +60 -0
- package/dist/components/InfoTip.d.ts +15 -0
- package/dist/components/InternalIcon.d.ts +19 -0
- package/dist/components/ListItem.d.ts +25 -0
- package/dist/components/Modal.d.ts +29 -0
- package/dist/components/RepoSyncIndicator.d.ts +29 -0
- package/dist/components/ResolvedParams.d.ts +31 -0
- package/dist/components/ServerResources.d.ts +47 -0
- package/dist/components/StepStatusPill.d.ts +51 -0
- package/dist/components/UptimeStrip.d.ts +56 -0
- package/dist/components/execution-format.d.ts +24 -0
- package/dist/components/expression-dom.d.ts +154 -0
- package/dist/components/expression-template.d.ts +86 -0
- package/dist/components/history-scale.d.ts +33 -0
- package/dist/components/icons.d.ts +41 -0
- package/dist/components/resolved-clip.d.ts +42 -0
- package/dist/components/server-resources-format.d.ts +68 -0
- package/dist/components/server-resources.fixture.d.ts +9 -0
- package/dist/components/use-copy.d.ts +14 -0
- package/dist/createW6WApi.d.ts +31 -0
- package/dist/flow-connect.d.ts +138 -0
- package/dist/flow-fanout.d.ts +15 -0
- package/dist/flow-types.d.ts +356 -0
- package/dist/flow-utils.d.ts +284 -0
- package/dist/flow.cjs +3 -0
- package/dist/flow.cjs.map +1 -0
- package/dist/flow.d.ts +24 -0
- package/dist/flow.mjs +1978 -0
- package/dist/flow.mjs.map +1 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +94 -0
- package/dist/index.mjs +1812 -0
- package/dist/index.mjs.map +1 -0
- package/dist/oauth-popup.d.ts +17 -0
- package/dist/output-shape.d.ts +58 -0
- package/dist/provider.d.ts +421 -0
- package/dist/resolve-params.d.ts +112 -0
- package/dist/resolved-json.d.ts +21 -0
- package/dist/run-visuals.d.ts +90 -0
- package/dist/step-preview-state.d.ts +143 -0
- package/dist/theme.d.ts +32 -0
- package/dist/trigger-fields.d.ts +56 -0
- package/dist/types.d.ts +413 -0
- package/dist/use-app-action-defs.d.ts +7 -0
- package/dist/use-enter-submit.d.ts +23 -0
- package/dist/use-seed-sources.d.ts +16 -0
- package/package.json +112 -3
- package/src/code.css +561 -0
- package/src/styles/_buttons.scss +38 -0
- package/src/styles/_chips.scss +210 -0
- package/src/styles/_code.scss +139 -0
- package/src/styles/_copyable.scss +147 -0
- package/src/styles/_data-vars.scss +38 -0
- package/src/styles/_execution-history.scss +282 -0
- package/src/styles/_execution-log.scss +178 -0
- package/src/styles/_expression-field.scss +65 -0
- package/src/styles/_expression-inline.scss +63 -0
- package/src/styles/_expression-modal.scss +292 -0
- package/src/styles/_fields.scss +161 -0
- package/src/styles/_flow.scss +217 -0
- package/src/styles/_fx.scss +158 -0
- package/src/styles/_health.scss +46 -0
- package/src/styles/_history-timeline.scss +156 -0
- package/src/styles/_icon-button.scss +22 -0
- package/src/styles/_icon.scss +15 -0
- package/src/styles/_icons.scss +31 -0
- package/src/styles/_incoming-state.scss +46 -0
- package/src/styles/_info-tip.scss +9 -0
- package/src/styles/_layout.scss +6 -0
- package/src/styles/_lists.scss +64 -0
- package/src/styles/_modal.scss +125 -0
- package/src/styles/_multiselect.scss +69 -0
- package/src/styles/_repo-sync-indicator.scss +99 -0
- package/src/styles/_scale.scss +70 -0
- package/src/styles/_sections.scss +36 -0
- package/src/styles/_server-resources.scss +163 -0
- package/src/styles/_step-builder.scss +376 -0
- package/src/styles/_step-config.scss +195 -0
- package/src/styles/_tabs.scss +54 -0
- package/src/styles/_tester.scss +111 -0
- package/src/styles/_tokens.scss +160 -0
- package/src/styles/_uptime.scss +61 -0
- package/src/styles.css +4894 -0
- package/src/styles.scss +61 -0
package/src/styles.css
ADDED
|
@@ -0,0 +1,4894 @@
|
|
|
1
|
+
/* GENERATED FILE — DO NOT EDIT.
|
|
2
|
+
*
|
|
3
|
+
* Compiled from src/styles.build.scss by scripts/build-css.mjs (`pnpm build:css`).
|
|
4
|
+
* Edit the .scss partials under src/styles/ instead; `pnpm check:css` fails
|
|
5
|
+
* if this file has drifted from them.
|
|
6
|
+
*/
|
|
7
|
+
@charset "UTF-8";
|
|
8
|
+
/* this gets exported as style.css and can be used for the default theming */
|
|
9
|
+
/* these are the necessary styles for React/Svelte Flow, they get used by base.css and style.css */
|
|
10
|
+
.react-flow {
|
|
11
|
+
direction: ltr;
|
|
12
|
+
--xy-edge-stroke-default: #b1b1b7;
|
|
13
|
+
--xy-edge-stroke-width-default: 1;
|
|
14
|
+
--xy-edge-stroke-selected-default: #555;
|
|
15
|
+
--xy-connectionline-stroke-default: #b1b1b7;
|
|
16
|
+
--xy-connectionline-stroke-width-default: 1;
|
|
17
|
+
--xy-attribution-background-color-default: rgba(255, 255, 255, 0.5);
|
|
18
|
+
--xy-minimap-background-color-default: #fff;
|
|
19
|
+
--xy-minimap-mask-background-color-default: rgba(240, 240, 240, 0.6);
|
|
20
|
+
--xy-minimap-mask-stroke-color-default: transparent;
|
|
21
|
+
--xy-minimap-mask-stroke-width-default: 1;
|
|
22
|
+
--xy-minimap-node-background-color-default: #e2e2e2;
|
|
23
|
+
--xy-minimap-node-stroke-color-default: transparent;
|
|
24
|
+
--xy-minimap-node-stroke-width-default: 2;
|
|
25
|
+
--xy-background-color-default: transparent;
|
|
26
|
+
--xy-background-pattern-dots-color-default: #91919a;
|
|
27
|
+
--xy-background-pattern-lines-color-default: #eee;
|
|
28
|
+
--xy-background-pattern-cross-color-default: #e2e2e2;
|
|
29
|
+
background-color: var(--xy-background-color, var(--xy-background-color-default));
|
|
30
|
+
--xy-node-color-default: inherit;
|
|
31
|
+
--xy-node-border-default: 1px solid #1a192b;
|
|
32
|
+
--xy-node-background-color-default: #fff;
|
|
33
|
+
--xy-node-group-background-color-default: rgba(240, 240, 240, 0.25);
|
|
34
|
+
--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(0, 0, 0, 0.08);
|
|
35
|
+
--xy-node-boxshadow-selected-default: 0 0 0 0.5px #1a192b;
|
|
36
|
+
--xy-node-border-radius-default: 3px;
|
|
37
|
+
--xy-handle-background-color-default: #1a192b;
|
|
38
|
+
--xy-handle-border-color-default: #fff;
|
|
39
|
+
--xy-selection-background-color-default: rgba(0, 89, 220, 0.08);
|
|
40
|
+
--xy-selection-border-default: 1px dotted rgba(0, 89, 220, 0.8);
|
|
41
|
+
--xy-controls-button-background-color-default: #fefefe;
|
|
42
|
+
--xy-controls-button-background-color-hover-default: #f4f4f4;
|
|
43
|
+
--xy-controls-button-color-default: inherit;
|
|
44
|
+
--xy-controls-button-color-hover-default: inherit;
|
|
45
|
+
--xy-controls-button-border-color-default: #eee;
|
|
46
|
+
--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, 0.08);
|
|
47
|
+
--xy-edge-label-background-color-default: #ffffff;
|
|
48
|
+
--xy-edge-label-color-default: inherit;
|
|
49
|
+
--xy-resize-background-color-default: #3367d9;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.react-flow.dark {
|
|
53
|
+
--xy-edge-stroke-default: #3e3e3e;
|
|
54
|
+
--xy-edge-stroke-width-default: 1;
|
|
55
|
+
--xy-edge-stroke-selected-default: #727272;
|
|
56
|
+
--xy-connectionline-stroke-default: #b1b1b7;
|
|
57
|
+
--xy-connectionline-stroke-width-default: 1;
|
|
58
|
+
--xy-attribution-background-color-default: rgba(150, 150, 150, 0.25);
|
|
59
|
+
--xy-minimap-background-color-default: #141414;
|
|
60
|
+
--xy-minimap-mask-background-color-default: rgba(60, 60, 60, 0.6);
|
|
61
|
+
--xy-minimap-mask-stroke-color-default: transparent;
|
|
62
|
+
--xy-minimap-mask-stroke-width-default: 1;
|
|
63
|
+
--xy-minimap-node-background-color-default: #2b2b2b;
|
|
64
|
+
--xy-minimap-node-stroke-color-default: transparent;
|
|
65
|
+
--xy-minimap-node-stroke-width-default: 2;
|
|
66
|
+
--xy-background-color-default: #141414;
|
|
67
|
+
--xy-background-pattern-dots-color-default: #777;
|
|
68
|
+
--xy-background-pattern-lines-color-default: #777;
|
|
69
|
+
--xy-background-pattern-cross-color-default: #777;
|
|
70
|
+
--xy-node-color-default: #f8f8f8;
|
|
71
|
+
--xy-node-border-default: 1px solid #3c3c3c;
|
|
72
|
+
--xy-node-background-color-default: #1e1e1e;
|
|
73
|
+
--xy-node-group-background-color-default: rgba(240, 240, 240, 0.25);
|
|
74
|
+
--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(255, 255, 255, 0.08);
|
|
75
|
+
--xy-node-boxshadow-selected-default: 0 0 0 0.5px #999;
|
|
76
|
+
--xy-handle-background-color-default: #bebebe;
|
|
77
|
+
--xy-handle-border-color-default: #1e1e1e;
|
|
78
|
+
--xy-selection-background-color-default: rgba(200, 200, 220, 0.08);
|
|
79
|
+
--xy-selection-border-default: 1px dotted rgba(200, 200, 220, 0.8);
|
|
80
|
+
--xy-controls-button-background-color-default: #2b2b2b;
|
|
81
|
+
--xy-controls-button-background-color-hover-default: #3e3e3e;
|
|
82
|
+
--xy-controls-button-color-default: #f8f8f8;
|
|
83
|
+
--xy-controls-button-color-hover-default: #fff;
|
|
84
|
+
--xy-controls-button-border-color-default: #5b5b5b;
|
|
85
|
+
--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, 0.08);
|
|
86
|
+
--xy-edge-label-background-color-default: #141414;
|
|
87
|
+
--xy-edge-label-color-default: #f8f8f8;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.react-flow__background {
|
|
91
|
+
background-color: var(--xy-background-color-props, var(--xy-background-color, var(--xy-background-color-default)));
|
|
92
|
+
pointer-events: none;
|
|
93
|
+
z-index: -1;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.react-flow__container {
|
|
97
|
+
position: absolute;
|
|
98
|
+
width: 100%;
|
|
99
|
+
height: 100%;
|
|
100
|
+
top: 0;
|
|
101
|
+
left: 0;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.react-flow__pane {
|
|
105
|
+
z-index: 1;
|
|
106
|
+
touch-action: none;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.react-flow__pane.draggable {
|
|
110
|
+
cursor: grab;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.react-flow__pane.dragging {
|
|
114
|
+
cursor: grabbing;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.react-flow__pane.selection {
|
|
118
|
+
cursor: pointer;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.react-flow__viewport {
|
|
122
|
+
transform-origin: 0 0;
|
|
123
|
+
z-index: 2;
|
|
124
|
+
pointer-events: none;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.react-flow__renderer {
|
|
128
|
+
z-index: 4;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.react-flow__selection {
|
|
132
|
+
z-index: 6;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.react-flow__nodesselection-rect:focus,
|
|
136
|
+
.react-flow__nodesselection-rect:focus-visible {
|
|
137
|
+
outline: none;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.react-flow__edge-path {
|
|
141
|
+
stroke: var(--xy-edge-stroke, var(--xy-edge-stroke-default));
|
|
142
|
+
stroke-width: var(--xy-edge-stroke-width, var(--xy-edge-stroke-width-default));
|
|
143
|
+
fill: none;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.react-flow__connection-path {
|
|
147
|
+
stroke: var(--xy-connectionline-stroke, var(--xy-connectionline-stroke-default));
|
|
148
|
+
stroke-width: var(--xy-connectionline-stroke-width, var(--xy-connectionline-stroke-width-default));
|
|
149
|
+
fill: none;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.react-flow .react-flow__edges {
|
|
153
|
+
position: absolute;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.react-flow .react-flow__edges svg {
|
|
157
|
+
overflow: visible;
|
|
158
|
+
position: absolute;
|
|
159
|
+
pointer-events: none;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.react-flow__edge {
|
|
163
|
+
pointer-events: visibleStroke;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.react-flow__edge.selectable {
|
|
167
|
+
cursor: pointer;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.react-flow__edge.animated path {
|
|
171
|
+
stroke-dasharray: 5;
|
|
172
|
+
animation: dashdraw 0.5s linear infinite;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.react-flow__edge.animated path.react-flow__edge-interaction {
|
|
176
|
+
stroke-dasharray: none;
|
|
177
|
+
animation: none;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.react-flow__edge.inactive {
|
|
181
|
+
pointer-events: none;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.react-flow__edge.selected,
|
|
185
|
+
.react-flow__edge:focus,
|
|
186
|
+
.react-flow__edge:focus-visible {
|
|
187
|
+
outline: none;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.react-flow__edge.selected .react-flow__edge-path,
|
|
191
|
+
.react-flow__edge.selectable:focus .react-flow__edge-path,
|
|
192
|
+
.react-flow__edge.selectable:focus-visible .react-flow__edge-path {
|
|
193
|
+
stroke: var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default));
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.react-flow__edge-textwrapper {
|
|
197
|
+
pointer-events: all;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.react-flow__edge .react-flow__edge-text {
|
|
201
|
+
pointer-events: none;
|
|
202
|
+
-webkit-user-select: none;
|
|
203
|
+
-moz-user-select: none;
|
|
204
|
+
user-select: none;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/* Arrowhead marker styles - use CSS custom properties as default */
|
|
208
|
+
.react-flow__arrowhead polyline {
|
|
209
|
+
stroke: var(--xy-edge-stroke, var(--xy-edge-stroke-default));
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.react-flow__arrowhead polyline.arrowclosed {
|
|
213
|
+
fill: var(--xy-edge-stroke, var(--xy-edge-stroke-default));
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.react-flow__connection {
|
|
217
|
+
pointer-events: none;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.react-flow__connection .animated {
|
|
221
|
+
stroke-dasharray: 5;
|
|
222
|
+
animation: dashdraw 0.5s linear infinite;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
svg.react-flow__connectionline {
|
|
226
|
+
z-index: 1001;
|
|
227
|
+
overflow: visible;
|
|
228
|
+
position: absolute;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.react-flow__nodes {
|
|
232
|
+
pointer-events: none;
|
|
233
|
+
transform-origin: 0 0;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.react-flow__node {
|
|
237
|
+
position: absolute;
|
|
238
|
+
-webkit-user-select: none;
|
|
239
|
+
-moz-user-select: none;
|
|
240
|
+
user-select: none;
|
|
241
|
+
pointer-events: all;
|
|
242
|
+
transform-origin: 0 0;
|
|
243
|
+
box-sizing: border-box;
|
|
244
|
+
cursor: default;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.react-flow__node.selectable {
|
|
248
|
+
cursor: pointer;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.react-flow__node.draggable {
|
|
252
|
+
cursor: grab;
|
|
253
|
+
pointer-events: all;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.react-flow__node.draggable.dragging {
|
|
257
|
+
cursor: grabbing;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.react-flow__nodesselection {
|
|
261
|
+
z-index: 3;
|
|
262
|
+
transform-origin: left top;
|
|
263
|
+
pointer-events: none;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.react-flow__nodesselection-rect {
|
|
267
|
+
position: absolute;
|
|
268
|
+
pointer-events: all;
|
|
269
|
+
cursor: grab;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
.react-flow__handle {
|
|
273
|
+
position: absolute;
|
|
274
|
+
pointer-events: none;
|
|
275
|
+
min-width: 5px;
|
|
276
|
+
min-height: 5px;
|
|
277
|
+
width: 6px;
|
|
278
|
+
height: 6px;
|
|
279
|
+
background-color: var(--xy-handle-background-color, var(--xy-handle-background-color-default));
|
|
280
|
+
border: 1px solid var(--xy-handle-border-color, var(--xy-handle-border-color-default));
|
|
281
|
+
border-radius: 100%;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.react-flow__handle.connectingfrom {
|
|
285
|
+
pointer-events: all;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.react-flow__handle.connectionindicator {
|
|
289
|
+
pointer-events: all;
|
|
290
|
+
cursor: crosshair;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
.react-flow__handle-bottom {
|
|
294
|
+
top: auto;
|
|
295
|
+
left: 50%;
|
|
296
|
+
bottom: 0;
|
|
297
|
+
transform: translate(-50%, 50%);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.react-flow__handle-top {
|
|
301
|
+
top: 0;
|
|
302
|
+
left: 50%;
|
|
303
|
+
transform: translate(-50%, -50%);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.react-flow__handle-left {
|
|
307
|
+
top: 50%;
|
|
308
|
+
left: 0;
|
|
309
|
+
transform: translate(-50%, -50%);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.react-flow__handle-right {
|
|
313
|
+
top: 50%;
|
|
314
|
+
right: 0;
|
|
315
|
+
transform: translate(50%, -50%);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.react-flow__edgeupdater {
|
|
319
|
+
cursor: move;
|
|
320
|
+
pointer-events: all;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.react-flow__pane.selection .react-flow__panel {
|
|
324
|
+
pointer-events: none;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
.react-flow__panel {
|
|
328
|
+
position: absolute;
|
|
329
|
+
z-index: 5;
|
|
330
|
+
margin: 15px;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.react-flow__panel.top {
|
|
334
|
+
top: 0;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.react-flow__panel.bottom {
|
|
338
|
+
bottom: 0;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.react-flow__panel.top.center, .react-flow__panel.bottom.center {
|
|
342
|
+
left: 50%;
|
|
343
|
+
transform: translateX(-15px) translateX(-50%);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.react-flow__panel.left {
|
|
347
|
+
left: 0;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.react-flow__panel.right {
|
|
351
|
+
right: 0;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.react-flow__panel.left.center, .react-flow__panel.right.center {
|
|
355
|
+
top: 50%;
|
|
356
|
+
transform: translateY(-15px) translateY(-50%);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.react-flow__attribution {
|
|
360
|
+
font-size: 10px;
|
|
361
|
+
background: var(--xy-attribution-background-color, var(--xy-attribution-background-color-default));
|
|
362
|
+
padding: 2px 3px;
|
|
363
|
+
margin: 0;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
.react-flow__attribution a {
|
|
367
|
+
text-decoration: none;
|
|
368
|
+
color: #999;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
@keyframes dashdraw {
|
|
372
|
+
from {
|
|
373
|
+
stroke-dashoffset: 10;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
.react-flow__edgelabel-renderer {
|
|
377
|
+
position: absolute;
|
|
378
|
+
width: 100%;
|
|
379
|
+
height: 100%;
|
|
380
|
+
pointer-events: none;
|
|
381
|
+
-webkit-user-select: none;
|
|
382
|
+
-moz-user-select: none;
|
|
383
|
+
user-select: none;
|
|
384
|
+
left: 0;
|
|
385
|
+
top: 0;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
.react-flow__viewport-portal {
|
|
389
|
+
position: absolute;
|
|
390
|
+
width: 100%;
|
|
391
|
+
height: 100%;
|
|
392
|
+
left: 0;
|
|
393
|
+
top: 0;
|
|
394
|
+
-webkit-user-select: none;
|
|
395
|
+
-moz-user-select: none;
|
|
396
|
+
user-select: none;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
.react-flow__minimap {
|
|
400
|
+
background: var(--xy-minimap-background-color-props, var(--xy-minimap-background-color, var(--xy-minimap-background-color-default)));
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.react-flow__minimap-svg {
|
|
404
|
+
display: block;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
.react-flow__minimap-mask {
|
|
408
|
+
fill: var(--xy-minimap-mask-background-color-props, var(--xy-minimap-mask-background-color, var(--xy-minimap-mask-background-color-default)));
|
|
409
|
+
stroke: var(--xy-minimap-mask-stroke-color-props, var(--xy-minimap-mask-stroke-color, var(--xy-minimap-mask-stroke-color-default)));
|
|
410
|
+
stroke-width: var(--xy-minimap-mask-stroke-width-props, var(--xy-minimap-mask-stroke-width, var(--xy-minimap-mask-stroke-width-default)));
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
.react-flow__minimap-node {
|
|
414
|
+
fill: var(--xy-minimap-node-background-color-props, var(--xy-minimap-node-background-color, var(--xy-minimap-node-background-color-default)));
|
|
415
|
+
stroke: var(--xy-minimap-node-stroke-color-props, var(--xy-minimap-node-stroke-color, var(--xy-minimap-node-stroke-color-default)));
|
|
416
|
+
stroke-width: var(--xy-minimap-node-stroke-width-props, var(--xy-minimap-node-stroke-width, var(--xy-minimap-node-stroke-width-default)));
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
.react-flow__background-pattern.dots {
|
|
420
|
+
fill: var(--xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-dots-color-default)));
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
.react-flow__background-pattern.lines {
|
|
424
|
+
stroke: var(--xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-lines-color-default)));
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
.react-flow__background-pattern.cross {
|
|
428
|
+
stroke: var(--xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-cross-color-default)));
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
.react-flow__controls {
|
|
432
|
+
display: flex;
|
|
433
|
+
flex-direction: column;
|
|
434
|
+
box-shadow: var(--xy-controls-box-shadow, var(--xy-controls-box-shadow-default));
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
.react-flow__controls.horizontal {
|
|
438
|
+
flex-direction: row;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
.react-flow__controls-button {
|
|
442
|
+
display: flex;
|
|
443
|
+
justify-content: center;
|
|
444
|
+
align-items: center;
|
|
445
|
+
height: 26px;
|
|
446
|
+
width: 26px;
|
|
447
|
+
padding: 4px;
|
|
448
|
+
border: none;
|
|
449
|
+
background: var(--xy-controls-button-background-color, var(--xy-controls-button-background-color-default));
|
|
450
|
+
border-bottom: 1px solid var(--xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)));
|
|
451
|
+
color: var(--xy-controls-button-color-props, var(--xy-controls-button-color, var(--xy-controls-button-color-default)));
|
|
452
|
+
cursor: pointer;
|
|
453
|
+
-webkit-user-select: none;
|
|
454
|
+
-moz-user-select: none;
|
|
455
|
+
user-select: none;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
.react-flow__controls-button svg {
|
|
459
|
+
width: 100%;
|
|
460
|
+
max-width: 12px;
|
|
461
|
+
max-height: 12px;
|
|
462
|
+
fill: currentColor;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
.react-flow__edge.updating .react-flow__edge-path {
|
|
466
|
+
stroke: #777;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
.react-flow__edge-text {
|
|
470
|
+
font-size: 10px;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
.react-flow__node.selectable:focus,
|
|
474
|
+
.react-flow__node.selectable:focus-visible {
|
|
475
|
+
outline: none;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
.react-flow__node-input,
|
|
479
|
+
.react-flow__node-default,
|
|
480
|
+
.react-flow__node-output,
|
|
481
|
+
.react-flow__node-group {
|
|
482
|
+
padding: 10px;
|
|
483
|
+
border-radius: var(--xy-node-border-radius, var(--xy-node-border-radius-default));
|
|
484
|
+
width: 150px;
|
|
485
|
+
font-size: 12px;
|
|
486
|
+
color: var(--xy-node-color, var(--xy-node-color-default));
|
|
487
|
+
text-align: center;
|
|
488
|
+
border: var(--xy-node-border, var(--xy-node-border-default));
|
|
489
|
+
background-color: var(--xy-node-background-color, var(--xy-node-background-color-default));
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
.react-flow__node-input.selectable:hover, .react-flow__node-default.selectable:hover, .react-flow__node-output.selectable:hover, .react-flow__node-group.selectable:hover {
|
|
493
|
+
box-shadow: var(--xy-node-boxshadow-hover, var(--xy-node-boxshadow-hover-default));
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
.react-flow__node-input.selectable.selected,
|
|
497
|
+
.react-flow__node-input.selectable:focus,
|
|
498
|
+
.react-flow__node-input.selectable:focus-visible,
|
|
499
|
+
.react-flow__node-default.selectable.selected,
|
|
500
|
+
.react-flow__node-default.selectable:focus,
|
|
501
|
+
.react-flow__node-default.selectable:focus-visible,
|
|
502
|
+
.react-flow__node-output.selectable.selected,
|
|
503
|
+
.react-flow__node-output.selectable:focus,
|
|
504
|
+
.react-flow__node-output.selectable:focus-visible,
|
|
505
|
+
.react-flow__node-group.selectable.selected,
|
|
506
|
+
.react-flow__node-group.selectable:focus,
|
|
507
|
+
.react-flow__node-group.selectable:focus-visible {
|
|
508
|
+
box-shadow: var(--xy-node-boxshadow-selected, var(--xy-node-boxshadow-selected-default));
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
.react-flow__node-group {
|
|
512
|
+
background-color: var(--xy-node-group-background-color, var(--xy-node-group-background-color-default));
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
.react-flow__nodesselection-rect,
|
|
516
|
+
.react-flow__selection {
|
|
517
|
+
background: var(--xy-selection-background-color, var(--xy-selection-background-color-default));
|
|
518
|
+
border: var(--xy-selection-border, var(--xy-selection-border-default));
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
.react-flow__nodesselection-rect:focus,
|
|
522
|
+
.react-flow__nodesselection-rect:focus-visible,
|
|
523
|
+
.react-flow__selection:focus,
|
|
524
|
+
.react-flow__selection:focus-visible {
|
|
525
|
+
outline: none;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
.react-flow__controls-button:hover {
|
|
529
|
+
background: var(--xy-controls-button-background-color-hover-props, var(--xy-controls-button-background-color-hover, var(--xy-controls-button-background-color-hover-default)));
|
|
530
|
+
color: var(--xy-controls-button-color-hover-props, var(--xy-controls-button-color-hover, var(--xy-controls-button-color-hover-default)));
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
.react-flow__controls-button:disabled {
|
|
534
|
+
pointer-events: none;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
.react-flow__controls-button:disabled svg {
|
|
538
|
+
fill-opacity: 0.4;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
.react-flow__controls-button:last-child {
|
|
542
|
+
border-bottom: none;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
.react-flow__controls.horizontal .react-flow__controls-button {
|
|
546
|
+
border-bottom: none;
|
|
547
|
+
border-right: 1px solid var(--xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)));
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
.react-flow__controls.horizontal .react-flow__controls-button:last-child {
|
|
551
|
+
border-right: none;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
.react-flow__resize-control {
|
|
555
|
+
position: absolute;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
.react-flow__resize-control.left,
|
|
559
|
+
.react-flow__resize-control.right {
|
|
560
|
+
cursor: ew-resize;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
.react-flow__resize-control.top,
|
|
564
|
+
.react-flow__resize-control.bottom {
|
|
565
|
+
cursor: ns-resize;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
.react-flow__resize-control.top.left,
|
|
569
|
+
.react-flow__resize-control.bottom.right {
|
|
570
|
+
cursor: nwse-resize;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
.react-flow__resize-control.bottom.left,
|
|
574
|
+
.react-flow__resize-control.top.right {
|
|
575
|
+
cursor: nesw-resize;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/* handle styles */
|
|
579
|
+
.react-flow__resize-control.handle {
|
|
580
|
+
width: 5px;
|
|
581
|
+
height: 5px;
|
|
582
|
+
border: 1px solid #fff;
|
|
583
|
+
border-radius: 1px;
|
|
584
|
+
background-color: var(--xy-resize-background-color, var(--xy-resize-background-color-default));
|
|
585
|
+
translate: -50% -50%;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
.react-flow__resize-control.handle.left {
|
|
589
|
+
left: 0;
|
|
590
|
+
top: 50%;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
.react-flow__resize-control.handle.right {
|
|
594
|
+
left: 100%;
|
|
595
|
+
top: 50%;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
.react-flow__resize-control.handle.top {
|
|
599
|
+
left: 50%;
|
|
600
|
+
top: 0;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
.react-flow__resize-control.handle.bottom {
|
|
604
|
+
left: 50%;
|
|
605
|
+
top: 100%;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
.react-flow__resize-control.handle.top.left {
|
|
609
|
+
left: 0;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
.react-flow__resize-control.handle.bottom.left {
|
|
613
|
+
left: 0;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
.react-flow__resize-control.handle.top.right {
|
|
617
|
+
left: 100%;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
.react-flow__resize-control.handle.bottom.right {
|
|
621
|
+
left: 100%;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/* line styles */
|
|
625
|
+
.react-flow__resize-control.line {
|
|
626
|
+
border-color: var(--xy-resize-background-color, var(--xy-resize-background-color-default));
|
|
627
|
+
border-width: 0;
|
|
628
|
+
border-style: solid;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
.react-flow__resize-control.line.left,
|
|
632
|
+
.react-flow__resize-control.line.right {
|
|
633
|
+
width: 1px;
|
|
634
|
+
transform: translate(-50%, 0);
|
|
635
|
+
top: 0;
|
|
636
|
+
height: 100%;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
.react-flow__resize-control.line.left {
|
|
640
|
+
left: 0;
|
|
641
|
+
border-left-width: 1px;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
.react-flow__resize-control.line.right {
|
|
645
|
+
left: 100%;
|
|
646
|
+
border-right-width: 1px;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
.react-flow__resize-control.line.top,
|
|
650
|
+
.react-flow__resize-control.line.bottom {
|
|
651
|
+
height: 1px;
|
|
652
|
+
transform: translate(0, -50%);
|
|
653
|
+
left: 0;
|
|
654
|
+
width: 100%;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
.react-flow__resize-control.line.top {
|
|
658
|
+
top: 0;
|
|
659
|
+
border-top-width: 1px;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
.react-flow__resize-control.line.bottom {
|
|
663
|
+
border-bottom-width: 1px;
|
|
664
|
+
top: 100%;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
.react-flow__edge-textbg {
|
|
668
|
+
fill: var(--xy-edge-label-background-color, var(--xy-edge-label-background-color-default));
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
.react-flow__edge-text {
|
|
672
|
+
fill: var(--xy-edge-label-color, var(--xy-edge-label-color-default));
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
/*
|
|
676
|
+
* @w6w/ui — styles for the pure-presentation components.
|
|
677
|
+
*
|
|
678
|
+
* Everything is namespaced under `.w6w-*` class names so this stylesheet
|
|
679
|
+
* won't collide with your app's CSS.
|
|
680
|
+
*
|
|
681
|
+
* THEMING
|
|
682
|
+
* -------
|
|
683
|
+
* The library ships a complete DEFAULT theme in BOTH light and dark:
|
|
684
|
+
* - Light is the base.
|
|
685
|
+
* - Dark applies automatically when the OS prefers dark
|
|
686
|
+
* (`prefers-color-scheme: dark`).
|
|
687
|
+
* - Either mode can be forced with `data-theme="light" | "dark"` on any
|
|
688
|
+
* ancestor (usually <html>) — the same signal the JS components read
|
|
689
|
+
* (AppIcon / CodeEditor / JsonEditor: explicit prop > data-theme > OS pref),
|
|
690
|
+
* so CSS and components always agree.
|
|
691
|
+
*
|
|
692
|
+
* A HOST can override any subset of the tokens — set the ones you care about and
|
|
693
|
+
* the rest keep their themed defaults:
|
|
694
|
+
*
|
|
695
|
+
* :root { --w6w-accent: #3355e6; } // one token, both modes
|
|
696
|
+
* html[data-theme="dark"] { --w6w-panel: #000 } // mode-specific
|
|
697
|
+
*
|
|
698
|
+
* Every default below is declared through `:where(...)` (specificity 0), so ANY
|
|
699
|
+
* host rule — even a plain `:root { ... }` — wins without !important. Tokens are
|
|
700
|
+
* defined on :root so every `.w6w-*` component inherits them out of the box.
|
|
701
|
+
*/
|
|
702
|
+
/* Light — the base defaults. */
|
|
703
|
+
:where(:root) {
|
|
704
|
+
--w6w-bg: #f7f8fa;
|
|
705
|
+
--w6w-panel: #ffffff;
|
|
706
|
+
--w6w-panel-2: #f0f2f6;
|
|
707
|
+
--w6w-border: #d9dee5;
|
|
708
|
+
--w6w-text: #1a1d24;
|
|
709
|
+
--w6w-muted: #5f6875;
|
|
710
|
+
--w6w-accent: #3355e6;
|
|
711
|
+
--w6w-danger: #c1362f;
|
|
712
|
+
--w6w-success: #2e9e5b;
|
|
713
|
+
--w6w-health-ok: var(--w6w-success);
|
|
714
|
+
--w6w-health-degraded: #c77700;
|
|
715
|
+
--w6w-health-down: var(--w6w-danger);
|
|
716
|
+
--w6w-health-unknown: #5f6875;
|
|
717
|
+
--w6w-icon-swatch: #f0f2f6;
|
|
718
|
+
--w6w-code-comment: #6b7280;
|
|
719
|
+
--w6w-code-keyword: #8250df;
|
|
720
|
+
--w6w-code-string: #0a7b34;
|
|
721
|
+
--w6w-code-number: #b3541e;
|
|
722
|
+
--w6w-code-function: #1f6feb;
|
|
723
|
+
--w6w-code-punctuation: #5f6875;
|
|
724
|
+
--w6w-code-variable: #953800;
|
|
725
|
+
--w6w-radius: 10px;
|
|
726
|
+
--w6w-scheme: light;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
/* Dark — followed automatically from the OS preference (unless a host has
|
|
730
|
+
forced a mode via data-theme, which is handled by the blocks below). */
|
|
731
|
+
@media (prefers-color-scheme: dark) {
|
|
732
|
+
:where(:root) {
|
|
733
|
+
--w6w-bg: #0f1115;
|
|
734
|
+
--w6w-panel: #181b22;
|
|
735
|
+
--w6w-panel-2: #1f232c;
|
|
736
|
+
--w6w-border: #2a2f3a;
|
|
737
|
+
--w6w-text: #e6e8ee;
|
|
738
|
+
--w6w-muted: #9aa3b2;
|
|
739
|
+
--w6w-accent: #5b8cff;
|
|
740
|
+
--w6w-danger: #ff6b6b;
|
|
741
|
+
--w6w-success: #3fbf77;
|
|
742
|
+
--w6w-health-ok: var(--w6w-success);
|
|
743
|
+
--w6w-health-degraded: #f0a020;
|
|
744
|
+
--w6w-health-down: var(--w6w-danger);
|
|
745
|
+
--w6w-health-unknown: #9aa3b2;
|
|
746
|
+
--w6w-icon-swatch: #1f232c;
|
|
747
|
+
--w6w-scheme: dark;
|
|
748
|
+
--w6w-code-comment: #7d8797;
|
|
749
|
+
--w6w-code-keyword: #d2a8ff;
|
|
750
|
+
--w6w-code-string: #7ee787;
|
|
751
|
+
--w6w-code-number: #ffab70;
|
|
752
|
+
--w6w-code-function: #79c0ff;
|
|
753
|
+
--w6w-code-punctuation: #9aa3b2;
|
|
754
|
+
--w6w-code-variable: #ffa657;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
/* Explicit mode. Declared AFTER the media query at equal (zero) specificity, so
|
|
758
|
+
a forced data-theme always beats the OS preference. */
|
|
759
|
+
:where([data-theme=light]) {
|
|
760
|
+
--w6w-scheme: light;
|
|
761
|
+
--w6w-bg: #f7f8fa;
|
|
762
|
+
--w6w-panel: #ffffff;
|
|
763
|
+
--w6w-panel-2: #f0f2f6;
|
|
764
|
+
--w6w-border: #d9dee5;
|
|
765
|
+
--w6w-text: #1a1d24;
|
|
766
|
+
--w6w-muted: #5f6875;
|
|
767
|
+
--w6w-accent: #3355e6;
|
|
768
|
+
--w6w-danger: #c1362f;
|
|
769
|
+
--w6w-success: #2e9e5b;
|
|
770
|
+
--w6w-health-ok: var(--w6w-success);
|
|
771
|
+
--w6w-health-degraded: #c77700;
|
|
772
|
+
--w6w-health-down: var(--w6w-danger);
|
|
773
|
+
--w6w-health-unknown: #5f6875;
|
|
774
|
+
--w6w-icon-swatch: #f0f2f6;
|
|
775
|
+
--w6w-code-comment: #6b7280;
|
|
776
|
+
--w6w-code-keyword: #8250df;
|
|
777
|
+
--w6w-code-string: #0a7b34;
|
|
778
|
+
--w6w-code-number: #b3541e;
|
|
779
|
+
--w6w-code-function: #1f6feb;
|
|
780
|
+
--w6w-code-punctuation: #5f6875;
|
|
781
|
+
--w6w-code-variable: #953800;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
:where([data-theme=dark]) {
|
|
785
|
+
--w6w-scheme: dark;
|
|
786
|
+
--w6w-bg: #0f1115;
|
|
787
|
+
--w6w-panel: #181b22;
|
|
788
|
+
--w6w-panel-2: #1f232c;
|
|
789
|
+
--w6w-border: #2a2f3a;
|
|
790
|
+
--w6w-text: #e6e8ee;
|
|
791
|
+
--w6w-muted: #9aa3b2;
|
|
792
|
+
--w6w-accent: #5b8cff;
|
|
793
|
+
--w6w-danger: #ff6b6b;
|
|
794
|
+
--w6w-success: #3fbf77;
|
|
795
|
+
--w6w-health-ok: var(--w6w-success);
|
|
796
|
+
--w6w-health-degraded: #f0a020;
|
|
797
|
+
--w6w-health-down: var(--w6w-danger);
|
|
798
|
+
--w6w-health-unknown: #9aa3b2;
|
|
799
|
+
--w6w-icon-swatch: #1f232c;
|
|
800
|
+
--w6w-code-comment: #7d8797;
|
|
801
|
+
--w6w-code-keyword: #d2a8ff;
|
|
802
|
+
--w6w-code-string: #7ee787;
|
|
803
|
+
--w6w-code-number: #ffab70;
|
|
804
|
+
--w6w-code-function: #79c0ff;
|
|
805
|
+
--w6w-code-punctuation: #9aa3b2;
|
|
806
|
+
--w6w-code-variable: #ffa657;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
.w6w-muted {
|
|
810
|
+
color: var(--w6w-muted);
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
.w6w-small {
|
|
814
|
+
font-size: 0.85em;
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
/* color-scheme — declared on ui COMPONENT ROOTS, never on the host's <html>.
|
|
818
|
+
`color-scheme` inherits and also themes the page canvas, scrollbars and form
|
|
819
|
+
controls, so setting it on :root / [data-theme] let importing this file flip a
|
|
820
|
+
host's whole document. Instead each token block above also sets the
|
|
821
|
+
`--w6w-scheme` custom property (light / dark), which INHERITS, so the nearest
|
|
822
|
+
themed ancestor wins however themes nest (a light panel inside a dark page and
|
|
823
|
+
the reverse). Elements ui renders (any `w6w-` class, which covers the native
|
|
824
|
+
<dialog> modals) and the native controls inside them read it with
|
|
825
|
+
`color-scheme: var(--w6w-scheme)`. Not a hand-picked root list: every ui
|
|
826
|
+
component carries a `w6w-` class. Only an element whose class LIST has a token
|
|
827
|
+
starting `w6w-` matches (`class^=` / `class*=" w6w-"`), so host elements are never
|
|
828
|
+
touched: not a host `data-theme` wrapper, not a host class that merely contains
|
|
829
|
+
`w6w-` (`my-w6w-card`), and not a host element's own color-scheme on inputs nested
|
|
830
|
+
in a ui root (color-scheme inherits, so no descendant rule is needed). Nothing here
|
|
831
|
+
ever matches <html>/:root. All zero specificity. */
|
|
832
|
+
:where([class^=w6w-]:not(:root), [class*=" w6w-"]:not(:root)) {
|
|
833
|
+
color-scheme: var(--w6w-scheme);
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
/*
|
|
837
|
+
* @w6w/ui — the spacing / typography scale.
|
|
838
|
+
*
|
|
839
|
+
* Values are MIRRORED, not invented, from `packages/frontend/packages/web`'s
|
|
840
|
+
* `src/styles/global.css:83-130` — that file is the canonical reference (it
|
|
841
|
+
* arrived at the same 4px base independently); this block copies its
|
|
842
|
+
* `--sp-*`/`--fs-*`/`--fw-*`/`--lh-*`/`--font-*` values byte-for-byte under the
|
|
843
|
+
* `--w6w-*` namespace this package already uses for every other token.
|
|
844
|
+
* `--fs-hero`'s `clamp()` stays `web`-only (a marketing-page concern; `ui` has
|
|
845
|
+
* no hero). Colour tokens, `--radius*`, `--shadow-*` and `--transition-fast`
|
|
846
|
+
* are NOT part of this scale — see `_tokens.scss`.
|
|
847
|
+
*
|
|
848
|
+
* HALF-STEPS (`--w6w-sp-0-5` / `--w6w-sp-1-5` / `--w6w-sp-2-5`) are `ui`-only
|
|
849
|
+
* additions on top of `web`'s set — `web` has none. The rule that keeps this a
|
|
850
|
+
* system rather than a free-for-all: whole steps for new code; a half-step is
|
|
851
|
+
* only for preserving an existing measured value that does not sit on a 4px
|
|
852
|
+
* step. Parity with `web` is therefore DIRECTIONAL — `ui` ⊇ `web` on the
|
|
853
|
+
* shared key set (every `web` token here has a byte-identical `ui` counterpart;
|
|
854
|
+
* `ui` additionally declares the three half-steps `web` does not).
|
|
855
|
+
*
|
|
856
|
+
* One `:where(:root)` block, not colour's three-way light / prefers-color-scheme /
|
|
857
|
+
* [data-theme] split — the scale is not theme-dependent, so a single specificity-0
|
|
858
|
+
* block covers every mode. Positioning this partial's `@use` line immediately
|
|
859
|
+
* after `styles/tokens` (see `styles.scss`) is a readability convention, not a
|
|
860
|
+
* cascade constraint: CSS custom properties resolve at computed-value time, so
|
|
861
|
+
* definition order relative to consumption order does not matter here, unlike
|
|
862
|
+
* `_tokens.scss`'s internal prefers-color-scheme / [data-theme] ordering, which
|
|
863
|
+
* IS load-bearing.
|
|
864
|
+
*/
|
|
865
|
+
:where(:root) {
|
|
866
|
+
/* Spacing — 4px ramp. Values mirror frontend/web's --sp-* verbatim. */
|
|
867
|
+
--w6w-sp-1: 4px;
|
|
868
|
+
--w6w-sp-2: 8px;
|
|
869
|
+
--w6w-sp-3: 12px;
|
|
870
|
+
--w6w-sp-4: 16px;
|
|
871
|
+
--w6w-sp-5: 20px;
|
|
872
|
+
--w6w-sp-6: 24px;
|
|
873
|
+
--w6w-sp-8: 32px;
|
|
874
|
+
--w6w-sp-10: 40px;
|
|
875
|
+
--w6w-sp-12: 48px;
|
|
876
|
+
--w6w-sp-16: 64px;
|
|
877
|
+
--w6w-sp-20: 80px;
|
|
878
|
+
/* Half-steps — ui-only, see the decision above. */
|
|
879
|
+
--w6w-sp-0-5: 2px;
|
|
880
|
+
--w6w-sp-1-5: 6px;
|
|
881
|
+
--w6w-sp-2-5: 10px;
|
|
882
|
+
/* Type ramp — rem, role names mirror frontend/web's --fs-*. */
|
|
883
|
+
--w6w-fs-xs: 0.75rem;
|
|
884
|
+
--w6w-fs-sm: 0.875rem;
|
|
885
|
+
--w6w-fs-base: 1rem;
|
|
886
|
+
--w6w-fs-lg: 1.125rem;
|
|
887
|
+
--w6w-fs-xl: 1.25rem;
|
|
888
|
+
--w6w-fs-2xl: 1.5rem;
|
|
889
|
+
--w6w-fs-3xl: 2rem;
|
|
890
|
+
--w6w-fw-regular: 400;
|
|
891
|
+
--w6w-fw-medium: 500;
|
|
892
|
+
--w6w-fw-semibold: 600;
|
|
893
|
+
--w6w-fw-bold: 700;
|
|
894
|
+
--w6w-lh-tight: 1.2;
|
|
895
|
+
--w6w-lh-normal: 1.5;
|
|
896
|
+
--w6w-lh-relaxed: 1.7;
|
|
897
|
+
--w6w-font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
898
|
+
--w6w-font-mono: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
/*
|
|
902
|
+
* Breakpoints — Sass variables, NOT CSS custom properties.
|
|
903
|
+
*
|
|
904
|
+
* `@media (min-width: var(--w6w-bp-md))` is invalid in every browser: a media
|
|
905
|
+
* query condition cannot read a custom property. So these live as Sass
|
|
906
|
+
* variables instead, resolved before the browser ever sees the stylesheet.
|
|
907
|
+
* `!default` lets a Sass consumer override one:
|
|
908
|
+
*
|
|
909
|
+
* @use "@w6w/ui/styles/scale" with ($w6w-bp-md: 960px);
|
|
910
|
+
*
|
|
911
|
+
* `ui` itself consumes none of these — it deliberately ships no layout media
|
|
912
|
+
* queries (the host owns page layout; `ui` owns component internals). They
|
|
913
|
+
* exist purely so a consumer stops inventing its own breakpoint values (seven
|
|
914
|
+
* uncoordinated ones exist across the four repos today).
|
|
915
|
+
*/
|
|
916
|
+
/* Layout helpers */
|
|
917
|
+
.w6w-stack {
|
|
918
|
+
display: flex;
|
|
919
|
+
flex-direction: column;
|
|
920
|
+
gap: var(--w6w-sp-2-5);
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
/* Form fields */
|
|
924
|
+
.w6w-field {
|
|
925
|
+
display: flex;
|
|
926
|
+
flex-direction: column;
|
|
927
|
+
gap: var(--w6w-sp-1);
|
|
928
|
+
color: var(--w6w-muted);
|
|
929
|
+
font-size: 0.9em;
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
.w6w-field > span {
|
|
933
|
+
color: var(--w6w-muted);
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
.w6w-field input[type=text],
|
|
937
|
+
.w6w-field input[type=password],
|
|
938
|
+
.w6w-field input[type=number],
|
|
939
|
+
.w6w-field select,
|
|
940
|
+
.w6w-field textarea {
|
|
941
|
+
background: var(--w6w-panel-2);
|
|
942
|
+
border: 1px solid var(--w6w-border);
|
|
943
|
+
border-radius: 8px;
|
|
944
|
+
padding: var(--w6w-sp-2) var(--w6w-sp-2-5);
|
|
945
|
+
color: var(--w6w-text);
|
|
946
|
+
font-size: var(--w6w-fs-sm);
|
|
947
|
+
font-family: inherit;
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
/* Native popups: the list background follows `color-scheme` (declared with the
|
|
951
|
+
tokens), so give the options token colours too — never one theme's text on
|
|
952
|
+
the other theme's background. */
|
|
953
|
+
.w6w-field option,
|
|
954
|
+
.w6w-field optgroup,
|
|
955
|
+
select option,
|
|
956
|
+
select optgroup {
|
|
957
|
+
color: var(--w6w-text);
|
|
958
|
+
background-color: var(--w6w-panel);
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
.w6w-field input:focus,
|
|
962
|
+
.w6w-field select:focus,
|
|
963
|
+
.w6w-field textarea:focus {
|
|
964
|
+
outline: none;
|
|
965
|
+
border-color: var(--w6w-accent);
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
/* Credential inputs are plain text fields (never type="password", which would
|
|
969
|
+
trigger the browser's save-password prompt + suggestions). Mask them visually
|
|
970
|
+
so a secret still reads as dots. WebKit/Blink support text-security; other
|
|
971
|
+
engines fall back to plain text, which is acceptable for a credential. */
|
|
972
|
+
.w6w-secret-input {
|
|
973
|
+
-webkit-text-security: disc;
|
|
974
|
+
text-security: disc;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
.w6w-hint {
|
|
978
|
+
color: var(--w6w-muted);
|
|
979
|
+
font-size: 0.8em;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
/* Side-by-side fields: params sharing a `row` id lay out horizontally. */
|
|
983
|
+
.w6w-field-row {
|
|
984
|
+
display: flex;
|
|
985
|
+
flex-wrap: wrap;
|
|
986
|
+
gap: var(--w6w-sp-2-5);
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
.w6w-field-row > .w6w-field {
|
|
990
|
+
flex: 1 1 140px;
|
|
991
|
+
min-width: 0;
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
/* Array control: a row per item + an add button. */
|
|
995
|
+
.w6w-array {
|
|
996
|
+
display: flex;
|
|
997
|
+
flex-direction: column;
|
|
998
|
+
gap: var(--w6w-sp-1-5);
|
|
999
|
+
align-items: flex-start;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
.w6w-array-row {
|
|
1003
|
+
display: flex;
|
|
1004
|
+
align-items: center;
|
|
1005
|
+
gap: var(--w6w-sp-1-5);
|
|
1006
|
+
width: 100%;
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
.w6w-array-cells {
|
|
1010
|
+
display: flex;
|
|
1011
|
+
flex-wrap: wrap;
|
|
1012
|
+
gap: var(--w6w-sp-1-5);
|
|
1013
|
+
flex: 1;
|
|
1014
|
+
min-width: 0;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
.w6w-array-cells > .w6w-array-input {
|
|
1018
|
+
flex: 1 1 120px;
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
/* An object-item array row's boolean cell: `<label><checkbox><span>`. It is a
|
|
1022
|
+
`<label>`, so `margin: 0` is load-bearing for the same reason it is on
|
|
1023
|
+
`.w6w-fx-inline-label` further down — a host page layers an unscoped
|
|
1024
|
+
`label { margin-bottom: 10px }` after this file (studio's does, at
|
|
1025
|
+
`studio/src/styles.css:499`) and owns any property this block leaves
|
|
1026
|
+
undeclared. `.w6w-array-cells` is a flex row at the default `align-items:
|
|
1027
|
+
stretch`, so a bottom margin does not translate this cell, it SHORTENS its
|
|
1028
|
+
stretched box — and because this block centres its own contents, the checkbox
|
|
1029
|
+
and its caption then ride upward off the row's centre line. Measured before
|
|
1030
|
+
this declaration existed, in [ui+studio]: checkbox cy 792 against the sibling
|
|
1031
|
+
text cell's 799 — 7.0px out, while a ui-only render showed 0.0px. */
|
|
1032
|
+
.w6w-array-check {
|
|
1033
|
+
display: inline-flex;
|
|
1034
|
+
align-items: center;
|
|
1035
|
+
gap: var(--w6w-sp-1-5);
|
|
1036
|
+
flex: 0 0 auto;
|
|
1037
|
+
margin: 0;
|
|
1038
|
+
font-size: 13px;
|
|
1039
|
+
color: var(--w6w-text);
|
|
1040
|
+
white-space: nowrap;
|
|
1041
|
+
cursor: pointer;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
/* `> input[type="checkbox"]`, not `input`: a bare `.w6w-array-check input` is
|
|
1045
|
+
(0,1,1), which TIES with a host `input[type="checkbox"] { margin-right: 6px }`
|
|
1046
|
+
(studio/src/styles.css:785) and then loses on source order — measured
|
|
1047
|
+
`margin-right: 6px` reaching this checkbox with the `margin: 0` below already
|
|
1048
|
+
present. The compound form is (0,2,1) and wins outright. Same shape as
|
|
1049
|
+
`.w6w-fx-inline > input[type="checkbox"]`, which is why that one was never
|
|
1050
|
+
affected. */
|
|
1051
|
+
.w6w-array-check > input[type=checkbox] {
|
|
1052
|
+
margin: 0;
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
.w6w-field .w6w-array-input {
|
|
1056
|
+
flex: 1;
|
|
1057
|
+
min-width: 0;
|
|
1058
|
+
/* Load-bearing, same class as `.w6w-array-check` above: a host
|
|
1059
|
+
`input[type="text"] { margin-top: 4px }` otherwise lands here and drops this
|
|
1060
|
+
cell 2px below its own row's checkbox cell. Measured in [ui+studio]:
|
|
1061
|
+
checkbox cy 797 against this input's 799. This selector is (0,2,0) and beats
|
|
1062
|
+
the host's (0,1,1). */
|
|
1063
|
+
margin: 0;
|
|
1064
|
+
background: var(--w6w-panel-2);
|
|
1065
|
+
border: 1px solid var(--w6w-border);
|
|
1066
|
+
border-radius: 8px;
|
|
1067
|
+
padding: var(--w6w-sp-1-5) var(--w6w-sp-2);
|
|
1068
|
+
color: var(--w6w-text);
|
|
1069
|
+
font-size: var(--w6w-fs-sm);
|
|
1070
|
+
font-family: inherit;
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
.w6w-field .w6w-array-input:focus {
|
|
1074
|
+
outline: none;
|
|
1075
|
+
border-color: var(--w6w-accent);
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
.w6w-array-x {
|
|
1079
|
+
display: inline-flex;
|
|
1080
|
+
align-items: center;
|
|
1081
|
+
justify-content: center;
|
|
1082
|
+
width: 26px;
|
|
1083
|
+
height: 26px;
|
|
1084
|
+
flex-shrink: 0;
|
|
1085
|
+
border: 1px solid var(--w6w-border);
|
|
1086
|
+
border-radius: 8px;
|
|
1087
|
+
background: transparent;
|
|
1088
|
+
color: var(--w6w-muted);
|
|
1089
|
+
font-size: var(--w6w-fs-base);
|
|
1090
|
+
line-height: 1;
|
|
1091
|
+
cursor: pointer;
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
.w6w-array-x:hover {
|
|
1095
|
+
background: var(--w6w-panel-2);
|
|
1096
|
+
color: var(--w6w-text);
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
.w6w-array-add {
|
|
1100
|
+
margin-top: var(--w6w-sp-0-5);
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
/* Material-style multi-select: chips live INSIDE a single input-like box,
|
|
1104
|
+
followed by the dropdown which reads as the trailing placeholder. */
|
|
1105
|
+
.w6w-multiselect {
|
|
1106
|
+
display: flex;
|
|
1107
|
+
flex-wrap: wrap;
|
|
1108
|
+
align-items: center;
|
|
1109
|
+
gap: var(--w6w-sp-1-5);
|
|
1110
|
+
background: var(--w6w-panel-2);
|
|
1111
|
+
border: 1px solid var(--w6w-border);
|
|
1112
|
+
border-radius: 8px;
|
|
1113
|
+
padding: 5px var(--w6w-sp-2);
|
|
1114
|
+
min-height: 38px;
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
.w6w-multiselect:focus-within {
|
|
1118
|
+
border-color: var(--w6w-accent);
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
.w6w-multiselect.is-readonly {
|
|
1122
|
+
opacity: 0.7;
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
/* The add-dropdown blends into the box (no border/background) — compound
|
|
1126
|
+
selector so it beats the global `.w6w-field select` styling. */
|
|
1127
|
+
.w6w-field .w6w-multiselect-add,
|
|
1128
|
+
.w6w-multiselect .w6w-multiselect-add {
|
|
1129
|
+
flex: 1 1 90px;
|
|
1130
|
+
min-width: 90px;
|
|
1131
|
+
border: none;
|
|
1132
|
+
background: transparent;
|
|
1133
|
+
color: var(--w6w-muted);
|
|
1134
|
+
font-size: var(--w6w-fs-sm);
|
|
1135
|
+
font-family: inherit;
|
|
1136
|
+
padding: var(--w6w-sp-0-5) 0;
|
|
1137
|
+
outline: none;
|
|
1138
|
+
cursor: pointer;
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
.w6w-multiselect .w6w-multiselect-add:disabled {
|
|
1142
|
+
cursor: default;
|
|
1143
|
+
opacity: 0.6;
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
/* A selected value, rendered as a filled chip inside the box. */
|
|
1147
|
+
.w6w-chip {
|
|
1148
|
+
display: inline-flex;
|
|
1149
|
+
align-items: center;
|
|
1150
|
+
gap: var(--w6w-sp-1);
|
|
1151
|
+
background: var(--w6w-panel);
|
|
1152
|
+
border: 1px solid var(--w6w-border);
|
|
1153
|
+
border-radius: 6px;
|
|
1154
|
+
padding: var(--w6w-sp-0-5) var(--w6w-sp-1) var(--w6w-sp-0-5) var(--w6w-sp-2);
|
|
1155
|
+
font-size: 13px;
|
|
1156
|
+
line-height: 1.4;
|
|
1157
|
+
color: var(--w6w-text);
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
.w6w-chip-x {
|
|
1161
|
+
display: inline-flex;
|
|
1162
|
+
align-items: center;
|
|
1163
|
+
justify-content: center;
|
|
1164
|
+
width: 16px;
|
|
1165
|
+
height: 16px;
|
|
1166
|
+
border: none;
|
|
1167
|
+
border-radius: 4px;
|
|
1168
|
+
background: transparent;
|
|
1169
|
+
color: var(--w6w-muted);
|
|
1170
|
+
font-size: var(--w6w-fs-sm);
|
|
1171
|
+
line-height: 1;
|
|
1172
|
+
cursor: pointer;
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
.w6w-chip-x:hover {
|
|
1176
|
+
background: var(--w6w-border);
|
|
1177
|
+
color: var(--w6w-text);
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
/* Incoming state (WorkflowFlowEditor · `IncomingStateField`, mounted by BOTH the
|
|
1181
|
+
step editor's Test tab and the canvas ▶ Run collect form). The raw JSON box is
|
|
1182
|
+
an OVERRIDE, so it sits behind a disclosure instead of being the first thing
|
|
1183
|
+
the tab shows — the seed chips above it stay in plain sight. */
|
|
1184
|
+
.w6w-state-override {
|
|
1185
|
+
border: 1px solid var(--w6w-border);
|
|
1186
|
+
border-radius: 6px;
|
|
1187
|
+
padding: var(--w6w-sp-1-5) var(--w6w-sp-2);
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
.w6w-state-override > summary {
|
|
1191
|
+
cursor: pointer;
|
|
1192
|
+
color: var(--w6w-muted);
|
|
1193
|
+
font-size: 0.85em;
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
/* Breathing room only once it is open: closed, the summary IS the whole box. */
|
|
1197
|
+
.w6w-state-override[open] > summary {
|
|
1198
|
+
margin-bottom: var(--w6w-sp-1-5);
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
.w6w-state-override > .w6w-hint {
|
|
1202
|
+
display: block;
|
|
1203
|
+
margin-top: var(--w6w-sp-1);
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
/* Incoming-state seed picker: upstream steps' saved tests offered as one-click
|
|
1207
|
+
seeds for the step's incoming state (WorkflowFlowEditor · StepEditModal). */
|
|
1208
|
+
.w6w-seed-picker {
|
|
1209
|
+
display: flex;
|
|
1210
|
+
flex-direction: column;
|
|
1211
|
+
gap: var(--w6w-sp-1);
|
|
1212
|
+
margin-bottom: var(--w6w-sp-1-5);
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
.w6w-seed-chips {
|
|
1216
|
+
display: flex;
|
|
1217
|
+
flex-wrap: wrap;
|
|
1218
|
+
gap: var(--w6w-sp-1-5);
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
.w6w-seed-chip {
|
|
1222
|
+
cursor: pointer;
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
.w6w-seed-chip:hover:not(:disabled) {
|
|
1226
|
+
border-color: var(--w6w-text);
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
.w6w-seed-chip:disabled {
|
|
1230
|
+
cursor: default;
|
|
1231
|
+
opacity: 0.6;
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
/* Expression input: a field whose contents are inline SEGMENTS — plain text
|
|
1235
|
+
plus var/secret/expr chips, edited in place (contentEditable, like a Notion /
|
|
1236
|
+
Zapier block field). A small toolbar carries the Insert menu + the {{ }} (fx)
|
|
1237
|
+
mode toggle. Theme-aware via the shared tokens. */
|
|
1238
|
+
.w6w-expr {
|
|
1239
|
+
display: flex;
|
|
1240
|
+
flex-direction: column;
|
|
1241
|
+
gap: var(--w6w-sp-1-5);
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
/* Inline expression field: ONE input-like box holding the editable surface plus
|
|
1245
|
+
a ƒx button that reads as a trailing decoration INSIDE it — the same idiom as
|
|
1246
|
+
`.w6w-multiselect` above and `.w6w-expr-sealed` below. The box lives here so
|
|
1247
|
+
the standalone uses still render as a field (the `secret` param path and the
|
|
1248
|
+
public ExpressionInput export). When this rides inside a `.w6w-fx-wrap`, that
|
|
1249
|
+
wrapper is the box and this is flattened — see `.w6w-fx-wrap` below. */
|
|
1250
|
+
.w6w-expr-field {
|
|
1251
|
+
display: flex;
|
|
1252
|
+
align-items: center;
|
|
1253
|
+
gap: var(--w6w-sp-1);
|
|
1254
|
+
background: var(--w6w-panel-2);
|
|
1255
|
+
border: 1px solid var(--w6w-border);
|
|
1256
|
+
border-radius: 8px;
|
|
1257
|
+
padding: var(--w6w-sp-1) var(--w6w-sp-2);
|
|
1258
|
+
min-height: 38px;
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
.w6w-expr-field:focus-within {
|
|
1262
|
+
border-color: var(--w6w-accent);
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
.w6w-expr-field .w6w-expr-editor {
|
|
1266
|
+
flex: 1;
|
|
1267
|
+
min-width: 0;
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
/* The ƒx rides inside the box, so it draws no chrome of its own — only its
|
|
1271
|
+
colour states remain. */
|
|
1272
|
+
.w6w-expr-field .w6w-expr-edit {
|
|
1273
|
+
border: none;
|
|
1274
|
+
background: transparent;
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
.w6w-expr-edit {
|
|
1278
|
+
flex-shrink: 0;
|
|
1279
|
+
color: var(--w6w-muted);
|
|
1280
|
+
font-family: var(--w6w-font-mono);
|
|
1281
|
+
font-size: 13px;
|
|
1282
|
+
line-height: 1;
|
|
1283
|
+
padding: var(--w6w-sp-1) var(--w6w-sp-1-5);
|
|
1284
|
+
cursor: pointer;
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
.w6w-expr-edit:hover {
|
|
1288
|
+
color: var(--w6w-accent);
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
/* Sealed at-rest secret (masked chip + Replace). */
|
|
1292
|
+
.w6w-expr-sealed {
|
|
1293
|
+
display: flex;
|
|
1294
|
+
align-items: center;
|
|
1295
|
+
gap: var(--w6w-sp-1-5);
|
|
1296
|
+
background: var(--w6w-panel-2);
|
|
1297
|
+
border: 1px solid var(--w6w-border);
|
|
1298
|
+
border-radius: 8px;
|
|
1299
|
+
padding: 5px var(--w6w-sp-2);
|
|
1300
|
+
min-height: 38px;
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
.w6w-expr-sealed.is-readonly {
|
|
1304
|
+
opacity: 0.7;
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
/* Expression editor modal: left data sources | right (editor over preview). */
|
|
1308
|
+
.w6w-exprmodal {
|
|
1309
|
+
flex: 1;
|
|
1310
|
+
min-height: 0;
|
|
1311
|
+
display: grid;
|
|
1312
|
+
grid-template-columns: 260px 1fr;
|
|
1313
|
+
gap: 14px;
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
.w6w-exprmodal-sources {
|
|
1317
|
+
overflow: auto;
|
|
1318
|
+
border: 1px solid var(--w6w-border);
|
|
1319
|
+
border-radius: 8px;
|
|
1320
|
+
background: var(--w6w-panel-2);
|
|
1321
|
+
padding: var(--w6w-sp-2-5);
|
|
1322
|
+
display: flex;
|
|
1323
|
+
flex-direction: column;
|
|
1324
|
+
gap: 14px;
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
.w6w-exprmodal-group {
|
|
1328
|
+
display: flex;
|
|
1329
|
+
flex-direction: column;
|
|
1330
|
+
gap: 3px;
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
.w6w-exprmodal-group-label {
|
|
1334
|
+
font-size: 0.72em;
|
|
1335
|
+
font-weight: var(--w6w-fw-semibold);
|
|
1336
|
+
letter-spacing: 0.04em;
|
|
1337
|
+
text-transform: uppercase;
|
|
1338
|
+
color: var(--w6w-muted);
|
|
1339
|
+
margin-bottom: var(--w6w-sp-0-5);
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
.w6w-exprmodal-source {
|
|
1343
|
+
display: flex;
|
|
1344
|
+
align-items: center;
|
|
1345
|
+
gap: var(--w6w-sp-1-5);
|
|
1346
|
+
text-align: left;
|
|
1347
|
+
background: transparent;
|
|
1348
|
+
border: 1px solid transparent;
|
|
1349
|
+
border-radius: 6px;
|
|
1350
|
+
padding: 5px var(--w6w-sp-2);
|
|
1351
|
+
color: var(--w6w-text);
|
|
1352
|
+
font-size: 13px;
|
|
1353
|
+
font-family: inherit;
|
|
1354
|
+
cursor: pointer;
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
.w6w-exprmodal-source:hover {
|
|
1358
|
+
background: var(--w6w-panel);
|
|
1359
|
+
border-color: var(--w6w-border);
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
.w6w-exprmodal-source.w6w-expr-chip-var {
|
|
1363
|
+
color: var(--w6w-accent);
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
.w6w-exprmodal-source.w6w-expr-chip-secret {
|
|
1367
|
+
color: var(--w6w-danger);
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
.w6w-exprmodal-source-label {
|
|
1371
|
+
overflow: hidden;
|
|
1372
|
+
text-overflow: ellipsis;
|
|
1373
|
+
white-space: nowrap;
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
/* A step's per-field sources, nested under its whole-output source, so three
|
|
1377
|
+
upstream steps x four fields reads as a tree rather than a flat wall. */
|
|
1378
|
+
.w6w-exprmodal-subsources {
|
|
1379
|
+
display: flex;
|
|
1380
|
+
flex-direction: column;
|
|
1381
|
+
gap: 3px;
|
|
1382
|
+
margin-left: 9px;
|
|
1383
|
+
padding-left: var(--w6w-sp-2);
|
|
1384
|
+
border-left: 1px solid var(--w6w-border);
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
/* One document-field row: the primary insert source (flex: 1, so it still
|
|
1388
|
+
truncates a long key the same way a bare `.w6w-exprmodal-source` does) plus
|
|
1389
|
+
the second, visible action (D-P1) that inserts the SAME ref as a `render`
|
|
1390
|
+
part — so the two read as one entry, not two unrelated controls. */
|
|
1391
|
+
.w6w-exprmodal-subsource-row {
|
|
1392
|
+
display: flex;
|
|
1393
|
+
align-items: center;
|
|
1394
|
+
gap: var(--w6w-sp-1);
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
.w6w-exprmodal-subsource-row .w6w-exprmodal-source {
|
|
1398
|
+
flex: 1;
|
|
1399
|
+
min-width: 0;
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
.w6w-exprmodal-render-btn {
|
|
1403
|
+
display: inline-flex;
|
|
1404
|
+
flex: none;
|
|
1405
|
+
align-items: center;
|
|
1406
|
+
justify-content: center;
|
|
1407
|
+
width: 20px;
|
|
1408
|
+
height: 20px;
|
|
1409
|
+
border: 1px solid var(--w6w-border);
|
|
1410
|
+
border-radius: 6px;
|
|
1411
|
+
background: transparent;
|
|
1412
|
+
color: var(--w6w-success);
|
|
1413
|
+
opacity: 0.75;
|
|
1414
|
+
font-size: var(--w6w-fs-xs);
|
|
1415
|
+
cursor: pointer;
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
.w6w-exprmodal-render-btn:hover {
|
|
1419
|
+
opacity: 1;
|
|
1420
|
+
background: var(--w6w-panel);
|
|
1421
|
+
border-color: var(--w6w-success);
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
/* A rail source with surviving child rows (a multi-field document, a step
|
|
1425
|
+
with declared outputs) — the "whole source" button plus the expand/collapse
|
|
1426
|
+
toggle, as siblings on one row. Mirrors `.w6w-exprmodal-subsource-row`'s
|
|
1427
|
+
flex row + child-fills-width shape (`:74-82` above), kept as its own class
|
|
1428
|
+
because the two are counted independently by the test suite. */
|
|
1429
|
+
.w6w-exprmodal-source-row {
|
|
1430
|
+
display: flex;
|
|
1431
|
+
align-items: center;
|
|
1432
|
+
gap: var(--w6w-sp-1);
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
.w6w-exprmodal-source-row .w6w-exprmodal-source {
|
|
1436
|
+
flex: 1;
|
|
1437
|
+
min-width: 0;
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
/* A step row's disclosure caret, sitting where the chip's `▸` sigil was —
|
|
1441
|
+
that arrow reads as "expand", so on a row with fields it does exactly that
|
|
1442
|
+
(the chip beside it still inserts the whole output). */
|
|
1443
|
+
.w6w-exprmodal-caret-btn {
|
|
1444
|
+
display: inline-flex;
|
|
1445
|
+
flex: none;
|
|
1446
|
+
align-items: center;
|
|
1447
|
+
justify-content: center;
|
|
1448
|
+
width: 20px;
|
|
1449
|
+
height: 20px;
|
|
1450
|
+
padding: 0;
|
|
1451
|
+
border: 0;
|
|
1452
|
+
border-radius: 6px;
|
|
1453
|
+
background: transparent;
|
|
1454
|
+
color: var(--w6w-accent);
|
|
1455
|
+
font-size: var(--w6w-fs-xs);
|
|
1456
|
+
cursor: pointer;
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
.w6w-exprmodal-caret-btn:hover {
|
|
1460
|
+
background: var(--w6w-panel);
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
/* The "N fields" toggle with the Metadata toggle stacked under it, so both
|
|
1464
|
+
disclosures share one left edge on a step row. */
|
|
1465
|
+
.w6w-exprmodal-toggle-stack {
|
|
1466
|
+
display: flex;
|
|
1467
|
+
flex: none;
|
|
1468
|
+
flex-direction: column;
|
|
1469
|
+
align-items: flex-start;
|
|
1470
|
+
gap: 3px; /* lint-tokens-allow: 3px sits between no two steps of the spacing scale; tight stack of the fields and Metadata toggles */
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
/* A step with no fields: its Metadata toggle sits at the leaf indentation of
|
|
1474
|
+
`.w6w-exprmodal-subsources` (margin 9px + 1px border + sp-2 padding). */
|
|
1475
|
+
.w6w-exprmodal-meta-row {
|
|
1476
|
+
margin-left: calc(10px + var(--w6w-sp-2)); /* lint-tokens-allow: 9px margin + 1px border of .w6w-exprmodal-subsources */
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
/* Same 20px-high chrome as `.w6w-exprmodal-render-btn` above — the sizing
|
|
1480
|
+
precedent for a dense rail control — but a separate class: this toggles
|
|
1481
|
+
the `.w6w-exprmodal-subsources` block below it, the render-btn inserts a
|
|
1482
|
+
`render` part. It carries a "N fields" label, not a bare chevron, so it is
|
|
1483
|
+
auto-width (a lone 20px chevron went unnoticed beside the chip). */
|
|
1484
|
+
.w6w-exprmodal-toggle-btn {
|
|
1485
|
+
display: inline-flex;
|
|
1486
|
+
flex: none;
|
|
1487
|
+
align-items: center;
|
|
1488
|
+
justify-content: center;
|
|
1489
|
+
gap: var(--w6w-sp-1);
|
|
1490
|
+
height: 20px;
|
|
1491
|
+
padding: 0 6px; /* lint-tokens-allow: no 6px step on the spacing scale; between sp-1 and sp-2 keeps the 20px pill's label centred */
|
|
1492
|
+
white-space: nowrap;
|
|
1493
|
+
border: 1px solid var(--w6w-border);
|
|
1494
|
+
border-radius: 6px;
|
|
1495
|
+
background: transparent;
|
|
1496
|
+
color: var(--w6w-muted);
|
|
1497
|
+
font-size: var(--w6w-fs-xs);
|
|
1498
|
+
cursor: pointer;
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
.w6w-exprmodal-toggle-btn:hover {
|
|
1502
|
+
background: var(--w6w-panel);
|
|
1503
|
+
border-color: var(--w6w-accent);
|
|
1504
|
+
color: var(--w6w-text);
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
.w6w-exprmodal-main {
|
|
1508
|
+
min-width: 0;
|
|
1509
|
+
min-height: 0;
|
|
1510
|
+
display: flex;
|
|
1511
|
+
flex-direction: column;
|
|
1512
|
+
gap: var(--w6w-sp-3);
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
.w6w-exprmodal-editor {
|
|
1516
|
+
display: flex;
|
|
1517
|
+
flex-direction: column;
|
|
1518
|
+
gap: var(--w6w-sp-1-5);
|
|
1519
|
+
min-height: 0;
|
|
1520
|
+
flex: 1 1 auto;
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
.w6w-exprmodal-pane-label {
|
|
1524
|
+
font-size: 13px;
|
|
1525
|
+
font-weight: var(--w6w-fw-semibold);
|
|
1526
|
+
color: var(--w6w-text);
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
/* The WYSIWYG chip editor: tags flow inline with text (colored + spaced). */
|
|
1530
|
+
.w6w-exprmodal-chips {
|
|
1531
|
+
flex: 1;
|
|
1532
|
+
min-height: 180px;
|
|
1533
|
+
overflow: auto;
|
|
1534
|
+
background: var(--w6w-panel-2);
|
|
1535
|
+
border: 1px solid var(--w6w-border);
|
|
1536
|
+
border-radius: 8px;
|
|
1537
|
+
padding: var(--w6w-sp-2-5) var(--w6w-sp-3);
|
|
1538
|
+
color: var(--w6w-text);
|
|
1539
|
+
font-size: var(--w6w-fs-sm);
|
|
1540
|
+
line-height: 2.1;
|
|
1541
|
+
outline: none;
|
|
1542
|
+
white-space: pre-wrap;
|
|
1543
|
+
word-break: break-word;
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
.w6w-exprmodal-chips:focus {
|
|
1547
|
+
border-color: var(--w6w-accent);
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
.w6w-exprmodal-chips.is-empty::before {
|
|
1551
|
+
content: attr(data-placeholder);
|
|
1552
|
+
color: var(--w6w-muted);
|
|
1553
|
+
pointer-events: none;
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
.w6w-exprmodal-chips.is-masked {
|
|
1557
|
+
-webkit-text-security: disc;
|
|
1558
|
+
text-security: disc;
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
.w6w-exprmodal-chips.is-masked .w6w-expr-chip {
|
|
1562
|
+
-webkit-text-security: none;
|
|
1563
|
+
text-security: none;
|
|
1564
|
+
}
|
|
1565
|
+
|
|
1566
|
+
.w6w-exprmodal-preview {
|
|
1567
|
+
display: flex;
|
|
1568
|
+
flex-direction: column;
|
|
1569
|
+
gap: var(--w6w-sp-1-5);
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
/* The Result pane's own share of `.w6w-exprmodal-main`'s flex column — the
|
|
1573
|
+
SHARE lives on this wrapper, not on the `<pre>` below: the `<pre>`'s parent
|
|
1574
|
+
is this wrapper (`.w6w-exprmodal-preview`, a flex column), not `-main`
|
|
1575
|
+
itself, so a `flex-basis` on the `<pre>` would be a share of a
|
|
1576
|
+
content-sized box and do nothing. 42% keeps the pane in the 30-50% band and
|
|
1577
|
+
the chips editor above the 25% floor at 1440x900, 1280x720 and 1440x1200 —
|
|
1578
|
+
measured in real Chromium, `test/expr-template/expr-template-guards.test.cjs`
|
|
1579
|
+
T-height; see the project's result for the numbers. */
|
|
1580
|
+
.w6w-exprmodal-result-pane {
|
|
1581
|
+
flex: 0 0 42%;
|
|
1582
|
+
min-height: 0;
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
/* The pane's 42% share above is a flex-basis on `.w6w-exprmodal-result-pane`
|
|
1586
|
+
itself (a column flex container) — it must still reach the `<pre>` now that
|
|
1587
|
+
`Copyable` wraps it in a `.w6w-copyable` div. That wrapper is the actual
|
|
1588
|
+
column child now, so it needs the grow/shrink share instead. */
|
|
1589
|
+
.w6w-exprmodal-result-pane > .w6w-copyable {
|
|
1590
|
+
flex: 1 1 auto;
|
|
1591
|
+
min-height: 0;
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
.w6w-exprmodal-result {
|
|
1595
|
+
flex: 1 1 auto;
|
|
1596
|
+
/* `.w6w-copyable` is a ROW flex container (`_copyable.scss:5`), and its
|
|
1597
|
+
`:has(> pre)` arm (`_copyable.scss:19-21`) sets `align-items: flex-start`
|
|
1598
|
+
for CodeBlock's snippet case, where the box is sized TO the pre's
|
|
1599
|
+
content. Here it's the other way around — the wrapper is grown to the
|
|
1600
|
+
pane's share by the rule above, and the `<pre>` must fill IT. `flex: 1 1
|
|
1601
|
+
auto`'s grow/shrink applies to the row's main axis (width) and does
|
|
1602
|
+
nothing for height there, so the cross-axis stretch has to be pinned
|
|
1603
|
+
directly on this item, overriding the container's `flex-start`. */
|
|
1604
|
+
align-self: stretch;
|
|
1605
|
+
min-height: 0;
|
|
1606
|
+
max-height: none;
|
|
1607
|
+
overflow: auto;
|
|
1608
|
+
margin: 0;
|
|
1609
|
+
background: var(--w6w-panel-2);
|
|
1610
|
+
border: 1px solid var(--w6w-border);
|
|
1611
|
+
border-radius: 8px;
|
|
1612
|
+
padding: var(--w6w-sp-2-5) var(--w6w-sp-3);
|
|
1613
|
+
/* `_copyable.scss:105-107`'s corner-button clearance is scoped to
|
|
1614
|
+
`.w6w-code-block` and does not apply here — same 40px value (icon box +
|
|
1615
|
+
inset + gap) so the overlaid copy button never sits on the first line. */
|
|
1616
|
+
padding-right: var(--w6w-sp-10);
|
|
1617
|
+
color: var(--w6w-muted);
|
|
1618
|
+
font-family: var(--w6w-font-mono);
|
|
1619
|
+
font-size: 12.5px;
|
|
1620
|
+
line-height: 1.6;
|
|
1621
|
+
white-space: pre-wrap;
|
|
1622
|
+
word-break: break-word;
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
.w6w-exprmodal-actions {
|
|
1626
|
+
display: flex;
|
|
1627
|
+
gap: var(--w6w-sp-2);
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
.w6w-expr-toolbar {
|
|
1631
|
+
display: flex;
|
|
1632
|
+
align-items: center;
|
|
1633
|
+
gap: var(--w6w-sp-2);
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
/* fx toggle — an end decoration INSIDE the field, not a button beside it. The
|
|
1637
|
+
WRAPPER owns the input chrome (background/border/radius/min-height and the
|
|
1638
|
+
focus ring) and every widget it holds is flattened below, so the value and its
|
|
1639
|
+
ƒx affordance read as ONE box. Mirrors `.w6w-multiselect` above. */
|
|
1640
|
+
.w6w-fx-wrap {
|
|
1641
|
+
display: flex;
|
|
1642
|
+
align-items: center;
|
|
1643
|
+
gap: var(--w6w-sp-1);
|
|
1644
|
+
background: var(--w6w-panel-2);
|
|
1645
|
+
border: 1px solid var(--w6w-border);
|
|
1646
|
+
border-radius: 8px;
|
|
1647
|
+
padding: var(--w6w-sp-1) var(--w6w-sp-2);
|
|
1648
|
+
min-height: 38px;
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1651
|
+
/* A textarea is taller than the ƒx, so there the decoration rides at the top. */
|
|
1652
|
+
.w6w-fx-wrap:has(> textarea) {
|
|
1653
|
+
align-items: flex-start;
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
/* Focus reads on the box now that the inner widget has no border of its own. */
|
|
1657
|
+
.w6w-fx-wrap:focus-within {
|
|
1658
|
+
border-color: var(--w6w-accent);
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
.w6w-fx-wrap > input,
|
|
1662
|
+
.w6w-fx-wrap > select,
|
|
1663
|
+
.w6w-fx-wrap > textarea,
|
|
1664
|
+
.w6w-fx-wrap > .w6w-multiselect,
|
|
1665
|
+
.w6w-fx-wrap > .w6w-expr {
|
|
1666
|
+
flex: 1 1 auto;
|
|
1667
|
+
min-width: 0;
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
/* The widget inside the wrapper carries NO chrome of its own. COMPOUND
|
|
1671
|
+
selectors, because the global `.w6w-field input|select|textarea` rule is
|
|
1672
|
+
(0,2,1) and a bare `.w6w-fx-wrap > input` at (0,1,1) would lose to it — the
|
|
1673
|
+
same trap documented on `.w6w-multiselect-add` above. `.w6w-datavar-row
|
|
1674
|
+
input|select` is the second rule to beat, for the `bare` vars-row cell. */
|
|
1675
|
+
.w6w-field .w6w-fx-wrap input[type=text],
|
|
1676
|
+
.w6w-field .w6w-fx-wrap input[type=password],
|
|
1677
|
+
.w6w-field .w6w-fx-wrap input[type=number],
|
|
1678
|
+
.w6w-field .w6w-fx-wrap select,
|
|
1679
|
+
.w6w-field .w6w-fx-wrap textarea,
|
|
1680
|
+
.w6w-datavar-row .w6w-fx-wrap input,
|
|
1681
|
+
.w6w-datavar-row .w6w-fx-wrap select,
|
|
1682
|
+
.w6w-fx-wrap input[type=text],
|
|
1683
|
+
.w6w-fx-wrap input[type=password],
|
|
1684
|
+
.w6w-fx-wrap input[type=number],
|
|
1685
|
+
.w6w-fx-wrap select,
|
|
1686
|
+
.w6w-fx-wrap textarea {
|
|
1687
|
+
border: none;
|
|
1688
|
+
background: transparent;
|
|
1689
|
+
border-radius: 0;
|
|
1690
|
+
padding: var(--w6w-sp-1) var(--w6w-sp-0-5);
|
|
1691
|
+
outline: none;
|
|
1692
|
+
/* EVERY property in this block is load-bearing, for the same reason
|
|
1693
|
+
`.w6w-fx-inline-label`'s `margin: 0` is (see below): a host page layers its
|
|
1694
|
+
own unscoped `input[type="text"], textarea { … }` rule AFTER this file
|
|
1695
|
+
(studio's does, at `studio/src/styles.css:513-533`, `:759-771` and `:788`),
|
|
1696
|
+
so every property this block leaves undeclared is the host's — including
|
|
1697
|
+
inside a box this library draws. The two below were measured leaking, in
|
|
1698
|
+
[ui+studio], before they were declared — and they fix DIFFERENT things:
|
|
1699
|
+
|
|
1700
|
+
margin — ALIGNMENT. A host `margin-top: 4px` in an `align-items:
|
|
1701
|
+
center` row drops the control 2px below the ƒx it shares the
|
|
1702
|
+
row with (string, number and the bare vars cell; select and
|
|
1703
|
+
multiselect escaped only because the host rule does not list
|
|
1704
|
+
them). Rendered: control cy 67 vs ƒx cy 65. On the textarea
|
|
1705
|
+
row — `align-items: flex-start` — the same 4px showed up as
|
|
1706
|
+
the ƒx sitting 4px off the control's first line. `margin: 0`
|
|
1707
|
+
is the whole of that fix.
|
|
1708
|
+
|
|
1709
|
+
min-height — SIZE, and nothing else. Do not re-justify this one as
|
|
1710
|
+
alignment: the counterfactual was rendered (this `margin: 0`
|
|
1711
|
+
kept, `min-height: 0` removed) and the row measures a 0.0px
|
|
1712
|
+
top delta with the host's 80px floor fully in effect. What it
|
|
1713
|
+
fixes is that a host `textarea { min-height: 80px }`, written
|
|
1714
|
+
for that host's own bare textareas, was sizing the INSIDE of
|
|
1715
|
+
a box it cannot see — 80px/94px against the 62px/72px the
|
|
1716
|
+
same markup renders elsewhere, i.e. one of five control types
|
|
1717
|
+
29% taller than the library drew it. The box is the library's
|
|
1718
|
+
to size; how many lines it holds is `rows` on the control.
|
|
1719
|
+
If a taller body field is ever wanted, it belongs HERE, not
|
|
1720
|
+
in a host element selector.
|
|
1721
|
+
|
|
1722
|
+
Declared, not fought for: this stays at the block's existing specificity and
|
|
1723
|
+
uses no `!important`. A component that is only aligned while the host
|
|
1724
|
+
cooperates is broken. */
|
|
1725
|
+
margin: 0;
|
|
1726
|
+
min-height: 0;
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1729
|
+
/* …and the two widgets that own an input-like box themselves are flattened too,
|
|
1730
|
+
so the wrapper never draws a box around a box. */
|
|
1731
|
+
.w6w-fx-wrap .w6w-expr-field,
|
|
1732
|
+
.w6w-fx-wrap .w6w-multiselect {
|
|
1733
|
+
border: none;
|
|
1734
|
+
background: transparent;
|
|
1735
|
+
border-radius: 0;
|
|
1736
|
+
padding: 0;
|
|
1737
|
+
min-height: 0;
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
/* The OTHER wrapper FxField can render (`variant="inline"`). A control that does
|
|
1741
|
+
not FILL a text-field box — today only a `boolean`'s ~13px checkbox — opts out
|
|
1742
|
+
of the box at the component seam and lands here instead, so `.w6w-fx-wrap`'s
|
|
1743
|
+
chrome above is never applied and nothing has to be clawed back with a more
|
|
1744
|
+
specific selector. Layout is the review's sketch: <checkbox> <ƒx> <label>,
|
|
1745
|
+
one row, no border/background/padding/min-height of its own. */
|
|
1746
|
+
.w6w-fx-inline {
|
|
1747
|
+
display: flex;
|
|
1748
|
+
align-items: center;
|
|
1749
|
+
gap: var(--w6w-sp-2);
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
.w6w-fx-inline > input[type=checkbox] {
|
|
1753
|
+
flex: 0 0 auto;
|
|
1754
|
+
margin: 0;
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1757
|
+
/* The label reads as the control's own text, next to it (mirrors
|
|
1758
|
+
`.w6w-array-check` above, the existing inline-checkbox idiom).
|
|
1759
|
+
`margin: 0` is LOAD-BEARING, not tidiness: a host page may carry an unscoped
|
|
1760
|
+
top-level `label { … margin-bottom: 10px }` (studio's own sheet does, at
|
|
1761
|
+
`studio/src/styles.css:499`), and since it is layered AFTER this file any
|
|
1762
|
+
property this block leaves undeclared is the host's. A bottom margin inside an
|
|
1763
|
+
`align-items: center` row lifts the text off the row's centre line — measured
|
|
1764
|
+
5px above the checkbox and the ƒx before this declaration existed. Every other
|
|
1765
|
+
element of the row is defended the same way: the checkbox's `margin: 0` above
|
|
1766
|
+
out-specifies a host `input[type="checkbox"] { margin-right: … }` (0,2,1 vs
|
|
1767
|
+
0,1,1), and the ƒx's chrome is pinned by `.w6w-fx-inline .w6w-expr-fx` below.
|
|
1768
|
+
A component that only lines up when the host sheet cooperates is broken. */
|
|
1769
|
+
.w6w-fx-inline-label {
|
|
1770
|
+
margin: 0;
|
|
1771
|
+
color: var(--w6w-text);
|
|
1772
|
+
font-size: 13px;
|
|
1773
|
+
cursor: pointer;
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1776
|
+
/* The ƒx itself is a decoration inside whichever wrapper holds it: no chrome,
|
|
1777
|
+
colour only. This is where the UA button border/background is removed (the
|
|
1778
|
+
`.w6w-expr-fx` block below declares neither), so the inline wrapper has to be
|
|
1779
|
+
listed here too or its ƒx comes back as a grey rounded button. The label row
|
|
1780
|
+
(`json` / childless `group` params, which have no field box) is a third
|
|
1781
|
+
placement and gets the same chrome-stripping. */
|
|
1782
|
+
.w6w-fx-wrap .w6w-expr-fx,
|
|
1783
|
+
.w6w-fx-inline .w6w-expr-fx,
|
|
1784
|
+
.w6w-field-labelrow .w6w-expr-fx {
|
|
1785
|
+
border: none;
|
|
1786
|
+
background: transparent;
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1789
|
+
.w6w-expr-fx {
|
|
1790
|
+
flex-shrink: 0;
|
|
1791
|
+
color: var(--w6w-muted);
|
|
1792
|
+
font-size: 13px;
|
|
1793
|
+
font-family: var(--w6w-font-mono);
|
|
1794
|
+
line-height: 1;
|
|
1795
|
+
padding: var(--w6w-sp-1) var(--w6w-sp-1-5);
|
|
1796
|
+
cursor: pointer;
|
|
1797
|
+
}
|
|
1798
|
+
|
|
1799
|
+
.w6w-expr-fx:hover {
|
|
1800
|
+
color: var(--w6w-text);
|
|
1801
|
+
}
|
|
1802
|
+
|
|
1803
|
+
.w6w-expr-fx.is-active {
|
|
1804
|
+
color: var(--w6w-accent);
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1807
|
+
/* Copyable — an in-box copy affordance decorating a value-displaying control
|
|
1808
|
+
(an <input>, a <textarea>, or CodeBlock's <pre>). Mirrors `.w6w-fx-wrap`
|
|
1809
|
+
(`_fx.scss:1-88`): the WRAPPER owns the box chrome and every child it holds
|
|
1810
|
+
is flattened below, so the value and the copy affordance read as ONE box. */
|
|
1811
|
+
.w6w-copyable {
|
|
1812
|
+
display: flex;
|
|
1813
|
+
align-items: center;
|
|
1814
|
+
gap: var(--w6w-sp-1);
|
|
1815
|
+
background: var(--w6w-panel-2);
|
|
1816
|
+
border: 1px solid var(--w6w-border);
|
|
1817
|
+
border-radius: 8px;
|
|
1818
|
+
padding: var(--w6w-sp-1) var(--w6w-sp-2);
|
|
1819
|
+
/* Box-family invariant: byte-identical to `.w6w-fx-wrap`'s at `_fx.scss:13` —
|
|
1820
|
+
six rules across four partials share this value (`building-blocks.md` §3
|
|
1821
|
+
row 7); a scale token here would drift the moment that family moves. */
|
|
1822
|
+
min-height: 38px;
|
|
1823
|
+
}
|
|
1824
|
+
|
|
1825
|
+
/* A textarea/pre is taller than the button, so the button rides at the top —
|
|
1826
|
+
mirrors `.w6w-fx-wrap:has(> textarea)` (`_fx.scss:16-18`). */
|
|
1827
|
+
.w6w-copyable:has(> textarea),
|
|
1828
|
+
.w6w-copyable:has(> pre) {
|
|
1829
|
+
align-items: flex-start;
|
|
1830
|
+
}
|
|
1831
|
+
|
|
1832
|
+
/* Focus reads on the box now that the inner control has no border of its own. */
|
|
1833
|
+
.w6w-copyable:focus-within {
|
|
1834
|
+
border-color: var(--w6w-accent);
|
|
1835
|
+
}
|
|
1836
|
+
|
|
1837
|
+
.w6w-copyable > input,
|
|
1838
|
+
.w6w-copyable > textarea,
|
|
1839
|
+
.w6w-copyable > pre {
|
|
1840
|
+
flex: 1 1 auto;
|
|
1841
|
+
min-width: 0;
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
/* The control inside the wrapper carries NO chrome of its own. Mirrors
|
|
1845
|
+
`_fx.scss:36-88`'s selector list and property list WHOLESALE
|
|
1846
|
+
(s/w6w-fx-wrap/w6w-copyable/g) — not re-derived, gated for parity by the
|
|
1847
|
+
project's test plan. See that file for the measured leak evidence (7.0px
|
|
1848
|
+
alignment / 2px / 29% height) each property below defends against; a host
|
|
1849
|
+
page's unscoped `input[type="text"], … textarea { … }` rule (studio's own,
|
|
1850
|
+
layered AFTER this stylesheet) is exactly what these declarations beat. */
|
|
1851
|
+
.w6w-field .w6w-copyable input[type=text],
|
|
1852
|
+
.w6w-field .w6w-copyable input[type=password],
|
|
1853
|
+
.w6w-field .w6w-copyable input[type=number],
|
|
1854
|
+
.w6w-field .w6w-copyable select,
|
|
1855
|
+
.w6w-field .w6w-copyable textarea,
|
|
1856
|
+
.w6w-datavar-row .w6w-copyable input,
|
|
1857
|
+
.w6w-datavar-row .w6w-copyable select,
|
|
1858
|
+
.w6w-copyable input[type=text],
|
|
1859
|
+
.w6w-copyable input[type=password],
|
|
1860
|
+
.w6w-copyable input[type=number],
|
|
1861
|
+
.w6w-copyable select,
|
|
1862
|
+
.w6w-copyable textarea {
|
|
1863
|
+
border: none;
|
|
1864
|
+
background: transparent;
|
|
1865
|
+
border-radius: 0;
|
|
1866
|
+
/* lint-tokens-allow: mirrors _fx.scss:36-88 byte-for-byte, required by the parity gate */
|
|
1867
|
+
padding: 4px 2px;
|
|
1868
|
+
outline: none;
|
|
1869
|
+
margin: 0;
|
|
1870
|
+
min-height: 0;
|
|
1871
|
+
}
|
|
1872
|
+
|
|
1873
|
+
/* The wrapper never draws a box around a box (mirrors `_fx.scss:91-98`). */
|
|
1874
|
+
.w6w-copyable .w6w-code-block {
|
|
1875
|
+
border: none;
|
|
1876
|
+
background: transparent;
|
|
1877
|
+
padding: 0;
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
/* Button chrome extends `.w6w-icon-btn` (`_icons.scss:1-11`) in markup — this
|
|
1881
|
+
class only pins the flex behaviour and the copied state, no re-authored
|
|
1882
|
+
hover/active states. */
|
|
1883
|
+
.w6w-copyable-btn {
|
|
1884
|
+
flex: none;
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1887
|
+
/* ── CodeBlock: the button OVERLAYS the box's top-right corner ──────────────
|
|
1888
|
+
For an <input>/<textarea> the button is a flex sibling, which is right: the
|
|
1889
|
+
value is one line and the control shrinks to leave room for it. A <pre> is
|
|
1890
|
+
different — it is a block of many lines, and a flex sibling would carve a
|
|
1891
|
+
permanent empty column out of the full height of it to seat one 28px button.
|
|
1892
|
+
So here the button leaves the flow and sits over the corner instead.
|
|
1893
|
+
|
|
1894
|
+
Absolute against the WRAPPER, not the <pre>, on purpose: the <pre> is the
|
|
1895
|
+
element that scrolls (`overflow-x: auto`, plus `overflow-y` when `maxHeight`
|
|
1896
|
+
is set), so anchoring to it would slide the button out of view on a wide or
|
|
1897
|
+
tall snippet. Anchored to the wrapper it stays pinned to the visible corner. */
|
|
1898
|
+
.w6w-copyable:has(> pre) {
|
|
1899
|
+
position: relative;
|
|
1900
|
+
}
|
|
1901
|
+
|
|
1902
|
+
.w6w-copyable:has(> pre) > .w6w-copyable-btn {
|
|
1903
|
+
position: absolute;
|
|
1904
|
+
top: var(--w6w-sp-1);
|
|
1905
|
+
right: var(--w6w-sp-1);
|
|
1906
|
+
/* An opaque backdrop, which the flex-sibling case does not need: this button
|
|
1907
|
+
sits ON the code, and `.w6w-icon-btn`'s transparent idle state would let
|
|
1908
|
+
the first line's text read through it. It also restores the hover feedback
|
|
1909
|
+
— `.w6w-icon-btn:hover` paints `--w6w-panel-2`, which is the wrapper's own
|
|
1910
|
+
background here and would otherwise be a no-op. */
|
|
1911
|
+
background: var(--w6w-panel);
|
|
1912
|
+
border-color: var(--w6w-border);
|
|
1913
|
+
}
|
|
1914
|
+
|
|
1915
|
+
/* Keep the first line clear of the button. Deliberately NOT folded into the
|
|
1916
|
+
`.w6w-copyable .w6w-code-block` reset above — that rule mirrors
|
|
1917
|
+
`_fx.scss:91-98` and is held byte-for-byte by the parity gate. 40px = the
|
|
1918
|
+
button's ~28px box + its 4px inset + a 8px gap before the text. */
|
|
1919
|
+
.w6w-copyable:has(> pre) > .w6w-code-block {
|
|
1920
|
+
padding-right: var(--w6w-sp-10);
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1923
|
+
.w6w-copyable-btn.is-copied {
|
|
1924
|
+
/* Mirrors `.w6w-expr-chip-render`'s "confirmed/success" convention exactly
|
|
1925
|
+
(`_chips.scss:38-42`) — the one visual for a copied/success state. */
|
|
1926
|
+
border-color: var(--w6w-success);
|
|
1927
|
+
color: var(--w6w-success);
|
|
1928
|
+
background: color-mix(in srgb, var(--w6w-success) 14%, transparent);
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
/* Scoped visually-hidden live region — not a new general `sr-only` utility
|
|
1932
|
+
(none exists in `ui` to extend; see `Copyable.tsx` for why this, not the
|
|
1933
|
+
button's own accessible name, carries the "Copied" announcement). */
|
|
1934
|
+
.w6w-copyable-status {
|
|
1935
|
+
position: absolute;
|
|
1936
|
+
overflow: hidden;
|
|
1937
|
+
width: 1px;
|
|
1938
|
+
height: 1px;
|
|
1939
|
+
white-space: nowrap;
|
|
1940
|
+
clip-path: inset(50%);
|
|
1941
|
+
border: 0;
|
|
1942
|
+
padding: 0;
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
/* ── Bare modifier: CopyableText (D-7) ───────────────────────────────────
|
|
1946
|
+
A self-contained modifier, NOT a widening of the shared `> input, >
|
|
1947
|
+
textarea, > pre` selector above (`:28-33`) — that list stays untouched.
|
|
1948
|
+
Strips the box chrome the base `.w6w-copyable` rule sets (`:5-17`: border,
|
|
1949
|
+
background, padding, min-height), and separately gives its own `> span`
|
|
1950
|
+
child the SAME flex-and-shrink pair the shared selector gives an
|
|
1951
|
+
`<input>`/`<textarea>`/`<pre>` (`:28-33` below) — a bare `<span>` is not in
|
|
1952
|
+
that list, and without this it silently reproduces the overflow bug
|
|
1953
|
+
`studio/src/pages/VarsPage.tsx:62-79` had to hand-patch. */
|
|
1954
|
+
.w6w-copyable--bare {
|
|
1955
|
+
border: none;
|
|
1956
|
+
background: transparent;
|
|
1957
|
+
padding: 0;
|
|
1958
|
+
min-height: 0;
|
|
1959
|
+
}
|
|
1960
|
+
|
|
1961
|
+
.w6w-copyable--bare > span {
|
|
1962
|
+
flex: 1 1 auto;
|
|
1963
|
+
min-width: 0;
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
/* The raw {{ }} input stands alone, so it keeps an input box of its own. */
|
|
1967
|
+
.w6w-expr-raw {
|
|
1968
|
+
width: 100%;
|
|
1969
|
+
background: var(--w6w-panel-2);
|
|
1970
|
+
border: 1px solid var(--w6w-border);
|
|
1971
|
+
border-radius: 8px;
|
|
1972
|
+
padding: var(--w6w-sp-2) var(--w6w-sp-2-5);
|
|
1973
|
+
min-height: 38px;
|
|
1974
|
+
color: var(--w6w-text);
|
|
1975
|
+
font-family: var(--w6w-font-mono);
|
|
1976
|
+
font-size: 13px;
|
|
1977
|
+
line-height: var(--w6w-lh-relaxed);
|
|
1978
|
+
}
|
|
1979
|
+
|
|
1980
|
+
.w6w-expr-raw:focus {
|
|
1981
|
+
outline: none;
|
|
1982
|
+
border-color: var(--w6w-accent);
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
/* The inline editor surface (one continuous field) sits INSIDE
|
|
1986
|
+
`.w6w-expr-field`'s box, so it draws no chrome — the border, the background
|
|
1987
|
+
and the focus ring all belong to that box. */
|
|
1988
|
+
.w6w-expr-editor {
|
|
1989
|
+
width: 100%;
|
|
1990
|
+
padding: var(--w6w-sp-0-5) 0;
|
|
1991
|
+
color: var(--w6w-text);
|
|
1992
|
+
font-size: var(--w6w-fs-sm);
|
|
1993
|
+
font-family: inherit;
|
|
1994
|
+
line-height: var(--w6w-lh-relaxed);
|
|
1995
|
+
outline: none;
|
|
1996
|
+
white-space: pre-wrap;
|
|
1997
|
+
word-break: break-word;
|
|
1998
|
+
}
|
|
1999
|
+
|
|
2000
|
+
.w6w-expr-editor.is-readonly,
|
|
2001
|
+
.w6w-expr-input.is-readonly {
|
|
2002
|
+
opacity: 0.7;
|
|
2003
|
+
}
|
|
2004
|
+
|
|
2005
|
+
/* Placeholder for the empty contentEditable field. */
|
|
2006
|
+
.w6w-expr-editor.is-empty::before {
|
|
2007
|
+
content: attr(data-placeholder);
|
|
2008
|
+
color: var(--w6w-muted);
|
|
2009
|
+
pointer-events: none;
|
|
2010
|
+
}
|
|
2011
|
+
|
|
2012
|
+
/* Masked (secret) fields: mask typed TEXT as dots; chips are exempt — a chip
|
|
2013
|
+
shows a name/label, never a secret value. */
|
|
2014
|
+
.w6w-expr-editor.is-masked {
|
|
2015
|
+
-webkit-text-security: disc;
|
|
2016
|
+
text-security: disc;
|
|
2017
|
+
}
|
|
2018
|
+
|
|
2019
|
+
.w6w-expr-editor.is-masked .w6w-expr-chip {
|
|
2020
|
+
-webkit-text-security: none;
|
|
2021
|
+
text-security: none;
|
|
2022
|
+
}
|
|
2023
|
+
|
|
2024
|
+
/* Sealed at-rest secret uses a simple flex wrapper (chip + Replace). */
|
|
2025
|
+
.w6w-expr-input {
|
|
2026
|
+
display: flex;
|
|
2027
|
+
flex-wrap: wrap;
|
|
2028
|
+
align-items: center;
|
|
2029
|
+
gap: var(--w6w-sp-1-5);
|
|
2030
|
+
background: var(--w6w-panel-2);
|
|
2031
|
+
border: 1px solid var(--w6w-border);
|
|
2032
|
+
border-radius: 8px;
|
|
2033
|
+
padding: 5px var(--w6w-sp-2);
|
|
2034
|
+
min-height: 38px;
|
|
2035
|
+
}
|
|
2036
|
+
|
|
2037
|
+
/* Chips: a var/secret/expr segment. Distinct look per kind; sits inline in the
|
|
2038
|
+
text flow. */
|
|
2039
|
+
.w6w-expr-chip {
|
|
2040
|
+
display: inline-flex;
|
|
2041
|
+
align-items: center;
|
|
2042
|
+
gap: var(--w6w-sp-1);
|
|
2043
|
+
vertical-align: baseline;
|
|
2044
|
+
box-sizing: border-box;
|
|
2045
|
+
/* Never exceed the field's content box; the label truncates before the chip
|
|
2046
|
+
can overrun the adjacent ƒx button. */
|
|
2047
|
+
max-width: 100%;
|
|
2048
|
+
border: 1px solid var(--w6w-border);
|
|
2049
|
+
border-radius: 6px;
|
|
2050
|
+
padding: 1px var(--w6w-sp-1-5);
|
|
2051
|
+
margin: 0 3px;
|
|
2052
|
+
font-size: 12.5px;
|
|
2053
|
+
line-height: 1.4;
|
|
2054
|
+
font-family: var(--w6w-font-mono);
|
|
2055
|
+
color: var(--w6w-text);
|
|
2056
|
+
background: var(--w6w-panel);
|
|
2057
|
+
white-space: nowrap;
|
|
2058
|
+
user-select: none;
|
|
2059
|
+
}
|
|
2060
|
+
|
|
2061
|
+
.w6w-expr-chip-var {
|
|
2062
|
+
border-color: var(--w6w-accent);
|
|
2063
|
+
color: var(--w6w-accent);
|
|
2064
|
+
background: color-mix(in srgb, var(--w6w-accent) 14%, transparent);
|
|
2065
|
+
}
|
|
2066
|
+
|
|
2067
|
+
.w6w-expr-chip-secret {
|
|
2068
|
+
border-color: var(--w6w-danger);
|
|
2069
|
+
color: var(--w6w-danger);
|
|
2070
|
+
background: color-mix(in srgb, var(--w6w-danger) 14%, transparent);
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2073
|
+
.w6w-expr-chip-expr {
|
|
2074
|
+
border-style: dashed;
|
|
2075
|
+
background: color-mix(in srgb, var(--w6w-text) 8%, transparent);
|
|
2076
|
+
}
|
|
2077
|
+
|
|
2078
|
+
.w6w-expr-chip-render {
|
|
2079
|
+
border-color: var(--w6w-success);
|
|
2080
|
+
color: var(--w6w-success);
|
|
2081
|
+
background: color-mix(in srgb, var(--w6w-success) 14%, transparent);
|
|
2082
|
+
}
|
|
2083
|
+
|
|
2084
|
+
.w6w-expr-chip-sigil {
|
|
2085
|
+
flex: none;
|
|
2086
|
+
font-weight: var(--w6w-fw-semibold);
|
|
2087
|
+
opacity: 0.8;
|
|
2088
|
+
}
|
|
2089
|
+
|
|
2090
|
+
.w6w-expr-chip-label {
|
|
2091
|
+
min-width: 0;
|
|
2092
|
+
overflow: hidden;
|
|
2093
|
+
text-overflow: ellipsis;
|
|
2094
|
+
white-space: nowrap;
|
|
2095
|
+
font-weight: var(--w6w-fw-medium);
|
|
2096
|
+
}
|
|
2097
|
+
|
|
2098
|
+
.w6w-expr-chip-x {
|
|
2099
|
+
display: inline-flex;
|
|
2100
|
+
flex: none;
|
|
2101
|
+
align-items: center;
|
|
2102
|
+
justify-content: center;
|
|
2103
|
+
width: 15px;
|
|
2104
|
+
height: 15px;
|
|
2105
|
+
border-radius: 4px;
|
|
2106
|
+
background: transparent;
|
|
2107
|
+
color: inherit;
|
|
2108
|
+
opacity: 0.6;
|
|
2109
|
+
font-size: var(--w6w-fs-sm);
|
|
2110
|
+
line-height: 1;
|
|
2111
|
+
cursor: pointer;
|
|
2112
|
+
}
|
|
2113
|
+
|
|
2114
|
+
.w6w-expr-chip-x:hover {
|
|
2115
|
+
opacity: 1;
|
|
2116
|
+
background: var(--w6w-border);
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2119
|
+
/* The render affordance: flips a var/render chip in place (see `makeChip`). */
|
|
2120
|
+
.w6w-expr-chip-toggle {
|
|
2121
|
+
display: inline-flex;
|
|
2122
|
+
flex: none;
|
|
2123
|
+
align-items: center;
|
|
2124
|
+
justify-content: center;
|
|
2125
|
+
width: 15px;
|
|
2126
|
+
height: 15px;
|
|
2127
|
+
border-radius: 4px;
|
|
2128
|
+
background: transparent;
|
|
2129
|
+
color: inherit;
|
|
2130
|
+
opacity: 0.6;
|
|
2131
|
+
font-size: var(--w6w-fs-xs);
|
|
2132
|
+
line-height: 1;
|
|
2133
|
+
cursor: pointer;
|
|
2134
|
+
}
|
|
2135
|
+
|
|
2136
|
+
.w6w-expr-chip-toggle:hover {
|
|
2137
|
+
opacity: 1;
|
|
2138
|
+
background: var(--w6w-border);
|
|
2139
|
+
}
|
|
2140
|
+
|
|
2141
|
+
.w6w-expr-replace {
|
|
2142
|
+
border: 1px solid var(--w6w-border);
|
|
2143
|
+
border-radius: 6px;
|
|
2144
|
+
background: transparent;
|
|
2145
|
+
color: var(--w6w-muted);
|
|
2146
|
+
font-size: var(--w6w-fs-xs);
|
|
2147
|
+
font-family: inherit;
|
|
2148
|
+
padding: 3px var(--w6w-sp-2);
|
|
2149
|
+
cursor: pointer;
|
|
2150
|
+
}
|
|
2151
|
+
|
|
2152
|
+
.w6w-expr-replace:hover {
|
|
2153
|
+
color: var(--w6w-text);
|
|
2154
|
+
background: var(--w6w-panel);
|
|
2155
|
+
}
|
|
2156
|
+
|
|
2157
|
+
/* Insert affordance + popover menu (variable / secret / expression). */
|
|
2158
|
+
.w6w-expr-insert {
|
|
2159
|
+
position: relative;
|
|
2160
|
+
display: inline-flex;
|
|
2161
|
+
}
|
|
2162
|
+
|
|
2163
|
+
.w6w-expr-insert-btn {
|
|
2164
|
+
border: 1px dashed var(--w6w-border);
|
|
2165
|
+
border-radius: 6px;
|
|
2166
|
+
background: transparent;
|
|
2167
|
+
color: var(--w6w-muted);
|
|
2168
|
+
font-size: var(--w6w-fs-xs);
|
|
2169
|
+
font-family: inherit;
|
|
2170
|
+
padding: 3px var(--w6w-sp-2);
|
|
2171
|
+
cursor: pointer;
|
|
2172
|
+
}
|
|
2173
|
+
|
|
2174
|
+
.w6w-expr-insert-btn:hover {
|
|
2175
|
+
color: var(--w6w-text);
|
|
2176
|
+
border-color: var(--w6w-accent);
|
|
2177
|
+
}
|
|
2178
|
+
|
|
2179
|
+
.w6w-expr-menu {
|
|
2180
|
+
position: absolute;
|
|
2181
|
+
top: calc(100% + var(--w6w-sp-1));
|
|
2182
|
+
left: 0;
|
|
2183
|
+
z-index: 60;
|
|
2184
|
+
display: flex;
|
|
2185
|
+
flex-direction: column;
|
|
2186
|
+
gap: var(--w6w-sp-2);
|
|
2187
|
+
min-width: 200px;
|
|
2188
|
+
background: var(--w6w-panel);
|
|
2189
|
+
border: 1px solid var(--w6w-border);
|
|
2190
|
+
border-radius: 8px;
|
|
2191
|
+
padding: var(--w6w-sp-2);
|
|
2192
|
+
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.35);
|
|
2193
|
+
}
|
|
2194
|
+
|
|
2195
|
+
.w6w-expr-menu-group {
|
|
2196
|
+
display: flex;
|
|
2197
|
+
flex-direction: column;
|
|
2198
|
+
gap: var(--w6w-sp-1);
|
|
2199
|
+
}
|
|
2200
|
+
|
|
2201
|
+
.w6w-expr-menu-group + .w6w-expr-menu-group {
|
|
2202
|
+
border-top: 1px solid var(--w6w-border);
|
|
2203
|
+
padding-top: var(--w6w-sp-2);
|
|
2204
|
+
}
|
|
2205
|
+
|
|
2206
|
+
.w6w-expr-menu-label {
|
|
2207
|
+
font-size: 0.72em;
|
|
2208
|
+
font-weight: var(--w6w-fw-semibold);
|
|
2209
|
+
letter-spacing: 0.04em;
|
|
2210
|
+
text-transform: uppercase;
|
|
2211
|
+
color: var(--w6w-muted);
|
|
2212
|
+
}
|
|
2213
|
+
|
|
2214
|
+
/* A secret-typed field surfaces the Secrets group first + highlighted, so
|
|
2215
|
+
picking a secret is the obvious one-click path (task 3.2). */
|
|
2216
|
+
.w6w-expr-menu-group.is-primary {
|
|
2217
|
+
background: var(--w6w-panel-2);
|
|
2218
|
+
border-radius: 6px;
|
|
2219
|
+
padding: var(--w6w-sp-1-5);
|
|
2220
|
+
margin: -2px;
|
|
2221
|
+
}
|
|
2222
|
+
|
|
2223
|
+
.w6w-expr-menu-group.is-primary .w6w-expr-menu-label {
|
|
2224
|
+
color: var(--w6w-accent);
|
|
2225
|
+
}
|
|
2226
|
+
|
|
2227
|
+
.w6w-expr-menu-empty {
|
|
2228
|
+
font-size: var(--w6w-fs-xs);
|
|
2229
|
+
color: var(--w6w-muted);
|
|
2230
|
+
padding: var(--w6w-sp-0-5) var(--w6w-sp-2);
|
|
2231
|
+
font-style: italic;
|
|
2232
|
+
}
|
|
2233
|
+
|
|
2234
|
+
.w6w-expr-menu-item {
|
|
2235
|
+
text-align: left;
|
|
2236
|
+
background: transparent;
|
|
2237
|
+
border: none;
|
|
2238
|
+
border-radius: 6px;
|
|
2239
|
+
padding: 5px var(--w6w-sp-2);
|
|
2240
|
+
color: var(--w6w-text);
|
|
2241
|
+
font-size: 13px;
|
|
2242
|
+
font-family: inherit;
|
|
2243
|
+
cursor: pointer;
|
|
2244
|
+
}
|
|
2245
|
+
|
|
2246
|
+
.w6w-expr-menu-item:hover {
|
|
2247
|
+
background: var(--w6w-panel-2);
|
|
2248
|
+
}
|
|
2249
|
+
|
|
2250
|
+
.w6w-expr-menu-add {
|
|
2251
|
+
display: flex;
|
|
2252
|
+
gap: var(--w6w-sp-1-5);
|
|
2253
|
+
align-items: center;
|
|
2254
|
+
}
|
|
2255
|
+
|
|
2256
|
+
.w6w-expr-menu-add input {
|
|
2257
|
+
flex: 1;
|
|
2258
|
+
min-width: 0;
|
|
2259
|
+
background: var(--w6w-panel-2);
|
|
2260
|
+
border: 1px solid var(--w6w-border);
|
|
2261
|
+
border-radius: 6px;
|
|
2262
|
+
padding: 5px var(--w6w-sp-2);
|
|
2263
|
+
color: var(--w6w-text);
|
|
2264
|
+
font-size: 13px;
|
|
2265
|
+
font-family: inherit;
|
|
2266
|
+
}
|
|
2267
|
+
|
|
2268
|
+
.w6w-expr-menu-add input:focus {
|
|
2269
|
+
outline: none;
|
|
2270
|
+
border-color: var(--w6w-accent);
|
|
2271
|
+
}
|
|
2272
|
+
|
|
2273
|
+
/* Typed key/value rows (the `vars` form element / `data` control step). */
|
|
2274
|
+
.w6w-datavar-row {
|
|
2275
|
+
display: grid;
|
|
2276
|
+
grid-template-columns: 1fr 110px 1fr auto;
|
|
2277
|
+
gap: var(--w6w-sp-1-5);
|
|
2278
|
+
/* Align to the end so that on an `expression` row — where the value cell is a
|
|
2279
|
+
taller ExpressionInput (toolbar above its editor) — the key/type/remove
|
|
2280
|
+
cells line up with the editor at the bottom, not the toolbar. Single-line
|
|
2281
|
+
rows are unaffected (every cell is the same height). */
|
|
2282
|
+
align-items: end;
|
|
2283
|
+
}
|
|
2284
|
+
|
|
2285
|
+
.w6w-datavar-row input,
|
|
2286
|
+
.w6w-datavar-row select {
|
|
2287
|
+
background: var(--w6w-panel-2);
|
|
2288
|
+
border: 1px solid var(--w6w-border);
|
|
2289
|
+
border-radius: 8px;
|
|
2290
|
+
padding: var(--w6w-sp-1-5) var(--w6w-sp-2);
|
|
2291
|
+
color: var(--w6w-text);
|
|
2292
|
+
font-size: 13px;
|
|
2293
|
+
font-family: inherit;
|
|
2294
|
+
min-width: 0;
|
|
2295
|
+
}
|
|
2296
|
+
|
|
2297
|
+
/* The block above is `.w6w-datavar-row input` at (0,1,1), which TIES with a host
|
|
2298
|
+
`input[type="text"] { margin-top: 4px }` and loses on source order — so the
|
|
2299
|
+
margin has to be re-declared at a specificity that wins, rather than added to
|
|
2300
|
+
that block where it would have no effect. `.w6w-field` is always an ancestor
|
|
2301
|
+
here (`VarsField` renders one), giving (0,2,1). */
|
|
2302
|
+
.w6w-field .w6w-datavar-row input,
|
|
2303
|
+
.w6w-field .w6w-datavar-row select {
|
|
2304
|
+
margin: 0;
|
|
2305
|
+
}
|
|
2306
|
+
|
|
2307
|
+
.w6w-datavar-row input:focus,
|
|
2308
|
+
.w6w-datavar-row select:focus {
|
|
2309
|
+
outline: none;
|
|
2310
|
+
border-color: var(--w6w-accent);
|
|
2311
|
+
}
|
|
2312
|
+
|
|
2313
|
+
.w6w-datavar-row .w6w-btn {
|
|
2314
|
+
padding: var(--w6w-sp-1-5) var(--w6w-sp-2-5);
|
|
2315
|
+
}
|
|
2316
|
+
|
|
2317
|
+
/* Buttons */
|
|
2318
|
+
.w6w-btn {
|
|
2319
|
+
background: var(--w6w-accent);
|
|
2320
|
+
color: white;
|
|
2321
|
+
border: none;
|
|
2322
|
+
border-radius: 8px;
|
|
2323
|
+
padding: var(--w6w-sp-2) 14px;
|
|
2324
|
+
font-size: var(--w6w-fs-sm);
|
|
2325
|
+
cursor: pointer;
|
|
2326
|
+
}
|
|
2327
|
+
|
|
2328
|
+
.w6w-btn:hover {
|
|
2329
|
+
filter: brightness(1.08);
|
|
2330
|
+
}
|
|
2331
|
+
|
|
2332
|
+
.w6w-btn:disabled {
|
|
2333
|
+
opacity: 0.5;
|
|
2334
|
+
cursor: default;
|
|
2335
|
+
}
|
|
2336
|
+
|
|
2337
|
+
.w6w-btn-ghost {
|
|
2338
|
+
background: transparent;
|
|
2339
|
+
border: 1px solid var(--w6w-border);
|
|
2340
|
+
color: var(--w6w-text);
|
|
2341
|
+
}
|
|
2342
|
+
|
|
2343
|
+
.w6w-btn-ghost:hover {
|
|
2344
|
+
background: var(--w6w-panel-2);
|
|
2345
|
+
}
|
|
2346
|
+
|
|
2347
|
+
.w6w-btn-ghost.active {
|
|
2348
|
+
border-color: var(--w6w-accent);
|
|
2349
|
+
background: var(--w6w-panel-2);
|
|
2350
|
+
}
|
|
2351
|
+
|
|
2352
|
+
/* Destructive confirm button (ConfirmModal's default). Styled from the same
|
|
2353
|
+
--w6w-danger token the error notices and health pills already use. */
|
|
2354
|
+
.w6w-btn-danger {
|
|
2355
|
+
background: var(--w6w-danger);
|
|
2356
|
+
color: white;
|
|
2357
|
+
}
|
|
2358
|
+
|
|
2359
|
+
/* List row — a clean, reusable list item (leading icon · title/subtitle · trailing).
|
|
2360
|
+
Mirrors the ghost saved-test button rows it replaces. */
|
|
2361
|
+
.w6w-list-item {
|
|
2362
|
+
display: flex;
|
|
2363
|
+
align-items: center;
|
|
2364
|
+
gap: var(--w6w-sp-2-5);
|
|
2365
|
+
width: 100%;
|
|
2366
|
+
padding: var(--w6w-sp-2) var(--w6w-sp-2-5);
|
|
2367
|
+
border: 1px solid transparent;
|
|
2368
|
+
border-radius: 8px;
|
|
2369
|
+
background: transparent;
|
|
2370
|
+
color: var(--w6w-text);
|
|
2371
|
+
text-align: left;
|
|
2372
|
+
font-size: var(--w6w-fs-sm);
|
|
2373
|
+
cursor: pointer;
|
|
2374
|
+
}
|
|
2375
|
+
|
|
2376
|
+
button.w6w-list-item {
|
|
2377
|
+
font: inherit;
|
|
2378
|
+
font-size: var(--w6w-fs-sm);
|
|
2379
|
+
}
|
|
2380
|
+
|
|
2381
|
+
.w6w-list-item:hover {
|
|
2382
|
+
background: var(--w6w-panel-2);
|
|
2383
|
+
}
|
|
2384
|
+
|
|
2385
|
+
.w6w-list-item:focus-visible {
|
|
2386
|
+
outline: none;
|
|
2387
|
+
border-color: var(--w6w-accent);
|
|
2388
|
+
box-shadow: 0 0 0 2px var(--w6w-accent);
|
|
2389
|
+
}
|
|
2390
|
+
|
|
2391
|
+
.w6w-list-item.active {
|
|
2392
|
+
border-color: var(--w6w-accent);
|
|
2393
|
+
background: var(--w6w-panel-2);
|
|
2394
|
+
}
|
|
2395
|
+
|
|
2396
|
+
.w6w-list-item-icon {
|
|
2397
|
+
display: inline-flex;
|
|
2398
|
+
align-items: center;
|
|
2399
|
+
flex-shrink: 0;
|
|
2400
|
+
}
|
|
2401
|
+
|
|
2402
|
+
.w6w-list-item-body {
|
|
2403
|
+
display: flex;
|
|
2404
|
+
flex-direction: column;
|
|
2405
|
+
min-width: 0;
|
|
2406
|
+
gap: var(--w6w-sp-0-5);
|
|
2407
|
+
}
|
|
2408
|
+
|
|
2409
|
+
.w6w-list-item-title {
|
|
2410
|
+
overflow: hidden;
|
|
2411
|
+
text-overflow: ellipsis;
|
|
2412
|
+
white-space: nowrap;
|
|
2413
|
+
}
|
|
2414
|
+
|
|
2415
|
+
.w6w-list-item-subtitle {
|
|
2416
|
+
color: var(--w6w-muted);
|
|
2417
|
+
font-size: var(--w6w-fs-xs);
|
|
2418
|
+
overflow: hidden;
|
|
2419
|
+
text-overflow: ellipsis;
|
|
2420
|
+
white-space: nowrap;
|
|
2421
|
+
}
|
|
2422
|
+
|
|
2423
|
+
.w6w-list-item-trailing {
|
|
2424
|
+
margin-left: auto;
|
|
2425
|
+
display: inline-flex;
|
|
2426
|
+
align-items: center;
|
|
2427
|
+
flex-shrink: 0;
|
|
2428
|
+
}
|
|
2429
|
+
|
|
2430
|
+
/* Health status pill — a small, theme-aware badge for one health state
|
|
2431
|
+
(ok · degraded · down · unknown). Colour comes from the `--w6w-health-*`
|
|
2432
|
+
tokens so a host can restyle every state by overriding those; the dot tints
|
|
2433
|
+
with the state while the pill keeps a soft tinted background + border. */
|
|
2434
|
+
.w6w-health-pill {
|
|
2435
|
+
display: inline-flex;
|
|
2436
|
+
align-items: center;
|
|
2437
|
+
gap: var(--w6w-sp-1-5);
|
|
2438
|
+
padding: var(--w6w-sp-0-5) var(--w6w-sp-2) var(--w6w-sp-0-5) 7px;
|
|
2439
|
+
border: 1px solid color-mix(in srgb, var(--w6w-health-color) 40%, var(--w6w-border));
|
|
2440
|
+
border-radius: 999px;
|
|
2441
|
+
background: color-mix(in srgb, var(--w6w-health-color) 12%, transparent);
|
|
2442
|
+
color: var(--w6w-text);
|
|
2443
|
+
font-size: var(--w6w-fs-xs);
|
|
2444
|
+
line-height: var(--w6w-lh-normal);
|
|
2445
|
+
white-space: nowrap;
|
|
2446
|
+
--w6w-health-color: var(--w6w-health-unknown);
|
|
2447
|
+
}
|
|
2448
|
+
|
|
2449
|
+
.w6w-health-pill-ok {
|
|
2450
|
+
--w6w-health-color: var(--w6w-health-ok);
|
|
2451
|
+
}
|
|
2452
|
+
|
|
2453
|
+
.w6w-health-pill-degraded {
|
|
2454
|
+
--w6w-health-color: var(--w6w-health-degraded);
|
|
2455
|
+
}
|
|
2456
|
+
|
|
2457
|
+
.w6w-health-pill-down {
|
|
2458
|
+
--w6w-health-color: var(--w6w-health-down);
|
|
2459
|
+
}
|
|
2460
|
+
|
|
2461
|
+
.w6w-health-pill-unknown {
|
|
2462
|
+
--w6w-health-color: var(--w6w-health-unknown);
|
|
2463
|
+
}
|
|
2464
|
+
|
|
2465
|
+
.w6w-health-pill-dot {
|
|
2466
|
+
flex-shrink: 0;
|
|
2467
|
+
width: 8px;
|
|
2468
|
+
height: 8px;
|
|
2469
|
+
border-radius: 50%;
|
|
2470
|
+
background: var(--w6w-health-color);
|
|
2471
|
+
}
|
|
2472
|
+
|
|
2473
|
+
.w6w-health-pill-label {
|
|
2474
|
+
overflow: hidden;
|
|
2475
|
+
text-overflow: ellipsis;
|
|
2476
|
+
}
|
|
2477
|
+
|
|
2478
|
+
/* App summary block */
|
|
2479
|
+
.w6w-app-summary {
|
|
2480
|
+
display: flex;
|
|
2481
|
+
align-items: center;
|
|
2482
|
+
gap: var(--w6w-sp-2-5);
|
|
2483
|
+
}
|
|
2484
|
+
|
|
2485
|
+
/* Modal */
|
|
2486
|
+
.w6w-modal-backdrop {
|
|
2487
|
+
position: fixed;
|
|
2488
|
+
inset: 0;
|
|
2489
|
+
background: rgba(0, 0, 0, 0.55);
|
|
2490
|
+
display: grid;
|
|
2491
|
+
place-items: center;
|
|
2492
|
+
padding: var(--w6w-sp-5);
|
|
2493
|
+
z-index: 50;
|
|
2494
|
+
}
|
|
2495
|
+
|
|
2496
|
+
dialog.w6w-modal {
|
|
2497
|
+
position: fixed;
|
|
2498
|
+
inset: 0;
|
|
2499
|
+
margin: auto;
|
|
2500
|
+
background: var(--w6w-panel);
|
|
2501
|
+
color: var(--w6w-text);
|
|
2502
|
+
border: 1px solid var(--w6w-border);
|
|
2503
|
+
border-radius: var(--w6w-radius);
|
|
2504
|
+
width: 100%;
|
|
2505
|
+
max-width: 800px;
|
|
2506
|
+
max-height: 90vh;
|
|
2507
|
+
overflow: auto;
|
|
2508
|
+
padding: var(--w6w-sp-5);
|
|
2509
|
+
display: flex;
|
|
2510
|
+
flex-direction: column;
|
|
2511
|
+
gap: var(--w6w-sp-3);
|
|
2512
|
+
}
|
|
2513
|
+
|
|
2514
|
+
dialog.w6w-modal::backdrop {
|
|
2515
|
+
background: rgba(0, 0, 0, 0.55);
|
|
2516
|
+
}
|
|
2517
|
+
|
|
2518
|
+
dialog.w6w-modal h3,
|
|
2519
|
+
dialog.w6w-modal h4,
|
|
2520
|
+
dialog.w6w-modal p {
|
|
2521
|
+
color: var(--w6w-text);
|
|
2522
|
+
margin: 0;
|
|
2523
|
+
}
|
|
2524
|
+
|
|
2525
|
+
dialog.w6w-modal.w6w-modal-wide {
|
|
2526
|
+
max-width: min(850px, 80vw);
|
|
2527
|
+
min-height: min(70vh, 560px);
|
|
2528
|
+
}
|
|
2529
|
+
|
|
2530
|
+
dialog.w6w-modal.w6w-modal-xl {
|
|
2531
|
+
max-width: 1040px;
|
|
2532
|
+
min-height: min(70vh, 620px);
|
|
2533
|
+
}
|
|
2534
|
+
|
|
2535
|
+
dialog.w6w-modal.w6w-modal-full {
|
|
2536
|
+
max-width: min(1200px, 96vw);
|
|
2537
|
+
width: 96vw;
|
|
2538
|
+
height: 92vh;
|
|
2539
|
+
max-height: 92vh;
|
|
2540
|
+
overflow: hidden;
|
|
2541
|
+
}
|
|
2542
|
+
|
|
2543
|
+
/* Edge-to-edge surface: the whole viewport, no rounded corners and no visible
|
|
2544
|
+
backdrop margin. Distinct from `.w6w-modal-full` (96vw x 92vh), which is
|
|
2545
|
+
deliberately inset so the page behind stays visible as context — the
|
|
2546
|
+
expression editor and the action tester both rely on that.
|
|
2547
|
+
`position: fixed; inset: 0` already sizes to the viewport, so width/height
|
|
2548
|
+
here are belt-and-braces against a UA stylesheet's `dialog` sizing.
|
|
2549
|
+
The header is pinned; the caller's own child scrolls (it must set
|
|
2550
|
+
`flex: 1; min-height: 0; overflow: auto` on itself). */
|
|
2551
|
+
dialog.w6w-modal.w6w-modal-fullscreen {
|
|
2552
|
+
max-width: none;
|
|
2553
|
+
width: 100vw;
|
|
2554
|
+
height: 100vh;
|
|
2555
|
+
max-height: 100vh;
|
|
2556
|
+
border: none;
|
|
2557
|
+
border-radius: 0;
|
|
2558
|
+
overflow: hidden;
|
|
2559
|
+
padding: var(--w6w-sp-5) var(--w6w-sp-6);
|
|
2560
|
+
}
|
|
2561
|
+
|
|
2562
|
+
dialog.w6w-modal.w6w-modal-fullscreen .w6w-modal-header {
|
|
2563
|
+
flex-shrink: 0;
|
|
2564
|
+
padding-bottom: var(--w6w-sp-4);
|
|
2565
|
+
border-bottom: 1px solid var(--w6w-border);
|
|
2566
|
+
}
|
|
2567
|
+
|
|
2568
|
+
.w6w-modal-header {
|
|
2569
|
+
display: flex;
|
|
2570
|
+
align-items: center;
|
|
2571
|
+
justify-content: space-between;
|
|
2572
|
+
gap: var(--w6w-sp-3);
|
|
2573
|
+
}
|
|
2574
|
+
|
|
2575
|
+
.w6w-modal-title {
|
|
2576
|
+
display: flex;
|
|
2577
|
+
align-items: center;
|
|
2578
|
+
gap: var(--w6w-sp-2-5);
|
|
2579
|
+
min-width: 0;
|
|
2580
|
+
}
|
|
2581
|
+
|
|
2582
|
+
.w6w-modal-subtitle {
|
|
2583
|
+
color: var(--w6w-muted);
|
|
2584
|
+
font-size: 0.7em;
|
|
2585
|
+
font-weight: var(--w6w-fw-regular);
|
|
2586
|
+
white-space: nowrap;
|
|
2587
|
+
overflow: hidden;
|
|
2588
|
+
text-overflow: ellipsis;
|
|
2589
|
+
}
|
|
2590
|
+
|
|
2591
|
+
.w6w-modal-subtitle code {
|
|
2592
|
+
font-size: inherit;
|
|
2593
|
+
}
|
|
2594
|
+
|
|
2595
|
+
/* The one scrolling region of a dialog (D-3): the body takes the leftover height
|
|
2596
|
+
and scrolls, so the header/footer around it stay put. The dialog's own
|
|
2597
|
+
`gap: var(--w6w-sp-3)` column is reproduced here so content-spacing is
|
|
2598
|
+
unchanged now that body children are flex items of THIS box, not the dialog's. */
|
|
2599
|
+
.w6w-modal-body {
|
|
2600
|
+
display: flex;
|
|
2601
|
+
flex-direction: column;
|
|
2602
|
+
gap: var(--w6w-sp-3);
|
|
2603
|
+
flex: 1;
|
|
2604
|
+
min-height: 0;
|
|
2605
|
+
overflow-y: auto;
|
|
2606
|
+
}
|
|
2607
|
+
|
|
2608
|
+
/* Pinned below the scrolling `.w6w-modal-body`, never shrunk away by it (D-3).
|
|
2609
|
+
Sits at the dialog's bottom for free: the body above it already absorbs the
|
|
2610
|
+
free space, so no `margin-top: auto` is needed (or wanted — it would shrink
|
|
2611
|
+
this row instead). */
|
|
2612
|
+
.w6w-modal-actions {
|
|
2613
|
+
display: flex;
|
|
2614
|
+
gap: var(--w6w-sp-2);
|
|
2615
|
+
justify-content: flex-end;
|
|
2616
|
+
flex-shrink: 0;
|
|
2617
|
+
}
|
|
2618
|
+
|
|
2619
|
+
/* Icon-button view toggle (e.g. Form ⇄ JSON), inline with a modal header. */
|
|
2620
|
+
.w6w-view-toggle {
|
|
2621
|
+
display: flex;
|
|
2622
|
+
gap: var(--w6w-sp-1);
|
|
2623
|
+
flex-shrink: 0;
|
|
2624
|
+
}
|
|
2625
|
+
|
|
2626
|
+
.w6w-icon-btn {
|
|
2627
|
+
display: inline-flex;
|
|
2628
|
+
align-items: center;
|
|
2629
|
+
justify-content: center;
|
|
2630
|
+
background: transparent;
|
|
2631
|
+
border: 1px solid transparent;
|
|
2632
|
+
border-radius: 8px;
|
|
2633
|
+
padding: var(--w6w-sp-1-5);
|
|
2634
|
+
color: var(--w6w-muted);
|
|
2635
|
+
cursor: pointer;
|
|
2636
|
+
}
|
|
2637
|
+
|
|
2638
|
+
.w6w-icon-btn:hover {
|
|
2639
|
+
background: var(--w6w-panel-2);
|
|
2640
|
+
color: var(--w6w-text);
|
|
2641
|
+
}
|
|
2642
|
+
|
|
2643
|
+
.w6w-icon-btn.active {
|
|
2644
|
+
background: var(--w6w-panel-2);
|
|
2645
|
+
border-color: var(--w6w-accent);
|
|
2646
|
+
color: var(--w6w-text);
|
|
2647
|
+
}
|
|
2648
|
+
|
|
2649
|
+
/* Segmented sub-tabs inside the edit modal's form view (Parameters | Config). */
|
|
2650
|
+
.w6w-subtabs {
|
|
2651
|
+
display: inline-flex;
|
|
2652
|
+
gap: var(--w6w-sp-0-5);
|
|
2653
|
+
padding: var(--w6w-sp-0-5);
|
|
2654
|
+
background: var(--w6w-panel-2);
|
|
2655
|
+
border: 1px solid var(--w6w-border);
|
|
2656
|
+
border-radius: 8px;
|
|
2657
|
+
align-self: flex-start;
|
|
2658
|
+
}
|
|
2659
|
+
|
|
2660
|
+
.w6w-subtab {
|
|
2661
|
+
background: transparent;
|
|
2662
|
+
border: none;
|
|
2663
|
+
border-radius: 6px;
|
|
2664
|
+
padding: 5px var(--w6w-sp-3);
|
|
2665
|
+
color: var(--w6w-muted);
|
|
2666
|
+
font-size: 13px;
|
|
2667
|
+
cursor: pointer;
|
|
2668
|
+
}
|
|
2669
|
+
|
|
2670
|
+
.w6w-subtab:hover {
|
|
2671
|
+
color: var(--w6w-text);
|
|
2672
|
+
}
|
|
2673
|
+
|
|
2674
|
+
.w6w-subtab.active {
|
|
2675
|
+
background: var(--w6w-panel);
|
|
2676
|
+
color: var(--w6w-text);
|
|
2677
|
+
font-weight: var(--w6w-fw-medium);
|
|
2678
|
+
}
|
|
2679
|
+
|
|
2680
|
+
.w6w-subtab:disabled {
|
|
2681
|
+
opacity: 0.4;
|
|
2682
|
+
cursor: default;
|
|
2683
|
+
}
|
|
2684
|
+
|
|
2685
|
+
.w6w-subtab:disabled:hover {
|
|
2686
|
+
color: var(--w6w-muted);
|
|
2687
|
+
}
|
|
2688
|
+
|
|
2689
|
+
/* Full-width tabs bar: segmented tabs on the left, view icons on the right. */
|
|
2690
|
+
.w6w-tabsbar {
|
|
2691
|
+
display: flex;
|
|
2692
|
+
align-items: center;
|
|
2693
|
+
justify-content: space-between;
|
|
2694
|
+
gap: var(--w6w-sp-3);
|
|
2695
|
+
border-bottom: 1px solid var(--w6w-border);
|
|
2696
|
+
padding-bottom: var(--w6w-sp-2);
|
|
2697
|
+
flex-shrink: 0;
|
|
2698
|
+
}
|
|
2699
|
+
|
|
2700
|
+
.w6w-icon-btn:disabled {
|
|
2701
|
+
opacity: 0.35;
|
|
2702
|
+
cursor: default;
|
|
2703
|
+
}
|
|
2704
|
+
|
|
2705
|
+
.w6w-icon-btn:disabled:hover {
|
|
2706
|
+
background: transparent;
|
|
2707
|
+
color: var(--w6w-muted);
|
|
2708
|
+
}
|
|
2709
|
+
|
|
2710
|
+
/* Config modal body (a picked app/node) fills the dialog so the footer pins to
|
|
2711
|
+
the modal's bottom rather than a fixed-height content area. */
|
|
2712
|
+
.w6w-stepbuilder-config {
|
|
2713
|
+
flex: 1;
|
|
2714
|
+
min-height: 0;
|
|
2715
|
+
display: flex;
|
|
2716
|
+
flex-direction: column;
|
|
2717
|
+
}
|
|
2718
|
+
|
|
2719
|
+
/* Compact one-line step identity (id · app · action) in the edit modal. */
|
|
2720
|
+
.w6w-step-meta {
|
|
2721
|
+
display: flex;
|
|
2722
|
+
flex-wrap: wrap;
|
|
2723
|
+
align-items: center;
|
|
2724
|
+
gap: var(--w6w-sp-1-5);
|
|
2725
|
+
/* lint-tokens-allow: relative em, not absolute rem like the scale's --w6w-fs- type tokens — mirrors the accepted _modal.scss:88 .w6w-modal-subtitle precedent; .w6w-step-meta currently has zero .tsx call sites (possible dead CSS, not this task's to delete) */
|
|
2726
|
+
font-size: 0.8em;
|
|
2727
|
+
color: var(--w6w-muted);
|
|
2728
|
+
}
|
|
2729
|
+
|
|
2730
|
+
.w6w-step-meta code {
|
|
2731
|
+
color: var(--w6w-text);
|
|
2732
|
+
}
|
|
2733
|
+
|
|
2734
|
+
/* Step builder (sidebar + content) */
|
|
2735
|
+
.w6w-stepbuilder {
|
|
2736
|
+
display: flex;
|
|
2737
|
+
gap: var(--w6w-sp-4);
|
|
2738
|
+
min-height: 340px;
|
|
2739
|
+
}
|
|
2740
|
+
|
|
2741
|
+
.w6w-stepbuilder-sidebar {
|
|
2742
|
+
display: flex;
|
|
2743
|
+
flex-direction: column;
|
|
2744
|
+
gap: var(--w6w-sp-1);
|
|
2745
|
+
width: 140px;
|
|
2746
|
+
flex-shrink: 0;
|
|
2747
|
+
border-right: 1px solid var(--w6w-border);
|
|
2748
|
+
padding-right: var(--w6w-sp-3);
|
|
2749
|
+
}
|
|
2750
|
+
|
|
2751
|
+
.w6w-stepbuilder-tab {
|
|
2752
|
+
text-align: left;
|
|
2753
|
+
background: transparent;
|
|
2754
|
+
border: 1px solid transparent;
|
|
2755
|
+
border-radius: 8px;
|
|
2756
|
+
padding: var(--w6w-sp-2) var(--w6w-sp-2-5);
|
|
2757
|
+
color: var(--w6w-muted);
|
|
2758
|
+
font-size: var(--w6w-fs-sm);
|
|
2759
|
+
cursor: pointer;
|
|
2760
|
+
}
|
|
2761
|
+
|
|
2762
|
+
.w6w-stepbuilder-tab:hover {
|
|
2763
|
+
background: var(--w6w-panel-2);
|
|
2764
|
+
color: var(--w6w-text);
|
|
2765
|
+
}
|
|
2766
|
+
|
|
2767
|
+
.w6w-stepbuilder-tab.active {
|
|
2768
|
+
background: var(--w6w-panel-2);
|
|
2769
|
+
color: var(--w6w-text);
|
|
2770
|
+
font-weight: var(--w6w-fw-medium);
|
|
2771
|
+
}
|
|
2772
|
+
|
|
2773
|
+
.w6w-stepbuilder-content {
|
|
2774
|
+
flex: 1;
|
|
2775
|
+
min-width: 0;
|
|
2776
|
+
/* Fixed height (not content-driven) so the modal never resizes when toggling
|
|
2777
|
+
tabs, and the sidebar divider — which stretches to this row — stays a
|
|
2778
|
+
constant length regardless of the right pane's content. */
|
|
2779
|
+
height: min(70vh, 520px);
|
|
2780
|
+
overflow: auto;
|
|
2781
|
+
}
|
|
2782
|
+
|
|
2783
|
+
/* Apps flow: a fixed search header + a separately scrolling list, so the
|
|
2784
|
+
scrollbar is contained to the list and never runs alongside the search. */
|
|
2785
|
+
.w6w-stepbuilder-apps {
|
|
2786
|
+
display: flex;
|
|
2787
|
+
flex-direction: column;
|
|
2788
|
+
gap: var(--w6w-sp-2-5);
|
|
2789
|
+
height: 100%;
|
|
2790
|
+
min-height: 0;
|
|
2791
|
+
}
|
|
2792
|
+
|
|
2793
|
+
.w6w-stepbuilder-scroll {
|
|
2794
|
+
overflow-y: auto;
|
|
2795
|
+
/* Fill the remaining height below the search header; the list — not the
|
|
2796
|
+
outer modal content — owns the scrollbar. */
|
|
2797
|
+
flex: 1;
|
|
2798
|
+
min-height: 0;
|
|
2799
|
+
padding-right: var(--w6w-sp-1);
|
|
2800
|
+
}
|
|
2801
|
+
|
|
2802
|
+
.w6w-stepbuilder-search {
|
|
2803
|
+
background: var(--w6w-panel-2);
|
|
2804
|
+
border: 1px solid var(--w6w-border);
|
|
2805
|
+
border-radius: 8px;
|
|
2806
|
+
padding: var(--w6w-sp-2) var(--w6w-sp-2-5);
|
|
2807
|
+
color: var(--w6w-text);
|
|
2808
|
+
font-size: var(--w6w-fs-sm);
|
|
2809
|
+
font-family: inherit;
|
|
2810
|
+
width: 100%;
|
|
2811
|
+
}
|
|
2812
|
+
|
|
2813
|
+
.w6w-stepbuilder-search:focus {
|
|
2814
|
+
outline: none;
|
|
2815
|
+
border-color: var(--w6w-accent);
|
|
2816
|
+
}
|
|
2817
|
+
|
|
2818
|
+
.w6w-stepbuilder-list {
|
|
2819
|
+
display: flex;
|
|
2820
|
+
flex-direction: column;
|
|
2821
|
+
gap: var(--w6w-sp-1-5);
|
|
2822
|
+
}
|
|
2823
|
+
|
|
2824
|
+
.w6w-stepbuilder-item {
|
|
2825
|
+
display: flex;
|
|
2826
|
+
align-items: center;
|
|
2827
|
+
gap: var(--w6w-sp-2-5);
|
|
2828
|
+
text-align: left;
|
|
2829
|
+
background: var(--w6w-panel-2);
|
|
2830
|
+
border: 1px solid var(--w6w-border);
|
|
2831
|
+
border-radius: 8px;
|
|
2832
|
+
padding: var(--w6w-sp-2-5) var(--w6w-sp-3);
|
|
2833
|
+
color: var(--w6w-text);
|
|
2834
|
+
cursor: pointer;
|
|
2835
|
+
font-size: var(--w6w-fs-sm);
|
|
2836
|
+
}
|
|
2837
|
+
|
|
2838
|
+
.w6w-stepbuilder-item:hover {
|
|
2839
|
+
border-color: var(--w6w-accent);
|
|
2840
|
+
}
|
|
2841
|
+
|
|
2842
|
+
.w6w-stepbuilder-item-main {
|
|
2843
|
+
display: flex;
|
|
2844
|
+
flex-direction: column;
|
|
2845
|
+
gap: var(--w6w-sp-0-5);
|
|
2846
|
+
min-width: 0;
|
|
2847
|
+
}
|
|
2848
|
+
|
|
2849
|
+
/* AppPicker's own multi-column card grid (T1.1.1). ADDITIVE on top of the
|
|
2850
|
+
shared `.w6w-stepbuilder-list`/`-item` above, which stay byte-identical to
|
|
2851
|
+
`main` (NodeList/CallableRow/ReadyToUseFlow still consume them unmodified)
|
|
2852
|
+
— this rule wins the cascade purely by being declared later at equal
|
|
2853
|
+
(single-class) specificity. `minmax(190px, 1fr)` is re-derived for this
|
|
2854
|
+
card's much shorter content (icon + name + id + version, not a full
|
|
2855
|
+
description card) from the scale `packages/frontend`'s generic `.grid`
|
|
2856
|
+
utility uses (`minmax(260px, 1fr)`) — `grid-template-columns` is box
|
|
2857
|
+
geometry, outside `lint:tokens`' scanned property set, so the literal is
|
|
2858
|
+
deliberate, not an oversight.
|
|
2859
|
+
|
|
2860
|
+
`auto-fill`, NOT `auto-fit`: the two differ in exactly one case, and it is
|
|
2861
|
+
the case a search box guarantees will happen. `auto-fit` COLLAPSES the
|
|
2862
|
+
tracks no card landed in, and the `1fr` then hands their width to the
|
|
2863
|
+
survivors — so typing a query that matches one app blew that single card up
|
|
2864
|
+
to the full width of the panel, a tile that changes size as you type. With
|
|
2865
|
+
`auto-fill` the empty tracks are kept at their `minmax()` width, so a card
|
|
2866
|
+
is the same size whether the grid holds 60 of them or 1.
|
|
2867
|
+
|
|
2868
|
+
`align-content: start` is the vertical half of the same invariant: an auto
|
|
2869
|
+
row track under the default `stretch` absorbs the free space of a grid with
|
|
2870
|
+
a definite height (this one's, from `.w6w-stepbuilder-scroll`'s `flex: 1`),
|
|
2871
|
+
so a single result would also have grown DOWN to fill the panel. */
|
|
2872
|
+
.w6w-apppicker-grid {
|
|
2873
|
+
display: grid;
|
|
2874
|
+
grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
|
|
2875
|
+
gap: var(--w6w-sp-2);
|
|
2876
|
+
align-content: start;
|
|
2877
|
+
}
|
|
2878
|
+
|
|
2879
|
+
/* The quieter resting card (D-3): `--w6w-panel` at rest instead of
|
|
2880
|
+
`--w6w-panel-2`, shifting TO `--w6w-panel-2` on hover/focus — the inverse
|
|
2881
|
+
of the shared item's flat `--w6w-panel-2` always-on tint. No new token;
|
|
2882
|
+
`.w6w-stepbuilder-item:hover`'s `border-color: var(--w6w-accent)` above
|
|
2883
|
+
still applies unchanged, so hover keeps both effects together. Slightly
|
|
2884
|
+
tighter padding than the shared item, sized for a narrower multi-column
|
|
2885
|
+
card rather than a single full-width row.
|
|
2886
|
+
|
|
2887
|
+
`min-height` pins every tile to one height regardless of what it holds:
|
|
2888
|
+
`version` is optional on `AppSummary`, so a catalog that mixes versioned and
|
|
2889
|
+
unversioned apps would otherwise render two card heights down the same grid
|
|
2890
|
+
(grid items stretch to their ROW, not to the whole grid). The floor is the
|
|
2891
|
+
three-line card's own content height rounded up, so it never clips.
|
|
2892
|
+
|
|
2893
|
+
`align-items: flex-start` overrides the shared item's `center`: against a
|
|
2894
|
+
three-line block a centred 24px icon floats beside the id rather than
|
|
2895
|
+
reading as the name's own mark. */
|
|
2896
|
+
.w6w-apppicker-card {
|
|
2897
|
+
background: var(--w6w-panel);
|
|
2898
|
+
padding: var(--w6w-sp-2) var(--w6w-sp-2-5);
|
|
2899
|
+
align-items: flex-start;
|
|
2900
|
+
min-height: 84px;
|
|
2901
|
+
}
|
|
2902
|
+
|
|
2903
|
+
.w6w-apppicker-card:hover,
|
|
2904
|
+
.w6w-apppicker-card:focus-visible {
|
|
2905
|
+
background: var(--w6w-panel-2);
|
|
2906
|
+
}
|
|
2907
|
+
|
|
2908
|
+
/* The card's two metadata lines. One `font-size` declaration for both, because
|
|
2909
|
+
there is only one deliberate literal here to justify: the type ramp's
|
|
2910
|
+
smallest role is `--w6w-fs-xs` (0.75rem), the id and version want to sit a
|
|
2911
|
+
step UNDER it, and the ramp has no `2xs` — its 30-name key set is pinned
|
|
2912
|
+
name-for-name by `scale-tokens.test.ts` and mirrored by `packages/frontend`'s
|
|
2913
|
+
`check:scale-parity`, so adding one is a cross-repo contract change, not a
|
|
2914
|
+
card tweak. `code`'s own UA `font-size` also has to be overridden here
|
|
2915
|
+
whatever value is chosen. */
|
|
2916
|
+
.w6w-apppicker-card-id,
|
|
2917
|
+
.w6w-apppicker-card-version {
|
|
2918
|
+
/* lint-tokens-allow: one step under --w6w-fs-xs; the ramp has no 2xs role and its keys are pinned */
|
|
2919
|
+
font-size: 0.6875rem;
|
|
2920
|
+
color: var(--w6w-muted);
|
|
2921
|
+
font-family: var(--w6w-font-mono);
|
|
2922
|
+
}
|
|
2923
|
+
|
|
2924
|
+
/* Truncation, not wrapping: `min-width: 0` on the parent
|
|
2925
|
+
`.w6w-stepbuilder-item-main` is what lets this shrink below its own
|
|
2926
|
+
min-content width in the first place — without it the ellipsis never
|
|
2927
|
+
engages and a long id widens the flex line instead. */
|
|
2928
|
+
.w6w-apppicker-card-id {
|
|
2929
|
+
display: block;
|
|
2930
|
+
max-width: 100%;
|
|
2931
|
+
overflow: hidden;
|
|
2932
|
+
text-overflow: ellipsis;
|
|
2933
|
+
white-space: nowrap;
|
|
2934
|
+
opacity: 0.6;
|
|
2935
|
+
}
|
|
2936
|
+
|
|
2937
|
+
/* Quieter than the name, but a step louder than the id it sits under — it is
|
|
2938
|
+
the shorter, more scannable of the two. */
|
|
2939
|
+
.w6w-apppicker-card-version {
|
|
2940
|
+
opacity: 0.75;
|
|
2941
|
+
}
|
|
2942
|
+
|
|
2943
|
+
/* The opt-in category-filter chip row (D-1a; AddConnectionModal only —
|
|
2944
|
+
`AppPickerProps.categoryFilter`). Extends `.w6w-chip`'s look
|
|
2945
|
+
(`_multiselect.scss:40-53`) for the general shape rather than importing
|
|
2946
|
+
it — that partial belongs to `ParamsForm`'s array-editor chips, a
|
|
2947
|
+
different feature with the opposite interaction (only SELECTED values are
|
|
2948
|
+
chips there; every available category is always a chip here). */
|
|
2949
|
+
.w6w-apppicker-cats {
|
|
2950
|
+
display: flex;
|
|
2951
|
+
flex-wrap: wrap;
|
|
2952
|
+
align-items: center;
|
|
2953
|
+
gap: var(--w6w-sp-1-5);
|
|
2954
|
+
}
|
|
2955
|
+
|
|
2956
|
+
.w6w-apppicker-chip {
|
|
2957
|
+
display: inline-flex;
|
|
2958
|
+
align-items: center;
|
|
2959
|
+
gap: var(--w6w-sp-0-5);
|
|
2960
|
+
background: var(--w6w-panel);
|
|
2961
|
+
border: 1px solid var(--w6w-border);
|
|
2962
|
+
border-radius: 999px;
|
|
2963
|
+
padding: var(--w6w-sp-0-5) var(--w6w-sp-2);
|
|
2964
|
+
color: var(--w6w-muted);
|
|
2965
|
+
font-size: var(--w6w-fs-xs);
|
|
2966
|
+
cursor: pointer;
|
|
2967
|
+
}
|
|
2968
|
+
|
|
2969
|
+
.w6w-apppicker-chip:hover {
|
|
2970
|
+
border-color: var(--w6w-accent);
|
|
2971
|
+
color: var(--w6w-text);
|
|
2972
|
+
}
|
|
2973
|
+
|
|
2974
|
+
/* The pressed/selected state is driven by the same `aria-pressed` the
|
|
2975
|
+
button already carries for assistive tech (P10) — no separate class to
|
|
2976
|
+
keep in sync with it. */
|
|
2977
|
+
.w6w-apppicker-chip[aria-pressed=true] {
|
|
2978
|
+
background: var(--w6w-accent);
|
|
2979
|
+
border-color: var(--w6w-accent);
|
|
2980
|
+
color: #fff;
|
|
2981
|
+
/* The count's `.w6w-muted` sets its OWN color, so it doesn't inherit this
|
|
2982
|
+
`color: #fff` — left alone it stays `var(--w6w-muted)`, a gray tuned for
|
|
2983
|
+
the unpressed `--w6w-panel` background, which is nearly invisible against
|
|
2984
|
+
the accent fill. Not full white: the count is still secondary to the
|
|
2985
|
+
label. */
|
|
2986
|
+
}
|
|
2987
|
+
.w6w-apppicker-chip[aria-pressed=true] .w6w-muted {
|
|
2988
|
+
color: rgba(255, 255, 255, 0.75);
|
|
2989
|
+
}
|
|
2990
|
+
|
|
2991
|
+
/* AppPicker's own layout owner, nested inside `.w6w-stepbuilder-content` (never
|
|
2992
|
+
applied in its place — see the call sites). A flex item's automatic minimum
|
|
2993
|
+
size is its min-content size unless `overflow` is non-`visible` or
|
|
2994
|
+
`min-height:0` is set; `.w6w-stepbuilder-content` has neither, so its
|
|
2995
|
+
min-content (every app row, unclipped) pushes `dialog.w6w-modal` up against
|
|
2996
|
+
`max-height:90vh`. This host's explicit `height` + `overflow:hidden` zeroes
|
|
2997
|
+
that contribution, so the dialog falls back to `.w6w-modal-xl`'s
|
|
2998
|
+
`min-height: min(70vh, 620px)` — the step builder's own height. */
|
|
2999
|
+
.w6w-apppicker-host {
|
|
3000
|
+
flex: 0 0 auto;
|
|
3001
|
+
min-width: 0;
|
|
3002
|
+
height: min(70vh, 520px);
|
|
3003
|
+
display: flex;
|
|
3004
|
+
flex-direction: column;
|
|
3005
|
+
overflow: hidden;
|
|
3006
|
+
}
|
|
3007
|
+
|
|
3008
|
+
.w6w-apppicker-host > .w6w-stepbuilder-apps {
|
|
3009
|
+
height: auto;
|
|
3010
|
+
flex: 1 1 auto;
|
|
3011
|
+
min-height: 0;
|
|
3012
|
+
}
|
|
3013
|
+
|
|
3014
|
+
/* The picker's home tab — the intake's two-column layout:
|
|
3015
|
+
|
|
3016
|
+
Connnected apps | functions
|
|
3017
|
+
| workflows
|
|
3018
|
+
|
|
3019
|
+
Connected apps down the left; Functions above Workflows down the right.
|
|
3020
|
+
Nested inside `.w6w-apppicker-host`, which owns the height, so each column's
|
|
3021
|
+
own list is what scrolls — never the modal. `min-height: 0` on the grid and
|
|
3022
|
+
on every column is load-bearing: a grid/flex item's automatic minimum size
|
|
3023
|
+
is its min-content size, so without it a long list pushes the dialog past
|
|
3024
|
+
`.w6w-apppicker-host`'s fixed height instead of scrolling inside it. */
|
|
3025
|
+
.w6w-readytouse {
|
|
3026
|
+
display: grid;
|
|
3027
|
+
grid-template-columns: 1fr 1fr;
|
|
3028
|
+
gap: var(--w6w-sp-4);
|
|
3029
|
+
flex: 1 1 auto;
|
|
3030
|
+
min-height: 0;
|
|
3031
|
+
}
|
|
3032
|
+
|
|
3033
|
+
/* A half with nothing in it is not rendered at all (an empty "Workflows"
|
|
3034
|
+
heading would claim you have workflows ready to use), so the grid collapses
|
|
3035
|
+
to the one column that survived — and the divider below, which only makes
|
|
3036
|
+
sense between two halves, goes with it. */
|
|
3037
|
+
.w6w-readytouse[data-cols="1"] {
|
|
3038
|
+
grid-template-columns: 1fr;
|
|
3039
|
+
}
|
|
3040
|
+
|
|
3041
|
+
/* The `|` in the intake's sketch. On the right half's leading edge rather than
|
|
3042
|
+
as a third grid track, so it spans the full column height however tall the
|
|
3043
|
+
two halves end up, and disappears with the half itself. */
|
|
3044
|
+
.w6w-readytouse[data-cols="2"] > .w6w-readytouse-stack {
|
|
3045
|
+
border-left: 1px solid var(--w6w-border);
|
|
3046
|
+
padding-left: var(--w6w-sp-4);
|
|
3047
|
+
}
|
|
3048
|
+
|
|
3049
|
+
/* The right half stacks its two sections; they share the height evenly. */
|
|
3050
|
+
.w6w-readytouse-stack {
|
|
3051
|
+
display: grid;
|
|
3052
|
+
grid-template-rows: 1fr 1fr;
|
|
3053
|
+
gap: var(--w6w-sp-3);
|
|
3054
|
+
min-height: 0;
|
|
3055
|
+
}
|
|
3056
|
+
|
|
3057
|
+
/* A single column: heading pinned, list scrolling under it. */
|
|
3058
|
+
.w6w-readytouse-col {
|
|
3059
|
+
display: flex;
|
|
3060
|
+
flex-direction: column;
|
|
3061
|
+
gap: var(--w6w-sp-2);
|
|
3062
|
+
min-height: 0;
|
|
3063
|
+
}
|
|
3064
|
+
|
|
3065
|
+
/* One section only in the stack — a picker offering a single callable family,
|
|
3066
|
+
or a workspace with Functions but no Workflows. It takes the whole right
|
|
3067
|
+
half rather than leaving a gap under it. */
|
|
3068
|
+
.w6w-readytouse-stack > .w6w-readytouse-col:only-child {
|
|
3069
|
+
grid-row: 1/-1;
|
|
3070
|
+
}
|
|
3071
|
+
|
|
3072
|
+
.w6w-readytouse-heading {
|
|
3073
|
+
margin: 0;
|
|
3074
|
+
font-size: var(--w6w-fs-sm);
|
|
3075
|
+
font-weight: var(--w6w-fw-semibold);
|
|
3076
|
+
color: var(--w6w-muted-text, var(--w6w-text));
|
|
3077
|
+
}
|
|
3078
|
+
|
|
3079
|
+
/* A Function/Workflow row, distinct from an app row at a glance: an app is
|
|
3080
|
+
somebody else's service, a Function/Workflow is something YOU built here.
|
|
3081
|
+
Applied by `CallableRow`, which both the home tab and the Workflows/
|
|
3082
|
+
Functions tabs render — so the tint and the glyph travel together and a
|
|
3083
|
+
Function looks the same wherever it is offered. */
|
|
3084
|
+
.w6w-stepbuilder-item--callable {
|
|
3085
|
+
background: var(--w6w-panel);
|
|
3086
|
+
border-style: dashed;
|
|
3087
|
+
}
|
|
3088
|
+
|
|
3089
|
+
/* Step config (app action / control node): a fixed header (connection + action)
|
|
3090
|
+
that never scrolls, a scrolling parameters body, and a pinned footer — mirrors
|
|
3091
|
+
the fixed-header/scroll-body split used by `.w6w-stepbuilder-apps`. */
|
|
3092
|
+
.w6w-stepconfig {
|
|
3093
|
+
display: flex;
|
|
3094
|
+
flex-direction: column;
|
|
3095
|
+
flex: 1;
|
|
3096
|
+
height: 100%;
|
|
3097
|
+
min-height: 0;
|
|
3098
|
+
gap: var(--w6w-sp-3);
|
|
3099
|
+
/* Horizontal breathing room so header/footer align with the padded body. */
|
|
3100
|
+
padding-inline: var(--w6w-sp-1);
|
|
3101
|
+
}
|
|
3102
|
+
|
|
3103
|
+
/* Inline step rename (pencil) shown next to the modal title. */
|
|
3104
|
+
.w6w-step-rename {
|
|
3105
|
+
display: inline-flex;
|
|
3106
|
+
align-items: center;
|
|
3107
|
+
gap: var(--w6w-sp-1);
|
|
3108
|
+
}
|
|
3109
|
+
|
|
3110
|
+
.w6w-step-rename input {
|
|
3111
|
+
background: var(--w6w-panel-2);
|
|
3112
|
+
border: 1px solid var(--w6w-accent);
|
|
3113
|
+
border-radius: 6px;
|
|
3114
|
+
padding: var(--w6w-sp-0-5) var(--w6w-sp-1-5);
|
|
3115
|
+
color: var(--w6w-text);
|
|
3116
|
+
/* lint-tokens-allow: relative em, not absolute rem like the scale's --w6w-fs- type tokens — mirrors the accepted _modal.scss:88 .w6w-modal-subtitle precedent */
|
|
3117
|
+
font-size: 0.9em;
|
|
3118
|
+
font-family: inherit;
|
|
3119
|
+
}
|
|
3120
|
+
|
|
3121
|
+
.w6w-stepconfig-header {
|
|
3122
|
+
display: flex;
|
|
3123
|
+
flex-direction: column;
|
|
3124
|
+
gap: var(--w6w-sp-2-5);
|
|
3125
|
+
flex-shrink: 0;
|
|
3126
|
+
}
|
|
3127
|
+
|
|
3128
|
+
/* Connection + action share a row and wrap on narrow widths. */
|
|
3129
|
+
.w6w-stepconfig-row {
|
|
3130
|
+
display: flex;
|
|
3131
|
+
flex-wrap: wrap;
|
|
3132
|
+
gap: var(--w6w-sp-3);
|
|
3133
|
+
align-items: flex-start;
|
|
3134
|
+
}
|
|
3135
|
+
|
|
3136
|
+
.w6w-stepconfig-conn,
|
|
3137
|
+
.w6w-stepconfig-action {
|
|
3138
|
+
flex: 1 1 240px;
|
|
3139
|
+
min-width: 0;
|
|
3140
|
+
}
|
|
3141
|
+
|
|
3142
|
+
.w6w-stepconfig-conn-empty {
|
|
3143
|
+
flex: 1 1 100%;
|
|
3144
|
+
}
|
|
3145
|
+
|
|
3146
|
+
/* Selected connection rendered as a static label (not a dropdown). */
|
|
3147
|
+
.w6w-conn-label {
|
|
3148
|
+
display: flex;
|
|
3149
|
+
align-items: center;
|
|
3150
|
+
gap: var(--w6w-sp-2);
|
|
3151
|
+
background: var(--w6w-panel-2);
|
|
3152
|
+
border: 1px solid var(--w6w-border);
|
|
3153
|
+
border-radius: 8px;
|
|
3154
|
+
padding: var(--w6w-sp-1-5) var(--w6w-sp-2) var(--w6w-sp-1-5) var(--w6w-sp-2-5);
|
|
3155
|
+
min-height: 36px;
|
|
3156
|
+
}
|
|
3157
|
+
|
|
3158
|
+
.w6w-conn-label-name {
|
|
3159
|
+
flex: 1;
|
|
3160
|
+
min-width: 0;
|
|
3161
|
+
color: var(--w6w-text);
|
|
3162
|
+
font-size: var(--w6w-fs-sm);
|
|
3163
|
+
overflow: hidden;
|
|
3164
|
+
text-overflow: ellipsis;
|
|
3165
|
+
white-space: nowrap;
|
|
3166
|
+
}
|
|
3167
|
+
|
|
3168
|
+
/* A pseudo-field wrapper (border/background, like every other field in this
|
|
3169
|
+
form) CONTAINING two real buttons, spaced apart — `[App] <--> [Connection]`
|
|
3170
|
+
(2026-08-30, fifth pass: "still missing border around SendGrid + prod...
|
|
3171
|
+
look like before, where both were inside a pseudo field, only change was
|
|
3172
|
+
to make the buttons look like buttons"). The outer border is back; each
|
|
3173
|
+
button ALSO keeps its own border/background (one shade lighter,
|
|
3174
|
+
`--w6w-panel` against the field's `--w6w-panel-2`) so it still reads as a
|
|
3175
|
+
clickable button, not merely text, without the two touching directly —
|
|
3176
|
+
the field's own padding is the gap between its edge and each button. */
|
|
3177
|
+
.w6w-app-conn-row {
|
|
3178
|
+
display: flex;
|
|
3179
|
+
align-items: center;
|
|
3180
|
+
justify-content: space-between;
|
|
3181
|
+
gap: var(--w6w-sp-2);
|
|
3182
|
+
background: var(--w6w-panel-2);
|
|
3183
|
+
border: 1px solid var(--w6w-border);
|
|
3184
|
+
border-radius: 8px;
|
|
3185
|
+
min-height: 36px;
|
|
3186
|
+
padding: var(--w6w-sp-1);
|
|
3187
|
+
}
|
|
3188
|
+
|
|
3189
|
+
.w6w-app-conn-btn {
|
|
3190
|
+
flex: 0 1 auto;
|
|
3191
|
+
min-width: 0;
|
|
3192
|
+
display: flex;
|
|
3193
|
+
align-items: center;
|
|
3194
|
+
gap: var(--w6w-sp-2);
|
|
3195
|
+
background: var(--w6w-panel);
|
|
3196
|
+
border: 1px solid var(--w6w-border);
|
|
3197
|
+
border-radius: 6px;
|
|
3198
|
+
padding: var(--w6w-sp-1) var(--w6w-sp-2-5);
|
|
3199
|
+
cursor: pointer;
|
|
3200
|
+
text-align: left;
|
|
3201
|
+
font: inherit;
|
|
3202
|
+
color: var(--w6w-text);
|
|
3203
|
+
}
|
|
3204
|
+
|
|
3205
|
+
.w6w-app-conn-btn:disabled {
|
|
3206
|
+
cursor: default;
|
|
3207
|
+
opacity: 0.6;
|
|
3208
|
+
}
|
|
3209
|
+
|
|
3210
|
+
.w6w-app-conn-btn:hover:not(:disabled),
|
|
3211
|
+
.w6w-app-conn-btn[aria-expanded=true] {
|
|
3212
|
+
border-color: var(--w6w-accent);
|
|
3213
|
+
}
|
|
3214
|
+
|
|
3215
|
+
/* A flyout popover (App/Connection pickers) — portaled to the enclosing
|
|
3216
|
+
`<dialog>` so it floats OVER the modal's own scrollable body instead of
|
|
3217
|
+
being clipped/squeezed inside it (`Flyout` component doc has the why).
|
|
3218
|
+
Plain positioned div, not a nested native dialog. No max-height/overflow
|
|
3219
|
+
of its own: `AppPicker` already caps and scrolls itself
|
|
3220
|
+
(`.w6w-apppicker-host`, `min(70vh, 520px)`), and the plain connection
|
|
3221
|
+
list is short enough in practice to size to content — a SECOND scroll
|
|
3222
|
+
container nested inside this one would double-scroll `AppPicker`. */
|
|
3223
|
+
.w6w-flyout {
|
|
3224
|
+
position: fixed;
|
|
3225
|
+
z-index: 40;
|
|
3226
|
+
/* No `box-sizing: border-box` reset elsewhere in this package (checked) —
|
|
3227
|
+
the inline `width` set by `Flyout` is meant to match the anchor row
|
|
3228
|
+
EXACTLY (2026-08-30: "should extend to the end of the prod button and
|
|
3229
|
+
div"), so padding/border must come out of that width, not add to it. */
|
|
3230
|
+
box-sizing: border-box;
|
|
3231
|
+
background: var(--w6w-panel);
|
|
3232
|
+
border: 1px solid var(--w6w-border);
|
|
3233
|
+
border-radius: 8px;
|
|
3234
|
+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
|
|
3235
|
+
padding: var(--w6w-sp-2);
|
|
3236
|
+
}
|
|
3237
|
+
|
|
3238
|
+
.w6w-btn-sm {
|
|
3239
|
+
padding: var(--w6w-sp-1) var(--w6w-sp-2);
|
|
3240
|
+
font-size: var(--w6w-fs-xs);
|
|
3241
|
+
flex-shrink: 0;
|
|
3242
|
+
}
|
|
3243
|
+
|
|
3244
|
+
/* Only the parameters form scrolls; x-padding keeps fields off the edge + scrollbar. */
|
|
3245
|
+
.w6w-stepconfig-body {
|
|
3246
|
+
flex: 1;
|
|
3247
|
+
min-height: 0;
|
|
3248
|
+
overflow-y: auto;
|
|
3249
|
+
padding-inline: var(--w6w-sp-1);
|
|
3250
|
+
padding-right: var(--w6w-sp-2);
|
|
3251
|
+
}
|
|
3252
|
+
|
|
3253
|
+
/* Footer pinned to the modal bottom, outside the scroll area. */
|
|
3254
|
+
.w6w-stepconfig-footer {
|
|
3255
|
+
flex-shrink: 0;
|
|
3256
|
+
border-top: 1px solid var(--w6w-border);
|
|
3257
|
+
padding-top: var(--w6w-sp-3);
|
|
3258
|
+
margin-top: 0;
|
|
3259
|
+
}
|
|
3260
|
+
|
|
3261
|
+
/* Test-required note — always rendered (empty when there is nothing to say),
|
|
3262
|
+
so its reserved height keeps the footer's buttons at the same x/y whether
|
|
3263
|
+
the note has text or not; one line, ellipsized rather than wrapped. */
|
|
3264
|
+
.w6w-stepconfig-testnote {
|
|
3265
|
+
flex-shrink: 0;
|
|
3266
|
+
min-height: 1.4em;
|
|
3267
|
+
white-space: nowrap;
|
|
3268
|
+
overflow: hidden;
|
|
3269
|
+
text-overflow: ellipsis;
|
|
3270
|
+
}
|
|
3271
|
+
|
|
3272
|
+
/* The whole-config "code"/JSON view is a DIRECT child of the body — stretch it
|
|
3273
|
+
to fill the modal height instead of leaving the dialog half-empty (it passes
|
|
3274
|
+
height="100%"). Inline json/code PARAM fields live inside a `.w6w-field` and
|
|
3275
|
+
size to their content, capped by the editor's own maxHeight (grow, then
|
|
3276
|
+
scroll inside), so they are intentionally NOT stretched here — that was the
|
|
3277
|
+
cause of the empty space + overlap under short group/json fields. */
|
|
3278
|
+
.w6w-stepconfig-body:has(> .w6w-code-editor, > .w6w-json-editor) {
|
|
3279
|
+
display: flex;
|
|
3280
|
+
flex-direction: column;
|
|
3281
|
+
gap: var(--w6w-sp-2-5);
|
|
3282
|
+
}
|
|
3283
|
+
|
|
3284
|
+
.w6w-stepconfig-body > .w6w-code-editor,
|
|
3285
|
+
.w6w-stepconfig-body > .w6w-json-editor {
|
|
3286
|
+
flex: 1 1 auto;
|
|
3287
|
+
min-height: 0;
|
|
3288
|
+
}
|
|
3289
|
+
|
|
3290
|
+
/* The `copyable` prop's button overlays `.w6w-json-editor`'s own top-right
|
|
3291
|
+
corner — mirrors `_copyable.scss:86-100`'s CodeBlock geometry, but there is
|
|
3292
|
+
no `<pre>` here for a `:has()` selector to reach, so it is scoped directly
|
|
3293
|
+
to the class instead. Anchored to `.w6w-json-editor` itself (not the
|
|
3294
|
+
CodeMirror scroller), so it stays pinned to the visible corner rather than
|
|
3295
|
+
scrolling with the content. */
|
|
3296
|
+
.w6w-json-editor {
|
|
3297
|
+
position: relative;
|
|
3298
|
+
}
|
|
3299
|
+
|
|
3300
|
+
.w6w-json-editor > .w6w-copyable-btn {
|
|
3301
|
+
position: absolute;
|
|
3302
|
+
top: var(--w6w-sp-1);
|
|
3303
|
+
right: var(--w6w-sp-1);
|
|
3304
|
+
/* Opaque backdrop: this button sits ON the JSON's first line, and
|
|
3305
|
+
`.w6w-icon-btn`'s transparent idle state would let the text read through
|
|
3306
|
+
it (mirrors `_copyable.scss:93-99`'s rationale exactly). */
|
|
3307
|
+
background: var(--w6w-panel);
|
|
3308
|
+
border-color: var(--w6w-border);
|
|
3309
|
+
}
|
|
3310
|
+
|
|
3311
|
+
.w6w-stepconfig-body .w6w-field > textarea {
|
|
3312
|
+
resize: vertical;
|
|
3313
|
+
}
|
|
3314
|
+
|
|
3315
|
+
/* Field label row with a trailing action (e.g. the JSON "open full view" btn). */
|
|
3316
|
+
.w6w-field-labelrow {
|
|
3317
|
+
display: flex;
|
|
3318
|
+
align-items: center;
|
|
3319
|
+
justify-content: space-between;
|
|
3320
|
+
gap: var(--w6w-sp-2);
|
|
3321
|
+
}
|
|
3322
|
+
|
|
3323
|
+
/* Full-view JSON modal body — fill the dialog so the editor is roomy. */
|
|
3324
|
+
.w6w-json-fullview {
|
|
3325
|
+
display: flex;
|
|
3326
|
+
flex-direction: column;
|
|
3327
|
+
min-height: 0;
|
|
3328
|
+
flex: 1 1 auto;
|
|
3329
|
+
height: 60vh;
|
|
3330
|
+
}
|
|
3331
|
+
|
|
3332
|
+
.w6w-json-fullview > .w6w-json-editor {
|
|
3333
|
+
flex: 1 1 auto;
|
|
3334
|
+
min-height: 0;
|
|
3335
|
+
}
|
|
3336
|
+
|
|
3337
|
+
/* React Flow chrome, driven from the app's own tokens.
|
|
3338
|
+
|
|
3339
|
+
React Flow themes every surface through a three-link chain,
|
|
3340
|
+
`var(--xy-X-props, var(--xy-X, var(--xy-X-default)))`. The library defines
|
|
3341
|
+
only the `-default` link (light/dark, its own palette); the MIDDLE name is
|
|
3342
|
+
never declared by the library and exists purely as a host hook. Setting those
|
|
3343
|
+
middle names here re-points the zoom/fit control stack at `--w6w-*`, so it
|
|
3344
|
+
matches whatever surface the host theme actually uses — and any ControlButton
|
|
3345
|
+
added to that stack later inherits it with no styling of its own.
|
|
3346
|
+
|
|
3347
|
+
Custom properties, deliberately, rather than a `.react-flow__controls-button`
|
|
3348
|
+
override: React Flow's own stylesheet is compiled into the same
|
|
3349
|
+
styles.css (`@use` in the build-only styles.build.scss), but cascade
|
|
3350
|
+
order is not something to lean on: a bare class override (0,1,0) would tie
|
|
3351
|
+
with the library's own rule and lose if the order ever changed. Custom properties inherit and are
|
|
3352
|
+
order-independent, and scoping them on `.w6w-flow` keeps them off the rest of
|
|
3353
|
+
the page.
|
|
3354
|
+
|
|
3355
|
+
Pairs with `colorMode={…}` on <ReactFlow>, which fixes the `-default` link for
|
|
3356
|
+
the chrome this block doesn't name (minimap mask, handles, background dots). */
|
|
3357
|
+
.w6w-flow {
|
|
3358
|
+
--xy-controls-button-background-color: var(--w6w-panel);
|
|
3359
|
+
--xy-controls-button-background-color-hover: var(--w6w-panel-2);
|
|
3360
|
+
--xy-controls-button-color: var(--w6w-text);
|
|
3361
|
+
--xy-controls-button-color-hover: var(--w6w-accent);
|
|
3362
|
+
--xy-controls-button-border-color: var(--w6w-border);
|
|
3363
|
+
}
|
|
3364
|
+
|
|
3365
|
+
/* An error edge — `Edge.when: "error"` (core rfcs/workflow.md · "Amendment —
|
|
3366
|
+
2026-07-29: failure-conditioned edges"). Dashed and drawn in the shared
|
|
3367
|
+
--w6w-danger token (never a hard-coded hex) so the failure lane reads
|
|
3368
|
+
differently from the success lane, and correctly, in BOTH themes.
|
|
3369
|
+
|
|
3370
|
+
ORDER MATTERS — this must stay ABOVE the selected/focused block below.
|
|
3371
|
+
Both selectors are (0,4,0), i.e. exactly equal specificity, so source order
|
|
3372
|
+
decides the winner. Selection has to be able to repaint the edge in the
|
|
3373
|
+
accent colour; put this block after that one and a selected error edge stops
|
|
3374
|
+
highlighting, which reads as a bug. */
|
|
3375
|
+
.w6w-flow .react-flow__edge.w6w-edge-error .react-flow__edge-path {
|
|
3376
|
+
stroke: var(--w6w-danger);
|
|
3377
|
+
stroke-dasharray: 6 4;
|
|
3378
|
+
}
|
|
3379
|
+
|
|
3380
|
+
.w6w-flow .react-flow__edge.w6w-edge-error .react-flow__edge-text {
|
|
3381
|
+
fill: var(--w6w-danger);
|
|
3382
|
+
}
|
|
3383
|
+
|
|
3384
|
+
.w6w-flow .react-flow__edge.w6w-edge-error .react-flow__edge-textbg {
|
|
3385
|
+
fill: var(--w6w-panel);
|
|
3386
|
+
}
|
|
3387
|
+
|
|
3388
|
+
/* Run-state edge painting (T1.1.1) — whether a main-graph edge was TAKEN or
|
|
3389
|
+
SKIPPED by the run currently showing on the canvas (see `run-visuals.ts`'s
|
|
3390
|
+
`edgeRunState`). Both classes are ADDITIVE to `.w6w-edge-error` above (an
|
|
3391
|
+
edge can be `w6w-edge-error w6w-edge-taken` at once), so ORDER decides how
|
|
3392
|
+
they compose — same equal-(0,4,0)-specificity discipline `.w6w-edge-error`
|
|
3393
|
+
already documents, kept below it in source:
|
|
3394
|
+
|
|
3395
|
+
- `.w6w-edge-taken`'s STROKE COLOUR is guarded to the non-error case via
|
|
3396
|
+
`:where(:not(.w6w-edge-error))` — `:where()` contributes ZERO
|
|
3397
|
+
specificity, so this stays at the SAME (0,4,0) weight as every other
|
|
3398
|
+
block here instead of out-ranking `.selected` below. A taken ERROR edge
|
|
3399
|
+
(the failure path a run actually followed) keeps the danger colour — the
|
|
3400
|
+
fact of having failed does not stop being true — and only gets the
|
|
3401
|
+
thicker stroke-width (the second, unconditional rule).
|
|
3402
|
+
- `.w6w-edge-skipped` is intentionally UNGUARDED: a skipped error edge
|
|
3403
|
+
(the step succeeded, so its error lane never fired) dims to muted same
|
|
3404
|
+
as a skipped success edge does — the failure never happened, so danger
|
|
3405
|
+
is the wrong colour regardless of which lane it is. */
|
|
3406
|
+
.w6w-flow .react-flow__edge.w6w-edge-taken:where(:not(.w6w-edge-error)) .react-flow__edge-path {
|
|
3407
|
+
stroke: var(--w6w-success);
|
|
3408
|
+
}
|
|
3409
|
+
|
|
3410
|
+
.w6w-flow .react-flow__edge.w6w-edge-taken .react-flow__edge-path {
|
|
3411
|
+
stroke-width: 2.5;
|
|
3412
|
+
}
|
|
3413
|
+
|
|
3414
|
+
.w6w-flow .react-flow__edge.w6w-edge-skipped .react-flow__edge-path {
|
|
3415
|
+
stroke: var(--w6w-muted);
|
|
3416
|
+
stroke-dasharray: 2 3;
|
|
3417
|
+
opacity: 0.55;
|
|
3418
|
+
}
|
|
3419
|
+
|
|
3420
|
+
/* A step's own Notes, shown under its canvas card — human override,
|
|
3421
|
+
2026-08-30, so a description written once (settings → gear icon) is
|
|
3422
|
+
visible without opening the step. One line, clipped with an ellipsis (the
|
|
3423
|
+
full text is still on the node's `title=` for a hover); `max-width`
|
|
3424
|
+
matches the card's own `minWidth` so a short note never forces the row
|
|
3425
|
+
wider than the card sitting above it. Font size matches the sibling
|
|
3426
|
+
meta-line's own inline fontSize:10 (not scanned by this ratchet) directly
|
|
3427
|
+
above it — the smallest declared token, --w6w-fs-xs, is 12px and would
|
|
3428
|
+
visibly mismatch the two lines. */
|
|
3429
|
+
.w6w-flow .w6w-node-notes {
|
|
3430
|
+
margin-top: var(--w6w-sp-0-5);
|
|
3431
|
+
padding-left: var(--w6w-sp-0-5);
|
|
3432
|
+
/* lint-tokens-allow: matches the sibling meta-line's inline fontSize:10 above it */
|
|
3433
|
+
font-size: 10px;
|
|
3434
|
+
font-style: italic;
|
|
3435
|
+
opacity: 0.75;
|
|
3436
|
+
max-width: 180px;
|
|
3437
|
+
overflow: hidden;
|
|
3438
|
+
text-overflow: ellipsis;
|
|
3439
|
+
white-space: nowrap;
|
|
3440
|
+
}
|
|
3441
|
+
|
|
3442
|
+
/* The ordinary (success) ports — bumped from the library's own 6px default
|
|
3443
|
+
(2026-08-30: "ports must have consistent size") to match the error port
|
|
3444
|
+
below exactly. `:not(.w6w-handle-multi)`: the multi-input handle is its
|
|
3445
|
+
own taller pill shape (`PortHandle`'s inline style), not a dot — this
|
|
3446
|
+
rule must not touch it. */
|
|
3447
|
+
.w6w-flow .react-flow__handle:not(.w6w-handle-multi) {
|
|
3448
|
+
width: 8px;
|
|
3449
|
+
height: 8px;
|
|
3450
|
+
}
|
|
3451
|
+
|
|
3452
|
+
/* The error exit port — a step/control node's second SOURCE handle (T1.1.1),
|
|
3453
|
+
rendered below the ordinary exit via the shared PortHandle component
|
|
3454
|
+
(`id={ERROR_SOURCE_HANDLE}`, `variant="error"`). Danger-tinted, same
|
|
3455
|
+
--w6w-danger token as .w6w-edge-error above (never a hard-coded hex).
|
|
3456
|
+
DELIBERATELY 1px SMALLER, in actual box size, than the ordinary ports
|
|
3457
|
+
above (2026-08-30, second pass on "consistent size"): setting both to the
|
|
3458
|
+
literal same 8px×8px box (the first pass) still read as bigger — measured
|
|
3459
|
+
directly, computed styles for both were byte-identical (same width,
|
|
3460
|
+
height, border-width, box-sizing, no box-shadow/outline difference) — a
|
|
3461
|
+
saturated warm fill on a light canvas background perceptually "expands"
|
|
3462
|
+
past a same-sized dark/cool one (the classic irradiation illusion), so
|
|
3463
|
+
matching PIXELS does not produce matching APPEARANCE. Compensating with a
|
|
3464
|
+
smaller literal box is what actually reads as equal. */
|
|
3465
|
+
.w6w-flow .react-flow__handle.w6w-handle-error {
|
|
3466
|
+
width: 7px;
|
|
3467
|
+
height: 7px;
|
|
3468
|
+
background: var(--w6w-danger);
|
|
3469
|
+
border-color: var(--w6w-danger);
|
|
3470
|
+
opacity: 0.85;
|
|
3471
|
+
}
|
|
3472
|
+
|
|
3473
|
+
.w6w-flow .react-flow__handle.w6w-handle-error:hover {
|
|
3474
|
+
opacity: 1;
|
|
3475
|
+
}
|
|
3476
|
+
|
|
3477
|
+
/* Workflow edges: highlight the selected/focused edge in the accent colour and
|
|
3478
|
+
thicken it, so it's obvious which one Backspace/Delete will remove. The wide,
|
|
3479
|
+
invisible interaction path keeps the click target generous. */
|
|
3480
|
+
.w6w-flow .react-flow__edge.selected .react-flow__edge-path,
|
|
3481
|
+
.w6w-flow .react-flow__edge:focus .react-flow__edge-path,
|
|
3482
|
+
.w6w-flow .react-flow__edge:focus-visible .react-flow__edge-path {
|
|
3483
|
+
stroke: var(--w6w-accent);
|
|
3484
|
+
stroke-width: 2.5;
|
|
3485
|
+
}
|
|
3486
|
+
|
|
3487
|
+
/* The edge-lane control — `Run on: Success / Error`, revealed in a React Flow
|
|
3488
|
+
<Panel position="top-right"> when exactly one edge is selected. Unlike the
|
|
3489
|
+
`+ Step` button (a self-contained .w6w-btn), this row mixes a label, two ghost
|
|
3490
|
+
buttons and an inline refusal, so it needs its own surface to stay legible over
|
|
3491
|
+
the canvas background. Same shape as .w6w-node-toolbar below; tokens only. */
|
|
3492
|
+
.w6w-edge-lane {
|
|
3493
|
+
display: flex;
|
|
3494
|
+
align-items: center;
|
|
3495
|
+
flex-wrap: wrap;
|
|
3496
|
+
gap: var(--w6w-sp-1-5);
|
|
3497
|
+
max-width: 280px;
|
|
3498
|
+
padding: var(--w6w-sp-1) var(--w6w-sp-2);
|
|
3499
|
+
background: var(--w6w-panel);
|
|
3500
|
+
border: 1px solid var(--w6w-border);
|
|
3501
|
+
border-radius: 8px;
|
|
3502
|
+
}
|
|
3503
|
+
|
|
3504
|
+
/* An inline refusal (re-laning would mint an id another edge already holds).
|
|
3505
|
+
Rendered here rather than through a browser dialog — see .ai/conventions.md ·
|
|
3506
|
+
"No browser dialogs" — and on its own row so the buttons don't reflow. */
|
|
3507
|
+
.w6w-edge-lane-err {
|
|
3508
|
+
flex: 1 1 100%;
|
|
3509
|
+
color: var(--w6w-danger);
|
|
3510
|
+
}
|
|
3511
|
+
|
|
3512
|
+
/* Per-node control toolbar (React Flow NodeToolbar) */
|
|
3513
|
+
.w6w-node-toolbar {
|
|
3514
|
+
display: flex;
|
|
3515
|
+
gap: var(--w6w-sp-1);
|
|
3516
|
+
background: var(--w6w-panel);
|
|
3517
|
+
border: 1px solid var(--w6w-border);
|
|
3518
|
+
border-radius: 8px;
|
|
3519
|
+
padding: var(--w6w-sp-1);
|
|
3520
|
+
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.3);
|
|
3521
|
+
}
|
|
3522
|
+
|
|
3523
|
+
.w6w-node-toolbar-btn {
|
|
3524
|
+
display: inline-flex;
|
|
3525
|
+
align-items: center;
|
|
3526
|
+
justify-content: center;
|
|
3527
|
+
background: transparent;
|
|
3528
|
+
border: none;
|
|
3529
|
+
border-radius: 6px;
|
|
3530
|
+
padding: 5px;
|
|
3531
|
+
color: var(--w6w-text);
|
|
3532
|
+
font-size: var(--w6w-fs-xs);
|
|
3533
|
+
cursor: pointer;
|
|
3534
|
+
}
|
|
3535
|
+
|
|
3536
|
+
.w6w-node-toolbar-btn:hover {
|
|
3537
|
+
background: var(--w6w-panel-2);
|
|
3538
|
+
}
|
|
3539
|
+
|
|
3540
|
+
.w6w-node-toolbar-btn.danger:hover {
|
|
3541
|
+
background: var(--w6w-danger);
|
|
3542
|
+
color: white;
|
|
3543
|
+
}
|
|
3544
|
+
|
|
3545
|
+
.w6w-params-optional > summary {
|
|
3546
|
+
cursor: pointer;
|
|
3547
|
+
}
|
|
3548
|
+
|
|
3549
|
+
/* `section` param — a layout-only container. `section: "collapsible"` renders as
|
|
3550
|
+
a titled, bordered disclosure; `section: "group"` reuses `.w6w-field-row` /
|
|
3551
|
+
`.w6w-stack` for its layout (no rules of its own needed). */
|
|
3552
|
+
/* Fan-out badge under a card: the glyph (⇉ parallel / → sequence), not colour, carries the mode. */
|
|
3553
|
+
.w6w-flow .w6w-fanout-badge {
|
|
3554
|
+
display: inline-block;
|
|
3555
|
+
margin-top: var(--w6w-sp-0-5);
|
|
3556
|
+
padding: 0 var(--w6w-sp-1);
|
|
3557
|
+
border: 1px solid var(--w6w-border);
|
|
3558
|
+
border-radius: var(--w6w-radius-sm, 3px);
|
|
3559
|
+
font-size: var(--w6w-fs-xs);
|
|
3560
|
+
color: var(--w6w-muted, inherit);
|
|
3561
|
+
}
|
|
3562
|
+
|
|
3563
|
+
.w6w-section {
|
|
3564
|
+
border: 1px solid var(--w6w-border);
|
|
3565
|
+
border-radius: 8px;
|
|
3566
|
+
padding: var(--w6w-sp-2) var(--w6w-sp-2-5);
|
|
3567
|
+
}
|
|
3568
|
+
|
|
3569
|
+
.w6w-section > summary {
|
|
3570
|
+
cursor: pointer;
|
|
3571
|
+
display: flex;
|
|
3572
|
+
flex-direction: column;
|
|
3573
|
+
gap: var(--w6w-sp-0-5);
|
|
3574
|
+
}
|
|
3575
|
+
|
|
3576
|
+
.w6w-section-title {
|
|
3577
|
+
color: var(--w6w-text);
|
|
3578
|
+
font-weight: var(--w6w-fw-semibold);
|
|
3579
|
+
}
|
|
3580
|
+
|
|
3581
|
+
.w6w-section-subtitle {
|
|
3582
|
+
color: var(--w6w-muted);
|
|
3583
|
+
font-size: 0.8em;
|
|
3584
|
+
}
|
|
3585
|
+
|
|
3586
|
+
.w6w-section-body {
|
|
3587
|
+
margin-top: var(--w6w-sp-2);
|
|
3588
|
+
}
|
|
3589
|
+
|
|
3590
|
+
/* Inline "Test run" block in the step builder (sits above the footer). */
|
|
3591
|
+
.w6w-steptest {
|
|
3592
|
+
display: flex;
|
|
3593
|
+
flex-direction: column;
|
|
3594
|
+
gap: var(--w6w-sp-2);
|
|
3595
|
+
flex-shrink: 0;
|
|
3596
|
+
}
|
|
3597
|
+
|
|
3598
|
+
.w6w-steptest-bar {
|
|
3599
|
+
display: flex;
|
|
3600
|
+
align-items: center;
|
|
3601
|
+
gap: var(--w6w-sp-2-5);
|
|
3602
|
+
}
|
|
3603
|
+
|
|
3604
|
+
/* A labeled test-run output block (Result vs Console). */
|
|
3605
|
+
.w6w-testout {
|
|
3606
|
+
display: flex;
|
|
3607
|
+
flex-direction: column;
|
|
3608
|
+
gap: var(--w6w-sp-1);
|
|
3609
|
+
}
|
|
3610
|
+
|
|
3611
|
+
.w6w-testout-label {
|
|
3612
|
+
font-size: 0.72em;
|
|
3613
|
+
font-weight: var(--w6w-fw-semibold);
|
|
3614
|
+
letter-spacing: 0.04em;
|
|
3615
|
+
text-transform: uppercase;
|
|
3616
|
+
color: var(--w6w-muted);
|
|
3617
|
+
}
|
|
3618
|
+
|
|
3619
|
+
/* Console output reads as a terminal — monospace + muted, distinct from Result. */
|
|
3620
|
+
.w6w-testout-console {
|
|
3621
|
+
font-family: var(--w6w-font-mono);
|
|
3622
|
+
color: var(--w6w-muted);
|
|
3623
|
+
border-style: dashed;
|
|
3624
|
+
}
|
|
3625
|
+
|
|
3626
|
+
/* Result / error box */
|
|
3627
|
+
.w6w-result {
|
|
3628
|
+
background: var(--w6w-panel-2);
|
|
3629
|
+
border: 1px solid var(--w6w-border);
|
|
3630
|
+
border-radius: 8px;
|
|
3631
|
+
padding: var(--w6w-sp-2-5) var(--w6w-sp-3);
|
|
3632
|
+
font-family: var(--w6w-font-mono);
|
|
3633
|
+
font-size: 0.85em;
|
|
3634
|
+
white-space: pre-wrap;
|
|
3635
|
+
word-break: break-word;
|
|
3636
|
+
color: var(--w6w-text);
|
|
3637
|
+
}
|
|
3638
|
+
|
|
3639
|
+
.w6w-result.w6w-error {
|
|
3640
|
+
border-color: var(--w6w-danger);
|
|
3641
|
+
color: var(--w6w-danger);
|
|
3642
|
+
}
|
|
3643
|
+
|
|
3644
|
+
/* Host-embedded ActionTestForm (studio's ConnectionTesterModal wraps it in its
|
|
3645
|
+
OWN full modal). The widget then fills that modal as a full-height flex column:
|
|
3646
|
+
the params + saved-tests region scrolls, and the action bar is a bottom-pinned,
|
|
3647
|
+
non-scrolling footer. These classes are only applied in `embedded` mode, so the
|
|
3648
|
+
inline / own-pop-out layout is untouched. */
|
|
3649
|
+
.w6w-tester-embedded-root {
|
|
3650
|
+
flex: 1;
|
|
3651
|
+
min-height: 0;
|
|
3652
|
+
}
|
|
3653
|
+
|
|
3654
|
+
.w6w-tester-embedded {
|
|
3655
|
+
display: flex;
|
|
3656
|
+
flex-direction: column;
|
|
3657
|
+
flex: 1;
|
|
3658
|
+
min-height: 0;
|
|
3659
|
+
}
|
|
3660
|
+
|
|
3661
|
+
.w6w-tester-embedded-scroll {
|
|
3662
|
+
flex: 1;
|
|
3663
|
+
min-height: 0;
|
|
3664
|
+
overflow: auto;
|
|
3665
|
+
}
|
|
3666
|
+
|
|
3667
|
+
.w6w-tester-embedded-cols {
|
|
3668
|
+
display: flex;
|
|
3669
|
+
gap: var(--w6w-sp-4);
|
|
3670
|
+
align-items: flex-start;
|
|
3671
|
+
}
|
|
3672
|
+
|
|
3673
|
+
.w6w-tester-embedded-main {
|
|
3674
|
+
flex: 1;
|
|
3675
|
+
min-width: 0;
|
|
3676
|
+
}
|
|
3677
|
+
|
|
3678
|
+
.w6w-tester-embedded-rail {
|
|
3679
|
+
width: 260px;
|
|
3680
|
+
flex-shrink: 0;
|
|
3681
|
+
}
|
|
3682
|
+
|
|
3683
|
+
/* The action bar as a pinned footer: kept out of the scroll region and separated
|
|
3684
|
+
with a top border so Run / Save / Delete stay visible however long the params. */
|
|
3685
|
+
.w6w-tester-actions-footer {
|
|
3686
|
+
margin-top: auto;
|
|
3687
|
+
border-top: 1px solid var(--w6w-border);
|
|
3688
|
+
padding-top: var(--w6w-sp-3);
|
|
3689
|
+
}
|
|
3690
|
+
|
|
3691
|
+
/* ActionTestForm's OWN pop-out (`Modal size="full"`, the "Edit params" ⤢
|
|
3692
|
+
toggle — not the host-embedded case above). T1.4.1 round 1 made `-full`'s
|
|
3693
|
+
`overflow: hidden` live for the first time; the dialog itself no longer
|
|
3694
|
+
scrolls, so at a realistic param count (15-23 is typical for a first-party
|
|
3695
|
+
action, e.g. followupboss/search-people, youtube/search) content below the
|
|
3696
|
+
fold became unreachable with zero scrollbar. This mirrors the
|
|
3697
|
+
`.w6w-tester-embedded-scroll` mechanism above — flex:1/min-height:0 to fill
|
|
3698
|
+
the dialog's remaining flex-column height, `overflow: auto` to own the
|
|
3699
|
+
scrollbar — so the params + result (+ saved-tests rail) region scrolls
|
|
3700
|
+
internally while the Run/Save/Delete action bar stays a pinned,
|
|
3701
|
+
non-scrolling footer via the SAME `.w6w-tester-actions-footer` class. */
|
|
3702
|
+
.w6w-tester-popout {
|
|
3703
|
+
display: flex;
|
|
3704
|
+
flex-direction: column;
|
|
3705
|
+
flex: 1;
|
|
3706
|
+
min-height: 0;
|
|
3707
|
+
}
|
|
3708
|
+
|
|
3709
|
+
.w6w-tester-popout-scroll {
|
|
3710
|
+
flex: 1;
|
|
3711
|
+
min-height: 0;
|
|
3712
|
+
overflow: auto;
|
|
3713
|
+
}
|
|
3714
|
+
|
|
3715
|
+
/* Uptime strip — one cell per day, "how has this service behaved lately" at a
|
|
3716
|
+
glance. Colour comes from the same `--w6w-health-*` tokens as the health pill,
|
|
3717
|
+
through the same single `--w6w-health-color` indirection (set once on the cell,
|
|
3718
|
+
remapped by the per-state class below), so overriding a token restyles the pill
|
|
3719
|
+
and the strip together.
|
|
3720
|
+
|
|
3721
|
+
Colour is never the only signal: the FILL HEIGHT encodes severity, so the row
|
|
3722
|
+
stays readable in greyscale and for a colour-blind viewer — `ok` a short
|
|
3723
|
+
baseline bar, `degraded` taller, `down` the full cell, and `unknown` a hatched
|
|
3724
|
+
outline with no solid fill (nothing was measured: not a good day, not a bad
|
|
3725
|
+
one). Each cell also carries a `title` with its day and state. */
|
|
3726
|
+
.w6w-uptime-strip {
|
|
3727
|
+
display: grid;
|
|
3728
|
+
grid-auto-flow: column;
|
|
3729
|
+
grid-auto-columns: minmax(0, 1fr);
|
|
3730
|
+
gap: var(--w6w-sp-0-5);
|
|
3731
|
+
height: 22px;
|
|
3732
|
+
min-width: 0;
|
|
3733
|
+
align-items: stretch;
|
|
3734
|
+
}
|
|
3735
|
+
|
|
3736
|
+
.w6w-uptime-cell {
|
|
3737
|
+
--w6w-health-color: var(--w6w-health-unknown);
|
|
3738
|
+
--w6w-uptime-fill: 100%;
|
|
3739
|
+
position: relative;
|
|
3740
|
+
min-width: 2px;
|
|
3741
|
+
border-radius: 2px;
|
|
3742
|
+
/* The unfilled remainder of the day, so the strip reads as a continuous row
|
|
3743
|
+
rather than as floating bars. */
|
|
3744
|
+
background: color-mix(in srgb, var(--w6w-border) 55%, transparent);
|
|
3745
|
+
overflow: hidden;
|
|
3746
|
+
}
|
|
3747
|
+
|
|
3748
|
+
.w6w-uptime-cell::after {
|
|
3749
|
+
content: "";
|
|
3750
|
+
position: absolute;
|
|
3751
|
+
left: 0;
|
|
3752
|
+
right: 0;
|
|
3753
|
+
bottom: 0;
|
|
3754
|
+
height: var(--w6w-uptime-fill);
|
|
3755
|
+
border-radius: inherit;
|
|
3756
|
+
background: var(--w6w-health-color);
|
|
3757
|
+
}
|
|
3758
|
+
|
|
3759
|
+
.w6w-uptime-cell-ok {
|
|
3760
|
+
--w6w-health-color: var(--w6w-health-ok);
|
|
3761
|
+
--w6w-uptime-fill: 35%;
|
|
3762
|
+
}
|
|
3763
|
+
|
|
3764
|
+
.w6w-uptime-cell-degraded {
|
|
3765
|
+
--w6w-health-color: var(--w6w-health-degraded);
|
|
3766
|
+
--w6w-uptime-fill: 65%;
|
|
3767
|
+
}
|
|
3768
|
+
|
|
3769
|
+
.w6w-uptime-cell-down {
|
|
3770
|
+
--w6w-health-color: var(--w6w-health-down);
|
|
3771
|
+
--w6w-uptime-fill: 100%;
|
|
3772
|
+
}
|
|
3773
|
+
|
|
3774
|
+
.w6w-uptime-cell-unknown {
|
|
3775
|
+
--w6w-health-color: var(--w6w-health-unknown);
|
|
3776
|
+
--w6w-uptime-fill: 100%;
|
|
3777
|
+
}
|
|
3778
|
+
|
|
3779
|
+
/* No solid fill for `unknown` — a hatch, so an unmeasured day can never be
|
|
3780
|
+
mistaken for a healthy or a failing one, with or without colour. */
|
|
3781
|
+
.w6w-uptime-cell-unknown::after {
|
|
3782
|
+
background: repeating-linear-gradient(45deg, color-mix(in srgb, var(--w6w-health-color) 45%, transparent) 0 2px, transparent 2px 5px);
|
|
3783
|
+
border: 1px solid color-mix(in srgb, var(--w6w-health-color) 35%, var(--w6w-border));
|
|
3784
|
+
}
|
|
3785
|
+
|
|
3786
|
+
/* --- CodeBlock ------------------------------------------------------------ */
|
|
3787
|
+
/* Read-only syntax-highlighted display (`<CodeBlock>`). The colours come from
|
|
3788
|
+
the `--w6w-code-*` tokens via inline styles Prism sets, so this rule only
|
|
3789
|
+
owns box, rhythm and overflow. */
|
|
3790
|
+
.w6w-history-timeline {
|
|
3791
|
+
display: flex;
|
|
3792
|
+
flex-direction: column;
|
|
3793
|
+
gap: var(--w6w-sp-2);
|
|
3794
|
+
width: 100%;
|
|
3795
|
+
}
|
|
3796
|
+
|
|
3797
|
+
/* One positioned container shared by both lanes AND the axis, so every
|
|
3798
|
+
`left`/`width` percentage in any of the three is on the same coordinate
|
|
3799
|
+
system — this is what keeps the two series from drifting apart. */
|
|
3800
|
+
.w6w-history-plot {
|
|
3801
|
+
position: relative;
|
|
3802
|
+
display: flex;
|
|
3803
|
+
flex-direction: column;
|
|
3804
|
+
gap: var(--w6w-sp-1);
|
|
3805
|
+
}
|
|
3806
|
+
|
|
3807
|
+
.w6w-history-lane {
|
|
3808
|
+
position: relative;
|
|
3809
|
+
height: 22px;
|
|
3810
|
+
min-width: 0;
|
|
3811
|
+
}
|
|
3812
|
+
|
|
3813
|
+
/* --- execution lane -------------------------------------------------- */
|
|
3814
|
+
.w6w-history-cell {
|
|
3815
|
+
--w6w-health-color: var(--w6w-health-unknown);
|
|
3816
|
+
--w6w-history-fill: 100%;
|
|
3817
|
+
position: absolute;
|
|
3818
|
+
top: 0;
|
|
3819
|
+
bottom: 0;
|
|
3820
|
+
min-width: 1px;
|
|
3821
|
+
border-radius: 2px;
|
|
3822
|
+
overflow: hidden;
|
|
3823
|
+
/* The unfilled remainder of the cell, so the lane reads as a continuous
|
|
3824
|
+
row rather than as floating marks — same treatment as `UptimeStrip`. */
|
|
3825
|
+
background: color-mix(in srgb, var(--w6w-border) 55%, transparent);
|
|
3826
|
+
}
|
|
3827
|
+
|
|
3828
|
+
.w6w-history-cell::after {
|
|
3829
|
+
content: "";
|
|
3830
|
+
position: absolute;
|
|
3831
|
+
left: 0;
|
|
3832
|
+
right: 0;
|
|
3833
|
+
bottom: 0;
|
|
3834
|
+
height: var(--w6w-history-fill);
|
|
3835
|
+
border-radius: inherit;
|
|
3836
|
+
background: var(--w6w-health-color);
|
|
3837
|
+
}
|
|
3838
|
+
|
|
3839
|
+
.w6w-history-cell-ok {
|
|
3840
|
+
--w6w-health-color: var(--w6w-health-ok);
|
|
3841
|
+
--w6w-history-fill: 35%;
|
|
3842
|
+
}
|
|
3843
|
+
|
|
3844
|
+
.w6w-history-cell-degraded {
|
|
3845
|
+
--w6w-health-color: var(--w6w-health-degraded);
|
|
3846
|
+
--w6w-history-fill: 65%;
|
|
3847
|
+
}
|
|
3848
|
+
|
|
3849
|
+
.w6w-history-cell-down {
|
|
3850
|
+
--w6w-health-color: var(--w6w-health-down);
|
|
3851
|
+
--w6w-history-fill: 100%;
|
|
3852
|
+
}
|
|
3853
|
+
|
|
3854
|
+
.w6w-history-cell-unknown {
|
|
3855
|
+
--w6w-health-color: var(--w6w-health-unknown);
|
|
3856
|
+
--w6w-history-fill: 100%;
|
|
3857
|
+
}
|
|
3858
|
+
|
|
3859
|
+
/* No solid fill for `unknown` — a hatch, same reasoning as `UptimeStrip`'s:
|
|
3860
|
+
an unmeasured day must never be mistaken for a healthy or a failing one. */
|
|
3861
|
+
.w6w-history-cell-unknown::after {
|
|
3862
|
+
background: repeating-linear-gradient(45deg, color-mix(in srgb, var(--w6w-health-color) 45%, transparent) 0 2px, transparent 2px 5px);
|
|
3863
|
+
border: 1px solid color-mix(in srgb, var(--w6w-health-color) 35%, var(--w6w-border));
|
|
3864
|
+
}
|
|
3865
|
+
|
|
3866
|
+
/* --- vendor lane ------------------------------------------------------- */
|
|
3867
|
+
.w6w-history-bar {
|
|
3868
|
+
--w6w-health-color: var(--w6w-health-unknown);
|
|
3869
|
+
position: absolute;
|
|
3870
|
+
/* Thickness is the geometry half of severity — thin for `ok`, thicker for
|
|
3871
|
+
`degraded`, full lane height for `down`/`unknown` — using the spacing
|
|
3872
|
+
scale rather than a one-off literal so it never drifts from it. */
|
|
3873
|
+
top: var(--w6w-sp-1);
|
|
3874
|
+
bottom: var(--w6w-sp-1);
|
|
3875
|
+
min-width: 2px;
|
|
3876
|
+
border-radius: 2px;
|
|
3877
|
+
background: var(--w6w-health-color);
|
|
3878
|
+
}
|
|
3879
|
+
|
|
3880
|
+
.w6w-history-bar-ok {
|
|
3881
|
+
--w6w-health-color: var(--w6w-health-ok);
|
|
3882
|
+
}
|
|
3883
|
+
|
|
3884
|
+
.w6w-history-bar-degraded {
|
|
3885
|
+
--w6w-health-color: var(--w6w-health-degraded);
|
|
3886
|
+
top: var(--w6w-sp-0-5);
|
|
3887
|
+
bottom: var(--w6w-sp-0-5);
|
|
3888
|
+
}
|
|
3889
|
+
|
|
3890
|
+
.w6w-history-bar-down {
|
|
3891
|
+
--w6w-health-color: var(--w6w-health-down);
|
|
3892
|
+
top: 0;
|
|
3893
|
+
bottom: 0;
|
|
3894
|
+
}
|
|
3895
|
+
|
|
3896
|
+
.w6w-history-bar-unknown {
|
|
3897
|
+
--w6w-health-color: var(--w6w-health-unknown);
|
|
3898
|
+
top: 0;
|
|
3899
|
+
bottom: 0;
|
|
3900
|
+
background: repeating-linear-gradient(45deg, color-mix(in srgb, var(--w6w-health-color) 45%, transparent) 0 2px, transparent 2px 5px);
|
|
3901
|
+
border: 1px solid color-mix(in srgb, var(--w6w-health-color) 35%, var(--w6w-border));
|
|
3902
|
+
}
|
|
3903
|
+
|
|
3904
|
+
/* A clipped edge is squared off rather than rounded, so a bar that runs off
|
|
3905
|
+
the window reads as continuing beyond it rather than as ending there. */
|
|
3906
|
+
.w6w-history-bar-clip-start {
|
|
3907
|
+
border-top-left-radius: 0;
|
|
3908
|
+
border-bottom-left-radius: 0;
|
|
3909
|
+
}
|
|
3910
|
+
|
|
3911
|
+
.w6w-history-bar-clip-end {
|
|
3912
|
+
border-top-right-radius: 0;
|
|
3913
|
+
border-bottom-right-radius: 0;
|
|
3914
|
+
}
|
|
3915
|
+
|
|
3916
|
+
.w6w-history-empty {
|
|
3917
|
+
position: absolute;
|
|
3918
|
+
inset: 0;
|
|
3919
|
+
display: flex;
|
|
3920
|
+
align-items: center;
|
|
3921
|
+
color: var(--w6w-muted);
|
|
3922
|
+
font-size: var(--w6w-fs-xs);
|
|
3923
|
+
white-space: nowrap;
|
|
3924
|
+
overflow: hidden;
|
|
3925
|
+
text-overflow: ellipsis;
|
|
3926
|
+
}
|
|
3927
|
+
|
|
3928
|
+
/* --- axis --------------------------------------------------------------- */
|
|
3929
|
+
.w6w-history-axis {
|
|
3930
|
+
position: relative;
|
|
3931
|
+
height: 16px;
|
|
3932
|
+
}
|
|
3933
|
+
|
|
3934
|
+
.w6w-history-tick {
|
|
3935
|
+
position: absolute;
|
|
3936
|
+
top: 0;
|
|
3937
|
+
color: var(--w6w-muted);
|
|
3938
|
+
font-size: var(--w6w-fs-xs);
|
|
3939
|
+
line-height: var(--w6w-lh-normal);
|
|
3940
|
+
white-space: nowrap;
|
|
3941
|
+
}
|
|
3942
|
+
|
|
3943
|
+
.w6w-history-tick-start {
|
|
3944
|
+
transform: translateX(0);
|
|
3945
|
+
}
|
|
3946
|
+
|
|
3947
|
+
.w6w-history-tick-end {
|
|
3948
|
+
transform: translateX(-100%);
|
|
3949
|
+
}
|
|
3950
|
+
|
|
3951
|
+
.w6w-code-block {
|
|
3952
|
+
background: var(--w6w-panel-2);
|
|
3953
|
+
border: 1px solid var(--w6w-border);
|
|
3954
|
+
border-radius: var(--w6w-radius);
|
|
3955
|
+
margin: 0;
|
|
3956
|
+
overflow-x: auto;
|
|
3957
|
+
padding: var(--w6w-sp-3) 14px;
|
|
3958
|
+
tab-size: 2;
|
|
3959
|
+
}
|
|
3960
|
+
|
|
3961
|
+
.w6w-code-block code {
|
|
3962
|
+
background: none;
|
|
3963
|
+
display: block;
|
|
3964
|
+
font-family: var(--w6w-font-mono);
|
|
3965
|
+
font-size: 13px;
|
|
3966
|
+
line-height: 1.55;
|
|
3967
|
+
padding: 0;
|
|
3968
|
+
}
|
|
3969
|
+
|
|
3970
|
+
/* Each line is its own row so a line number can sit beside the text rather
|
|
3971
|
+
than inside it — a number inside the flow would be caught by a copy. */
|
|
3972
|
+
.w6w-code-line {
|
|
3973
|
+
display: flex;
|
|
3974
|
+
gap: var(--w6w-sp-3);
|
|
3975
|
+
white-space: pre;
|
|
3976
|
+
}
|
|
3977
|
+
|
|
3978
|
+
.w6w-code-line-text {
|
|
3979
|
+
white-space: inherit;
|
|
3980
|
+
}
|
|
3981
|
+
|
|
3982
|
+
/* `user-select: none` keeps the gutter out of a mouse selection; `aria-hidden`
|
|
3983
|
+
on the element keeps it out of the accessibility tree. Both are needed —
|
|
3984
|
+
neither one alone stops a copy from picking up the digits. */
|
|
3985
|
+
.w6w-code-line-no {
|
|
3986
|
+
color: var(--w6w-muted);
|
|
3987
|
+
flex: 0 0 auto;
|
|
3988
|
+
min-width: 2ch;
|
|
3989
|
+
opacity: 0.65;
|
|
3990
|
+
text-align: right;
|
|
3991
|
+
user-select: none;
|
|
3992
|
+
}
|
|
3993
|
+
|
|
3994
|
+
/* Wrapped mode indents continuation rows to the text column so a wrapped line
|
|
3995
|
+
still reads as one line. */
|
|
3996
|
+
.w6w-code-block--wrap .w6w-code-line,
|
|
3997
|
+
.w6w-code-block--wrap .w6w-code-line-text {
|
|
3998
|
+
white-space: pre-wrap;
|
|
3999
|
+
word-break: break-word;
|
|
4000
|
+
}
|
|
4001
|
+
|
|
4002
|
+
.w6w-code-block--wrap {
|
|
4003
|
+
overflow-x: hidden;
|
|
4004
|
+
}
|
|
4005
|
+
|
|
4006
|
+
/* Resolved params (Test tab, read-only): inline badge weight — like
|
|
4007
|
+
JsonParamField's "Invalid JSON" hint, not a full `.w6w-result.w6w-error`
|
|
4008
|
+
block per param, since either can appear once per configured param. */
|
|
4009
|
+
.w6w-param-unresolved {
|
|
4010
|
+
color: var(--w6w-danger);
|
|
4011
|
+
font-size: 0.85em;
|
|
4012
|
+
font-style: italic;
|
|
4013
|
+
}
|
|
4014
|
+
|
|
4015
|
+
.w6w-param-unevaluated {
|
|
4016
|
+
color: var(--w6w-muted);
|
|
4017
|
+
font-size: 0.85em;
|
|
4018
|
+
font-style: italic;
|
|
4019
|
+
}
|
|
4020
|
+
|
|
4021
|
+
/* One resolved param: a table row, not a stacked form field — this list is
|
|
4022
|
+
read-only display, never an editable `.w6w-field`, so it earns its own
|
|
4023
|
+
compact key-left/value-right layout instead of a label-above-control block
|
|
4024
|
+
(human report, 2026-09-01: key and value were indistinguishable and every
|
|
4025
|
+
row burned a full stacked block of vertical space). ONE grid across the
|
|
4026
|
+
whole list (`.w6w-resolved-table`), not one grid per row, so every row's
|
|
4027
|
+
key column lines up with the one above and below it. */
|
|
4028
|
+
.w6w-resolved-table {
|
|
4029
|
+
display: grid;
|
|
4030
|
+
grid-template-columns: auto 1fr;
|
|
4031
|
+
align-items: baseline;
|
|
4032
|
+
}
|
|
4033
|
+
|
|
4034
|
+
/* Each row is `display: contents` — it renders no box of its own, so its two
|
|
4035
|
+
children (label, value) become direct items of the parent grid above,
|
|
4036
|
+
sharing its column tracks instead of sizing their own. */
|
|
4037
|
+
.w6w-resolved-row {
|
|
4038
|
+
display: contents;
|
|
4039
|
+
font-size: calc(var(--w6w-fs-sm) * 0.9);
|
|
4040
|
+
}
|
|
4041
|
+
|
|
4042
|
+
/* No `column-gap` on the grid: a gap leaves a hole no cell's own border
|
|
4043
|
+
crosses, breaking the row divider into two segments. The same visual
|
|
4044
|
+
space between key and value comes from padding instead, which is part of
|
|
4045
|
+
each cell's own box — the border-bottom stays one unbroken line. */
|
|
4046
|
+
.w6w-resolved-row > * {
|
|
4047
|
+
padding: var(--w6w-sp-1-5) 0;
|
|
4048
|
+
border-bottom: 1px solid var(--w6w-border);
|
|
4049
|
+
}
|
|
4050
|
+
|
|
4051
|
+
.w6w-resolved-row:last-child > * {
|
|
4052
|
+
border-bottom: none;
|
|
4053
|
+
}
|
|
4054
|
+
|
|
4055
|
+
.w6w-resolved-label {
|
|
4056
|
+
padding-right: var(--w6w-sp-3);
|
|
4057
|
+
color: var(--w6w-muted);
|
|
4058
|
+
}
|
|
4059
|
+
|
|
4060
|
+
/* One resolved row's value. `anywhere` (not `break-word`) because these values
|
|
4061
|
+
are markup and URLs as often as prose: a single unbroken 40kB attribute
|
|
4062
|
+
string would otherwise force the whole modal to scroll sideways. Full-
|
|
4063
|
+
strength text color (not `--w6w-muted`) so it reads as the actual content,
|
|
4064
|
+
distinct from the label beside it. */
|
|
4065
|
+
.w6w-resolved-value {
|
|
4066
|
+
color: var(--w6w-text);
|
|
4067
|
+
overflow-wrap: anywhere;
|
|
4068
|
+
min-width: 0;
|
|
4069
|
+
}
|
|
4070
|
+
|
|
4071
|
+
/* The expanded form of a clipped value (`resolved-clip.ts`). A block with its
|
|
4072
|
+
own scroll, so "Show all" can never restore the unbounded inline paste that
|
|
4073
|
+
buried the other params and the run's result. */
|
|
4074
|
+
.w6w-resolved-text-full {
|
|
4075
|
+
display: block;
|
|
4076
|
+
margin: var(--w6w-sp-1) 0;
|
|
4077
|
+
max-height: 14em;
|
|
4078
|
+
overflow: auto;
|
|
4079
|
+
padding: var(--w6w-sp-2);
|
|
4080
|
+
background: var(--w6w-panel-2);
|
|
4081
|
+
border: 1px solid var(--w6w-border);
|
|
4082
|
+
border-radius: var(--w6w-radius);
|
|
4083
|
+
font-family: var(--w6w-font-mono);
|
|
4084
|
+
font-size: 0.85em; /* lint-tokens-allow: matches the sibling code-typography rules above in this same file */
|
|
4085
|
+
line-height: var(--w6w-lh-normal);
|
|
4086
|
+
white-space: pre-wrap;
|
|
4087
|
+
}
|
|
4088
|
+
|
|
4089
|
+
/* Link-weight toggle — this sits inside a value, so it must not read as a
|
|
4090
|
+
second action competing with the modal's own buttons. */
|
|
4091
|
+
.w6w-resolved-more {
|
|
4092
|
+
background: none;
|
|
4093
|
+
border: none;
|
|
4094
|
+
padding: 0;
|
|
4095
|
+
margin-left: var(--w6w-sp-2);
|
|
4096
|
+
color: var(--w6w-accent);
|
|
4097
|
+
font-size: 0.85em; /* lint-tokens-allow: matches the sibling code-typography rules above in this same file */
|
|
4098
|
+
cursor: pointer;
|
|
4099
|
+
white-space: nowrap;
|
|
4100
|
+
}
|
|
4101
|
+
|
|
4102
|
+
.w6w-resolved-more:hover {
|
|
4103
|
+
text-decoration: underline;
|
|
4104
|
+
}
|
|
4105
|
+
|
|
4106
|
+
.w6w-icon-button {
|
|
4107
|
+
display: inline-flex;
|
|
4108
|
+
align-items: center;
|
|
4109
|
+
justify-content: center;
|
|
4110
|
+
background: transparent;
|
|
4111
|
+
border: none;
|
|
4112
|
+
border-radius: 8px;
|
|
4113
|
+
padding: var(--w6w-sp-1-5);
|
|
4114
|
+
color: var(--w6w-muted);
|
|
4115
|
+
cursor: pointer;
|
|
4116
|
+
}
|
|
4117
|
+
|
|
4118
|
+
.w6w-icon-button:hover:not(:disabled) {
|
|
4119
|
+
background: var(--w6w-panel-2);
|
|
4120
|
+
color: var(--w6w-text);
|
|
4121
|
+
}
|
|
4122
|
+
|
|
4123
|
+
.w6w-icon-button-danger:hover:not(:disabled) {
|
|
4124
|
+
color: var(--w6w-danger);
|
|
4125
|
+
}
|
|
4126
|
+
|
|
4127
|
+
.w6w-icon-button:disabled {
|
|
4128
|
+
opacity: 0.4;
|
|
4129
|
+
cursor: default;
|
|
4130
|
+
}
|
|
4131
|
+
|
|
4132
|
+
.w6w-info-tip {
|
|
4133
|
+
display: inline-flex;
|
|
4134
|
+
flex-wrap: wrap;
|
|
4135
|
+
align-items: center;
|
|
4136
|
+
gap: var(--w6w-sp-1);
|
|
4137
|
+
}
|
|
4138
|
+
|
|
4139
|
+
.w6w-info-tip-body {
|
|
4140
|
+
flex-basis: 100%;
|
|
4141
|
+
}
|
|
4142
|
+
|
|
4143
|
+
/* The shared `Icon` (`src/components/Icon.tsx`).
|
|
4144
|
+
*
|
|
4145
|
+
* Only geometry invariants live here. The PAINT is per-entry in
|
|
4146
|
+
* `src/components/icons.tsx` (the set mixes filled Material-style glyphs with
|
|
4147
|
+
* stroked Feather ones, and the language marks paint their own elements), and
|
|
4148
|
+
* the SIZE comes from the `size` prop — so there is nothing about colour or
|
|
4149
|
+
* scale for this class to say. */
|
|
4150
|
+
.w6w-icon {
|
|
4151
|
+
/* Never squashed by a flex parent: a rail glyph squeezed to 9px is unreadable,
|
|
4152
|
+
and the sources draw at 14–20px inside rows that can be tight. */
|
|
4153
|
+
flex-shrink: 0;
|
|
4154
|
+
/* A glyph dropped into a line of text sits on the baseline by default, which
|
|
4155
|
+
reads as a foot below the words. */
|
|
4156
|
+
vertical-align: middle;
|
|
4157
|
+
}
|
|
4158
|
+
|
|
4159
|
+
.w6w-repo-sync {
|
|
4160
|
+
position: relative;
|
|
4161
|
+
display: inline-flex;
|
|
4162
|
+
}
|
|
4163
|
+
|
|
4164
|
+
.w6w-repo-sync-trigger {
|
|
4165
|
+
display: inline-flex;
|
|
4166
|
+
align-items: center;
|
|
4167
|
+
gap: var(--w6w-sp-2);
|
|
4168
|
+
padding: var(--w6w-sp-1-5) var(--w6w-sp-3);
|
|
4169
|
+
border: 1px solid var(--w6w-border);
|
|
4170
|
+
border-radius: 999px;
|
|
4171
|
+
background: var(--w6w-panel-2);
|
|
4172
|
+
color: var(--w6w-text);
|
|
4173
|
+
font-size: var(--w6w-fs-sm);
|
|
4174
|
+
cursor: pointer;
|
|
4175
|
+
}
|
|
4176
|
+
|
|
4177
|
+
.w6w-repo-sync-trigger:hover {
|
|
4178
|
+
border-color: var(--w6w-accent);
|
|
4179
|
+
}
|
|
4180
|
+
|
|
4181
|
+
.w6w-repo-sync-icon {
|
|
4182
|
+
position: relative;
|
|
4183
|
+
display: inline-flex;
|
|
4184
|
+
}
|
|
4185
|
+
|
|
4186
|
+
.w6w-repo-sync-spin {
|
|
4187
|
+
position: absolute;
|
|
4188
|
+
bottom: calc(-1 * var(--w6w-sp-0-5));
|
|
4189
|
+
right: calc(-1 * var(--w6w-sp-0-5));
|
|
4190
|
+
width: 10px;
|
|
4191
|
+
height: 10px;
|
|
4192
|
+
background: var(--w6w-panel-2);
|
|
4193
|
+
border-radius: 50%;
|
|
4194
|
+
animation: w6w-spin 0.8s linear infinite;
|
|
4195
|
+
}
|
|
4196
|
+
|
|
4197
|
+
@keyframes w6w-spin {
|
|
4198
|
+
to {
|
|
4199
|
+
transform: rotate(360deg);
|
|
4200
|
+
}
|
|
4201
|
+
}
|
|
4202
|
+
@media (prefers-reduced-motion: reduce) {
|
|
4203
|
+
.w6w-repo-sync-spin {
|
|
4204
|
+
animation: none;
|
|
4205
|
+
}
|
|
4206
|
+
}
|
|
4207
|
+
.w6w-repo-sync-branch {
|
|
4208
|
+
font-weight: var(--w6w-fw-medium);
|
|
4209
|
+
}
|
|
4210
|
+
|
|
4211
|
+
.w6w-repo-sync-sha {
|
|
4212
|
+
color: var(--w6w-muted);
|
|
4213
|
+
font-size: var(--w6w-fs-xs);
|
|
4214
|
+
font-family: var(--w6w-font-mono);
|
|
4215
|
+
}
|
|
4216
|
+
|
|
4217
|
+
.w6w-repo-sync-menu {
|
|
4218
|
+
position: absolute;
|
|
4219
|
+
top: calc(100% + var(--w6w-sp-1-5));
|
|
4220
|
+
right: 0;
|
|
4221
|
+
min-width: 220px;
|
|
4222
|
+
background: var(--w6w-panel);
|
|
4223
|
+
border: 1px solid var(--w6w-border);
|
|
4224
|
+
border-radius: var(--w6w-radius);
|
|
4225
|
+
padding: var(--w6w-sp-1-5);
|
|
4226
|
+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
|
|
4227
|
+
z-index: 30;
|
|
4228
|
+
display: flex;
|
|
4229
|
+
flex-direction: column;
|
|
4230
|
+
gap: var(--w6w-sp-0-5);
|
|
4231
|
+
}
|
|
4232
|
+
|
|
4233
|
+
.w6w-repo-sync-detail {
|
|
4234
|
+
display: flex;
|
|
4235
|
+
flex-direction: column;
|
|
4236
|
+
gap: var(--w6w-sp-0-5);
|
|
4237
|
+
padding: var(--w6w-sp-2) var(--w6w-sp-2-5);
|
|
4238
|
+
color: var(--w6w-muted);
|
|
4239
|
+
font-size: var(--w6w-fs-xs);
|
|
4240
|
+
}
|
|
4241
|
+
|
|
4242
|
+
.w6w-repo-sync-detail > :first-child {
|
|
4243
|
+
color: var(--w6w-text);
|
|
4244
|
+
font-size: var(--w6w-fs-sm);
|
|
4245
|
+
font-weight: var(--w6w-fw-medium);
|
|
4246
|
+
}
|
|
4247
|
+
|
|
4248
|
+
.w6w-repo-sync-item {
|
|
4249
|
+
display: flex;
|
|
4250
|
+
align-items: center;
|
|
4251
|
+
width: 100%;
|
|
4252
|
+
text-align: left;
|
|
4253
|
+
background: transparent;
|
|
4254
|
+
border: none;
|
|
4255
|
+
border-radius: 8px;
|
|
4256
|
+
padding: var(--w6w-sp-2) var(--w6w-sp-2-5);
|
|
4257
|
+
color: var(--w6w-text);
|
|
4258
|
+
font-size: var(--w6w-fs-sm);
|
|
4259
|
+
cursor: pointer;
|
|
4260
|
+
}
|
|
4261
|
+
|
|
4262
|
+
.w6w-repo-sync-item:hover:not(:disabled) {
|
|
4263
|
+
background: var(--w6w-panel-2);
|
|
4264
|
+
}
|
|
4265
|
+
|
|
4266
|
+
.w6w-repo-sync-item:disabled {
|
|
4267
|
+
cursor: default;
|
|
4268
|
+
opacity: 0.6;
|
|
4269
|
+
}
|
|
4270
|
+
|
|
4271
|
+
/* --- StepStatusPill ---------------------------------------------------- */
|
|
4272
|
+
/* Mirrors `.w6w-health-pill` shape for shape (see `_health.scss`), with its
|
|
4273
|
+
own five-state colour set behind `--w6w-step-color` — never a new global
|
|
4274
|
+
`--w6w-*` token, only the base palette (`--w6w-muted`/`--w6w-accent`/
|
|
4275
|
+
`--w6w-success`/`--w6w-danger`) this file is scoped to. */
|
|
4276
|
+
.w6w-step-pill {
|
|
4277
|
+
display: inline-flex;
|
|
4278
|
+
align-items: center;
|
|
4279
|
+
gap: var(--w6w-sp-1-5);
|
|
4280
|
+
padding: var(--w6w-sp-0-5) var(--w6w-sp-2) var(--w6w-sp-0-5) var(--w6w-sp-1-5);
|
|
4281
|
+
border: 1px solid color-mix(in srgb, var(--w6w-step-color) 40%, var(--w6w-border));
|
|
4282
|
+
border-radius: 999px;
|
|
4283
|
+
background: color-mix(in srgb, var(--w6w-step-color) 12%, transparent);
|
|
4284
|
+
color: var(--w6w-text);
|
|
4285
|
+
font-size: var(--w6w-fs-xs);
|
|
4286
|
+
line-height: var(--w6w-lh-normal);
|
|
4287
|
+
white-space: nowrap;
|
|
4288
|
+
--w6w-step-color: var(--w6w-muted);
|
|
4289
|
+
}
|
|
4290
|
+
|
|
4291
|
+
.w6w-step-pill-pending {
|
|
4292
|
+
--w6w-step-color: var(--w6w-muted);
|
|
4293
|
+
}
|
|
4294
|
+
|
|
4295
|
+
.w6w-step-pill-running {
|
|
4296
|
+
--w6w-step-color: var(--w6w-accent);
|
|
4297
|
+
}
|
|
4298
|
+
|
|
4299
|
+
.w6w-step-pill-succeeded {
|
|
4300
|
+
--w6w-step-color: var(--w6w-success);
|
|
4301
|
+
}
|
|
4302
|
+
|
|
4303
|
+
.w6w-step-pill-failed {
|
|
4304
|
+
--w6w-step-color: var(--w6w-danger);
|
|
4305
|
+
}
|
|
4306
|
+
|
|
4307
|
+
/* Same base colour as `pending` — a dashed border, not a second colour, is
|
|
4308
|
+
what keeps this distinct: colour alone is never the only signal, and this
|
|
4309
|
+
pill already carries a different text label too. */
|
|
4310
|
+
.w6w-step-pill-skipped {
|
|
4311
|
+
--w6w-step-color: var(--w6w-muted);
|
|
4312
|
+
border-style: dashed;
|
|
4313
|
+
}
|
|
4314
|
+
|
|
4315
|
+
/* The two RUN states (`ExecutionStatus`), both deliberately in the same muted
|
|
4316
|
+
family as `pending`/`skipped` above: neither is a verdict on the work —
|
|
4317
|
+
`queued` hasn't started and `canceled` stopped before reaching one — so
|
|
4318
|
+
neither earns `--w6w-success`/`--w6w-danger`/`--w6w-accent`, and this file
|
|
4319
|
+
keeps its stated scope (the base palette only, never a new global token).
|
|
4320
|
+
`canceled` takes `skipped`'s dashed border for the same reason that one
|
|
4321
|
+
does; the two never co-occur in one list (one is a step state, the other a
|
|
4322
|
+
run state), and the label carries the meaning regardless. */
|
|
4323
|
+
.w6w-step-pill-queued {
|
|
4324
|
+
--w6w-step-color: var(--w6w-muted);
|
|
4325
|
+
}
|
|
4326
|
+
|
|
4327
|
+
.w6w-step-pill-canceled {
|
|
4328
|
+
--w6w-step-color: var(--w6w-muted);
|
|
4329
|
+
border-style: dashed;
|
|
4330
|
+
}
|
|
4331
|
+
|
|
4332
|
+
.w6w-step-pill-dot {
|
|
4333
|
+
flex-shrink: 0;
|
|
4334
|
+
width: 8px;
|
|
4335
|
+
height: 8px;
|
|
4336
|
+
border-radius: 50%;
|
|
4337
|
+
background: var(--w6w-step-color);
|
|
4338
|
+
}
|
|
4339
|
+
|
|
4340
|
+
.w6w-step-pill-label {
|
|
4341
|
+
overflow: hidden;
|
|
4342
|
+
text-overflow: ellipsis;
|
|
4343
|
+
}
|
|
4344
|
+
|
|
4345
|
+
/* --- ExecutionLogPanel --------------------------------------------------- */
|
|
4346
|
+
/* A vertical ordered list, not `_history-timeline.scss`'s idiom: that
|
|
4347
|
+
partial lays out a fixed WINDOW of time-proportional lanes (`left`/`width`
|
|
4348
|
+
percentages against a shared axis) for a health-history strip, which has
|
|
4349
|
+
no notion of "one row per step" or of steps that haven't happened yet.
|
|
4350
|
+
This panel is a plain in-order list of a priori unbounded rows, closer in
|
|
4351
|
+
shape to `.w6w-resolved-table`'s row list — reused here as `.w6w-stack`
|
|
4352
|
+
(`_layout.scss`) for the two-block (input/output) stack inside a row,
|
|
4353
|
+
rather than inventing a second vertical-list treatment.
|
|
4354
|
+
|
|
4355
|
+
Each row's own box (border/background/border-radius/padding) comes from
|
|
4356
|
+
`.w6w-section` (`_sections.scss`), reused rather than duplicated here —
|
|
4357
|
+
`ApiCallsPanel.tsx`'s collapsed-by-default `<details>` idiom, applied to
|
|
4358
|
+
this panel's rows (REVIEW.md R-1). This file only adds the row-specific
|
|
4359
|
+
layout `.w6w-section` doesn't know about: the flex line for the summary's
|
|
4360
|
+
pill/label/timing. */
|
|
4361
|
+
/* The optional header row (T1.1.1 A4) — rendered only when the host supplies
|
|
4362
|
+
`onDismiss`, and in BOTH branches below, since the empty state is exactly
|
|
4363
|
+
where a dismiss control is needed most. Right-aligned, mirroring where
|
|
4364
|
+
studio's own `.notice-close` dismiss sits on a panel header; that class is
|
|
4365
|
+
studio-scoped CSS and does not exist in this package, so only the placement
|
|
4366
|
+
transfers, not the rule. */
|
|
4367
|
+
.w6w-execution-log-head {
|
|
4368
|
+
display: flex;
|
|
4369
|
+
justify-content: flex-end;
|
|
4370
|
+
align-items: center;
|
|
4371
|
+
gap: var(--w6w-sp-2);
|
|
4372
|
+
width: 100%;
|
|
4373
|
+
margin-bottom: var(--w6w-sp-2);
|
|
4374
|
+
}
|
|
4375
|
+
|
|
4376
|
+
.w6w-execution-log {
|
|
4377
|
+
display: flex;
|
|
4378
|
+
flex-direction: column;
|
|
4379
|
+
gap: var(--w6w-sp-3);
|
|
4380
|
+
list-style: none;
|
|
4381
|
+
margin: 0;
|
|
4382
|
+
padding: 0;
|
|
4383
|
+
width: 100%;
|
|
4384
|
+
}
|
|
4385
|
+
|
|
4386
|
+
/* `width: 100%` plus padding and a border overflows the parent under the
|
|
4387
|
+
default content-box sizing; this package has no global box-sizing reset, so
|
|
4388
|
+
it opts in per element (as `_chips.scss` and `_step-config.scss` do). */
|
|
4389
|
+
.w6w-execution-log-empty {
|
|
4390
|
+
box-sizing: border-box;
|
|
4391
|
+
width: 100%;
|
|
4392
|
+
padding: var(--w6w-sp-4);
|
|
4393
|
+
border: 1px dashed var(--w6w-border);
|
|
4394
|
+
border-radius: var(--w6w-radius);
|
|
4395
|
+
text-align: center;
|
|
4396
|
+
}
|
|
4397
|
+
|
|
4398
|
+
.w6w-execution-log-row {
|
|
4399
|
+
min-width: 0;
|
|
4400
|
+
}
|
|
4401
|
+
|
|
4402
|
+
.w6w-execution-log-row-header {
|
|
4403
|
+
display: flex;
|
|
4404
|
+
align-items: center;
|
|
4405
|
+
gap: var(--w6w-sp-2);
|
|
4406
|
+
flex-wrap: wrap;
|
|
4407
|
+
}
|
|
4408
|
+
|
|
4409
|
+
.w6w-execution-log-row-label {
|
|
4410
|
+
flex: 1 1 auto;
|
|
4411
|
+
min-width: 0;
|
|
4412
|
+
font-weight: var(--w6w-fw-medium);
|
|
4413
|
+
overflow: hidden;
|
|
4414
|
+
text-overflow: ellipsis;
|
|
4415
|
+
white-space: nowrap;
|
|
4416
|
+
}
|
|
4417
|
+
|
|
4418
|
+
/* Shrinkable, so a narrow row (the 360px docked panel) wraps the
|
|
4419
|
+
"<ts> → <ts> (elapsed)" text inside the row's box. With `flex-shrink: 0` it
|
|
4420
|
+
kept its max-content width, wrapped onto its own flex line, and ran past the
|
|
4421
|
+
row's border. */
|
|
4422
|
+
.w6w-execution-log-timing {
|
|
4423
|
+
flex: 0 1 auto;
|
|
4424
|
+
min-width: 0;
|
|
4425
|
+
color: var(--w6w-muted);
|
|
4426
|
+
font-size: var(--w6w-fs-xs);
|
|
4427
|
+
}
|
|
4428
|
+
|
|
4429
|
+
.w6w-execution-log-json {
|
|
4430
|
+
min-width: 0;
|
|
4431
|
+
}
|
|
4432
|
+
|
|
4433
|
+
/* Error blocks (step `error`, run `runError`/`stepErrors`). The box itself is
|
|
4434
|
+
`.w6w-result.w6w-error` (`_tester.scss`) — TriggerFillForm's StepError
|
|
4435
|
+
visual, reused, not restyled here; these rules only place it. */
|
|
4436
|
+
.w6w-execution-log-errors {
|
|
4437
|
+
width: 100%;
|
|
4438
|
+
margin-bottom: var(--w6w-sp-2);
|
|
4439
|
+
}
|
|
4440
|
+
|
|
4441
|
+
/* A step's error sits after its `.w6w-section` box, inside the same `<li>` —
|
|
4442
|
+
closer to its own row than the list's row gap, so it reads as that row's. */
|
|
4443
|
+
.w6w-execution-log-row > .w6w-error {
|
|
4444
|
+
margin-top: var(--w6w-sp-1-5);
|
|
4445
|
+
}
|
|
4446
|
+
|
|
4447
|
+
/* TriggerFillForm's inline `opacity: 0.75; marginBottom: 4` code line, as tokens. */
|
|
4448
|
+
.w6w-execution-log-error-code {
|
|
4449
|
+
opacity: 0.75;
|
|
4450
|
+
margin-bottom: var(--w6w-sp-1);
|
|
4451
|
+
}
|
|
4452
|
+
|
|
4453
|
+
.w6w-execution-log-error-label {
|
|
4454
|
+
display: block;
|
|
4455
|
+
margin-bottom: var(--w6w-sp-1);
|
|
4456
|
+
}
|
|
4457
|
+
|
|
4458
|
+
/* --- ExecutionList ------------------------------------------------------- */
|
|
4459
|
+
/* Rows of past executions: a click-to-select list plus a prev/next pager.
|
|
4460
|
+
Closer in shape to `.w6w-execution-log` (`_execution-log.scss`) than to
|
|
4461
|
+
`.w6w-history-*`: that family lays out a time-proportional strip against a
|
|
4462
|
+
shared axis, while this is a plain in-order list of one row per run. The row
|
|
4463
|
+
itself is `ListItem` (`.w6w-list-item`, `_lists.scss`) — reused whole, box,
|
|
4464
|
+
hover, focus ring, `active` highlight and all — so this partial only owns
|
|
4465
|
+
the LIST around the rows: the `ul` reset and the pager strip.
|
|
4466
|
+
|
|
4467
|
+
Spacing/type come from the scale tokens only (the `lint:tokens` ratchet has
|
|
4468
|
+
no baseline entry for this file, so anything literal here would be a new
|
|
4469
|
+
violation); colour stays on `_execution-log.scss`'s pill and the shared
|
|
4470
|
+
`.w6w-btn` classes. */
|
|
4471
|
+
.w6w-execution-list {
|
|
4472
|
+
display: flex;
|
|
4473
|
+
flex-direction: column;
|
|
4474
|
+
gap: var(--w6w-sp-3);
|
|
4475
|
+
width: 100%;
|
|
4476
|
+
min-width: 0;
|
|
4477
|
+
}
|
|
4478
|
+
|
|
4479
|
+
/* A `<ul>`, reset to a bare vertical stack — the marker/indent are the only
|
|
4480
|
+
things `_layout.scss`'s `.w6w-stack` doesn't already strip, and rows are
|
|
4481
|
+
`<li>` so the list is announced as a list, not a run of cards. */
|
|
4482
|
+
.w6w-execution-list-rows {
|
|
4483
|
+
display: flex;
|
|
4484
|
+
flex-direction: column;
|
|
4485
|
+
gap: var(--w6w-sp-1);
|
|
4486
|
+
list-style: none;
|
|
4487
|
+
margin: 0;
|
|
4488
|
+
padding: 0;
|
|
4489
|
+
width: 100%;
|
|
4490
|
+
min-width: 0;
|
|
4491
|
+
}
|
|
4492
|
+
|
|
4493
|
+
.w6w-execution-list-rows > li {
|
|
4494
|
+
min-width: 0;
|
|
4495
|
+
}
|
|
4496
|
+
|
|
4497
|
+
/* Both non-list branches (the loading and the empty `<p>`) hang straight off
|
|
4498
|
+
the root, so one direct-child rule covers them and neither needs a class the
|
|
4499
|
+
pinned markup doesn't have. Same dashed box `.w6w-execution-log-empty`
|
|
4500
|
+
uses — one treatment for "nothing here yet" across the run-log family. */
|
|
4501
|
+
.w6w-execution-list > p {
|
|
4502
|
+
width: 100%;
|
|
4503
|
+
margin: 0;
|
|
4504
|
+
padding: var(--w6w-sp-4);
|
|
4505
|
+
border: 1px dashed var(--w6w-border);
|
|
4506
|
+
border-radius: var(--w6w-radius);
|
|
4507
|
+
color: var(--w6w-muted);
|
|
4508
|
+
font-size: var(--w6w-fs-sm);
|
|
4509
|
+
text-align: center;
|
|
4510
|
+
}
|
|
4511
|
+
|
|
4512
|
+
.w6w-execution-list-pager {
|
|
4513
|
+
display: flex;
|
|
4514
|
+
align-items: center;
|
|
4515
|
+
justify-content: flex-end;
|
|
4516
|
+
gap: var(--w6w-sp-2);
|
|
4517
|
+
}
|
|
4518
|
+
|
|
4519
|
+
/* --- ExecutionFilters --------------------------------------------------- */
|
|
4520
|
+
/* One dense row of heterogeneous controls. The control chrome cannot come from
|
|
4521
|
+
`_fields.scss`: those rules are anchored on `.w6w-field` (a labelled,
|
|
4522
|
+
stacked field with a visible `<span>`), and these controls are labelled
|
|
4523
|
+
accessibly (`aria-label`) instead — a visible label per control would triple
|
|
4524
|
+
the bar's height. Tokens only, for the same reason as the rules above. */
|
|
4525
|
+
/* The row is width-driven: a wrapped line is formed from each control's
|
|
4526
|
+
*hypothetical* size, so six controls plus their gaps sit on one line for as
|
|
4527
|
+
long as they fit, and the row breaks by itself once they don't. That is the
|
|
4528
|
+
behaviour this bar needs — it renders full width in the studio History page
|
|
4529
|
+
and ~500px wide inside the detail modal — so the break follows THIS box
|
|
4530
|
+
rather than the viewport, and nothing here may key off a media query. */
|
|
4531
|
+
.w6w-execution-filters {
|
|
4532
|
+
display: flex;
|
|
4533
|
+
flex-wrap: wrap;
|
|
4534
|
+
align-items: center;
|
|
4535
|
+
gap: var(--w6w-sp-2);
|
|
4536
|
+
width: 100%;
|
|
4537
|
+
min-width: 0;
|
|
4538
|
+
}
|
|
4539
|
+
|
|
4540
|
+
/* These are bare form elements, so a host's own global `input`/`select` chrome
|
|
4541
|
+
lands on them too — and in the studio it is decisive: `studio/src/styles.css`
|
|
4542
|
+
gives `input[type="search"]`/`input[type="date"]` a `width: 100%` and a
|
|
4543
|
+
`margin-top`. A `width: 100%` on a flex item whose `flex-basis` is `auto` IS
|
|
4544
|
+
that item's basis, so each date picker asked for the whole bar and the row
|
|
4545
|
+
broke into one control per line, while the margin lifted the two inputs off
|
|
4546
|
+
the selects' line. Both are pinned back here; at (0,2,1) this selector beats
|
|
4547
|
+
a host's bare `input[type=…]` (0,1,1) and `input` (0,0,1) rules without
|
|
4548
|
+
needing `!important`, and a host that leaves the controls alone is unaffected
|
|
4549
|
+
because `width: auto`/`margin: 0` are what these controls want anyway. */
|
|
4550
|
+
.w6w-execution-filters input[type=search],
|
|
4551
|
+
.w6w-execution-filters input[type=date],
|
|
4552
|
+
.w6w-execution-filters select {
|
|
4553
|
+
background: var(--w6w-panel-2);
|
|
4554
|
+
border: 1px solid var(--w6w-border);
|
|
4555
|
+
border-radius: var(--w6w-radius);
|
|
4556
|
+
padding: var(--w6w-sp-2) var(--w6w-sp-2-5);
|
|
4557
|
+
margin: 0;
|
|
4558
|
+
width: auto;
|
|
4559
|
+
color: var(--w6w-text);
|
|
4560
|
+
font-size: var(--w6w-fs-sm);
|
|
4561
|
+
font-family: inherit;
|
|
4562
|
+
}
|
|
4563
|
+
|
|
4564
|
+
.w6w-execution-filters input[type=search]:focus-visible,
|
|
4565
|
+
.w6w-execution-filters input[type=date]:focus-visible,
|
|
4566
|
+
.w6w-execution-filters select:focus-visible {
|
|
4567
|
+
outline: 2px solid var(--w6w-accent);
|
|
4568
|
+
outline-offset: 1px;
|
|
4569
|
+
}
|
|
4570
|
+
|
|
4571
|
+
/* The dropdowns and the two date pickers show one short, fixed label, so they
|
|
4572
|
+
keep their intrinsic width and neither grow nor shrink: the row's spare width
|
|
4573
|
+
is the search box's alone. */
|
|
4574
|
+
.w6w-execution-filters select,
|
|
4575
|
+
.w6w-execution-filters input[type=date] {
|
|
4576
|
+
flex: 0 0 auto;
|
|
4577
|
+
}
|
|
4578
|
+
|
|
4579
|
+
/* The search box is the only control that flexes — it takes the spare width and
|
|
4580
|
+
gives it back down to a 160px floor, and that floor is what sets the row's
|
|
4581
|
+
breakpoint: 160px of search + the five intrinsic controls + five 8px gaps
|
|
4582
|
+
≈ 757px, so the bar is one row from the 760px the layout promises, and wraps
|
|
4583
|
+
below it. */
|
|
4584
|
+
.w6w-execution-filters-search {
|
|
4585
|
+
flex: 1 1 160px;
|
|
4586
|
+
min-width: 160px;
|
|
4587
|
+
}
|
|
4588
|
+
|
|
4589
|
+
/* Clear is a fixed-size control and stays at the end of the row. */
|
|
4590
|
+
.w6w-execution-filters-clear {
|
|
4591
|
+
flex: 0 0 auto;
|
|
4592
|
+
}
|
|
4593
|
+
|
|
4594
|
+
/* --- ExecutionStats ----------------------------------------------------- */
|
|
4595
|
+
/* The `DashboardPage.tsx` `StatCard` shape (big value, muted label) promoted
|
|
4596
|
+
out of the page and onto tokens — that page had the value's type ramp and
|
|
4597
|
+
weight inline, which is exactly what a shared component must not leave to
|
|
4598
|
+
its host. */
|
|
4599
|
+
.w6w-execution-stats {
|
|
4600
|
+
display: flex;
|
|
4601
|
+
flex-direction: column;
|
|
4602
|
+
gap: var(--w6w-sp-2);
|
|
4603
|
+
width: 100%;
|
|
4604
|
+
min-width: 0;
|
|
4605
|
+
}
|
|
4606
|
+
|
|
4607
|
+
.w6w-execution-stats-label {
|
|
4608
|
+
margin: 0;
|
|
4609
|
+
color: var(--w6w-muted);
|
|
4610
|
+
font-size: var(--w6w-fs-sm);
|
|
4611
|
+
}
|
|
4612
|
+
|
|
4613
|
+
.w6w-execution-stats-cards {
|
|
4614
|
+
display: flex;
|
|
4615
|
+
flex-wrap: wrap;
|
|
4616
|
+
gap: var(--w6w-sp-3);
|
|
4617
|
+
}
|
|
4618
|
+
|
|
4619
|
+
.w6w-execution-stat {
|
|
4620
|
+
display: flex;
|
|
4621
|
+
flex-direction: column;
|
|
4622
|
+
gap: var(--w6w-sp-0-5);
|
|
4623
|
+
flex: 1 1 140px;
|
|
4624
|
+
min-width: 0;
|
|
4625
|
+
padding: var(--w6w-sp-3);
|
|
4626
|
+
border: 1px solid var(--w6w-border);
|
|
4627
|
+
border-radius: var(--w6w-radius);
|
|
4628
|
+
background: var(--w6w-panel-2);
|
|
4629
|
+
}
|
|
4630
|
+
|
|
4631
|
+
.w6w-execution-stat-value {
|
|
4632
|
+
color: var(--w6w-text);
|
|
4633
|
+
font-size: var(--w6w-fs-3xl);
|
|
4634
|
+
font-weight: var(--w6w-fw-semibold);
|
|
4635
|
+
line-height: var(--w6w-lh-tight);
|
|
4636
|
+
}
|
|
4637
|
+
|
|
4638
|
+
.w6w-execution-stat-label {
|
|
4639
|
+
color: var(--w6w-muted);
|
|
4640
|
+
font-size: var(--w6w-fs-sm);
|
|
4641
|
+
}
|
|
4642
|
+
|
|
4643
|
+
/* --- ExecutionDetail ---------------------------------------------------- */
|
|
4644
|
+
.w6w-execution-detail {
|
|
4645
|
+
width: 100%;
|
|
4646
|
+
min-width: 0;
|
|
4647
|
+
}
|
|
4648
|
+
|
|
4649
|
+
/* Title block left, controls right; the actions keep their width, the name
|
|
4650
|
+
wraps or ellipses into whatever is left. */
|
|
4651
|
+
.w6w-execution-detail-head {
|
|
4652
|
+
display: flex;
|
|
4653
|
+
align-items: flex-start;
|
|
4654
|
+
justify-content: space-between;
|
|
4655
|
+
gap: var(--w6w-sp-3);
|
|
4656
|
+
}
|
|
4657
|
+
|
|
4658
|
+
.w6w-execution-detail-title {
|
|
4659
|
+
display: flex;
|
|
4660
|
+
flex-direction: column;
|
|
4661
|
+
gap: var(--w6w-sp-0-5);
|
|
4662
|
+
min-width: 0;
|
|
4663
|
+
}
|
|
4664
|
+
|
|
4665
|
+
.w6w-execution-detail-name {
|
|
4666
|
+
margin: 0;
|
|
4667
|
+
color: var(--w6w-text);
|
|
4668
|
+
font-size: var(--w6w-fs-lg);
|
|
4669
|
+
font-weight: var(--w6w-fw-semibold);
|
|
4670
|
+
overflow-wrap: anywhere;
|
|
4671
|
+
}
|
|
4672
|
+
|
|
4673
|
+
.w6w-execution-detail-meta {
|
|
4674
|
+
display: flex;
|
|
4675
|
+
align-items: center;
|
|
4676
|
+
gap: var(--w6w-sp-2);
|
|
4677
|
+
}
|
|
4678
|
+
|
|
4679
|
+
.w6w-execution-detail-actions {
|
|
4680
|
+
display: flex;
|
|
4681
|
+
align-items: center;
|
|
4682
|
+
gap: var(--w6w-sp-2);
|
|
4683
|
+
flex-shrink: 0;
|
|
4684
|
+
}
|
|
4685
|
+
|
|
4686
|
+
.w6w-execution-detail-id-line {
|
|
4687
|
+
margin: 0;
|
|
4688
|
+
}
|
|
4689
|
+
|
|
4690
|
+
.w6w-execution-detail-id {
|
|
4691
|
+
font-family: var(--w6w-font-mono);
|
|
4692
|
+
font-size: var(--w6w-fs-sm);
|
|
4693
|
+
color: var(--w6w-muted);
|
|
4694
|
+
overflow-wrap: anywhere;
|
|
4695
|
+
}
|
|
4696
|
+
|
|
4697
|
+
/* A `<dl>` whose pairs are `<div>`s, so the three facts row up side by side
|
|
4698
|
+
instead of stacking as three label/value paragraphs. */
|
|
4699
|
+
.w6w-execution-detail-timing {
|
|
4700
|
+
display: flex;
|
|
4701
|
+
flex-wrap: wrap;
|
|
4702
|
+
gap: var(--w6w-sp-5);
|
|
4703
|
+
margin: 0;
|
|
4704
|
+
}
|
|
4705
|
+
|
|
4706
|
+
.w6w-execution-detail-timing-item {
|
|
4707
|
+
display: flex;
|
|
4708
|
+
flex-direction: column;
|
|
4709
|
+
gap: var(--w6w-sp-0-5);
|
|
4710
|
+
min-width: 0;
|
|
4711
|
+
}
|
|
4712
|
+
|
|
4713
|
+
.w6w-execution-detail-timing-item dt {
|
|
4714
|
+
color: var(--w6w-muted);
|
|
4715
|
+
font-size: var(--w6w-fs-xs);
|
|
4716
|
+
}
|
|
4717
|
+
|
|
4718
|
+
.w6w-execution-detail-timing-item dd {
|
|
4719
|
+
margin: 0;
|
|
4720
|
+
color: var(--w6w-text);
|
|
4721
|
+
font-size: var(--w6w-fs-sm);
|
|
4722
|
+
}
|
|
4723
|
+
|
|
4724
|
+
/* The view-level failure notice: the same danger token `.w6w-btn-danger` and
|
|
4725
|
+
the health pills use, tinted rather than filled so it reads as a notice and
|
|
4726
|
+
not as a button. */
|
|
4727
|
+
.w6w-execution-detail-error-message {
|
|
4728
|
+
margin: 0;
|
|
4729
|
+
padding: var(--w6w-sp-2) var(--w6w-sp-3);
|
|
4730
|
+
border: 1px solid var(--w6w-danger);
|
|
4731
|
+
border-radius: var(--w6w-radius);
|
|
4732
|
+
background: color-mix(in srgb, var(--w6w-danger) 10%, transparent);
|
|
4733
|
+
color: var(--w6w-danger);
|
|
4734
|
+
font-size: var(--w6w-fs-sm);
|
|
4735
|
+
}
|
|
4736
|
+
|
|
4737
|
+
/*
|
|
4738
|
+
* Server resources — the four presentational variants from
|
|
4739
|
+
* `src/components/ServerResources.tsx` (card, small card, rail, badge).
|
|
4740
|
+
*
|
|
4741
|
+
* Spacing and type come from the `--w6w-sp-*` / `--w6w-fs-*` ramps only, so a
|
|
4742
|
+
* host that re-tunes the scale re-tunes these too; box geometry (heights,
|
|
4743
|
+
* track widths, radii) is deliberately literal, as everywhere else in this
|
|
4744
|
+
* package. The only colour that is not a themed token reference is the
|
|
4745
|
+
* sparkline stroke, which is `--w6w-accent` in both modes.
|
|
4746
|
+
*
|
|
4747
|
+
* The rail variant is the size-sensitive one: it lands in a ~200 px sidebar
|
|
4748
|
+
* column, so every part of it is `min-width: 0`-safe and the sparkline is
|
|
4749
|
+
* scaled by `preserveAspectRatio="none"` rather than given an intrinsic width.
|
|
4750
|
+
*/
|
|
4751
|
+
.w6w-server-resources {
|
|
4752
|
+
display: flex;
|
|
4753
|
+
flex-direction: column;
|
|
4754
|
+
gap: var(--w6w-sp-2);
|
|
4755
|
+
min-width: 0;
|
|
4756
|
+
color: var(--w6w-text);
|
|
4757
|
+
font-size: var(--w6w-fs-sm);
|
|
4758
|
+
line-height: var(--w6w-lh-normal);
|
|
4759
|
+
}
|
|
4760
|
+
|
|
4761
|
+
.w6w-server-resources__title {
|
|
4762
|
+
margin: 0;
|
|
4763
|
+
font-size: var(--w6w-fs-base);
|
|
4764
|
+
font-weight: var(--w6w-fw-semibold);
|
|
4765
|
+
line-height: var(--w6w-lh-tight);
|
|
4766
|
+
}
|
|
4767
|
+
|
|
4768
|
+
.w6w-server-resources__rows {
|
|
4769
|
+
display: flex;
|
|
4770
|
+
flex-direction: column;
|
|
4771
|
+
gap: var(--w6w-sp-2);
|
|
4772
|
+
margin: 0;
|
|
4773
|
+
padding: 0;
|
|
4774
|
+
list-style: none;
|
|
4775
|
+
}
|
|
4776
|
+
|
|
4777
|
+
.w6w-server-resources__row {
|
|
4778
|
+
display: grid;
|
|
4779
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
4780
|
+
align-items: baseline;
|
|
4781
|
+
gap: var(--w6w-sp-1) var(--w6w-sp-2);
|
|
4782
|
+
}
|
|
4783
|
+
|
|
4784
|
+
.w6w-server-resources__label {
|
|
4785
|
+
color: var(--w6w-muted);
|
|
4786
|
+
font-size: var(--w6w-fs-xs);
|
|
4787
|
+
letter-spacing: 0.04em;
|
|
4788
|
+
text-transform: uppercase;
|
|
4789
|
+
}
|
|
4790
|
+
|
|
4791
|
+
.w6w-server-resources__value {
|
|
4792
|
+
font-family: var(--w6w-font-mono);
|
|
4793
|
+
font-size: var(--w6w-fs-sm);
|
|
4794
|
+
font-variant-numeric: tabular-nums;
|
|
4795
|
+
}
|
|
4796
|
+
|
|
4797
|
+
/* The line itself. `stroke` is repeated as a property (not only as the
|
|
4798
|
+
polyline's presentation attribute) so a host stylesheet can re-colour it
|
|
4799
|
+
without reaching into the SVG. */
|
|
4800
|
+
.w6w-server-resources__spark {
|
|
4801
|
+
grid-column: 1/-1;
|
|
4802
|
+
display: block;
|
|
4803
|
+
width: 100%;
|
|
4804
|
+
height: 28px;
|
|
4805
|
+
stroke: var(--w6w-accent);
|
|
4806
|
+
stroke-width: 2;
|
|
4807
|
+
stroke-linejoin: round;
|
|
4808
|
+
stroke-linecap: round;
|
|
4809
|
+
overflow: visible;
|
|
4810
|
+
}
|
|
4811
|
+
|
|
4812
|
+
.w6w-server-resources__meta {
|
|
4813
|
+
margin: 0;
|
|
4814
|
+
color: var(--w6w-muted);
|
|
4815
|
+
font-family: var(--w6w-font-mono);
|
|
4816
|
+
font-size: var(--w6w-fs-xs);
|
|
4817
|
+
}
|
|
4818
|
+
|
|
4819
|
+
/* --- card ---------------------------------------------------------------- */
|
|
4820
|
+
.w6w-server-resources--card {
|
|
4821
|
+
gap: var(--w6w-sp-3);
|
|
4822
|
+
padding: var(--w6w-sp-4);
|
|
4823
|
+
border: 1px solid var(--w6w-border);
|
|
4824
|
+
border-radius: var(--w6w-radius);
|
|
4825
|
+
background: var(--w6w-panel);
|
|
4826
|
+
}
|
|
4827
|
+
|
|
4828
|
+
/* --- small card ---------------------------------------------------------- */
|
|
4829
|
+
.w6w-server-resources--small {
|
|
4830
|
+
gap: var(--w6w-sp-1-5);
|
|
4831
|
+
padding: var(--w6w-sp-3);
|
|
4832
|
+
border: 1px solid var(--w6w-border);
|
|
4833
|
+
border-radius: var(--w6w-radius);
|
|
4834
|
+
background: var(--w6w-panel);
|
|
4835
|
+
}
|
|
4836
|
+
|
|
4837
|
+
.w6w-server-resources--small .w6w-server-resources__title {
|
|
4838
|
+
font-size: var(--w6w-fs-sm);
|
|
4839
|
+
}
|
|
4840
|
+
|
|
4841
|
+
/* --- rail ---------------------------------------------------------------- */
|
|
4842
|
+
.w6w-server-resources--rail {
|
|
4843
|
+
gap: var(--w6w-sp-1);
|
|
4844
|
+
padding: var(--w6w-sp-2);
|
|
4845
|
+
border: 1px solid var(--w6w-border);
|
|
4846
|
+
border-radius: var(--w6w-radius);
|
|
4847
|
+
background: var(--w6w-panel);
|
|
4848
|
+
}
|
|
4849
|
+
|
|
4850
|
+
.w6w-server-resources__rail-row {
|
|
4851
|
+
display: grid;
|
|
4852
|
+
grid-template-columns: auto minmax(0, 1fr);
|
|
4853
|
+
align-items: baseline;
|
|
4854
|
+
gap: 0 var(--w6w-sp-2);
|
|
4855
|
+
}
|
|
4856
|
+
|
|
4857
|
+
.w6w-server-resources__rail-row .w6w-server-resources__value {
|
|
4858
|
+
text-align: right;
|
|
4859
|
+
}
|
|
4860
|
+
|
|
4861
|
+
.w6w-server-resources__rail-row .w6w-server-resources__spark {
|
|
4862
|
+
height: 20px;
|
|
4863
|
+
}
|
|
4864
|
+
|
|
4865
|
+
.w6w-server-resources__expand {
|
|
4866
|
+
width: 100%;
|
|
4867
|
+
padding: var(--w6w-sp-1) var(--w6w-sp-2);
|
|
4868
|
+
border: 1px solid var(--w6w-border);
|
|
4869
|
+
border-radius: var(--w6w-radius);
|
|
4870
|
+
background: var(--w6w-panel-2);
|
|
4871
|
+
color: var(--w6w-muted);
|
|
4872
|
+
font-family: inherit;
|
|
4873
|
+
font-size: var(--w6w-fs-xs);
|
|
4874
|
+
cursor: pointer;
|
|
4875
|
+
}
|
|
4876
|
+
|
|
4877
|
+
.w6w-server-resources__expand:hover {
|
|
4878
|
+
color: var(--w6w-text);
|
|
4879
|
+
border-color: var(--w6w-accent);
|
|
4880
|
+
}
|
|
4881
|
+
|
|
4882
|
+
/* --- badge --------------------------------------------------------------- */
|
|
4883
|
+
.w6w-server-resources--badge {
|
|
4884
|
+
flex-direction: row;
|
|
4885
|
+
gap: var(--w6w-sp-2);
|
|
4886
|
+
align-items: center;
|
|
4887
|
+
padding: 0 var(--w6w-sp-2);
|
|
4888
|
+
border: 1px solid var(--w6w-border);
|
|
4889
|
+
border-radius: 999px;
|
|
4890
|
+
background: var(--w6w-panel-2);
|
|
4891
|
+
font-family: var(--w6w-font-mono);
|
|
4892
|
+
font-size: var(--w6w-fs-xs);
|
|
4893
|
+
white-space: nowrap;
|
|
4894
|
+
}
|