@ponchia/ui 0.9.0 → 0.11.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 (98) hide show
  1. package/CHANGELOG.md +107 -4
  2. package/MIGRATIONS.json +127 -18
  3. package/README.md +17 -9
  4. package/behaviors/index.d.ts +0 -2
  5. package/behaviors/index.d.ts.map +1 -1
  6. package/behaviors/index.js +0 -2
  7. package/behaviors/popover.js +4 -4
  8. package/classes/classes.json +53 -9
  9. package/classes/index.d.ts +20 -3
  10. package/classes/index.js +33 -3
  11. package/classes/vscode.css-custom-data.json +10 -10
  12. package/css/annotations.css +2 -2
  13. package/css/app.css +55 -31
  14. package/css/base.css +10 -14
  15. package/css/command.css +4 -4
  16. package/css/content.css +23 -21
  17. package/css/disclosure.css +17 -17
  18. package/css/discussion.css +150 -0
  19. package/css/feedback.css +15 -15
  20. package/css/figure.css +6 -4
  21. package/css/forms.css +8 -7
  22. package/css/generated.css +19 -12
  23. package/css/legend.css +13 -5
  24. package/css/navigation.css +3 -3
  25. package/css/overlay.css +13 -29
  26. package/css/primitives.css +48 -28
  27. package/css/report.css +91 -53
  28. package/css/sources.css +1 -1
  29. package/css/state.css +95 -6
  30. package/css/table.css +3 -3
  31. package/css/tokens.css +10 -10
  32. package/css/workbench.css +21 -9
  33. package/dist/bronto.css +1 -1
  34. package/dist/css/analytical.css +1 -1
  35. package/dist/css/annotations.css +1 -1
  36. package/dist/css/app.css +1 -1
  37. package/dist/css/base.css +1 -1
  38. package/dist/css/command.css +1 -1
  39. package/dist/css/content.css +1 -1
  40. package/dist/css/disclosure.css +1 -1
  41. package/dist/css/discussion.css +1 -0
  42. package/dist/css/feedback.css +1 -1
  43. package/dist/css/figure.css +1 -1
  44. package/dist/css/forms.css +1 -1
  45. package/dist/css/generated.css +1 -1
  46. package/dist/css/legend.css +1 -1
  47. package/dist/css/navigation.css +1 -1
  48. package/dist/css/overlay.css +1 -1
  49. package/dist/css/primitives.css +1 -1
  50. package/dist/css/report-kit.css +1 -1
  51. package/dist/css/report.css +1 -1
  52. package/dist/css/sources.css +1 -1
  53. package/dist/css/state.css +1 -1
  54. package/dist/css/table.css +1 -1
  55. package/dist/css/tokens.css +1 -1
  56. package/dist/css/workbench.css +1 -1
  57. package/docs/adr/0004-prune-unused-adapters.md +5 -1
  58. package/docs/adr/0005-productive-tools-and-editorial-reports.md +58 -0
  59. package/docs/adr/0006-trusted-publishing.md +92 -0
  60. package/docs/architecture.md +16 -23
  61. package/docs/command.md +1 -2
  62. package/docs/compositions.md +131 -0
  63. package/docs/discussion.md +64 -0
  64. package/docs/figure.md +10 -1
  65. package/docs/frontier-primitives.md +1 -2
  66. package/docs/migrations/0.10-to-0.11.md +61 -0
  67. package/docs/migrations/0.9-to-0.10.md +47 -0
  68. package/docs/package-contract.md +16 -13
  69. package/docs/reference.md +47 -18
  70. package/docs/reporting.md +15 -9
  71. package/docs/stability.md +20 -55
  72. package/docs/state.md +47 -0
  73. package/docs/usage.md +18 -30
  74. package/llms.txt +7 -18
  75. package/package.json +18 -54
  76. package/tokens/figma.variables.json +20 -20
  77. package/tokens/index.js +10 -10
  78. package/tokens/index.json +20 -20
  79. package/tokens/resolved.json +10 -10
  80. package/tokens/tokens.dtcg.json +20 -20
  81. package/behaviors/modal.d.ts +0 -45
  82. package/behaviors/modal.d.ts.map +0 -1
  83. package/behaviors/modal.js +0 -373
  84. package/qwik/index.d.ts +0 -48
  85. package/qwik/index.d.ts.map +0 -1
  86. package/qwik/index.js +0 -227
  87. package/react/index.d.ts +0 -45
  88. package/react/index.d.ts.map +0 -1
  89. package/react/index.js +0 -165
  90. package/solid/index.d.ts +0 -75
  91. package/solid/index.d.ts.map +0 -1
  92. package/solid/index.js +0 -172
  93. package/svelte/index.d.ts +0 -114
  94. package/svelte/index.d.ts.map +0 -1
  95. package/svelte/index.js +0 -197
  96. package/vue/index.d.ts +0 -116
  97. package/vue/index.d.ts.map +0 -1
  98. package/vue/index.js +0 -266
