@ponchia/ui 0.5.0 → 0.6.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 (117) hide show
  1. package/CHANGELOG.md +322 -0
  2. package/MIGRATIONS.json +14 -0
  3. package/README.md +28 -5
  4. package/annotations/index.d.ts +398 -276
  5. package/annotations/index.d.ts.map +1 -0
  6. package/annotations/index.js +315 -45
  7. package/behaviors/carousel.js +17 -16
  8. package/behaviors/combobox.js +47 -16
  9. package/behaviors/command.js +18 -15
  10. package/behaviors/connectors.js +4 -5
  11. package/behaviors/crosshair.js +4 -5
  12. package/behaviors/dialog.js +3 -2
  13. package/behaviors/disclosure.js +3 -2
  14. package/behaviors/dismissible.js +3 -2
  15. package/behaviors/forms.js +41 -13
  16. package/behaviors/glyph.js +4 -5
  17. package/behaviors/internal.js +47 -0
  18. package/behaviors/legend.js +23 -2
  19. package/behaviors/menu.js +3 -2
  20. package/behaviors/popover.js +78 -7
  21. package/behaviors/spotlight.js +4 -5
  22. package/behaviors/table.js +39 -12
  23. package/behaviors/tabs.js +14 -14
  24. package/behaviors/theme.js +5 -3
  25. package/behaviors/toast.js +13 -1
  26. package/classes/classes.json +1857 -0
  27. package/classes/index.d.ts +28 -13
  28. package/classes/index.js +34 -18
  29. package/classes/vscode.css-custom-data.json +12 -0
  30. package/connectors/index.d.ts +189 -69
  31. package/connectors/index.d.ts.map +1 -0
  32. package/connectors/index.js +120 -24
  33. package/css/app.css +43 -13
  34. package/css/base.css +15 -10
  35. package/css/connectors.css +17 -0
  36. package/css/content.css +7 -1
  37. package/css/dataviz.css +5 -1
  38. package/css/disclosure.css +38 -6
  39. package/css/dots.css +57 -0
  40. package/css/feedback.css +60 -2
  41. package/css/forms.css +42 -1
  42. package/css/legend.css +11 -7
  43. package/css/marks.css +38 -8
  44. package/css/motion.css +24 -44
  45. package/css/navigation.css +7 -0
  46. package/css/overlay.css +31 -1
  47. package/css/primitives.css +91 -5
  48. package/css/report.css +40 -63
  49. package/css/site.css +16 -2
  50. package/css/sources.css +43 -1
  51. package/css/spotlight.css +1 -1
  52. package/css/tokens.css +36 -1
  53. package/css/workbench.css +1 -1
  54. package/dist/bronto.css +1 -1
  55. package/dist/css/analytical.css +1 -1
  56. package/dist/css/app.css +1 -1
  57. package/dist/css/base.css +1 -1
  58. package/dist/css/connectors.css +1 -1
  59. package/dist/css/content.css +1 -1
  60. package/dist/css/disclosure.css +1 -1
  61. package/dist/css/dots.css +1 -1
  62. package/dist/css/feedback.css +1 -1
  63. package/dist/css/forms.css +1 -1
  64. package/dist/css/legend.css +1 -1
  65. package/dist/css/marks.css +1 -1
  66. package/dist/css/motion.css +1 -1
  67. package/dist/css/navigation.css +1 -1
  68. package/dist/css/overlay.css +1 -1
  69. package/dist/css/primitives.css +1 -1
  70. package/dist/css/report.css +1 -1
  71. package/dist/css/site.css +1 -1
  72. package/dist/css/sources.css +1 -1
  73. package/dist/css/spotlight.css +1 -1
  74. package/dist/css/tokens.css +1 -1
  75. package/dist/css/workbench.css +1 -1
  76. package/docs/adr/0003-theme-model.md +1 -1
  77. package/docs/annotations.md +94 -14
  78. package/docs/architecture.md +50 -6
  79. package/docs/contrast.md +116 -92
  80. package/docs/d2.md +195 -0
  81. package/docs/legends.md +18 -2
  82. package/docs/marks.md +9 -2
  83. package/docs/mermaid.md +152 -0
  84. package/docs/reference.md +78 -22
  85. package/docs/reporting.md +395 -57
  86. package/docs/sources.md +27 -0
  87. package/docs/stability.md +9 -2
  88. package/docs/usage.md +101 -4
  89. package/docs/vega.md +225 -0
  90. package/docs/workbench.md +7 -1
  91. package/glyphs/glyphs.js +6 -4
  92. package/llms.txt +139 -14
  93. package/package.json +50 -12
  94. package/qwik/index.d.ts +42 -59
  95. package/qwik/index.d.ts.map +1 -0
  96. package/qwik/index.js +55 -3
  97. package/react/index.d.ts +39 -61
  98. package/react/index.d.ts.map +1 -0
  99. package/react/index.js +57 -3
  100. package/solid/index.d.ts +64 -61
  101. package/solid/index.d.ts.map +1 -0
  102. package/solid/index.js +60 -3
  103. package/tokens/d2.d.ts +38 -0
  104. package/tokens/d2.js +71 -0
  105. package/tokens/d2.json +43 -0
  106. package/tokens/index.d.ts +5 -5
  107. package/tokens/index.js +15 -1
  108. package/tokens/index.json +9 -0
  109. package/tokens/mermaid.d.ts +23 -0
  110. package/tokens/mermaid.js +181 -0
  111. package/tokens/mermaid.json +163 -0
  112. package/tokens/resolved.json +45 -1
  113. package/tokens/skins.js +3 -2
  114. package/tokens/tokens.dtcg.json +26 -0
  115. package/tokens/vega.d.ts +34 -0
  116. package/tokens/vega.js +155 -0
  117. package/tokens/vega.json +179 -0
