@wtfalch/design 0.7.0 → 0.9.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/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/Field.d.ts +22 -19
- package/dist/components/Field.js +11 -9
- package/dist/components/Input.d.ts +10 -0
- package/dist/components/Input.js +26 -5
- 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.d.ts +3 -1
- package/dist/components/Select.js +28 -6
- package/dist/components/Shell.d.ts +35 -0
- package/dist/components/Shell.js +36 -0
- package/dist/components/SizeGrid.js +14 -2
- package/dist/components/Stat.js +11 -2
- package/dist/components/Table.js +7 -1
- package/dist/components/Textarea.js +14 -4
- package/dist/components/ThemeSwitch.d.ts +19 -0
- package/dist/components/ThemeSwitch.js +65 -0
- package/dist/components/Toast.js +1 -1
- package/dist/components/Tooltip.js +16 -2
- package/dist/components/Tour.js +1 -1
- package/dist/components/fieldWiring.d.ts +44 -0
- package/dist/components/fieldWiring.js +30 -0
- package/dist/index.d.ts +10 -1
- package/dist/index.js +8 -0
- package/dist/styles/index.css +1110 -355
- package/dist/tf.css +1110 -355
- package/dist/themes/choice.d.ts +71 -0
- package/dist/themes/choice.js +81 -0
- package/dist/valet.css +1110 -355
- package/package.json +3 -1
package/dist/tf.css
CHANGED
|
@@ -278,6 +278,705 @@
|
|
|
278
278
|
*
|
|
279
279
|
* `scripts/copy-css.mjs` flattens these into one file at build time.
|
|
280
280
|
*/
|
|
281
|
+
/* ---- ./_tailwind.built.css ---- */
|
|
282
|
+
/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
|
|
283
|
+
@layer properties;
|
|
284
|
+
@layer theme, base, components, utilities;
|
|
285
|
+
@layer theme {
|
|
286
|
+
:root, :host {
|
|
287
|
+
--font-sans: var(--font-sans);
|
|
288
|
+
--font-mono: var(--font-mono);
|
|
289
|
+
--text-xs: var(--text-xs);
|
|
290
|
+
--text-xs--line-height: inherit;
|
|
291
|
+
--text-sm: var(--text-sm);
|
|
292
|
+
--text-sm--line-height: inherit;
|
|
293
|
+
--text-base: var(--text-base);
|
|
294
|
+
--text-lg: var(--text-lg);
|
|
295
|
+
--text-lg--line-height: inherit;
|
|
296
|
+
--text-xl: var(--text-xl);
|
|
297
|
+
--font-weight-normal: var(--weight);
|
|
298
|
+
--tracking-normal: var(--tracking);
|
|
299
|
+
--radius-sm: var(--radius-sm);
|
|
300
|
+
--radius-md: var(--radius-md);
|
|
301
|
+
--radius-lg: var(--radius-lg);
|
|
302
|
+
--ease-out: cubic-bezier(0, 0, 0.2, 1);
|
|
303
|
+
--spacing-1: var(--space-1);
|
|
304
|
+
--spacing-2: var(--space-2);
|
|
305
|
+
--spacing-3: var(--space-3);
|
|
306
|
+
--spacing-4: var(--space-4);
|
|
307
|
+
--spacing-5: var(--space-5);
|
|
308
|
+
--spacing-6: var(--space-6);
|
|
309
|
+
--spacing-10: var(--space-10);
|
|
310
|
+
--text-2xs--line-height: inherit;
|
|
311
|
+
--text-2xs: var(--text-2xs);
|
|
312
|
+
--text-md: var(--text-md);
|
|
313
|
+
--font-weight-strong: var(--weight-strong);
|
|
314
|
+
--radius-pill: var(--radius-pill);
|
|
315
|
+
--color-text: var(--text);
|
|
316
|
+
--color-muted: var(--muted);
|
|
317
|
+
--color-accent: var(--accent);
|
|
318
|
+
--color-border: var(--border);
|
|
319
|
+
--color-border-strong: var(--border-strong);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
@layer utilities {
|
|
323
|
+
.collapse {
|
|
324
|
+
visibility: collapse;
|
|
325
|
+
}
|
|
326
|
+
.invisible {
|
|
327
|
+
visibility: hidden;
|
|
328
|
+
}
|
|
329
|
+
.visible {
|
|
330
|
+
visibility: visible;
|
|
331
|
+
}
|
|
332
|
+
.sr-only {
|
|
333
|
+
position: absolute;
|
|
334
|
+
width: 1px;
|
|
335
|
+
height: 1px;
|
|
336
|
+
padding: 0;
|
|
337
|
+
margin: -1px;
|
|
338
|
+
overflow: hidden;
|
|
339
|
+
clip-path: inset(50%);
|
|
340
|
+
white-space: nowrap;
|
|
341
|
+
border-width: 0;
|
|
342
|
+
}
|
|
343
|
+
.absolute {
|
|
344
|
+
position: absolute;
|
|
345
|
+
}
|
|
346
|
+
.fixed {
|
|
347
|
+
position: fixed;
|
|
348
|
+
}
|
|
349
|
+
.relative {
|
|
350
|
+
position: relative;
|
|
351
|
+
}
|
|
352
|
+
.sticky {
|
|
353
|
+
position: sticky;
|
|
354
|
+
}
|
|
355
|
+
.z-\[60\] {
|
|
356
|
+
z-index: 60;
|
|
357
|
+
}
|
|
358
|
+
.container {
|
|
359
|
+
width: 100%;
|
|
360
|
+
@media (width >= 40rem) {
|
|
361
|
+
max-width: 40rem;
|
|
362
|
+
}
|
|
363
|
+
@media (width >= 48rem) {
|
|
364
|
+
max-width: 48rem;
|
|
365
|
+
}
|
|
366
|
+
@media (width >= 64rem) {
|
|
367
|
+
max-width: 64rem;
|
|
368
|
+
}
|
|
369
|
+
@media (width >= 80rem) {
|
|
370
|
+
max-width: 80rem;
|
|
371
|
+
}
|
|
372
|
+
@media (width >= 96rem) {
|
|
373
|
+
max-width: 96rem;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
.m-0 {
|
|
377
|
+
margin: 0px;
|
|
378
|
+
}
|
|
379
|
+
.m-auto {
|
|
380
|
+
margin: auto;
|
|
381
|
+
}
|
|
382
|
+
.mx-auto {
|
|
383
|
+
margin-inline: auto;
|
|
384
|
+
}
|
|
385
|
+
.mt-1 {
|
|
386
|
+
margin-top: var(--spacing-1);
|
|
387
|
+
}
|
|
388
|
+
.mb-3 {
|
|
389
|
+
margin-bottom: var(--spacing-3);
|
|
390
|
+
}
|
|
391
|
+
.ml-2 {
|
|
392
|
+
margin-left: var(--spacing-2);
|
|
393
|
+
}
|
|
394
|
+
.block {
|
|
395
|
+
display: block;
|
|
396
|
+
}
|
|
397
|
+
.contents {
|
|
398
|
+
display: contents;
|
|
399
|
+
}
|
|
400
|
+
.flex {
|
|
401
|
+
display: flex;
|
|
402
|
+
}
|
|
403
|
+
.grid {
|
|
404
|
+
display: grid;
|
|
405
|
+
}
|
|
406
|
+
.hidden {
|
|
407
|
+
display: none;
|
|
408
|
+
}
|
|
409
|
+
.inline {
|
|
410
|
+
display: inline;
|
|
411
|
+
}
|
|
412
|
+
.inline-flex {
|
|
413
|
+
display: inline-flex;
|
|
414
|
+
}
|
|
415
|
+
.table {
|
|
416
|
+
display: table;
|
|
417
|
+
}
|
|
418
|
+
.h-\[14px\] {
|
|
419
|
+
height: 14px;
|
|
420
|
+
}
|
|
421
|
+
.h-\[18px\] {
|
|
422
|
+
height: 18px;
|
|
423
|
+
}
|
|
424
|
+
.max-h-\[24rem\] {
|
|
425
|
+
max-height: 24rem;
|
|
426
|
+
}
|
|
427
|
+
.max-h-\[280px\] {
|
|
428
|
+
max-height: 280px;
|
|
429
|
+
}
|
|
430
|
+
.min-h-0 {
|
|
431
|
+
min-height: 0px;
|
|
432
|
+
}
|
|
433
|
+
.min-h-screen {
|
|
434
|
+
min-height: 100vh;
|
|
435
|
+
}
|
|
436
|
+
.w-\[18px\] {
|
|
437
|
+
width: 18px;
|
|
438
|
+
}
|
|
439
|
+
.w-full {
|
|
440
|
+
width: 100%;
|
|
441
|
+
}
|
|
442
|
+
.max-w-\[46ch\] {
|
|
443
|
+
max-width: 46ch;
|
|
444
|
+
}
|
|
445
|
+
.max-w-\[min\(20rem\,calc\(100vw-var\(--space-6\)\)\)\] {
|
|
446
|
+
max-width: min(20rem, calc(100vw - var(--space-6)));
|
|
447
|
+
}
|
|
448
|
+
.max-w-\[var\(--shell-measure\)\] {
|
|
449
|
+
max-width: var(--shell-measure);
|
|
450
|
+
}
|
|
451
|
+
.max-w-\[var\(--shell-measure-wide\)\] {
|
|
452
|
+
max-width: var(--shell-measure-wide);
|
|
453
|
+
}
|
|
454
|
+
.min-w-0 {
|
|
455
|
+
min-width: 0px;
|
|
456
|
+
}
|
|
457
|
+
.min-w-\[12rem\] {
|
|
458
|
+
min-width: 12rem;
|
|
459
|
+
}
|
|
460
|
+
.flex-1 {
|
|
461
|
+
flex: 1;
|
|
462
|
+
}
|
|
463
|
+
.flex-none {
|
|
464
|
+
flex: none;
|
|
465
|
+
}
|
|
466
|
+
.shrink {
|
|
467
|
+
flex-shrink: 1;
|
|
468
|
+
}
|
|
469
|
+
.grow {
|
|
470
|
+
flex-grow: 1;
|
|
471
|
+
}
|
|
472
|
+
.transform {
|
|
473
|
+
transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);
|
|
474
|
+
}
|
|
475
|
+
.cursor-help {
|
|
476
|
+
cursor: help;
|
|
477
|
+
}
|
|
478
|
+
.cursor-pointer {
|
|
479
|
+
cursor: pointer;
|
|
480
|
+
}
|
|
481
|
+
.resize {
|
|
482
|
+
resize: both;
|
|
483
|
+
}
|
|
484
|
+
.list-none {
|
|
485
|
+
list-style-type: none;
|
|
486
|
+
}
|
|
487
|
+
.flex-col {
|
|
488
|
+
flex-direction: column;
|
|
489
|
+
}
|
|
490
|
+
.flex-wrap {
|
|
491
|
+
flex-wrap: wrap;
|
|
492
|
+
}
|
|
493
|
+
.items-baseline {
|
|
494
|
+
align-items: baseline;
|
|
495
|
+
}
|
|
496
|
+
.items-center {
|
|
497
|
+
align-items: center;
|
|
498
|
+
}
|
|
499
|
+
.items-start {
|
|
500
|
+
align-items: flex-start;
|
|
501
|
+
}
|
|
502
|
+
.justify-between {
|
|
503
|
+
justify-content: space-between;
|
|
504
|
+
}
|
|
505
|
+
.justify-items-center {
|
|
506
|
+
justify-items: center;
|
|
507
|
+
}
|
|
508
|
+
.gap-0 {
|
|
509
|
+
gap: 0px;
|
|
510
|
+
}
|
|
511
|
+
.gap-1 {
|
|
512
|
+
gap: var(--spacing-1);
|
|
513
|
+
}
|
|
514
|
+
.gap-2 {
|
|
515
|
+
gap: var(--spacing-2);
|
|
516
|
+
}
|
|
517
|
+
.gap-3 {
|
|
518
|
+
gap: var(--spacing-3);
|
|
519
|
+
}
|
|
520
|
+
.gap-4 {
|
|
521
|
+
gap: var(--spacing-4);
|
|
522
|
+
}
|
|
523
|
+
.gap-\[var\(--border-width\)\] {
|
|
524
|
+
gap: var(--border-width);
|
|
525
|
+
}
|
|
526
|
+
.self-center {
|
|
527
|
+
align-self: center;
|
|
528
|
+
}
|
|
529
|
+
.truncate {
|
|
530
|
+
overflow: hidden;
|
|
531
|
+
text-overflow: ellipsis;
|
|
532
|
+
white-space: nowrap;
|
|
533
|
+
}
|
|
534
|
+
.overflow-auto {
|
|
535
|
+
overflow: auto;
|
|
536
|
+
}
|
|
537
|
+
.overflow-hidden {
|
|
538
|
+
overflow: hidden;
|
|
539
|
+
}
|
|
540
|
+
.overflow-x-auto {
|
|
541
|
+
overflow-x: auto;
|
|
542
|
+
}
|
|
543
|
+
.overflow-y-auto {
|
|
544
|
+
overflow-y: auto;
|
|
545
|
+
}
|
|
546
|
+
.overscroll-contain {
|
|
547
|
+
overscroll-behavior: contain;
|
|
548
|
+
}
|
|
549
|
+
.rounded {
|
|
550
|
+
border-radius: 0.25rem;
|
|
551
|
+
}
|
|
552
|
+
.rounded-full {
|
|
553
|
+
border-radius: calc(infinity * 1px);
|
|
554
|
+
}
|
|
555
|
+
.rounded-md {
|
|
556
|
+
border-radius: var(--radius-md);
|
|
557
|
+
}
|
|
558
|
+
.rounded-sm {
|
|
559
|
+
border-radius: var(--radius-sm);
|
|
560
|
+
}
|
|
561
|
+
.border {
|
|
562
|
+
border-style: var(--tw-border-style);
|
|
563
|
+
border-width: var(--border-width);
|
|
564
|
+
}
|
|
565
|
+
.border-b {
|
|
566
|
+
border-bottom-style: var(--tw-border-style);
|
|
567
|
+
border-bottom-width: var(--border-width);
|
|
568
|
+
}
|
|
569
|
+
.border-dashed {
|
|
570
|
+
--tw-border-style: dashed;
|
|
571
|
+
border-style: dashed;
|
|
572
|
+
}
|
|
573
|
+
.border-accent {
|
|
574
|
+
border-color: var(--color-accent);
|
|
575
|
+
}
|
|
576
|
+
.border-border {
|
|
577
|
+
border-color: var(--color-border);
|
|
578
|
+
}
|
|
579
|
+
.border-border-strong {
|
|
580
|
+
border-color: var(--color-border-strong);
|
|
581
|
+
}
|
|
582
|
+
.p-0 {
|
|
583
|
+
padding: 0px;
|
|
584
|
+
}
|
|
585
|
+
.p-1 {
|
|
586
|
+
padding: var(--spacing-1);
|
|
587
|
+
}
|
|
588
|
+
.p-2 {
|
|
589
|
+
padding: var(--spacing-2);
|
|
590
|
+
}
|
|
591
|
+
.p-4 {
|
|
592
|
+
padding: var(--spacing-4);
|
|
593
|
+
}
|
|
594
|
+
.px-4 {
|
|
595
|
+
padding-inline: var(--spacing-4);
|
|
596
|
+
}
|
|
597
|
+
.py-2 {
|
|
598
|
+
padding-block: var(--spacing-2);
|
|
599
|
+
}
|
|
600
|
+
.py-3 {
|
|
601
|
+
padding-block: var(--spacing-3);
|
|
602
|
+
}
|
|
603
|
+
.py-5 {
|
|
604
|
+
padding-block: var(--spacing-5);
|
|
605
|
+
}
|
|
606
|
+
.py-6 {
|
|
607
|
+
padding-block: var(--spacing-6);
|
|
608
|
+
}
|
|
609
|
+
.py-10 {
|
|
610
|
+
padding-block: var(--spacing-10);
|
|
611
|
+
}
|
|
612
|
+
.pb-2 {
|
|
613
|
+
padding-bottom: var(--spacing-2);
|
|
614
|
+
}
|
|
615
|
+
.pb-3 {
|
|
616
|
+
padding-bottom: var(--spacing-3);
|
|
617
|
+
}
|
|
618
|
+
.text-center {
|
|
619
|
+
text-align: center;
|
|
620
|
+
}
|
|
621
|
+
.font-mono {
|
|
622
|
+
font-family: var(--font-mono);
|
|
623
|
+
}
|
|
624
|
+
.text-2xs {
|
|
625
|
+
font-size: var(--text-2xs);
|
|
626
|
+
line-height: var(--tw-leading, var(--text-2xs--line-height));
|
|
627
|
+
}
|
|
628
|
+
.text-lg {
|
|
629
|
+
font-size: var(--text-lg);
|
|
630
|
+
line-height: var(--tw-leading, var(--text-lg--line-height));
|
|
631
|
+
}
|
|
632
|
+
.text-sm {
|
|
633
|
+
font-size: var(--text-sm);
|
|
634
|
+
line-height: var(--tw-leading, var(--text-sm--line-height));
|
|
635
|
+
}
|
|
636
|
+
.text-xs {
|
|
637
|
+
font-size: var(--text-xs);
|
|
638
|
+
line-height: var(--tw-leading, var(--text-xs--line-height));
|
|
639
|
+
}
|
|
640
|
+
.leading-\[0\] {
|
|
641
|
+
--tw-leading: 0;
|
|
642
|
+
line-height: 0;
|
|
643
|
+
}
|
|
644
|
+
.leading-\[1\.5\] {
|
|
645
|
+
--tw-leading: 1.5;
|
|
646
|
+
line-height: 1.5;
|
|
647
|
+
}
|
|
648
|
+
.leading-\[1\.25\] {
|
|
649
|
+
--tw-leading: 1.25;
|
|
650
|
+
line-height: 1.25;
|
|
651
|
+
}
|
|
652
|
+
.leading-\[16px\] {
|
|
653
|
+
--tw-leading: 16px;
|
|
654
|
+
line-height: 16px;
|
|
655
|
+
}
|
|
656
|
+
.font-normal {
|
|
657
|
+
--tw-font-weight: var(--font-weight-normal);
|
|
658
|
+
font-weight: var(--font-weight-normal);
|
|
659
|
+
}
|
|
660
|
+
.font-strong {
|
|
661
|
+
--tw-font-weight: var(--font-weight-strong);
|
|
662
|
+
font-weight: var(--font-weight-strong);
|
|
663
|
+
}
|
|
664
|
+
.tracking-normal {
|
|
665
|
+
--tw-tracking: var(--tracking-normal);
|
|
666
|
+
letter-spacing: var(--tracking-normal);
|
|
667
|
+
}
|
|
668
|
+
.text-ellipsis {
|
|
669
|
+
text-overflow: ellipsis;
|
|
670
|
+
}
|
|
671
|
+
.whitespace-nowrap {
|
|
672
|
+
white-space: nowrap;
|
|
673
|
+
}
|
|
674
|
+
.text-muted {
|
|
675
|
+
color: var(--color-muted);
|
|
676
|
+
}
|
|
677
|
+
.text-text {
|
|
678
|
+
color: var(--color-text);
|
|
679
|
+
}
|
|
680
|
+
.lowercase {
|
|
681
|
+
text-transform: lowercase;
|
|
682
|
+
}
|
|
683
|
+
.normal-case {
|
|
684
|
+
text-transform: none;
|
|
685
|
+
}
|
|
686
|
+
.uppercase {
|
|
687
|
+
text-transform: uppercase;
|
|
688
|
+
}
|
|
689
|
+
.tabular-nums {
|
|
690
|
+
--tw-numeric-spacing: tabular-nums;
|
|
691
|
+
font-variant-numeric: var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,);
|
|
692
|
+
}
|
|
693
|
+
.opacity-0 {
|
|
694
|
+
opacity: 0%;
|
|
695
|
+
}
|
|
696
|
+
.opacity-60 {
|
|
697
|
+
opacity: 60%;
|
|
698
|
+
}
|
|
699
|
+
.opacity-\[0\.55\] {
|
|
700
|
+
opacity: 0.55;
|
|
701
|
+
}
|
|
702
|
+
.shadow {
|
|
703
|
+
--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));
|
|
704
|
+
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
705
|
+
}
|
|
706
|
+
.ring {
|
|
707
|
+
--tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
|
708
|
+
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
709
|
+
}
|
|
710
|
+
.outline {
|
|
711
|
+
outline-style: var(--tw-outline-style);
|
|
712
|
+
outline-width: 1px;
|
|
713
|
+
}
|
|
714
|
+
.blur {
|
|
715
|
+
--tw-blur: blur(8px);
|
|
716
|
+
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,);
|
|
717
|
+
}
|
|
718
|
+
.sepia {
|
|
719
|
+
--tw-sepia: sepia(100%);
|
|
720
|
+
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,);
|
|
721
|
+
}
|
|
722
|
+
.filter {
|
|
723
|
+
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,);
|
|
724
|
+
}
|
|
725
|
+
.outline-none {
|
|
726
|
+
--tw-outline-style: none;
|
|
727
|
+
outline-style: none;
|
|
728
|
+
}
|
|
729
|
+
.\[font\:inherit\] {
|
|
730
|
+
font: inherit;
|
|
731
|
+
}
|
|
732
|
+
.surface-bg {
|
|
733
|
+
background: var(--bg);
|
|
734
|
+
}
|
|
735
|
+
.surface-panel {
|
|
736
|
+
background: var(--panel);
|
|
737
|
+
}
|
|
738
|
+
.surface-panel-2 {
|
|
739
|
+
background: var(--panel-2);
|
|
740
|
+
}
|
|
741
|
+
.disabled\:cursor-default:disabled {
|
|
742
|
+
cursor: default;
|
|
743
|
+
}
|
|
744
|
+
.disabled\:opacity-50:disabled {
|
|
745
|
+
opacity: 50%;
|
|
746
|
+
}
|
|
747
|
+
.\[\&\>p\]\:m-0 > p {
|
|
748
|
+
margin: 0px;
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
@property --tw-rotate-x {
|
|
752
|
+
syntax: "*";
|
|
753
|
+
inherits: false;
|
|
754
|
+
}
|
|
755
|
+
@property --tw-rotate-y {
|
|
756
|
+
syntax: "*";
|
|
757
|
+
inherits: false;
|
|
758
|
+
}
|
|
759
|
+
@property --tw-rotate-z {
|
|
760
|
+
syntax: "*";
|
|
761
|
+
inherits: false;
|
|
762
|
+
}
|
|
763
|
+
@property --tw-skew-x {
|
|
764
|
+
syntax: "*";
|
|
765
|
+
inherits: false;
|
|
766
|
+
}
|
|
767
|
+
@property --tw-skew-y {
|
|
768
|
+
syntax: "*";
|
|
769
|
+
inherits: false;
|
|
770
|
+
}
|
|
771
|
+
@property --tw-border-style {
|
|
772
|
+
syntax: "*";
|
|
773
|
+
inherits: false;
|
|
774
|
+
initial-value: solid;
|
|
775
|
+
}
|
|
776
|
+
@property --tw-leading {
|
|
777
|
+
syntax: "*";
|
|
778
|
+
inherits: false;
|
|
779
|
+
}
|
|
780
|
+
@property --tw-font-weight {
|
|
781
|
+
syntax: "*";
|
|
782
|
+
inherits: false;
|
|
783
|
+
}
|
|
784
|
+
@property --tw-tracking {
|
|
785
|
+
syntax: "*";
|
|
786
|
+
inherits: false;
|
|
787
|
+
}
|
|
788
|
+
@property --tw-ordinal {
|
|
789
|
+
syntax: "*";
|
|
790
|
+
inherits: false;
|
|
791
|
+
}
|
|
792
|
+
@property --tw-slashed-zero {
|
|
793
|
+
syntax: "*";
|
|
794
|
+
inherits: false;
|
|
795
|
+
}
|
|
796
|
+
@property --tw-numeric-figure {
|
|
797
|
+
syntax: "*";
|
|
798
|
+
inherits: false;
|
|
799
|
+
}
|
|
800
|
+
@property --tw-numeric-spacing {
|
|
801
|
+
syntax: "*";
|
|
802
|
+
inherits: false;
|
|
803
|
+
}
|
|
804
|
+
@property --tw-numeric-fraction {
|
|
805
|
+
syntax: "*";
|
|
806
|
+
inherits: false;
|
|
807
|
+
}
|
|
808
|
+
@property --tw-shadow {
|
|
809
|
+
syntax: "*";
|
|
810
|
+
inherits: false;
|
|
811
|
+
initial-value: 0 0 #0000;
|
|
812
|
+
}
|
|
813
|
+
@property --tw-shadow-color {
|
|
814
|
+
syntax: "*";
|
|
815
|
+
inherits: false;
|
|
816
|
+
}
|
|
817
|
+
@property --tw-shadow-alpha {
|
|
818
|
+
syntax: "<percentage>";
|
|
819
|
+
inherits: false;
|
|
820
|
+
initial-value: 100%;
|
|
821
|
+
}
|
|
822
|
+
@property --tw-inset-shadow {
|
|
823
|
+
syntax: "*";
|
|
824
|
+
inherits: false;
|
|
825
|
+
initial-value: 0 0 #0000;
|
|
826
|
+
}
|
|
827
|
+
@property --tw-inset-shadow-color {
|
|
828
|
+
syntax: "*";
|
|
829
|
+
inherits: false;
|
|
830
|
+
}
|
|
831
|
+
@property --tw-inset-shadow-alpha {
|
|
832
|
+
syntax: "<percentage>";
|
|
833
|
+
inherits: false;
|
|
834
|
+
initial-value: 100%;
|
|
835
|
+
}
|
|
836
|
+
@property --tw-ring-color {
|
|
837
|
+
syntax: "*";
|
|
838
|
+
inherits: false;
|
|
839
|
+
}
|
|
840
|
+
@property --tw-ring-shadow {
|
|
841
|
+
syntax: "*";
|
|
842
|
+
inherits: false;
|
|
843
|
+
initial-value: 0 0 #0000;
|
|
844
|
+
}
|
|
845
|
+
@property --tw-inset-ring-color {
|
|
846
|
+
syntax: "*";
|
|
847
|
+
inherits: false;
|
|
848
|
+
}
|
|
849
|
+
@property --tw-inset-ring-shadow {
|
|
850
|
+
syntax: "*";
|
|
851
|
+
inherits: false;
|
|
852
|
+
initial-value: 0 0 #0000;
|
|
853
|
+
}
|
|
854
|
+
@property --tw-ring-inset {
|
|
855
|
+
syntax: "*";
|
|
856
|
+
inherits: false;
|
|
857
|
+
}
|
|
858
|
+
@property --tw-ring-offset-width {
|
|
859
|
+
syntax: "<length>";
|
|
860
|
+
inherits: false;
|
|
861
|
+
initial-value: 0px;
|
|
862
|
+
}
|
|
863
|
+
@property --tw-ring-offset-color {
|
|
864
|
+
syntax: "*";
|
|
865
|
+
inherits: false;
|
|
866
|
+
initial-value: #fff;
|
|
867
|
+
}
|
|
868
|
+
@property --tw-ring-offset-shadow {
|
|
869
|
+
syntax: "*";
|
|
870
|
+
inherits: false;
|
|
871
|
+
initial-value: 0 0 #0000;
|
|
872
|
+
}
|
|
873
|
+
@property --tw-outline-style {
|
|
874
|
+
syntax: "*";
|
|
875
|
+
inherits: false;
|
|
876
|
+
initial-value: solid;
|
|
877
|
+
}
|
|
878
|
+
@property --tw-blur {
|
|
879
|
+
syntax: "*";
|
|
880
|
+
inherits: false;
|
|
881
|
+
}
|
|
882
|
+
@property --tw-brightness {
|
|
883
|
+
syntax: "*";
|
|
884
|
+
inherits: false;
|
|
885
|
+
}
|
|
886
|
+
@property --tw-contrast {
|
|
887
|
+
syntax: "*";
|
|
888
|
+
inherits: false;
|
|
889
|
+
}
|
|
890
|
+
@property --tw-grayscale {
|
|
891
|
+
syntax: "*";
|
|
892
|
+
inherits: false;
|
|
893
|
+
}
|
|
894
|
+
@property --tw-hue-rotate {
|
|
895
|
+
syntax: "*";
|
|
896
|
+
inherits: false;
|
|
897
|
+
}
|
|
898
|
+
@property --tw-invert {
|
|
899
|
+
syntax: "*";
|
|
900
|
+
inherits: false;
|
|
901
|
+
}
|
|
902
|
+
@property --tw-opacity {
|
|
903
|
+
syntax: "*";
|
|
904
|
+
inherits: false;
|
|
905
|
+
}
|
|
906
|
+
@property --tw-saturate {
|
|
907
|
+
syntax: "*";
|
|
908
|
+
inherits: false;
|
|
909
|
+
}
|
|
910
|
+
@property --tw-sepia {
|
|
911
|
+
syntax: "*";
|
|
912
|
+
inherits: false;
|
|
913
|
+
}
|
|
914
|
+
@property --tw-drop-shadow {
|
|
915
|
+
syntax: "*";
|
|
916
|
+
inherits: false;
|
|
917
|
+
}
|
|
918
|
+
@property --tw-drop-shadow-color {
|
|
919
|
+
syntax: "*";
|
|
920
|
+
inherits: false;
|
|
921
|
+
}
|
|
922
|
+
@property --tw-drop-shadow-alpha {
|
|
923
|
+
syntax: "<percentage>";
|
|
924
|
+
inherits: false;
|
|
925
|
+
initial-value: 100%;
|
|
926
|
+
}
|
|
927
|
+
@property --tw-drop-shadow-size {
|
|
928
|
+
syntax: "*";
|
|
929
|
+
inherits: false;
|
|
930
|
+
}
|
|
931
|
+
@layer properties {
|
|
932
|
+
@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
|
|
933
|
+
*, ::before, ::after, ::backdrop {
|
|
934
|
+
--tw-rotate-x: initial;
|
|
935
|
+
--tw-rotate-y: initial;
|
|
936
|
+
--tw-rotate-z: initial;
|
|
937
|
+
--tw-skew-x: initial;
|
|
938
|
+
--tw-skew-y: initial;
|
|
939
|
+
--tw-border-style: solid;
|
|
940
|
+
--tw-leading: initial;
|
|
941
|
+
--tw-font-weight: initial;
|
|
942
|
+
--tw-tracking: initial;
|
|
943
|
+
--tw-ordinal: initial;
|
|
944
|
+
--tw-slashed-zero: initial;
|
|
945
|
+
--tw-numeric-figure: initial;
|
|
946
|
+
--tw-numeric-spacing: initial;
|
|
947
|
+
--tw-numeric-fraction: initial;
|
|
948
|
+
--tw-shadow: 0 0 #0000;
|
|
949
|
+
--tw-shadow-color: initial;
|
|
950
|
+
--tw-shadow-alpha: 100%;
|
|
951
|
+
--tw-inset-shadow: 0 0 #0000;
|
|
952
|
+
--tw-inset-shadow-color: initial;
|
|
953
|
+
--tw-inset-shadow-alpha: 100%;
|
|
954
|
+
--tw-ring-color: initial;
|
|
955
|
+
--tw-ring-shadow: 0 0 #0000;
|
|
956
|
+
--tw-inset-ring-color: initial;
|
|
957
|
+
--tw-inset-ring-shadow: 0 0 #0000;
|
|
958
|
+
--tw-ring-inset: initial;
|
|
959
|
+
--tw-ring-offset-width: 0px;
|
|
960
|
+
--tw-ring-offset-color: #fff;
|
|
961
|
+
--tw-ring-offset-shadow: 0 0 #0000;
|
|
962
|
+
--tw-outline-style: solid;
|
|
963
|
+
--tw-blur: initial;
|
|
964
|
+
--tw-brightness: initial;
|
|
965
|
+
--tw-contrast: initial;
|
|
966
|
+
--tw-grayscale: initial;
|
|
967
|
+
--tw-hue-rotate: initial;
|
|
968
|
+
--tw-invert: initial;
|
|
969
|
+
--tw-opacity: initial;
|
|
970
|
+
--tw-saturate: initial;
|
|
971
|
+
--tw-sepia: initial;
|
|
972
|
+
--tw-drop-shadow: initial;
|
|
973
|
+
--tw-drop-shadow-color: initial;
|
|
974
|
+
--tw-drop-shadow-alpha: 100%;
|
|
975
|
+
--tw-drop-shadow-size: initial;
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
|
|
281
980
|
/* ---- ./base.css ---- */
|
|
282
981
|
/* Light, only under the `system` theme. This used to override `:root`
|
|
283
982
|
unconditionally, so choosing a dark theme on a light-mode laptop got
|
|
@@ -371,23 +1070,31 @@ body::before {
|
|
|
371
1070
|
`[aria-disabled='true']` twin rather than a rewrite, which leaves each
|
|
372
1071
|
`button` selector at the specificity it had and every committed baseline
|
|
373
1072
|
untouched. */
|
|
374
|
-
|
|
1073
|
+
.btn {
|
|
1074
|
+
/* The three an anchor brings that a `<button>` does not. Harmless on the
|
|
1075
|
+
button form -- it has no underline and centres already -- and the reason
|
|
1076
|
+
`Button` puts one class on both elements rather than keeping a twin
|
|
1077
|
+
selector for each. */
|
|
375
1078
|
text-decoration: none;
|
|
376
1079
|
color: var(--text);
|
|
377
1080
|
text-align: center;
|
|
378
1081
|
}
|
|
379
1082
|
|
|
380
|
-
|
|
1083
|
+
.btn[aria-disabled='true'] {
|
|
381
1084
|
/* A disabled anchor still takes the pointer, so say so. The click itself is
|
|
382
1085
|
blocked in the capture phase by the component. */
|
|
383
1086
|
cursor: not-allowed;
|
|
384
1087
|
}
|
|
385
1088
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
input,
|
|
389
|
-
|
|
390
|
-
|
|
1089
|
+
/* `:where`, so this base carries no specificity of its own.
|
|
1090
|
+
*
|
|
1091
|
+
* It was `button, input, textarea, select` -- an element selector, which
|
|
1092
|
+
* `.size-sm` and every other class outranked without anyone thinking about
|
|
1093
|
+
* it. Moving it to `.btn` to stop a tab inheriting a control's look raised it
|
|
1094
|
+
* to a class, so it tied with `.size-sm` and won on source order: every
|
|
1095
|
+
* button came out `8px 12px` whatever size it asked for. `:where` puts it
|
|
1096
|
+
* back to zero, which is what the element selector was silently providing. */
|
|
1097
|
+
:where(.btn, input, textarea, select) {
|
|
391
1098
|
font: inherit;
|
|
392
1099
|
color: var(--text);
|
|
393
1100
|
background: var(--control);
|
|
@@ -408,8 +1115,7 @@ select {
|
|
|
408
1115
|
the icon; the button simply had no opinion about how to arrange two things.
|
|
409
1116
|
`inline-flex` and a gap gives it one, and the gap replaces the space
|
|
410
1117
|
character people were putting between an icon and its label. */
|
|
411
|
-
|
|
412
|
-
a.btn {
|
|
1118
|
+
.btn {
|
|
413
1119
|
display: inline-flex;
|
|
414
1120
|
align-items: center;
|
|
415
1121
|
justify-content: center;
|
|
@@ -425,18 +1131,41 @@ a.btn {
|
|
|
425
1131
|
|
|
426
1132
|
Several places already drew this by hand as `.chat-bar-btn.on`. This is the
|
|
427
1133
|
same look, said once, on a plain button. */
|
|
428
|
-
|
|
1134
|
+
.btn[aria-pressed='true'] {
|
|
429
1135
|
border-color: var(--accent);
|
|
430
1136
|
color: var(--accent);
|
|
431
1137
|
background: color-mix(in srgb, var(--accent) 10%, var(--panel));
|
|
432
1138
|
}
|
|
433
1139
|
|
|
434
|
-
|
|
1140
|
+
.btn[aria-pressed='true']:hover:not(:disabled) { border-color: var(--accent); }
|
|
435
1141
|
|
|
436
1142
|
/* The glyph never shrinks: in a narrow row flexbox would take it from the icon
|
|
437
1143
|
before the text, and half an icon is not a smaller icon. */
|
|
438
|
-
|
|
439
|
-
|
|
1144
|
+
.btn > svg { flex: none; }
|
|
1145
|
+
|
|
1146
|
+
/* `Select`'s control wears the control styling, and says so.
|
|
1147
|
+
*
|
|
1148
|
+
* It renders React Aria's `Button` -- a bare `<button>` -- and used to take
|
|
1149
|
+
* `font`, colour, the surface and the border from the
|
|
1150
|
+
* `button, input, textarea, select` reset without asking. When that reset
|
|
1151
|
+
* moved to `.btn`, so a tab and a row would stop inheriting a control's look
|
|
1152
|
+
* only to undo it, this lost all of it at once.
|
|
1153
|
+
*
|
|
1154
|
+
* Here rather than in `select.css`, and that placement is the rule, not
|
|
1155
|
+
* tidiness: `font` is a shorthand and it resets `font-size`, so declared
|
|
1156
|
+
* after `.size-sm` below it silently makes every small control full size.
|
|
1157
|
+
* `index.css` says the import order is behaviour; this is what that means.
|
|
1158
|
+
*
|
|
1159
|
+
* `:where` for the same reason the reset above uses it: this is a base a
|
|
1160
|
+
* `size` class has to be able to beat, and a bare class ties with one. */
|
|
1161
|
+
:where(.sel-control) {
|
|
1162
|
+
font: inherit;
|
|
1163
|
+
color: var(--text);
|
|
1164
|
+
background: var(--control);
|
|
1165
|
+
border: var(--border-width) solid var(--border-strong);
|
|
1166
|
+
border-radius: var(--radius);
|
|
1167
|
+
cursor: pointer;
|
|
1168
|
+
}
|
|
440
1169
|
|
|
441
1170
|
.size-sm { font-size: var(--text-xs); padding: var(--space-1) var(--space-2); }
|
|
442
1171
|
|
|
@@ -461,8 +1190,7 @@ input, textarea, select { width: 100%; }
|
|
|
461
1190
|
same disagreement written twice. */
|
|
462
1191
|
textarea { resize: none; }
|
|
463
1192
|
|
|
464
|
-
|
|
465
|
-
a.btn:hover:not([aria-disabled='true']),
|
|
1193
|
+
.btn:hover:not(:disabled),
|
|
466
1194
|
input:hover:not(:disabled),
|
|
467
1195
|
textarea:hover:not(:disabled),
|
|
468
1196
|
select:hover:not(:disabled) { border-color: var(--accent); }
|
|
@@ -470,8 +1198,7 @@ select:hover:not(:disabled) { border-color: var(--accent); }
|
|
|
470
1198
|
/* `:focus-visible` on the button so a click does not leave a ring behind it,
|
|
471
1199
|
`:focus` on the fields because a focused field is a place you are typing and
|
|
472
1200
|
should say so however you got there. */
|
|
473
|
-
|
|
474
|
-
a.btn:focus-visible,
|
|
1201
|
+
.btn:focus-visible,
|
|
475
1202
|
input:focus,
|
|
476
1203
|
textarea:focus,
|
|
477
1204
|
select:focus { outline: none; border-color: var(--accent); }
|
|
@@ -564,14 +1291,13 @@ input[type='radio']:focus-visible { outline: none; box-shadow: var(--focus-ring)
|
|
|
564
1291
|
input[type='checkbox']:disabled,
|
|
565
1292
|
input[type='radio']:disabled { cursor: not-allowed; background: var(--panel-2); }
|
|
566
1293
|
|
|
567
|
-
|
|
568
|
-
|
|
1294
|
+
.btn:disabled,
|
|
1295
|
+
.btn[aria-disabled='true'],
|
|
569
1296
|
input:disabled,
|
|
570
1297
|
textarea:disabled,
|
|
571
1298
|
select:disabled { opacity: 0.45; cursor: not-allowed; }
|
|
572
1299
|
|
|
573
|
-
|
|
574
|
-
a.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
|
|
1300
|
+
.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
|
|
575
1301
|
|
|
576
1302
|
/* A disabled primary is not a faded primary.
|
|
577
1303
|
`opacity: .45` was the whole of it, and a coloured fill at 45% is still a
|
|
@@ -579,8 +1305,7 @@ a.btn.primary { background: var(--accent); border-color: var(--accent); color: v
|
|
|
579
1305
|
thing on the panel. That got worse when onboarding started holding people at
|
|
580
1306
|
a disabled Next. So it gives up the fill entirely and becomes the shape of a
|
|
581
1307
|
disabled control -- the opacity then has nothing left to do. */
|
|
582
|
-
|
|
583
|
-
a.btn.primary[aria-disabled='true'] {
|
|
1308
|
+
.btn.primary:disabled {
|
|
584
1309
|
background: var(--panel-2);
|
|
585
1310
|
border-color: var(--border);
|
|
586
1311
|
color: var(--muted);
|
|
@@ -594,7 +1319,7 @@ a.btn.primary[aria-disabled='true'] {
|
|
|
594
1319
|
line under it that travels.
|
|
595
1320
|
`aria-busy` rather than a class: the attribute is what a screen reader reads,
|
|
596
1321
|
and styling the thing that carries the meaning is how they stay in step. */
|
|
597
|
-
|
|
1322
|
+
.btn[aria-busy='true'] {
|
|
598
1323
|
position: relative;
|
|
599
1324
|
overflow: hidden;
|
|
600
1325
|
cursor: progress;
|
|
@@ -607,18 +1332,18 @@ button[aria-busy='true'] {
|
|
|
607
1332
|
something that is working, that reads as a control that failed and went
|
|
608
1333
|
grey. So a busy button keeps every colour it had and takes only the loss of
|
|
609
1334
|
the cursor and the press; the travelling line is what says why. */
|
|
610
|
-
|
|
1335
|
+
.btn[aria-busy='true']:disabled {
|
|
611
1336
|
opacity: 1;
|
|
612
1337
|
cursor: progress;
|
|
613
1338
|
}
|
|
614
1339
|
|
|
615
|
-
|
|
1340
|
+
.btn.primary[aria-busy='true']:disabled {
|
|
616
1341
|
background: var(--accent);
|
|
617
1342
|
border-color: var(--accent);
|
|
618
1343
|
color: var(--on-accent);
|
|
619
1344
|
}
|
|
620
1345
|
|
|
621
|
-
|
|
1346
|
+
.btn[aria-busy='true']::after {
|
|
622
1347
|
content: '';
|
|
623
1348
|
position: absolute;
|
|
624
1349
|
left: 0;
|
|
@@ -650,15 +1375,13 @@ button[aria-busy='true']::after {
|
|
|
650
1375
|
|
|
651
1376
|
/* Quiet: no border, no fill. For the action beside the action -- Cancel next to
|
|
652
1377
|
Save -- where a bordered box competes with the thing it is next to. */
|
|
653
|
-
|
|
654
|
-
a.btn.ghost {
|
|
1378
|
+
.btn.ghost {
|
|
655
1379
|
background: transparent;
|
|
656
1380
|
border-color: transparent;
|
|
657
1381
|
color: var(--muted);
|
|
658
1382
|
}
|
|
659
1383
|
|
|
660
|
-
|
|
661
|
-
a.btn.ghost:hover:not([aria-disabled='true']) {
|
|
1384
|
+
.btn.ghost:hover:not(:disabled) {
|
|
662
1385
|
background: var(--panel-2);
|
|
663
1386
|
border-color: transparent;
|
|
664
1387
|
color: var(--text);
|
|
@@ -740,7 +1463,7 @@ a.btn.ghost:hover:not([aria-disabled='true']) {
|
|
|
740
1463
|
header.) */
|
|
741
1464
|
.row { display: flex; align-items: center; gap: var(--space-3); }
|
|
742
1465
|
|
|
743
|
-
.grow { flex: 1; min-width: 0; }
|
|
1466
|
+
.ctl-grow { flex: 1; min-width: 0; }
|
|
744
1467
|
|
|
745
1468
|
.mono { font-family: var(--font-mono); font-size: var(--text-sm); }
|
|
746
1469
|
|
|
@@ -804,10 +1527,17 @@ a.btn.ghost:hover:not([aria-disabled='true']) {
|
|
|
804
1527
|
/* A pill following a name needs the gap outside its own border. Leading
|
|
805
1528
|
whitespace inside the span puts it under the pill's background instead,
|
|
806
1529
|
which reads as the badge touching the word it qualifies. */
|
|
807
|
-
|
|
1530
|
+
/* A pill beside a name, and the one thing that keeps the pair working:
|
|
1531
|
+
`flex: none`, so the pill never shrinks and the name ellipsises instead.
|
|
1532
|
+
That was `rows.css`'s `.named > .pill`, which meant anybody laying out a
|
|
1533
|
+
name and its pills had to know a package class by name to get it. The
|
|
1534
|
+
variant already says "I am in a row"; it may as well say what that costs. */
|
|
1535
|
+
.row-pill { margin-left: var(--space-2); vertical-align: baseline; flex: none; }
|
|
808
1536
|
|
|
809
1537
|
/* The tile's only control. Dim until hovered: it is chrome on someone's app. */
|
|
810
1538
|
.icon-btn {
|
|
1539
|
+
/* 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`. */
|
|
1540
|
+
font: inherit;
|
|
811
1541
|
display: inline-flex; align-items: center; padding: var(--space-1);
|
|
812
1542
|
background: none; border: 0; color: var(--muted); opacity: 0.6; cursor: pointer;
|
|
813
1543
|
}
|
|
@@ -873,19 +1603,17 @@ a.btn.ghost:hover:not([aria-disabled='true']) {
|
|
|
873
1603
|
transition: none;
|
|
874
1604
|
}
|
|
875
1605
|
|
|
876
|
-
|
|
877
|
-
a.btn.primary:active:not([aria-disabled='true']) {
|
|
1606
|
+
.btn.primary:active:not(:disabled) {
|
|
878
1607
|
background: color-mix(in srgb, var(--text) var(--press-ink), var(--accent));
|
|
879
1608
|
border-color: color-mix(in srgb, var(--text) var(--press-ink), var(--accent));
|
|
880
1609
|
}
|
|
881
1610
|
|
|
882
|
-
|
|
883
|
-
a.btn.ghost:active:not([aria-disabled='true']) {
|
|
1611
|
+
.btn.ghost:active:not(:disabled) {
|
|
884
1612
|
background: color-mix(in srgb, var(--text) var(--press-ink), var(--panel-2));
|
|
885
1613
|
border-color: transparent;
|
|
886
1614
|
}
|
|
887
1615
|
|
|
888
|
-
|
|
1616
|
+
.btn[aria-pressed='true']:active:not(:disabled) {
|
|
889
1617
|
background: color-mix(in srgb, var(--accent) 18%, var(--panel));
|
|
890
1618
|
}
|
|
891
1619
|
|
|
@@ -1056,7 +1784,7 @@ input:active, textarea:active, select:active { transform: none; }
|
|
|
1056
1784
|
|
|
1057
1785
|
/* The top bar carries the title, the views and the way into settings. Nothing
|
|
1058
1786
|
that belongs to a conversation lives here any more, so it can breathe. */
|
|
1059
|
-
.topbar .grow { flex: 1; min-width: 0; }
|
|
1787
|
+
.topbar .ctl-grow { flex: 1; min-width: 0; }
|
|
1060
1788
|
|
|
1061
1789
|
/* Back on the left, Next on the right, with the gap between them doing the
|
|
1062
1790
|
separating -- so the button that goes forward is in the same place on both
|
|
@@ -1088,6 +1816,57 @@ input:active, textarea:active, select:active { transform: none; }
|
|
|
1088
1816
|
to { opacity: 1; }
|
|
1089
1817
|
}
|
|
1090
1818
|
|
|
1819
|
+
/* The states the `button` element rule used to hand every bare `<button>` in
|
|
1820
|
+
the package, now asked for by name.
|
|
1821
|
+
*
|
|
1822
|
+
* This is the half of the decoupling that a screenshot cannot show: `:focus-visible`
|
|
1823
|
+
* is not photographed, so nine components would have lost their focus ring in
|
|
1824
|
+
* silence. `keyboard.spec.ts` is what actually holds this.
|
|
1825
|
+
*
|
|
1826
|
+
* `.btn` has its own, in the rules above. These are the ones that are a button
|
|
1827
|
+
* for their behaviour and not for their appearance -- a tab, a row, a card, a
|
|
1828
|
+
* pager step, a grid cell, a remove cross. */
|
|
1829
|
+
.tab:focus-visible,
|
|
1830
|
+
.row-hit:focus-visible,
|
|
1831
|
+
.card:focus-visible,
|
|
1832
|
+
.ident-remove:focus-visible,
|
|
1833
|
+
.size-cell:focus-visible,
|
|
1834
|
+
.pager-step:focus-visible,
|
|
1835
|
+
.pager-page:focus-visible,
|
|
1836
|
+
.sel-control:focus-visible {
|
|
1837
|
+
outline: 2px solid var(--accent);
|
|
1838
|
+
outline-offset: 2px;
|
|
1839
|
+
}
|
|
1840
|
+
|
|
1841
|
+
/* `:disabled` came from the same rule. A control that cannot be pressed has to
|
|
1842
|
+
say so whatever element it is. */
|
|
1843
|
+
.tab:disabled,
|
|
1844
|
+
.row-hit:disabled,
|
|
1845
|
+
.card:disabled,
|
|
1846
|
+
.ident-remove:disabled,
|
|
1847
|
+
.size-cell:disabled,
|
|
1848
|
+
.pager-step:disabled,
|
|
1849
|
+
.pager-page:disabled,
|
|
1850
|
+
.sel-control:disabled {
|
|
1851
|
+
opacity: 0.45;
|
|
1852
|
+
cursor: not-allowed;
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
/* The anchor form's disabled states, alongside the button's.
|
|
1856
|
+
*
|
|
1857
|
+
* `.btn` is one class on two elements, and an `<a>` has no `:disabled` -- it
|
|
1858
|
+
* carries `aria-disabled` and a capture-phase click block instead. Every
|
|
1859
|
+
* rule above that reads `:disabled` needs the attribute twin, or a disabled
|
|
1860
|
+
* link is a link that looks pressable and refuses silently. Folding the old
|
|
1861
|
+
* `a.btn` twins into `.btn` dropped these, and the baselines showed a
|
|
1862
|
+
* disabled link at full strength. */
|
|
1863
|
+
.btn.primary[aria-disabled='true'] {
|
|
1864
|
+
background: var(--panel-2);
|
|
1865
|
+
border-color: var(--border);
|
|
1866
|
+
color: var(--muted);
|
|
1867
|
+
opacity: 1;
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1091
1870
|
/* ---- ./select.css ---- */
|
|
1092
1871
|
/* How big a control is, asked for rather than inherited.
|
|
1093
1872
|
Four sizes existed and every one of them came from a descendant selector:
|
|
@@ -1103,8 +1882,7 @@ input:active, textarea:active, select:active { transform: none; }
|
|
|
1103
1882
|
/* Full width, for the one action a card or a step is about. Not a size: a
|
|
1104
1883
|
`block` button is the same height as any other, it just stops being a thing
|
|
1105
1884
|
you have to aim at. */
|
|
1106
|
-
|
|
1107
|
-
a.btn.block { display: flex; width: 100%; }
|
|
1885
|
+
.btn.ctl-block { display: flex; width: 100%; }
|
|
1108
1886
|
|
|
1109
1887
|
/* The default is `size-md`, spelled once for every control.
|
|
1110
1888
|
The paragraph above promised one scale for buttons, inputs and selects, and
|
|
@@ -1112,13 +1890,24 @@ a.btn.block { display: flex; width: 100%; }
|
|
|
1112
1890
|
input was eight pixels taller than the button beside it and no row of the two
|
|
1113
1891
|
could line up. The download modal's search box against its Search button was
|
|
1114
1892
|
the version you could see from across the room. */
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
input,
|
|
1118
|
-
|
|
1119
|
-
|
|
1893
|
+
/* `:where`, so this base carries no specificity of its own.
|
|
1894
|
+
*
|
|
1895
|
+
* It was `button, input, textarea, select` -- an element selector, which
|
|
1896
|
+
* `.size-sm` and every other class outranked without anyone thinking about
|
|
1897
|
+
* it. Moving it to `.btn` to stop a tab inheriting a control's look raised it
|
|
1898
|
+
* to a class, so it tied with `.size-sm` and won on source order: every
|
|
1899
|
+
* button came out `8px 12px` whatever size it asked for. `:where` puts it
|
|
1900
|
+
* back to zero, which is what the element selector was silently providing. */
|
|
1901
|
+
:where(.btn, input, textarea, select) { padding: var(--space-2) var(--space-3); }
|
|
1902
|
+
|
|
1903
|
+
/* The select's control keeps its padding at full class weight, and after
|
|
1904
|
+
`.size-sm` in the cascade, because that is where it has always been: this
|
|
1905
|
+
file is imported after `base.css`, so a `size`d select took the size's type
|
|
1906
|
+
and this padding. Folding it into the `:where` above handed the padding
|
|
1907
|
+
back to `.size-sm` and shrank every small select by seven pixels. */
|
|
1120
1908
|
.sel-control { padding: var(--space-2) var(--space-3); }
|
|
1121
1909
|
|
|
1910
|
+
|
|
1122
1911
|
/* Centred on the whole block -- the caption and the sentence together -- rather
|
|
1123
1912
|
than aligned to either end of it. `.field-row` pins to the bottom, which is
|
|
1124
1913
|
right for a field beside a button and wrong beside two lines of prose. */
|
|
@@ -1142,16 +1931,16 @@ select,
|
|
|
1142
1931
|
.sel { position: relative; display: inline-block; }
|
|
1143
1932
|
|
|
1144
1933
|
/* The subject of its pane rather than a field in it: full width and a size up.
|
|
1145
|
-
That was `.select-field.block` on the native element, and it carried the
|
|
1934
|
+
That was `.select-field.ctl-block` on the native element, and it carried the
|
|
1146
1935
|
reason with it -- model ids are long (`qwen2.5-coder:32b-instruct-q4_K_M`) and
|
|
1147
1936
|
at the narrow size they truncated mid-name. */
|
|
1148
|
-
.sel.block { display: block; width: 100%; }
|
|
1937
|
+
.sel.ctl-block { display: block; width: 100%; }
|
|
1149
1938
|
|
|
1150
|
-
.sel.block .sel-control { padding: var(--space-2) var(--space-3); font-weight: 500; }
|
|
1939
|
+
.sel.ctl-block .sel-control { padding: var(--space-2) var(--space-3); font-weight: 500; }
|
|
1151
1940
|
|
|
1152
1941
|
/* Not full width otherwise: a select as wide as its row, holding one short
|
|
1153
1942
|
word, reads as an input somebody forgot to fill in. */
|
|
1154
|
-
.sel:not(.block) .sel-control { width: auto; max-width: 320px; }
|
|
1943
|
+
.sel:not(.ctl-block) .sel-control { width: auto; max-width: 320px; }
|
|
1155
1944
|
|
|
1156
1945
|
.sel-control {
|
|
1157
1946
|
display: flex;
|
|
@@ -1164,9 +1953,7 @@ select,
|
|
|
1164
1953
|
background: var(--control);
|
|
1165
1954
|
}
|
|
1166
1955
|
|
|
1167
|
-
.sel-
|
|
1168
|
-
|
|
1169
|
-
.sel-caret { flex: none; opacity: 0.6; transition: transform var(--dur-fast) var(--ease); }
|
|
1956
|
+
.sel-caret { transition: transform var(--dur-fast) var(--ease); }
|
|
1170
1957
|
|
|
1171
1958
|
.sel[data-open] .sel-caret { transform: rotate(180deg); }
|
|
1172
1959
|
|
|
@@ -1175,21 +1962,7 @@ select,
|
|
|
1175
1962
|
/* State is read off React Aria's attributes: `data-open` on the root,
|
|
1176
1963
|
`data-focused` / `data-selected` / `data-disabled` on an item, where
|
|
1177
1964
|
`.open`, `[data-active]`, `.on` and `.off` used to be. */
|
|
1178
|
-
.sel-list {
|
|
1179
|
-
/* `fixed`, and in `document.body`: an ancestor that scrolls or hides its
|
|
1180
|
-
overflow would otherwise clip it, which in this app means every settings
|
|
1181
|
-
pane. Position comes from the button's measured rectangle. */
|
|
1182
|
-
/* Positioned by React Aria -- inline `top`/`left` on a portalled popover
|
|
1183
|
-
that flips when the edge is near. `position: fixed` and the measured
|
|
1184
|
-
rectangle it was placed by are gone with the hand-rolled version. */
|
|
1185
|
-
z-index: 60;
|
|
1186
|
-
max-height: 280px;
|
|
1187
|
-
overflow-y: auto;
|
|
1188
|
-
margin: 0;
|
|
1189
|
-
padding: var(--space-1);
|
|
1190
|
-
/* The same room while the list is scrolled as it has at rest. Padding at
|
|
1191
|
-
the top of a scroll container scrolls away with the content, so the row
|
|
1192
|
-
`scrollIntoView({block: 'nearest'})` brings up ended flush against the
|
|
1965
|
+
.sel-list { scroll-padding-block: var(--space-1); box-shadow: var(--shadow-2); })` brings up ended flush against the
|
|
1193
1966
|
border and read as clipped rather than as one of a set -- and this list
|
|
1194
1967
|
opens scrolled to whatever is chosen, so that was the ordinary state.
|
|
1195
1968
|
`scroll-padding` insets what counts as "in view", so it stops short by
|
|
@@ -1202,18 +1975,6 @@ select,
|
|
|
1202
1975
|
box-shadow: var(--shadow-2);
|
|
1203
1976
|
}
|
|
1204
1977
|
|
|
1205
|
-
.sel-item {
|
|
1206
|
-
display: flex;
|
|
1207
|
-
align-items: center;
|
|
1208
|
-
gap: var(--space-2);
|
|
1209
|
-
padding: var(--space-2) var(--space-2);
|
|
1210
|
-
border-radius: var(--radius-sm);
|
|
1211
|
-
cursor: pointer;
|
|
1212
|
-
white-space: nowrap;
|
|
1213
|
-
}
|
|
1214
|
-
|
|
1215
|
-
.sel-item-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
|
|
1216
|
-
|
|
1217
1978
|
/* Hover and keyboard land on the same row, because they are the same idea --
|
|
1218
1979
|
two highlights for one cursor is how a list starts lying about where Enter
|
|
1219
1980
|
will go. */
|
|
@@ -1225,8 +1986,6 @@ select,
|
|
|
1225
1986
|
|
|
1226
1987
|
/* The tick marks the chosen row. Colour alone would not: a list where the only
|
|
1227
1988
|
difference is a hue is a list you cannot read past. */
|
|
1228
|
-
.sel-tick { flex: none; opacity: 0; }
|
|
1229
|
-
|
|
1230
1989
|
.sel-item[data-selected] .sel-tick { opacity: 1; }
|
|
1231
1990
|
|
|
1232
1991
|
/* The icon on a speaker's row in the open list -- `Select`'s `aside`. Last in
|
|
@@ -1264,21 +2023,18 @@ select,
|
|
|
1264
2023
|
|
|
1265
2024
|
/* ---- ./dangerzone.css ---- */
|
|
1266
2025
|
/* Destructive, and legible as such standing still. */
|
|
1267
|
-
|
|
1268
|
-
a.btn.danger {
|
|
2026
|
+
.btn.danger {
|
|
1269
2027
|
color: var(--bad);
|
|
1270
2028
|
border-color: color-mix(in srgb, var(--bad) 45%, var(--border-strong));
|
|
1271
2029
|
}
|
|
1272
2030
|
|
|
1273
|
-
|
|
1274
|
-
a.btn.danger:hover:not([aria-disabled='true']) {
|
|
2031
|
+
.btn.danger:hover:not(:disabled) {
|
|
1275
2032
|
background: color-mix(in srgb, var(--bad) 12%, var(--panel));
|
|
1276
2033
|
border-color: var(--bad);
|
|
1277
2034
|
color: var(--bad);
|
|
1278
2035
|
}
|
|
1279
2036
|
|
|
1280
|
-
|
|
1281
|
-
a.btn.danger:active:not([aria-disabled='true']) {
|
|
2037
|
+
.btn.danger:active:not(:disabled) {
|
|
1282
2038
|
background: color-mix(in srgb, var(--bad) 20%, var(--panel));
|
|
1283
2039
|
border-color: var(--bad);
|
|
1284
2040
|
}
|
|
@@ -1519,33 +2275,46 @@ a.btn.danger:active:not([aria-disabled='true']) {
|
|
|
1519
2275
|
.callout button { flex: none; }
|
|
1520
2276
|
|
|
1521
2277
|
/* ---- ./card.css ---- */
|
|
2278
|
+
/* `.card` is public API, not this component's private styling.
|
|
2279
|
+
*
|
|
2280
|
+
* Consumers apply it to their own markup -- the gallery's skeleton specimen
|
|
2281
|
+
* renders `<div className="card">` around three rows, and app-template uses
|
|
2282
|
+
* `card-pick`. Moving the box into `Card`'s own class list took that away
|
|
2283
|
+
* with no type error and no failing test in this package: it broke only
|
|
2284
|
+
* where somebody else had used the class, which is the worst way for an API
|
|
2285
|
+
* to go.
|
|
2286
|
+
*
|
|
2287
|
+
* So the rule stays and `Card` wears it. The lesson generalises to every
|
|
2288
|
+
* class in this package that a consumer can reach: a component may draw
|
|
2289
|
+
* itself with utilities only where its class is genuinely private. */
|
|
1522
2290
|
.card {
|
|
2291
|
+
display: block;
|
|
2292
|
+
width: 100%;
|
|
2293
|
+
box-sizing: border-box;
|
|
2294
|
+
font: inherit;
|
|
2295
|
+
color: var(--text);
|
|
2296
|
+
text-align: left;
|
|
1523
2297
|
background: var(--panel);
|
|
1524
2298
|
border: var(--border-width) solid var(--border);
|
|
1525
2299
|
border-radius: var(--radius-md);
|
|
1526
|
-
padding: var(--space-3)
|
|
2300
|
+
padding: var(--space-3);
|
|
1527
2301
|
margin-bottom: var(--space-3);
|
|
1528
2302
|
}
|
|
1529
2303
|
|
|
2304
|
+
/* What is left once `Card` draws its own box: the tones, the pick and
|
|
2305
|
+
selected states, and the rules that reach from the card into what it
|
|
2306
|
+
holds. `:has(.card-icon) .card-inline` is a relationship, and a tone is a
|
|
2307
|
+
`color-mix`; neither is a property on one element. */
|
|
2308
|
+
|
|
1530
2309
|
/* Header, when there is one. The title and the line under it were retyped at
|
|
1531
2310
|
every call site and no two agreed on the gap between them. */
|
|
1532
|
-
.card-head { display: flex; align-items: flex-start; gap: var(--space-3); }
|
|
1533
|
-
|
|
1534
|
-
.card-head:not(:last-child) { margin-bottom: var(--space-3); }
|
|
1535
|
-
|
|
1536
|
-
.card-headings { min-width: 0; flex: 1; }
|
|
1537
|
-
|
|
1538
2311
|
/* The card owns the space between the things it holds. Without this a callout
|
|
1539
2312
|
and the button under it sit edge to edge, and every caller has to remember a
|
|
1540
2313
|
margin on whichever child happens to be second. */
|
|
1541
|
-
.card-body { display: grid; gap: var(--space-3); }
|
|
1542
|
-
|
|
1543
2314
|
/* The card's own control, on the card's padding rather than indented into its
|
|
1544
2315
|
body. Centred against the whole heading block, not against the title -- a
|
|
1545
2316
|
switch aligned to the first line drifts upward the moment the description
|
|
1546
2317
|
runs to two. */
|
|
1547
|
-
.card-action { flex: none; align-self: center; display: flex; align-items: center; }
|
|
1548
|
-
|
|
1549
2318
|
/* A row inside a card that lines up with the header rather than indenting past
|
|
1550
2319
|
it: same left edge as the title, same right edge as the action. Its label is
|
|
1551
2320
|
a quiet caption, not a second heading -- the card already has one, and two
|
|
@@ -1592,17 +2361,6 @@ a.btn.danger:active:not([aria-disabled='true']) {
|
|
|
1592
2361
|
color: var(--muted);
|
|
1593
2362
|
}
|
|
1594
2363
|
|
|
1595
|
-
/* A card that is itself the choice. Reset first, because it is a `<button>`
|
|
1596
|
-
now and inherits a control's padding and centring. */
|
|
1597
|
-
button.card {
|
|
1598
|
-
display: block;
|
|
1599
|
-
width: 100%;
|
|
1600
|
-
text-align: left;
|
|
1601
|
-
font: inherit;
|
|
1602
|
-
color: inherit;
|
|
1603
|
-
padding: var(--space-3);
|
|
1604
|
-
}
|
|
1605
|
-
|
|
1606
2364
|
/* Variants, because a card is doing four jobs and looked like one.
|
|
1607
2365
|
A search result you can act on, a thing already installed, something that
|
|
1608
2366
|
went wrong, and a heading with rows under it are not the same object, and
|
|
@@ -1645,6 +2403,20 @@ button.card {
|
|
|
1645
2403
|
|
|
1646
2404
|
.modal-body .card { background: var(--panel-2); }
|
|
1647
2405
|
|
|
2406
|
+
/* Selected, which used to arrive from `button[aria-pressed='true']`.
|
|
2407
|
+
*
|
|
2408
|
+
* A card marks its choice with `aria-pressed`, and the tint came from the
|
|
2409
|
+
* element rule every bare `<button>` in the package was picking up. That rule
|
|
2410
|
+
* belongs to `Button` now, so the card says what being chosen looks like --
|
|
2411
|
+
* which is the right place for it anyway: a chosen card is a card's idea, not
|
|
2412
|
+
* a button's. */
|
|
2413
|
+
.card[aria-pressed='true'] {
|
|
2414
|
+
border-color: var(--accent);
|
|
2415
|
+
background: color-mix(in srgb, var(--accent) 10%, var(--panel));
|
|
2416
|
+
}
|
|
2417
|
+
|
|
2418
|
+
.card[aria-pressed='true']:hover { border-color: var(--accent); }
|
|
2419
|
+
|
|
1648
2420
|
/* ---- ./toggle.css ---- */
|
|
1649
2421
|
.card-action .switch-row { padding: 0; gap: var(--space-2); }
|
|
1650
2422
|
|
|
@@ -2195,71 +2967,21 @@ input[type='radio']:active:not(:disabled) {
|
|
|
2195
2967
|
|
|
2196
2968
|
.row-hit:focus-visible { outline: none; box-shadow: var(--focus-ring); }
|
|
2197
2969
|
|
|
2198
|
-
/* ---- ./empty.css ---- */
|
|
2199
|
-
/* `Empty`: a list with nothing in it.
|
|
2200
|
-
|
|
2201
|
-
Quieter than `.empty`, which is a whole-screen state at `--space-10`. These
|
|
2202
|
-
sit inside a card that already has a heading and a description, so the same
|
|
2203
|
-
padding would leave a card that is mostly air about nothing.
|
|
2204
|
-
|
|
2205
|
-
Dashed rather than solid: a solid border reads as a thing, and the point of
|
|
2206
|
-
this box is that there is no thing. It marks out where the list will be. */
|
|
2207
|
-
.nothing {
|
|
2208
|
-
display: grid;
|
|
2209
|
-
justify-items: center;
|
|
2210
|
-
gap: var(--space-2);
|
|
2211
|
-
padding: var(--space-5) var(--space-4);
|
|
2212
|
-
border: var(--border-width) dashed var(--border-strong);
|
|
2213
|
-
border-radius: var(--radius-md);
|
|
2214
|
-
text-align: center;
|
|
2215
|
-
}
|
|
2216
|
-
|
|
2217
|
-
.nothing-mark { color: var(--muted); line-height: 0; }
|
|
2218
|
-
|
|
2219
|
-
/* The same box with a figure in it, for a whole surface rather than a slot in
|
|
2220
|
-
a card. Two things change and both follow from the size: the dashed outline
|
|
2221
|
-
goes, because an outline marks out where a list will be and a window-sized
|
|
2222
|
-
dashed rectangle reads as a layout that failed rather than a view with
|
|
2223
|
-
nothing on it; and the box centres itself in whatever it was dropped into,
|
|
2224
|
-
which is what makes it land in the middle of an empty dashboard rather than
|
|
2225
|
-
under the header. */
|
|
2226
|
-
.nothing-surface {
|
|
2227
|
-
border: none;
|
|
2228
|
-
padding: var(--space-10) var(--space-4);
|
|
2229
|
-
gap: var(--space-3);
|
|
2230
|
-
margin: auto;
|
|
2231
|
-
}
|
|
2232
|
-
|
|
2233
|
-
/* `currentColor` reaches the figure through the two rules the illustrations
|
|
2234
|
-
ship with, so the colour is set here and the drawing follows it -- the same
|
|
2235
|
-
grey as the sentence under it, in every theme.
|
|
2236
|
-
Two classes, not one: `.illo` sets `color: inherit` further down this file,
|
|
2237
|
-
which beats a single-class rule written earlier and drew the figure in full
|
|
2238
|
-
text black beside a muted sentence. */
|
|
2239
|
-
.nothing-surface .nothing-figure { color: var(--muted); }
|
|
2240
|
-
|
|
2241
|
-
/* `--text-sm`, not the `--text-xs` these lines used to be: it is a sentence
|
|
2242
|
-
somebody is meant to read, not a caption qualifying something else. */
|
|
2243
|
-
.nothing-said { margin: 0; color: var(--muted); font-size: var(--text-sm); line-height: 1.5; max-width: 46ch; }
|
|
2244
|
-
|
|
2245
|
-
.nothing-act { margin-top: var(--space-1); }
|
|
2246
|
-
|
|
2247
2970
|
/* ---- ./progress.css ---- */
|
|
2248
2971
|
/* progress ----------------------------------------------------------- */
|
|
2249
2972
|
|
|
2250
|
-
/* The bar
|
|
2973
|
+
/* The bar itself: a track with a child it fills, an animation and a
|
|
2974
|
+
reduced-motion answer. A utility is a property on one element, so none of
|
|
2975
|
+
that is one -- `Progress` draws its own wrapper and head with utilities and
|
|
2976
|
+
this is what is left.
|
|
2977
|
+
|
|
2978
|
+
The bar sat 4px under its own label and flush against whatever was above
|
|
2251
2979
|
the whole block, so a download row read as four lines of text with a rule
|
|
2252
2980
|
drawn through the last one. The label is a caption for the bar and stays
|
|
2253
2981
|
close to it; the block as a whole is a separate statement from the row it
|
|
2254
2982
|
follows. */
|
|
2255
|
-
.progress { display: grid; gap: var(--space-1); }
|
|
2256
|
-
|
|
2257
2983
|
.card > .progress { margin-top: var(--space-3); }
|
|
2258
2984
|
|
|
2259
|
-
.progress-head { display: flex; align-items: baseline; gap: var(--space-2); font-size: var(--text-sm); }
|
|
2260
|
-
|
|
2261
|
-
.progress-detail { color: var(--muted); font-size: var(--text-xs); }
|
|
2262
|
-
|
|
2263
2985
|
.bar { height: 6px; background: var(--panel-2); border-radius: var(--radius-pill); overflow: hidden; }
|
|
2264
2986
|
|
|
2265
2987
|
.bar > i {
|
|
@@ -2293,6 +3015,14 @@ input[type='radio']:active:not(:disabled) {
|
|
|
2293
3015
|
.tabs { position: relative; display: flex; gap: var(--space-1); }
|
|
2294
3016
|
|
|
2295
3017
|
.tab {
|
|
3018
|
+
/* 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. */
|
|
3019
|
+
display: inline-flex;
|
|
3020
|
+
align-items: center;
|
|
3021
|
+
justify-content: center;
|
|
3022
|
+
gap: var(--space-2);
|
|
3023
|
+
/* 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`. */
|
|
3024
|
+
font: inherit;
|
|
3025
|
+
cursor: pointer;
|
|
2296
3026
|
position: relative;
|
|
2297
3027
|
z-index: 1;
|
|
2298
3028
|
background: transparent;
|
|
@@ -2449,6 +3179,38 @@ input[type='radio']:active:not(:disabled) {
|
|
|
2449
3179
|
.toast[data-exiting] { animation: none; }
|
|
2450
3180
|
}
|
|
2451
3181
|
|
|
3182
|
+
/* The dismiss control, in its own words.
|
|
3183
|
+
*
|
|
3184
|
+
* It was `className="ghost size-sm"` -- `Button`'s vocabulary, borrowed from
|
|
3185
|
+
* a component that does not render a `Button`. That only ever worked because
|
|
3186
|
+
* `.ghost` and `.size-sm` were element-and-class rules any `<button>` could
|
|
3187
|
+
* pick up, which is the coupling this pass is removing. Nothing photographed
|
|
3188
|
+
* it, either: the toast is transient and the close button is not in any
|
|
3189
|
+
* baseline, so this would have gone quiet. */
|
|
3190
|
+
.toast-close {
|
|
3191
|
+
display: inline-flex;
|
|
3192
|
+
align-items: center;
|
|
3193
|
+
justify-content: center;
|
|
3194
|
+
font: inherit;
|
|
3195
|
+
font-size: var(--text-xs);
|
|
3196
|
+
padding: var(--space-1) var(--space-2);
|
|
3197
|
+
background: transparent;
|
|
3198
|
+
border: var(--border-width) solid transparent;
|
|
3199
|
+
border-radius: var(--radius);
|
|
3200
|
+
color: var(--muted);
|
|
3201
|
+
cursor: pointer;
|
|
3202
|
+
}
|
|
3203
|
+
|
|
3204
|
+
.toast-close:hover:not(:disabled) {
|
|
3205
|
+
background: var(--panel-2);
|
|
3206
|
+
color: var(--text);
|
|
3207
|
+
}
|
|
3208
|
+
|
|
3209
|
+
.toast-close:focus-visible {
|
|
3210
|
+
outline: 2px solid var(--accent);
|
|
3211
|
+
outline-offset: 2px;
|
|
3212
|
+
}
|
|
3213
|
+
|
|
2452
3214
|
/* ---- ./modal.css ---- */
|
|
2453
3215
|
/* modal --------------------------------------------------------------- */
|
|
2454
3216
|
|
|
@@ -2489,13 +3251,6 @@ input[type='radio']:active:not(:disabled) {
|
|
|
2489
3251
|
Not `display: contents`, which was the first attempt. An element with no box
|
|
2490
3252
|
cannot take focus, so React Aria's initial focus fell through to the first
|
|
2491
3253
|
input and Escape -- handled on the section -- stopped closing the window. */
|
|
2492
|
-
.modal-dialog {
|
|
2493
|
-
display: flex;
|
|
2494
|
-
flex-direction: column;
|
|
2495
|
-
min-height: 0;
|
|
2496
|
-
flex: 1;
|
|
2497
|
-
}
|
|
2498
|
-
|
|
2499
3254
|
.modal {
|
|
2500
3255
|
background: var(--panel);
|
|
2501
3256
|
border: 1px solid var(--border);
|
|
@@ -2546,18 +3301,9 @@ input[type='radio']:active:not(:disabled) {
|
|
|
2546
3301
|
laid out for the bare `<strong>` it used to hold -- 86px tall with them,
|
|
2547
3302
|
41px without, on a head whose padding is 12 over 8. `font: inherit` so the
|
|
2548
3303
|
`<strong>` rule above is the one that sets the size. */
|
|
2549
|
-
.modal-title { margin: 0; font: inherit; }
|
|
2550
|
-
|
|
2551
3304
|
/* Under the title, on the header's padding rather than the body's, so it reads
|
|
2552
3305
|
as part of the heading rather than as the first line of content. */
|
|
2553
|
-
.modal-desc {
|
|
2554
|
-
margin: 0;
|
|
2555
|
-
padding: 0 var(--space-4) var(--space-3);
|
|
2556
|
-
color: var(--muted);
|
|
2557
|
-
font-size: var(--text-sm);
|
|
2558
|
-
line-height: 1.5;
|
|
2559
|
-
max-width: 62ch;
|
|
2560
|
-
}
|
|
3306
|
+
.modal-desc { line-height: 1.5; }
|
|
2561
3307
|
|
|
2562
3308
|
.modal-body { padding: var(--space-2) var(--space-4) var(--space-3); overflow-y: auto; }
|
|
2563
3309
|
|
|
@@ -2917,7 +3663,8 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
|
|
|
2917
3663
|
buttons only, so a button in a row stood 25px beside a 35px select and no
|
|
2918
3664
|
size class could ask for the select's height. Type from the row, box from
|
|
2919
3665
|
the scale, and the two line up; an explicit `size-*` still wins. */
|
|
2920
|
-
:where(.set-row) button,
|
|
3666
|
+
:where(.set-row) button,
|
|
3667
|
+
:where(.set-row) .slider-box { font-size: var(--text-xs); }
|
|
2921
3668
|
|
|
2922
3669
|
/* ---- ./checkbox.css ---- */
|
|
2923
3670
|
/* A row you choose. There is no checkbox in it.
|
|
@@ -3095,30 +3842,28 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
|
|
|
3095
3842
|
one. The cell is bold because it is a heading; what hangs under it is not,
|
|
3096
3843
|
and inherited the weight -- so a pinned version read as loud as the thing it
|
|
3097
3844
|
versions. */
|
|
3098
|
-
.table th .set-hint { font-weight: 400; }
|
|
3845
|
+
.data-table th .set-hint { font-weight: 400; }
|
|
3099
3846
|
|
|
3100
|
-
.table
|
|
3101
|
-
|
|
3102
|
-
.table {
|
|
3847
|
+
.data-table {
|
|
3103
3848
|
width: 100%;
|
|
3104
3849
|
border-collapse: collapse;
|
|
3105
3850
|
font-size: var(--text-sm);
|
|
3106
3851
|
}
|
|
3107
3852
|
|
|
3108
|
-
.table th,
|
|
3109
|
-
.table td {
|
|
3853
|
+
.data-table th,
|
|
3854
|
+
.data-table td {
|
|
3110
3855
|
text-align: left;
|
|
3111
3856
|
padding: var(--space-2) var(--space-3);
|
|
3112
3857
|
border-bottom: var(--border-width) solid var(--border);
|
|
3113
3858
|
}
|
|
3114
3859
|
|
|
3115
|
-
.table th:first-child,
|
|
3116
|
-
.table td:first-child { padding-left: 0; }
|
|
3860
|
+
.data-table th:first-child,
|
|
3861
|
+
.data-table td:first-child { padding-left: 0; }
|
|
3117
3862
|
|
|
3118
|
-
.table th:last-child,
|
|
3119
|
-
.table td:last-child { padding-right: 0; }
|
|
3863
|
+
.data-table th:last-child,
|
|
3864
|
+
.data-table td:last-child { padding-right: 0; }
|
|
3120
3865
|
|
|
3121
|
-
.table thead th {
|
|
3866
|
+
.data-table thead th {
|
|
3122
3867
|
font-size: var(--text-xs);
|
|
3123
3868
|
font-weight: var(--weight-strong);
|
|
3124
3869
|
text-transform: uppercase;
|
|
@@ -3129,40 +3874,31 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
|
|
|
3129
3874
|
|
|
3130
3875
|
/* The row's own name: a `<th scope="row">`, so it carries weight rather than
|
|
3131
3876
|
reading as one more cell. */
|
|
3132
|
-
.table tbody th { font-weight: var(--weight-strong); }
|
|
3877
|
+
.data-table tbody th { font-weight: var(--weight-strong); }
|
|
3133
3878
|
|
|
3134
|
-
.table tbody tr:last-child th,
|
|
3135
|
-
.table tbody tr:last-child td { border-bottom: none; }
|
|
3879
|
+
.data-table tbody tr:last-child th,
|
|
3880
|
+
.data-table tbody tr:last-child td { border-bottom: none; }
|
|
3136
3881
|
|
|
3137
3882
|
/* Numbers compare by column, so they align right and hold their tracks --
|
|
3138
3883
|
proportional digits shift the alignment by a pixel per glyph, which is
|
|
3139
3884
|
exactly the comparison the column was for. */
|
|
3140
|
-
.table .num { text-align: right; font-variant-numeric: tabular-nums; font-family: var(--font-mono); }
|
|
3885
|
+
.data-table .num { text-align: right; font-variant-numeric: tabular-nums; font-family: var(--font-mono); }
|
|
3141
3886
|
|
|
3142
|
-
.table thead th[style*='right'] { text-align: right; }
|
|
3887
|
+
.data-table thead th[style*='right'] { text-align: right; }
|
|
3143
3888
|
|
|
3144
3889
|
/* ---- ./sizegrid.css ---- */
|
|
3145
|
-
/*
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3890
|
+
/* What is left of the size grid once it draws itself.
|
|
3891
|
+
*
|
|
3892
|
+
* `on` follows the pointer; `chosen` is what is actually saved, shown only
|
|
3893
|
+
* when nothing is hovered so the two can never contradict each other.
|
|
3894
|
+
* `chosen` is a border colour and says so at the call site; `on` is a fill
|
|
3895
|
+
* mixed from the accent, and `color-mix` in an arbitrary value is less
|
|
3896
|
+
* readable than the rule it replaces. */
|
|
3897
|
+
.size-cell.on {
|
|
3898
|
+
border-color: var(--accent);
|
|
3899
|
+
background: color-mix(in srgb, var(--accent) 45%, transparent);
|
|
3154
3900
|
}
|
|
3155
3901
|
|
|
3156
|
-
/* `on` follows the pointer; `chosen` is what is actually saved, shown only
|
|
3157
|
-
when nothing is hovered so the two can never contradict each other. */
|
|
3158
|
-
.size-cell.on { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 45%, transparent); }
|
|
3159
|
-
|
|
3160
|
-
.size-cell.chosen { border-color: var(--accent); }
|
|
3161
|
-
|
|
3162
|
-
.size-cell:disabled { cursor: default; opacity: 0.5; }
|
|
3163
|
-
|
|
3164
|
-
.size-ceiling { opacity: 0.55; }
|
|
3165
|
-
|
|
3166
3902
|
/* ---- ./tooltip.css ---- */
|
|
3167
3903
|
/* A callout: something worth knowing, with nothing to answer. Distinct from a
|
|
3168
3904
|
`?`, which is an offer to read more, and from a banner, which is a problem.
|
|
@@ -3171,36 +3907,15 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
|
|
|
3171
3907
|
/* An info-toned `.callout`, spelled the old way. Identical to it now rather than
|
|
3172
3908
|
nearly identical to it, which is the whole point of the consolidation: the
|
|
3173
3909
|
|
|
3174
|
-
/*
|
|
3910
|
+
/* What is left once `Tooltip` draws its own mark: the hover and focus that
|
|
3911
|
+
reach the mark from its parent, and the tip -- whose closed and open
|
|
3912
|
+
states are three rules the cascade resolves in order, with
|
|
3913
|
+
`data-entering` and `data-exiting` around the transition. None of that is
|
|
3914
|
+
a property on one element.
|
|
3915
|
+
|
|
3916
|
+
The `?` beside a setting, and the box it shows on hover. Built like the
|
|
3175
3917
|
status dot's tooltip and for the same reasons: `title` waits a second and a
|
|
3176
3918
|
half, renders newlines however it likes, and cannot be styled. */
|
|
3177
|
-
.explain {
|
|
3178
|
-
position: relative;
|
|
3179
|
-
flex: none;
|
|
3180
|
-
display: inline-flex;
|
|
3181
|
-
align-items: center;
|
|
3182
|
-
/* The heading it follows is tracked out, which leaves the last letter's
|
|
3183
|
-
spacing sitting between them and reads as none at all. */
|
|
3184
|
-
margin-left: var(--space-2);
|
|
3185
|
-
cursor: help;
|
|
3186
|
-
/* Headings here are uppercase and tracked out, and one of these sits inside
|
|
3187
|
-
a heading. */
|
|
3188
|
-
text-transform: none;
|
|
3189
|
-
letter-spacing: normal;
|
|
3190
|
-
font-weight: 400;
|
|
3191
|
-
}
|
|
3192
|
-
|
|
3193
|
-
.explain-mark {
|
|
3194
|
-
width: 18px;
|
|
3195
|
-
height: 18px;
|
|
3196
|
-
border-radius: 50%;
|
|
3197
|
-
border: 1px solid var(--border);
|
|
3198
|
-
color: var(--muted);
|
|
3199
|
-
font-size: var(--text-xs);
|
|
3200
|
-
line-height: 16px;
|
|
3201
|
-
text-align: center;
|
|
3202
|
-
}
|
|
3203
|
-
|
|
3204
3919
|
.explain:hover .explain-mark,
|
|
3205
3920
|
.explain:focus-visible .explain-mark { color: var(--text); border-color: var(--accent); }
|
|
3206
3921
|
|
|
@@ -3301,6 +4016,18 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
|
|
|
3301
4016
|
a shirt that lets the arm behind it show through reads as a hole. */
|
|
3302
4017
|
.illo .paper { fill: var(--illo-paper); }
|
|
3303
4018
|
|
|
4019
|
+
/* The figure in a whole-surface `Empty`, drawn in the muted grey of the
|
|
4020
|
+
sentence under it.
|
|
4021
|
+
*
|
|
4022
|
+
* A utility cannot do this, and the reason is worth keeping: `.illo` sets
|
|
4023
|
+
* `color: inherit` and is unlayered, while every Tailwind utility lives in
|
|
4024
|
+
* `@layer utilities` -- and an unlayered declaration beats a layered one
|
|
4025
|
+
* whatever the specificity. So `text-muted` on the figure lost, silently,
|
|
4026
|
+
* and the shirt came out full text black beside a muted sentence. The
|
|
4027
|
+
* original rule already carried a note about needing two classes to beat
|
|
4028
|
+
* `.illo`; layers make that impossible rather than merely fiddly. */
|
|
4029
|
+
.nothing-figure { color: var(--muted); }
|
|
4030
|
+
|
|
3304
4031
|
/* ---- ./field.css ---- */
|
|
3305
4032
|
/* fields --------------------------------------------------------------- */
|
|
3306
4033
|
|
|
@@ -3388,6 +4115,95 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
|
|
|
3388
4115
|
|
|
3389
4116
|
.secret-lg > .secret-eye { padding: var(--space-2); }
|
|
3390
4117
|
|
|
4118
|
+
/* An input with something inside its edges: a glyph on the left, a hint or a
|
|
4119
|
+
clear button on the right. Same arrangement as `.secret` above, and for the
|
|
4120
|
+
same reason -- one grid cell with everything stacked in it, and the room
|
|
4121
|
+
reserved in the input's own padding, so nothing is positioned against a
|
|
4122
|
+
height that changes with `size`. */
|
|
4123
|
+
.adorned { display: grid; align-items: center; }
|
|
4124
|
+
|
|
4125
|
+
.adorned > input,
|
|
4126
|
+
.adorned > .adorned-mark,
|
|
4127
|
+
.adorned > .adorned-end { grid-area: 1 / 1; }
|
|
4128
|
+
|
|
4129
|
+
.adorned.ctl-block { width: 100%; }
|
|
4130
|
+
|
|
4131
|
+
.adorned > .adorned-mark {
|
|
4132
|
+
justify-self: start;
|
|
4133
|
+
margin-left: var(--space-2);
|
|
4134
|
+
color: var(--muted);
|
|
4135
|
+
/* The glyph is decoration over the box; clicks belong to the input under
|
|
4136
|
+
it, which is otherwise unreachable in its own left edge. */
|
|
4137
|
+
pointer-events: none;
|
|
4138
|
+
/* Over the input, not under it. Both share one grid cell, the input has an
|
|
4139
|
+
opaque `--control` background, and it comes later in the DOM -- so
|
|
4140
|
+
without this the glyph is painted and then covered, which looks exactly
|
|
4141
|
+
like an icon that failed to render. `.secret` never hit this because its
|
|
4142
|
+
button is written after the input. */
|
|
4143
|
+
z-index: 1;
|
|
4144
|
+
}
|
|
4145
|
+
|
|
4146
|
+
/* Room for the glyph, on the scale, so a density change moves the text with
|
|
4147
|
+
the mark rather than leaving one behind. `--space-8` is what `.secret`
|
|
4148
|
+
reserves on the right for the same reason; the scale has no 7, and an
|
|
4149
|
+
undefined custom property does not fall back -- the declaration computes
|
|
4150
|
+
to 0 and the text sits under the glyph. */
|
|
4151
|
+
.adorned-icon > input { padding-left: var(--space-8); }
|
|
4152
|
+
|
|
4153
|
+
/* No `--space-12` on the scale; two steps that are, added. Same arithmetic
|
|
4154
|
+
as `.secret-lg`. */
|
|
4155
|
+
.adorned-icon.adorned-lg > input { padding-left: calc(var(--space-10) + var(--space-1)); }
|
|
4156
|
+
|
|
4157
|
+
.adorned > .adorned-end {
|
|
4158
|
+
justify-self: end;
|
|
4159
|
+
display: flex;
|
|
4160
|
+
align-items: center;
|
|
4161
|
+
gap: var(--space-1);
|
|
4162
|
+
margin-right: var(--space-1);
|
|
4163
|
+
}
|
|
4164
|
+
|
|
4165
|
+
/* `:has`, not a sibling combinator: the input comes *before* the end cap in
|
|
4166
|
+
the DOM, so `~` reads the wrong way and matches nothing. */
|
|
4167
|
+
.adorned:has(> .adorned-end) > input { padding-right: var(--space-8); }
|
|
4168
|
+
.adorned-lg:has(> .adorned-end) > input {
|
|
4169
|
+
padding-right: calc(var(--space-10) + var(--space-1));
|
|
4170
|
+
}
|
|
4171
|
+
|
|
4172
|
+
/* Sized from its glyph, not `.icon-btn`'s 34px tile, which would be taller
|
|
4173
|
+
than a small input -- the note above `.secret-eye` in full. */
|
|
4174
|
+
.adorned-clear {
|
|
4175
|
+
width: auto; height: auto;
|
|
4176
|
+
padding: var(--space-1);
|
|
4177
|
+
opacity: 1;
|
|
4178
|
+
}
|
|
4179
|
+
|
|
4180
|
+
.adorned-lg .adorned-clear { padding: var(--space-2); }
|
|
4181
|
+
|
|
4182
|
+
/* The eye and the clear button stop borrowing `ghost`.
|
|
4183
|
+
*
|
|
4184
|
+
* Both were `className="icon-btn ghost …"` -- reaching into `Button`'s class
|
|
4185
|
+
* vocabulary from another component, which worked only because `.ghost` was
|
|
4186
|
+
* written as `button.ghost` and they happen to be `<button>`s. It is `.btn.ghost`
|
|
4187
|
+
* now, so the borrowing stopped matching and `.icon-btn`'s panel background
|
|
4188
|
+
* came through: the baselines showed a filled tile where there had been a bare
|
|
4189
|
+
* glyph.
|
|
4190
|
+
*
|
|
4191
|
+
* Stated here instead. What they actually wanted from `ghost` is two lines,
|
|
4192
|
+
* and saying them is cheaper than either component knowing what a button's
|
|
4193
|
+
* classes are called. */
|
|
4194
|
+
.secret-eye,
|
|
4195
|
+
.adorned-clear {
|
|
4196
|
+
background: transparent;
|
|
4197
|
+
border-color: transparent;
|
|
4198
|
+
color: var(--muted);
|
|
4199
|
+
}
|
|
4200
|
+
|
|
4201
|
+
.secret-eye:hover:not(:disabled),
|
|
4202
|
+
.adorned-clear:hover:not(:disabled) {
|
|
4203
|
+
background: var(--panel-2);
|
|
4204
|
+
color: var(--text);
|
|
4205
|
+
}
|
|
4206
|
+
|
|
3391
4207
|
/* ---- ./tour.css ---- */
|
|
3392
4208
|
/* tour ----------------------------------------------------------------- */
|
|
3393
4209
|
|
|
@@ -3455,72 +4271,46 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
|
|
|
3455
4271
|
anchored surfaces (`.pop`, `.menu-sheet`, `.cmd`) sit over everything and a
|
|
3456
4272
|
rule of equal specificity that came earlier would lose to whatever the
|
|
3457
4273
|
sheets they cover happen to set. */
|
|
3458
|
-
/* ---- ./kbd.css ---- */
|
|
3459
|
-
/* One rule where there were two identical ones, in `menu.css` and
|
|
3460
|
-
`command.css`. Both keep their class as well, so `Menu` and `Command` are
|
|
3461
|
-
`.kbd .menu-key` and `.kbd .cmd-key` now: the declarations are the same, so
|
|
3462
|
-
nothing moves, and the context classes stay available for a rule that ever
|
|
3463
|
-
needs to tell the two apart. */
|
|
3464
|
-
.kbd {
|
|
3465
|
-
flex: none;
|
|
3466
|
-
font-family: var(--font-mono);
|
|
3467
|
-
font-size: var(--text-2xs);
|
|
3468
|
-
color: var(--muted);
|
|
3469
|
-
letter-spacing: var(--tracking);
|
|
3470
|
-
}
|
|
3471
|
-
|
|
3472
4274
|
/* ---- ./stat.css ---- */
|
|
3473
|
-
/*
|
|
3474
|
-
|
|
3475
|
-
.
|
|
3476
|
-
display: grid;
|
|
3477
|
-
gap: var(--space-1);
|
|
3478
|
-
padding: var(--space-4);
|
|
3479
|
-
border: var(--border-width) solid var(--border);
|
|
3480
|
-
border-radius: var(--radius-md);
|
|
3481
|
-
background: var(--panel);
|
|
3482
|
-
}
|
|
3483
|
-
|
|
3484
|
-
/* Inside something already bordered. A bordered tile in a bordered row is two
|
|
3485
|
-
boxes saying one thing. */
|
|
3486
|
-
.stat-bare {
|
|
3487
|
-
padding: 0;
|
|
3488
|
-
border: 0;
|
|
3489
|
-
border-radius: 0;
|
|
3490
|
-
background: none;
|
|
3491
|
-
gap: 0;
|
|
3492
|
-
line-height: 1.25;
|
|
3493
|
-
}
|
|
3494
|
-
|
|
3495
|
-
.stat > p { margin: 0; }
|
|
4275
|
+
/* What the utilities on `Stat` cannot say: a tone on the tile colouring the
|
|
4276
|
+
figure inside it. An attribute on the parent selecting a child is a
|
|
4277
|
+
relationship; a utility is a property on one element.
|
|
3496
4278
|
|
|
3497
|
-
.
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
}
|
|
4279
|
+
Only the figure takes the colour. Colouring the label too makes the tile a
|
|
4280
|
+
status box, where a tone here is a remark about the number. */
|
|
4281
|
+
.stat[data-tone='info'] .stat-value { color: var(--info); }
|
|
4282
|
+
.stat[data-tone='good'] .stat-value { color: var(--good); }
|
|
4283
|
+
.stat[data-tone='warn'] .stat-value { color: var(--warn); }
|
|
4284
|
+
.stat[data-tone='bad'] .stat-value { color: var(--bad); }
|
|
3501
4285
|
|
|
3502
|
-
/*
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
4286
|
+
/* ---- ./shell.css ---- */
|
|
4287
|
+
/* The measure, and only the measure.
|
|
4288
|
+
*
|
|
4289
|
+
* `Shell` draws itself with utilities -- it is layout and nothing else. What
|
|
4290
|
+
* stays here is the one value the header band, the nav band and the main band
|
|
4291
|
+
* all have to agree on: a custom property, so an app changes it in one place
|
|
4292
|
+
* rather than overriding three rules and missing the fourth. That is how
|
|
4293
|
+
* manage ended up carrying `head-inner-wide` and `main-wide` as separate
|
|
4294
|
+
* classes it had to remember together. */
|
|
4295
|
+
.shell {
|
|
4296
|
+
--shell-measure: 64rem;
|
|
4297
|
+
--shell-measure-wide: 90rem;
|
|
4298
|
+
}
|
|
4299
|
+
|
|
4300
|
+
/* The label beside the theme control, when it is drawn. */
|
|
4301
|
+
.theme-switch {
|
|
4302
|
+
display: flex;
|
|
4303
|
+
align-items: center;
|
|
4304
|
+
gap: var(--space-2);
|
|
4305
|
+
min-width: 0;
|
|
3508
4306
|
}
|
|
3509
4307
|
|
|
3510
|
-
.
|
|
3511
|
-
|
|
3512
|
-
.stat-note {
|
|
4308
|
+
.theme-switch-label {
|
|
3513
4309
|
color: var(--muted);
|
|
3514
|
-
font-size: var(--text-
|
|
4310
|
+
font-size: var(--text-sm);
|
|
4311
|
+
white-space: nowrap;
|
|
3515
4312
|
}
|
|
3516
4313
|
|
|
3517
|
-
/* Only the figure takes the colour. Colouring the label too makes the tile a
|
|
3518
|
-
status box, and a tone here is a remark about the number. */
|
|
3519
|
-
.stat[data-tone='info'] .stat-value { color: var(--info); }
|
|
3520
|
-
.stat[data-tone='good'] .stat-value { color: var(--good); }
|
|
3521
|
-
.stat[data-tone='warn'] .stat-value { color: var(--warn); }
|
|
3522
|
-
.stat[data-tone='bad'] .stat-value { color: var(--bad); }
|
|
3523
|
-
|
|
3524
4314
|
/* ---- ./scrollarea.css ---- */
|
|
3525
4315
|
/* A box that scrolls, with its edges drawn.
|
|
3526
4316
|
|
|
@@ -3772,27 +4562,13 @@ body.splitting * { cursor: inherit !important; }
|
|
|
3772
4562
|
}
|
|
3773
4563
|
|
|
3774
4564
|
/* ---- ./menu.css ---- */
|
|
3775
|
-
/*
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
box-shadow: var(--shadow-2);
|
|
3781
|
-
min-width: 12rem;
|
|
3782
|
-
max-width: min(20rem, calc(100vw - var(--space-6)));
|
|
3783
|
-
max-height: 24rem;
|
|
3784
|
-
overflow: auto;
|
|
3785
|
-
overscroll-behavior: contain;
|
|
3786
|
-
z-index: 60;
|
|
3787
|
-
}
|
|
3788
|
-
|
|
3789
|
-
.menu-list {
|
|
3790
|
-
padding: var(--space-1);
|
|
3791
|
-
outline: none;
|
|
3792
|
-
display: grid;
|
|
3793
|
-
gap: var(--border-width);
|
|
3794
|
-
}
|
|
4565
|
+
/* What is left once `Menu` draws its sheet and its list: the rows, whose
|
|
4566
|
+
`data-focused`, `data-pressed` and danger states React Aria stamps on
|
|
4567
|
+
them, and the rules that reach from a row into what it holds. The
|
|
4568
|
+
`box-shadow` stays on the sheet too -- `--shadow-2` is a token, and a
|
|
4569
|
+
utility would have to inline it. */
|
|
3795
4570
|
|
|
4571
|
+
/* A list of verbs, on the same sheet as every other anchored surface. */
|
|
3796
4572
|
.menu-item {
|
|
3797
4573
|
display: flex;
|
|
3798
4574
|
align-items: center;
|
|
@@ -3831,14 +4607,6 @@ body.splitting * { cursor: inherit !important; }
|
|
|
3831
4607
|
/* The binding, set in the mono face at the size of the small print. Right of
|
|
3832
4608
|
the row and never the reason the row is wide: `flex: none` with the label
|
|
3833
4609
|
taking the slack. */
|
|
3834
|
-
.menu-key {
|
|
3835
|
-
flex: none;
|
|
3836
|
-
font-family: var(--font-mono);
|
|
3837
|
-
font-size: var(--text-2xs);
|
|
3838
|
-
color: var(--muted);
|
|
3839
|
-
letter-spacing: var(--tracking);
|
|
3840
|
-
}
|
|
3841
|
-
|
|
3842
4610
|
.menu-more { flex: none; color: var(--muted); }
|
|
3843
4611
|
|
|
3844
4612
|
.menu-rule {
|
|
@@ -3874,6 +4642,8 @@ body.splitting * { cursor: inherit !important; }
|
|
|
3874
4642
|
.menu-sheet[data-exiting] { animation: none; }
|
|
3875
4643
|
}
|
|
3876
4644
|
|
|
4645
|
+
.menu-sheet { box-shadow: var(--shadow-2); }
|
|
4646
|
+
|
|
3877
4647
|
/* ---- ./command.css ---- */
|
|
3878
4648
|
/* The command palette: a field over the app and a list under it. */
|
|
3879
4649
|
.cmd-scrim {
|
|
@@ -3991,14 +4761,6 @@ body.splitting * { cursor: inherit !important; }
|
|
|
3991
4761
|
white-space: nowrap;
|
|
3992
4762
|
}
|
|
3993
4763
|
|
|
3994
|
-
.cmd-key {
|
|
3995
|
-
flex: none;
|
|
3996
|
-
font-family: var(--font-mono);
|
|
3997
|
-
font-size: var(--text-2xs);
|
|
3998
|
-
color: var(--muted);
|
|
3999
|
-
letter-spacing: var(--tracking);
|
|
4000
|
-
}
|
|
4001
|
-
|
|
4002
4764
|
.cmd-empty {
|
|
4003
4765
|
margin: 0;
|
|
4004
4766
|
padding: var(--space-6) var(--space-4);
|
|
@@ -4026,23 +4788,14 @@ body.splitting * { cursor: inherit !important; }
|
|
|
4026
4788
|
}
|
|
4027
4789
|
|
|
4028
4790
|
/* ---- ./pagination.css ---- */
|
|
4029
|
-
/*
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
justify-content: space-between;
|
|
4034
|
-
gap: var(--space-4);
|
|
4035
|
-
flex-wrap: wrap;
|
|
4036
|
-
padding: var(--space-2) 0;
|
|
4037
|
-
font-size: var(--text-xs);
|
|
4038
|
-
color: var(--muted);
|
|
4039
|
-
}
|
|
4791
|
+
/* What is left once `Pagination` draws its own frame: the step and page
|
|
4792
|
+
buttons, whose hover, focus-visible and current states are pseudo-classes
|
|
4793
|
+
on two selectors at once, and `.pager-count strong`, which reaches into
|
|
4794
|
+
text the caller passed. */
|
|
4040
4795
|
|
|
4041
|
-
|
|
4796
|
+
/* Moving through a list that does not fit, and saying how far in you are. */
|
|
4042
4797
|
.pager-count strong { color: var(--text); font-weight: var(--weight-strong); }
|
|
4043
4798
|
|
|
4044
|
-
.pager-controls { display: flex; align-items: center; gap: var(--space-1); }
|
|
4045
|
-
|
|
4046
4799
|
.pager-step,
|
|
4047
4800
|
.pager-page {
|
|
4048
4801
|
display: inline-flex;
|
|
@@ -4234,6 +4987,8 @@ body.splitting * { cursor: inherit !important; }
|
|
|
4234
4987
|
}
|
|
4235
4988
|
|
|
4236
4989
|
.ident-remove {
|
|
4990
|
+
/* 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`. */
|
|
4991
|
+
font: inherit;
|
|
4237
4992
|
flex: none;
|
|
4238
4993
|
display: inline-flex;
|
|
4239
4994
|
align-items: center;
|