@@ -6,6 +6,8 @@
6
6
  /* --- Layout composition --- */
7
7
 
8
8
  .ui-stack {
9
+ min-inline-size: 0;
10
+ grid-template-columns: minmax(0, 1fr);
9
11
  display: grid;
10
12
  gap: var(--stack-gap, var(--space-md));
11
13
  }
@@ -169,7 +171,7 @@
169
171
  .ui-app-metrics {
170
172
  display: grid;
171
173
  gap: var(--space-md);
172
- grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
174
+ grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr));
173
175
  }
174
176
 
175
177
  /* Inside an opt-in .ui-cq container, collapse to one column when the
@@ -201,27 +203,27 @@
201
203
  .ui-stat__label,
202
204
  .ui-app-metric__label {
203
205
  color: var(--text-dim);
204
- font-family: var(--mono);
206
+ font-family: var(--sans);
205
207
  font-size: var(--text-2xs);
206
- letter-spacing: var(--tracking-wide);
207
- text-transform: uppercase;
208
+ letter-spacing: 0;
209
+ text-transform: none;
208
210
  }
209
211
 
210
212
  .ui-stat__value,
211
213
  .ui-app-metric__value {
212
214
  color: var(--text);
213
- font-family: var(--display);
215
+ font-family: var(--sans);
214
216
  font-size: 1.9rem;
215
217
  font-variant-numeric: tabular-nums;
216
218
  font-weight: var(--display-weight-strong);
217
- letter-spacing: 0.02em;
219
+ letter-spacing: 0;
218
220
  line-height: 1.05;
219
221
  overflow-wrap: anywhere; /* break an unspaced ID/hash rather than overflow */
220
222
  }
221
223
 
222
224
  .ui-stat__delta,
223
225
  .ui-app-metric__delta {
224
- font-family: var(--mono);
226
+ font-family: var(--sans);
225
227
  font-size: var(--text-xs);
226
228
  }
227
229
 
@@ -329,18 +331,18 @@
329
331
  color: var(--success);
330
332
  }
331
333
 
332
- /* --- Eyebrow / section label — dot-matrix face --- */
334
+ /* --- Eyebrow / section label — supporting text --- */
333
335
 
334
336
  .ui-eyebrow {
335
337
  /* accent-strong, not accent: this is small bold text and must clear
336
338
  WCAG AA 4.5:1 on the soft/tinted surfaces eyebrows sit on too. */
337
339
  color: var(--accent-text);
338
- font-family: var(--display);
340
+ font-family: var(--sans);
339
341
  font-size: var(--text-xs);
340
342
  font-weight: 700;
341
- letter-spacing: var(--tracking-wide);
343
+ letter-spacing: 0;
342
344
  margin: 0;
343
- text-transform: uppercase;
345
+ text-transform: none;
344
346
  }
345
347
 