package/docs/marks.md CHANGED
@@ -44,6 +44,13 @@ Put `.ui-mark` on a `<mark>` so the emphasis is semantic, not just visual.
44
44
  `prefers-reduced-motion` (reduced motion shows the resting full highlight). It
45
45
  applies to the highlight fill, so pair it with the default (no style modifier).
46
46
 
47
+ > **A mark is a behind-text highlight, not a filled chip.** The fill is a
48
+ > low-alpha gradient *behind* the running text, so the text keeps its normal ink
49
+ > and the contrast stays text-on-background — even `ui-mark--accent` is
50
+ > contrast-safe by construction. Don't reach for `--on-accent` here (that ink is
51
+ > for a *solid* accent fill, like a button or a D2 node); a `<mark>` never needs
52
+ > it.
53
+
47
54
  ## Passage bracket — `.ui-bracket-note`
48
55
 
49
56
  Brackets a whole block and optionally labels it — the prose analogue of
@@ -56,8 +63,8 @@ Brackets a whole block and optionally labels it — the prose analogue of
56
63
  </blockquote>
57
64
  ```
58
65
 
59
- Tones: `--accent` (the rationed accent), `--warning`, `--danger`, `--info`. The
60
- default is a neutral bracket.
66
+ Tones: `--accent` (the rationed accent), `--success`, `--warning`, `--danger`,
67
+ `--info`. The default is a neutral bracket.
61
68
 
62
69
  ## Recipes
63
70
 
@@ -0,0 +1,152 @@
1
+ # Mermaid
2
+
3
+ [Mermaid](https://mermaid.js.org) renders diagrams (flowcharts, sequence, pie,
4
+ git, gantt…) from text to **SVG**. `@ponchia/ui` does not render diagrams — it
5
+ **themes** the ones you already have and lets you **annotate** them, the same way
6
+ it dresses any other SVG figure in a report. Two things ship:
7
+
8
+ - `@ponchia/ui/mermaid` — a resolved Mermaid `base` theme, per bronto theme.
9
+ - `@ponchia/ui/mermaid.json` — the same data as plain JSON, for any consumer.
10
+
11
+ Mermaid stays the consumer's renderer. This is config only: bronto never imports
12
+ or runs Mermaid, and Mermaid is **not** a dependency.
13
+
14
+ ## Theme a diagram
15
+
16
+ Mermaid's `base` theme is the only one meant to be customized. Hand it the
17
+ bronto theme variables:
18
+
19
+ ```js
20
+ import mermaid from 'mermaid';
21
+ import { brontoMermaidTheme } from '@ponchia/ui/mermaid';
22
+
23
+ mermaid.initialize(brontoMermaidTheme()); // light
24
+ await mermaid.run();
25
+ ```
26
+
27
+ `brontoMermaidTheme(theme)` returns `{ theme: 'base', themeVariables }` ready to
28
+ spread into `initialize`. Pass `'dark'` for the dark palette, or read the active
29
+ bronto theme:
30
+
31
+ ```js
32
+ const theme = document.documentElement.dataset.theme === 'dark' ? 'dark' : 'light';
33
+ mermaid.initialize(brontoMermaidTheme(theme));
34
+ ```
35
+
36
+ You can also splice the variables into a single diagram via an init directive,
37
+ or read the raw maps (`import { mermaid } from '@ponchia/ui/mermaid'` →
38
+ `{ light, dark }`). For a build step or non-JS host, read
39
+ `@ponchia/ui/mermaid.json` directly.
40
+
41
+ > **file:// portability.** A report opened straight from disk (`file://`) cannot
42
+ > `import` the `@ponchia/ui/mermaid` module **nor** `fetch('…/mermaid.json')` —
43
+ > the browser blocks both across the `null`/file origin (CORS), exactly as with
44
+ > [Vega](./vega.md#from-a-cdn-no-bundler). So for a double-clickable or PDF-bound
45
+ > report either **inline the theme variables** (paste the object for your theme
46
+ > from `mermaid.json` into the init directive) or, better, **pre-render to a
47
+ > frozen SVG** with the Mermaid CLI (`mmdc`, below) so there is no runtime at
48
+ > all. Over an `http(s)` origin the `import`/`fetch` forms both work.
49
+
50
+ The result is monochrome surfaces and lines with the rationed accent reserved
51
+ for notes — a diagram that looks like the rest of a bronto surface and
52
+ **re-skins for free** when you change `--accent`, exactly like the chart palette.
53
+
54
+ ### Why resolved colours, not `var(--x)`
55
+
56
+ Mermaid's theming engine derives shades (lighten/darken) from your seed colours,
57
+ so it only understands real colours — a `var(--accent)` string breaks
58
+ derivation. The theme map therefore ships **resolved hex/rgba per theme**,
59
+ projected from the same token source that feeds
60
+ [`tokens/resolved.json`](./architecture.md) and `charts.json`. That projection
61
+ is the bridge a CSS-first system needs until Mermaid can read CSS variables
62
+ directly. It also means the theme is **static per theme**: on a light/dark
63
+ switch, re-`initialize` with the other palette and re-render.
64
+
65
+ ### Which diagrams get the palette
66
+
67
+ - **Chart-like** diagrams carry a categorical series palette — **pie**
68
+ (`pie1`…`pie12`), **git** (`git0`…`git7`), and **user-journey**
69
+ (`fillType0`…`fillType7`) are wired to the CVD-safe
70
+ [charts palette](./legends.md) (series 1 = the live accent).
71
+ - **Structural** diagrams — flowchart, sequence, class, ER, state — use the
72
+ monochrome node/edge/cluster grammar and spend the accent only on notes.
73
+ - **Not themed: `gantt` and `timeline`.** Their colours come from
74
+ diagram-specific slots (`taskBkgColor`, `sectionBkgColor*`, `gridColor`,
75
+ `todayLineColor`, …) that the base `themeVariables` map does **not** set, so a
76
+ gantt/timeline renders with Mermaid's own off-brand defaults (red/grey bars),
77
+ not the bronto palette. For a **report timeline**, prefer the native,
78
+ fully-themed [`ui-timeline`](./reporting.md) primitive (it also prints and
79
+ needs no renderer); reach for a Mermaid gantt only when you specifically need
80
+ its scheduling layout, and accept its default colours.
81
+
82
+ Pie wedge labels (`pieSectionTextColor`) sit on arbitrary palette colours; if a
83
+ label is hard to read on a given wedge, prefer a legend or direct labels over
84
+ recolouring.
85
+
86
+ ### Fit to small screens
87
+
88
+ The theme map sets colours, not size — sizing stays Mermaid's. Keep `useMaxWidth`
89
+ on (the default for most diagram types) so each SVG scales to its container
90
+ instead of forcing page-wide horizontal scroll:
91
+
92
+ ```js
93
+ mermaid.initialize({
94
+ ...brontoMermaidTheme(theme),
95
+ flowchart: { useMaxWidth: true },
96
+ sequence: { useMaxWidth: true },
97
+ });
98
+ ```
99
+
100
+ A genuinely wide diagram (a long flowchart, a big ER) can still be unreadable
101
+ once squeezed onto a phone. Rather than let it overflow the page, wrap the render
102
+ in a scroll container so the *diagram* scrolls, not the document — the same
103
+ pattern the report layer uses for wide figures and tables:
104
+
105
+ ```css
106
+ .diagram-scroll {
107
+ overflow-x: auto;
108
+ }
109
+ ```
110
+
111
+ ## Annotate a diagram
112
+
113
+ Mermaid output is SVG, and the [annotation layer](./annotations.md) is
114
+ renderer-agnostic SVG — so a `<g class="ui-annotation">` callout composes onto a
115
+ rendered diagram the same as onto any figure. bronto supplies the geometry and
116
+ the styling; **placing a callout on a specific node is yours**, because that
117
+ means reading Mermaid's laid-out coordinates, which bronto deliberately does not
118
+ own (no scales, no DOM, no hit-testing — see [annotations.md](./annotations.md)).
119
+
120
+ The robust path is **build-time**, mirroring the
121
+ [static-report recipe](./annotations.md#using-the-helpers-in-a-static-no-js-report):
122
+
123
+ 1. Pre-render the diagram to a frozen SVG with the Mermaid CLI
124
+ (`mmdc -t base -i diagram.mmd -o diagram.svg`, feeding the same
125
+ `themeVariables`).
126
+ 2. From that SVG, read the target node's box (`getBBox()` / the node's
127
+ `transform`), accounting for the diagram's root `<g>` translate and the
128
+ `viewBox`.
129
+ 3. Compute the callout strings with `@ponchia/ui/annotations` and paste a
130
+ `<g class="ui-annotation …">` into the SVG at those coordinates.
131
+
132
+ The output is a static, on-brand, annotated SVG with no runtime — ideal for the
133
+ [report layer](./reporting.md).
134
+
135
+ To annotate a **live** client render instead, run the same measure-and-inject
136
+ pass on the SVG returned by `mermaid.render()`, after it is in the DOM. Two
137
+ honest caveats, both inherent to overlaying a foreign renderer (not bronto
138
+ limitations):
139
+
140
+ - **Mermaid's internal SVG structure is not a public contract.** Node ids and
141
+ classes are undocumented and have changed across major versions. Match nodes
142
+ by your own author-supplied id substring, measure positions rather than
143
+ hard-coding them, and **pin your Mermaid version**.
144
+ - **Every re-render replaces the SVG**, discarding injected overlays. Re-apply
145
+ the annotation pass after each `render()` / theme switch / resize.
146
+
147
+ ## Scope
148
+
149
+ bronto owns the theme map (gated: every value resolves to a colour, both themes,
150
+ no `var()` leaks) and the annotation geometry. It does **not** own Mermaid's
151
+ rendering, its internal DOM, or its re-render lifecycle — those stay Mermaid's,
152
+ and the overlay above is a documented composition, not a shipped runtime binding.
package/docs/reference.md CHANGED
@@ -9,8 +9,11 @@ rendering of every class is the kitchen-sink demo:
9
9
  **<https://ponchia.github.io/bronto-ui/>**. Theming knobs and the token
10
10
  contract: [docs/theming.md](theming.md).
11
11
 
12
- - 474 classes across 148 component groups
12
+ - 477 classes across 149 component groups
13
13
  - Import the typed registry: `import { cls, ui, cx } from '@ponchia/ui/classes'`
14
+ - Validate markup as data (no JS/TS): `@ponchia/ui/classes.json` — the same
15
+ vocabulary as language-neutral JSON (`groups`, `classes`, `states`,
16
+ `customProperties`), for an external linter or non-JS host
14
17
  - Tokens as data: `import { cssVars, tokens, themeColor } from '@ponchia/ui/tokens'`
15
18
 
16
19
  ## Classes
@@ -162,7 +165,6 @@ each one matches a real selector in the stylesheet.
162
165
  | `cls.appRailAccount` | `ui-app-rail__account` | part |
163
166
  | `cls.appRailBrand` | `ui-app-rail__brand` | part |
164
167
  | `cls.appRailFoot` | `ui-app-rail__foot` | part |
165
- | `cls.appRailToggle` | `ui-app-rail__toggle` | part |
166
168
 
167
169
  ### `.ui-app-shell`
168
170
 
@@ -221,6 +223,7 @@ each one matches a real selector in the stylesheet.
221
223
  | `cls.bracketNoteAccent` | `ui-bracket-note--accent` | modifier |
222
224
  | `cls.bracketNoteDanger` | `ui-bracket-note--danger` | modifier |
223
225
  | `cls.bracketNoteInfo` | `ui-bracket-note--info` | modifier |
226
+ | `cls.bracketNoteSuccess` | `ui-bracket-note--success` | modifier |
224
227
  | `cls.bracketNoteWarning` | `ui-bracket-note--warning` | modifier |
225
228
 
226
229
  ### `.ui-breadcrumb`
@@ -289,19 +292,6 @@ each one matches a real selector in the stylesheet.
289
292
  | --- | --- | --- |
290
293
  | `cls.center` | `ui-center` | base |
291
294
 
292
- ### `.ui-chart`
293
-
294
- | Registry key | Class | Kind |
295
- | --- | --- | --- |
296
- | `cls.chart` | `ui-chart` | base |
297
- | `cls.chartBar` | `ui-chart__bar` | part |
298
- | `cls.chartCaption` | `ui-chart__caption` | part |
299
- | `cls.chartFallback` | `ui-chart__fallback` | part |
300
- | `cls.chartFill` | `ui-chart__fill` | part |
301
- | `cls.chartLabel` | `ui-chart__label` | part |
302
- | `cls.chartPlot` | `ui-chart__plot` | part |
303
- | `cls.chartTrack` | `ui-chart__track` | part |
304
-
305
295
  ### `.ui-check`
306
296
 
307
297
  | Registry key | Class | Kind |
@@ -352,6 +342,15 @@ each one matches a real selector in the stylesheet.
352
342
  | `cls.commandMeta` | `ui-command__meta` | part |
353
343
  | `cls.commandShortcut` | `ui-command__shortcut` | part |
354
344
 
345
+ ### `.ui-compare`
346
+
347
+ | Registry key | Class | Kind |
348
+ | --- | --- | --- |
349
+ | `cls.compare` | `ui-compare` | base |
350
+ | `cls.compareCol` | `ui-compare__col` | part |
351
+ | `cls.compareHead` | `ui-compare__head` | part |
352
+ | `cls.compare2up` | `ui-compare--2up` | modifier |
353
+
355
354
  ### `.ui-connector`
356
355
 
357
356
  | Registry key | Class | Kind |
@@ -393,6 +392,16 @@ each one matches a real selector in the stylesheet.
393
392
  | `cls.crosshairLineY` | `ui-crosshair__line--y` | modifier |
394
393
  | `cls.crosshairMuted` | `ui-crosshair--muted` | modifier |
395
394
 
395
+ ### `.ui-delta`
396
+
397
+ | Registry key | Class | Kind |
398
+ | --- | --- | --- |
399
+ | `cls.delta` | `ui-delta` | base |
400
+ | `cls.deltaDown` | `ui-delta--down` | modifier |
401
+ | `cls.deltaFlat` | `ui-delta--flat` | modifier |
402
+ | `cls.deltaInvert` | `ui-delta--invert` | modifier |
403
+ | `cls.deltaUp` | `ui-delta--up` | modifier |
404
+
396
405
  ### `.ui-display`
397
406
 
398
407
  | Registry key | Class | Kind |
@@ -556,7 +565,7 @@ each one matches a real selector in the stylesheet.
556
565
  | --- | --- | --- |
557
566
  | `cls.inspector` | `ui-inspector` | base |
558
567
  | `cls.inspectorBody` | `ui-inspector__body` | part |
559
- | `cls.inspectorHeader` | `ui-inspector__header` | part |
568
+ | `cls.inspectorHead` | `ui-inspector__head` | part |
560
569
 
561
570
  ### `.ui-kbd`
562
571
 
@@ -682,6 +691,7 @@ each one matches a real selector in the stylesheet.
682
691
  | `cls.meterFill` | `ui-meter__fill` | part |
683
692
  | `cls.meterAccent` | `ui-meter--accent` | modifier |
684
693
  | `cls.meterDanger` | `ui-meter--danger` | modifier |
694
+ | `cls.meterInfo` | `ui-meter--info` | modifier |
685
695
  | `cls.meterSuccess` | `ui-meter--success` | modifier |
686
696
  | `cls.meterWarning` | `ui-meter--warning` | modifier |
687
697
 
@@ -840,7 +850,7 @@ each one matches a real selector in the stylesheet.
840
850
  | `cls.reportFigure` | `ui-report__figure` | part |
841
851
  | `cls.reportFinding` | `ui-report__finding` | part |
842
852
  | `cls.reportFootnotes` | `ui-report__footnotes` | part |
843
- | `cls.reportHeader` | `ui-report__header` | part |
853
+ | `cls.reportHead` | `ui-report__head` | part |
844
854
  | `cls.reportMeta` | `ui-report__meta` | part |
845
855
  | `cls.reportSection` | `ui-report__section` | part |
846
856
  | `cls.reportSectionUnnumbered` | `ui-report__section--unnumbered` | modifier |
@@ -1003,6 +1013,7 @@ each one matches a real selector in the stylesheet.
1003
1013
 
1004
1014
  | Registry key | Class | Kind |
1005
1015
  | --- | --- | --- |
1016
+ | `cls.src` | `ui-src` | base |
1006
1017
  | `cls.srcConflict` | `ui-src--conflict` | modifier |
1007
1018
  | `cls.srcGenerated` | `ui-src--generated` | modifier |
1008
1019
  | `cls.srcReviewed` | `ui-src--reviewed` | modifier |
@@ -1244,11 +1255,19 @@ registry consumer should reach for these instead of re-implementing
1244
1255
  | Class | Where | Effect |
1245
1256
  | --- | --- | --- |
1246
1257
  | `.ui-table .is-num` | numeric `<td>`/`<th>` | tabular figures + end-aligned (the canonical numeric cell) |
1247
- | `.ui-table .is-pos` | numeric `<td>` | positive-delta tone |
1248
- | `.ui-table .is-neg` | numeric `<td>` | negative-delta tone |
1258
+ | `.ui-table .is-pos` | numeric `<td>`, `.ui-stat__delta` | positive-delta tone |
1259
+ | `.ui-table .is-neg` | numeric `<td>`, `.ui-stat__delta` | negative-delta tone |
1260
+ | `.ui-table .is-key` | `<td>`/`<th>` | emphasised key column |
1249
1261
 
1250
1262
  For numeric text *outside* a table, use the `ui-num` primitive
1251
- (`ui.num({ tone })`), which carries the same tabular/aligned/tone intent.
1263
+ (`ui.num({ tone })`), which carries the same tabular/aligned/tone intent; for
1264
+ a trend figure use `ui-delta` (`ui.delta({ dir, invert })`). The full,
1265
+ machine-readable list of these `is-*` state hooks — and the author-set inline
1266
+ custom properties (`--chart-color`, `--chart-pattern`, `--value`, and the
1267
+ **required** `--icon-mask` on `.ui-icon` and `--ui-vt-name` on `.ui-vt` —
1268
+ without which those classes render a solid square / do nothing) — is in
1269
+ [`@ponchia/ui/classes.json`](../classes/classes.json)
1270
+ (`states` / `customProperties`).
1252
1271
 
1253
1272
  ## Composition & state (read before re-implementing glue)
1254
1273
 
@@ -1270,12 +1289,45 @@ works in any framework without a binding layer:
1270
1289
  - **Modal** — native `<dialog>` gets backdrop + top-layer + focus-trap
1271
1290
  free. For a controlled/portal modal, add `is-open`
1272
1291
  (`ui.modal({ open: true })`) for the same skin/layout; the
1273
- backdrop and focus-trap are then yours.
1292
+ backdrop, top-layer stacking AND focus-trap are then yours (`.is-open`
1293
+ is a bare grid — it does not float or stack on its own).
1294
+ - **Current page** — mark the active link with `aria-current="page"`; it is
1295
+ the programmatic cue the navs honour (`ui-sitenav`, `ui-app-nav`). The
1296
+ `.is-active` class is the visual-only equivalent on `ui-app-nav`/`ui-tab`;
1297
+ prefer `aria-current` so assistive tech announces the current page.
1298
+ - **Form validation wiring** — `initFormValidation` (`@ponchia/ui/behaviors`)
1299
+ reads these attributes; they ARE the contract, not styling. Markup that omits
1300
+ them renders but the behavior silently no-ops: `data-bronto-validate` on the
1301
+ `<form>`; an optional empty `[data-bronto-error]` node per field (it falls
1302
+ back to the field's `.ui-hint`, restoring the help text when valid again); a
1303
+ `[data-bronto-error-summary]` (`.ui-error-summary`) block. The combobox
1304
+ reads `[data-bronto-combobox]` + per-option `data-value` and emits
1305
+ `bronto:change` (`{ detail: { value } }`) on selection; the interactive
1306
+ legend emits `bronto:legend:toggle` (`{ detail: { series, active } }`).
1307
+ - **Status indicator** — `ui-status` carries no dot of its own: compose it with
1308
+ a `.ui-dot` child + a text label, e.g.
1309
+ `<span class="ui-status"><span class="ui-dot ui-dot--success"></span> Live</span>`.
1310
+ (`ui-state` instead bakes in its own dot + the full tone vocabulary — pick
1311
+ one.) A semantic `ui-dot--success|warning|danger|info` is colour-only outside
1312
+ forced-colors, so it ALWAYS needs an adjacent text/aria label — never ship a
1313
+ bare coloured dot as the sole signal.
1314
+ - **Opt-in component CSS** — a few classes are not in the core bundle and need
1315
+ their leaf imported, or they render unstyled: `ui-property`/`ui-readout` →
1316
+ `@ponchia/ui/css/workbench.css`; `ui-mark`/`ui-bracket-note` →
1317
+ `@ponchia/ui/css/marks.css`; the analytical leaves (`ui-annotations`,
1318
+ `ui-crosshair`, `ui-spotlight`, …) → their matching leaf.
1319
+ - **Loaders need their children** — `ui-dotspinner` requires exactly eight
1320
+ `<i>` children, `ui-dotloader` three `<span>`, and a static `ui-dotbar`
1321
+ lights a segment with `<i class="is-on">`. A childless
1322
+ `<span class="ui-dotspinner">` renders nothing.
1323
+ - **`ui-caret` is a typing cursor**, not a dropdown chevron — a blinking block
1324
+ caret (driven by `initDotGlyph`/`uiBlink`). For a disclosure/affordance
1325
+ arrow use `ui-link--arrow` (`ui.link({ arrow: true })`).
1274
1326
 
1275
1327
  ## Tokens
1276
1328
 
1277
1329
  Exact mirror of the `:root` blocks in `css/tokens.css`
1278
- (`check-tokens` enforces parity). DTCG export:
1330
+ (`check-fresh` enforces parity). DTCG export:
1279
1331
  [`@ponchia/ui/tokens.dtcg.json`](../tokens/tokens.dtcg.json).
1280
1332
 
1281
1333
  ### Global (scales — shared by both themes)
@@ -1298,6 +1350,8 @@ Exact mirror of the `:root` blocks in `css/tokens.css`
1298
1350
  | `--sans` | `'Inter', 'SF Pro Text', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif` |
1299
1351
  | `--dot-font` | `'Doto', var(--mono)` |
1300
1352
  | `--display` | `var(--dot-font)` |
1353
+ | `--display-weight` | `700` |
1354
+ | `--display-weight-strong` | `800` |
1301
1355
  | `--text-2xs` | `0.68rem` |
1302
1356
  | `--text-xs` | `0.76rem` |
1303
1357
  | `--text-sm` | `0.86rem` |
@@ -1371,6 +1425,7 @@ Exact mirror of the `:root` blocks in `css/tokens.css`
1371
1425
  | `--accent-ramp-end` | `#ffffff` |
1372
1426
  | `--accent-strong` | `color-mix(in srgb, var(--accent) 83%, #000)` |
1373
1427
  | `--accent-text` | `var(--accent-strong)` |
1428
+ | `--on-accent` | `var(--button-text)` |
1374
1429
  | `--accent-soft` | `color-mix(in srgb, var(--accent) 10%, transparent)` |
1375
1430
  | `--success` | `#2f7d4f` |
1376
1431
  | `--success-soft` | `rgb(47, 125, 79, 0.12)` |
@@ -1408,6 +1463,7 @@ Exact mirror of the `:root` blocks in `css/tokens.css`
1408
1463
  | `--accent-ramp-end` | `#000000` |
1409
1464
  | `--accent-strong` | `color-mix(in srgb, var(--accent) 84%, #fff)` |
1410
1465
  | `--accent-text` | `var(--accent-strong)` |
1466
+ | `--on-accent` | `var(--button-text)` |
1411
1467
  | `--accent-soft` | `color-mix(in srgb, var(--accent) 14%, transparent)` |
1412
1468
  | `--success` | `#4ec27e` |
1413
1469
  | `--success-soft` | `rgb(78, 194, 126, 0.14)` |