@wtfalch/design 0.8.0 → 0.9.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/README.md +18 -0
- package/dist/components/Button.js +8 -7
- package/dist/components/Callout.js +1 -1
- package/dist/components/Card.d.ts +1 -1
- package/dist/components/Card.js +21 -4
- package/dist/components/Command.js +2 -2
- package/dist/components/Empty.js +22 -1
- package/dist/components/Input.js +4 -4
- package/dist/components/Kbd.js +11 -1
- package/dist/components/Menu.js +3 -3
- package/dist/components/Modal.js +2 -2
- package/dist/components/Pagination.js +6 -1
- package/dist/components/Progress.js +8 -1
- package/dist/components/Rows.d.ts +1 -1
- package/dist/components/Rows.js +1 -1
- package/dist/components/Select.js +2 -2
- package/dist/components/Shell.js +11 -1
- package/dist/components/SizeGrid.js +18 -2
- package/dist/components/Stat.js +11 -2
- package/dist/components/Table.js +7 -1
- package/dist/components/Toast.js +1 -1
- package/dist/components/Tooltip.js +16 -2
- package/dist/components/Tour.js +1 -1
- package/dist/styles/index.css +1117 -418
- package/dist/tf.css +1117 -418
- package/dist/valet.css +1117 -418
- package/package.json +3 -1
package/dist/styles/index.css
CHANGED
|
@@ -8,7 +8,700 @@
|
|
|
8
8
|
*
|
|
9
9
|
* `scripts/copy-css.mjs` flattens these into one file at build time.
|
|
10
10
|
*/
|
|
11
|
-
/* ---- ./
|
|
11
|
+
/* ---- ./_tailwind.built.css ---- */
|
|
12
|
+
/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
|
|
13
|
+
@layer properties;
|
|
14
|
+
@layer theme, base, components, utilities;
|
|
15
|
+
@layer theme {
|
|
16
|
+
:root, :host {
|
|
17
|
+
--font-sans: var(--font-sans);
|
|
18
|
+
--font-mono: var(--font-mono);
|
|
19
|
+
--text-xs: var(--text-xs);
|
|
20
|
+
--text-sm: var(--text-sm);
|
|
21
|
+
--text-base: var(--text-base);
|
|
22
|
+
--text-lg: var(--text-lg);
|
|
23
|
+
--text-xl: var(--text-xl);
|
|
24
|
+
--font-weight-normal: var(--weight);
|
|
25
|
+
--tracking-normal: var(--tracking);
|
|
26
|
+
--radius-sm: var(--radius-sm);
|
|
27
|
+
--radius-md: var(--radius-md);
|
|
28
|
+
--radius-lg: var(--radius-lg);
|
|
29
|
+
--ease-out: cubic-bezier(0, 0, 0.2, 1);
|
|
30
|
+
--spacing-1: var(--space-1);
|
|
31
|
+
--spacing-2: var(--space-2);
|
|
32
|
+
--spacing-3: var(--space-3);
|
|
33
|
+
--spacing-4: var(--space-4);
|
|
34
|
+
--spacing-5: var(--space-5);
|
|
35
|
+
--spacing-6: var(--space-6);
|
|
36
|
+
--spacing-10: var(--space-10);
|
|
37
|
+
--text-2xs: var(--text-2xs);
|
|
38
|
+
--text-md: var(--text-md);
|
|
39
|
+
--font-weight-strong: var(--weight-strong);
|
|
40
|
+
--radius-pill: var(--radius-pill);
|
|
41
|
+
--color-text: var(--text);
|
|
42
|
+
--color-muted: var(--muted);
|
|
43
|
+
--color-border: var(--border);
|
|
44
|
+
--color-border-strong: var(--border-strong);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
@layer utilities {
|
|
48
|
+
.collapse {
|
|
49
|
+
visibility: collapse;
|
|
50
|
+
}
|
|
51
|
+
.invisible {
|
|
52
|
+
visibility: hidden;
|
|
53
|
+
}
|
|
54
|
+
.visible {
|
|
55
|
+
visibility: visible;
|
|
56
|
+
}
|
|
57
|
+
.sr-only {
|
|
58
|
+
position: absolute;
|
|
59
|
+
width: 1px;
|
|
60
|
+
height: 1px;
|
|
61
|
+
padding: 0;
|
|
62
|
+
margin: -1px;
|
|
63
|
+
overflow: hidden;
|
|
64
|
+
clip-path: inset(50%);
|
|
65
|
+
white-space: nowrap;
|
|
66
|
+
border-width: 0;
|
|
67
|
+
}
|
|
68
|
+
.absolute {
|
|
69
|
+
position: absolute;
|
|
70
|
+
}
|
|
71
|
+
.fixed {
|
|
72
|
+
position: fixed;
|
|
73
|
+
}
|
|
74
|
+
.relative {
|
|
75
|
+
position: relative;
|
|
76
|
+
}
|
|
77
|
+
.sticky {
|
|
78
|
+
position: sticky;
|
|
79
|
+
}
|
|
80
|
+
.z-\[60\] {
|
|
81
|
+
z-index: 60;
|
|
82
|
+
}
|
|
83
|
+
.container {
|
|
84
|
+
width: 100%;
|
|
85
|
+
@media (width >= 40rem) {
|
|
86
|
+
max-width: 40rem;
|
|
87
|
+
}
|
|
88
|
+
@media (width >= 48rem) {
|
|
89
|
+
max-width: 48rem;
|
|
90
|
+
}
|
|
91
|
+
@media (width >= 64rem) {
|
|
92
|
+
max-width: 64rem;
|
|
93
|
+
}
|
|
94
|
+
@media (width >= 80rem) {
|
|
95
|
+
max-width: 80rem;
|
|
96
|
+
}
|
|
97
|
+
@media (width >= 96rem) {
|
|
98
|
+
max-width: 96rem;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
.m-0 {
|
|
102
|
+
margin: 0px;
|
|
103
|
+
}
|
|
104
|
+
.m-auto {
|
|
105
|
+
margin: auto;
|
|
106
|
+
}
|
|
107
|
+
.mx-auto {
|
|
108
|
+
margin-inline: auto;
|
|
109
|
+
}
|
|
110
|
+
.mt-1 {
|
|
111
|
+
margin-top: var(--spacing-1);
|
|
112
|
+
}
|
|
113
|
+
.mb-3 {
|
|
114
|
+
margin-bottom: var(--spacing-3);
|
|
115
|
+
}
|
|
116
|
+
.ml-2 {
|
|
117
|
+
margin-left: var(--spacing-2);
|
|
118
|
+
}
|
|
119
|
+
.block {
|
|
120
|
+
display: block;
|
|
121
|
+
}
|
|
122
|
+
.contents {
|
|
123
|
+
display: contents;
|
|
124
|
+
}
|
|
125
|
+
.flex {
|
|
126
|
+
display: flex;
|
|
127
|
+
}
|
|
128
|
+
.grid {
|
|
129
|
+
display: grid;
|
|
130
|
+
}
|
|
131
|
+
.hidden {
|
|
132
|
+
display: none;
|
|
133
|
+
}
|
|
134
|
+
.inline {
|
|
135
|
+
display: inline;
|
|
136
|
+
}
|
|
137
|
+
.inline-flex {
|
|
138
|
+
display: inline-flex;
|
|
139
|
+
}
|
|
140
|
+
.table {
|
|
141
|
+
display: table;
|
|
142
|
+
}
|
|
143
|
+
.h-\[14px\] {
|
|
144
|
+
height: 14px;
|
|
145
|
+
}
|
|
146
|
+
.h-\[18px\] {
|
|
147
|
+
height: 18px;
|
|
148
|
+
}
|
|
149
|
+
.max-h-\[24rem\] {
|
|
150
|
+
max-height: 24rem;
|
|
151
|
+
}
|
|
152
|
+
.max-h-\[280px\] {
|
|
153
|
+
max-height: 280px;
|
|
154
|
+
}
|
|
155
|
+
.min-h-0 {
|
|
156
|
+
min-height: 0px;
|
|
157
|
+
}
|
|
158
|
+
.min-h-screen {
|
|
159
|
+
min-height: 100vh;
|
|
160
|
+
}
|
|
161
|
+
.w-\[18px\] {
|
|
162
|
+
width: 18px;
|
|
163
|
+
}
|
|
164
|
+
.w-full {
|
|
165
|
+
width: 100%;
|
|
166
|
+
}
|
|
167
|
+
.max-w-\[46ch\] {
|
|
168
|
+
max-width: 46ch;
|
|
169
|
+
}
|
|
170
|
+
.max-w-\[min\(20rem\,calc\(100vw-var\(--space-6\)\)\)\] {
|
|
171
|
+
max-width: min(20rem, calc(100vw - var(--space-6)));
|
|
172
|
+
}
|
|
173
|
+
.max-w-\[var\(--shell-measure\)\] {
|
|
174
|
+
max-width: var(--shell-measure);
|
|
175
|
+
}
|
|
176
|
+
.max-w-\[var\(--shell-measure-wide\)\] {
|
|
177
|
+
max-width: var(--shell-measure-wide);
|
|
178
|
+
}
|
|
179
|
+
.min-w-0 {
|
|
180
|
+
min-width: 0px;
|
|
181
|
+
}
|
|
182
|
+
.min-w-\[12rem\] {
|
|
183
|
+
min-width: 12rem;
|
|
184
|
+
}
|
|
185
|
+
.flex-1 {
|
|
186
|
+
flex: 1;
|
|
187
|
+
}
|
|
188
|
+
.flex-none {
|
|
189
|
+
flex: none;
|
|
190
|
+
}
|
|
191
|
+
.shrink {
|
|
192
|
+
flex-shrink: 1;
|
|
193
|
+
}
|
|
194
|
+
.grow {
|
|
195
|
+
flex-grow: 1;
|
|
196
|
+
}
|
|
197
|
+
.transform {
|
|
198
|
+
transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);
|
|
199
|
+
}
|
|
200
|
+
.cursor-help {
|
|
201
|
+
cursor: help;
|
|
202
|
+
}
|
|
203
|
+
.cursor-pointer {
|
|
204
|
+
cursor: pointer;
|
|
205
|
+
}
|
|
206
|
+
.resize {
|
|
207
|
+
resize: both;
|
|
208
|
+
}
|
|
209
|
+
.list-none {
|
|
210
|
+
list-style-type: none;
|
|
211
|
+
}
|
|
212
|
+
.flex-col {
|
|
213
|
+
flex-direction: column;
|
|
214
|
+
}
|
|
215
|
+
.flex-wrap {
|
|
216
|
+
flex-wrap: wrap;
|
|
217
|
+
}
|
|
218
|
+
.items-baseline {
|
|
219
|
+
align-items: baseline;
|
|
220
|
+
}
|
|
221
|
+
.items-center {
|
|
222
|
+
align-items: center;
|
|
223
|
+
}
|
|
224
|
+
.items-start {
|
|
225
|
+
align-items: flex-start;
|
|
226
|
+
}
|
|
227
|
+
.justify-between {
|
|
228
|
+
justify-content: space-between;
|
|
229
|
+
}
|
|
230
|
+
.justify-items-center {
|
|
231
|
+
justify-items: center;
|
|
232
|
+
}
|
|
233
|
+
.gap-0 {
|
|
234
|
+
gap: 0px;
|
|
235
|
+
}
|
|
236
|
+
.gap-1 {
|
|
237
|
+
gap: var(--spacing-1);
|
|
238
|
+
}
|
|
239
|
+
.gap-2 {
|
|
240
|
+
gap: var(--spacing-2);
|
|
241
|
+
}
|
|
242
|
+
.gap-3 {
|
|
243
|
+
gap: var(--spacing-3);
|
|
244
|
+
}
|
|
245
|
+
.gap-4 {
|
|
246
|
+
gap: var(--spacing-4);
|
|
247
|
+
}
|
|
248
|
+
.gap-\[var\(--border-width\)\] {
|
|
249
|
+
gap: var(--border-width);
|
|
250
|
+
}
|
|
251
|
+
.self-center {
|
|
252
|
+
align-self: center;
|
|
253
|
+
}
|
|
254
|
+
.truncate {
|
|
255
|
+
overflow: hidden;
|
|
256
|
+
text-overflow: ellipsis;
|
|
257
|
+
white-space: nowrap;
|
|
258
|
+
}
|
|
259
|
+
.overflow-auto {
|
|
260
|
+
overflow: auto;
|
|
261
|
+
}
|
|
262
|
+
.overflow-hidden {
|
|
263
|
+
overflow: hidden;
|
|
264
|
+
}
|
|
265
|
+
.overflow-x-auto {
|
|
266
|
+
overflow-x: auto;
|
|
267
|
+
}
|
|
268
|
+
.overflow-y-auto {
|
|
269
|
+
overflow-y: auto;
|
|
270
|
+
}
|
|
271
|
+
.overscroll-contain {
|
|
272
|
+
overscroll-behavior: contain;
|
|
273
|
+
}
|
|
274
|
+
.rounded {
|
|
275
|
+
border-radius: 0.25rem;
|
|
276
|
+
}
|
|
277
|
+
.rounded-full {
|
|
278
|
+
border-radius: calc(infinity * 1px);
|
|
279
|
+
}
|
|
280
|
+
.rounded-md {
|
|
281
|
+
border-radius: var(--radius-md);
|
|
282
|
+
}
|
|
283
|
+
.rounded-sm {
|
|
284
|
+
border-radius: var(--radius-sm);
|
|
285
|
+
}
|
|
286
|
+
.border {
|
|
287
|
+
border-style: var(--tw-border-style);
|
|
288
|
+
border-width: var(--border-width);
|
|
289
|
+
}
|
|
290
|
+
.border-b {
|
|
291
|
+
border-bottom-style: var(--tw-border-style);
|
|
292
|
+
border-bottom-width: var(--border-width);
|
|
293
|
+
}
|
|
294
|
+
.border-dashed {
|
|
295
|
+
--tw-border-style: dashed;
|
|
296
|
+
border-style: dashed;
|
|
297
|
+
}
|
|
298
|
+
.border-border {
|
|
299
|
+
border-color: var(--color-border);
|
|
300
|
+
}
|
|
301
|
+
.border-border-strong {
|
|
302
|
+
border-color: var(--color-border-strong);
|
|
303
|
+
}
|
|
304
|
+
.p-0 {
|
|
305
|
+
padding: 0px;
|
|
306
|
+
}
|
|
307
|
+
.p-1 {
|
|
308
|
+
padding: var(--spacing-1);
|
|
309
|
+
}
|
|
310
|
+
.p-2 {
|
|
311
|
+
padding: var(--spacing-2);
|
|
312
|
+
}
|
|
313
|
+
.p-4 {
|
|
314
|
+
padding: var(--spacing-4);
|
|
315
|
+
}
|
|
316
|
+
.px-4 {
|
|
317
|
+
padding-inline: var(--spacing-4);
|
|
318
|
+
}
|
|
319
|
+
.py-2 {
|
|
320
|
+
padding-block: var(--spacing-2);
|
|
321
|
+
}
|
|
322
|
+
.py-3 {
|
|
323
|
+
padding-block: var(--spacing-3);
|
|
324
|
+
}
|
|
325
|
+
.py-5 {
|
|
326
|
+
padding-block: var(--spacing-5);
|
|
327
|
+
}
|
|
328
|
+
.py-6 {
|
|
329
|
+
padding-block: var(--spacing-6);
|
|
330
|
+
}
|
|
331
|
+
.py-10 {
|
|
332
|
+
padding-block: var(--spacing-10);
|
|
333
|
+
}
|
|
334
|
+
.pb-2 {
|
|
335
|
+
padding-bottom: var(--spacing-2);
|
|
336
|
+
}
|
|
337
|
+
.pb-3 {
|
|
338
|
+
padding-bottom: var(--spacing-3);
|
|
339
|
+
}
|
|
340
|
+
.text-center {
|
|
341
|
+
text-align: center;
|
|
342
|
+
}
|
|
343
|
+
.font-mono {
|
|
344
|
+
font-family: var(--font-mono);
|
|
345
|
+
}
|
|
346
|
+
.text-2xs {
|
|
347
|
+
font-size: var(--text-2xs);
|
|
348
|
+
}
|
|
349
|
+
.text-lg {
|
|
350
|
+
font-size: var(--text-lg);
|
|
351
|
+
}
|
|
352
|
+
.text-sm {
|
|
353
|
+
font-size: var(--text-sm);
|
|
354
|
+
}
|
|
355
|
+
.text-xs {
|
|
356
|
+
font-size: var(--text-xs);
|
|
357
|
+
}
|
|
358
|
+
.leading-\[0\] {
|
|
359
|
+
--tw-leading: 0;
|
|
360
|
+
line-height: 0;
|
|
361
|
+
}
|
|
362
|
+
.leading-\[1\.5\] {
|
|
363
|
+
--tw-leading: 1.5;
|
|
364
|
+
line-height: 1.5;
|
|
365
|
+
}
|
|
366
|
+
.leading-\[1\.25\] {
|
|
367
|
+
--tw-leading: 1.25;
|
|
368
|
+
line-height: 1.25;
|
|
369
|
+
}
|
|
370
|
+
.leading-\[16px\] {
|
|
371
|
+
--tw-leading: 16px;
|
|
372
|
+
line-height: 16px;
|
|
373
|
+
}
|
|
374
|
+
.font-normal {
|
|
375
|
+
--tw-font-weight: var(--font-weight-normal);
|
|
376
|
+
font-weight: var(--font-weight-normal);
|
|
377
|
+
}
|
|
378
|
+
.font-strong {
|
|
379
|
+
--tw-font-weight: var(--font-weight-strong);
|
|
380
|
+
font-weight: var(--font-weight-strong);
|
|
381
|
+
}
|
|
382
|
+
.tracking-normal {
|
|
383
|
+
--tw-tracking: var(--tracking-normal);
|
|
384
|
+
letter-spacing: var(--tracking-normal);
|
|
385
|
+
}
|
|
386
|
+
.text-ellipsis {
|
|
387
|
+
text-overflow: ellipsis;
|
|
388
|
+
}
|
|
389
|
+
.whitespace-nowrap {
|
|
390
|
+
white-space: nowrap;
|
|
391
|
+
}
|
|
392
|
+
.text-muted {
|
|
393
|
+
color: var(--color-muted);
|
|
394
|
+
}
|
|
395
|
+
.text-text {
|
|
396
|
+
color: var(--color-text);
|
|
397
|
+
}
|
|
398
|
+
.lowercase {
|
|
399
|
+
text-transform: lowercase;
|
|
400
|
+
}
|
|
401
|
+
.normal-case {
|
|
402
|
+
text-transform: none;
|
|
403
|
+
}
|
|
404
|
+
.uppercase {
|
|
405
|
+
text-transform: uppercase;
|
|
406
|
+
}
|
|
407
|
+
.tabular-nums {
|
|
408
|
+
--tw-numeric-spacing: tabular-nums;
|
|
409
|
+
font-variant-numeric: var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,);
|
|
410
|
+
}
|
|
411
|
+
.opacity-60 {
|
|
412
|
+
opacity: 60%;
|
|
413
|
+
}
|
|
414
|
+
.opacity-\[0\.55\] {
|
|
415
|
+
opacity: 0.55;
|
|
416
|
+
}
|
|
417
|
+
.shadow {
|
|
418
|
+
--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
|
419
|
+
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
420
|
+
}
|
|
421
|
+
.ring {
|
|
422
|
+
--tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
|
423
|
+
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
424
|
+
}
|
|
425
|
+
.outline {
|
|
426
|
+
outline-style: var(--tw-outline-style);
|
|
427
|
+
outline-width: 1px;
|
|
428
|
+
}
|
|
429
|
+
.blur {
|
|
430
|
+
--tw-blur: blur(8px);
|
|
431
|
+
filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
|
|
432
|
+
}
|
|
433
|
+
.sepia {
|
|
434
|
+
--tw-sepia: sepia(100%);
|
|
435
|
+
filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
|
|
436
|
+
}
|
|
437
|
+
.filter {
|
|
438
|
+
filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
|
|
439
|
+
}
|
|
440
|
+
.outline-none {
|
|
441
|
+
--tw-outline-style: none;
|
|
442
|
+
outline-style: none;
|
|
443
|
+
}
|
|
444
|
+
.\[font\:inherit\] {
|
|
445
|
+
font: inherit;
|
|
446
|
+
}
|
|
447
|
+
.surface-bg {
|
|
448
|
+
background: var(--bg);
|
|
449
|
+
}
|
|
450
|
+
.surface-panel {
|
|
451
|
+
background: var(--panel);
|
|
452
|
+
}
|
|
453
|
+
.disabled\:cursor-default:disabled {
|
|
454
|
+
cursor: default;
|
|
455
|
+
}
|
|
456
|
+
.disabled\:opacity-50:disabled {
|
|
457
|
+
opacity: 50%;
|
|
458
|
+
}
|
|
459
|
+
.\[\&\>p\]\:m-0 > p {
|
|
460
|
+
margin: 0px;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
@property --tw-rotate-x {
|
|
464
|
+
syntax: "*";
|
|
465
|
+
inherits: false;
|
|
466
|
+
}
|
|
467
|
+
@property --tw-rotate-y {
|
|
468
|
+
syntax: "*";
|
|
469
|
+
inherits: false;
|
|
470
|
+
}
|
|
471
|
+
@property --tw-rotate-z {
|
|
472
|
+
syntax: "*";
|
|
473
|
+
inherits: false;
|
|
474
|
+
}
|
|
475
|
+
@property --tw-skew-x {
|
|
476
|
+
syntax: "*";
|
|
477
|
+
inherits: false;
|
|
478
|
+
}
|
|
479
|
+
@property --tw-skew-y {
|
|
480
|
+
syntax: "*";
|
|
481
|
+
inherits: false;
|
|
482
|
+
}
|
|
483
|
+
@property --tw-border-style {
|
|
484
|
+
syntax: "*";
|
|
485
|
+
inherits: false;
|
|
486
|
+
initial-value: solid;
|
|
487
|
+
}
|
|
488
|
+
@property --tw-leading {
|
|
489
|
+
syntax: "*";
|
|
490
|
+
inherits: false;
|
|
491
|
+
}
|
|
492
|
+
@property --tw-font-weight {
|
|
493
|
+
syntax: "*";
|
|
494
|
+
inherits: false;
|
|
495
|
+
}
|
|
496
|
+
@property --tw-tracking {
|
|
497
|
+
syntax: "*";
|
|
498
|
+
inherits: false;
|
|
499
|
+
}
|
|
500
|
+
@property --tw-ordinal {
|
|
501
|
+
syntax: "*";
|
|
502
|
+
inherits: false;
|
|
503
|
+
}
|
|
504
|
+
@property --tw-slashed-zero {
|
|
505
|
+
syntax: "*";
|
|
506
|
+
inherits: false;
|
|
507
|
+
}
|
|
508
|
+
@property --tw-numeric-figure {
|
|
509
|
+
syntax: "*";
|
|
510
|
+
inherits: false;
|
|
511
|
+
}
|
|
512
|
+
@property --tw-numeric-spacing {
|
|
513
|
+
syntax: "*";
|
|
514
|
+
inherits: false;
|
|
515
|
+
}
|
|
516
|
+
@property --tw-numeric-fraction {
|
|
517
|
+
syntax: "*";
|
|
518
|
+
inherits: false;
|
|
519
|
+
}
|
|
520
|
+
@property --tw-shadow {
|
|
521
|
+
syntax: "*";
|
|
522
|
+
inherits: false;
|
|
523
|
+
initial-value: 0 0 #0000;
|
|
524
|
+
}
|
|
525
|
+
@property --tw-shadow-color {
|
|
526
|
+
syntax: "*";
|
|
527
|
+
inherits: false;
|
|
528
|
+
}
|
|
529
|
+
@property --tw-shadow-alpha {
|
|
530
|
+
syntax: "<percentage>";
|
|
531
|
+
inherits: false;
|
|
532
|
+
initial-value: 100%;
|
|
533
|
+
}
|
|
534
|
+
@property --tw-inset-shadow {
|
|
535
|
+
syntax: "*";
|
|
536
|
+
inherits: false;
|
|
537
|
+
initial-value: 0 0 #0000;
|
|
538
|
+
}
|
|
539
|
+
@property --tw-inset-shadow-color {
|
|
540
|
+
syntax: "*";
|
|
541
|
+
inherits: false;
|
|
542
|
+
}
|
|
543
|
+
@property --tw-inset-shadow-alpha {
|
|
544
|
+
syntax: "<percentage>";
|
|
545
|
+
inherits: false;
|
|
546
|
+
initial-value: 100%;
|
|
547
|
+
}
|
|
548
|
+
@property --tw-ring-color {
|
|
549
|
+
syntax: "*";
|
|
550
|
+
inherits: false;
|
|
551
|
+
}
|
|
552
|
+
@property --tw-ring-shadow {
|
|
553
|
+
syntax: "*";
|
|
554
|
+
inherits: false;
|
|
555
|
+
initial-value: 0 0 #0000;
|
|
556
|
+
}
|
|
557
|
+
@property --tw-inset-ring-color {
|
|
558
|
+
syntax: "*";
|
|
559
|
+
inherits: false;
|
|
560
|
+
}
|
|
561
|
+
@property --tw-inset-ring-shadow {
|
|
562
|
+
syntax: "*";
|
|
563
|
+
inherits: false;
|
|
564
|
+
initial-value: 0 0 #0000;
|
|
565
|
+
}
|
|
566
|
+
@property --tw-ring-inset {
|
|
567
|
+
syntax: "*";
|
|
568
|
+
inherits: false;
|
|
569
|
+
}
|
|
570
|
+
@property --tw-ring-offset-width {
|
|
571
|
+
syntax: "<length>";
|
|
572
|
+
inherits: false;
|
|
573
|
+
initial-value: 0px;
|
|
574
|
+
}
|
|
575
|
+
@property --tw-ring-offset-color {
|
|
576
|
+
syntax: "*";
|
|
577
|
+
inherits: false;
|
|
578
|
+
initial-value: #fff;
|
|
579
|
+
}
|
|
580
|
+
@property --tw-ring-offset-shadow {
|
|
581
|
+
syntax: "*";
|
|
582
|
+
inherits: false;
|
|
583
|
+
initial-value: 0 0 #0000;
|
|
584
|
+
}
|
|
585
|
+
@property --tw-outline-style {
|
|
586
|
+
syntax: "*";
|
|
587
|
+
inherits: false;
|
|
588
|
+
initial-value: solid;
|
|
589
|
+
}
|
|
590
|
+
@property --tw-blur {
|
|
591
|
+
syntax: "*";
|
|
592
|
+
inherits: false;
|
|
593
|
+
}
|
|
594
|
+
@property --tw-brightness {
|
|
595
|
+
syntax: "*";
|
|
596
|
+
inherits: false;
|
|
597
|
+
}
|
|
598
|
+
@property --tw-contrast {
|
|
599
|
+
syntax: "*";
|
|
600
|
+
inherits: false;
|
|
601
|
+
}
|
|
602
|
+
@property --tw-grayscale {
|
|
603
|
+
syntax: "*";
|
|
604
|
+
inherits: false;
|
|
605
|
+
}
|
|
606
|
+
@property --tw-hue-rotate {
|
|
607
|
+
syntax: "*";
|
|
608
|
+
inherits: false;
|
|
609
|
+
}
|
|
610
|
+
@property --tw-invert {
|
|
611
|
+
syntax: "*";
|
|
612
|
+
inherits: false;
|
|
613
|
+
}
|
|
614
|
+
@property --tw-opacity {
|
|
615
|
+
syntax: "*";
|
|
616
|
+
inherits: false;
|
|
617
|
+
}
|
|
618
|
+
@property --tw-saturate {
|
|
619
|
+
syntax: "*";
|
|
620
|
+
inherits: false;
|
|
621
|
+
}
|
|
622
|
+
@property --tw-sepia {
|
|
623
|
+
syntax: "*";
|
|
624
|
+
inherits: false;
|
|
625
|
+
}
|
|
626
|
+
@property --tw-drop-shadow {
|
|
627
|
+
syntax: "*";
|
|
628
|
+
inherits: false;
|
|
629
|
+
}
|
|
630
|
+
@property --tw-drop-shadow-color {
|
|
631
|
+
syntax: "*";
|
|
632
|
+
inherits: false;
|
|
633
|
+
}
|
|
634
|
+
@property --tw-drop-shadow-alpha {
|
|
635
|
+
syntax: "<percentage>";
|
|
636
|
+
inherits: false;
|
|
637
|
+
initial-value: 100%;
|
|
638
|
+
}
|
|
639
|
+
@property --tw-drop-shadow-size {
|
|
640
|
+
syntax: "*";
|
|
641
|
+
inherits: false;
|
|
642
|
+
}
|
|
643
|
+
@layer properties {
|
|
644
|
+
@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
|
|
645
|
+
*, ::before, ::after, ::backdrop {
|
|
646
|
+
--tw-rotate-x: initial;
|
|
647
|
+
--tw-rotate-y: initial;
|
|
648
|
+
--tw-rotate-z: initial;
|
|
649
|
+
--tw-skew-x: initial;
|
|
650
|
+
--tw-skew-y: initial;
|
|
651
|
+
--tw-border-style: solid;
|
|
652
|
+
--tw-leading: initial;
|
|
653
|
+
--tw-font-weight: initial;
|
|
654
|
+
--tw-tracking: initial;
|
|
655
|
+
--tw-ordinal: initial;
|
|
656
|
+
--tw-slashed-zero: initial;
|
|
657
|
+
--tw-numeric-figure: initial;
|
|
658
|
+
--tw-numeric-spacing: initial;
|
|
659
|
+
--tw-numeric-fraction: initial;
|
|
660
|
+
--tw-shadow: 0 0 #0000;
|
|
661
|
+
--tw-shadow-color: initial;
|
|
662
|
+
--tw-shadow-alpha: 100%;
|
|
663
|
+
--tw-inset-shadow: 0 0 #0000;
|
|
664
|
+
--tw-inset-shadow-color: initial;
|
|
665
|
+
--tw-inset-shadow-alpha: 100%;
|
|
666
|
+
--tw-ring-color: initial;
|
|
667
|
+
--tw-ring-shadow: 0 0 #0000;
|
|
668
|
+
--tw-inset-ring-color: initial;
|
|
669
|
+
--tw-inset-ring-shadow: 0 0 #0000;
|
|
670
|
+
--tw-ring-inset: initial;
|
|
671
|
+
--tw-ring-offset-width: 0px;
|
|
672
|
+
--tw-ring-offset-color: #fff;
|
|
673
|
+
--tw-ring-offset-shadow: 0 0 #0000;
|
|
674
|
+
--tw-outline-style: solid;
|
|
675
|
+
--tw-blur: initial;
|
|
676
|
+
--tw-brightness: initial;
|
|
677
|
+
--tw-contrast: initial;
|
|
678
|
+
--tw-grayscale: initial;
|
|
679
|
+
--tw-hue-rotate: initial;
|
|
680
|
+
--tw-invert: initial;
|
|
681
|
+
--tw-opacity: initial;
|
|
682
|
+
--tw-saturate: initial;
|
|
683
|
+
--tw-sepia: initial;
|
|
684
|
+
--tw-drop-shadow: initial;
|
|
685
|
+
--tw-drop-shadow-color: initial;
|
|
686
|
+
--tw-drop-shadow-alpha: 100%;
|
|
687
|
+
--tw-drop-shadow-size: initial;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
/* ---- ./_system-light.css ---- */
|
|
693
|
+
/* The `system` theme's light half.
|
|
694
|
+
*
|
|
695
|
+
* Its own file, and outside the components layer, because it is a *theme*
|
|
696
|
+
* rather than a component rule. `tokens.css` states the dark base on `:root`
|
|
697
|
+
* and is unlayered; the moment this sat inside `@layer components` it lost to
|
|
698
|
+
* that, and every `system` specimen rendered dark on a light-mode machine.
|
|
699
|
+
* Unlayered beats layered whatever the selector says, which is exactly the
|
|
700
|
+
* trap this repository keeps finding in different costumes.
|
|
701
|
+
*
|
|
702
|
+
* The underscore marks it the same way `_tailwind.built.css` is marked:
|
|
703
|
+
* `copy-css.mjs` passes both through without wrapping them.
|
|
704
|
+
*/
|
|
12
705
|
/* Light, only under the `system` theme. This used to override `:root`
|
|
13
706
|
unconditionally, so choosing a dark theme on a light-mode laptop got
|
|
14
707
|
silently repainted. Every other theme states its own palette. */
|
|
@@ -37,6 +730,8 @@
|
|
|
37
730
|
}
|
|
38
731
|
}
|
|
39
732
|
|
|
733
|
+
/* ---- ./base.css ---- */
|
|
734
|
+
@layer components {
|
|
40
735
|
/* Derived from the two surfaces every theme already defines, so a theme gets a
|
|
41
736
|
control colour without knowing this exists. */
|
|
42
737
|
/* Pseudo-elements too. `*` does not match them, and `box-sizing` is not
|
|
@@ -101,23 +796,31 @@ body::before {
|
|
|
101
796
|
`[aria-disabled='true']` twin rather than a rewrite, which leaves each
|
|
102
797
|
`button` selector at the specificity it had and every committed baseline
|
|
103
798
|
untouched. */
|
|
104
|
-
|
|
799
|
+
.btn {
|
|
800
|
+
/* The three an anchor brings that a `<button>` does not. Harmless on the
|
|
801
|
+
button form -- it has no underline and centres already -- and the reason
|
|
802
|
+
`Button` puts one class on both elements rather than keeping a twin
|
|
803
|
+
selector for each. */
|
|
105
804
|
text-decoration: none;
|
|
106
805
|
color: var(--text);
|
|
107
806
|
text-align: center;
|
|
108
807
|
}
|
|
109
808
|
|
|
110
|
-
|
|
809
|
+
.btn[aria-disabled='true'] {
|
|
111
810
|
/* A disabled anchor still takes the pointer, so say so. The click itself is
|
|
112
811
|
blocked in the capture phase by the component. */
|
|
113
812
|
cursor: not-allowed;
|
|
114
813
|
}
|
|
115
814
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
input,
|
|
119
|
-
|
|
120
|
-
|
|
815
|
+
/* `:where`, so this base carries no specificity of its own.
|
|
816
|
+
*
|
|
817
|
+
* It was `button, input, textarea, select` -- an element selector, which
|
|
818
|
+
* `.size-sm` and every other class outranked without anyone thinking about
|
|
819
|
+
* it. Moving it to `.btn` to stop a tab inheriting a control's look raised it
|
|
820
|
+
* to a class, so it tied with `.size-sm` and won on source order: every
|
|
821
|
+
* button came out `8px 12px` whatever size it asked for. `:where` puts it
|
|
822
|
+
* back to zero, which is what the element selector was silently providing. */
|
|
823
|
+
:where(.btn, input, textarea, select) {
|
|
121
824
|
font: inherit;
|
|
122
825
|
color: var(--text);
|
|
123
826
|
background: var(--control);
|
|
@@ -138,8 +841,7 @@ select {
|
|
|
138
841
|
the icon; the button simply had no opinion about how to arrange two things.
|
|
139
842
|
`inline-flex` and a gap gives it one, and the gap replaces the space
|
|
140
843
|
character people were putting between an icon and its label. */
|
|
141
|
-
|
|
142
|
-
a.btn {
|
|
844
|
+
.btn {
|
|
143
845
|
display: inline-flex;
|
|
144
846
|
align-items: center;
|
|
145
847
|
justify-content: center;
|
|
@@ -155,18 +857,41 @@ a.btn {
|
|
|
155
857
|
|
|
156
858
|
Several places already drew this by hand as `.chat-bar-btn.on`. This is the
|
|
157
859
|
same look, said once, on a plain button. */
|
|
158
|
-
|
|
860
|
+
.btn[aria-pressed='true'] {
|
|
159
861
|
border-color: var(--accent);
|
|
160
862
|
color: var(--accent);
|
|
161
863
|
background: color-mix(in srgb, var(--accent) 10%, var(--panel));
|
|
162
864
|
}
|
|
163
865
|
|
|
164
|
-
|
|
866
|
+
.btn[aria-pressed='true']:hover:not(:disabled) { border-color: var(--accent); }
|
|
165
867
|
|
|
166
868
|
/* The glyph never shrinks: in a narrow row flexbox would take it from the icon
|
|
167
869
|
before the text, and half an icon is not a smaller icon. */
|
|
168
|
-
|
|
169
|
-
|
|
870
|
+
.btn > svg { flex: none; }
|
|
871
|
+
|
|
872
|
+
/* `Select`'s control wears the control styling, and says so.
|
|
873
|
+
*
|
|
874
|
+
* It renders React Aria's `Button` -- a bare `<button>` -- and used to take
|
|
875
|
+
* `font`, colour, the surface and the border from the
|
|
876
|
+
* `button, input, textarea, select` reset without asking. When that reset
|
|
877
|
+
* moved to `.btn`, so a tab and a row would stop inheriting a control's look
|
|
878
|
+
* only to undo it, this lost all of it at once.
|
|
879
|
+
*
|
|
880
|
+
* Here rather than in `select.css`, and that placement is the rule, not
|
|
881
|
+
* tidiness: `font` is a shorthand and it resets `font-size`, so declared
|
|
882
|
+
* after `.size-sm` below it silently makes every small control full size.
|
|
883
|
+
* `index.css` says the import order is behaviour; this is what that means.
|
|
884
|
+
*
|
|
885
|
+
* `:where` for the same reason the reset above uses it: this is a base a
|
|
886
|
+
* `size` class has to be able to beat, and a bare class ties with one. */
|
|
887
|
+
:where(.sel-control) {
|
|
888
|
+
font: inherit;
|
|
889
|
+
color: var(--text);
|
|
890
|
+
background: var(--control);
|
|
891
|
+
border: var(--border-width) solid var(--border-strong);
|
|
892
|
+
border-radius: var(--radius);
|
|
893
|
+
cursor: pointer;
|
|
894
|
+
}
|
|
170
895
|
|
|
171
896
|
.size-sm { font-size: var(--text-xs); padding: var(--space-1) var(--space-2); }
|
|
172
897
|
|
|
@@ -191,8 +916,7 @@ input, textarea, select { width: 100%; }
|
|
|
191
916
|
same disagreement written twice. */
|
|
192
917
|
textarea { resize: none; }
|
|
193
918
|
|
|
194
|
-
|
|
195
|
-
a.btn:hover:not([aria-disabled='true']),
|
|
919
|
+
.btn:hover:not(:disabled),
|
|
196
920
|
input:hover:not(:disabled),
|
|
197
921
|
textarea:hover:not(:disabled),
|
|
198
922
|
select:hover:not(:disabled) { border-color: var(--accent); }
|
|
@@ -200,8 +924,7 @@ select:hover:not(:disabled) { border-color: var(--accent); }
|
|
|
200
924
|
/* `:focus-visible` on the button so a click does not leave a ring behind it,
|
|
201
925
|
`:focus` on the fields because a focused field is a place you are typing and
|
|
202
926
|
should say so however you got there. */
|
|
203
|
-
|
|
204
|
-
a.btn:focus-visible,
|
|
927
|
+
.btn:focus-visible,
|
|
205
928
|
input:focus,
|
|
206
929
|
textarea:focus,
|
|
207
930
|
select:focus { outline: none; border-color: var(--accent); }
|
|
@@ -294,14 +1017,13 @@ input[type='radio']:focus-visible { outline: none; box-shadow: var(--focus-ring)
|
|
|
294
1017
|
input[type='checkbox']:disabled,
|
|
295
1018
|
input[type='radio']:disabled { cursor: not-allowed; background: var(--panel-2); }
|
|
296
1019
|
|
|
297
|
-
|
|
298
|
-
|
|
1020
|
+
.btn:disabled,
|
|
1021
|
+
.btn[aria-disabled='true'],
|
|
299
1022
|
input:disabled,
|
|
300
1023
|
textarea:disabled,
|
|
301
1024
|
select:disabled { opacity: 0.45; cursor: not-allowed; }
|
|
302
1025
|
|
|
303
|
-
|
|
304
|
-
a.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
|
|
1026
|
+
.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
|
|
305
1027
|
|
|
306
1028
|
/* A disabled primary is not a faded primary.
|
|
307
1029
|
`opacity: .45` was the whole of it, and a coloured fill at 45% is still a
|
|
@@ -309,8 +1031,7 @@ a.btn.primary { background: var(--accent); border-color: var(--accent); color: v
|
|
|
309
1031
|
thing on the panel. That got worse when onboarding started holding people at
|
|
310
1032
|
a disabled Next. So it gives up the fill entirely and becomes the shape of a
|
|
311
1033
|
disabled control -- the opacity then has nothing left to do. */
|
|
312
|
-
|
|
313
|
-
a.btn.primary[aria-disabled='true'] {
|
|
1034
|
+
.btn.primary:disabled {
|
|
314
1035
|
background: var(--panel-2);
|
|
315
1036
|
border-color: var(--border);
|
|
316
1037
|
color: var(--muted);
|
|
@@ -324,7 +1045,7 @@ a.btn.primary[aria-disabled='true'] {
|
|
|
324
1045
|
line under it that travels.
|
|
325
1046
|
`aria-busy` rather than a class: the attribute is what a screen reader reads,
|
|
326
1047
|
and styling the thing that carries the meaning is how they stay in step. */
|
|
327
|
-
|
|
1048
|
+
.btn[aria-busy='true'] {
|
|
328
1049
|
position: relative;
|
|
329
1050
|
overflow: hidden;
|
|
330
1051
|
cursor: progress;
|
|
@@ -337,18 +1058,18 @@ button[aria-busy='true'] {
|
|
|
337
1058
|
something that is working, that reads as a control that failed and went
|
|
338
1059
|
grey. So a busy button keeps every colour it had and takes only the loss of
|
|
339
1060
|
the cursor and the press; the travelling line is what says why. */
|
|
340
|
-
|
|
1061
|
+
.btn[aria-busy='true']:disabled {
|
|
341
1062
|
opacity: 1;
|
|
342
1063
|
cursor: progress;
|
|
343
1064
|
}
|
|
344
1065
|
|
|
345
|
-
|
|
1066
|
+
.btn.primary[aria-busy='true']:disabled {
|
|
346
1067
|
background: var(--accent);
|
|
347
1068
|
border-color: var(--accent);
|
|
348
1069
|
color: var(--on-accent);
|
|
349
1070
|
}
|
|
350
1071
|
|
|
351
|
-
|
|
1072
|
+
.btn[aria-busy='true']::after {
|
|
352
1073
|
content: '';
|
|
353
1074
|
position: absolute;
|
|
354
1075
|
left: 0;
|
|
@@ -380,15 +1101,13 @@ button[aria-busy='true']::after {
|
|
|
380
1101
|
|
|
381
1102
|
/* Quiet: no border, no fill. For the action beside the action -- Cancel next to
|
|
382
1103
|
Save -- where a bordered box competes with the thing it is next to. */
|
|
383
|
-
|
|
384
|
-
a.btn.ghost {
|
|
1104
|
+
.btn.ghost {
|
|
385
1105
|
background: transparent;
|
|
386
1106
|
border-color: transparent;
|
|
387
1107
|
color: var(--muted);
|
|
388
1108
|
}
|
|
389
1109
|
|
|
390
|
-
|
|
391
|
-
a.btn.ghost:hover:not([aria-disabled='true']) {
|
|
1110
|
+
.btn.ghost:hover:not(:disabled) {
|
|
392
1111
|
background: var(--panel-2);
|
|
393
1112
|
border-color: transparent;
|
|
394
1113
|
color: var(--text);
|
|
@@ -470,7 +1189,7 @@ a.btn.ghost:hover:not([aria-disabled='true']) {
|
|
|
470
1189
|
header.) */
|
|
471
1190
|
.row { display: flex; align-items: center; gap: var(--space-3); }
|
|
472
1191
|
|
|
473
|
-
.grow { flex: 1; min-width: 0; }
|
|
1192
|
+
.ctl-grow { flex: 1; min-width: 0; }
|
|
474
1193
|
|
|
475
1194
|
.mono { font-family: var(--font-mono); font-size: var(--text-sm); }
|
|
476
1195
|
|
|
@@ -534,10 +1253,17 @@ a.btn.ghost:hover:not([aria-disabled='true']) {
|
|
|
534
1253
|
/* A pill following a name needs the gap outside its own border. Leading
|
|
535
1254
|
whitespace inside the span puts it under the pill's background instead,
|
|
536
1255
|
which reads as the badge touching the word it qualifies. */
|
|
537
|
-
|
|
1256
|
+
/* A pill beside a name, and the one thing that keeps the pair working:
|
|
1257
|
+
`flex: none`, so the pill never shrinks and the name ellipsises instead.
|
|
1258
|
+
That was `rows.css`'s `.named > .pill`, which meant anybody laying out a
|
|
1259
|
+
name and its pills had to know a package class by name to get it. The
|
|
1260
|
+
variant already says "I am in a row"; it may as well say what that costs. */
|
|
1261
|
+
.row-pill { margin-left: var(--space-2); vertical-align: baseline; flex: none; }
|
|
538
1262
|
|
|
539
1263
|
/* The tile's only control. Dim until hovered: it is chrome on someone's app. */
|
|
540
1264
|
.icon-btn {
|
|
1265
|
+
/* Stated rather than inherited. These came from the `button, input, textarea, select` reset, which applied control styling to everything that happened to be a `<button>` -- so this rule spent its opening lines undoing it, and would break silently if that rule ever moved. It did move, to `.btn`. */
|
|
1266
|
+
font: inherit;
|
|
541
1267
|
display: inline-flex; align-items: center; padding: var(--space-1);
|
|
542
1268
|
background: none; border: 0; color: var(--muted); opacity: 0.6; cursor: pointer;
|
|
543
1269
|
}
|
|
@@ -603,19 +1329,17 @@ a.btn.ghost:hover:not([aria-disabled='true']) {
|
|
|
603
1329
|
transition: none;
|
|
604
1330
|
}
|
|
605
1331
|
|
|
606
|
-
|
|
607
|
-
a.btn.primary:active:not([aria-disabled='true']) {
|
|
1332
|
+
.btn.primary:active:not(:disabled) {
|
|
608
1333
|
background: color-mix(in srgb, var(--text) var(--press-ink), var(--accent));
|
|
609
1334
|
border-color: color-mix(in srgb, var(--text) var(--press-ink), var(--accent));
|
|
610
1335
|
}
|
|
611
1336
|
|
|
612
|
-
|
|
613
|
-
a.btn.ghost:active:not([aria-disabled='true']) {
|
|
1337
|
+
.btn.ghost:active:not(:disabled) {
|
|
614
1338
|
background: color-mix(in srgb, var(--text) var(--press-ink), var(--panel-2));
|
|
615
1339
|
border-color: transparent;
|
|
616
1340
|
}
|
|
617
1341
|
|
|
618
|
-
|
|
1342
|
+
.btn[aria-pressed='true']:active:not(:disabled) {
|
|
619
1343
|
background: color-mix(in srgb, var(--accent) 18%, var(--panel));
|
|
620
1344
|
}
|
|
621
1345
|
|
|
@@ -786,7 +1510,7 @@ input:active, textarea:active, select:active { transform: none; }
|
|
|
786
1510
|
|
|
787
1511
|
/* The top bar carries the title, the views and the way into settings. Nothing
|
|
788
1512
|
that belongs to a conversation lives here any more, so it can breathe. */
|
|
789
|
-
.topbar .grow { flex: 1; min-width: 0; }
|
|
1513
|
+
.topbar .ctl-grow { flex: 1; min-width: 0; }
|
|
790
1514
|
|
|
791
1515
|
/* Back on the left, Next on the right, with the gap between them doing the
|
|
792
1516
|
separating -- so the button that goes forward is in the same place on both
|
|
@@ -818,7 +1542,60 @@ input:active, textarea:active, select:active { transform: none; }
|
|
|
818
1542
|
to { opacity: 1; }
|
|
819
1543
|
}
|
|
820
1544
|
|
|
1545
|
+
/* The states the `button` element rule used to hand every bare `<button>` in
|
|
1546
|
+
the package, now asked for by name.
|
|
1547
|
+
*
|
|
1548
|
+
* This is the half of the decoupling that a screenshot cannot show: `:focus-visible`
|
|
1549
|
+
* is not photographed, so nine components would have lost their focus ring in
|
|
1550
|
+
* silence. `keyboard.spec.ts` is what actually holds this.
|
|
1551
|
+
*
|
|
1552
|
+
* `.btn` has its own, in the rules above. These are the ones that are a button
|
|
1553
|
+
* for their behaviour and not for their appearance -- a tab, a row, a card, a
|
|
1554
|
+
* pager step, a grid cell, a remove cross. */
|
|
1555
|
+
.tab:focus-visible,
|
|
1556
|
+
.row-hit:focus-visible,
|
|
1557
|
+
.card:focus-visible,
|
|
1558
|
+
.ident-remove:focus-visible,
|
|
1559
|
+
.size-cell:focus-visible,
|
|
1560
|
+
.pager-step:focus-visible,
|
|
1561
|
+
.pager-page:focus-visible,
|
|
1562
|
+
.sel-control:focus-visible {
|
|
1563
|
+
outline: 2px solid var(--accent);
|
|
1564
|
+
outline-offset: 2px;
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
/* `:disabled` came from the same rule. A control that cannot be pressed has to
|
|
1568
|
+
say so whatever element it is. */
|
|
1569
|
+
.tab:disabled,
|
|
1570
|
+
.row-hit:disabled,
|
|
1571
|
+
.card:disabled,
|
|
1572
|
+
.ident-remove:disabled,
|
|
1573
|
+
.size-cell:disabled,
|
|
1574
|
+
.pager-step:disabled,
|
|
1575
|
+
.pager-page:disabled,
|
|
1576
|
+
.sel-control:disabled {
|
|
1577
|
+
opacity: 0.45;
|
|
1578
|
+
cursor: not-allowed;
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
/* The anchor form's disabled states, alongside the button's.
|
|
1582
|
+
*
|
|
1583
|
+
* `.btn` is one class on two elements, and an `<a>` has no `:disabled` -- it
|
|
1584
|
+
* carries `aria-disabled` and a capture-phase click block instead. Every
|
|
1585
|
+
* rule above that reads `:disabled` needs the attribute twin, or a disabled
|
|
1586
|
+
* link is a link that looks pressable and refuses silently. Folding the old
|
|
1587
|
+
* `a.btn` twins into `.btn` dropped these, and the baselines showed a
|
|
1588
|
+
* disabled link at full strength. */
|
|
1589
|
+
.btn.primary[aria-disabled='true'] {
|
|
1590
|
+
background: var(--panel-2);
|
|
1591
|
+
border-color: var(--border);
|
|
1592
|
+
color: var(--muted);
|
|
1593
|
+
opacity: 1;
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
|
|
821
1597
|
/* ---- ./select.css ---- */
|
|
1598
|
+
@layer components {
|
|
822
1599
|
/* How big a control is, asked for rather than inherited.
|
|
823
1600
|
Four sizes existed and every one of them came from a descendant selector:
|
|
824
1601
|
`.set-row button` was 11px in 3px of padding, `.approval-actions button` was
|
|
@@ -833,8 +1610,7 @@ input:active, textarea:active, select:active { transform: none; }
|
|
|
833
1610
|
/* Full width, for the one action a card or a step is about. Not a size: a
|
|
834
1611
|
`block` button is the same height as any other, it just stops being a thing
|
|
835
1612
|
you have to aim at. */
|
|
836
|
-
|
|
837
|
-
a.btn.block { display: flex; width: 100%; }
|
|
1613
|
+
.btn.ctl-block { display: flex; width: 100%; }
|
|
838
1614
|
|
|
839
1615
|
/* The default is `size-md`, spelled once for every control.
|
|
840
1616
|
The paragraph above promised one scale for buttons, inputs and selects, and
|
|
@@ -842,13 +1618,24 @@ a.btn.block { display: flex; width: 100%; }
|
|
|
842
1618
|
input was eight pixels taller than the button beside it and no row of the two
|
|
843
1619
|
could line up. The download modal's search box against its Search button was
|
|
844
1620
|
the version you could see from across the room. */
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
input,
|
|
848
|
-
|
|
849
|
-
|
|
1621
|
+
/* `:where`, so this base carries no specificity of its own.
|
|
1622
|
+
*
|
|
1623
|
+
* It was `button, input, textarea, select` -- an element selector, which
|
|
1624
|
+
* `.size-sm` and every other class outranked without anyone thinking about
|
|
1625
|
+
* it. Moving it to `.btn` to stop a tab inheriting a control's look raised it
|
|
1626
|
+
* to a class, so it tied with `.size-sm` and won on source order: every
|
|
1627
|
+
* button came out `8px 12px` whatever size it asked for. `:where` puts it
|
|
1628
|
+
* back to zero, which is what the element selector was silently providing. */
|
|
1629
|
+
:where(.btn, input, textarea, select) { padding: var(--space-2) var(--space-3); }
|
|
1630
|
+
|
|
1631
|
+
/* The select's control keeps its padding at full class weight, and after
|
|
1632
|
+
`.size-sm` in the cascade, because that is where it has always been: this
|
|
1633
|
+
file is imported after `base.css`, so a `size`d select took the size's type
|
|
1634
|
+
and this padding. Folding it into the `:where` above handed the padding
|
|
1635
|
+
back to `.size-sm` and shrank every small select by seven pixels. */
|
|
850
1636
|
.sel-control { padding: var(--space-2) var(--space-3); }
|
|
851
1637
|
|
|
1638
|
+
|
|
852
1639
|
/* Centred on the whole block -- the caption and the sentence together -- rather
|
|
853
1640
|
than aligned to either end of it. `.field-row` pins to the bottom, which is
|
|
854
1641
|
right for a field beside a button and wrong beside two lines of prose. */
|
|
@@ -872,16 +1659,16 @@ select,
|
|
|
872
1659
|
.sel { position: relative; display: inline-block; }
|
|
873
1660
|
|
|
874
1661
|
/* The subject of its pane rather than a field in it: full width and a size up.
|
|
875
|
-
That was `.select-field.block` on the native element, and it carried the
|
|
1662
|
+
That was `.select-field.ctl-block` on the native element, and it carried the
|
|
876
1663
|
reason with it -- model ids are long (`qwen2.5-coder:32b-instruct-q4_K_M`) and
|
|
877
1664
|
at the narrow size they truncated mid-name. */
|
|
878
|
-
.sel.block { display: block; width: 100%; }
|
|
1665
|
+
.sel.ctl-block { display: block; width: 100%; }
|
|
879
1666
|
|
|
880
|
-
.sel.block .sel-control { padding: var(--space-2) var(--space-3); font-weight: 500; }
|
|
1667
|
+
.sel.ctl-block .sel-control { padding: var(--space-2) var(--space-3); font-weight: 500; }
|
|
881
1668
|
|
|
882
1669
|
/* Not full width otherwise: a select as wide as its row, holding one short
|
|
883
1670
|
word, reads as an input somebody forgot to fill in. */
|
|
884
|
-
.sel:not(.block) .sel-control { width: auto; max-width: 320px; }
|
|
1671
|
+
.sel:not(.ctl-block) .sel-control { width: auto; max-width: 320px; }
|
|
885
1672
|
|
|
886
1673
|
.sel-control {
|
|
887
1674
|
display: flex;
|
|
@@ -894,9 +1681,7 @@ select,
|
|
|
894
1681
|
background: var(--control);
|
|
895
1682
|
}
|
|
896
1683
|
|
|
897
|
-
.sel-
|
|
898
|
-
|
|
899
|
-
.sel-caret { flex: none; opacity: 0.6; transition: transform var(--dur-fast) var(--ease); }
|
|
1684
|
+
.sel-caret { transition: transform var(--dur-fast) var(--ease); }
|
|
900
1685
|
|
|
901
1686
|
.sel[data-open] .sel-caret { transform: rotate(180deg); }
|
|
902
1687
|
|
|
@@ -905,45 +1690,22 @@ select,
|
|
|
905
1690
|
/* State is read off React Aria's attributes: `data-open` on the root,
|
|
906
1691
|
`data-focused` / `data-selected` / `data-disabled` on an item, where
|
|
907
1692
|
`.open`, `[data-active]`, `.on` and `.off` used to be. */
|
|
1693
|
+
/* The list keeps two things the utilities on `Select` cannot say.
|
|
1694
|
+
*
|
|
1695
|
+
* `scroll-padding-block`: the same room while the list is scrolled as it has
|
|
1696
|
+
* at rest. Padding at the top of a scroll container scrolls away with the
|
|
1697
|
+
* content, so the row `scrollIntoView({block: 'nearest'})` brings up ended
|
|
1698
|
+
* flush against the border and read as clipped rather than as one of a set --
|
|
1699
|
+
* and this list opens scrolled to whatever is chosen, so that was the
|
|
1700
|
+
* ordinary state.
|
|
1701
|
+
*
|
|
1702
|
+
* `box-shadow`: `--shadow-2` is a token, and a utility would have to inline
|
|
1703
|
+
* the value, which is the one thing the vocabulary exists to stop. */
|
|
908
1704
|
.sel-list {
|
|
909
|
-
/* `fixed`, and in `document.body`: an ancestor that scrolls or hides its
|
|
910
|
-
overflow would otherwise clip it, which in this app means every settings
|
|
911
|
-
pane. Position comes from the button's measured rectangle. */
|
|
912
|
-
/* Positioned by React Aria -- inline `top`/`left` on a portalled popover
|
|
913
|
-
that flips when the edge is near. `position: fixed` and the measured
|
|
914
|
-
rectangle it was placed by are gone with the hand-rolled version. */
|
|
915
|
-
z-index: 60;
|
|
916
|
-
max-height: 280px;
|
|
917
|
-
overflow-y: auto;
|
|
918
|
-
margin: 0;
|
|
919
|
-
padding: var(--space-1);
|
|
920
|
-
/* The same room while the list is scrolled as it has at rest. Padding at
|
|
921
|
-
the top of a scroll container scrolls away with the content, so the row
|
|
922
|
-
`scrollIntoView({block: 'nearest'})` brings up ended flush against the
|
|
923
|
-
border and read as clipped rather than as one of a set -- and this list
|
|
924
|
-
opens scrolled to whatever is chosen, so that was the ordinary state.
|
|
925
|
-
`scroll-padding` insets what counts as "in view", so it stops short by
|
|
926
|
-
the same four the sides have. */
|
|
927
1705
|
scroll-padding-block: var(--space-1);
|
|
928
|
-
list-style: none;
|
|
929
|
-
border: var(--border-width) solid var(--border-strong);
|
|
930
|
-
border-radius: var(--radius-md);
|
|
931
|
-
background: var(--panel);
|
|
932
1706
|
box-shadow: var(--shadow-2);
|
|
933
1707
|
}
|
|
934
1708
|
|
|
935
|
-
.sel-item {
|
|
936
|
-
display: flex;
|
|
937
|
-
align-items: center;
|
|
938
|
-
gap: var(--space-2);
|
|
939
|
-
padding: var(--space-2) var(--space-2);
|
|
940
|
-
border-radius: var(--radius-sm);
|
|
941
|
-
cursor: pointer;
|
|
942
|
-
white-space: nowrap;
|
|
943
|
-
}
|
|
944
|
-
|
|
945
|
-
.sel-item-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
|
|
946
|
-
|
|
947
1709
|
/* Hover and keyboard land on the same row, because they are the same idea --
|
|
948
1710
|
two highlights for one cursor is how a list starts lying about where Enter
|
|
949
1711
|
will go. */
|
|
@@ -955,7 +1717,18 @@ select,
|
|
|
955
1717
|
|
|
956
1718
|
/* The tick marks the chosen row. Colour alone would not: a list where the only
|
|
957
1719
|
difference is a hue is a list you cannot read past. */
|
|
958
|
-
|
|
1720
|
+
/* The tick's resting state lives here, beside the state that overrides it.
|
|
1721
|
+
*
|
|
1722
|
+
* It was `opacity-0` on the element and `opacity: 1` here, which worked only
|
|
1723
|
+
* while this sheet was unlayered. A utility is in `@layer utilities` and
|
|
1724
|
+
* beats `@layer components` whatever the selector, so the moment the sheets
|
|
1725
|
+
* moved into a layer the tick stopped appearing on the selected row -- the
|
|
1726
|
+
* resting state won permanently.
|
|
1727
|
+
*
|
|
1728
|
+
* The rule generalises: a utility for a resting state whose active state is a
|
|
1729
|
+
* relationship between elements will always beat that active state. The pair
|
|
1730
|
+
* has to sit in the same layer. */
|
|
1731
|
+
.sel-tick { opacity: 0; }
|
|
959
1732
|
|
|
960
1733
|
.sel-item[data-selected] .sel-tick { opacity: 1; }
|
|
961
1734
|
|
|
@@ -991,24 +1764,23 @@ select,
|
|
|
991
1764
|
.field > input,
|
|
992
1765
|
.field > textarea,
|
|
993
1766
|
.field > .sel { width: 100%; }
|
|
1767
|
+
}
|
|
994
1768
|
|
|
995
1769
|
/* ---- ./dangerzone.css ---- */
|
|
1770
|
+
@layer components {
|
|
996
1771
|
/* Destructive, and legible as such standing still. */
|
|
997
|
-
|
|
998
|
-
a.btn.danger {
|
|
1772
|
+
.btn.danger {
|
|
999
1773
|
color: var(--bad);
|
|
1000
1774
|
border-color: color-mix(in srgb, var(--bad) 45%, var(--border-strong));
|
|
1001
1775
|
}
|
|
1002
1776
|
|
|
1003
|
-
|
|
1004
|
-
a.btn.danger:hover:not([aria-disabled='true']) {
|
|
1777
|
+
.btn.danger:hover:not(:disabled) {
|
|
1005
1778
|
background: color-mix(in srgb, var(--bad) 12%, var(--panel));
|
|
1006
1779
|
border-color: var(--bad);
|
|
1007
1780
|
color: var(--bad);
|
|
1008
1781
|
}
|
|
1009
1782
|
|
|
1010
|
-
|
|
1011
|
-
a.btn.danger:active:not([aria-disabled='true']) {
|
|
1783
|
+
.btn.danger:active:not(:disabled) {
|
|
1012
1784
|
background: color-mix(in srgb, var(--bad) 20%, var(--panel));
|
|
1013
1785
|
border-color: var(--bad);
|
|
1014
1786
|
}
|
|
@@ -1107,8 +1879,10 @@ a.btn.danger:active:not([aria-disabled='true']) {
|
|
|
1107
1879
|
controls in the same column at the same indent that do not line up read as
|
|
1108
1880
|
an accident rather than as a pair. */
|
|
1109
1881
|
.field-row > button { min-width: 9ch; }
|
|
1882
|
+
}
|
|
1110
1883
|
|
|
1111
1884
|
/* ---- ./callout.css ---- */
|
|
1885
|
+
@layer components {
|
|
1112
1886
|
/* One shape for everything that tells you something.
|
|
1113
1887
|
`.banner` and `.callout` were the same box drawn twice: a bordered, rounded,
|
|
1114
1888
|
12px panel with a tint. They differed in padding by a pixel in each direction
|
|
@@ -1247,35 +2021,50 @@ a.btn.danger:active:not([aria-disabled='true']) {
|
|
|
1247
2021
|
}
|
|
1248
2022
|
|
|
1249
2023
|
.callout button { flex: none; }
|
|
2024
|
+
}
|
|
1250
2025
|
|
|
1251
2026
|
/* ---- ./card.css ---- */
|
|
2027
|
+
@layer components {
|
|
2028
|
+
/* `.card` is public API, not this component's private styling.
|
|
2029
|
+
*
|
|
2030
|
+
* Consumers apply it to their own markup -- the gallery's skeleton specimen
|
|
2031
|
+
* renders `<div className="card">` around three rows, and app-template uses
|
|
2032
|
+
* `card-pick`. Moving the box into `Card`'s own class list took that away
|
|
2033
|
+
* with no type error and no failing test in this package: it broke only
|
|
2034
|
+
* where somebody else had used the class, which is the worst way for an API
|
|
2035
|
+
* to go.
|
|
2036
|
+
*
|
|
2037
|
+
* So the rule stays and `Card` wears it. The lesson generalises to every
|
|
2038
|
+
* class in this package that a consumer can reach: a component may draw
|
|
2039
|
+
* itself with utilities only where its class is genuinely private. */
|
|
1252
2040
|
.card {
|
|
2041
|
+
display: block;
|
|
2042
|
+
width: 100%;
|
|
2043
|
+
box-sizing: border-box;
|
|
2044
|
+
font: inherit;
|
|
2045
|
+
color: var(--text);
|
|
2046
|
+
text-align: left;
|
|
1253
2047
|
background: var(--panel);
|
|
1254
2048
|
border: var(--border-width) solid var(--border);
|
|
1255
2049
|
border-radius: var(--radius-md);
|
|
1256
|
-
padding: var(--space-3)
|
|
2050
|
+
padding: var(--space-3);
|
|
1257
2051
|
margin-bottom: var(--space-3);
|
|
1258
2052
|
}
|
|
1259
2053
|
|
|
2054
|
+
/* What is left once `Card` draws its own box: the tones, the pick and
|
|
2055
|
+
selected states, and the rules that reach from the card into what it
|
|
2056
|
+
holds. `:has(.card-icon) .card-inline` is a relationship, and a tone is a
|
|
2057
|
+
`color-mix`; neither is a property on one element. */
|
|
2058
|
+
|
|
1260
2059
|
/* Header, when there is one. The title and the line under it were retyped at
|
|
1261
2060
|
every call site and no two agreed on the gap between them. */
|
|
1262
|
-
.card-head { display: flex; align-items: flex-start; gap: var(--space-3); }
|
|
1263
|
-
|
|
1264
|
-
.card-head:not(:last-child) { margin-bottom: var(--space-3); }
|
|
1265
|
-
|
|
1266
|
-
.card-headings { min-width: 0; flex: 1; }
|
|
1267
|
-
|
|
1268
2061
|
/* The card owns the space between the things it holds. Without this a callout
|
|
1269
2062
|
and the button under it sit edge to edge, and every caller has to remember a
|
|
1270
2063
|
margin on whichever child happens to be second. */
|
|
1271
|
-
.card-body { display: grid; gap: var(--space-3); }
|
|
1272
|
-
|
|
1273
2064
|
/* The card's own control, on the card's padding rather than indented into its
|
|
1274
2065
|
body. Centred against the whole heading block, not against the title -- a
|
|
1275
2066
|
switch aligned to the first line drifts upward the moment the description
|
|
1276
2067
|
runs to two. */
|
|
1277
|
-
.card-action { flex: none; align-self: center; display: flex; align-items: center; }
|
|
1278
|
-
|
|
1279
2068
|
/* A row inside a card that lines up with the header rather than indenting past
|
|
1280
2069
|
it: same left edge as the title, same right edge as the action. Its label is
|
|
1281
2070
|
a quiet caption, not a second heading -- the card already has one, and two
|
|
@@ -1322,17 +2111,6 @@ a.btn.danger:active:not([aria-disabled='true']) {
|
|
|
1322
2111
|
color: var(--muted);
|
|
1323
2112
|
}
|
|
1324
2113
|
|
|
1325
|
-
/* A card that is itself the choice. Reset first, because it is a `<button>`
|
|
1326
|
-
now and inherits a control's padding and centring. */
|
|
1327
|
-
button.card {
|
|
1328
|
-
display: block;
|
|
1329
|
-
width: 100%;
|
|
1330
|
-
text-align: left;
|
|
1331
|
-
font: inherit;
|
|
1332
|
-
color: inherit;
|
|
1333
|
-
padding: var(--space-3);
|
|
1334
|
-
}
|
|
1335
|
-
|
|
1336
2114
|
/* Variants, because a card is doing four jobs and looked like one.
|
|
1337
2115
|
A search result you can act on, a thing already installed, something that
|
|
1338
2116
|
went wrong, and a heading with rows under it are not the same object, and
|
|
@@ -1375,7 +2153,23 @@ button.card {
|
|
|
1375
2153
|
|
|
1376
2154
|
.modal-body .card { background: var(--panel-2); }
|
|
1377
2155
|
|
|
2156
|
+
/* Selected, which used to arrive from `button[aria-pressed='true']`.
|
|
2157
|
+
*
|
|
2158
|
+
* A card marks its choice with `aria-pressed`, and the tint came from the
|
|
2159
|
+
* element rule every bare `<button>` in the package was picking up. That rule
|
|
2160
|
+
* belongs to `Button` now, so the card says what being chosen looks like --
|
|
2161
|
+
* which is the right place for it anyway: a chosen card is a card's idea, not
|
|
2162
|
+
* a button's. */
|
|
2163
|
+
.card[aria-pressed='true'] {
|
|
2164
|
+
border-color: var(--accent);
|
|
2165
|
+
background: color-mix(in srgb, var(--accent) 10%, var(--panel));
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2168
|
+
.card[aria-pressed='true']:hover { border-color: var(--accent); }
|
|
2169
|
+
}
|
|
2170
|
+
|
|
1378
2171
|
/* ---- ./toggle.css ---- */
|
|
2172
|
+
@layer components {
|
|
1379
2173
|
.card-action .switch-row { padding: 0; gap: var(--space-2); }
|
|
1380
2174
|
|
|
1381
2175
|
.card-action .switch-row .switch-body { flex: none; }
|
|
@@ -1606,8 +2400,10 @@ input[type='radio']:active:not(:disabled) {
|
|
|
1606
2400
|
@media (prefers-reduced-motion: reduce) {
|
|
1607
2401
|
.toggle-sweep::before { animation: none; background: color-mix(in oklab, var(--accent) 45%, transparent); }
|
|
1608
2402
|
}
|
|
2403
|
+
}
|
|
1609
2404
|
|
|
1610
2405
|
/* ---- ./skeleton.css ---- */
|
|
2406
|
+
@layer components {
|
|
1611
2407
|
.muted { color: var(--muted); }
|
|
1612
2408
|
|
|
1613
2409
|
.pulse-block {
|
|
@@ -1662,8 +2458,10 @@ input[type='radio']:active:not(:disabled) {
|
|
|
1662
2458
|
/* Still distinguishable from a real block of colour, and still still. */
|
|
1663
2459
|
.skel-pulse { animation: none; opacity: 0.8; }
|
|
1664
2460
|
}
|
|
2461
|
+
}
|
|
1665
2462
|
|
|
1666
2463
|
/* ---- ./rows.css ---- */
|
|
2464
|
+
@layer components {
|
|
1667
2465
|
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1668
2466
|
|
|
1669
2467
|
/* A name and the pills that qualify it, on one line, where the name is the only
|
|
@@ -1924,72 +2722,24 @@ input[type='radio']:active:not(:disabled) {
|
|
|
1924
2722
|
.row-hit:hover .truncate { color: var(--accent); }
|
|
1925
2723
|
|
|
1926
2724
|
.row-hit:focus-visible { outline: none; box-shadow: var(--focus-ring); }
|
|
1927
|
-
|
|
1928
|
-
/* ---- ./empty.css ---- */
|
|
1929
|
-
/* `Empty`: a list with nothing in it.
|
|
1930
|
-
|
|
1931
|
-
Quieter than `.empty`, which is a whole-screen state at `--space-10`. These
|
|
1932
|
-
sit inside a card that already has a heading and a description, so the same
|
|
1933
|
-
padding would leave a card that is mostly air about nothing.
|
|
1934
|
-
|
|
1935
|
-
Dashed rather than solid: a solid border reads as a thing, and the point of
|
|
1936
|
-
this box is that there is no thing. It marks out where the list will be. */
|
|
1937
|
-
.nothing {
|
|
1938
|
-
display: grid;
|
|
1939
|
-
justify-items: center;
|
|
1940
|
-
gap: var(--space-2);
|
|
1941
|
-
padding: var(--space-5) var(--space-4);
|
|
1942
|
-
border: var(--border-width) dashed var(--border-strong);
|
|
1943
|
-
border-radius: var(--radius-md);
|
|
1944
|
-
text-align: center;
|
|
1945
|
-
}
|
|
1946
|
-
|
|
1947
|
-
.nothing-mark { color: var(--muted); line-height: 0; }
|
|
1948
|
-
|
|
1949
|
-
/* The same box with a figure in it, for a whole surface rather than a slot in
|
|
1950
|
-
a card. Two things change and both follow from the size: the dashed outline
|
|
1951
|
-
goes, because an outline marks out where a list will be and a window-sized
|
|
1952
|
-
dashed rectangle reads as a layout that failed rather than a view with
|
|
1953
|
-
nothing on it; and the box centres itself in whatever it was dropped into,
|
|
1954
|
-
which is what makes it land in the middle of an empty dashboard rather than
|
|
1955
|
-
under the header. */
|
|
1956
|
-
.nothing-surface {
|
|
1957
|
-
border: none;
|
|
1958
|
-
padding: var(--space-10) var(--space-4);
|
|
1959
|
-
gap: var(--space-3);
|
|
1960
|
-
margin: auto;
|
|
1961
2725
|
}
|
|
1962
2726
|
|
|
1963
|
-
/* `currentColor` reaches the figure through the two rules the illustrations
|
|
1964
|
-
ship with, so the colour is set here and the drawing follows it -- the same
|
|
1965
|
-
grey as the sentence under it, in every theme.
|
|
1966
|
-
Two classes, not one: `.illo` sets `color: inherit` further down this file,
|
|
1967
|
-
which beats a single-class rule written earlier and drew the figure in full
|
|
1968
|
-
text black beside a muted sentence. */
|
|
1969
|
-
.nothing-surface .nothing-figure { color: var(--muted); }
|
|
1970
|
-
|
|
1971
|
-
/* `--text-sm`, not the `--text-xs` these lines used to be: it is a sentence
|
|
1972
|
-
somebody is meant to read, not a caption qualifying something else. */
|
|
1973
|
-
.nothing-said { margin: 0; color: var(--muted); font-size: var(--text-sm); line-height: 1.5; max-width: 46ch; }
|
|
1974
|
-
|
|
1975
|
-
.nothing-act { margin-top: var(--space-1); }
|
|
1976
|
-
|
|
1977
2727
|
/* ---- ./progress.css ---- */
|
|
2728
|
+
@layer components {
|
|
1978
2729
|
/* progress ----------------------------------------------------------- */
|
|
1979
2730
|
|
|
1980
|
-
/* The bar
|
|
2731
|
+
/* The bar itself: a track with a child it fills, an animation and a
|
|
2732
|
+
reduced-motion answer. A utility is a property on one element, so none of
|
|
2733
|
+
that is one -- `Progress` draws its own wrapper and head with utilities and
|
|
2734
|
+
this is what is left.
|
|
2735
|
+
|
|
2736
|
+
The bar sat 4px under its own label and flush against whatever was above
|
|
1981
2737
|
the whole block, so a download row read as four lines of text with a rule
|
|
1982
2738
|
drawn through the last one. The label is a caption for the bar and stays
|
|
1983
2739
|
close to it; the block as a whole is a separate statement from the row it
|
|
1984
2740
|
follows. */
|
|
1985
|
-
.progress { display: grid; gap: var(--space-1); }
|
|
1986
|
-
|
|
1987
2741
|
.card > .progress { margin-top: var(--space-3); }
|
|
1988
2742
|
|
|
1989
|
-
.progress-head { display: flex; align-items: baseline; gap: var(--space-2); font-size: var(--text-sm); }
|
|
1990
|
-
|
|
1991
|
-
.progress-detail { color: var(--muted); font-size: var(--text-xs); }
|
|
1992
|
-
|
|
1993
2743
|
.bar { height: 6px; background: var(--panel-2); border-radius: var(--radius-pill); overflow: hidden; }
|
|
1994
2744
|
|
|
1995
2745
|
.bar > i {
|
|
@@ -2017,12 +2767,22 @@ input[type='radio']:active:not(:disabled) {
|
|
|
2017
2767
|
/* Still distinguishable from empty, and from full. */
|
|
2018
2768
|
.bar-indeterminate > i { animation: none; width: 100%; opacity: 0.35; }
|
|
2019
2769
|
}
|
|
2770
|
+
}
|
|
2020
2771
|
|
|
2021
2772
|
/* ---- ./tabs.css ---- */
|
|
2773
|
+
@layer components {
|
|
2022
2774
|
/* ---------------------------------------------------------------- tabs */
|
|
2023
2775
|
.tabs { position: relative; display: flex; gap: var(--space-1); }
|
|
2024
2776
|
|
|
2025
2777
|
.tab {
|
|
2778
|
+
/* Layout the `button` element rule used to supply. A tab is a button for its behaviour, not its look, so it now says what it wants instead of taking a control's arrangement and undoing the rest. */
|
|
2779
|
+
display: inline-flex;
|
|
2780
|
+
align-items: center;
|
|
2781
|
+
justify-content: center;
|
|
2782
|
+
gap: var(--space-2);
|
|
2783
|
+
/* Stated rather than inherited. These came from the `button, input, textarea, select` reset, which applied control styling to everything that happened to be a `<button>` -- so this rule spent its opening lines undoing it, and would break silently if that rule ever moved. It did move, to `.btn`. */
|
|
2784
|
+
font: inherit;
|
|
2785
|
+
cursor: pointer;
|
|
2026
2786
|
position: relative;
|
|
2027
2787
|
z-index: 1;
|
|
2028
2788
|
background: transparent;
|
|
@@ -2111,8 +2871,10 @@ input[type='radio']:active:not(:disabled) {
|
|
|
2111
2871
|
}
|
|
2112
2872
|
|
|
2113
2873
|
.tabs-vertical .tab:active:not(:disabled) { border-color: transparent; }
|
|
2874
|
+
}
|
|
2114
2875
|
|
|
2115
2876
|
/* ---- ./toast.css ---- */
|
|
2877
|
+
@layer components {
|
|
2116
2878
|
/* ---------------------------------------------------------------- toasts */
|
|
2117
2879
|
.toasts {
|
|
2118
2880
|
position: fixed;
|
|
@@ -2179,7 +2941,41 @@ input[type='radio']:active:not(:disabled) {
|
|
|
2179
2941
|
.toast[data-exiting] { animation: none; }
|
|
2180
2942
|
}
|
|
2181
2943
|
|
|
2944
|
+
/* The dismiss control, in its own words.
|
|
2945
|
+
*
|
|
2946
|
+
* It was `className="ghost size-sm"` -- `Button`'s vocabulary, borrowed from
|
|
2947
|
+
* a component that does not render a `Button`. That only ever worked because
|
|
2948
|
+
* `.ghost` and `.size-sm` were element-and-class rules any `<button>` could
|
|
2949
|
+
* pick up, which is the coupling this pass is removing. Nothing photographed
|
|
2950
|
+
* it, either: the toast is transient and the close button is not in any
|
|
2951
|
+
* baseline, so this would have gone quiet. */
|
|
2952
|
+
.toast-close {
|
|
2953
|
+
display: inline-flex;
|
|
2954
|
+
align-items: center;
|
|
2955
|
+
justify-content: center;
|
|
2956
|
+
font: inherit;
|
|
2957
|
+
font-size: var(--text-xs);
|
|
2958
|
+
padding: var(--space-1) var(--space-2);
|
|
2959
|
+
background: transparent;
|
|
2960
|
+
border: var(--border-width) solid transparent;
|
|
2961
|
+
border-radius: var(--radius);
|
|
2962
|
+
color: var(--muted);
|
|
2963
|
+
cursor: pointer;
|
|
2964
|
+
}
|
|
2965
|
+
|
|
2966
|
+
.toast-close:hover:not(:disabled) {
|
|
2967
|
+
background: var(--panel-2);
|
|
2968
|
+
color: var(--text);
|
|
2969
|
+
}
|
|
2970
|
+
|
|
2971
|
+
.toast-close:focus-visible {
|
|
2972
|
+
outline: 2px solid var(--accent);
|
|
2973
|
+
outline-offset: 2px;
|
|
2974
|
+
}
|
|
2975
|
+
}
|
|
2976
|
+
|
|
2182
2977
|
/* ---- ./modal.css ---- */
|
|
2978
|
+
@layer components {
|
|
2183
2979
|
/* modal --------------------------------------------------------------- */
|
|
2184
2980
|
|
|
2185
2981
|
/* `hidden` needs saying out loud here. The browser's own `[hidden]` rule is a
|
|
@@ -2219,13 +3015,6 @@ input[type='radio']:active:not(:disabled) {
|
|
|
2219
3015
|
Not `display: contents`, which was the first attempt. An element with no box
|
|
2220
3016
|
cannot take focus, so React Aria's initial focus fell through to the first
|
|
2221
3017
|
input and Escape -- handled on the section -- stopped closing the window. */
|
|
2222
|
-
.modal-dialog {
|
|
2223
|
-
display: flex;
|
|
2224
|
-
flex-direction: column;
|
|
2225
|
-
min-height: 0;
|
|
2226
|
-
flex: 1;
|
|
2227
|
-
}
|
|
2228
|
-
|
|
2229
3018
|
.modal {
|
|
2230
3019
|
background: var(--panel);
|
|
2231
3020
|
border: 1px solid var(--border);
|
|
@@ -2276,18 +3065,9 @@ input[type='radio']:active:not(:disabled) {
|
|
|
2276
3065
|
laid out for the bare `<strong>` it used to hold -- 86px tall with them,
|
|
2277
3066
|
41px without, on a head whose padding is 12 over 8. `font: inherit` so the
|
|
2278
3067
|
`<strong>` rule above is the one that sets the size. */
|
|
2279
|
-
.modal-title { margin: 0; font: inherit; }
|
|
2280
|
-
|
|
2281
3068
|
/* Under the title, on the header's padding rather than the body's, so it reads
|
|
2282
3069
|
as part of the heading rather than as the first line of content. */
|
|
2283
|
-
.modal-desc {
|
|
2284
|
-
margin: 0;
|
|
2285
|
-
padding: 0 var(--space-4) var(--space-3);
|
|
2286
|
-
color: var(--muted);
|
|
2287
|
-
font-size: var(--text-sm);
|
|
2288
|
-
line-height: 1.5;
|
|
2289
|
-
max-width: 62ch;
|
|
2290
|
-
}
|
|
3070
|
+
.modal-desc { line-height: 1.5; }
|
|
2291
3071
|
|
|
2292
3072
|
.modal-body { padding: var(--space-2) var(--space-4) var(--space-3); overflow-y: auto; }
|
|
2293
3073
|
|
|
@@ -2426,8 +3206,10 @@ input[type='radio']:active:not(:disabled) {
|
|
|
2426
3206
|
.modal.sheet[data-entering],
|
|
2427
3207
|
.modal.sheet[data-exiting] { animation: none; }
|
|
2428
3208
|
}
|
|
3209
|
+
}
|
|
2429
3210
|
|
|
2430
3211
|
/* ---- ./slider.css ---- */
|
|
3212
|
+
@layer components {
|
|
2431
3213
|
/* slider ----------------------------------------------------------------- */
|
|
2432
3214
|
/* A number from a range -- `Slider.tsx` says when one is the right control.
|
|
2433
3215
|
The row is laid out like a switch row: words on the left, the control on the
|
|
@@ -2647,9 +3429,12 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
|
|
|
2647
3429
|
buttons only, so a button in a row stood 25px beside a 35px select and no
|
|
2648
3430
|
size class could ask for the select's height. Type from the row, box from
|
|
2649
3431
|
the scale, and the two line up; an explicit `size-*` still wins. */
|
|
2650
|
-
:where(.set-row) button,
|
|
3432
|
+
:where(.set-row) button,
|
|
3433
|
+
:where(.set-row) .slider-box { font-size: var(--text-xs); }
|
|
3434
|
+
}
|
|
2651
3435
|
|
|
2652
3436
|
/* ---- ./checkbox.css ---- */
|
|
3437
|
+
@layer components {
|
|
2653
3438
|
/* A row you choose. There is no checkbox in it.
|
|
2654
3439
|
Every one of the fourteen in this app sits beside a name and a line of
|
|
2655
3440
|
explanation, so the row was always the thing being designed and the 17px
|
|
@@ -2819,36 +3604,36 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
|
|
|
2819
3604
|
.choice[data-disabled] .choice-why { opacity: 0.5; }
|
|
2820
3605
|
|
|
2821
3606
|
.choice[data-disabled]::after { opacity: 0.4; }
|
|
3607
|
+
}
|
|
2822
3608
|
|
|
2823
3609
|
/* ---- ./table.css ---- */
|
|
3610
|
+
@layer components {
|
|
2824
3611
|
/* A second line under a row's name, inside the `<th scope="row">` that makes it
|
|
2825
3612
|
one. The cell is bold because it is a heading; what hangs under it is not,
|
|
2826
3613
|
and inherited the weight -- so a pinned version read as loud as the thing it
|
|
2827
3614
|
versions. */
|
|
2828
|
-
.table th .set-hint { font-weight: 400; }
|
|
2829
|
-
|
|
2830
|
-
.table-scroll { overflow-x: auto; }
|
|
3615
|
+
.data-table th .set-hint { font-weight: 400; }
|
|
2831
3616
|
|
|
2832
|
-
.table {
|
|
3617
|
+
.data-table {
|
|
2833
3618
|
width: 100%;
|
|
2834
3619
|
border-collapse: collapse;
|
|
2835
3620
|
font-size: var(--text-sm);
|
|
2836
3621
|
}
|
|
2837
3622
|
|
|
2838
|
-
.table th,
|
|
2839
|
-
.table td {
|
|
3623
|
+
.data-table th,
|
|
3624
|
+
.data-table td {
|
|
2840
3625
|
text-align: left;
|
|
2841
3626
|
padding: var(--space-2) var(--space-3);
|
|
2842
3627
|
border-bottom: var(--border-width) solid var(--border);
|
|
2843
3628
|
}
|
|
2844
3629
|
|
|
2845
|
-
.table th:first-child,
|
|
2846
|
-
.table td:first-child { padding-left: 0; }
|
|
3630
|
+
.data-table th:first-child,
|
|
3631
|
+
.data-table td:first-child { padding-left: 0; }
|
|
2847
3632
|
|
|
2848
|
-
.table th:last-child,
|
|
2849
|
-
.table td:last-child { padding-right: 0; }
|
|
3633
|
+
.data-table th:last-child,
|
|
3634
|
+
.data-table td:last-child { padding-right: 0; }
|
|
2850
3635
|
|
|
2851
|
-
.table thead th {
|
|
3636
|
+
.data-table thead th {
|
|
2852
3637
|
font-size: var(--text-xs);
|
|
2853
3638
|
font-weight: var(--weight-strong);
|
|
2854
3639
|
text-transform: uppercase;
|
|
@@ -2859,78 +3644,69 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
|
|
|
2859
3644
|
|
|
2860
3645
|
/* The row's own name: a `<th scope="row">`, so it carries weight rather than
|
|
2861
3646
|
reading as one more cell. */
|
|
2862
|
-
.table tbody th { font-weight: var(--weight-strong); }
|
|
3647
|
+
.data-table tbody th { font-weight: var(--weight-strong); }
|
|
2863
3648
|
|
|
2864
|
-
.table tbody tr:last-child th,
|
|
2865
|
-
.table tbody tr:last-child td { border-bottom: none; }
|
|
3649
|
+
.data-table tbody tr:last-child th,
|
|
3650
|
+
.data-table tbody tr:last-child td { border-bottom: none; }
|
|
2866
3651
|
|
|
2867
3652
|
/* Numbers compare by column, so they align right and hold their tracks --
|
|
2868
3653
|
proportional digits shift the alignment by a pixel per glyph, which is
|
|
2869
3654
|
exactly the comparison the column was for. */
|
|
2870
|
-
.table .num { text-align: right; font-variant-numeric: tabular-nums; font-family: var(--font-mono); }
|
|
3655
|
+
.data-table .num { text-align: right; font-variant-numeric: tabular-nums; font-family: var(--font-mono); }
|
|
2871
3656
|
|
|
2872
|
-
.table thead th[style*='right'] { text-align: right; }
|
|
3657
|
+
.data-table thead th[style*='right'] { text-align: right; }
|
|
3658
|
+
}
|
|
2873
3659
|
|
|
2874
3660
|
/* ---- ./sizegrid.css ---- */
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
3661
|
+
@layer components {
|
|
3662
|
+
/* The cell's colour, all of it, in one place.
|
|
3663
|
+
*
|
|
3664
|
+
* `SizeGrid` draws the cell's geometry with utilities and leaves every colour
|
|
3665
|
+
* here, because `on` and `chosen` override the resting state -- and a utility
|
|
3666
|
+
* is in `@layer utilities`, which beats `@layer components` whatever the
|
|
3667
|
+
* selector. Stated as `surface-panel-2` and `border-border` on the element,
|
|
3668
|
+
* the resting state won permanently and no cell ever lit up.
|
|
3669
|
+
*
|
|
3670
|
+
* That is the third time this pattern has bitten: `Select`'s tick and
|
|
3671
|
+
* `Empty`'s figure were the other two. The rule: a resting state whose
|
|
3672
|
+
* active state is a CSS rule has to be a CSS rule too. */
|
|
2880
3673
|
.size-cell {
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
background: var(--panel-2); cursor: pointer;
|
|
3674
|
+
border: var(--border-width) solid var(--border);
|
|
3675
|
+
background: var(--panel-2);
|
|
2884
3676
|
}
|
|
2885
3677
|
|
|
2886
3678
|
/* `on` follows the pointer; `chosen` is what is actually saved, shown only
|
|
2887
3679
|
when nothing is hovered so the two can never contradict each other. */
|
|
2888
|
-
.size-cell.on {
|
|
3680
|
+
.size-cell.on {
|
|
3681
|
+
border-color: var(--accent);
|
|
3682
|
+
background: color-mix(in srgb, var(--accent) 45%, transparent);
|
|
3683
|
+
}
|
|
2889
3684
|
|
|
2890
3685
|
.size-cell.chosen { border-color: var(--accent); }
|
|
2891
|
-
|
|
2892
|
-
.size-cell:disabled { cursor: default; opacity: 0.5; }
|
|
2893
|
-
|
|
2894
|
-
.size-ceiling { opacity: 0.55; }
|
|
3686
|
+
}
|
|
2895
3687
|
|
|
2896
3688
|
/* ---- ./tooltip.css ---- */
|
|
3689
|
+
@layer components {
|
|
2897
3690
|
/* A callout: something worth knowing, with nothing to answer. Distinct from a
|
|
2898
3691
|
`?`, which is an offer to read more, and from a banner, which is a problem.
|
|
2899
3692
|
The mark is a round `i` rather than an emoji so it takes the theme's colours
|
|
2900
3693
|
and stays the same size as the text beside it. */
|
|
2901
|
-
/* An info-toned `.callout`, spelled the old way. Identical to it now rather
|
|
2902
|
-
nearly identical to it, which is the whole point of the consolidation
|
|
2903
|
-
|
|
2904
|
-
|
|
3694
|
+
/* An info-toned `.callout`, spelled the old way. Identical to it now rather
|
|
3695
|
+
than nearly identical to it, which is the whole point of the consolidation.
|
|
3696
|
+
(This comment has been unterminated since before the Tailwind branch -- it
|
|
3697
|
+
stops mid-sentence and never closes, so the CSS parser merged it with the
|
|
3698
|
+
one below and recovered. Nothing was lost from the stylesheet; the rest of
|
|
3699
|
+
the sentence was. Closed here rather than guessed at.) */
|
|
3700
|
+
|
|
3701
|
+
/* What is left once `Tooltip` draws its own mark: the hover and focus that
|
|
3702
|
+
reach the mark from its parent, and the tip -- whose closed and open
|
|
3703
|
+
states are three rules the cascade resolves in order, with
|
|
3704
|
+
`data-entering` and `data-exiting` around the transition. None of that is
|
|
3705
|
+
a property on one element.
|
|
3706
|
+
|
|
3707
|
+
The `?` beside a setting, and the box it shows on hover. Built like the
|
|
2905
3708
|
status dot's tooltip and for the same reasons: `title` waits a second and a
|
|
2906
3709
|
half, renders newlines however it likes, and cannot be styled. */
|
|
2907
|
-
.explain {
|
|
2908
|
-
position: relative;
|
|
2909
|
-
flex: none;
|
|
2910
|
-
display: inline-flex;
|
|
2911
|
-
align-items: center;
|
|
2912
|
-
/* The heading it follows is tracked out, which leaves the last letter's
|
|
2913
|
-
spacing sitting between them and reads as none at all. */
|
|
2914
|
-
margin-left: var(--space-2);
|
|
2915
|
-
cursor: help;
|
|
2916
|
-
/* Headings here are uppercase and tracked out, and one of these sits inside
|
|
2917
|
-
a heading. */
|
|
2918
|
-
text-transform: none;
|
|
2919
|
-
letter-spacing: normal;
|
|
2920
|
-
font-weight: 400;
|
|
2921
|
-
}
|
|
2922
|
-
|
|
2923
|
-
.explain-mark {
|
|
2924
|
-
width: 18px;
|
|
2925
|
-
height: 18px;
|
|
2926
|
-
border-radius: 50%;
|
|
2927
|
-
border: 1px solid var(--border);
|
|
2928
|
-
color: var(--muted);
|
|
2929
|
-
font-size: var(--text-xs);
|
|
2930
|
-
line-height: 16px;
|
|
2931
|
-
text-align: center;
|
|
2932
|
-
}
|
|
2933
|
-
|
|
2934
3710
|
.explain:hover .explain-mark,
|
|
2935
3711
|
.explain:focus-visible .explain-mark { color: var(--text); border-color: var(--accent); }
|
|
2936
3712
|
|
|
@@ -3003,8 +3779,10 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
|
|
|
3003
3779
|
}
|
|
3004
3780
|
|
|
3005
3781
|
.explain-tip strong { color: var(--text); font-weight: 600; }
|
|
3782
|
+
}
|
|
3006
3783
|
|
|
3007
3784
|
/* ---- ./illustration.css ---- */
|
|
3785
|
+
@layer components {
|
|
3008
3786
|
/* illustrations -------------------------------------------------------- */
|
|
3009
3787
|
|
|
3010
3788
|
/* Open Peeps, two colours, wearing whatever the theme is.
|
|
@@ -3031,7 +3809,21 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
|
|
|
3031
3809
|
a shirt that lets the arm behind it show through reads as a hole. */
|
|
3032
3810
|
.illo .paper { fill: var(--illo-paper); }
|
|
3033
3811
|
|
|
3812
|
+
/* The figure in a whole-surface `Empty`, drawn in the muted grey of the
|
|
3813
|
+
sentence under it.
|
|
3814
|
+
*
|
|
3815
|
+
* A utility cannot do this, and the reason is worth keeping: `.illo` sets
|
|
3816
|
+
* `color: inherit` and is unlayered, while every Tailwind utility lives in
|
|
3817
|
+
* `@layer utilities` -- and an unlayered declaration beats a layered one
|
|
3818
|
+
* whatever the specificity. So `text-muted` on the figure lost, silently,
|
|
3819
|
+
* and the shirt came out full text black beside a muted sentence. The
|
|
3820
|
+
* original rule already carried a note about needing two classes to beat
|
|
3821
|
+
* `.illo`; layers make that impossible rather than merely fiddly. */
|
|
3822
|
+
.nothing-figure { color: var(--muted); }
|
|
3823
|
+
}
|
|
3824
|
+
|
|
3034
3825
|
/* ---- ./field.css ---- */
|
|
3826
|
+
@layer components {
|
|
3035
3827
|
/* fields --------------------------------------------------------------- */
|
|
3036
3828
|
|
|
3037
3829
|
/* Label, description, input, error -- in the order they are wanted. The
|
|
@@ -3129,7 +3921,7 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
|
|
|
3129
3921
|
.adorned > .adorned-mark,
|
|
3130
3922
|
.adorned > .adorned-end { grid-area: 1 / 1; }
|
|
3131
3923
|
|
|
3132
|
-
.adorned.block { width: 100%; }
|
|
3924
|
+
.adorned.ctl-block { width: 100%; }
|
|
3133
3925
|
|
|
3134
3926
|
.adorned > .adorned-mark {
|
|
3135
3927
|
justify-self: start;
|
|
@@ -3182,7 +3974,34 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
|
|
|
3182
3974
|
|
|
3183
3975
|
.adorned-lg .adorned-clear { padding: var(--space-2); }
|
|
3184
3976
|
|
|
3977
|
+
/* The eye and the clear button stop borrowing `ghost`.
|
|
3978
|
+
*
|
|
3979
|
+
* Both were `className="icon-btn ghost …"` -- reaching into `Button`'s class
|
|
3980
|
+
* vocabulary from another component, which worked only because `.ghost` was
|
|
3981
|
+
* written as `button.ghost` and they happen to be `<button>`s. It is `.btn.ghost`
|
|
3982
|
+
* now, so the borrowing stopped matching and `.icon-btn`'s panel background
|
|
3983
|
+
* came through: the baselines showed a filled tile where there had been a bare
|
|
3984
|
+
* glyph.
|
|
3985
|
+
*
|
|
3986
|
+
* Stated here instead. What they actually wanted from `ghost` is two lines,
|
|
3987
|
+
* and saying them is cheaper than either component knowing what a button's
|
|
3988
|
+
* classes are called. */
|
|
3989
|
+
.secret-eye,
|
|
3990
|
+
.adorned-clear {
|
|
3991
|
+
background: transparent;
|
|
3992
|
+
border-color: transparent;
|
|
3993
|
+
color: var(--muted);
|
|
3994
|
+
}
|
|
3995
|
+
|
|
3996
|
+
.secret-eye:hover:not(:disabled),
|
|
3997
|
+
.adorned-clear:hover:not(:disabled) {
|
|
3998
|
+
background: var(--panel-2);
|
|
3999
|
+
color: var(--text);
|
|
4000
|
+
}
|
|
4001
|
+
}
|
|
4002
|
+
|
|
3185
4003
|
/* ---- ./tour.css ---- */
|
|
4004
|
+
@layer components {
|
|
3186
4005
|
/* tour ----------------------------------------------------------------- */
|
|
3187
4006
|
|
|
3188
4007
|
/* The layer sits over everything and catches nothing: the scrim is painted by
|
|
@@ -3244,141 +4063,41 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
|
|
|
3244
4063
|
.tour-actions { display: flex; align-items: center; gap: var(--space-2); margin-top: var(--space-2); }
|
|
3245
4064
|
|
|
3246
4065
|
.tour-count { color: var(--muted); font-size: var(--text-xs); }
|
|
4066
|
+
}
|
|
3247
4067
|
|
|
3248
4068
|
/* The mail and forum shell, added in 0.4.0. After the rest, because the
|
|
3249
4069
|
anchored surfaces (`.pop`, `.menu-sheet`, `.cmd`) sit over everything and a
|
|
3250
4070
|
rule of equal specificity that came earlier would lose to whatever the
|
|
3251
4071
|
sheets they cover happen to set. */
|
|
3252
|
-
/* ---- ./kbd.css ---- */
|
|
3253
|
-
/* One rule where there were two identical ones, in `menu.css` and
|
|
3254
|
-
`command.css`. Both keep their class as well, so `Menu` and `Command` are
|
|
3255
|
-
`.kbd .menu-key` and `.kbd .cmd-key` now: the declarations are the same, so
|
|
3256
|
-
nothing moves, and the context classes stay available for a rule that ever
|
|
3257
|
-
needs to tell the two apart. */
|
|
3258
|
-
.kbd {
|
|
3259
|
-
flex: none;
|
|
3260
|
-
font-family: var(--font-mono);
|
|
3261
|
-
font-size: var(--text-2xs);
|
|
3262
|
-
color: var(--muted);
|
|
3263
|
-
letter-spacing: var(--tracking);
|
|
3264
|
-
}
|
|
3265
|
-
|
|
3266
4072
|
/* ---- ./stat.css ---- */
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
.
|
|
3270
|
-
|
|
3271
|
-
gap: var(--space-1);
|
|
3272
|
-
padding: var(--space-4);
|
|
3273
|
-
border: var(--border-width) solid var(--border);
|
|
3274
|
-
border-radius: var(--radius-md);
|
|
3275
|
-
background: var(--panel);
|
|
3276
|
-
}
|
|
4073
|
+
@layer components {
|
|
4074
|
+
/* What the utilities on `Stat` cannot say: a tone on the tile colouring the
|
|
4075
|
+
figure inside it. An attribute on the parent selecting a child is a
|
|
4076
|
+
relationship; a utility is a property on one element.
|
|
3277
4077
|
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
.stat-bare {
|
|
3281
|
-
padding: 0;
|
|
3282
|
-
border: 0;
|
|
3283
|
-
border-radius: 0;
|
|
3284
|
-
background: none;
|
|
3285
|
-
gap: 0;
|
|
3286
|
-
line-height: 1.25;
|
|
3287
|
-
}
|
|
3288
|
-
|
|
3289
|
-
.stat > p { margin: 0; }
|
|
3290
|
-
|
|
3291
|
-
.stat-label {
|
|
3292
|
-
color: var(--muted);
|
|
3293
|
-
font-size: var(--text-xs);
|
|
3294
|
-
}
|
|
3295
|
-
|
|
3296
|
-
/* Tabular figures are the point: a column of numbers is compared by its
|
|
3297
|
-
digits' positions, and proportional ones move them per row. */
|
|
3298
|
-
.stat-value {
|
|
3299
|
-
font-size: var(--text-lg);
|
|
3300
|
-
font-weight: var(--weight-strong);
|
|
3301
|
-
font-variant-numeric: tabular-nums;
|
|
3302
|
-
}
|
|
3303
|
-
|
|
3304
|
-
.stat-bare .stat-value { font-size: var(--text-sm); }
|
|
3305
|
-
|
|
3306
|
-
.stat-note {
|
|
3307
|
-
color: var(--muted);
|
|
3308
|
-
font-size: var(--text-xs);
|
|
3309
|
-
}
|
|
3310
|
-
|
|
3311
|
-
/* Only the figure takes the colour. Colouring the label too makes the tile a
|
|
3312
|
-
status box, and a tone here is a remark about the number. */
|
|
4078
|
+
Only the figure takes the colour. Colouring the label too makes the tile a
|
|
4079
|
+
status box, where a tone here is a remark about the number. */
|
|
3313
4080
|
.stat[data-tone='info'] .stat-value { color: var(--info); }
|
|
3314
4081
|
.stat[data-tone='good'] .stat-value { color: var(--good); }
|
|
3315
4082
|
.stat[data-tone='warn'] .stat-value { color: var(--warn); }
|
|
3316
4083
|
.stat[data-tone='bad'] .stat-value { color: var(--bad); }
|
|
3317
|
-
|
|
3318
|
-
/* ---- ./shell.css ---- */
|
|
3319
|
-
/* The frame. Layout only: every colour and every step is a token, and the
|
|
3320
|
-
page inside it owns its own spacing. */
|
|
3321
|
-
.shell {
|
|
3322
|
-
display: flex;
|
|
3323
|
-
flex-direction: column;
|
|
3324
|
-
min-height: 100vh;
|
|
3325
|
-
background: var(--bg);
|
|
3326
|
-
color: var(--text);
|
|
3327
4084
|
}
|
|
3328
4085
|
|
|
3329
|
-
.
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
and `main-wide` as separate classes. */
|
|
4086
|
+
/* ---- ./shell.css ---- */
|
|
4087
|
+
@layer components {
|
|
4088
|
+
/* The measure, and only the measure.
|
|
4089
|
+
*
|
|
4090
|
+
* `Shell` draws itself with utilities -- it is layout and nothing else. What
|
|
4091
|
+
* stays here is the one value the header band, the nav band and the main band
|
|
4092
|
+
* all have to agree on: a custom property, so an app changes it in one place
|
|
4093
|
+
* rather than overriding three rules and missing the fourth. That is how
|
|
4094
|
+
* manage ended up carrying `head-inner-wide` and `main-wide` as separate
|
|
4095
|
+
* classes it had to remember together. */
|
|
3340
4096
|
.shell {
|
|
3341
4097
|
--shell-measure: 64rem;
|
|
3342
4098
|
--shell-measure-wide: 90rem;
|
|
3343
4099
|
}
|
|
3344
4100
|
|
|
3345
|
-
.shell-head-inner,
|
|
3346
|
-
.shell-nav,
|
|
3347
|
-
.shell-main {
|
|
3348
|
-
width: 100%;
|
|
3349
|
-
max-width: var(--shell-measure);
|
|
3350
|
-
margin-inline: auto;
|
|
3351
|
-
padding-inline: var(--space-4);
|
|
3352
|
-
}
|
|
3353
|
-
|
|
3354
|
-
.shell-wide { max-width: var(--shell-measure-wide); }
|
|
3355
|
-
|
|
3356
|
-
.shell-head-inner {
|
|
3357
|
-
display: flex;
|
|
3358
|
-
align-items: center;
|
|
3359
|
-
justify-content: space-between;
|
|
3360
|
-
gap: var(--space-4);
|
|
3361
|
-
padding-block: var(--space-3);
|
|
3362
|
-
min-width: 0;
|
|
3363
|
-
}
|
|
3364
|
-
|
|
3365
|
-
.shell-who {
|
|
3366
|
-
display: flex;
|
|
3367
|
-
align-items: center;
|
|
3368
|
-
gap: var(--space-3);
|
|
3369
|
-
min-width: 0;
|
|
3370
|
-
}
|
|
3371
|
-
|
|
3372
|
-
.shell-nav { padding-bottom: var(--space-2); }
|
|
3373
|
-
|
|
3374
|
-
.shell-main {
|
|
3375
|
-
flex: 1;
|
|
3376
|
-
padding-block: var(--space-6);
|
|
3377
|
-
/* `min-width: 0` because a flex child will not shrink below its content,
|
|
3378
|
-
and one wide table inside then pushes the whole page sideways. */
|
|
3379
|
-
min-width: 0;
|
|
3380
|
-
}
|
|
3381
|
-
|
|
3382
4101
|
/* The label beside the theme control, when it is drawn. */
|
|
3383
4102
|
.theme-switch {
|
|
3384
4103
|
display: flex;
|
|
@@ -3392,8 +4111,10 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
|
|
|
3392
4111
|
font-size: var(--text-sm);
|
|
3393
4112
|
white-space: nowrap;
|
|
3394
4113
|
}
|
|
4114
|
+
}
|
|
3395
4115
|
|
|
3396
4116
|
/* ---- ./scrollarea.css ---- */
|
|
4117
|
+
@layer components {
|
|
3397
4118
|
/* A box that scrolls, with its edges drawn.
|
|
3398
4119
|
|
|
3399
4120
|
The fades are `::before`/`::after` on the scroller itself, pinned with
|
|
@@ -3486,8 +4207,10 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
|
|
|
3486
4207
|
.scroller.faded::before,
|
|
3487
4208
|
.scroller.faded::after { transition: none; }
|
|
3488
4209
|
}
|
|
4210
|
+
}
|
|
3489
4211
|
|
|
3490
4212
|
/* ---- ./splitpane.css ---- */
|
|
4213
|
+
@layer components {
|
|
3491
4214
|
/* Two panes and the handle between them. */
|
|
3492
4215
|
.split {
|
|
3493
4216
|
display: flex;
|
|
@@ -3587,8 +4310,10 @@ body.splitting * { cursor: inherit !important; }
|
|
|
3587
4310
|
@media (prefers-reduced-motion: reduce) {
|
|
3588
4311
|
.split-grip { transition: none; }
|
|
3589
4312
|
}
|
|
4313
|
+
}
|
|
3590
4314
|
|
|
3591
4315
|
/* ---- ./popover.css ---- */
|
|
4316
|
+
@layer components {
|
|
3592
4317
|
/* A small surface anchored to what opened it. Same sheet as the select's list,
|
|
3593
4318
|
because they are the same object -- something that appeared over the page,
|
|
3594
4319
|
attached to a control. */
|
|
@@ -3642,29 +4367,17 @@ body.splitting * { cursor: inherit !important; }
|
|
|
3642
4367
|
.pop[data-entering],
|
|
3643
4368
|
.pop[data-exiting] { animation: none; }
|
|
3644
4369
|
}
|
|
3645
|
-
|
|
3646
|
-
/* ---- ./menu.css ---- */
|
|
3647
|
-
/* A list of verbs, on the same sheet as every other anchored surface. */
|
|
3648
|
-
.menu-sheet {
|
|
3649
|
-
background: var(--panel);
|
|
3650
|
-
border: var(--border-width) solid var(--border);
|
|
3651
|
-
border-radius: var(--radius-md);
|
|
3652
|
-
box-shadow: var(--shadow-2);
|
|
3653
|
-
min-width: 12rem;
|
|
3654
|
-
max-width: min(20rem, calc(100vw - var(--space-6)));
|
|
3655
|
-
max-height: 24rem;
|
|
3656
|
-
overflow: auto;
|
|
3657
|
-
overscroll-behavior: contain;
|
|
3658
|
-
z-index: 60;
|
|
3659
4370
|
}
|
|
3660
4371
|
|
|
3661
|
-
.
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
4372
|
+
/* ---- ./menu.css ---- */
|
|
4373
|
+
@layer components {
|
|
4374
|
+
/* What is left once `Menu` draws its sheet and its list: the rows, whose
|
|
4375
|
+
`data-focused`, `data-pressed` and danger states React Aria stamps on
|
|
4376
|
+
them, and the rules that reach from a row into what it holds. The
|
|
4377
|
+
`box-shadow` stays on the sheet too -- `--shadow-2` is a token, and a
|
|
4378
|
+
utility would have to inline it. */
|
|
3667
4379
|
|
|
4380
|
+
/* A list of verbs, on the same sheet as every other anchored surface. */
|
|
3668
4381
|
.menu-item {
|
|
3669
4382
|
display: flex;
|
|
3670
4383
|
align-items: center;
|
|
@@ -3703,14 +4416,6 @@ body.splitting * { cursor: inherit !important; }
|
|
|
3703
4416
|
/* The binding, set in the mono face at the size of the small print. Right of
|
|
3704
4417
|
the row and never the reason the row is wide: `flex: none` with the label
|
|
3705
4418
|
taking the slack. */
|
|
3706
|
-
.menu-key {
|
|
3707
|
-
flex: none;
|
|
3708
|
-
font-family: var(--font-mono);
|
|
3709
|
-
font-size: var(--text-2xs);
|
|
3710
|
-
color: var(--muted);
|
|
3711
|
-
letter-spacing: var(--tracking);
|
|
3712
|
-
}
|
|
3713
|
-
|
|
3714
4419
|
.menu-more { flex: none; color: var(--muted); }
|
|
3715
4420
|
|
|
3716
4421
|
.menu-rule {
|
|
@@ -3746,7 +4451,11 @@ body.splitting * { cursor: inherit !important; }
|
|
|
3746
4451
|
.menu-sheet[data-exiting] { animation: none; }
|
|
3747
4452
|
}
|
|
3748
4453
|
|
|
4454
|
+
.menu-sheet { box-shadow: var(--shadow-2); }
|
|
4455
|
+
}
|
|
4456
|
+
|
|
3749
4457
|
/* ---- ./command.css ---- */
|
|
4458
|
+
@layer components {
|
|
3750
4459
|
/* The command palette: a field over the app and a list under it. */
|
|
3751
4460
|
.cmd-scrim {
|
|
3752
4461
|
position: fixed;
|
|
@@ -3863,14 +4572,6 @@ body.splitting * { cursor: inherit !important; }
|
|
|
3863
4572
|
white-space: nowrap;
|
|
3864
4573
|
}
|
|
3865
4574
|
|
|
3866
|
-
.cmd-key {
|
|
3867
|
-
flex: none;
|
|
3868
|
-
font-family: var(--font-mono);
|
|
3869
|
-
font-size: var(--text-2xs);
|
|
3870
|
-
color: var(--muted);
|
|
3871
|
-
letter-spacing: var(--tracking);
|
|
3872
|
-
}
|
|
3873
|
-
|
|
3874
4575
|
.cmd-empty {
|
|
3875
4576
|
margin: 0;
|
|
3876
4577
|
padding: var(--space-6) var(--space-4);
|
|
@@ -3896,25 +4597,18 @@ body.splitting * { cursor: inherit !important; }
|
|
|
3896
4597
|
.cmd-scrim[data-exiting],
|
|
3897
4598
|
.cmd[data-entering] { animation: none; }
|
|
3898
4599
|
}
|
|
4600
|
+
}
|
|
3899
4601
|
|
|
3900
4602
|
/* ---- ./pagination.css ---- */
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
gap: var(--space-4);
|
|
3907
|
-
flex-wrap: wrap;
|
|
3908
|
-
padding: var(--space-2) 0;
|
|
3909
|
-
font-size: var(--text-xs);
|
|
3910
|
-
color: var(--muted);
|
|
3911
|
-
}
|
|
4603
|
+
@layer components {
|
|
4604
|
+
/* What is left once `Pagination` draws its own frame: the step and page
|
|
4605
|
+
buttons, whose hover, focus-visible and current states are pseudo-classes
|
|
4606
|
+
on two selectors at once, and `.pager-count strong`, which reaches into
|
|
4607
|
+
text the caller passed. */
|
|
3912
4608
|
|
|
3913
|
-
|
|
4609
|
+
/* Moving through a list that does not fit, and saying how far in you are. */
|
|
3914
4610
|
.pager-count strong { color: var(--text); font-weight: var(--weight-strong); }
|
|
3915
4611
|
|
|
3916
|
-
.pager-controls { display: flex; align-items: center; gap: var(--space-1); }
|
|
3917
|
-
|
|
3918
4612
|
.pager-step,
|
|
3919
4613
|
.pager-page {
|
|
3920
4614
|
display: inline-flex;
|
|
@@ -4025,8 +4719,10 @@ body.splitting * { cursor: inherit !important; }
|
|
|
4025
4719
|
.pager-page,
|
|
4026
4720
|
.pager-jump { transition: none; }
|
|
4027
4721
|
}
|
|
4722
|
+
}
|
|
4028
4723
|
|
|
4029
4724
|
/* ---- ./identity.css ---- */
|
|
4725
|
+
@layer components {
|
|
4030
4726
|
/* A person, said in one line: initials, name, sometimes the address. */
|
|
4031
4727
|
.ident {
|
|
4032
4728
|
display: inline-flex;
|
|
@@ -4106,6 +4802,8 @@ body.splitting * { cursor: inherit !important; }
|
|
|
4106
4802
|
}
|
|
4107
4803
|
|
|
4108
4804
|
.ident-remove {
|
|
4805
|
+
/* Stated rather than inherited. These came from the `button, input, textarea, select` reset, which applied control styling to everything that happened to be a `<button>` -- so this rule spent its opening lines undoing it, and would break silently if that rule ever moved. It did move, to `.btn`. */
|
|
4806
|
+
font: inherit;
|
|
4109
4807
|
flex: none;
|
|
4110
4808
|
display: inline-flex;
|
|
4111
4809
|
align-items: center;
|
|
@@ -4125,4 +4823,5 @@ body.splitting * { cursor: inherit !important; }
|
|
|
4125
4823
|
|
|
4126
4824
|
.ident-remove:hover { background: var(--panel); color: var(--text); }
|
|
4127
4825
|
.ident-remove:focus-visible { outline: none; box-shadow: var(--focus-ring); }
|
|
4826
|
+
}
|
|
4128
4827
|
|