346
348
  .ui-eyebrow--muted {
@@ -363,17 +365,17 @@
363
365
  color: var(--button-text);
364
366
  cursor: pointer;
365
367
  display: inline-flex;
366
- font-family: var(--mono);
368
+ font-family: var(--sans);
367
369
  font-size: var(--text-sm);
368
370
  font-weight: 600;
369
371
  gap: 0.45rem;
370
372
  justify-content: center;
371
- letter-spacing: var(--tracking-wide);
373
+ letter-spacing: 0;
372
374
  line-height: 1;
373
375
  min-block-size: 2.4rem;
374
376
  min-inline-size: 2.4rem;
375
377
  padding: 0.66rem 1rem;
376
- text-transform: uppercase;
378
+ text-transform: none;
377
379
  transition:
378
380
  background-color var(--duration-fast) var(--ease-standard),
379
381
  border-color var(--duration-fast) var(--ease-standard),
@@ -554,14 +556,14 @@
554
556
  text-decoration: none;
555
557
  }
556
558
 
557
- /* CTA: the eyebrow-faced action link (accent · display · uppercase),
559
+ /* CTA: the accent action link with a directional cue,
558
560
  composed from the same tokens as .ui-eyebrow + the arrow glyph. */
559
561
  .ui-link--cta {
560
562
  color: var(--accent-text);
561
- font-family: var(--display);
563
+ font-family: var(--sans);
562
564
  font-weight: 700;
563
- letter-spacing: var(--tracking-wide);
564
- text-transform: uppercase;
565
+ letter-spacing: 0;
566
+ text-transform: none;
565
567
  }
566
568
 
567
569
  .ui-link--arrow::after,
@@ -603,14 +605,14 @@
603
605
  border-radius: var(--radius-sm);
604
606
  color: var(--text-soft);
605
607
  display: inline-flex;
606
- font-family: var(--mono);
608
+ font-family: var(--sans);
607
609
  font-size: var(--text-2xs);
608
610
  gap: 0.36rem;
609
- letter-spacing: var(--tracking-wide);
611
+ letter-spacing: 0;
610
612
  line-height: 1;
611
613
  min-block-size: 1.7rem;
612
614
  padding: 0.32rem 0.55rem;
613
- text-transform: uppercase;
615
+ text-transform: none;
614
616
  }
615
617
 
616
618
  .ui-chip--accent {
@@ -619,6 +621,24 @@
619
621
  border-color: var(--accent);
620
622
  }
621
623
 
624
+ /* Static labels in a pane header need less height than a clickable control. */
625
+ .ui-chip--dense {
626
+ min-block-size: 1.25rem;
627
+ padding: 0.15rem 0.4rem;
628
+ }
629
+
630
+ .ui-chip--dense:is(button, a, [role='button']) {
631
+ min-block-size: var(--tap-target-min);
632
+ min-inline-size: var(--tap-target-min);
633
+ }
634
+
635
+ @media (pointer: coarse) {
636
+ .ui-chip--dense:is(button, a, [role='button']) {
637
+ min-block-size: var(--tap-target);
638
+ min-inline-size: var(--tap-target);
639
+ }
640
+ }
641
+
622
642
  /* --- Badge / status pill --- */
623
643
 
624
644
  .ui-badge {
@@ -628,14 +648,14 @@
628
648
  border-radius: var(--radius-sm);
629
649
  color: var(--text-soft);
630
650
  display: inline-flex;
631
- font-family: var(--mono);
651
+ font-family: var(--sans);
632
652
  font-size: var(--text-2xs);
633
653
  font-weight: 700;
634
654
  gap: 0.34rem;
635
- letter-spacing: var(--tracking-wide);
655
+ letter-spacing: 0;
636
656
  line-height: 1;
637
657
  padding: 0.28rem 0.5rem;
638
- text-transform: uppercase;
658
+ text-transform: none;
639
659
  }
640
660
 
641
661
  /* Tone rides the border + tint; text stays the high-contrast neutral
@@ -726,17 +746,17 @@
726
746
 
727
747
  .ui-key-value dt {
728
748
  color: var(--text-dim);
729
- font-family: var(--mono);
749
+ font-family: var(--sans);
730
750
  font-size: var(--text-2xs);
731
751
  font-weight: 700;
732
- letter-spacing: var(--tracking-wide);
752
+ letter-spacing: 0;
733
753
  line-height: 1;
734
- text-transform: uppercase;
754
+ text-transform: none;
735
755
  }
736
756
 
737
757
  .ui-key-value dd {
738
758
  color: var(--text);
739
- font-family: var(--mono);
759
+ font-family: var(--sans);
740
760
  margin: 0;
741
761
  min-inline-size: 0;
742
762
  overflow-wrap: anywhere; /* IDs/hashes/paths are the common value — break, don't overflow */
