@wtfalch/design 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/components/Button.d.ts +19 -27
  2. package/dist/components/Button.js +61 -1
  3. package/dist/components/Callout.d.ts +0 -21
  4. package/dist/components/Callout.js +7 -0
  5. package/dist/components/Card.js +7 -0
  6. package/dist/components/Checkbox.d.ts +12 -23
  7. package/dist/components/Checkbox.js +25 -2
  8. package/dist/components/Command.js +10 -2
  9. package/dist/components/DangerZone.js +7 -0
  10. package/dist/components/Dialog.d.ts +0 -21
  11. package/dist/components/Dialog.js +7 -0
  12. package/dist/components/Field.d.ts +13 -31
  13. package/dist/components/Field.js +10 -1
  14. package/dist/components/Identity.d.ts +0 -25
  15. package/dist/components/Identity.js +7 -0
  16. package/dist/components/Input.js +7 -0
  17. package/dist/components/Kbd.d.ts +7 -0
  18. package/dist/components/Kbd.js +34 -0
  19. package/dist/components/Markdown.js +7 -0
  20. package/dist/components/Menu.js +10 -2
  21. package/dist/components/Modal.d.ts +0 -33
  22. package/dist/components/Modal.js +7 -0
  23. package/dist/components/Pagination.d.ts +0 -33
  24. package/dist/components/Pagination.js +7 -0
  25. package/dist/components/Popover.js +7 -0
  26. package/dist/components/Rows.js +7 -0
  27. package/dist/components/ScrollArea.js +7 -0
  28. package/dist/components/Select.d.ts +6 -1
  29. package/dist/components/Select.js +9 -2
  30. package/dist/components/SizeGrid.js +7 -0
  31. package/dist/components/Slider.js +7 -0
  32. package/dist/components/SplitPane.js +7 -0
  33. package/dist/components/Stat.d.ts +45 -0
  34. package/dist/components/Stat.js +31 -0
  35. package/dist/components/Tabs.d.ts +21 -0
  36. package/dist/components/Tabs.js +8 -1
  37. package/dist/components/Toast.d.ts +24 -18
  38. package/dist/components/Toast.js +44 -3
  39. package/dist/components/Toggle.d.ts +0 -30
  40. package/dist/components/Toggle.js +7 -0
  41. package/dist/components/Tooltip.js +7 -0
  42. package/dist/components/Tour.d.ts +0 -23
  43. package/dist/components/Tour.js +7 -0
  44. package/dist/index.d.ts +13 -2
  45. package/dist/index.js +9 -1
  46. package/dist/styles/index.css +117 -13
  47. package/dist/tf.css +117 -13
  48. package/dist/valet.css +117 -13
  49. package/package.json +2 -1
