@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/valet.css
CHANGED
|
@@ -282,7 +282,700 @@
|
|
|
282
282
|
*
|
|
283
283
|
* `scripts/copy-css.mjs` flattens these into one file at build time.
|
|
284
284
|
*/
|
|
285
|
-
/* ---- ./
|
|
285
|
+
/* ---- ./_tailwind.built.css ---- */
|
|
286
|
+
/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
|
|
287
|
+
@layer properties;
|
|
288
|
+
@layer theme, base, components, utilities;
|
|
289
|
+
@layer theme {
|
|
290
|
+
:root, :host {
|
|
291
|
+
--font-sans: var(--font-sans);
|
|
292
|
+
--font-mono: var(--font-mono);
|
|
293
|
+
--text-xs: var(--text-xs);
|
|
294
|
+
--text-sm: var(--text-sm);
|
|
295
|
+
--text-base: var(--text-base);
|
|
296
|
+
--text-lg: var(--text-lg);
|
|
297
|
+
--text-xl: var(--text-xl);
|
|
298
|
+
--font-weight-normal: var(--weight);
|
|
299
|
+
--tracking-normal: var(--tracking);
|
|
300
|
+
--radius-sm: var(--radius-sm);
|
|
301
|
+
--radius-md: var(--radius-md);
|
|
302
|
+
--radius-lg: var(--radius-lg);
|
|
303
|
+
--ease-out: cubic-bezier(0, 0, 0.2, 1);
|
|
304
|
+
--spacing-1: var(--space-1);
|
|
305
|
+
--spacing-2: var(--space-2);
|
|
306
|
+
--spacing-3: var(--space-3);
|
|
307
|
+
--spacing-4: var(--space-4);
|
|
308
|
+
--spacing-5: var(--space-5);
|
|
309
|
+
--spacing-6: var(--space-6);
|
|
310
|
+
--spacing-10: var(--space-10);
|
|
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-border: var(--border);
|
|
318
|
+
--color-border-strong: var(--border-strong);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
@layer utilities {
|
|
322
|
+
.collapse {
|
|
323
|
+
visibility: collapse;
|
|
324
|
+
}
|
|
325
|
+
.invisible {
|
|
326
|
+
visibility: hidden;
|
|
327
|
+
}
|
|
328
|
+
.visible {
|
|
329
|
+
visibility: visible;
|
|
330
|
+
}
|
|
331
|
+
.sr-only {
|
|
332
|
+
position: absolute;
|
|
333
|
+
width: 1px;
|
|
334
|
+
height: 1px;
|
|
335
|
+
padding: 0;
|
|
336
|
+
margin: -1px;
|
|
337
|
+
overflow: hidden;
|
|
338
|
+
clip-path: inset(50%);
|
|
339
|
+
white-space: nowrap;
|
|
340
|
+
border-width: 0;
|
|
341
|
+
}
|
|
342
|
+
.absolute {
|
|
343
|
+
position: absolute;
|
|
344
|
+
}
|
|
345
|
+
.fixed {
|
|
346
|
+
position: fixed;
|
|
347
|
+
}
|
|
348
|
+
.relative {
|
|
349
|
+
position: relative;
|
|
350
|
+
}
|
|
351
|
+
.sticky {
|
|
352
|
+
position: sticky;
|
|
353
|
+
}
|
|
354
|
+
.z-\[60\] {
|
|
355
|
+
z-index: 60;
|
|
356
|
+
}
|
|
357
|
+
.container {
|
|
358
|
+
width: 100%;
|
|
359
|
+
@media (width >= 40rem) {
|
|
360
|
+
max-width: 40rem;
|
|
361
|
+
}
|
|
362
|
+
@media (width >= 48rem) {
|
|
363
|
+
max-width: 48rem;
|
|
364
|
+
}
|
|
365
|
+
@media (width >= 64rem) {
|
|
366
|
+
max-width: 64rem;
|
|
367
|
+
}
|
|
368
|
+
@media (width >= 80rem) {
|
|
369
|
+
max-width: 80rem;
|
|
370
|
+
}
|
|
371
|
+
@media (width >= 96rem) {
|
|
372
|
+
max-width: 96rem;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
.m-0 {
|
|
376
|
+
margin: 0px;
|
|
377
|
+
}
|
|
378
|
+
.m-auto {
|
|
379
|
+
margin: auto;
|
|
380
|
+
}
|
|
381
|
+
.mx-auto {
|
|
382
|
+
margin-inline: auto;
|
|
383
|
+
}
|
|
384
|
+
.mt-1 {
|
|
385
|
+
margin-top: var(--spacing-1);
|
|
386
|
+
}
|
|
387
|
+
.mb-3 {
|
|
388
|
+
margin-bottom: var(--spacing-3);
|
|
389
|
+
}
|
|
390
|
+
.ml-2 {
|
|
391
|
+
margin-left: var(--spacing-2);
|
|
392
|
+
}
|
|
393
|
+
.block {
|
|
394
|
+
display: block;
|
|
395
|
+
}
|
|
396
|
+
.contents {
|
|
397
|
+
display: contents;
|
|
398
|
+
}
|
|
399
|
+
.flex {
|
|
400
|
+
display: flex;
|
|
401
|
+
}
|
|
402
|
+
.grid {
|
|
403
|
+
display: grid;
|
|
404
|
+
}
|
|
405
|
+
.hidden {
|
|
406
|
+
display: none;
|
|
407
|
+
}
|
|
408
|
+
.inline {
|
|
409
|
+
display: inline;
|
|
410
|
+
}
|
|
411
|
+
.inline-flex {
|
|
412
|
+
display: inline-flex;
|
|
413
|
+
}
|
|
414
|
+
.table {
|
|
415
|
+
display: table;
|
|
416
|
+
}
|
|
417
|
+
.h-\[14px\] {
|
|
418
|
+
height: 14px;
|
|
419
|
+
}
|
|
420
|
+
.h-\[18px\] {
|
|
421
|
+
height: 18px;
|
|
422
|
+
}
|
|
423
|
+
.max-h-\[24rem\] {
|
|
424
|
+
max-height: 24rem;
|
|
425
|
+
}
|
|
426
|
+
.max-h-\[280px\] {
|
|
427
|
+
max-height: 280px;
|
|
428
|
+
}
|
|
429
|
+
.min-h-0 {
|
|
430
|
+
min-height: 0px;
|
|
431
|
+
}
|
|
432
|
+
.min-h-screen {
|
|
433
|
+
min-height: 100vh;
|
|
434
|
+
}
|
|
435
|
+
.w-\[18px\] {
|
|
436
|
+
width: 18px;
|
|
437
|
+
}
|
|
438
|
+
.w-full {
|
|
439
|
+
width: 100%;
|
|
440
|
+
}
|
|
441
|
+
.max-w-\[46ch\] {
|
|
442
|
+
max-width: 46ch;
|
|
443
|
+
}
|
|
444
|
+
.max-w-\[min\(20rem\,calc\(100vw-var\(--space-6\)\)\)\] {
|
|
445
|
+
max-width: min(20rem, calc(100vw - var(--space-6)));
|
|
446
|
+
}
|
|
447
|
+
.max-w-\[var\(--shell-measure\)\] {
|
|
448
|
+
max-width: var(--shell-measure);
|
|
449
|
+
}
|
|
450
|
+
.max-w-\[var\(--shell-measure-wide\)\] {
|
|
451
|
+
max-width: var(--shell-measure-wide);
|
|
452
|
+
}
|
|
453
|
+
.min-w-0 {
|
|
454
|
+
min-width: 0px;
|
|
455
|
+
}
|
|
456
|
+
.min-w-\[12rem\] {
|
|
457
|
+
min-width: 12rem;
|
|
458
|
+
}
|
|
459
|
+
.flex-1 {
|
|
460
|
+
flex: 1;
|
|
461
|
+
}
|
|
462
|
+
.flex-none {
|
|
463
|
+
flex: none;
|
|
464
|
+
}
|
|
465
|
+
.shrink {
|
|
466
|
+
flex-shrink: 1;
|
|
467
|
+
}
|
|
468
|
+
.grow {
|
|
469
|
+
flex-grow: 1;
|
|
470
|
+
}
|
|
471
|
+
.transform {
|
|
472
|
+
transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);
|
|
473
|
+
}
|
|
474
|
+
.cursor-help {
|
|
475
|
+
cursor: help;
|
|
476
|
+
}
|
|
477
|
+
.cursor-pointer {
|
|
478
|
+
cursor: pointer;
|
|
479
|
+
}
|
|
480
|
+
.resize {
|
|
481
|
+
resize: both;
|
|
482
|
+
}
|
|
483
|
+
.list-none {
|
|
484
|
+
list-style-type: none;
|
|
485
|
+
}
|
|
486
|
+
.flex-col {
|
|
487
|
+
flex-direction: column;
|
|
488
|
+
}
|
|
489
|
+
.flex-wrap {
|
|
490
|
+
flex-wrap: wrap;
|
|
491
|
+
}
|
|
492
|
+
.items-baseline {
|
|
493
|
+
align-items: baseline;
|
|
494
|
+
}
|
|
495
|
+
.items-center {
|
|
496
|
+
align-items: center;
|
|
497
|
+
}
|
|
498
|
+
.items-start {
|
|
499
|
+
align-items: flex-start;
|
|
500
|
+
}
|
|
501
|
+
.justify-between {
|
|
502
|
+
justify-content: space-between;
|
|
503
|
+
}
|
|
504
|
+
.justify-items-center {
|
|
505
|
+
justify-items: center;
|
|
506
|
+
}
|
|
507
|
+
.gap-0 {
|
|
508
|
+
gap: 0px;
|
|
509
|
+
}
|
|
510
|
+
.gap-1 {
|
|
511
|
+
gap: var(--spacing-1);
|
|
512
|
+
}
|
|
513
|
+
.gap-2 {
|
|
514
|
+
gap: var(--spacing-2);
|
|
515
|
+
}
|
|
516
|
+
.gap-3 {
|
|
517
|
+
gap: var(--spacing-3);
|
|
518
|
+
}
|
|
519
|
+
.gap-4 {
|
|
520
|
+
gap: var(--spacing-4);
|
|
521
|
+
}
|
|
522
|
+
.gap-\[var\(--border-width\)\] {
|
|
523
|
+
gap: var(--border-width);
|
|
524
|
+
}
|
|
525
|
+
.self-center {
|
|
526
|
+
align-self: center;
|
|
527
|
+
}
|
|
528
|
+
.truncate {
|
|
529
|
+
overflow: hidden;
|
|
530
|
+
text-overflow: ellipsis;
|
|
531
|
+
white-space: nowrap;
|
|
532
|
+
}
|
|
533
|
+
.overflow-auto {
|
|
534
|
+
overflow: auto;
|
|
535
|
+
}
|
|
536
|
+
.overflow-hidden {
|
|
537
|
+
overflow: hidden;
|
|
538
|
+
}
|
|
539
|
+
.overflow-x-auto {
|
|
540
|
+
overflow-x: auto;
|
|
541
|
+
}
|
|
542
|
+
.overflow-y-auto {
|
|
543
|
+
overflow-y: auto;
|
|
544
|
+
}
|
|
545
|
+
.overscroll-contain {
|
|
546
|
+
overscroll-behavior: contain;
|
|
547
|
+
}
|
|
548
|
+
.rounded {
|
|
549
|
+
border-radius: 0.25rem;
|
|
550
|
+
}
|
|
551
|
+
.rounded-full {
|
|
552
|
+
border-radius: calc(infinity * 1px);
|
|
553
|
+
}
|
|
554
|
+
.rounded-md {
|
|
555
|
+
border-radius: var(--radius-md);
|
|
556
|
+
}
|
|
557
|
+
.rounded-sm {
|
|
558
|
+
border-radius: var(--radius-sm);
|
|
559
|
+
}
|
|
560
|
+
.border {
|
|
561
|
+
border-style: var(--tw-border-style);
|
|
562
|
+
border-width: var(--border-width);
|
|
563
|
+
}
|
|
564
|
+
.border-b {
|
|
565
|
+
border-bottom-style: var(--tw-border-style);
|
|
566
|
+
border-bottom-width: var(--border-width);
|
|
567
|
+
}
|
|
568
|
+
.border-dashed {
|
|
569
|
+
--tw-border-style: dashed;
|
|
570
|
+
border-style: dashed;
|
|
571
|
+
}
|
|
572
|
+
.border-border {
|
|
573
|
+
border-color: var(--color-border);
|
|
574
|
+
}
|
|
575
|
+
.border-border-strong {
|
|
576
|
+
border-color: var(--color-border-strong);
|
|
577
|
+
}
|
|
578
|
+
.p-0 {
|
|
579
|
+
padding: 0px;
|
|
580
|
+
}
|
|
581
|
+
.p-1 {
|
|
582
|
+
padding: var(--spacing-1);
|
|
583
|
+
}
|
|
584
|
+
.p-2 {
|
|
585
|
+
padding: var(--spacing-2);
|
|
586
|
+
}
|
|
587
|
+
.p-4 {
|
|
588
|
+
padding: var(--spacing-4);
|
|
589
|
+
}
|
|
590
|
+
.px-4 {
|
|
591
|
+
padding-inline: var(--spacing-4);
|
|
592
|
+
}
|
|
593
|
+
.py-2 {
|
|
594
|
+
padding-block: var(--spacing-2);
|
|
595
|
+
}
|
|
596
|
+
.py-3 {
|
|
597
|
+
padding-block: var(--spacing-3);
|
|
598
|
+
}
|
|
599
|
+
.py-5 {
|
|
600
|
+
padding-block: var(--spacing-5);
|
|
601
|
+
}
|
|
602
|
+
.py-6 {
|
|
603
|
+
padding-block: var(--spacing-6);
|
|
604
|
+
}
|
|
605
|
+
.py-10 {
|
|
606
|
+
padding-block: var(--spacing-10);
|
|
607
|
+
}
|
|
608
|
+
.pb-2 {
|
|
609
|
+
padding-bottom: var(--spacing-2);
|
|
610
|
+
}
|
|
611
|
+
.pb-3 {
|
|
612
|
+
padding-bottom: var(--spacing-3);
|
|
613
|
+
}
|
|
614
|
+
.text-center {
|
|
615
|
+
text-align: center;
|
|
616
|
+
}
|
|
617
|
+
.font-mono {
|
|
618
|
+
font-family: var(--font-mono);
|
|
619
|
+
}
|
|
620
|
+
.text-2xs {
|
|
621
|
+
font-size: var(--text-2xs);
|
|
622
|
+
}
|
|
623
|
+
.text-lg {
|
|
624
|
+
font-size: var(--text-lg);
|
|
625
|
+
}
|
|
626
|
+
.text-sm {
|
|
627
|
+
font-size: var(--text-sm);
|
|
628
|
+
}
|
|
629
|
+
.text-xs {
|
|
630
|
+
font-size: var(--text-xs);
|
|
631
|
+
}
|
|
632
|
+
.leading-\[0\] {
|
|
633
|
+
--tw-leading: 0;
|
|
634
|
+
line-height: 0;
|
|
635
|
+
}
|
|
636
|
+
.leading-\[1\.5\] {
|
|
637
|
+
--tw-leading: 1.5;
|
|
638
|
+
line-height: 1.5;
|
|
639
|
+
}
|
|
640
|
+
.leading-\[1\.25\] {
|
|
641
|
+
--tw-leading: 1.25;
|
|
642
|
+
line-height: 1.25;
|
|
643
|
+
}
|
|
644
|
+
.leading-\[16px\] {
|
|
645
|
+
--tw-leading: 16px;
|
|
646
|
+
line-height: 16px;
|
|
647
|
+
}
|
|
648
|
+
.font-normal {
|
|
649
|
+
--tw-font-weight: var(--font-weight-normal);
|
|
650
|
+
font-weight: var(--font-weight-normal);
|
|
651
|
+
}
|
|
652
|
+
.font-strong {
|
|
653
|
+
--tw-font-weight: var(--font-weight-strong);
|
|
654
|
+
font-weight: var(--font-weight-strong);
|
|
655
|
+
}
|
|
656
|
+
.tracking-normal {
|
|
657
|
+
--tw-tracking: var(--tracking-normal);
|
|
658
|
+
letter-spacing: var(--tracking-normal);
|
|
659
|
+
}
|
|
660
|
+
.text-ellipsis {
|
|
661
|
+
text-overflow: ellipsis;
|
|
662
|
+
}
|
|
663
|
+
.whitespace-nowrap {
|
|
664
|
+
white-space: nowrap;
|
|
665
|
+
}
|
|
666
|
+
.text-muted {
|
|
667
|
+
color: var(--color-muted);
|
|
668
|
+
}
|
|
669
|
+
.text-text {
|
|
670
|
+
color: var(--color-text);
|
|
671
|
+
}
|
|
672
|
+
.lowercase {
|
|
673
|
+
text-transform: lowercase;
|
|
674
|
+
}
|
|
675
|
+
.normal-case {
|
|
676
|
+
text-transform: none;
|
|
677
|
+
}
|
|
678
|
+
.uppercase {
|
|
679
|
+
text-transform: uppercase;
|
|
680
|
+
}
|
|
681
|
+
.tabular-nums {
|
|
682
|
+
--tw-numeric-spacing: tabular-nums;
|
|
683
|
+
font-variant-numeric: var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,);
|
|
684
|
+
}
|
|
685
|
+
.opacity-60 {
|
|
686
|
+
opacity: 60%;
|
|
687
|
+
}
|
|
688
|
+
.opacity-\[0\.55\] {
|
|
689
|
+
opacity: 0.55;
|
|
690
|
+
}
|
|
691
|
+
.shadow {
|
|
692
|
+
--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));
|
|
693
|
+
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
694
|
+
}
|
|
695
|
+
.ring {
|
|
696
|
+
--tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
|
697
|
+
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
698
|
+
}
|
|
699
|
+
.outline {
|
|
700
|
+
outline-style: var(--tw-outline-style);
|
|
701
|
+
outline-width: 1px;
|
|
702
|
+
}
|
|
703
|
+
.blur {
|
|
704
|
+
--tw-blur: blur(8px);
|
|
705
|
+
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,);
|
|
706
|
+
}
|
|
707
|
+
.sepia {
|
|
708
|
+
--tw-sepia: sepia(100%);
|
|
709
|
+
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,);
|
|
710
|
+
}
|
|
711
|
+
.filter {
|
|
712
|
+
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,);
|
|
713
|
+
}
|
|
714
|
+
.outline-none {
|
|
715
|
+
--tw-outline-style: none;
|
|
716
|
+
outline-style: none;
|
|
717
|
+
}
|
|
718
|
+
.\[font\:inherit\] {
|
|
719
|
+
font: inherit;
|
|
720
|
+
}
|
|
721
|
+
.surface-bg {
|
|
722
|
+
background: var(--bg);
|
|
723
|
+
}
|
|
724
|
+
.surface-panel {
|
|
725
|
+
background: var(--panel);
|
|
726
|
+
}
|
|
727
|
+
.disabled\:cursor-default:disabled {
|
|
728
|
+
cursor: default;
|
|
729
|
+
}
|
|
730
|
+
.disabled\:opacity-50:disabled {
|
|
731
|
+
opacity: 50%;
|
|
732
|
+
}
|
|
733
|
+
.\[\&\>p\]\:m-0 > p {
|
|
734
|
+
margin: 0px;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
@property --tw-rotate-x {
|
|
738
|
+
syntax: "*";
|
|
739
|
+
inherits: false;
|
|
740
|
+
}
|
|
741
|
+
@property --tw-rotate-y {
|
|
742
|
+
syntax: "*";
|
|
743
|
+
inherits: false;
|
|
744
|
+
}
|
|
745
|
+
@property --tw-rotate-z {
|
|
746
|
+
syntax: "*";
|
|
747
|
+
inherits: false;
|
|
748
|
+
}
|
|
749
|
+
@property --tw-skew-x {
|
|
750
|
+
syntax: "*";
|
|
751
|
+
inherits: false;
|
|
752
|
+
}
|
|
753
|
+
@property --tw-skew-y {
|
|
754
|
+
syntax: "*";
|
|
755
|
+
inherits: false;
|
|
756
|
+
}
|
|
757
|
+
@property --tw-border-style {
|
|
758
|
+
syntax: "*";
|
|
759
|
+
inherits: false;
|
|
760
|
+
initial-value: solid;
|
|
761
|
+
}
|
|
762
|
+
@property --tw-leading {
|
|
763
|
+
syntax: "*";
|
|
764
|
+
inherits: false;
|
|
765
|
+
}
|
|
766
|
+
@property --tw-font-weight {
|
|
767
|
+
syntax: "*";
|
|
768
|
+
inherits: false;
|
|
769
|
+
}
|
|
770
|
+
@property --tw-tracking {
|
|
771
|
+
syntax: "*";
|
|
772
|
+
inherits: false;
|
|
773
|
+
}
|
|
774
|
+
@property --tw-ordinal {
|
|
775
|
+
syntax: "*";
|
|
776
|
+
inherits: false;
|
|
777
|
+
}
|
|
778
|
+
@property --tw-slashed-zero {
|
|
779
|
+
syntax: "*";
|
|
780
|
+
inherits: false;
|
|
781
|
+
}
|
|
782
|
+
@property --tw-numeric-figure {
|
|
783
|
+
syntax: "*";
|
|
784
|
+
inherits: false;
|
|
785
|
+
}
|
|
786
|
+
@property --tw-numeric-spacing {
|
|
787
|
+
syntax: "*";
|
|
788
|
+
inherits: false;
|
|
789
|
+
}
|
|
790
|
+
@property --tw-numeric-fraction {
|
|
791
|
+
syntax: "*";
|
|
792
|
+
inherits: false;
|
|
793
|
+
}
|
|
794
|
+
@property --tw-shadow {
|
|
795
|
+
syntax: "*";
|
|
796
|
+
inherits: false;
|
|
797
|
+
initial-value: 0 0 #0000;
|
|
798
|
+
}
|
|
799
|
+
@property --tw-shadow-color {
|
|
800
|
+
syntax: "*";
|
|
801
|
+
inherits: false;
|
|
802
|
+
}
|
|
803
|
+
@property --tw-shadow-alpha {
|
|
804
|
+
syntax: "<percentage>";
|
|
805
|
+
inherits: false;
|
|
806
|
+
initial-value: 100%;
|
|
807
|
+
}
|
|
808
|
+
@property --tw-inset-shadow {
|
|
809
|
+
syntax: "*";
|
|
810
|
+
inherits: false;
|
|
811
|
+
initial-value: 0 0 #0000;
|
|
812
|
+
}
|
|
813
|
+
@property --tw-inset-shadow-color {
|
|
814
|
+
syntax: "*";
|
|
815
|
+
inherits: false;
|
|
816
|
+
}
|
|
817
|
+
@property --tw-inset-shadow-alpha {
|
|
818
|
+
syntax: "<percentage>";
|
|
819
|
+
inherits: false;
|
|
820
|
+
initial-value: 100%;
|
|
821
|
+
}
|
|
822
|
+
@property --tw-ring-color {
|
|
823
|
+
syntax: "*";
|
|
824
|
+
inherits: false;
|
|
825
|
+
}
|
|
826
|
+
@property --tw-ring-shadow {
|
|
827
|
+
syntax: "*";
|
|
828
|
+
inherits: false;
|
|
829
|
+
initial-value: 0 0 #0000;
|
|
830
|
+
}
|
|
831
|
+
@property --tw-inset-ring-color {
|
|
832
|
+
syntax: "*";
|
|
833
|
+
inherits: false;
|
|
834
|
+
}
|
|
835
|
+
@property --tw-inset-ring-shadow {
|
|
836
|
+
syntax: "*";
|
|
837
|
+
inherits: false;
|
|
838
|
+
initial-value: 0 0 #0000;
|
|
839
|
+
}
|
|
840
|
+
@property --tw-ring-inset {
|
|
841
|
+
syntax: "*";
|
|
842
|
+
inherits: false;
|
|
843
|
+
}
|
|
844
|
+
@property --tw-ring-offset-width {
|
|
845
|
+
syntax: "<length>";
|
|
846
|
+
inherits: false;
|
|
847
|
+
initial-value: 0px;
|
|
848
|
+
}
|
|
849
|
+
@property --tw-ring-offset-color {
|
|
850
|
+
syntax: "*";
|
|
851
|
+
inherits: false;
|
|
852
|
+
initial-value: #fff;
|
|
853
|
+
}
|
|
854
|
+
@property --tw-ring-offset-shadow {
|
|
855
|
+
syntax: "*";
|
|
856
|
+
inherits: false;
|
|
857
|
+
initial-value: 0 0 #0000;
|
|
858
|
+
}
|
|
859
|
+
@property --tw-outline-style {
|
|
860
|
+
syntax: "*";
|
|
861
|
+
inherits: false;
|
|
862
|
+
initial-value: solid;
|
|
863
|
+
}
|
|
864
|
+
@property --tw-blur {
|
|
865
|
+
syntax: "*";
|
|
866
|
+
inherits: false;
|
|
867
|
+
}
|
|
868
|
+
@property --tw-brightness {
|
|
869
|
+
syntax: "*";
|
|
870
|
+
inherits: false;
|
|
871
|
+
}
|
|
872
|
+
@property --tw-contrast {
|
|
873
|
+
syntax: "*";
|
|
874
|
+
inherits: false;
|
|
875
|
+
}
|
|
876
|
+
@property --tw-grayscale {
|
|
877
|
+
syntax: "*";
|
|
878
|
+
inherits: false;
|
|
879
|
+
}
|
|
880
|
+
@property --tw-hue-rotate {
|
|
881
|
+
syntax: "*";
|
|
882
|
+
inherits: false;
|
|
883
|
+
}
|
|
884
|
+
@property --tw-invert {
|
|
885
|
+
syntax: "*";
|
|
886
|
+
inherits: false;
|
|
887
|
+
}
|
|
888
|
+
@property --tw-opacity {
|
|
889
|
+
syntax: "*";
|
|
890
|
+
inherits: false;
|
|
891
|
+
}
|
|
892
|
+
@property --tw-saturate {
|
|
893
|
+
syntax: "*";
|
|
894
|
+
inherits: false;
|
|
895
|
+
}
|
|
896
|
+
@property --tw-sepia {
|
|
897
|
+
syntax: "*";
|
|
898
|
+
inherits: false;
|
|
899
|
+
}
|
|
900
|
+
@property --tw-drop-shadow {
|
|
901
|
+
syntax: "*";
|
|
902
|
+
inherits: false;
|
|
903
|
+
}
|
|
904
|
+
@property --tw-drop-shadow-color {
|
|
905
|
+
syntax: "*";
|
|
906
|
+
inherits: false;
|
|
907
|
+
}
|
|
908
|
+
@property --tw-drop-shadow-alpha {
|
|
909
|
+
syntax: "<percentage>";
|
|
910
|
+
inherits: false;
|
|
911
|
+
initial-value: 100%;
|
|
912
|
+
}
|
|
913
|
+
@property --tw-drop-shadow-size {
|
|
914
|
+
syntax: "*";
|
|
915
|
+
inherits: false;
|
|
916
|
+
}
|
|
917
|
+
@layer properties {
|
|
918
|
+
@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
|
|
919
|
+
*, ::before, ::after, ::backdrop {
|
|
920
|
+
--tw-rotate-x: initial;
|
|
921
|
+
--tw-rotate-y: initial;
|
|
922
|
+
--tw-rotate-z: initial;
|
|
923
|
+
--tw-skew-x: initial;
|
|
924
|
+
--tw-skew-y: initial;
|
|
925
|
+
--tw-border-style: solid;
|
|
926
|
+
--tw-leading: initial;
|
|
927
|
+
--tw-font-weight: initial;
|
|
928
|
+
--tw-tracking: initial;
|
|
929
|
+
--tw-ordinal: initial;
|
|
930
|
+
--tw-slashed-zero: initial;
|
|
931
|
+
--tw-numeric-figure: initial;
|
|
932
|
+
--tw-numeric-spacing: initial;
|
|
933
|
+
--tw-numeric-fraction: initial;
|
|
934
|
+
--tw-shadow: 0 0 #0000;
|
|
935
|
+
--tw-shadow-color: initial;
|
|
936
|
+
--tw-shadow-alpha: 100%;
|
|
937
|
+
--tw-inset-shadow: 0 0 #0000;
|
|
938
|
+
--tw-inset-shadow-color: initial;
|
|
939
|
+
--tw-inset-shadow-alpha: 100%;
|
|
940
|
+
--tw-ring-color: initial;
|
|
941
|
+
--tw-ring-shadow: 0 0 #0000;
|
|
942
|
+
--tw-inset-ring-color: initial;
|
|
943
|
+
--tw-inset-ring-shadow: 0 0 #0000;
|
|
944
|
+
--tw-ring-inset: initial;
|
|
945
|
+
--tw-ring-offset-width: 0px;
|
|
946
|
+
--tw-ring-offset-color: #fff;
|
|
947
|
+
--tw-ring-offset-shadow: 0 0 #0000;
|
|
948
|
+
--tw-outline-style: solid;
|
|
949
|
+
--tw-blur: initial;
|
|
950
|
+
--tw-brightness: initial;
|
|
951
|
+
--tw-contrast: initial;
|
|
952
|
+
--tw-grayscale: initial;
|
|
953
|
+
--tw-hue-rotate: initial;
|
|
954
|
+
--tw-invert: initial;
|
|
955
|
+
--tw-opacity: initial;
|
|
956
|
+
--tw-saturate: initial;
|
|
957
|
+
--tw-sepia: initial;
|
|
958
|
+
--tw-drop-shadow: initial;
|
|
959
|
+
--tw-drop-shadow-color: initial;
|
|
960
|
+
--tw-drop-shadow-alpha: 100%;
|
|
961
|
+
--tw-drop-shadow-size: initial;
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
/* ---- ./_system-light.css ---- */
|
|
967
|
+
/* The `system` theme's light half.
|
|
968
|
+
*
|
|
969
|
+
* Its own file, and outside the components layer, because it is a *theme*
|
|
970
|
+
* rather than a component rule. `tokens.css` states the dark base on `:root`
|
|
971
|
+
* and is unlayered; the moment this sat inside `@layer components` it lost to
|
|
972
|
+
* that, and every `system` specimen rendered dark on a light-mode machine.
|
|
973
|
+
* Unlayered beats layered whatever the selector says, which is exactly the
|
|
974
|
+
* trap this repository keeps finding in different costumes.
|
|
975
|
+
*
|
|
976
|
+
* The underscore marks it the same way `_tailwind.built.css` is marked:
|
|
977
|
+
* `copy-css.mjs` passes both through without wrapping them.
|
|
978
|
+
*/
|
|
286
979
|
/* Light, only under the `system` theme. This used to override `:root`
|
|
287
980
|
unconditionally, so choosing a dark theme on a light-mode laptop got
|
|
288
981
|
silently repainted. Every other theme states its own palette. */
|
|
@@ -311,6 +1004,8 @@
|
|
|
311
1004
|
}
|
|
312
1005
|
}
|
|
313
1006
|
|
|
1007
|
+
/* ---- ./base.css ---- */
|
|
1008
|
+
@layer components {
|
|
314
1009
|
/* Derived from the two surfaces every theme already defines, so a theme gets a
|
|
315
1010
|
control colour without knowing this exists. */
|
|
316
1011
|
/* Pseudo-elements too. `*` does not match them, and `box-sizing` is not
|
|
@@ -375,23 +1070,31 @@ body::before {
|
|
|
375
1070
|
`[aria-disabled='true']` twin rather than a rewrite, which leaves each
|
|
376
1071
|
`button` selector at the specificity it had and every committed baseline
|
|
377
1072
|
untouched. */
|
|
378
|
-
|
|
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. */
|
|
379
1078
|
text-decoration: none;
|
|
380
1079
|
color: var(--text);
|
|
381
1080
|
text-align: center;
|
|
382
1081
|
}
|
|
383
1082
|
|
|
384
|
-
|
|
1083
|
+
.btn[aria-disabled='true'] {
|
|
385
1084
|
/* A disabled anchor still takes the pointer, so say so. The click itself is
|
|
386
1085
|
blocked in the capture phase by the component. */
|
|
387
1086
|
cursor: not-allowed;
|
|
388
1087
|
}
|
|
389
1088
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
input,
|
|
393
|
-
|
|
394
|
-
|
|
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) {
|
|
395
1098
|
font: inherit;
|
|
396
1099
|
color: var(--text);
|
|
397
1100
|
background: var(--control);
|
|
@@ -412,8 +1115,7 @@ select {
|
|
|
412
1115
|
the icon; the button simply had no opinion about how to arrange two things.
|
|
413
1116
|
`inline-flex` and a gap gives it one, and the gap replaces the space
|
|
414
1117
|
character people were putting between an icon and its label. */
|
|
415
|
-
|
|
416
|
-
a.btn {
|
|
1118
|
+
.btn {
|
|
417
1119
|
display: inline-flex;
|
|
418
1120
|
align-items: center;
|
|
419
1121
|
justify-content: center;
|
|
@@ -429,18 +1131,41 @@ a.btn {
|
|
|
429
1131
|
|
|
430
1132
|
Several places already drew this by hand as `.chat-bar-btn.on`. This is the
|
|
431
1133
|
same look, said once, on a plain button. */
|
|
432
|
-
|
|
1134
|
+
.btn[aria-pressed='true'] {
|
|
433
1135
|
border-color: var(--accent);
|
|
434
1136
|
color: var(--accent);
|
|
435
1137
|
background: color-mix(in srgb, var(--accent) 10%, var(--panel));
|
|
436
1138
|
}
|
|
437
1139
|
|
|
438
|
-
|
|
1140
|
+
.btn[aria-pressed='true']:hover:not(:disabled) { border-color: var(--accent); }
|
|
439
1141
|
|
|
440
1142
|
/* The glyph never shrinks: in a narrow row flexbox would take it from the icon
|
|
441
1143
|
before the text, and half an icon is not a smaller icon. */
|
|
442
|
-
|
|
443
|
-
|
|
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
|
+
}
|
|
444
1169
|
|
|
445
1170
|
.size-sm { font-size: var(--text-xs); padding: var(--space-1) var(--space-2); }
|
|
446
1171
|
|
|
@@ -465,8 +1190,7 @@ input, textarea, select { width: 100%; }
|
|
|
465
1190
|
same disagreement written twice. */
|
|
466
1191
|
textarea { resize: none; }
|
|
467
1192
|
|
|
468
|
-
|
|
469
|
-
a.btn:hover:not([aria-disabled='true']),
|
|
1193
|
+
.btn:hover:not(:disabled),
|
|
470
1194
|
input:hover:not(:disabled),
|
|
471
1195
|
textarea:hover:not(:disabled),
|
|
472
1196
|
select:hover:not(:disabled) { border-color: var(--accent); }
|
|
@@ -474,8 +1198,7 @@ select:hover:not(:disabled) { border-color: var(--accent); }
|
|
|
474
1198
|
/* `:focus-visible` on the button so a click does not leave a ring behind it,
|
|
475
1199
|
`:focus` on the fields because a focused field is a place you are typing and
|
|
476
1200
|
should say so however you got there. */
|
|
477
|
-
|
|
478
|
-
a.btn:focus-visible,
|
|
1201
|
+
.btn:focus-visible,
|
|
479
1202
|
input:focus,
|
|
480
1203
|
textarea:focus,
|
|
481
1204
|
select:focus { outline: none; border-color: var(--accent); }
|
|
@@ -568,14 +1291,13 @@ input[type='radio']:focus-visible { outline: none; box-shadow: var(--focus-ring)
|
|
|
568
1291
|
input[type='checkbox']:disabled,
|
|
569
1292
|
input[type='radio']:disabled { cursor: not-allowed; background: var(--panel-2); }
|
|
570
1293
|
|
|
571
|
-
|
|
572
|
-
|
|
1294
|
+
.btn:disabled,
|
|
1295
|
+
.btn[aria-disabled='true'],
|
|
573
1296
|
input:disabled,
|
|
574
1297
|
textarea:disabled,
|
|
575
1298
|
select:disabled { opacity: 0.45; cursor: not-allowed; }
|
|
576
1299
|
|
|
577
|
-
|
|
578
|
-
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); }
|
|
579
1301
|
|
|
580
1302
|
/* A disabled primary is not a faded primary.
|
|
581
1303
|
`opacity: .45` was the whole of it, and a coloured fill at 45% is still a
|
|
@@ -583,8 +1305,7 @@ a.btn.primary { background: var(--accent); border-color: var(--accent); color: v
|
|
|
583
1305
|
thing on the panel. That got worse when onboarding started holding people at
|
|
584
1306
|
a disabled Next. So it gives up the fill entirely and becomes the shape of a
|
|
585
1307
|
disabled control -- the opacity then has nothing left to do. */
|
|
586
|
-
|
|
587
|
-
a.btn.primary[aria-disabled='true'] {
|
|
1308
|
+
.btn.primary:disabled {
|
|
588
1309
|
background: var(--panel-2);
|
|
589
1310
|
border-color: var(--border);
|
|
590
1311
|
color: var(--muted);
|
|
@@ -598,7 +1319,7 @@ a.btn.primary[aria-disabled='true'] {
|
|
|
598
1319
|
line under it that travels.
|
|
599
1320
|
`aria-busy` rather than a class: the attribute is what a screen reader reads,
|
|
600
1321
|
and styling the thing that carries the meaning is how they stay in step. */
|
|
601
|
-
|
|
1322
|
+
.btn[aria-busy='true'] {
|
|
602
1323
|
position: relative;
|
|
603
1324
|
overflow: hidden;
|
|
604
1325
|
cursor: progress;
|
|
@@ -611,18 +1332,18 @@ button[aria-busy='true'] {
|
|
|
611
1332
|
something that is working, that reads as a control that failed and went
|
|
612
1333
|
grey. So a busy button keeps every colour it had and takes only the loss of
|
|
613
1334
|
the cursor and the press; the travelling line is what says why. */
|
|
614
|
-
|
|
1335
|
+
.btn[aria-busy='true']:disabled {
|
|
615
1336
|
opacity: 1;
|
|
616
1337
|
cursor: progress;
|
|
617
1338
|
}
|
|
618
1339
|
|
|
619
|
-
|
|
1340
|
+
.btn.primary[aria-busy='true']:disabled {
|
|
620
1341
|
background: var(--accent);
|
|
621
1342
|
border-color: var(--accent);
|
|
622
1343
|
color: var(--on-accent);
|
|
623
1344
|
}
|
|
624
1345
|
|
|
625
|
-
|
|
1346
|
+
.btn[aria-busy='true']::after {
|
|
626
1347
|
content: '';
|
|
627
1348
|
position: absolute;
|
|
628
1349
|
left: 0;
|
|
@@ -654,15 +1375,13 @@ button[aria-busy='true']::after {
|
|
|
654
1375
|
|
|
655
1376
|
/* Quiet: no border, no fill. For the action beside the action -- Cancel next to
|
|
656
1377
|
Save -- where a bordered box competes with the thing it is next to. */
|
|
657
|
-
|
|
658
|
-
a.btn.ghost {
|
|
1378
|
+
.btn.ghost {
|
|
659
1379
|
background: transparent;
|
|
660
1380
|
border-color: transparent;
|
|
661
1381
|
color: var(--muted);
|
|
662
1382
|
}
|
|
663
1383
|
|
|
664
|
-
|
|
665
|
-
a.btn.ghost:hover:not([aria-disabled='true']) {
|
|
1384
|
+
.btn.ghost:hover:not(:disabled) {
|
|
666
1385
|
background: var(--panel-2);
|
|
667
1386
|
border-color: transparent;
|
|
668
1387
|
color: var(--text);
|
|
@@ -744,7 +1463,7 @@ a.btn.ghost:hover:not([aria-disabled='true']) {
|
|
|
744
1463
|
header.) */
|
|
745
1464
|
.row { display: flex; align-items: center; gap: var(--space-3); }
|
|
746
1465
|
|
|
747
|
-
.grow { flex: 1; min-width: 0; }
|
|
1466
|
+
.ctl-grow { flex: 1; min-width: 0; }
|
|
748
1467
|
|
|
749
1468
|
.mono { font-family: var(--font-mono); font-size: var(--text-sm); }
|
|
750
1469
|
|
|
@@ -808,10 +1527,17 @@ a.btn.ghost:hover:not([aria-disabled='true']) {
|
|
|
808
1527
|
/* A pill following a name needs the gap outside its own border. Leading
|
|
809
1528
|
whitespace inside the span puts it under the pill's background instead,
|
|
810
1529
|
which reads as the badge touching the word it qualifies. */
|
|
811
|
-
|
|
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; }
|
|
812
1536
|
|
|
813
1537
|
/* The tile's only control. Dim until hovered: it is chrome on someone's app. */
|
|
814
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;
|
|
815
1541
|
display: inline-flex; align-items: center; padding: var(--space-1);
|
|
816
1542
|
background: none; border: 0; color: var(--muted); opacity: 0.6; cursor: pointer;
|
|
817
1543
|
}
|
|
@@ -877,19 +1603,17 @@ a.btn.ghost:hover:not([aria-disabled='true']) {
|
|
|
877
1603
|
transition: none;
|
|
878
1604
|
}
|
|
879
1605
|
|
|
880
|
-
|
|
881
|
-
a.btn.primary:active:not([aria-disabled='true']) {
|
|
1606
|
+
.btn.primary:active:not(:disabled) {
|
|
882
1607
|
background: color-mix(in srgb, var(--text) var(--press-ink), var(--accent));
|
|
883
1608
|
border-color: color-mix(in srgb, var(--text) var(--press-ink), var(--accent));
|
|
884
1609
|
}
|
|
885
1610
|
|
|
886
|
-
|
|
887
|
-
a.btn.ghost:active:not([aria-disabled='true']) {
|
|
1611
|
+
.btn.ghost:active:not(:disabled) {
|
|
888
1612
|
background: color-mix(in srgb, var(--text) var(--press-ink), var(--panel-2));
|
|
889
1613
|
border-color: transparent;
|
|
890
1614
|
}
|
|
891
1615
|
|
|
892
|
-
|
|
1616
|
+
.btn[aria-pressed='true']:active:not(:disabled) {
|
|
893
1617
|
background: color-mix(in srgb, var(--accent) 18%, var(--panel));
|
|
894
1618
|
}
|
|
895
1619
|
|
|
@@ -1060,7 +1784,7 @@ input:active, textarea:active, select:active { transform: none; }
|
|
|
1060
1784
|
|
|
1061
1785
|
/* The top bar carries the title, the views and the way into settings. Nothing
|
|
1062
1786
|
that belongs to a conversation lives here any more, so it can breathe. */
|
|
1063
|
-
.topbar .grow { flex: 1; min-width: 0; }
|
|
1787
|
+
.topbar .ctl-grow { flex: 1; min-width: 0; }
|
|
1064
1788
|
|
|
1065
1789
|
/* Back on the left, Next on the right, with the gap between them doing the
|
|
1066
1790
|
separating -- so the button that goes forward is in the same place on both
|
|
@@ -1092,7 +1816,60 @@ input:active, textarea:active, select:active { transform: none; }
|
|
|
1092
1816
|
to { opacity: 1; }
|
|
1093
1817
|
}
|
|
1094
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
|
+
}
|
|
1870
|
+
|
|
1095
1871
|
/* ---- ./select.css ---- */
|
|
1872
|
+
@layer components {
|
|
1096
1873
|
/* How big a control is, asked for rather than inherited.
|
|
1097
1874
|
Four sizes existed and every one of them came from a descendant selector:
|
|
1098
1875
|
`.set-row button` was 11px in 3px of padding, `.approval-actions button` was
|
|
@@ -1107,8 +1884,7 @@ input:active, textarea:active, select:active { transform: none; }
|
|
|
1107
1884
|
/* Full width, for the one action a card or a step is about. Not a size: a
|
|
1108
1885
|
`block` button is the same height as any other, it just stops being a thing
|
|
1109
1886
|
you have to aim at. */
|
|
1110
|
-
|
|
1111
|
-
a.btn.block { display: flex; width: 100%; }
|
|
1887
|
+
.btn.ctl-block { display: flex; width: 100%; }
|
|
1112
1888
|
|
|
1113
1889
|
/* The default is `size-md`, spelled once for every control.
|
|
1114
1890
|
The paragraph above promised one scale for buttons, inputs and selects, and
|
|
@@ -1116,13 +1892,24 @@ a.btn.block { display: flex; width: 100%; }
|
|
|
1116
1892
|
input was eight pixels taller than the button beside it and no row of the two
|
|
1117
1893
|
could line up. The download modal's search box against its Search button was
|
|
1118
1894
|
the version you could see from across the room. */
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
input,
|
|
1122
|
-
|
|
1123
|
-
|
|
1895
|
+
/* `:where`, so this base carries no specificity of its own.
|
|
1896
|
+
*
|
|
1897
|
+
* It was `button, input, textarea, select` -- an element selector, which
|
|
1898
|
+
* `.size-sm` and every other class outranked without anyone thinking about
|
|
1899
|
+
* it. Moving it to `.btn` to stop a tab inheriting a control's look raised it
|
|
1900
|
+
* to a class, so it tied with `.size-sm` and won on source order: every
|
|
1901
|
+
* button came out `8px 12px` whatever size it asked for. `:where` puts it
|
|
1902
|
+
* back to zero, which is what the element selector was silently providing. */
|
|
1903
|
+
:where(.btn, input, textarea, select) { padding: var(--space-2) var(--space-3); }
|
|
1904
|
+
|
|
1905
|
+
/* The select's control keeps its padding at full class weight, and after
|
|
1906
|
+
`.size-sm` in the cascade, because that is where it has always been: this
|
|
1907
|
+
file is imported after `base.css`, so a `size`d select took the size's type
|
|
1908
|
+
and this padding. Folding it into the `:where` above handed the padding
|
|
1909
|
+
back to `.size-sm` and shrank every small select by seven pixels. */
|
|
1124
1910
|
.sel-control { padding: var(--space-2) var(--space-3); }
|
|
1125
1911
|
|
|
1912
|
+
|
|
1126
1913
|
/* Centred on the whole block -- the caption and the sentence together -- rather
|
|
1127
1914
|
than aligned to either end of it. `.field-row` pins to the bottom, which is
|
|
1128
1915
|
right for a field beside a button and wrong beside two lines of prose. */
|
|
@@ -1146,16 +1933,16 @@ select,
|
|
|
1146
1933
|
.sel { position: relative; display: inline-block; }
|
|
1147
1934
|
|
|
1148
1935
|
/* The subject of its pane rather than a field in it: full width and a size up.
|
|
1149
|
-
That was `.select-field.block` on the native element, and it carried the
|
|
1936
|
+
That was `.select-field.ctl-block` on the native element, and it carried the
|
|
1150
1937
|
reason with it -- model ids are long (`qwen2.5-coder:32b-instruct-q4_K_M`) and
|
|
1151
1938
|
at the narrow size they truncated mid-name. */
|
|
1152
|
-
.sel.block { display: block; width: 100%; }
|
|
1939
|
+
.sel.ctl-block { display: block; width: 100%; }
|
|
1153
1940
|
|
|
1154
|
-
.sel.block .sel-control { padding: var(--space-2) var(--space-3); font-weight: 500; }
|
|
1941
|
+
.sel.ctl-block .sel-control { padding: var(--space-2) var(--space-3); font-weight: 500; }
|
|
1155
1942
|
|
|
1156
1943
|
/* Not full width otherwise: a select as wide as its row, holding one short
|
|
1157
1944
|
word, reads as an input somebody forgot to fill in. */
|
|
1158
|
-
.sel:not(.block) .sel-control { width: auto; max-width: 320px; }
|
|
1945
|
+
.sel:not(.ctl-block) .sel-control { width: auto; max-width: 320px; }
|
|
1159
1946
|
|
|
1160
1947
|
.sel-control {
|
|
1161
1948
|
display: flex;
|
|
@@ -1168,9 +1955,7 @@ select,
|
|
|
1168
1955
|
background: var(--control);
|
|
1169
1956
|
}
|
|
1170
1957
|
|
|
1171
|
-
.sel-
|
|
1172
|
-
|
|
1173
|
-
.sel-caret { flex: none; opacity: 0.6; transition: transform var(--dur-fast) var(--ease); }
|
|
1958
|
+
.sel-caret { transition: transform var(--dur-fast) var(--ease); }
|
|
1174
1959
|
|
|
1175
1960
|
.sel[data-open] .sel-caret { transform: rotate(180deg); }
|
|
1176
1961
|
|
|
@@ -1179,45 +1964,22 @@ select,
|
|
|
1179
1964
|
/* State is read off React Aria's attributes: `data-open` on the root,
|
|
1180
1965
|
`data-focused` / `data-selected` / `data-disabled` on an item, where
|
|
1181
1966
|
`.open`, `[data-active]`, `.on` and `.off` used to be. */
|
|
1967
|
+
/* The list keeps two things the utilities on `Select` cannot say.
|
|
1968
|
+
*
|
|
1969
|
+
* `scroll-padding-block`: the same room while the list is scrolled as it has
|
|
1970
|
+
* at rest. Padding at the top of a scroll container scrolls away with the
|
|
1971
|
+
* content, so the row `scrollIntoView({block: 'nearest'})` brings up ended
|
|
1972
|
+
* flush against the border and read as clipped rather than as one of a set --
|
|
1973
|
+
* and this list opens scrolled to whatever is chosen, so that was the
|
|
1974
|
+
* ordinary state.
|
|
1975
|
+
*
|
|
1976
|
+
* `box-shadow`: `--shadow-2` is a token, and a utility would have to inline
|
|
1977
|
+
* the value, which is the one thing the vocabulary exists to stop. */
|
|
1182
1978
|
.sel-list {
|
|
1183
|
-
/* `fixed`, and in `document.body`: an ancestor that scrolls or hides its
|
|
1184
|
-
overflow would otherwise clip it, which in this app means every settings
|
|
1185
|
-
pane. Position comes from the button's measured rectangle. */
|
|
1186
|
-
/* Positioned by React Aria -- inline `top`/`left` on a portalled popover
|
|
1187
|
-
that flips when the edge is near. `position: fixed` and the measured
|
|
1188
|
-
rectangle it was placed by are gone with the hand-rolled version. */
|
|
1189
|
-
z-index: 60;
|
|
1190
|
-
max-height: 280px;
|
|
1191
|
-
overflow-y: auto;
|
|
1192
|
-
margin: 0;
|
|
1193
|
-
padding: var(--space-1);
|
|
1194
|
-
/* The same room while the list is scrolled as it has at rest. Padding at
|
|
1195
|
-
the top of a scroll container scrolls away with the content, so the row
|
|
1196
|
-
`scrollIntoView({block: 'nearest'})` brings up ended flush against the
|
|
1197
|
-
border and read as clipped rather than as one of a set -- and this list
|
|
1198
|
-
opens scrolled to whatever is chosen, so that was the ordinary state.
|
|
1199
|
-
`scroll-padding` insets what counts as "in view", so it stops short by
|
|
1200
|
-
the same four the sides have. */
|
|
1201
1979
|
scroll-padding-block: var(--space-1);
|
|
1202
|
-
list-style: none;
|
|
1203
|
-
border: var(--border-width) solid var(--border-strong);
|
|
1204
|
-
border-radius: var(--radius-md);
|
|
1205
|
-
background: var(--panel);
|
|
1206
1980
|
box-shadow: var(--shadow-2);
|
|
1207
1981
|
}
|
|
1208
1982
|
|
|
1209
|
-
.sel-item {
|
|
1210
|
-
display: flex;
|
|
1211
|
-
align-items: center;
|
|
1212
|
-
gap: var(--space-2);
|
|
1213
|
-
padding: var(--space-2) var(--space-2);
|
|
1214
|
-
border-radius: var(--radius-sm);
|
|
1215
|
-
cursor: pointer;
|
|
1216
|
-
white-space: nowrap;
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
|
-
.sel-item-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
|
|
1220
|
-
|
|
1221
1983
|
/* Hover and keyboard land on the same row, because they are the same idea --
|
|
1222
1984
|
two highlights for one cursor is how a list starts lying about where Enter
|
|
1223
1985
|
will go. */
|
|
@@ -1229,7 +1991,18 @@ select,
|
|
|
1229
1991
|
|
|
1230
1992
|
/* The tick marks the chosen row. Colour alone would not: a list where the only
|
|
1231
1993
|
difference is a hue is a list you cannot read past. */
|
|
1232
|
-
|
|
1994
|
+
/* The tick's resting state lives here, beside the state that overrides it.
|
|
1995
|
+
*
|
|
1996
|
+
* It was `opacity-0` on the element and `opacity: 1` here, which worked only
|
|
1997
|
+
* while this sheet was unlayered. A utility is in `@layer utilities` and
|
|
1998
|
+
* beats `@layer components` whatever the selector, so the moment the sheets
|
|
1999
|
+
* moved into a layer the tick stopped appearing on the selected row -- the
|
|
2000
|
+
* resting state won permanently.
|
|
2001
|
+
*
|
|
2002
|
+
* The rule generalises: a utility for a resting state whose active state is a
|
|
2003
|
+
* relationship between elements will always beat that active state. The pair
|
|
2004
|
+
* has to sit in the same layer. */
|
|
2005
|
+
.sel-tick { opacity: 0; }
|
|
1233
2006
|
|
|
1234
2007
|
.sel-item[data-selected] .sel-tick { opacity: 1; }
|
|
1235
2008
|
|
|
@@ -1265,24 +2038,23 @@ select,
|
|
|
1265
2038
|
.field > input,
|
|
1266
2039
|
.field > textarea,
|
|
1267
2040
|
.field > .sel { width: 100%; }
|
|
2041
|
+
}
|
|
1268
2042
|
|
|
1269
2043
|
/* ---- ./dangerzone.css ---- */
|
|
2044
|
+
@layer components {
|
|
1270
2045
|
/* Destructive, and legible as such standing still. */
|
|
1271
|
-
|
|
1272
|
-
a.btn.danger {
|
|
2046
|
+
.btn.danger {
|
|
1273
2047
|
color: var(--bad);
|
|
1274
2048
|
border-color: color-mix(in srgb, var(--bad) 45%, var(--border-strong));
|
|
1275
2049
|
}
|
|
1276
2050
|
|
|
1277
|
-
|
|
1278
|
-
a.btn.danger:hover:not([aria-disabled='true']) {
|
|
2051
|
+
.btn.danger:hover:not(:disabled) {
|
|
1279
2052
|
background: color-mix(in srgb, var(--bad) 12%, var(--panel));
|
|
1280
2053
|
border-color: var(--bad);
|
|
1281
2054
|
color: var(--bad);
|
|
1282
2055
|
}
|
|
1283
2056
|
|
|
1284
|
-
|
|
1285
|
-
a.btn.danger:active:not([aria-disabled='true']) {
|
|
2057
|
+
.btn.danger:active:not(:disabled) {
|
|
1286
2058
|
background: color-mix(in srgb, var(--bad) 20%, var(--panel));
|
|
1287
2059
|
border-color: var(--bad);
|
|
1288
2060
|
}
|
|
@@ -1381,8 +2153,10 @@ a.btn.danger:active:not([aria-disabled='true']) {
|
|
|
1381
2153
|
controls in the same column at the same indent that do not line up read as
|
|
1382
2154
|
an accident rather than as a pair. */
|
|
1383
2155
|
.field-row > button { min-width: 9ch; }
|
|
2156
|
+
}
|
|
1384
2157
|
|
|
1385
2158
|
/* ---- ./callout.css ---- */
|
|
2159
|
+
@layer components {
|
|
1386
2160
|
/* One shape for everything that tells you something.
|
|
1387
2161
|
`.banner` and `.callout` were the same box drawn twice: a bordered, rounded,
|
|
1388
2162
|
12px panel with a tint. They differed in padding by a pixel in each direction
|
|
@@ -1521,35 +2295,50 @@ a.btn.danger:active:not([aria-disabled='true']) {
|
|
|
1521
2295
|
}
|
|
1522
2296
|
|
|
1523
2297
|
.callout button { flex: none; }
|
|
2298
|
+
}
|
|
1524
2299
|
|
|
1525
2300
|
/* ---- ./card.css ---- */
|
|
2301
|
+
@layer components {
|
|
2302
|
+
/* `.card` is public API, not this component's private styling.
|
|
2303
|
+
*
|
|
2304
|
+
* Consumers apply it to their own markup -- the gallery's skeleton specimen
|
|
2305
|
+
* renders `<div className="card">` around three rows, and app-template uses
|
|
2306
|
+
* `card-pick`. Moving the box into `Card`'s own class list took that away
|
|
2307
|
+
* with no type error and no failing test in this package: it broke only
|
|
2308
|
+
* where somebody else had used the class, which is the worst way for an API
|
|
2309
|
+
* to go.
|
|
2310
|
+
*
|
|
2311
|
+
* So the rule stays and `Card` wears it. The lesson generalises to every
|
|
2312
|
+
* class in this package that a consumer can reach: a component may draw
|
|
2313
|
+
* itself with utilities only where its class is genuinely private. */
|
|
1526
2314
|
.card {
|
|
2315
|
+
display: block;
|
|
2316
|
+
width: 100%;
|
|
2317
|
+
box-sizing: border-box;
|
|
2318
|
+
font: inherit;
|
|
2319
|
+
color: var(--text);
|
|
2320
|
+
text-align: left;
|
|
1527
2321
|
background: var(--panel);
|
|
1528
2322
|
border: var(--border-width) solid var(--border);
|
|
1529
2323
|
border-radius: var(--radius-md);
|
|
1530
|
-
padding: var(--space-3)
|
|
2324
|
+
padding: var(--space-3);
|
|
1531
2325
|
margin-bottom: var(--space-3);
|
|
1532
2326
|
}
|
|
1533
2327
|
|
|
2328
|
+
/* What is left once `Card` draws its own box: the tones, the pick and
|
|
2329
|
+
selected states, and the rules that reach from the card into what it
|
|
2330
|
+
holds. `:has(.card-icon) .card-inline` is a relationship, and a tone is a
|
|
2331
|
+
`color-mix`; neither is a property on one element. */
|
|
2332
|
+
|
|
1534
2333
|
/* Header, when there is one. The title and the line under it were retyped at
|
|
1535
2334
|
every call site and no two agreed on the gap between them. */
|
|
1536
|
-
.card-head { display: flex; align-items: flex-start; gap: var(--space-3); }
|
|
1537
|
-
|
|
1538
|
-
.card-head:not(:last-child) { margin-bottom: var(--space-3); }
|
|
1539
|
-
|
|
1540
|
-
.card-headings { min-width: 0; flex: 1; }
|
|
1541
|
-
|
|
1542
2335
|
/* The card owns the space between the things it holds. Without this a callout
|
|
1543
2336
|
and the button under it sit edge to edge, and every caller has to remember a
|
|
1544
2337
|
margin on whichever child happens to be second. */
|
|
1545
|
-
.card-body { display: grid; gap: var(--space-3); }
|
|
1546
|
-
|
|
1547
2338
|
/* The card's own control, on the card's padding rather than indented into its
|
|
1548
2339
|
body. Centred against the whole heading block, not against the title -- a
|
|
1549
2340
|
switch aligned to the first line drifts upward the moment the description
|
|
1550
2341
|
runs to two. */
|
|
1551
|
-
.card-action { flex: none; align-self: center; display: flex; align-items: center; }
|
|
1552
|
-
|
|
1553
2342
|
/* A row inside a card that lines up with the header rather than indenting past
|
|
1554
2343
|
it: same left edge as the title, same right edge as the action. Its label is
|
|
1555
2344
|
a quiet caption, not a second heading -- the card already has one, and two
|
|
@@ -1596,17 +2385,6 @@ a.btn.danger:active:not([aria-disabled='true']) {
|
|
|
1596
2385
|
color: var(--muted);
|
|
1597
2386
|
}
|
|
1598
2387
|
|
|
1599
|
-
/* A card that is itself the choice. Reset first, because it is a `<button>`
|
|
1600
|
-
now and inherits a control's padding and centring. */
|
|
1601
|
-
button.card {
|
|
1602
|
-
display: block;
|
|
1603
|
-
width: 100%;
|
|
1604
|
-
text-align: left;
|
|
1605
|
-
font: inherit;
|
|
1606
|
-
color: inherit;
|
|
1607
|
-
padding: var(--space-3);
|
|
1608
|
-
}
|
|
1609
|
-
|
|
1610
2388
|
/* Variants, because a card is doing four jobs and looked like one.
|
|
1611
2389
|
A search result you can act on, a thing already installed, something that
|
|
1612
2390
|
went wrong, and a heading with rows under it are not the same object, and
|
|
@@ -1649,7 +2427,23 @@ button.card {
|
|
|
1649
2427
|
|
|
1650
2428
|
.modal-body .card { background: var(--panel-2); }
|
|
1651
2429
|
|
|
2430
|
+
/* Selected, which used to arrive from `button[aria-pressed='true']`.
|
|
2431
|
+
*
|
|
2432
|
+
* A card marks its choice with `aria-pressed`, and the tint came from the
|
|
2433
|
+
* element rule every bare `<button>` in the package was picking up. That rule
|
|
2434
|
+
* belongs to `Button` now, so the card says what being chosen looks like --
|
|
2435
|
+
* which is the right place for it anyway: a chosen card is a card's idea, not
|
|
2436
|
+
* a button's. */
|
|
2437
|
+
.card[aria-pressed='true'] {
|
|
2438
|
+
border-color: var(--accent);
|
|
2439
|
+
background: color-mix(in srgb, var(--accent) 10%, var(--panel));
|
|
2440
|
+
}
|
|
2441
|
+
|
|
2442
|
+
.card[aria-pressed='true']:hover { border-color: var(--accent); }
|
|
2443
|
+
}
|
|
2444
|
+
|
|
1652
2445
|
/* ---- ./toggle.css ---- */
|
|
2446
|
+
@layer components {
|
|
1653
2447
|
.card-action .switch-row { padding: 0; gap: var(--space-2); }
|
|
1654
2448
|
|
|
1655
2449
|
.card-action .switch-row .switch-body { flex: none; }
|
|
@@ -1880,8 +2674,10 @@ input[type='radio']:active:not(:disabled) {
|
|
|
1880
2674
|
@media (prefers-reduced-motion: reduce) {
|
|
1881
2675
|
.toggle-sweep::before { animation: none; background: color-mix(in oklab, var(--accent) 45%, transparent); }
|
|
1882
2676
|
}
|
|
2677
|
+
}
|
|
1883
2678
|
|
|
1884
2679
|
/* ---- ./skeleton.css ---- */
|
|
2680
|
+
@layer components {
|
|
1885
2681
|
.muted { color: var(--muted); }
|
|
1886
2682
|
|
|
1887
2683
|
.pulse-block {
|
|
@@ -1936,8 +2732,10 @@ input[type='radio']:active:not(:disabled) {
|
|
|
1936
2732
|
/* Still distinguishable from a real block of colour, and still still. */
|
|
1937
2733
|
.skel-pulse { animation: none; opacity: 0.8; }
|
|
1938
2734
|
}
|
|
2735
|
+
}
|
|
1939
2736
|
|
|
1940
2737
|
/* ---- ./rows.css ---- */
|
|
2738
|
+
@layer components {
|
|
1941
2739
|
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1942
2740
|
|
|
1943
2741
|
/* A name and the pills that qualify it, on one line, where the name is the only
|
|
@@ -2198,72 +2996,24 @@ input[type='radio']:active:not(:disabled) {
|
|
|
2198
2996
|
.row-hit:hover .truncate { color: var(--accent); }
|
|
2199
2997
|
|
|
2200
2998
|
.row-hit:focus-visible { outline: none; box-shadow: var(--focus-ring); }
|
|
2201
|
-
|
|
2202
|
-
/* ---- ./empty.css ---- */
|
|
2203
|
-
/* `Empty`: a list with nothing in it.
|
|
2204
|
-
|
|
2205
|
-
Quieter than `.empty`, which is a whole-screen state at `--space-10`. These
|
|
2206
|
-
sit inside a card that already has a heading and a description, so the same
|
|
2207
|
-
padding would leave a card that is mostly air about nothing.
|
|
2208
|
-
|
|
2209
|
-
Dashed rather than solid: a solid border reads as a thing, and the point of
|
|
2210
|
-
this box is that there is no thing. It marks out where the list will be. */
|
|
2211
|
-
.nothing {
|
|
2212
|
-
display: grid;
|
|
2213
|
-
justify-items: center;
|
|
2214
|
-
gap: var(--space-2);
|
|
2215
|
-
padding: var(--space-5) var(--space-4);
|
|
2216
|
-
border: var(--border-width) dashed var(--border-strong);
|
|
2217
|
-
border-radius: var(--radius-md);
|
|
2218
|
-
text-align: center;
|
|
2219
2999
|
}
|
|
2220
3000
|
|
|
2221
|
-
.nothing-mark { color: var(--muted); line-height: 0; }
|
|
2222
|
-
|
|
2223
|
-
/* The same box with a figure in it, for a whole surface rather than a slot in
|
|
2224
|
-
a card. Two things change and both follow from the size: the dashed outline
|
|
2225
|
-
goes, because an outline marks out where a list will be and a window-sized
|
|
2226
|
-
dashed rectangle reads as a layout that failed rather than a view with
|
|
2227
|
-
nothing on it; and the box centres itself in whatever it was dropped into,
|
|
2228
|
-
which is what makes it land in the middle of an empty dashboard rather than
|
|
2229
|
-
under the header. */
|
|
2230
|
-
.nothing-surface {
|
|
2231
|
-
border: none;
|
|
2232
|
-
padding: var(--space-10) var(--space-4);
|
|
2233
|
-
gap: var(--space-3);
|
|
2234
|
-
margin: auto;
|
|
2235
|
-
}
|
|
2236
|
-
|
|
2237
|
-
/* `currentColor` reaches the figure through the two rules the illustrations
|
|
2238
|
-
ship with, so the colour is set here and the drawing follows it -- the same
|
|
2239
|
-
grey as the sentence under it, in every theme.
|
|
2240
|
-
Two classes, not one: `.illo` sets `color: inherit` further down this file,
|
|
2241
|
-
which beats a single-class rule written earlier and drew the figure in full
|
|
2242
|
-
text black beside a muted sentence. */
|
|
2243
|
-
.nothing-surface .nothing-figure { color: var(--muted); }
|
|
2244
|
-
|
|
2245
|
-
/* `--text-sm`, not the `--text-xs` these lines used to be: it is a sentence
|
|
2246
|
-
somebody is meant to read, not a caption qualifying something else. */
|
|
2247
|
-
.nothing-said { margin: 0; color: var(--muted); font-size: var(--text-sm); line-height: 1.5; max-width: 46ch; }
|
|
2248
|
-
|
|
2249
|
-
.nothing-act { margin-top: var(--space-1); }
|
|
2250
|
-
|
|
2251
3001
|
/* ---- ./progress.css ---- */
|
|
3002
|
+
@layer components {
|
|
2252
3003
|
/* progress ----------------------------------------------------------- */
|
|
2253
3004
|
|
|
2254
|
-
/* The bar
|
|
3005
|
+
/* The bar itself: a track with a child it fills, an animation and a
|
|
3006
|
+
reduced-motion answer. A utility is a property on one element, so none of
|
|
3007
|
+
that is one -- `Progress` draws its own wrapper and head with utilities and
|
|
3008
|
+
this is what is left.
|
|
3009
|
+
|
|
3010
|
+
The bar sat 4px under its own label and flush against whatever was above
|
|
2255
3011
|
the whole block, so a download row read as four lines of text with a rule
|
|
2256
3012
|
drawn through the last one. The label is a caption for the bar and stays
|
|
2257
3013
|
close to it; the block as a whole is a separate statement from the row it
|
|
2258
3014
|
follows. */
|
|
2259
|
-
.progress { display: grid; gap: var(--space-1); }
|
|
2260
|
-
|
|
2261
3015
|
.card > .progress { margin-top: var(--space-3); }
|
|
2262
3016
|
|
|
2263
|
-
.progress-head { display: flex; align-items: baseline; gap: var(--space-2); font-size: var(--text-sm); }
|
|
2264
|
-
|
|
2265
|
-
.progress-detail { color: var(--muted); font-size: var(--text-xs); }
|
|
2266
|
-
|
|
2267
3017
|
.bar { height: 6px; background: var(--panel-2); border-radius: var(--radius-pill); overflow: hidden; }
|
|
2268
3018
|
|
|
2269
3019
|
.bar > i {
|
|
@@ -2291,12 +3041,22 @@ input[type='radio']:active:not(:disabled) {
|
|
|
2291
3041
|
/* Still distinguishable from empty, and from full. */
|
|
2292
3042
|
.bar-indeterminate > i { animation: none; width: 100%; opacity: 0.35; }
|
|
2293
3043
|
}
|
|
3044
|
+
}
|
|
2294
3045
|
|
|
2295
3046
|
/* ---- ./tabs.css ---- */
|
|
3047
|
+
@layer components {
|
|
2296
3048
|
/* ---------------------------------------------------------------- tabs */
|
|
2297
3049
|
.tabs { position: relative; display: flex; gap: var(--space-1); }
|
|
2298
3050
|
|
|
2299
3051
|
.tab {
|
|
3052
|
+
/* 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. */
|
|
3053
|
+
display: inline-flex;
|
|
3054
|
+
align-items: center;
|
|
3055
|
+
justify-content: center;
|
|
3056
|
+
gap: var(--space-2);
|
|
3057
|
+
/* 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`. */
|
|
3058
|
+
font: inherit;
|
|
3059
|
+
cursor: pointer;
|
|
2300
3060
|
position: relative;
|
|
2301
3061
|
z-index: 1;
|
|
2302
3062
|
background: transparent;
|
|
@@ -2385,8 +3145,10 @@ input[type='radio']:active:not(:disabled) {
|
|
|
2385
3145
|
}
|
|
2386
3146
|
|
|
2387
3147
|
.tabs-vertical .tab:active:not(:disabled) { border-color: transparent; }
|
|
3148
|
+
}
|
|
2388
3149
|
|
|
2389
3150
|
/* ---- ./toast.css ---- */
|
|
3151
|
+
@layer components {
|
|
2390
3152
|
/* ---------------------------------------------------------------- toasts */
|
|
2391
3153
|
.toasts {
|
|
2392
3154
|
position: fixed;
|
|
@@ -2453,7 +3215,41 @@ input[type='radio']:active:not(:disabled) {
|
|
|
2453
3215
|
.toast[data-exiting] { animation: none; }
|
|
2454
3216
|
}
|
|
2455
3217
|
|
|
3218
|
+
/* The dismiss control, in its own words.
|
|
3219
|
+
*
|
|
3220
|
+
* It was `className="ghost size-sm"` -- `Button`'s vocabulary, borrowed from
|
|
3221
|
+
* a component that does not render a `Button`. That only ever worked because
|
|
3222
|
+
* `.ghost` and `.size-sm` were element-and-class rules any `<button>` could
|
|
3223
|
+
* pick up, which is the coupling this pass is removing. Nothing photographed
|
|
3224
|
+
* it, either: the toast is transient and the close button is not in any
|
|
3225
|
+
* baseline, so this would have gone quiet. */
|
|
3226
|
+
.toast-close {
|
|
3227
|
+
display: inline-flex;
|
|
3228
|
+
align-items: center;
|
|
3229
|
+
justify-content: center;
|
|
3230
|
+
font: inherit;
|
|
3231
|
+
font-size: var(--text-xs);
|
|
3232
|
+
padding: var(--space-1) var(--space-2);
|
|
3233
|
+
background: transparent;
|
|
3234
|
+
border: var(--border-width) solid transparent;
|
|
3235
|
+
border-radius: var(--radius);
|
|
3236
|
+
color: var(--muted);
|
|
3237
|
+
cursor: pointer;
|
|
3238
|
+
}
|
|
3239
|
+
|
|
3240
|
+
.toast-close:hover:not(:disabled) {
|
|
3241
|
+
background: var(--panel-2);
|
|
3242
|
+
color: var(--text);
|
|
3243
|
+
}
|
|
3244
|
+
|
|
3245
|
+
.toast-close:focus-visible {
|
|
3246
|
+
outline: 2px solid var(--accent);
|
|
3247
|
+
outline-offset: 2px;
|
|
3248
|
+
}
|
|
3249
|
+
}
|
|
3250
|
+
|
|
2456
3251
|
/* ---- ./modal.css ---- */
|
|
3252
|
+
@layer components {
|
|
2457
3253
|
/* modal --------------------------------------------------------------- */
|
|
2458
3254
|
|
|
2459
3255
|
/* `hidden` needs saying out loud here. The browser's own `[hidden]` rule is a
|
|
@@ -2493,13 +3289,6 @@ input[type='radio']:active:not(:disabled) {
|
|
|
2493
3289
|
Not `display: contents`, which was the first attempt. An element with no box
|
|
2494
3290
|
cannot take focus, so React Aria's initial focus fell through to the first
|
|
2495
3291
|
input and Escape -- handled on the section -- stopped closing the window. */
|
|
2496
|
-
.modal-dialog {
|
|
2497
|
-
display: flex;
|
|
2498
|
-
flex-direction: column;
|
|
2499
|
-
min-height: 0;
|
|
2500
|
-
flex: 1;
|
|
2501
|
-
}
|
|
2502
|
-
|
|
2503
3292
|
.modal {
|
|
2504
3293
|
background: var(--panel);
|
|
2505
3294
|
border: 1px solid var(--border);
|
|
@@ -2550,18 +3339,9 @@ input[type='radio']:active:not(:disabled) {
|
|
|
2550
3339
|
laid out for the bare `<strong>` it used to hold -- 86px tall with them,
|
|
2551
3340
|
41px without, on a head whose padding is 12 over 8. `font: inherit` so the
|
|
2552
3341
|
`<strong>` rule above is the one that sets the size. */
|
|
2553
|
-
.modal-title { margin: 0; font: inherit; }
|
|
2554
|
-
|
|
2555
3342
|
/* Under the title, on the header's padding rather than the body's, so it reads
|
|
2556
3343
|
as part of the heading rather than as the first line of content. */
|
|
2557
|
-
.modal-desc {
|
|
2558
|
-
margin: 0;
|
|
2559
|
-
padding: 0 var(--space-4) var(--space-3);
|
|
2560
|
-
color: var(--muted);
|
|
2561
|
-
font-size: var(--text-sm);
|
|
2562
|
-
line-height: 1.5;
|
|
2563
|
-
max-width: 62ch;
|
|
2564
|
-
}
|
|
3344
|
+
.modal-desc { line-height: 1.5; }
|
|
2565
3345
|
|
|
2566
3346
|
.modal-body { padding: var(--space-2) var(--space-4) var(--space-3); overflow-y: auto; }
|
|
2567
3347
|
|
|
@@ -2700,8 +3480,10 @@ input[type='radio']:active:not(:disabled) {
|
|
|
2700
3480
|
.modal.sheet[data-entering],
|
|
2701
3481
|
.modal.sheet[data-exiting] { animation: none; }
|
|
2702
3482
|
}
|
|
3483
|
+
}
|
|
2703
3484
|
|
|
2704
3485
|
/* ---- ./slider.css ---- */
|
|
3486
|
+
@layer components {
|
|
2705
3487
|
/* slider ----------------------------------------------------------------- */
|
|
2706
3488
|
/* A number from a range -- `Slider.tsx` says when one is the right control.
|
|
2707
3489
|
The row is laid out like a switch row: words on the left, the control on the
|
|
@@ -2921,9 +3703,12 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
|
|
|
2921
3703
|
buttons only, so a button in a row stood 25px beside a 35px select and no
|
|
2922
3704
|
size class could ask for the select's height. Type from the row, box from
|
|
2923
3705
|
the scale, and the two line up; an explicit `size-*` still wins. */
|
|
2924
|
-
:where(.set-row) button,
|
|
3706
|
+
:where(.set-row) button,
|
|
3707
|
+
:where(.set-row) .slider-box { font-size: var(--text-xs); }
|
|
3708
|
+
}
|
|
2925
3709
|
|
|
2926
3710
|
/* ---- ./checkbox.css ---- */
|
|
3711
|
+
@layer components {
|
|
2927
3712
|
/* A row you choose. There is no checkbox in it.
|
|
2928
3713
|
Every one of the fourteen in this app sits beside a name and a line of
|
|
2929
3714
|
explanation, so the row was always the thing being designed and the 17px
|
|
@@ -3093,36 +3878,36 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
|
|
|
3093
3878
|
.choice[data-disabled] .choice-why { opacity: 0.5; }
|
|
3094
3879
|
|
|
3095
3880
|
.choice[data-disabled]::after { opacity: 0.4; }
|
|
3881
|
+
}
|
|
3096
3882
|
|
|
3097
3883
|
/* ---- ./table.css ---- */
|
|
3884
|
+
@layer components {
|
|
3098
3885
|
/* A second line under a row's name, inside the `<th scope="row">` that makes it
|
|
3099
3886
|
one. The cell is bold because it is a heading; what hangs under it is not,
|
|
3100
3887
|
and inherited the weight -- so a pinned version read as loud as the thing it
|
|
3101
3888
|
versions. */
|
|
3102
|
-
.table th .set-hint { font-weight: 400; }
|
|
3889
|
+
.data-table th .set-hint { font-weight: 400; }
|
|
3103
3890
|
|
|
3104
|
-
.table
|
|
3105
|
-
|
|
3106
|
-
.table {
|
|
3891
|
+
.data-table {
|
|
3107
3892
|
width: 100%;
|
|
3108
3893
|
border-collapse: collapse;
|
|
3109
3894
|
font-size: var(--text-sm);
|
|
3110
3895
|
}
|
|
3111
3896
|
|
|
3112
|
-
.table th,
|
|
3113
|
-
.table td {
|
|
3897
|
+
.data-table th,
|
|
3898
|
+
.data-table td {
|
|
3114
3899
|
text-align: left;
|
|
3115
3900
|
padding: var(--space-2) var(--space-3);
|
|
3116
3901
|
border-bottom: var(--border-width) solid var(--border);
|
|
3117
3902
|
}
|
|
3118
3903
|
|
|
3119
|
-
.table th:first-child,
|
|
3120
|
-
.table td:first-child { padding-left: 0; }
|
|
3904
|
+
.data-table th:first-child,
|
|
3905
|
+
.data-table td:first-child { padding-left: 0; }
|
|
3121
3906
|
|
|
3122
|
-
.table th:last-child,
|
|
3123
|
-
.table td:last-child { padding-right: 0; }
|
|
3907
|
+
.data-table th:last-child,
|
|
3908
|
+
.data-table td:last-child { padding-right: 0; }
|
|
3124
3909
|
|
|
3125
|
-
.table thead th {
|
|
3910
|
+
.data-table thead th {
|
|
3126
3911
|
font-size: var(--text-xs);
|
|
3127
3912
|
font-weight: var(--weight-strong);
|
|
3128
3913
|
text-transform: uppercase;
|
|
@@ -3133,78 +3918,69 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
|
|
|
3133
3918
|
|
|
3134
3919
|
/* The row's own name: a `<th scope="row">`, so it carries weight rather than
|
|
3135
3920
|
reading as one more cell. */
|
|
3136
|
-
.table tbody th { font-weight: var(--weight-strong); }
|
|
3921
|
+
.data-table tbody th { font-weight: var(--weight-strong); }
|
|
3137
3922
|
|
|
3138
|
-
.table tbody tr:last-child th,
|
|
3139
|
-
.table tbody tr:last-child td { border-bottom: none; }
|
|
3923
|
+
.data-table tbody tr:last-child th,
|
|
3924
|
+
.data-table tbody tr:last-child td { border-bottom: none; }
|
|
3140
3925
|
|
|
3141
3926
|
/* Numbers compare by column, so they align right and hold their tracks --
|
|
3142
3927
|
proportional digits shift the alignment by a pixel per glyph, which is
|
|
3143
3928
|
exactly the comparison the column was for. */
|
|
3144
|
-
.table .num { text-align: right; font-variant-numeric: tabular-nums; font-family: var(--font-mono); }
|
|
3929
|
+
.data-table .num { text-align: right; font-variant-numeric: tabular-nums; font-family: var(--font-mono); }
|
|
3145
3930
|
|
|
3146
|
-
.table thead th[style*='right'] { text-align: right; }
|
|
3931
|
+
.data-table thead th[style*='right'] { text-align: right; }
|
|
3932
|
+
}
|
|
3147
3933
|
|
|
3148
3934
|
/* ---- ./sizegrid.css ---- */
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3935
|
+
@layer components {
|
|
3936
|
+
/* The cell's colour, all of it, in one place.
|
|
3937
|
+
*
|
|
3938
|
+
* `SizeGrid` draws the cell's geometry with utilities and leaves every colour
|
|
3939
|
+
* here, because `on` and `chosen` override the resting state -- and a utility
|
|
3940
|
+
* is in `@layer utilities`, which beats `@layer components` whatever the
|
|
3941
|
+
* selector. Stated as `surface-panel-2` and `border-border` on the element,
|
|
3942
|
+
* the resting state won permanently and no cell ever lit up.
|
|
3943
|
+
*
|
|
3944
|
+
* That is the third time this pattern has bitten: `Select`'s tick and
|
|
3945
|
+
* `Empty`'s figure were the other two. The rule: a resting state whose
|
|
3946
|
+
* active state is a CSS rule has to be a CSS rule too. */
|
|
3154
3947
|
.size-cell {
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
background: var(--panel-2); cursor: pointer;
|
|
3948
|
+
border: var(--border-width) solid var(--border);
|
|
3949
|
+
background: var(--panel-2);
|
|
3158
3950
|
}
|
|
3159
3951
|
|
|
3160
3952
|
/* `on` follows the pointer; `chosen` is what is actually saved, shown only
|
|
3161
3953
|
when nothing is hovered so the two can never contradict each other. */
|
|
3162
|
-
.size-cell.on {
|
|
3954
|
+
.size-cell.on {
|
|
3955
|
+
border-color: var(--accent);
|
|
3956
|
+
background: color-mix(in srgb, var(--accent) 45%, transparent);
|
|
3957
|
+
}
|
|
3163
3958
|
|
|
3164
3959
|
.size-cell.chosen { border-color: var(--accent); }
|
|
3165
|
-
|
|
3166
|
-
.size-cell:disabled { cursor: default; opacity: 0.5; }
|
|
3167
|
-
|
|
3168
|
-
.size-ceiling { opacity: 0.55; }
|
|
3960
|
+
}
|
|
3169
3961
|
|
|
3170
3962
|
/* ---- ./tooltip.css ---- */
|
|
3963
|
+
@layer components {
|
|
3171
3964
|
/* A callout: something worth knowing, with nothing to answer. Distinct from a
|
|
3172
3965
|
`?`, which is an offer to read more, and from a banner, which is a problem.
|
|
3173
3966
|
The mark is a round `i` rather than an emoji so it takes the theme's colours
|
|
3174
3967
|
and stays the same size as the text beside it. */
|
|
3175
|
-
/* An info-toned `.callout`, spelled the old way. Identical to it now rather
|
|
3176
|
-
nearly identical to it, which is the whole point of the consolidation
|
|
3177
|
-
|
|
3178
|
-
|
|
3968
|
+
/* An info-toned `.callout`, spelled the old way. Identical to it now rather
|
|
3969
|
+
than nearly identical to it, which is the whole point of the consolidation.
|
|
3970
|
+
(This comment has been unterminated since before the Tailwind branch -- it
|
|
3971
|
+
stops mid-sentence and never closes, so the CSS parser merged it with the
|
|
3972
|
+
one below and recovered. Nothing was lost from the stylesheet; the rest of
|
|
3973
|
+
the sentence was. Closed here rather than guessed at.) */
|
|
3974
|
+
|
|
3975
|
+
/* What is left once `Tooltip` draws its own mark: the hover and focus that
|
|
3976
|
+
reach the mark from its parent, and the tip -- whose closed and open
|
|
3977
|
+
states are three rules the cascade resolves in order, with
|
|
3978
|
+
`data-entering` and `data-exiting` around the transition. None of that is
|
|
3979
|
+
a property on one element.
|
|
3980
|
+
|
|
3981
|
+
The `?` beside a setting, and the box it shows on hover. Built like the
|
|
3179
3982
|
status dot's tooltip and for the same reasons: `title` waits a second and a
|
|
3180
3983
|
half, renders newlines however it likes, and cannot be styled. */
|
|
3181
|
-
.explain {
|
|
3182
|
-
position: relative;
|
|
3183
|
-
flex: none;
|
|
3184
|
-
display: inline-flex;
|
|
3185
|
-
align-items: center;
|
|
3186
|
-
/* The heading it follows is tracked out, which leaves the last letter's
|
|
3187
|
-
spacing sitting between them and reads as none at all. */
|
|
3188
|
-
margin-left: var(--space-2);
|
|
3189
|
-
cursor: help;
|
|
3190
|
-
/* Headings here are uppercase and tracked out, and one of these sits inside
|
|
3191
|
-
a heading. */
|
|
3192
|
-
text-transform: none;
|
|
3193
|
-
letter-spacing: normal;
|
|
3194
|
-
font-weight: 400;
|
|
3195
|
-
}
|
|
3196
|
-
|
|
3197
|
-
.explain-mark {
|
|
3198
|
-
width: 18px;
|
|
3199
|
-
height: 18px;
|
|
3200
|
-
border-radius: 50%;
|
|
3201
|
-
border: 1px solid var(--border);
|
|
3202
|
-
color: var(--muted);
|
|
3203
|
-
font-size: var(--text-xs);
|
|
3204
|
-
line-height: 16px;
|
|
3205
|
-
text-align: center;
|
|
3206
|
-
}
|
|
3207
|
-
|
|
3208
3984
|
.explain:hover .explain-mark,
|
|
3209
3985
|
.explain:focus-visible .explain-mark { color: var(--text); border-color: var(--accent); }
|
|
3210
3986
|
|
|
@@ -3277,8 +4053,10 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
|
|
|
3277
4053
|
}
|
|
3278
4054
|
|
|
3279
4055
|
.explain-tip strong { color: var(--text); font-weight: 600; }
|
|
4056
|
+
}
|
|
3280
4057
|
|
|
3281
4058
|
/* ---- ./illustration.css ---- */
|
|
4059
|
+
@layer components {
|
|
3282
4060
|
/* illustrations -------------------------------------------------------- */
|
|
3283
4061
|
|
|
3284
4062
|
/* Open Peeps, two colours, wearing whatever the theme is.
|
|
@@ -3305,7 +4083,21 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
|
|
|
3305
4083
|
a shirt that lets the arm behind it show through reads as a hole. */
|
|
3306
4084
|
.illo .paper { fill: var(--illo-paper); }
|
|
3307
4085
|
|
|
4086
|
+
/* The figure in a whole-surface `Empty`, drawn in the muted grey of the
|
|
4087
|
+
sentence under it.
|
|
4088
|
+
*
|
|
4089
|
+
* A utility cannot do this, and the reason is worth keeping: `.illo` sets
|
|
4090
|
+
* `color: inherit` and is unlayered, while every Tailwind utility lives in
|
|
4091
|
+
* `@layer utilities` -- and an unlayered declaration beats a layered one
|
|
4092
|
+
* whatever the specificity. So `text-muted` on the figure lost, silently,
|
|
4093
|
+
* and the shirt came out full text black beside a muted sentence. The
|
|
4094
|
+
* original rule already carried a note about needing two classes to beat
|
|
4095
|
+
* `.illo`; layers make that impossible rather than merely fiddly. */
|
|
4096
|
+
.nothing-figure { color: var(--muted); }
|
|
4097
|
+
}
|
|
4098
|
+
|
|
3308
4099
|
/* ---- ./field.css ---- */
|
|
4100
|
+
@layer components {
|
|
3309
4101
|
/* fields --------------------------------------------------------------- */
|
|
3310
4102
|
|
|
3311
4103
|
/* Label, description, input, error -- in the order they are wanted. The
|
|
@@ -3403,7 +4195,7 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
|
|
|
3403
4195
|
.adorned > .adorned-mark,
|
|
3404
4196
|
.adorned > .adorned-end { grid-area: 1 / 1; }
|
|
3405
4197
|
|
|
3406
|
-
.adorned.block { width: 100%; }
|
|
4198
|
+
.adorned.ctl-block { width: 100%; }
|
|
3407
4199
|
|
|
3408
4200
|
.adorned > .adorned-mark {
|
|
3409
4201
|
justify-self: start;
|
|
@@ -3456,7 +4248,34 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
|
|
|
3456
4248
|
|
|
3457
4249
|
.adorned-lg .adorned-clear { padding: var(--space-2); }
|
|
3458
4250
|
|
|
4251
|
+
/* The eye and the clear button stop borrowing `ghost`.
|
|
4252
|
+
*
|
|
4253
|
+
* Both were `className="icon-btn ghost …"` -- reaching into `Button`'s class
|
|
4254
|
+
* vocabulary from another component, which worked only because `.ghost` was
|
|
4255
|
+
* written as `button.ghost` and they happen to be `<button>`s. It is `.btn.ghost`
|
|
4256
|
+
* now, so the borrowing stopped matching and `.icon-btn`'s panel background
|
|
4257
|
+
* came through: the baselines showed a filled tile where there had been a bare
|
|
4258
|
+
* glyph.
|
|
4259
|
+
*
|
|
4260
|
+
* Stated here instead. What they actually wanted from `ghost` is two lines,
|
|
4261
|
+
* and saying them is cheaper than either component knowing what a button's
|
|
4262
|
+
* classes are called. */
|
|
4263
|
+
.secret-eye,
|
|
4264
|
+
.adorned-clear {
|
|
4265
|
+
background: transparent;
|
|
4266
|
+
border-color: transparent;
|
|
4267
|
+
color: var(--muted);
|
|
4268
|
+
}
|
|
4269
|
+
|
|
4270
|
+
.secret-eye:hover:not(:disabled),
|
|
4271
|
+
.adorned-clear:hover:not(:disabled) {
|
|
4272
|
+
background: var(--panel-2);
|
|
4273
|
+
color: var(--text);
|
|
4274
|
+
}
|
|
4275
|
+
}
|
|
4276
|
+
|
|
3459
4277
|
/* ---- ./tour.css ---- */
|
|
4278
|
+
@layer components {
|
|
3460
4279
|
/* tour ----------------------------------------------------------------- */
|
|
3461
4280
|
|
|
3462
4281
|
/* The layer sits over everything and catches nothing: the scrim is painted by
|
|
@@ -3518,141 +4337,41 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
|
|
|
3518
4337
|
.tour-actions { display: flex; align-items: center; gap: var(--space-2); margin-top: var(--space-2); }
|
|
3519
4338
|
|
|
3520
4339
|
.tour-count { color: var(--muted); font-size: var(--text-xs); }
|
|
4340
|
+
}
|
|
3521
4341
|
|
|
3522
4342
|
/* The mail and forum shell, added in 0.4.0. After the rest, because the
|
|
3523
4343
|
anchored surfaces (`.pop`, `.menu-sheet`, `.cmd`) sit over everything and a
|
|
3524
4344
|
rule of equal specificity that came earlier would lose to whatever the
|
|
3525
4345
|
sheets they cover happen to set. */
|
|
3526
|
-
/* ---- ./kbd.css ---- */
|
|
3527
|
-
/* One rule where there were two identical ones, in `menu.css` and
|
|
3528
|
-
`command.css`. Both keep their class as well, so `Menu` and `Command` are
|
|
3529
|
-
`.kbd .menu-key` and `.kbd .cmd-key` now: the declarations are the same, so
|
|
3530
|
-
nothing moves, and the context classes stay available for a rule that ever
|
|
3531
|
-
needs to tell the two apart. */
|
|
3532
|
-
.kbd {
|
|
3533
|
-
flex: none;
|
|
3534
|
-
font-family: var(--font-mono);
|
|
3535
|
-
font-size: var(--text-2xs);
|
|
3536
|
-
color: var(--muted);
|
|
3537
|
-
letter-spacing: var(--tracking);
|
|
3538
|
-
}
|
|
3539
|
-
|
|
3540
4346
|
/* ---- ./stat.css ---- */
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
.
|
|
3544
|
-
|
|
3545
|
-
gap: var(--space-1);
|
|
3546
|
-
padding: var(--space-4);
|
|
3547
|
-
border: var(--border-width) solid var(--border);
|
|
3548
|
-
border-radius: var(--radius-md);
|
|
3549
|
-
background: var(--panel);
|
|
3550
|
-
}
|
|
3551
|
-
|
|
3552
|
-
/* Inside something already bordered. A bordered tile in a bordered row is two
|
|
3553
|
-
boxes saying one thing. */
|
|
3554
|
-
.stat-bare {
|
|
3555
|
-
padding: 0;
|
|
3556
|
-
border: 0;
|
|
3557
|
-
border-radius: 0;
|
|
3558
|
-
background: none;
|
|
3559
|
-
gap: 0;
|
|
3560
|
-
line-height: 1.25;
|
|
3561
|
-
}
|
|
3562
|
-
|
|
3563
|
-
.stat > p { margin: 0; }
|
|
3564
|
-
|
|
3565
|
-
.stat-label {
|
|
3566
|
-
color: var(--muted);
|
|
3567
|
-
font-size: var(--text-xs);
|
|
3568
|
-
}
|
|
3569
|
-
|
|
3570
|
-
/* Tabular figures are the point: a column of numbers is compared by its
|
|
3571
|
-
digits' positions, and proportional ones move them per row. */
|
|
3572
|
-
.stat-value {
|
|
3573
|
-
font-size: var(--text-lg);
|
|
3574
|
-
font-weight: var(--weight-strong);
|
|
3575
|
-
font-variant-numeric: tabular-nums;
|
|
3576
|
-
}
|
|
3577
|
-
|
|
3578
|
-
.stat-bare .stat-value { font-size: var(--text-sm); }
|
|
3579
|
-
|
|
3580
|
-
.stat-note {
|
|
3581
|
-
color: var(--muted);
|
|
3582
|
-
font-size: var(--text-xs);
|
|
3583
|
-
}
|
|
4347
|
+
@layer components {
|
|
4348
|
+
/* What the utilities on `Stat` cannot say: a tone on the tile colouring the
|
|
4349
|
+
figure inside it. An attribute on the parent selecting a child is a
|
|
4350
|
+
relationship; a utility is a property on one element.
|
|
3584
4351
|
|
|
3585
|
-
|
|
3586
|
-
status box,
|
|
4352
|
+
Only the figure takes the colour. Colouring the label too makes the tile a
|
|
4353
|
+
status box, where a tone here is a remark about the number. */
|
|
3587
4354
|
.stat[data-tone='info'] .stat-value { color: var(--info); }
|
|
3588
4355
|
.stat[data-tone='good'] .stat-value { color: var(--good); }
|
|
3589
4356
|
.stat[data-tone='warn'] .stat-value { color: var(--warn); }
|
|
3590
4357
|
.stat[data-tone='bad'] .stat-value { color: var(--bad); }
|
|
3591
|
-
|
|
3592
|
-
/* ---- ./shell.css ---- */
|
|
3593
|
-
/* The frame. Layout only: every colour and every step is a token, and the
|
|
3594
|
-
page inside it owns its own spacing. */
|
|
3595
|
-
.shell {
|
|
3596
|
-
display: flex;
|
|
3597
|
-
flex-direction: column;
|
|
3598
|
-
min-height: 100vh;
|
|
3599
|
-
background: var(--bg);
|
|
3600
|
-
color: var(--text);
|
|
3601
4358
|
}
|
|
3602
4359
|
|
|
3603
|
-
.
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
and `main-wide` as separate classes. */
|
|
4360
|
+
/* ---- ./shell.css ---- */
|
|
4361
|
+
@layer components {
|
|
4362
|
+
/* The measure, and only the measure.
|
|
4363
|
+
*
|
|
4364
|
+
* `Shell` draws itself with utilities -- it is layout and nothing else. What
|
|
4365
|
+
* stays here is the one value the header band, the nav band and the main band
|
|
4366
|
+
* all have to agree on: a custom property, so an app changes it in one place
|
|
4367
|
+
* rather than overriding three rules and missing the fourth. That is how
|
|
4368
|
+
* manage ended up carrying `head-inner-wide` and `main-wide` as separate
|
|
4369
|
+
* classes it had to remember together. */
|
|
3614
4370
|
.shell {
|
|
3615
4371
|
--shell-measure: 64rem;
|
|
3616
4372
|
--shell-measure-wide: 90rem;
|
|
3617
4373
|
}
|
|
3618
4374
|
|
|
3619
|
-
.shell-head-inner,
|
|
3620
|
-
.shell-nav,
|
|
3621
|
-
.shell-main {
|
|
3622
|
-
width: 100%;
|
|
3623
|
-
max-width: var(--shell-measure);
|
|
3624
|
-
margin-inline: auto;
|
|
3625
|
-
padding-inline: var(--space-4);
|
|
3626
|
-
}
|
|
3627
|
-
|
|
3628
|
-
.shell-wide { max-width: var(--shell-measure-wide); }
|
|
3629
|
-
|
|
3630
|
-
.shell-head-inner {
|
|
3631
|
-
display: flex;
|
|
3632
|
-
align-items: center;
|
|
3633
|
-
justify-content: space-between;
|
|
3634
|
-
gap: var(--space-4);
|
|
3635
|
-
padding-block: var(--space-3);
|
|
3636
|
-
min-width: 0;
|
|
3637
|
-
}
|
|
3638
|
-
|
|
3639
|
-
.shell-who {
|
|
3640
|
-
display: flex;
|
|
3641
|
-
align-items: center;
|
|
3642
|
-
gap: var(--space-3);
|
|
3643
|
-
min-width: 0;
|
|
3644
|
-
}
|
|
3645
|
-
|
|
3646
|
-
.shell-nav { padding-bottom: var(--space-2); }
|
|
3647
|
-
|
|
3648
|
-
.shell-main {
|
|
3649
|
-
flex: 1;
|
|
3650
|
-
padding-block: var(--space-6);
|
|
3651
|
-
/* `min-width: 0` because a flex child will not shrink below its content,
|
|
3652
|
-
and one wide table inside then pushes the whole page sideways. */
|
|
3653
|
-
min-width: 0;
|
|
3654
|
-
}
|
|
3655
|
-
|
|
3656
4375
|
/* The label beside the theme control, when it is drawn. */
|
|
3657
4376
|
.theme-switch {
|
|
3658
4377
|
display: flex;
|
|
@@ -3666,8 +4385,10 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
|
|
|
3666
4385
|
font-size: var(--text-sm);
|
|
3667
4386
|
white-space: nowrap;
|
|
3668
4387
|
}
|
|
4388
|
+
}
|
|
3669
4389
|
|
|
3670
4390
|
/* ---- ./scrollarea.css ---- */
|
|
4391
|
+
@layer components {
|
|
3671
4392
|
/* A box that scrolls, with its edges drawn.
|
|
3672
4393
|
|
|
3673
4394
|
The fades are `::before`/`::after` on the scroller itself, pinned with
|
|
@@ -3760,8 +4481,10 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
|
|
|
3760
4481
|
.scroller.faded::before,
|
|
3761
4482
|
.scroller.faded::after { transition: none; }
|
|
3762
4483
|
}
|
|
4484
|
+
}
|
|
3763
4485
|
|
|
3764
4486
|
/* ---- ./splitpane.css ---- */
|
|
4487
|
+
@layer components {
|
|
3765
4488
|
/* Two panes and the handle between them. */
|
|
3766
4489
|
.split {
|
|
3767
4490
|
display: flex;
|
|
@@ -3861,8 +4584,10 @@ body.splitting * { cursor: inherit !important; }
|
|
|
3861
4584
|
@media (prefers-reduced-motion: reduce) {
|
|
3862
4585
|
.split-grip { transition: none; }
|
|
3863
4586
|
}
|
|
4587
|
+
}
|
|
3864
4588
|
|
|
3865
4589
|
/* ---- ./popover.css ---- */
|
|
4590
|
+
@layer components {
|
|
3866
4591
|
/* A small surface anchored to what opened it. Same sheet as the select's list,
|
|
3867
4592
|
because they are the same object -- something that appeared over the page,
|
|
3868
4593
|
attached to a control. */
|
|
@@ -3916,29 +4641,17 @@ body.splitting * { cursor: inherit !important; }
|
|
|
3916
4641
|
.pop[data-entering],
|
|
3917
4642
|
.pop[data-exiting] { animation: none; }
|
|
3918
4643
|
}
|
|
3919
|
-
|
|
3920
|
-
/* ---- ./menu.css ---- */
|
|
3921
|
-
/* A list of verbs, on the same sheet as every other anchored surface. */
|
|
3922
|
-
.menu-sheet {
|
|
3923
|
-
background: var(--panel);
|
|
3924
|
-
border: var(--border-width) solid var(--border);
|
|
3925
|
-
border-radius: var(--radius-md);
|
|
3926
|
-
box-shadow: var(--shadow-2);
|
|
3927
|
-
min-width: 12rem;
|
|
3928
|
-
max-width: min(20rem, calc(100vw - var(--space-6)));
|
|
3929
|
-
max-height: 24rem;
|
|
3930
|
-
overflow: auto;
|
|
3931
|
-
overscroll-behavior: contain;
|
|
3932
|
-
z-index: 60;
|
|
3933
4644
|
}
|
|
3934
4645
|
|
|
3935
|
-
.
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
4646
|
+
/* ---- ./menu.css ---- */
|
|
4647
|
+
@layer components {
|
|
4648
|
+
/* What is left once `Menu` draws its sheet and its list: the rows, whose
|
|
4649
|
+
`data-focused`, `data-pressed` and danger states React Aria stamps on
|
|
4650
|
+
them, and the rules that reach from a row into what it holds. The
|
|
4651
|
+
`box-shadow` stays on the sheet too -- `--shadow-2` is a token, and a
|
|
4652
|
+
utility would have to inline it. */
|
|
3941
4653
|
|
|
4654
|
+
/* A list of verbs, on the same sheet as every other anchored surface. */
|
|
3942
4655
|
.menu-item {
|
|
3943
4656
|
display: flex;
|
|
3944
4657
|
align-items: center;
|
|
@@ -3977,14 +4690,6 @@ body.splitting * { cursor: inherit !important; }
|
|
|
3977
4690
|
/* The binding, set in the mono face at the size of the small print. Right of
|
|
3978
4691
|
the row and never the reason the row is wide: `flex: none` with the label
|
|
3979
4692
|
taking the slack. */
|
|
3980
|
-
.menu-key {
|
|
3981
|
-
flex: none;
|
|
3982
|
-
font-family: var(--font-mono);
|
|
3983
|
-
font-size: var(--text-2xs);
|
|
3984
|
-
color: var(--muted);
|
|
3985
|
-
letter-spacing: var(--tracking);
|
|
3986
|
-
}
|
|
3987
|
-
|
|
3988
4693
|
.menu-more { flex: none; color: var(--muted); }
|
|
3989
4694
|
|
|
3990
4695
|
.menu-rule {
|
|
@@ -4020,7 +4725,11 @@ body.splitting * { cursor: inherit !important; }
|
|
|
4020
4725
|
.menu-sheet[data-exiting] { animation: none; }
|
|
4021
4726
|
}
|
|
4022
4727
|
|
|
4728
|
+
.menu-sheet { box-shadow: var(--shadow-2); }
|
|
4729
|
+
}
|
|
4730
|
+
|
|
4023
4731
|
/* ---- ./command.css ---- */
|
|
4732
|
+
@layer components {
|
|
4024
4733
|
/* The command palette: a field over the app and a list under it. */
|
|
4025
4734
|
.cmd-scrim {
|
|
4026
4735
|
position: fixed;
|
|
@@ -4137,14 +4846,6 @@ body.splitting * { cursor: inherit !important; }
|
|
|
4137
4846
|
white-space: nowrap;
|
|
4138
4847
|
}
|
|
4139
4848
|
|
|
4140
|
-
.cmd-key {
|
|
4141
|
-
flex: none;
|
|
4142
|
-
font-family: var(--font-mono);
|
|
4143
|
-
font-size: var(--text-2xs);
|
|
4144
|
-
color: var(--muted);
|
|
4145
|
-
letter-spacing: var(--tracking);
|
|
4146
|
-
}
|
|
4147
|
-
|
|
4148
4849
|
.cmd-empty {
|
|
4149
4850
|
margin: 0;
|
|
4150
4851
|
padding: var(--space-6) var(--space-4);
|
|
@@ -4170,25 +4871,18 @@ body.splitting * { cursor: inherit !important; }
|
|
|
4170
4871
|
.cmd-scrim[data-exiting],
|
|
4171
4872
|
.cmd[data-entering] { animation: none; }
|
|
4172
4873
|
}
|
|
4874
|
+
}
|
|
4173
4875
|
|
|
4174
4876
|
/* ---- ./pagination.css ---- */
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
gap: var(--space-4);
|
|
4181
|
-
flex-wrap: wrap;
|
|
4182
|
-
padding: var(--space-2) 0;
|
|
4183
|
-
font-size: var(--text-xs);
|
|
4184
|
-
color: var(--muted);
|
|
4185
|
-
}
|
|
4877
|
+
@layer components {
|
|
4878
|
+
/* What is left once `Pagination` draws its own frame: the step and page
|
|
4879
|
+
buttons, whose hover, focus-visible and current states are pseudo-classes
|
|
4880
|
+
on two selectors at once, and `.pager-count strong`, which reaches into
|
|
4881
|
+
text the caller passed. */
|
|
4186
4882
|
|
|
4187
|
-
|
|
4883
|
+
/* Moving through a list that does not fit, and saying how far in you are. */
|
|
4188
4884
|
.pager-count strong { color: var(--text); font-weight: var(--weight-strong); }
|
|
4189
4885
|
|
|
4190
|
-
.pager-controls { display: flex; align-items: center; gap: var(--space-1); }
|
|
4191
|
-
|
|
4192
4886
|
.pager-step,
|
|
4193
4887
|
.pager-page {
|
|
4194
4888
|
display: inline-flex;
|
|
@@ -4299,8 +4993,10 @@ body.splitting * { cursor: inherit !important; }
|
|
|
4299
4993
|
.pager-page,
|
|
4300
4994
|
.pager-jump { transition: none; }
|
|
4301
4995
|
}
|
|
4996
|
+
}
|
|
4302
4997
|
|
|
4303
4998
|
/* ---- ./identity.css ---- */
|
|
4999
|
+
@layer components {
|
|
4304
5000
|
/* A person, said in one line: initials, name, sometimes the address. */
|
|
4305
5001
|
.ident {
|
|
4306
5002
|
display: inline-flex;
|
|
@@ -4380,6 +5076,8 @@ body.splitting * { cursor: inherit !important; }
|
|
|
4380
5076
|
}
|
|
4381
5077
|
|
|
4382
5078
|
.ident-remove {
|
|
5079
|
+
/* 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`. */
|
|
5080
|
+
font: inherit;
|
|
4383
5081
|
flex: none;
|
|
4384
5082
|
display: inline-flex;
|
|
4385
5083
|
align-items: center;
|
|
@@ -4399,6 +5097,7 @@ body.splitting * { cursor: inherit !important; }
|
|
|
4399
5097
|
|
|
4400
5098
|
.ident-remove:hover { background: var(--panel); color: var(--text); }
|
|
4401
5099
|
.ident-remove:focus-visible { outline: none; box-shadow: var(--focus-ring); }
|
|
5100
|
+
}
|
|
4402
5101
|
/* ---- valet: the themes ---- */
|
|
4403
5102
|
:root[data-theme='valet']{--bg:#f4f5f8;--panel:#ffffff;--panel-2:#eceef3;--border:#dcdfe7;--border-strong:#7b8597;--text:#171a21;--muted:#5b6474;--accent:#4f46e5;--accent-dim:#a9a4f0;--on-accent:#ffffff;--good:#1b7f4b;--warn:#8a5f0a;--bad:#bf3a31;--info:#0e6f8e;--app-bg:#f4f5f8;--shadow-1:0 4px 14px rgba(23, 26, 33, 0.08);--shadow-2:0 8px 24px rgba(23, 26, 33, 0.10);--shadow-3:0 12px 32px rgba(23, 26, 33, 0.12);--scrim:rgba(23, 26, 33, 0.32);color-scheme:light}
|
|
4404
5103
|
:root[data-theme='valet-night']{--bg:#0c0f14;--panel:#141820;--panel-2:#1b2029;--border:#262c37;--border-strong:#616b7d;--text:#e8eaf0;--muted:#9ba4b5;--accent:#8f88ff;--accent-dim:#3f3a8f;--on-accent:#0d0b2e;--good:#5fcb8f;--warn:#e2ae58;--bad:#f28b84;--info:#57c4e8;--app-bg:#0c0f14;--shadow-1:0 6px 20px rgba(0, 0, 0, 0.28);--shadow-2:0 8px 28px rgba(0, 0, 0, 0.34);--shadow-3:0 10px 34px rgba(0, 0, 0, 0.38);--scrim:rgba(0, 0, 0, 0.5);color-scheme:dark}
|