package/css/report.css CHANGED
@@ -8,19 +8,32 @@
8
8
 
9
9
  .ui-report {
10
10
  /* Declare override-surface tokens first so authors can set them. */
11
- --report-width: 72rem;
11
+ --report-width: 64rem;
12
12
  --report-padding-block: var(--space-2xl);
13
- --report-gap: var(--space-lg);
14
- --report-measure: 74ch;
13
+ --report-gap: var(--space-xl);
14
+ --report-measure: 68ch;
15
15
 
16
16
  color: var(--text-soft);
17
17
  display: grid;
18
+ font-size: 1.125rem;
19
+ line-height: 1.65;
18
20
  gap: var(--report-gap);
19
21
  inline-size: min(100%, var(--report-width));
20
22
  margin-inline: auto;
21
23
  padding: var(--report-padding-block) var(--space-md);
22
24
  }
23
25
 
26
+ /* Keep reading measure independent of a wide figure or evidence table. */
27
+ .ui-report p,
28
+ .ui-report__section > :is(ul, ol, blockquote) {
29
+ max-inline-size: var(--report-measure);
30
+ overflow-wrap: anywhere;
31
+ }
32
+
33
+ .ui-report .ui-prose {
34
+ font-size: inherit;
35
+ }
36
+
24
37
  .ui-report--compact {
25
38
  --report-gap: var(--space-md);
26
39
  --report-padding-block: var(--space-xl);
@@ -74,14 +87,14 @@
74
87
 
75
88
  .ui-report__title {
76
89
  color: var(--text);
77
- font-family: var(--display);
78
- font-size: calc(var(--text-xl) * 1.35);
79
- font-weight: var(--display-weight-strong);
90
+ font-family: var(--sans);
91
+ font-size: clamp(2rem, 4vw, 3rem);
92
+ font-weight: 650;
80
93
  letter-spacing: 0;
81
- line-height: 1.05;
94
+ line-height: 1.15;
82
95
  margin: 0;
83
96
  max-inline-size: var(--report-measure);
84
- text-transform: uppercase;
97
+ text-transform: none;
85
98
  text-wrap: balance;
86
99
  }
87
100
 
@@ -98,14 +111,14 @@
98
111
  color: var(--text-dim);
99
112
  display: flex;
100
113
  flex-wrap: wrap;
101
- font-family: var(--mono);
102
- font-size: var(--text-2xs);
114
+ font-family: var(--sans);
115
+ font-size: var(--text-xs);
103
116
  gap: 0.55rem;
104
117
  letter-spacing: 0;
105
118
  list-style: none;
106
119
  margin: 0;
107
120
  padding: 0;
108
- text-transform: uppercase;
121
+ text-transform: none;
109
122
  }
110
123
 
111
124
  .ui-report__meta > * {
@@ -123,11 +136,22 @@
123
136
  }
124
137
 
125
138
  .ui-report__toc {
126
- border: 1px solid var(--line);
127
- border-radius: var(--radius-md);
139
+ border-block: 1px solid var(--line);
128
140
  display: grid;
129
141
  gap: var(--space-xs);
130
- padding: var(--space-md);
142
+ padding-block: var(--space-md);
143
+ }
144
+
145
+ .ui-report__toc > summary {
146
+ cursor: pointer;
147
+ font-size: var(--text-sm);
148
+ font-weight: 600;
149
+ min-block-size: var(--tap-target);
150
+ padding-block: var(--space-xs);
151
+ }
152
+
153
+ details.ui-report__toc:not([open]) > :not(summary) {
154
+ display: none;
131
155
  }
132
156
 
133
157
  .ui-report__toc ol,
@@ -162,7 +186,7 @@
162
186
 
163
187
  .ui-report__decision {
164
188
  background: var(--panel);
165
- border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--line));
189
+ border: 0;
166
190
  border-inline-start: 3px solid var(--accent);
167
191
  border-radius: var(--radius-md);
