cadcode 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +22 -10
- package/client/favicon.svg +17 -0
- package/client/index.html +48 -35
- package/client/render-worker.js +333 -0
- package/client/scene.js +166 -0
- package/client/viewer.css +421 -112
- package/client/viewer.js +127 -159
- package/package.json +9 -3
- package/src/core/evaluate.js +59 -0
- package/src/core/program.js +4 -44
- package/src/dev/server.js +8 -3
- package/src/dev/worker.js +4 -1
- package/src/export/stl.js +9 -7
package/client/viewer.css
CHANGED
|
@@ -1,14 +1,30 @@
|
|
|
1
|
+
/* The dev viewer as the playground's photo studio, without the code sheet: the model
|
|
2
|
+
stands on a soft, seamless backdrop that fills the window, and the controls float
|
|
3
|
+
on it in small groups, one per corner. Top left says what is on screen (the file,
|
|
4
|
+
the part), top right takes it away (PNG, STL), bottom left measures it, bottom
|
|
5
|
+
right changes how it is drawn. One accent, filament yellow, for the primary action
|
|
6
|
+
and the current selection; red only for faults. */
|
|
1
7
|
:root {
|
|
2
|
-
--
|
|
3
|
-
--
|
|
4
|
-
--
|
|
5
|
-
--
|
|
6
|
-
--
|
|
7
|
-
--
|
|
8
|
-
--
|
|
9
|
-
--
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
--stage-light: #ffffff;
|
|
9
|
+
--stage-mid: #f2f3f5;
|
|
10
|
+
--stage-edge: #e2e5e9;
|
|
11
|
+
--ink: #1f2833;
|
|
12
|
+
--ink-soft: #77818d;
|
|
13
|
+
--glass: rgba(255, 255, 255, 0.72);
|
|
14
|
+
--hairline: rgba(31, 40, 51, 0.08);
|
|
15
|
+
--lift: 0 1px 2px rgba(31, 40, 51, 0.06), 0 8px 24px -8px rgba(31, 40, 51, 0.14);
|
|
16
|
+
--pop: 0 2px 6px rgba(31, 40, 51, 0.06), 0 18px 48px -12px rgba(31, 40, 51, 0.28);
|
|
17
|
+
--filament: #f2c14e;
|
|
18
|
+
--filament-deep: #dcaa2c;
|
|
19
|
+
--selected: #fdf6e3;
|
|
20
|
+
--fault: #c2412d;
|
|
21
|
+
--ok: #3f9a62;
|
|
22
|
+
--gap: 20px;
|
|
23
|
+
--ui: 'Instrument Sans', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
|
|
24
|
+
--mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;
|
|
25
|
+
font: 14px/1.45 var(--ui);
|
|
26
|
+
color: var(--ink);
|
|
27
|
+
accent-color: var(--ink);
|
|
12
28
|
}
|
|
13
29
|
|
|
14
30
|
* {
|
|
@@ -20,123 +36,241 @@ body {
|
|
|
20
36
|
margin: 0;
|
|
21
37
|
height: 100%;
|
|
22
38
|
overflow: hidden;
|
|
23
|
-
background: var(--
|
|
39
|
+
background: var(--stage-mid);
|
|
24
40
|
}
|
|
25
41
|
|
|
26
|
-
|
|
42
|
+
[hidden] {
|
|
43
|
+
display: none !important;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
:focus-visible {
|
|
47
|
+
outline: 2px solid var(--ink);
|
|
48
|
+
outline-offset: 2px;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
button {
|
|
52
|
+
font: inherit;
|
|
53
|
+
color: inherit;
|
|
54
|
+
cursor: pointer;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
button:disabled {
|
|
58
|
+
cursor: progress;
|
|
59
|
+
opacity: 0.5;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
p {
|
|
63
|
+
margin: 0;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* --- Stage ------------------------------------------------------------------ */
|
|
67
|
+
|
|
68
|
+
/* The canvas is transparent; the backdrop is a light sweep, brightest where the
|
|
69
|
+
model stands, a little above the middle. */
|
|
70
|
+
.stage {
|
|
27
71
|
position: fixed;
|
|
28
72
|
inset: 0;
|
|
73
|
+
background: radial-gradient(ellipse 70% 80% at 50% 42%, var(--stage-light) 0%, var(--stage-mid) 55%, var(--stage-edge) 100%);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
#view {
|
|
77
|
+
position: absolute;
|
|
78
|
+
inset: 0;
|
|
29
79
|
width: 100%;
|
|
30
80
|
height: 100%;
|
|
31
81
|
display: block;
|
|
82
|
+
transition: opacity 0.25s ease, filter 0.25s ease;
|
|
32
83
|
}
|
|
33
84
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
top: 12px;
|
|
38
|
-
left: 12px;
|
|
39
|
-
right: 12px;
|
|
85
|
+
.corner {
|
|
86
|
+
position: absolute;
|
|
87
|
+
z-index: 2;
|
|
40
88
|
display: flex;
|
|
41
|
-
|
|
89
|
+
align-items: center;
|
|
90
|
+
gap: 10px;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.top-left {
|
|
94
|
+
top: var(--gap);
|
|
95
|
+
left: var(--gap);
|
|
96
|
+
/* Leaves room for the export pills; a long path gives way first. */
|
|
97
|
+
right: calc(var(--gap) + 260px);
|
|
98
|
+
pointer-events: none;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.top-left > * {
|
|
102
|
+
pointer-events: auto;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.top-right {
|
|
106
|
+
top: var(--gap);
|
|
107
|
+
right: var(--gap);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.bottom-left {
|
|
111
|
+
left: var(--gap);
|
|
112
|
+
bottom: var(--gap);
|
|
113
|
+
right: calc(var(--gap) + 240px);
|
|
114
|
+
flex-direction: column;
|
|
42
115
|
align-items: flex-start;
|
|
43
|
-
gap:
|
|
116
|
+
gap: 14px;
|
|
44
117
|
pointer-events: none;
|
|
45
118
|
}
|
|
46
119
|
|
|
47
|
-
.
|
|
120
|
+
.bottom-left > * {
|
|
48
121
|
pointer-events: auto;
|
|
49
122
|
}
|
|
50
123
|
|
|
51
|
-
.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
124
|
+
.bottom-right {
|
|
125
|
+
right: var(--gap);
|
|
126
|
+
bottom: var(--gap);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/* --- Floating controls -------------------------------------------------------- */
|
|
130
|
+
|
|
131
|
+
.brand {
|
|
132
|
+
flex-shrink: 0;
|
|
133
|
+
display: inline-flex;
|
|
55
134
|
align-items: center;
|
|
56
|
-
gap:
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
border-radius: 10px;
|
|
62
|
-
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.06);
|
|
135
|
+
gap: 9px;
|
|
136
|
+
margin-right: 8px;
|
|
137
|
+
font-weight: 600;
|
|
138
|
+
font-size: 17px;
|
|
139
|
+
letter-spacing: -0.01em;
|
|
63
140
|
}
|
|
64
141
|
|
|
65
|
-
.
|
|
142
|
+
.pill {
|
|
66
143
|
flex-shrink: 0;
|
|
144
|
+
display: inline-flex;
|
|
145
|
+
align-items: center;
|
|
146
|
+
gap: 8px;
|
|
147
|
+
height: 36px;
|
|
148
|
+
padding: 0 14px;
|
|
149
|
+
background: var(--glass);
|
|
150
|
+
-webkit-backdrop-filter: blur(12px) saturate(1.4);
|
|
151
|
+
backdrop-filter: blur(12px) saturate(1.4);
|
|
152
|
+
border: 1px solid var(--hairline);
|
|
153
|
+
border-radius: 999px;
|
|
154
|
+
box-shadow: var(--lift);
|
|
155
|
+
font-weight: 500;
|
|
156
|
+
white-space: nowrap;
|
|
157
|
+
transition: background 0.15s ease;
|
|
67
158
|
}
|
|
68
159
|
|
|
69
|
-
.
|
|
70
|
-
|
|
71
|
-
|
|
160
|
+
button.pill:hover {
|
|
161
|
+
background: #fff;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.pill.primary {
|
|
165
|
+
background: var(--filament);
|
|
166
|
+
border-color: var(--filament-deep);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.pill.primary:hover {
|
|
170
|
+
background: var(--filament-deep);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.pill[aria-pressed='true'] {
|
|
174
|
+
background: var(--ink);
|
|
175
|
+
border-color: var(--ink);
|
|
176
|
+
color: #fff;
|
|
72
177
|
}
|
|
73
178
|
|
|
179
|
+
.pill[aria-pressed='true']:hover {
|
|
180
|
+
background: var(--ink);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.pill.round {
|
|
184
|
+
justify-content: center;
|
|
185
|
+
width: 40px;
|
|
186
|
+
height: 40px;
|
|
187
|
+
padding: 0;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/* The program being watched: its folder quietly, its name plainly. A long path
|
|
191
|
+
gives up its folder first; the name always stays. */
|
|
74
192
|
.file {
|
|
75
|
-
|
|
193
|
+
flex-shrink: 1;
|
|
76
194
|
min-width: 0;
|
|
77
|
-
|
|
78
|
-
font-family:
|
|
79
|
-
font-size:
|
|
80
|
-
|
|
195
|
+
gap: 0;
|
|
196
|
+
font-family: var(--mono);
|
|
197
|
+
font-size: 12.5px;
|
|
198
|
+
font-weight: 400;
|
|
199
|
+
overflow: hidden;
|
|
81
200
|
}
|
|
82
201
|
|
|
83
|
-
/* A long path gives up its directory first; the file name always stays. */
|
|
84
202
|
.file .dir {
|
|
85
203
|
min-width: 0;
|
|
86
204
|
overflow: hidden;
|
|
87
205
|
text-overflow: ellipsis;
|
|
206
|
+
color: var(--ink-soft);
|
|
88
207
|
}
|
|
89
208
|
|
|
90
209
|
.file .name {
|
|
91
210
|
flex-shrink: 0;
|
|
211
|
+
font-weight: 500;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.field {
|
|
215
|
+
color: var(--ink-soft);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.field strong {
|
|
219
|
+
font-weight: 600;
|
|
220
|
+
color: var(--ink);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.field svg {
|
|
224
|
+
margin-left: -2px;
|
|
92
225
|
}
|
|
93
226
|
|
|
94
|
-
.
|
|
227
|
+
.tools {
|
|
95
228
|
display: flex;
|
|
96
|
-
|
|
97
|
-
gap: 6px;
|
|
98
|
-
color: var(--muted);
|
|
229
|
+
gap: 8px;
|
|
99
230
|
}
|
|
100
231
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
232
|
+
/* --- The readout: the model's size, set large ----------------------------------- */
|
|
233
|
+
|
|
234
|
+
.readout .size {
|
|
235
|
+
font-size: clamp(28px, 3.4vw, 44px);
|
|
236
|
+
font-weight: 400;
|
|
237
|
+
line-height: 1.05;
|
|
238
|
+
letter-spacing: -0.03em;
|
|
239
|
+
font-variant-numeric: tabular-nums;
|
|
109
240
|
}
|
|
110
241
|
|
|
111
|
-
|
|
112
|
-
|
|
242
|
+
.readout .size small {
|
|
243
|
+
margin-left: 0.2em;
|
|
244
|
+
font-size: 0.42em;
|
|
245
|
+
letter-spacing: 0;
|
|
246
|
+
color: var(--ink-soft);
|
|
113
247
|
}
|
|
114
248
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
249
|
+
.readout .meta {
|
|
250
|
+
display: flex;
|
|
251
|
+
flex-wrap: wrap;
|
|
252
|
+
column-gap: 16px;
|
|
253
|
+
margin-top: 8px;
|
|
254
|
+
color: var(--ink-soft);
|
|
255
|
+
font-variant-numeric: tabular-nums;
|
|
118
256
|
}
|
|
119
257
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
border-color: rgba(20, 30, 40, 0.28);
|
|
258
|
+
.readout .meta span:empty {
|
|
259
|
+
display: none;
|
|
123
260
|
}
|
|
124
261
|
|
|
125
262
|
.status {
|
|
126
263
|
display: inline-flex;
|
|
127
264
|
align-items: center;
|
|
128
|
-
gap:
|
|
129
|
-
color: var(--muted);
|
|
130
|
-
white-space: nowrap;
|
|
131
|
-
font-variant-numeric: tabular-nums;
|
|
265
|
+
gap: 7px;
|
|
132
266
|
}
|
|
133
267
|
|
|
134
268
|
.status::before {
|
|
135
269
|
content: '';
|
|
136
|
-
width:
|
|
137
|
-
height:
|
|
270
|
+
width: 7px;
|
|
271
|
+
height: 7px;
|
|
138
272
|
border-radius: 50%;
|
|
139
|
-
background: var(--
|
|
273
|
+
background: var(--ink-soft);
|
|
140
274
|
}
|
|
141
275
|
|
|
142
276
|
.status[data-state='ready']::before {
|
|
@@ -145,77 +279,252 @@ select:hover {
|
|
|
145
279
|
|
|
146
280
|
.status[data-state='building']::before,
|
|
147
281
|
.status[data-state='evaluating']::before {
|
|
148
|
-
background: var(--
|
|
282
|
+
background: var(--filament-deep);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.status[data-state='error'],
|
|
286
|
+
.status[data-state='disconnected'] {
|
|
287
|
+
color: var(--fault);
|
|
288
|
+
font-weight: 500;
|
|
149
289
|
}
|
|
150
290
|
|
|
151
291
|
.status[data-state='error']::before,
|
|
152
292
|
.status[data-state='disconnected']::before {
|
|
153
|
-
background: var(--
|
|
293
|
+
background: var(--fault);
|
|
154
294
|
}
|
|
155
295
|
|
|
156
|
-
.
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
bottom: 40px;
|
|
161
|
-
max-height: 45vh;
|
|
162
|
-
overflow: auto;
|
|
163
|
-
background: #fff6f5;
|
|
164
|
-
border: 1px solid rgba(200, 55, 45, 0.35);
|
|
165
|
-
border-left: 4px solid var(--bad);
|
|
166
|
-
border-radius: 8px;
|
|
167
|
-
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
|
|
296
|
+
.hint {
|
|
297
|
+
font-size: 12.5px;
|
|
298
|
+
color: var(--ink-soft);
|
|
299
|
+
pointer-events: none !important;
|
|
168
300
|
}
|
|
169
301
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
302
|
+
/* --- Cards: logs and errors ----------------------------------------------------- */
|
|
303
|
+
|
|
304
|
+
.card {
|
|
305
|
+
background: rgba(255, 255, 255, 0.9);
|
|
306
|
+
-webkit-backdrop-filter: blur(12px);
|
|
307
|
+
backdrop-filter: blur(12px);
|
|
308
|
+
border: 1px solid var(--hairline);
|
|
309
|
+
border-radius: 14px;
|
|
310
|
+
box-shadow: var(--lift);
|
|
176
311
|
}
|
|
177
312
|
|
|
313
|
+
/* The program's console output, hanging under the file it came from. */
|
|
178
314
|
.logs {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
315
|
+
position: absolute;
|
|
316
|
+
z-index: 2;
|
|
317
|
+
top: calc(var(--gap) + 56px);
|
|
318
|
+
left: var(--gap);
|
|
319
|
+
max-width: min(480px, calc(100% - 2 * var(--gap)));
|
|
320
|
+
max-height: 35%;
|
|
183
321
|
overflow: auto;
|
|
184
|
-
padding:
|
|
185
|
-
|
|
186
|
-
border: 1px solid var(--border);
|
|
187
|
-
border-radius: 10px;
|
|
188
|
-
font: 12px/1.5 ui-monospace, 'SF Mono', Menlo, monospace;
|
|
322
|
+
padding: 10px 14px;
|
|
323
|
+
font: 12px/1.55 var(--mono);
|
|
189
324
|
white-space: pre-wrap;
|
|
190
325
|
}
|
|
191
326
|
|
|
192
327
|
.logs .log-warn {
|
|
193
|
-
color:
|
|
328
|
+
color: #a8730b;
|
|
194
329
|
}
|
|
195
330
|
|
|
196
331
|
.logs .log-error {
|
|
197
|
-
color: var(--
|
|
332
|
+
color: var(--fault);
|
|
198
333
|
}
|
|
199
334
|
|
|
200
|
-
.
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
335
|
+
.error {
|
|
336
|
+
max-width: min(720px, 100%);
|
|
337
|
+
max-height: 42vh;
|
|
338
|
+
overflow: auto;
|
|
339
|
+
border-left: 3px solid var(--fault);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.error pre {
|
|
343
|
+
margin: 0;
|
|
344
|
+
padding: 12px 16px;
|
|
345
|
+
font: 12.5px/1.55 var(--mono);
|
|
346
|
+
white-space: pre-wrap;
|
|
347
|
+
color: #8a2a1c;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/* --- Busy ------------------------------------------------------------------------ */
|
|
351
|
+
/* While the program rebuilds: a line runs along the top and the model on screen
|
|
352
|
+
steps back. With no model yet, a line of text in the middle instead. Both wait a
|
|
353
|
+
moment, so a quick rebuild does not flicker. A lost connection steps the model
|
|
354
|
+
back the same way, without the running line. */
|
|
355
|
+
|
|
356
|
+
.progress {
|
|
357
|
+
position: absolute;
|
|
358
|
+
z-index: 3;
|
|
359
|
+
top: 0;
|
|
360
|
+
left: 0;
|
|
361
|
+
right: 0;
|
|
362
|
+
height: 2px;
|
|
363
|
+
overflow: hidden;
|
|
364
|
+
opacity: 0;
|
|
365
|
+
transition: opacity 0.2s ease;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
.progress::before {
|
|
369
|
+
content: '';
|
|
370
|
+
position: absolute;
|
|
371
|
+
inset: 0 auto 0 0;
|
|
372
|
+
width: 35%;
|
|
373
|
+
background: linear-gradient(90deg, transparent, var(--filament-deep), transparent);
|
|
374
|
+
animation: run 1.1s ease-in-out infinite;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
@keyframes run {
|
|
378
|
+
from {
|
|
379
|
+
translate: -100% 0;
|
|
380
|
+
}
|
|
381
|
+
to {
|
|
382
|
+
translate: 300% 0;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
.empty {
|
|
387
|
+
position: absolute;
|
|
388
|
+
top: 50%;
|
|
389
|
+
left: 50%;
|
|
390
|
+
translate: -50% -50%;
|
|
391
|
+
color: var(--ink-soft);
|
|
392
|
+
font-size: 15px;
|
|
393
|
+
opacity: 0;
|
|
206
394
|
pointer-events: none;
|
|
395
|
+
transition: opacity 0.2s ease;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
.stage[data-busy] .progress {
|
|
399
|
+
opacity: 1;
|
|
400
|
+
transition-delay: 0.15s;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.stage[data-busy] #view,
|
|
404
|
+
.stage[data-offline] #view {
|
|
405
|
+
opacity: 0.45;
|
|
406
|
+
filter: saturate(0.4);
|
|
407
|
+
transition-delay: 0.15s;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
.stage[data-empty]:is([data-busy], [data-offline]) .empty {
|
|
411
|
+
opacity: 1;
|
|
412
|
+
transition-delay: 0.15s;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/* --- Part menu ------------------------------------------------------------------ */
|
|
416
|
+
/* A list of the program's parts hanging under the Part pill. */
|
|
417
|
+
|
|
418
|
+
.menu {
|
|
419
|
+
position: fixed;
|
|
420
|
+
inset: auto;
|
|
421
|
+
min-width: 180px;
|
|
422
|
+
max-height: min(420px, calc(100dvh - 84px));
|
|
423
|
+
margin: 0;
|
|
424
|
+
padding: 6px;
|
|
425
|
+
display: none;
|
|
426
|
+
flex-direction: column;
|
|
427
|
+
gap: 2px;
|
|
428
|
+
overflow-y: auto;
|
|
429
|
+
background: #fff;
|
|
430
|
+
color: var(--ink);
|
|
431
|
+
border: 1px solid var(--hairline);
|
|
432
|
+
border-radius: 14px;
|
|
433
|
+
box-shadow: var(--pop);
|
|
434
|
+
transform-origin: 24px 0;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
.menu:popover-open {
|
|
438
|
+
display: flex;
|
|
439
|
+
animation: drop 0.14s ease-out;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
@keyframes drop {
|
|
443
|
+
from {
|
|
444
|
+
opacity: 0;
|
|
445
|
+
scale: 0.97;
|
|
446
|
+
translate: 0 -4px;
|
|
447
|
+
}
|
|
207
448
|
}
|
|
208
449
|
|
|
450
|
+
.menu button {
|
|
451
|
+
display: flex;
|
|
452
|
+
align-items: center;
|
|
453
|
+
justify-content: space-between;
|
|
454
|
+
gap: 16px;
|
|
455
|
+
padding: 7px 12px;
|
|
456
|
+
text-align: left;
|
|
457
|
+
font-weight: 500;
|
|
458
|
+
white-space: nowrap;
|
|
459
|
+
background: transparent;
|
|
460
|
+
border: 0;
|
|
461
|
+
border-radius: 9px;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
.menu button:hover,
|
|
465
|
+
.menu button:focus-visible {
|
|
466
|
+
background: var(--stage-mid);
|
|
467
|
+
outline: none;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
.menu button[aria-checked='true'] {
|
|
471
|
+
background: var(--selected);
|
|
472
|
+
font-weight: 600;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
.menu button[aria-checked='true']::after {
|
|
476
|
+
content: '';
|
|
477
|
+
width: 7px;
|
|
478
|
+
height: 7px;
|
|
479
|
+
border-radius: 50%;
|
|
480
|
+
background: var(--filament-deep);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
@media (prefers-reduced-motion: reduce) {
|
|
484
|
+
.progress::before {
|
|
485
|
+
animation: none;
|
|
486
|
+
width: 100%;
|
|
487
|
+
opacity: 0.6;
|
|
488
|
+
}
|
|
489
|
+
#view,
|
|
490
|
+
.progress,
|
|
491
|
+
.empty {
|
|
492
|
+
transition: none !important;
|
|
493
|
+
}
|
|
494
|
+
.menu:popover-open {
|
|
495
|
+
animation: none;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/* Phones: the brand keeps only its mark, the path goes, and the readout
|
|
500
|
+
rises above the display tools. */
|
|
209
501
|
@media (max-width: 720px) {
|
|
502
|
+
.stage {
|
|
503
|
+
--gap: 12px;
|
|
504
|
+
}
|
|
505
|
+
.brand {
|
|
506
|
+
font-size: 0;
|
|
507
|
+
gap: 0;
|
|
508
|
+
margin-right: 0;
|
|
509
|
+
}
|
|
510
|
+
.top-left {
|
|
511
|
+
right: calc(var(--gap) + 170px);
|
|
512
|
+
gap: 8px;
|
|
513
|
+
}
|
|
514
|
+
.top-right {
|
|
515
|
+
gap: 6px;
|
|
516
|
+
}
|
|
210
517
|
.file,
|
|
518
|
+
.wide,
|
|
211
519
|
.hint {
|
|
212
520
|
display: none;
|
|
213
521
|
}
|
|
214
|
-
.
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
522
|
+
.bottom-left {
|
|
523
|
+
right: var(--gap);
|
|
524
|
+
bottom: calc(var(--gap) + 56px);
|
|
525
|
+
gap: 10px;
|
|
526
|
+
}
|
|
527
|
+
.readout .size {
|
|
528
|
+
font-size: 26px;
|
|
220
529
|
}
|
|
221
530
|
}
|