@@ -93,7 +93,28 @@ body::before {
93
93
  where the flat grey reads as recessed rather than as something to use. It is
94
94
  derived rather than declared -- a new token would have to be added to every
95
95
  theme in `themes.ts`, and a theme that missed it would lose its controls. */
96
+ /* An anchor drawn as a button. Three things the element brings that a
97
+ `<button>` does not, and all three have to go: the underline, the link
98
+ colour, and the text alignment a block anchor inherits. `cursor: pointer`
99
+ it already has. Disabled is `aria-disabled` here -- an anchor ignores the
100
+ native attribute -- so every `:disabled` rule above has an
101
+ `[aria-disabled='true']` twin rather than a rewrite, which leaves each
102
+ `button` selector at the specificity it had and every committed baseline
103
+ untouched. */
104
+ a.btn {
105
+ text-decoration: none;
106
+ color: var(--text);
107
+ text-align: center;
108
+ }
109
+
110
+ a.btn[aria-disabled='true'] {
111
+ /* A disabled anchor still takes the pointer, so say so. The click itself is
112
+ blocked in the capture phase by the component. */
113
+ cursor: not-allowed;
114
+ }
115
+
96
116
  button,
117
+ a.btn,
97
118
  input,
98
119
  textarea,
99
120
  select {
@@ -117,7 +138,8 @@ select {
117
138
  the icon; the button simply had no opinion about how to arrange two things.
118
139
  `inline-flex` and a gap gives it one, and the gap replaces the space
119
140
  character people were putting between an icon and its label. */
120
- button {
141
+ button,
142
+ a.btn {
121
143
  display: inline-flex;
122
144
  align-items: center;
123
145
  justify-content: center;
@@ -143,7 +165,8 @@ button[aria-pressed='true']:hover:not(:disabled) { border-color: var(--accent);
143
165
 
144
166
  /* The glyph never shrinks: in a narrow row flexbox would take it from the icon
145
167
  before the text, and half an icon is not a smaller icon. */
146
- button > svg { flex: none; }
168
+ button > svg,
169
+ a.btn > svg { flex: none; }
147
170
 
148
171
  .size-sm { font-size: var(--text-xs); padding: var(--space-1) var(--space-2); }
149
172
 
@@ -169,6 +192,7 @@ input, textarea, select { width: 100%; }
169
192
  textarea { resize: none; }
170
193
 
171
194
  button:hover:not(:disabled),
195
+ a.btn:hover:not([aria-disabled='true']),
172
196
  input:hover:not(:disabled),
173
197
  textarea:hover:not(:disabled),
174
198
  select:hover:not(:disabled) { border-color: var(--accent); }
@@ -177,6 +201,7 @@ select:hover:not(:disabled) { border-color: var(--accent); }
177
201
  `:focus` on the fields because a focused field is a place you are typing and
178
202
  should say so however you got there. */
179
203
  button:focus-visible,
204
+ a.btn:focus-visible,
180
205
  input:focus,
181
206
  textarea:focus,
182
207
  select:focus { outline: none; border-color: var(--accent); }
@@ -270,11 +295,13 @@ input[type='checkbox']:disabled,
270
295
  input[type='radio']:disabled { cursor: not-allowed; background: var(--panel-2); }
271
296
 
272
297
  button:disabled,
298
+ a.btn[aria-disabled='true'],
273
299
  input:disabled,
274
300
  textarea:disabled,
275
301
  select:disabled { opacity: 0.45; cursor: not-allowed; }
276
302
 
277
- button.primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
303
+ button.primary,
304
+ a.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
278
305
 
279
306
  /* A disabled primary is not a faded primary.
280
307
  `opacity: .45` was the whole of it, and a coloured fill at 45% is still a
@@ -282,7 +309,8 @@ button.primary { background: var(--accent); border-color: var(--accent); color:
282
309
  thing on the panel. That got worse when onboarding started holding people at
283
310
  a disabled Next. So it gives up the fill entirely and becomes the shape of a
284
311
  disabled control -- the opacity then has nothing left to do. */
285
- button.primary:disabled {
312
+ button.primary:disabled,
313
+ a.btn.primary[aria-disabled='true'] {
286
314
  background: var(--panel-2);
287
315
  border-color: var(--border);
288
316
  color: var(--muted);
@@ -352,13 +380,15 @@ button[aria-busy='true']::after {
352
380
 
353
381
  /* Quiet: no border, no fill. For the action beside the action -- Cancel next to
354
382
  Save -- where a bordered box competes with the thing it is next to. */
355
- button.ghost {
383
+ button.ghost,
384
+ a.btn.ghost {
356
385
  background: transparent;
357
386
  border-color: transparent;
358
387
  color: var(--muted);
359
388
  }
360
389
 
361
- button.ghost:hover:not(:disabled) {
390
+ button.ghost:hover:not(:disabled),
391
+ a.btn.ghost:hover:not([aria-disabled='true']) {
362
392
  background: var(--panel-2);
363
393
  border-color: transparent;
364
394
  color: var(--text);
@@ -565,19 +595,22 @@ button.ghost:hover:not(:disabled) {
565
595
  /* `:where(button)` so this carries no specificity of its own: a component's
566
596
  press rule below -- a card, a tab, a rail item, all of them buttons --
567
597
  wins by coming later, instead of every one having to restate `button`. */
568
- :where(button):active:not(:disabled) {
598
+ :where(button):active:not(:disabled),
599
+ :where(a.btn):active:not([aria-disabled='true']) {
569
600
  background: color-mix(in srgb, var(--text) var(--press-ink), var(--control));
570
601
  border-color: var(--accent);
571
602
  transform: scale(var(--press-scale));
572
603
  transition: none;
573
604
  }
574
605
 
575
- button.primary:active:not(:disabled) {
606
+ button.primary:active:not(:disabled),
607
+ a.btn.primary:active:not([aria-disabled='true']) {
576
608
  background: color-mix(in srgb, var(--text) var(--press-ink), var(--accent));
577
609
  border-color: color-mix(in srgb, var(--text) var(--press-ink), var(--accent));
578
610
  }
579
611
 
580
- button.ghost:active:not(:disabled) {
612
+ button.ghost:active:not(:disabled),
613
+ a.btn.ghost:active:not([aria-disabled='true']) {
581
614
  background: color-mix(in srgb, var(--text) var(--press-ink), var(--panel-2));
582
615
  border-color: transparent;
583
616
  }
@@ -800,7 +833,8 @@ input:active, textarea:active, select:active { transform: none; }
800
833
  /* Full width, for the one action a card or a step is about. Not a size: a
801
834
  `block` button is the same height as any other, it just stops being a thing
802
835
  you have to aim at. */
803
- button.block { display: flex; width: 100%; }
836
+ button.block,
837
+ a.btn.block { display: flex; width: 100%; }
804
838
 
805
839
  /* The default is `size-md`, spelled once for every control.
806
840
  The paragraph above promised one scale for buttons, inputs and selects, and
@@ -809,6 +843,7 @@ button.block { display: flex; width: 100%; }
809
843
  could line up. The download modal's search box against its Search button was
810
844
  the version you could see from across the room. */
811
845
  button,
846
+ a.btn,
812
847
  input,
813
848
  textarea,
814
849
  select,
@@ -959,18 +994,21 @@ select,
959
994
 
960
995
  /* ---- ./dangerzone.css ---- */
961
996
  /* Destructive, and legible as such standing still. */
962
- button.danger {
997
+ button.danger,
998
+ a.btn.danger {
963
999
  color: var(--bad);
964
1000
  border-color: color-mix(in srgb, var(--bad) 45%, var(--border-strong));
965
1001
  }
966
1002
 
967
- button.danger:hover:not(:disabled) {
1003
+ button.danger:hover:not(:disabled),
1004
+ a.btn.danger:hover:not([aria-disabled='true']) {
968
1005
  background: color-mix(in srgb, var(--bad) 12%, var(--panel));
969
1006
  border-color: var(--bad);
970
1007
  color: var(--bad);
971
1008
  }
972
1009
 
973
- button.danger:active:not(:disabled) {
1010
+ button.danger:active:not(:disabled),
1011
+ a.btn.danger:active:not([aria-disabled='true']) {
974
1012
  background: color-mix(in srgb, var(--bad) 20%, var(--panel));
975
1013
  border-color: var(--bad);
976
1014
  }
@@ -3147,6 +3185,72 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
3147
3185
  anchored surfaces (`.pop`, `.menu-sheet`, `.cmd`) sit over everything and a
3148
3186
  rule of equal specificity that came earlier would lose to whatever the
3149
3187
  sheets they cover happen to set. */
3188
+ /* ---- ./kbd.css ---- */
3189
+ /* One rule where there were two identical ones, in `menu.css` and
3190
+ `command.css`. Both keep their class as well, so `Menu` and `Command` are
3191
+ `.kbd .menu-key` and `.kbd .cmd-key` now: the declarations are the same, so
3192
+ nothing moves, and the context classes stay available for a rule that ever
3193
+ needs to tell the two apart. */
3194
+ .kbd {
3195
+ flex: none;
3196
+ font-family: var(--font-mono);
3197
+ font-size: var(--text-2xs);
3198
+ color: var(--muted);
3199
+ letter-spacing: var(--tracking);
3200
+ }
3201
+
3202
+ /* ---- ./stat.css ---- */
3203
+ /* A figure with furniture. `--space-1` between the three lines because they
3204
+ are one object read top to bottom, not three paragraphs. */
3205
+ .stat {
3206
+ display: grid;
3207
+ gap: var(--space-1);
3208
+ padding: var(--space-4);
3209
+ border: var(--border-width) solid var(--border);
3210
+ border-radius: var(--radius-md);
3211
+ background: var(--panel);
3212
+ }
3213
+
3214
+ /* Inside something already bordered. A bordered tile in a bordered row is two
3215
+ boxes saying one thing. */
3216
+ .stat-bare {
3217
+ padding: 0;
3218
+ border: 0;
3219
+ border-radius: 0;
3220
+ background: none;
3221
+ gap: 0;
3222
+ line-height: 1.25;
3223
+ }
3224
+
3225
+ .stat > p { margin: 0; }
3226
+
3227
+ .stat-label {
3228
+ color: var(--muted);
3229
+ font-size: var(--text-xs);
3230
+ }
3231
+
3232
+ /* Tabular figures are the point: a column of numbers is compared by its
3233
+ digits' positions, and proportional ones move them per row. */
3234
+ .stat-value {
3235
+ font-size: var(--text-lg);
3236
+ font-weight: var(--weight-strong);
3237
+ font-variant-numeric: tabular-nums;
3238
+ }
3239
+
3240
+ .stat-bare .stat-value { font-size: var(--text-sm); }
3241
+
3242
+ .stat-note {
3243
+ color: var(--muted);
3244
+ font-size: var(--text-xs);
3245
+ }
3246
+
3247
+ /* Only the figure takes the colour. Colouring the label too makes the tile a
3248
+ status box, and a tone here is a remark about the number. */
3249
+ .stat[data-tone='info'] .stat-value { color: var(--info); }
3250
+ .stat[data-tone='good'] .stat-value { color: var(--good); }
3251
+ .stat[data-tone='warn'] .stat-value { color: var(--warn); }
3252
+ .stat[data-tone='bad'] .stat-value { color: var(--bad); }
3253
+
3150
3254
  /* ---- ./scrollarea.css ---- */
3151
3255
  /* A box that scrolls, with its edges drawn.
3152
3256
 
package/dist/tf.css CHANGED
@@ -363,7 +363,28 @@ body::before {
363
363
  where the flat grey reads as recessed rather than as something to use. It is
364
364
  derived rather than declared -- a new token would have to be added to every
365
365
  theme in `themes.ts`, and a theme that missed it would lose its controls. */
366
+ /* An anchor drawn as a button. Three things the element brings that a
367
+ `<button>` does not, and all three have to go: the underline, the link
368
+ colour, and the text alignment a block anchor inherits. `cursor: pointer`
369
+ it already has. Disabled is `aria-disabled` here -- an anchor ignores the
370
+ native attribute -- so every `:disabled` rule above has an
371
+ `[aria-disabled='true']` twin rather than a rewrite, which leaves each
372
+ `button` selector at the specificity it had and every committed baseline
373
+ untouched. */
374
+ a.btn {
375
+ text-decoration: none;
376
+ color: var(--text);
377
+ text-align: center;
378
+ }
379
+
380
+ a.btn[aria-disabled='true'] {
381
+ /* A disabled anchor still takes the pointer, so say so. The click itself is
382
+ blocked in the capture phase by the component. */
383
+ cursor: not-allowed;
384
+ }
385
+
366
386
  button,
387
+ a.btn,
367
388
  input,
368
389
  textarea,
369
390
  select {
@@ -387,7 +408,8 @@ select {
387
408
  the icon; the button simply had no opinion about how to arrange two things.
388
409
  `inline-flex` and a gap gives it one, and the gap replaces the space
389
410
  character people were putting between an icon and its label. */
390
- button {
411
+ button,
412
+ a.btn {
391
413
  display: inline-flex;
392
414
  align-items: center;
393
415
  justify-content: center;
@@ -413,7 +435,8 @@ button[aria-pressed='true']:hover:not(:disabled) { border-color: var(--accent);
413
435
 
414
436
  /* The glyph never shrinks: in a narrow row flexbox would take it from the icon
415
437
  before the text, and half an icon is not a smaller icon. */
416
- button > svg { flex: none; }
438
+ button > svg,
439
+ a.btn > svg { flex: none; }
417
440
 
418
441
  .size-sm { font-size: var(--text-xs); padding: var(--space-1) var(--space-2); }
419
442
 
@@ -439,6 +462,7 @@ input, textarea, select { width: 100%; }
439
462
  textarea { resize: none; }
440
463
 
441
464
  button:hover:not(:disabled),
465
+ a.btn:hover:not([aria-disabled='true']),
442
466
  input:hover:not(:disabled),
443
467
  textarea:hover:not(:disabled),
444
468
  select:hover:not(:disabled) { border-color: var(--accent); }
@@ -447,6 +471,7 @@ select:hover:not(:disabled) { border-color: var(--accent); }
447
471
  `:focus` on the fields because a focused field is a place you are typing and
448
472
  should say so however you got there. */
449
473
  button:focus-visible,
474
+ a.btn:focus-visible,
450
475
  input:focus,
451
476
  textarea:focus,
452
477
  select:focus { outline: none; border-color: var(--accent); }
@@ -540,11 +565,13 @@ input[type='checkbox']:disabled,
540
565
  input[type='radio']:disabled { cursor: not-allowed; background: var(--panel-2); }
541
566
 
542
567
  button:disabled,
568
+ a.btn[aria-disabled='true'],
543
569
  input:disabled,
544
570
  textarea:disabled,
545
571
  select:disabled { opacity: 0.45; cursor: not-allowed; }
546
572
 
547
- button.primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
573
+ button.primary,
574
+ a.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
548
575
 
549
576
  /* A disabled primary is not a faded primary.
550
577
  `opacity: .45` was the whole of it, and a coloured fill at 45% is still a
@@ -552,7 +579,8 @@ button.primary { background: var(--accent); border-color: var(--accent); color:
552
579
  thing on the panel. That got worse when onboarding started holding people at
553
580
  a disabled Next. So it gives up the fill entirely and becomes the shape of a
554
581
  disabled control -- the opacity then has nothing left to do. */
555
- button.primary:disabled {
582
+ button.primary:disabled,
583
+ a.btn.primary[aria-disabled='true'] {
556
584
  background: var(--panel-2);
557
585
  border-color: var(--border);
558
586
  color: var(--muted);
@@ -622,13 +650,15 @@ button[aria-busy='true']::after {
622
650
 
623
651
  /* Quiet: no border, no fill. For the action beside the action -- Cancel next to
624
652
  Save -- where a bordered box competes with the thing it is next to. */
625
- button.ghost {
653
+ button.ghost,
654
+ a.btn.ghost {
626
655
  background: transparent;
627
656
  border-color: transparent;
628
657
  color: var(--muted);
629
658
  }
630
659
 
631
- button.ghost:hover:not(:disabled) {
660
+ button.ghost:hover:not(:disabled),
661
+ a.btn.ghost:hover:not([aria-disabled='true']) {
632
662
  background: var(--panel-2);
633
663
  border-color: transparent;
634
664
  color: var(--text);
@@ -835,19 +865,22 @@ button.ghost:hover:not(:disabled) {
835
865
  /* `:where(button)` so this carries no specificity of its own: a component's
836
866
  press rule below -- a card, a tab, a rail item, all of them buttons --
837
867
  wins by coming later, instead of every one having to restate `button`. */
838
- :where(button):active:not(:disabled) {
868
+ :where(button):active:not(:disabled),
869
+ :where(a.btn):active:not([aria-disabled='true']) {
839
870
  background: color-mix(in srgb, var(--text) var(--press-ink), var(--control));
840
871
  border-color: var(--accent);
841
872
  transform: scale(var(--press-scale));
842
873
  transition: none;
843
874
  }
844
875
 
845
- button.primary:active:not(:disabled) {
876
+ button.primary:active:not(:disabled),
877
+ a.btn.primary:active:not([aria-disabled='true']) {
846
878
  background: color-mix(in srgb, var(--text) var(--press-ink), var(--accent));
847
879
  border-color: color-mix(in srgb, var(--text) var(--press-ink), var(--accent));
848
880
  }
849
881
 
850
- button.ghost:active:not(:disabled) {
882
+ button.ghost:active:not(:disabled),
883
+ a.btn.ghost:active:not([aria-disabled='true']) {
851
884
  background: color-mix(in srgb, var(--text) var(--press-ink), var(--panel-2));
852
885
  border-color: transparent;
853
886
  }
@@ -1070,7 +1103,8 @@ input:active, textarea:active, select:active { transform: none; }
1070
1103
  /* Full width, for the one action a card or a step is about. Not a size: a
1071
1104
  `block` button is the same height as any other, it just stops being a thing
1072
1105
  you have to aim at. */
1073
- button.block { display: flex; width: 100%; }
1106
+ button.block,
1107
+ a.btn.block { display: flex; width: 100%; }
1074
1108
 
1075
1109
  /* The default is `size-md`, spelled once for every control.
1076
1110
  The paragraph above promised one scale for buttons, inputs and selects, and
@@ -1079,6 +1113,7 @@ button.block { display: flex; width: 100%; }
1079
1113
  could line up. The download modal's search box against its Search button was
1080
1114
  the version you could see from across the room. */
1081
1115
  button,
1116
+ a.btn,
1082
1117
  input,
1083
1118
  textarea,
1084
1119
  select,
@@ -1229,18 +1264,21 @@ select,
1229
1264
 
1230
1265
  /* ---- ./dangerzone.css ---- */
1231
1266
  /* Destructive, and legible as such standing still. */
1232
- button.danger {
1267
+ button.danger,
1268
+ a.btn.danger {
1233
1269
  color: var(--bad);
1234
1270
  border-color: color-mix(in srgb, var(--bad) 45%, var(--border-strong));
1235
1271
  }
1236
1272
 
1237
- button.danger:hover:not(:disabled) {
1273
+ button.danger:hover:not(:disabled),
1274
+ a.btn.danger:hover:not([aria-disabled='true']) {
1238
1275
  background: color-mix(in srgb, var(--bad) 12%, var(--panel));
1239
1276
  border-color: var(--bad);
1240
1277
  color: var(--bad);
1241
1278
  }
1242
1279
 
1243
- button.danger:active:not(:disabled) {
1280
+ button.danger:active:not(:disabled),
1281
+ a.btn.danger:active:not([aria-disabled='true']) {
1244
1282
  background: color-mix(in srgb, var(--bad) 20%, var(--panel));
1245
1283
  border-color: var(--bad);
1246
1284
  }
@@ -3417,6 +3455,72 @@ input[type='range'].slider:disabled::-moz-range-thumb { opacity: 0; }
3417
3455
  anchored surfaces (`.pop`, `.menu-sheet`, `.cmd`) sit over everything and a
3418
3456
  rule of equal specificity that came earlier would lose to whatever the
3419
3457
  sheets they cover happen to set. */
3458
+ /* ---- ./kbd.css ---- */
3459
+ /* One rule where there were two identical ones, in `menu.css` and
3460
+ `command.css`. Both keep their class as well, so `Menu` and `Command` are
3461
+ `.kbd .menu-key` and `.kbd .cmd-key` now: the declarations are the same, so
3462
+ nothing moves, and the context classes stay available for a rule that ever
3463
+ needs to tell the two apart. */
3464
+ .kbd {
3465
+ flex: none;
3466
+ font-family: var(--font-mono);
3467
+ font-size: var(--text-2xs);
3468
+ color: var(--muted);
3469
+ letter-spacing: var(--tracking);
3470
+ }
3471
+
3472
+ /* ---- ./stat.css ---- */
3473
+ /* A figure with furniture. `--space-1` between the three lines because they
3474
+ are one object read top to bottom, not three paragraphs. */
3475
+ .stat {
3476
+ display: grid;
3477
+ gap: var(--space-1);
3478
+ padding: var(--space-4);
3479
+ border: var(--border-width) solid var(--border);
3480
+ border-radius: var(--radius-md);
3481
+ background: var(--panel);
3482
+ }
3483
+
3484
+ /* Inside something already bordered. A bordered tile in a bordered row is two
3485
+ boxes saying one thing. */
3486
+ .stat-bare {
3487
+ padding: 0;
3488
+ border: 0;
3489
+ border-radius: 0;
3490
+ background: none;
3491
+ gap: 0;
3492
+ line-height: 1.25;
3493
+ }
3494
+
3495
+ .stat > p { margin: 0; }
3496
+
3497
+ .stat-label {
3498
+ color: var(--muted);
3499
+ font-size: var(--text-xs);
3500
+ }
3501
+
3502
+ /* Tabular figures are the point: a column of numbers is compared by its
3503
+ digits' positions, and proportional ones move them per row. */
3504
+ .stat-value {
3505
+ font-size: var(--text-lg);
3506
+ font-weight: var(--weight-strong);
3507
+ font-variant-numeric: tabular-nums;
3508
+ }
3509
+
3510
+ .stat-bare .stat-value { font-size: var(--text-sm); }
3511
+
3512
+ .stat-note {
3513
+ color: var(--muted);
3514
+ font-size: var(--text-xs);
3515
+ }
3516
+
3517
+ /* Only the figure takes the colour. Colouring the label too makes the tile a
3518
+ status box, and a tone here is a remark about the number. */
3519
+ .stat[data-tone='info'] .stat-value { color: var(--info); }
3520
+ .stat[data-tone='good'] .stat-value { color: var(--good); }
3521
+ .stat[data-tone='warn'] .stat-value { color: var(--warn); }
3522
+ .stat[data-tone='bad'] .stat-value { color: var(--bad); }
3523
+
3420
3524
  /* ---- ./scrollarea.css ---- */
3421
3525
  /* A box that scrolls, with its edges drawn.
3422
3526