168
192
  display: grid;
@@ -172,22 +196,22 @@
172
196
 
173
197
  .ui-report__decision-kicker {
174
198
  color: var(--accent-text);
175
- font-family: var(--mono);
199
+ font-family: var(--sans);
176
200
  font-size: var(--text-2xs);
177
- letter-spacing: var(--tracking-wide);
201
+ letter-spacing: 0;
178
202
  margin: 0;
179
- text-transform: uppercase;
203
+ text-transform: none;
180
204
  }
181
205
 
182
206
  .ui-report__decision-title {
183
207
  color: var(--text);
184
- font-family: var(--display);
208
+ font-family: var(--sans);
185
209
  font-size: var(--text-lg);
186
210
  font-weight: var(--display-weight);
187
211
  letter-spacing: 0;
188
212
  line-height: 1.18;
189
213
  margin: 0;
190
- text-transform: uppercase;
214
+ text-transform: none;
191
215
  text-wrap: balance;
192
216
  }
193
217
 
@@ -202,13 +226,14 @@
202
226
  color: var(--text-dim);
203
227
  display: flex;
204
228
  flex-wrap: wrap;
205
- font-family: var(--mono);
229
+ font-family: var(--sans);
206
230
  font-size: var(--text-2xs);
207
231
  gap: 0.45rem 0.75rem;
208
232
  letter-spacing: 0;
209
233
  }
210
234
 
211
235
  .ui-report__decision-grid {
236
+ container: bronto-decision / inline-size;
212
237
  border-block-start: 1px solid var(--line);
213
238
  display: grid;
214
239
  gap: 0;
@@ -230,13 +255,14 @@
230
255
 
231
256
  .ui-report__decision-label {
232
257
  color: var(--text-dim);
233
- font-family: var(--mono);
258
+ font-family: var(--sans);
234
259
  font-size: var(--text-2xs);
235
- letter-spacing: var(--tracking-wide);
236
- text-transform: uppercase;
260
+ letter-spacing: 0;
261
+ text-transform: none;
237
262
  }
238
263
 
239
264
  .ui-report__decision-value {
265
+ overflow-wrap: anywhere;
240
266
  color: var(--text-soft);
241
267
  line-height: 1.5;
242
268
  }
@@ -346,10 +372,10 @@
346
372
  .ui-claim__scope,
347
373
  .ui-claim__refs {
348
374
  color: var(--text-dim);
349
- font-family: var(--mono);
375
+ font-family: var(--sans);
350
376
  font-size: var(--text-2xs);
351
377
  letter-spacing: 0;
352
- text-transform: uppercase;
378
+ text-transform: none;
353
379
  }
354
380
 
355
381
  .ui-claim__basis,
@@ -386,13 +412,13 @@
386
412
 
387
413
  .ui-report__section-head {
388
414
  color: var(--text);
389
- font-family: var(--display);
415
+ font-family: var(--sans);
390
416
  font-size: var(--text-xl);
391
- font-weight: var(--display-weight);
417
+ font-weight: 650;
392
418
  letter-spacing: 0;
393
419
  line-height: 1.1;
394
420
  margin: 0;
395
- text-transform: uppercase;
421
+ text-transform: none;
396
422
  text-wrap: balance;
397
423
  }
398
424
 
@@ -415,11 +441,11 @@
415
441
 
416
442
  .ui-report__caption {
417
443
  color: var(--text-dim);
418
- font-family: var(--mono);
444
+ font-family: var(--sans);
419
445
  font-size: var(--text-2xs);
420
446
  letter-spacing: 0;
421
447
  line-height: 1.5;
422
- text-transform: uppercase;
448
+ text-transform: none;
423
449
  }
424
450
 
425
451
  .ui-evidence-grid {
@@ -446,7 +472,7 @@
446
472
 
447
473
  .ui-evidence-item__meta {
448
474
  color: var(--text-dim);
449
- font-family: var(--mono);
475
+ font-family: var(--sans);
450
476
  font-size: var(--text-2xs);
451
477
  letter-spacing: 0;
452
478
  }
@@ -472,10 +498,10 @@
472
498
  .ui-evidence-item__window,
473
499
  .ui-evidence-item__source {
474
500
  color: var(--text-dim);
475
- font-family: var(--mono);
501
+ font-family: var(--sans);
476
502
  font-size: var(--text-2xs);
477
503
  letter-spacing: 0;
478
- text-transform: uppercase;
504
+ text-transform: none;
479
505
  }
480
506
 
481
507
  .ui-evidence-item__value {
@@ -496,6 +522,7 @@
496
522
  }
497
523
 
498
524
  .ui-report__actions {
525
+ container: bronto-actions / inline-size;
499
526
  border-block-start: 1px solid var(--line);
500
527
  display: grid;
501
528
  gap: 0;
@@ -516,14 +543,15 @@
516
543
 
517
544
  .ui-report__action-status {
518
545
  color: var(--text-dim);
519
- font-family: var(--mono);
546
+ font-family: var(--sans);
520
547
  font-size: var(--text-2xs);
521
548
  grid-column: 2;
522
549
  grid-row: 1;
523
- letter-spacing: var(--tracking-wide);
550
+ letter-spacing: 0;
524
551
  place-self: start end;
525
- text-transform: uppercase;
526
- white-space: nowrap;
552
+ text-transform: none;
553
+ overflow-wrap: anywhere;
554
+ white-space: normal;
527
555
  }
528
556
 
529
557
  .ui-report__action-title,
@@ -546,10 +574,10 @@
546
574
  .ui-report__action-priority,
547
575
  .ui-report__action-source {
548
576
  color: var(--text-dim);
549
- font-family: var(--mono);
577
+ font-family: var(--sans);
550
578
  font-size: var(--text-2xs);
551
579
  letter-spacing: 0;
552
- text-transform: uppercase;
580
+ text-transform: none;
553
581
  }
554
582
 
555
583
  .ui-report__action-criteria {
@@ -558,8 +586,13 @@
558
586
  line-height: 1.5;
559
587
  }
560
588
 
561
- @media (max-width: 32rem) {
562
- .ui-report__decision-item,
589
+ @container bronto-decision (max-width: 32rem) {
590
+ .ui-report__decision-item {
591
+ grid-template-columns: minmax(0, 1fr);
592
+ }
593
+ }
594
+
595
+ @container bronto-actions (max-width: 32rem) {
563
596
  .ui-report__action {
564
597
  grid-template-columns: 1fr;
565
598
  }
@@ -588,7 +621,7 @@
588
621
  a single stack on a narrow screen via auto-fit, so two panels never
589
622
  overflow. `ui-compare__col` is one side, `ui-compare__head` labels it.
590
623
  `ui-compare--2up` pins exactly two equal columns for a hard before/after
591
- pairing (still collapsing to one column on a phone). */
624
+ pairing, with a 16rem reading floor per column in any parent. */
592
625
  .ui-compare {
593
626
  display: grid;
594
627
  gap: var(--space-md);
@@ -596,13 +629,12 @@
596
629
  }
597
630
 
598
631
  .ui-compare--2up {
599
- grid-template-columns: repeat(2, minmax(0, 1fr));
600
- }
601
-
602
- @media (max-width: 33rem) {
603
- .ui-compare--2up {
604
- grid-template-columns: 1fr;
605
- }
632
+ /* At most two columns, each at least 16rem unless the whole parent is narrower.
633
+ Intrinsic wrapping also works outside a report or named query container. */
634
+ grid-template-columns: repeat(
635
+ auto-fit,
636
+ minmax(min(100%, max(16rem, (100% - var(--space-md)) / 2)), 1fr)
637
+ );
606
638
  }
607
639
 
608
640
  .ui-compare__col {
@@ -613,10 +645,10 @@
613
645
 
614
646
  .ui-compare__head {
615
647
  color: var(--text-dim);
616
- font-family: var(--mono);
648
+ font-family: var(--sans);
617
649
  font-size: var(--text-2xs);
618
- letter-spacing: var(--tracking-wide);
619
- text-transform: uppercase;
650
+ letter-spacing: 0;
651
+ text-transform: none;
620
652
  }
621
653
 
622
654
  /* A chart is NOT a bronto component — it needs scales + data binding, which the
@@ -660,9 +692,15 @@
660
692
  --line-strong: #b3b3b3;
661
693
 
662
694
  inline-size: auto;
695
+ font-size: 11pt;
663
696
  padding: 0;
664
697
  }
665
698
 
699
+ .ui-report__decision-grid,
700
+ .ui-report__actions {
701
+ container-type: normal;
702
+ }
703
+
666
704
  .ui-report__cover {
667
705
  min-block-size: auto;
668
706
  }
package/css/sources.css CHANGED
@@ -78,7 +78,7 @@
78
78
  .ui-citation {
79
79
  color: var(--accent-text);
80
80
  font-family: var(--mono);
81
- font-size: 0.72em;
81
+ font-size: max(0.72em, var(--text-2xs));
82
82
  font-weight: 600;
83
83
  text-decoration: none;
84
84
  vertical-align: super;
package/css/state.css CHANGED
@@ -262,29 +262,38 @@
262
262
  ========================================================================== */
263
263
 
264
264
  /* Declared once so a host putting the level on its own element gets the same
265
- mapping from `data-level` + `var(--severity-tone)`, without copying a table. */
265
+ mapping from `data-level` + `var(--severity-tone)`, without copying a table.
266
+
267
+ `.ui-severity-tone` is that host element's hook, and it paints nothing: the
268
+ three classes below all draw something — a chip, a ruled row, a background
269
+ dot — and a consumer whose mark Bronto does not ship needs the VALUE without
270
+ any of them. The case that proved it was an SVG `<circle>`, which ignores
271
+ `background` entirely, so a status strip had to restate the whole tier table
272
+ in `fill` and could then disagree with the rows beside it. */
266
273
  .ui-severity,
267
274
  .ui-severity-row,
268
- .ui-severity-dot {
275
+ .ui-severity-dot,
276
+ .ui-severity-tone,
277
+ .ui-timestrip__event {
269
278
  --severity-tone: var(--text-dim);
270
279
  }
271
280
 
272
- :is(.ui-severity, .ui-severity-row, .ui-severity-dot):is(
281
+ :is(.ui-severity, .ui-severity-row, .ui-severity-dot, .ui-severity-tone, .ui-timestrip__event):is(
273
282
  [data-level='critical'],
274
283
  [data-level='error']
275
284
  ) {
276
285
  --severity-tone: var(--danger);
277
286
  }
278
287
 
279
- :is(.ui-severity, .ui-severity-row, .ui-severity-dot)[data-level='warning'] {
288
+ :is(.ui-severity, .ui-severity-row, .ui-severity-dot, .ui-severity-tone, .ui-timestrip__event)[data-level='warning'] {
280
289
  --severity-tone: var(--warning);
281
290
  }
282
291
 
283
- :is(.ui-severity, .ui-severity-row, .ui-severity-dot)[data-level='notice'] {
292
+ :is(.ui-severity, .ui-severity-row, .ui-severity-dot, .ui-severity-tone, .ui-timestrip__event)[data-level='notice'] {
284
293
  --severity-tone: var(--info);
285
294
  }
286
295
 
287
- :is(.ui-severity, .ui-severity-row, .ui-severity-dot)[data-level='ok'] {
296
+ :is(.ui-severity, .ui-severity-row, .ui-severity-dot, .ui-severity-tone, .ui-timestrip__event)[data-level='ok'] {
288
297
  --severity-tone: var(--success);
289
298
  }
290
299
 
@@ -370,6 +379,86 @@
370
379
  font-size: var(--text-2xs);
371
380
  }
372
381
 
382
+ /* ==========================================================================
383
+ timestrip — WHEN the things in a list entered the state they are in.
384
+
385
+ A status list answers "what". This answers "when", on one axis, at a glance:
386
+ a cluster of marks at the leading edge is a fresh incident, a lone mark
387
+ pinned to the trailing edge has been wrong for a while. It is the companion
388
+ to `.ui-severity-row` and takes the same `data-level`, so a strip can never
389
+ disagree with the rows beneath it.
390
+
391
+ BOUNDARY — this is geometry, not a chart. The host owns the window, the
392
+ clock, and the arithmetic: it normalises each event to a position in 0..1 and
393
+ writes it as `--at`. Bronto owns the rail, the marker, and the mark. There
394
+ are no scales, no ticks, no axis labels and no time parsing here; a surface
395
+ that wanted those wants a chart, and Bronto refuses chart scales.
396
+
397
+ <div class="ui-timestrip" role="img" aria-label="…">
398
+ <span class="ui-timestrip__axis"></span>
399
+ <span class="ui-timestrip__now"></span>
400
+ <span class="ui-timestrip__event" data-level="critical" style="--at: .92"></span>
401
+ <span class="ui-timestrip__event" data-level="ok" data-outside style="--at: 0"></span>
402
+ </div>
403
+
404
+ `data-outside` is for an event older than the window. It stays at the edge at
405
+ reduced weight rather than vanishing, because a strip that reads "quiet"
406
+ while a row says "failing for three days" is worse than one that reads
407
+ crowded. The mark is not the state's only channel: the rows below name their
408
+ level in words, and the strip needs an `aria-label` naming what it plots.
409
+ ========================================================================== */
410
+
411
+ .ui-timestrip {
412
+ block-size: 1.4rem;
413
+ display: block;
414
+ inline-size: 100%;
415
+ position: relative;
416
+ }
417
+
418
+ /* The rail the marks sit on, and the edge that is "now". Both are decorative:
419
+ they carry no fact the label and the rows do not already carry. */
420
+ .ui-timestrip__axis {
421
+ background: var(--line);
422
+ block-size: 1px;
423
+ inset-block-end: 0.35rem;
424
+ inset-inline: 0;
425
+ position: absolute;
426
+ }
427
+
428
+ .ui-timestrip__now {
429
+ border-inline-end: 1px dashed var(--text-dim);
430
+ inset-block: 0.1rem 0.25rem;
431
+ inset-inline-end: 0;
432
+ position: absolute;
433
+ }
434
+
435
+ /* `--at` is the host's answer: 0 is the oldest edge of the window, 1 is now.
436
+ Clamped rather than trusted — an out-of-range value is a host bug, and a mark
437
+ drawn outside its own strip is harder to diagnose than one at the edge. */
438
+ .ui-timestrip__event {
439
+ background: var(--severity-tone);
440
+ block-size: 0.4rem;
441
+ border-radius: var(--radius-pill);
442
+ inline-size: 0.4rem;
443
+ inset-block-end: 0.55rem;
444
+ inset-inline-start: calc(clamp(0, var(--at, 0), 1) * 100%);
445
+ position: absolute;
446
+ translate: -50% 0;
447
+ }
448
+
449
+ .ui-timestrip__event[data-outside] {
450
+ opacity: 0.55;
451
+ }
452
+
453
+ /* Forced colours: the tone is replaced, so the marks stop distinguishing tiers.
454
+ They still say WHEN, which is the strip's whole job, and the level stays
455
+ readable in the rows. */
456
+ @media (forced-colors: active) {
457
+ .ui-timestrip__event {
458
+ background: CanvasText;
459
+ }
460
+ }
461
+
373
462
  /* Forced colours: the tone dot collapses to a system colour, so the
374
463
  author-written label remains the state channel (it already must be). */
375
464
  @media (forced-colors: active) {
package/css/table.css CHANGED
@@ -11,7 +11,7 @@
11
11
 
12
12
  .ui-table {
13
13
  border-collapse: collapse;
14
- font-family: var(--mono);
14
+ font-family: var(--sans);
15
15
  font-size: var(--text-sm);
16
16
  min-inline-size: 100%;
17
17
  inline-size: 100%;
@@ -32,9 +32,9 @@
32
32
  color: var(--text-dim);
33
33
  font-size: var(--text-2xs);
34
34
  font-weight: 700;
35
- letter-spacing: var(--tracking-wide);
35
+ letter-spacing: 0;
36
36
  position: sticky;
37
- text-transform: uppercase;
37
+ text-transform: none;
38
38
  inset-block-start: 0;
39
39
 
40
40
  /* Keep the sticky header above body cells — cheap insurance for the