@ponchia/ui 0.4.1 → 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 (153) hide show
  1. package/CHANGELOG.md +552 -8
  2. package/MIGRATIONS.json +106 -0
  3. package/README.md +34 -8
  4. package/annotations/index.d.ts +402 -0
  5. package/annotations/index.d.ts.map +1 -0
  6. package/annotations/index.js +792 -0
  7. package/behaviors/carousel.js +198 -0
  8. package/behaviors/combobox.js +226 -0
  9. package/behaviors/command.js +190 -0
  10. package/behaviors/connectors.js +95 -0
  11. package/behaviors/crosshair.js +57 -0
  12. package/behaviors/dialog.js +74 -0
  13. package/behaviors/disclosure.js +26 -0
  14. package/behaviors/dismissible.js +25 -0
  15. package/behaviors/forms.js +186 -0
  16. package/behaviors/glyph.js +108 -0
  17. package/behaviors/index.d.ts +79 -0
  18. package/behaviors/index.js +18 -1409
  19. package/behaviors/internal.js +97 -0
  20. package/behaviors/legend.js +67 -0
  21. package/behaviors/menu.js +47 -0
  22. package/behaviors/popover.js +179 -0
  23. package/behaviors/spotlight.js +52 -0
  24. package/behaviors/table.js +136 -0
  25. package/behaviors/tabs.js +103 -0
  26. package/behaviors/theme.js +84 -0
  27. package/behaviors/toast.js +164 -0
  28. package/classes/classes.json +1857 -0
  29. package/classes/index.d.ts +306 -13
  30. package/classes/index.js +339 -12
  31. package/classes/vscode.css-custom-data.json +12 -0
  32. package/connectors/index.d.ts +191 -0
  33. package/connectors/index.d.ts.map +1 -0
  34. package/connectors/index.js +275 -0
  35. package/css/analytical.css +21 -0
  36. package/css/annotations.css +292 -0
  37. package/css/app.css +43 -13
  38. package/css/base.css +15 -10
  39. package/css/command.css +97 -0
  40. package/css/connectors.css +110 -0
  41. package/css/content.css +7 -1
  42. package/css/crosshair.css +100 -0
  43. package/css/dataviz.css +5 -1
  44. package/css/disclosure.css +38 -6
  45. package/css/dots.css +57 -0
  46. package/css/feedback.css +111 -2
  47. package/css/fonts.css +11 -7
  48. package/css/forms.css +42 -1
  49. package/css/generated.css +117 -0
  50. package/css/legend.css +272 -0
  51. package/css/marks.css +174 -0
  52. package/css/motion.css +24 -44
  53. package/css/navigation.css +7 -0
  54. package/css/overlay.css +31 -1
  55. package/css/primitives.css +109 -5
  56. package/css/report.css +39 -81
  57. package/css/selection.css +46 -0
  58. package/css/site.css +16 -2
  59. package/css/sources.css +221 -0
  60. package/css/spotlight.css +104 -0
  61. package/css/state.css +121 -0
  62. package/css/tokens.css +60 -37
  63. package/css/workbench.css +83 -0
  64. package/dist/bronto.css +1 -1
  65. package/dist/css/analytical.css +1 -0
  66. package/dist/css/annotations.css +1 -0
  67. package/dist/css/app.css +1 -1
  68. package/dist/css/base.css +1 -1
  69. package/dist/css/command.css +1 -0
  70. package/dist/css/connectors.css +1 -0
  71. package/dist/css/content.css +1 -1
  72. package/dist/css/crosshair.css +1 -0
  73. package/dist/css/disclosure.css +1 -1
  74. package/dist/css/dots.css +1 -1
  75. package/dist/css/feedback.css +1 -1
  76. package/dist/css/fonts.css +1 -1
  77. package/dist/css/forms.css +1 -1
  78. package/dist/css/generated.css +1 -0
  79. package/dist/css/legend.css +1 -0
  80. package/dist/css/marks.css +1 -0
  81. package/dist/css/motion.css +1 -1
  82. package/dist/css/navigation.css +1 -1
  83. package/dist/css/overlay.css +1 -1
  84. package/dist/css/primitives.css +1 -1
  85. package/dist/css/report.css +1 -1
  86. package/dist/css/selection.css +1 -0
  87. package/dist/css/site.css +1 -1
  88. package/dist/css/sources.css +1 -0
  89. package/dist/css/spotlight.css +1 -0
  90. package/dist/css/state.css +1 -0
  91. package/dist/css/tokens.css +1 -1
  92. package/dist/css/workbench.css +1 -0
  93. package/docs/adr/0003-theme-model.md +7 -4
  94. package/docs/annotations.md +425 -0
  95. package/docs/architecture.md +246 -0
  96. package/docs/command.md +95 -0
  97. package/docs/connectors.md +91 -0
  98. package/docs/contrast.md +116 -92
  99. package/docs/crosshair.md +63 -0
  100. package/docs/d2.md +195 -0
  101. package/docs/generated.md +91 -0
  102. package/docs/legends.md +184 -0
  103. package/docs/marks.md +93 -0
  104. package/docs/mermaid.md +152 -0
  105. package/docs/reference.md +385 -23
  106. package/docs/reporting.md +436 -63
  107. package/docs/selection.md +40 -0
  108. package/docs/sources.md +137 -0
  109. package/docs/spotlight.md +78 -0
  110. package/docs/stability.md +24 -2
  111. package/docs/state.md +85 -0
  112. package/docs/usage.md +123 -4
  113. package/docs/vega.md +225 -0
  114. package/docs/workbench.md +78 -0
  115. package/fonts/doto-400.woff2 +0 -0
  116. package/fonts/doto-500.woff2 +0 -0
  117. package/fonts/doto-600.woff2 +0 -0
  118. package/fonts/doto-700.woff2 +0 -0
  119. package/fonts/doto-800.woff2 +0 -0
  120. package/fonts/doto-900.woff2 +0 -0
  121. package/glyphs/glyphs.js +6 -4
  122. package/llms.txt +362 -14
  123. package/package.json +115 -12
  124. package/qwik/index.d.ts +42 -54
  125. package/qwik/index.d.ts.map +1 -0
  126. package/qwik/index.js +75 -3
  127. package/react/index.d.ts +39 -56
  128. package/react/index.d.ts.map +1 -0
  129. package/react/index.js +67 -3
  130. package/solid/index.d.ts +64 -56
  131. package/solid/index.d.ts.map +1 -0
  132. package/solid/index.js +70 -3
  133. package/tokens/d2.d.ts +38 -0
  134. package/tokens/d2.js +71 -0
  135. package/tokens/d2.json +43 -0
  136. package/tokens/index.d.ts +5 -5
  137. package/tokens/index.js +23 -5
  138. package/tokens/index.json +9 -0
  139. package/tokens/mermaid.d.ts +23 -0
  140. package/tokens/mermaid.js +181 -0
  141. package/tokens/mermaid.json +163 -0
  142. package/tokens/resolved.json +45 -1
  143. package/tokens/skins.js +3 -2
  144. package/tokens/tokens.dtcg.json +26 -0
  145. package/tokens/vega.d.ts +34 -0
  146. package/tokens/vega.js +155 -0
  147. package/tokens/vega.json +179 -0
  148. package/fonts/doto-400.ttf +0 -0
  149. package/fonts/doto-500.ttf +0 -0
  150. package/fonts/doto-600.ttf +0 -0
  151. package/fonts/doto-700.ttf +0 -0
  152. package/fonts/doto-800.ttf +0 -0
  153. package/fonts/doto-900.ttf +0 -0
package/llms.txt CHANGED
@@ -16,8 +16,8 @@
16
16
  CSS (pick one; do not import both):
17
17
 
18
18
  ```css
19
- @import '@ponchia/ui'; /* dist/bronto.css — flattened, minified, one file (recommended) */
20
- @import '@ponchia/ui/css'; /* css/core.css — @import fan-out, needs a bundler */
19
+ @import '@ponchia/ui'; /* dist/bronto.css — flattened, minified, one file (recommended) */
20
+ @import '@ponchia/ui/css'; /* css/core.css — @import fan-out, needs a bundler */
21
21
  ```
22
22
 
23
23
  `import '@ponchia/ui'` is supported only as a CSS side-effect import in a
@@ -31,6 +31,23 @@ later layer) always win over framework styles regardless of selector
31
31
  specificity — this is the intended override mechanism; do not fight it
32
32
  with `!important`.
33
33
 
34
+ Loading a stylesheet — read before copying a `<link>` below. The opt-in
35
+ leaves are written as `@ponchia/ui/css/<leaf>.css` for brevity. That
36
+ package-specifier form resolves ONLY inside a CSS-aware bundler
37
+ (Vite/webpack); in a standalone `.html` file it does not resolve. For plain
38
+ HTML (the usual case when an LLM emits a report) use a real URL — and note
39
+ the path changes from source `css/` to built `dist/css/`:
40
+
41
+ ```html
42
+ <!-- installed locally -->
43
+ <link rel="stylesheet" href="./node_modules/@ponchia/ui/dist/css/<leaf>.css" />
44
+ <!-- or from a CDN; pin the version (pre-1.0, breaking changes ship in the minor) -->
45
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.0/dist/css/<leaf>.css" />
46
+ ```
47
+
48
+ The flattened default bundle is `dist/bronto.css` (bundler shorthand
49
+ `@ponchia/ui`). A complete, copy-pasteable CDN report is in `docs/reporting.md`.
50
+
34
51
  Typed class vocabulary (returns plain strings — works in any framework):
35
52
 
36
53
  ```js
@@ -69,12 +86,35 @@ import { renderGlyph, GLYPH_NAMES } from '@ponchia/ui/glyphs';
69
86
  el.innerHTML = renderGlyph('check', { label: 'Done' });
70
87
  ```
71
88
 
89
+ Layout primitives (core bundle, no media queries — intrinsic Every-Layout
90
+ composition that responds to content + available space): `ui-stack` (vertical
91
+ rhythm), `ui-cluster` (wrapping inline row), `ui-grid` (auto-fit columns),
92
+ `ui-sidebar` (sidebar + main that stacks when cramped), `ui-switcher` (row →
93
+ column together), `ui-center` (measure-bounded column), `ui-ratio` (aspect-ratio
94
+ box), and the `ui-app-shell`/`ui-app-rail`/`ui-app-nav` admin shell. Each is
95
+ tuned with an inline custom property rather than a modifier — set
96
+ `style="--grid-min: 12rem"`, `--sidebar-width`, `--switcher-min`, `--center-max`
97
+ (the INNER measure; gutters add to the total), `--ratio`, `--stack-gap`,
98
+ `--cluster-gap`, `--app-rail`, etc. The full list with defaults is in
99
+ `classes.json` `customProperties`. App-shell/sitenav current page is
100
+ `aria-current="page"`.
101
+
102
+ Motion utilities (core bundle, all reduced-motion-safe — they collapse to the
103
+ static end state, not just a zeroed duration): `ui-animate-in`,
104
+ `ui-animate-fade`, `ui-animate-dot`, `ui-animate-matrix` (enter animations),
105
+ `ui-stagger` (+ `--i` per child, or `ui-stagger--auto` to
106
+ derive the delay from `:nth-child`), `ui-reveal` (JS/IntersectionObserver — adds
107
+ `is-visible`), `ui-scroll-reveal` and `ui-scroll-progress` (zero-JS,
108
+ scroll-driven; the recommended reveal for static reports), and `ui-vt` (View
109
+ Transitions — needs the required `--ui-vt-name`). Prefer `ui-scroll-reveal` over
110
+ `ui-reveal` when no JS will run. Details: `docs/usage.md`.
111
+
72
112
  Optional display colorways — opt-in, never in the default bundle. Root-level,
73
113
  like `data-theme` (the derived accent family only recomputes at `:root`):
74
114
 
75
115
  ```html
76
116
  <link rel="stylesheet" href="@ponchia/ui/css/skins.css" />
77
- <html data-bronto-skin="amber-crt | phosphor-green | e-ink">
117
+ <html data-bronto-skin="amber-crt | phosphor-green | e-ink"></html>
78
118
  ```
79
119
 
80
120
  Each re-points the one `--accent` (OKLCH, per-theme, contrast-gated); status
@@ -92,11 +132,277 @@ import charts from '@ponchia/ui/charts.json' with { type: 'json' };
92
132
  // charts.dark.categorical → ['#ff3b41', …] (series 0 = the resolved accent)
93
133
  ```
94
134
 
135
+ On-brand Mermaid diagrams use the same tokens-as-data path — Mermaid is the
136
+ consumer's renderer, bronto just hands it a resolved `base` theme (Mermaid can't
137
+ read `var(--x)`):
138
+
139
+ ```js
140
+ import { brontoMermaidTheme } from '@ponchia/ui/mermaid';
141
+ mermaid.initialize(brontoMermaidTheme('dark')); // { theme: 'base', themeVariables }
142
+ ```
143
+
144
+ Annotate a rendered diagram with the SVG annotation layer as a build-time
145
+ recipe. Details: `docs/mermaid.md`.
146
+
147
+ D2 (d2lang.com) is themed the same way — it compiles to a frozen SVG, so the
148
+ slots take resolved hex; the base ramp is monochrome and the accent is opt-in
149
+ per node:
150
+
151
+ ```js
152
+ import { brontoD2Vars } from '@ponchia/ui/d2';
153
+ const source = brontoD2Vars() + 'a -> b'; // prepend the vars block, then render
154
+ ```
155
+
156
+ Details: `docs/d2.md`.
157
+
158
+ Charting is the same path: bronto does NOT ship a chart component (a chart needs
159
+ scales + data binding, which the analytical layer refuses). For charts, recommend
160
+ Vega-Lite — a declarative JSON spec an external system can emit — themed by the
161
+ on-brand `config` (resolved hex; Vega bakes colours into SVG/canvas, can't read
162
+ `var()`). `range.category` is the `--chart-*` palette, series 1 = accent:
163
+
164
+ ```js
165
+ import { brontoVegaConfig, brontoVegaAccent, brontoVegaNeutral } from '@ponchia/ui/vega';
166
+ vegaEmbed('#chart', spec, { config: brontoVegaConfig('dark'), renderer: 'svg', actions: false });
167
+ ```
168
+
169
+ Pass `renderer: 'svg'` (canvas is the wrong default for print/inspection).
170
+ `brontoVegaAccent(theme)`/`brontoVegaNeutral(theme)` give the exact hexes to spend
171
+ the accent on one mark. From a CDN, pin the `/build/*.min.js` UMD bundles (a bare
172
+ `vega@6` tag has no `window.vega`; keep Vega-Lite 6 / Vega 6 / vega-embed 7
173
+ aligned) and INLINE the config from `vega.json` — a
174
+ `file://` report can't `import`/`fetch` it (CORS). A label on an accent fill in a
175
+ foreign renderer (a themed Vega/D2/Mermaid node or bar) reads the `--on-accent`
176
+ token, never `--accent-text` (that is accent-coloured text for a neutral bg).
177
+ `--on-accent` is a READ-ONLY export for those renderers — no in-DOM `.ui-*` rule
178
+ consumes it, so setting it does not re-ink a component; to colour text on an
179
+ accent-filled DOM control, set `--button-text`. Details: `docs/vega.md`. (Observable
180
+ Plot works too — it inherits the page CSS, so it needs even less theming;
181
+ Vega-Lite is the recommended LLM-emittable path.)
182
+
95
183
  `--chart-1..8` (categorical; series 1 = accent; colourblind-safe, gated under
96
184
  simulated protan/deutan/tritan), `--chart-seq-*` (sequential), `--chart-div-*`
97
185
  (diverging), and `--chart-pattern-1..8` (dot-matrix fills — pair colour N with
98
186
  pattern N; colour is never the sole signal). Details in `docs/theming.md`.
99
187
 
188
+ Building analytical / generated-report UI? Import the roll-up
189
+ `@ponchia/ui/css/analytical.css` (bundles annotations + legend + marks +
190
+ connectors + spotlight + crosshair + selection) instead of the seven leaves;
191
+ add `css/dataviz.css` for chart colours and `css/report.css` for the document
192
+ grammar. The individual layers (each opt-in, none in the default bundle):
193
+
194
+ Optional SVG annotations for charts/reports — opt-in, never in the default
195
+ bundle. This is Bronto's subject / connector / note grammar inspired by
196
+ d3-annotation, not an authoring engine:
197
+
198
+ ```html
199
+ <link rel="stylesheet" href="@ponchia/ui/css/annotations.css" />
200
+ ```
201
+
202
+ ```js
203
+ import { annotationParts, connectorLine, circleSubjectPath } from '@ponchia/ui/annotations';
204
+ ```
205
+
206
+ Use `ui-annotation` groups inside SVG with `ui-annotation__subject`,
207
+ `ui-annotation__connector`, `ui-annotation__note`, `ui-annotation__title`, and
208
+ `ui-annotation__label`. `ui.annotation({ variant, tone, motion })` builds the
209
+ base class string. Variants cover labels, callouts, elbow/curve connectors,
210
+ circle/rect/threshold subjects, badges, brackets, bands, slopes, comparisons,
211
+ clusters, axis marks, timeline pins, and evidence markers. Motion is opt-in
212
+ (`draw`, `reveal`, `pulse`, `focus`) and respects reduced-motion preferences.
213
+ Use `notePlacement()` for one-note bounded placement, but do not treat it as a
214
+ whole-chart collision solver. `declutterLabels(items,{gap,min,max})` is a
215
+ deterministic 1-D declutter; `directLabels(items,{axis,cross,gap,min,max,shape})`
216
+ adds the leader line (it declutters labels along an axis and returns each placed
217
+ point plus a leader path `d` for `ui-annotation__connector`) — neither owns
218
+ scales, DOM, or 2-D placement. Status tones are only for status-bearing callouts.
219
+ Keep charts sparse; dense mobile figures need horizontal scrolling, a simplified
220
+ SVG, or complete caption/fallback text. Details: `docs/annotations.md`.
221
+
222
+ Optional legends / data keys for charts and figures — opt-in, never in the
223
+ default bundle. Reads the `--chart-*` tokens, so a key never drifts from its
224
+ series:
225
+
226
+ ```html
227
+ <link rel="stylesheet" href="@ponchia/ui/css/legend.css" />
228
+ ```
229
+
230
+ Use a `ui-legend` container with `ui-legend__item` rows, each holding a
231
+ `ui-legend__swatch` (decorative, `aria-hidden`) and a `ui-legend__label` (the
232
+ required non-colour channel — WCAG 1.4.1; colour alone never carries meaning).
233
+ Set the swatch colour inline (`style="--chart-color: var(--chart-3)"`, plus
234
+ `--chart-pattern` to match a patterned mark) or with a `ui-legend__swatch--1..8`
235
+ index helper. Variants: `ui-legend--vertical`/`--compact`/`--with-values`,
236
+ `ui-legend--gradient` (+`--diverging`, with `ui-legend__track`/`__ticks`/`__tick`),
237
+ and `ui-legend--threshold`. `ui.legend()`/`ui.legendItem()`/`ui.legendSwatch()`
238
+ build the class strings. Interactive (series-toggling) legends are opt-in:
239
+ author entries as `<button aria-pressed>` under `[data-bronto-legend]`, run
240
+ `initLegend()` (or `useLegend()`), and listen for `bronto:legend:toggle`
241
+ (`{ series, active }`) — Bronto flips the control state; you hide the series and
242
+ own the `aria-live` announcement. Details: `docs/legends.md`.
243
+
244
+ Optional text marks / evidence emphasis for running prose — opt-in, never in
245
+ the default bundle. The prose counterpart to annotations (annotations call out a
246
+ figure; marks call out a sentence):
247
+
248
+ ```html
249
+ <link rel="stylesheet" href="@ponchia/ui/css/marks.css" />
250
+ ```
251
+
252
+ Put `ui-mark` on a `<mark>` for inline emphasis (semantic, not just visual).
253
+ Styles: default highlight, `ui-mark--underline`, `ui-mark--box`,
254
+ `ui-mark--strike`. Tones: `ui-mark--accent` (the rationed accent),
255
+ `--success`/`--warning`/`--danger`/`--info` (status-bearing only), `--muted`.
256
+ `ui-mark--draw` sweeps the highlight in (reduced-motion-safe). `ui-bracket-note`
257
+ (+ `ui-bracket-note__label`, tones `--accent`/`--warning`/`--danger`/`--info`)
258
+ brackets a whole passage — the prose analogue of `ui-annotation--bracket`.
259
+ `ui.mark({ style, tone, motion })` / `ui.bracketNote({ tone })` build the class
260
+ strings. A mark is visual only; if the emphasis carries meaning the words don't,
261
+ state it in the text (WCAG 1.4.1). Details: `docs/marks.md`.
262
+
263
+ Optional connectors / leader lines between two DOM elements — opt-in, never in
264
+ the default bundle. Pure geometry + an optional draw/track behavior; owns no
265
+ layout:
266
+
267
+ ```html
268
+ <link rel="stylesheet" href="@ponchia/ui/css/connectors.css" />
269
+ ```
270
+
271
+ Place a `ui-connector` SVG (`data-bronto-connector`, `aria-hidden`) as an
272
+ overlay inside a `position: relative` container holding both endpoints; set
273
+ `data-from`/`data-to` (element ids), optional `data-shape`
274
+ (straight|elbow|curve), `data-from-side`/`data-to-side`, and `data-end`
275
+ (arrow|dot|none). `initConnectors()` (or `useConnectors()`) draws the path and
276
+ redraws on resize/scroll. Tones `ui-connector--accent`/`--muted`/status,
277
+ `ui-connector--dashed`, `ui-connector--draw`. Pure helpers from
278
+ `@ponchia/ui/connectors` (`connectRects`, `connectorPath`, `arrowHead`,
279
+ `anchorPoint`, …) return SVG strings for SSR/canvas. Details: `docs/connectors.md`.
280
+
281
+ Optional spotlight / guided-focus overlay — opt-in, never in the default
282
+ bundle. The visual language of a tour, NOT a tour engine (the host owns step
283
+ order/advancing/visibility):
284
+
285
+ ```html
286
+ <link rel="stylesheet" href="@ponchia/ui/css/spotlight.css" />
287
+ ```
288
+
289
+ A `ui-spotlight` overlay (`data-bronto-spotlight`, `data-target=<element id>`)
290
+ contains a `ui-spotlight__hole` (the box-shadow cutout) and a `ui-tour-note`
291
+ callout (`__step`/`__title`/`__body`/`__actions`). `initSpotlight()` (or
292
+ `useSpotlight()`) measures the target and sets `--spot-x/y/w/h`, re-placing on
293
+ resize/scroll and when `data-target` changes — so advance a tour by updating
294
+ `data-target`. `ui-spotlight--ring` adds a ring. The overlay is non-blocking by
295
+ design; put the real guidance text in the focusable `ui-tour-note`. Details:
296
+ `docs/spotlight.md`.
297
+
298
+ Optional crosshair / readout for reading a value off a plot — opt-in, never in
299
+ the default bundle. Reports the pointer position; the host maps it to data:
300
+
301
+ ```html
302
+ <link rel="stylesheet" href="@ponchia/ui/css/crosshair.css" />
303
+ ```
304
+
305
+ Mark the plot `[data-bronto-crosshair]` (position: relative) and put a
306
+ `ui-crosshair` overlay inside it with `ui-crosshair__line ui-crosshair__line--x`
307
+ and/or `--y`, optional `ui-crosshair__badge`, and a `ui-readout` chip.
308
+ `initCrosshair()` (or `useCrosshair()`) sets `--crosshair-x/y` (px) on pointer
309
+ move, toggles `is-active`, and dispatches `bronto:crosshair:move`
310
+ ({ x, y, fx, fy } — px + 0..1 fractions) / `bronto:crosshair:leave`. It does NOT
311
+ find the nearest datum or map pixels→data (that needs your scales). `ui.crosshair({ muted })`.
312
+ Details: `docs/crosshair.md`.
313
+
314
+ Optional selection-state vocabulary — opt-in, cross-cutting, CSS only. The carve
315
+ from brush/lasso: Bronto does not do region selection/hit-testing; it ships only
316
+ the states an item can be in:
317
+
318
+ ```html
319
+ <link rel="stylesheet" href="@ponchia/ui/css/selection.css" />
320
+ ```
321
+
322
+ Apply `ui-sel` + `ui-sel--on` (selected), `ui-sel--off` (excluded), or
323
+ `ui-sel--maybe` (live-brush candidate) to any data element (chart mark, table
324
+ row, list item, map region) from YOUR selection/brush logic — Bronto only styles
325
+ them. `ui.sel({ state: 'on'|'off'|'maybe' })`. Details: `docs/selection.md`.
326
+
327
+ Optional source/citation/provenance trust layer — opt-in, CSS only, never in
328
+ the default bundle. The grammar for "where did this come from?" in generated
329
+ reports/AI output:
330
+
331
+ ```html
332
+ <link rel="stylesheet" href="@ponchia/ui/css/sources.css" />
333
+ ```
334
+
335
+ `ui-citation` (inline ref on a real `<a>`/`<button>`; `--chip` = named-source
336
+ pill), `ui-source-card` (+`__title`/`__origin`/`__time`/`__excerpt`/`__actions`;
337
+ the body part is `__excerpt`, not `__detail`), `ui-source-list` (+`__item`),
338
+ `ui-provenance` (+`__item`), and `ui-src` (a standalone trust pill). A
339
+ cross-cutting trust state sets the tone: `ui-src--verified`/`--reviewed`/
340
+ `--generated`/`--unverified`/`--stale`/`--conflict` — always paired with an
341
+ author-written label (never colour alone). A tone class **needs a host**:
342
+ `ui-src--verified` on its own renders nothing — put it on `ui-src`,
343
+ `ui-citation`, `ui-source-card`, or `ui-provenance__item`. Bronto styles +
344
+ states; the host owns fetching, numbering, and trust. `ui.citation({chip,state})` / `ui.source({state})` /
345
+ `ui.provenance({state})`. Details: `docs/sources.md`.
346
+
347
+ Optional lifecycle/system-state vocabulary — opt-in, CSS only, never in the
348
+ default bundle. The states apps live in (saving/saved/queued/offline/stale/
349
+ conflict/error/locked/reviewed/needs-review):
350
+
351
+ ```html
352
+ <link rel="stylesheet" href="@ponchia/ui/css/state.css" />
353
+ ```
354
+
355
+ `ui-state` (+`__label`/`__detail`) carries a tone dot + the canonical label;
356
+ the `ui-state--saving`/`--saved`/… modifier bakes the tone, `ui-state--busy`
357
+ pulses the indicator for
358
+ in-progress states (reduced-motion-safe). `ui-syncbar` is a page/document
359
+ save-status strip. The label IS the state (never colour alone); the host owns
360
+ the state machine, retry, and persistence — persistent state gets persistent UI,
361
+ not a toast. `ui.state({ state, busy })`. Details: `docs/state.md`.
362
+
363
+ Optional generated-content / AI-trust surfaces — opt-in, CSS only, never in the
364
+ default bundle. NOT a chat kit; the trust surfaces around generated content:
365
+
366
+ ```html
367
+ <link rel="stylesheet" href="@ponchia/ui/css/generated.css" />
368
+ ```
369
+
370
+ `ui-generated` (+`__label`) marks a machine-authored region; `ui-origin-label`
371
+ (+`--ai`) tags origin ("AI generated" / "Human reviewed"); `ui-reasoning`
372
+ (+`__body`) and `ui-tool-log` / `ui-tool-call` (+`__name`/`__status`/`__body`)
373
+ are quiet native-`<details>` collapsibles for reasoning + tool traces. Bronto
374
+ styles disclosure/origin/trace; the host owns model metadata, redaction, and
375
+ safety. No confidence/verdict widget (don't fabricate precision). `ui.originLabel({ ai })`.
376
+ Details: `docs/generated.md`.
377
+
378
+ Optional workbench primitives for tool UIs — opt-in, CSS only, never in the
379
+ default bundle:
380
+
381
+ ```html
382
+ <link rel="stylesheet" href="@ponchia/ui/css/workbench.css" />
383
+ ```
384
+
385
+ `ui-inspector` (+`__header`/`__body`) is a selected-object detail panel;
386
+ `ui-property` (+`__label`/`__value`) is a denser key/value row for it;
387
+ `ui-selectionbar` (+`__count`/`__actions`) is a raised action bar for the current
388
+ selection (pair with `ui-sel` states on the items). Layout/affordances only —
389
+ resizable split panes and drag handles are deferred. Class-only. Details:
390
+ `docs/workbench.md`.
391
+
392
+ Optional command palette — opt-in CSS shell (`css/command.css`) + `initCommand`
393
+ behavior. Filter + keyboard-navigate a DOM-authored command list:
394
+
395
+ ```html
396
+ <link rel="stylesheet" href="@ponchia/ui/css/command.css" />
397
+ ```
398
+
399
+ `ui-command` (+`__input`/`__list`/`__group`/`__item`/`__shortcut`/`__meta`/
400
+ `__empty`); `initCommand()` owns filtering, roving focus (Down/Up/Home/End),
401
+ Enter→`bronto:command:select` ({value,label}) and Escape→`bronto:command:close`.
402
+ The HOST owns the action registry + execution; NO global Cmd/Ctrl+K (open it
403
+ yourself, e.g. a <dialog> via initDialog). Pairs with `ui-shortcut`. Binding:
404
+ `useCommand()` (react/solid/qwik). Details: `docs/command.md`.
405
+
100
406
  Optional static report layer for LLM-authored HTML reports — opt-in, never in
101
407
  the default bundle. Pair it with the normal bundle, and add data-viz only when
102
408
  the report contains charts. For standalone browser HTML, use real URLs; package
@@ -119,7 +425,10 @@ Canonical report skeleton:
119
425
  <p class="ui-eyebrow">Report</p>
120
426
  <h1 class="ui-report__title">System review</h1>
121
427
  <p class="ui-report__subtitle">Static HTML, Chromium PDF-ready.</p>
122
- <ol class="ui-report__meta"><li>2026-06-01</li><li>Generated</li></ol>
428
+ <ol class="ui-report__meta">
429
+ <li>2026-06-01</li>
430
+ <li>Generated</li>
431
+ </ol>
123
432
  </header>
124
433
  <section class="ui-report__section">
125
434
  <h2 class="ui-report__section-head">Executive summary</h2>
@@ -133,10 +442,18 @@ Canonical report skeleton:
133
442
  Report rules for agents: static output by default; do not initialize behaviors
134
443
  over untrusted generated content; sanitize arbitrary LLM/CMS/user HTML before
135
444
  rendering; use semantic headings; give tables captions and header cells; give
136
- charts captions, legends/direct labels, and fallback data; use
137
- `ui-chart__plot`/`ui-chart__bar`/`ui-chart__fill` for simple static bar charts;
138
- use `ui-report__section--unnumbered` for appendices in numbered reports; never
139
- use raw chromatic inline colors. Full cookbook: `docs/reporting.md`.
445
+ charts captions, legends/direct labels, and fallback data; for a chart, theme
446
+ Vega-Lite with `@ponchia/ui/vega` (or hand-author a token-themed inline `<svg>`)
447
+ inside a `ui-report__figure` bronto ships no chart component; use
448
+ `ui-delta` (`--up`/`--down`/`--flat`, `--invert` when up is bad) for a
449
+ trend figure and `ui-compare` (`--2up`) for an A/B / before-after section; use
450
+ `ui-report__section--unnumbered` for appendices in numbered reports; never
451
+ use raw chromatic inline colors. Format numbers/dates yourself (the framework
452
+ aligns figures, it does not format them) — see the reporting cookbook. To make
453
+ a PDF, render with `chrome-headless-shell` (or any Chromium) using
454
+ `printBackground: true` so figure fills survive — reports are static/zero-JS, so
455
+ it is just load → print; see "Print and PDF" in `docs/reporting.md`. Full
456
+ cookbook: `docs/reporting.md`.
140
457
 
141
458
  ## Authoritative offline references (shipped in this package)
142
459
 
@@ -145,6 +462,11 @@ Read these from `node_modules/@ponchia/ui/` — no network needed:
145
462
  - `classes/index.d.ts` — literal-typed `cls` map (exact class strings),
146
463
  every `ui.*()` recipe signature, every `*Opts` interface. The complete
147
464
  class surface; an agent should read this to know valid class names.
465
+ - `classes/classes.json` — the same vocabulary as language-neutral data, to
466
+ VALIDATE markup without executing ESM/parsing TS: `groups` (base →
467
+ modifiers/parts, the BEM structure), `classes` (flat list), `states` (the
468
+ `is-*` hooks that live outside `cls` by design, with their scope), and
469
+ `customProperties` (the author-set inline-style knobs like `--chart-color` / `--value`).
148
470
  - `docs/reference.md` — the full class catalog as prose tables (every
149
471
  class grouped by component, with registry key + kind). Generated from
150
472
  the same source as the types and CI-drift-checked.
@@ -158,6 +480,15 @@ Read these from `node_modules/@ponchia/ui/` — no network needed:
158
480
  - `docs/reporting.md` — static/PDF-first report cookbook for LLM-authored
159
481
  reports, including report skeletons, chart rules, print utilities, and safety
160
482
  boundaries.
483
+ - `docs/annotations.md` — SVG annotation recipes and helper guidance for
484
+ analytical figures.
485
+ - `docs/mermaid.md` — theme Mermaid diagrams from bronto tokens (resolved
486
+ `base` themeVariables, gated) and annotate the rendered SVG.
487
+ - `docs/d2.md` — theme D2 diagrams from bronto tokens (theme-override slots,
488
+ monochrome base + opt-in accent, gated) and annotate the rendered SVG.
489
+ - `docs/vega.md` — theme Vega-Lite charts from bronto tokens (resolved `config`,
490
+ gated + render-probed) — the recommended path when a report needs a chart,
491
+ since bronto ships no chart component.
161
492
  - `docs/contrast.md` — the published, CI-gated WCAG 2.1 contrast matrix
162
493
  for every contractual token pairing, per theme. Generated from the
163
494
  resolved palette; the build fails below the declared floor.
@@ -165,12 +496,17 @@ Read these from `node_modules/@ponchia/ui/` — no network needed:
165
496
  - `tokens/index.json` — tokens as plain data (global / light / dark).
166
497
  - `tokens/tokens.dtcg.json` — same tokens in W3C DTCG format.
167
498
  - `tokens/resolved.json` — every colour token resolved to a static
168
- `#rrggbb` / `rgba(...)` per theme (var() + color-mix() evaluated).
169
- Use this for non-CSS render targets: MapLibre/canvas/WebGL/SVG.
499
+ `#rrggbb` / `rgba(...)` per theme (var() + color-mix() evaluated) in
500
+ `light`/`dark`, plus a `scale` block of the non-colour scales
501
+ (spacing/radius/type/z/motion, var() chains flattened). The complete token
502
+ contract for non-CSS render targets: MapLibre/canvas/WebGL/SVG, or a
503
+ non-JS host (Python/Go) building a themed report.
170
504
  - `behaviors/index.d.ts` — typed signatures for the optional behaviors.
171
505
  - `glyphs/glyphs.d.ts` — the `GlyphName` literal union plus `renderGlyph` /
172
506
  `glyphCells` signatures for the display glyphs. (The DOM form,
173
507
  `initDotGlyph`, is declared in `behaviors/index.d.ts`.)
508
+ - `annotations/index.d.ts` — no-dependency SVG path helpers for Bronto
509
+ annotation geometry.
174
510
  - `classes/vscode.css-custom-data.json` — editor autocomplete for tokens.
175
511
 
176
512
  ## Human-browsable references (not shipped in the npm tarball, by design)
@@ -182,12 +518,24 @@ Read these from `node_modules/@ponchia/ui/` — no network needed:
182
518
 
183
519
  ## Rules an agent should respect
184
520
 
185
- - Never invent `ui-*` class names. Every valid class is a member of
186
- `cls` in `classes/index.d.ts`; if it is not there, it does not exist.
521
+ - Never invent `ui-*` class names. Every valid `ui-*` class is a member of
522
+ `cls` in `classes/index.d.ts` (and `classes/classes.json`); if a `ui-*`
523
+ name is not there, it does not exist. The `is-*` state hooks
524
+ (`is-num`/`is-pos`/`is-neg`/`is-key` on `.ui-table` cells and `.ui-stat`
525
+ deltas, `is-open`/`is-active`/`is-inactive` on stateful components) are the
526
+ one exception — they are real, documented in `docs/reference.md`
527
+ (§"Table-local state classes" / §"Composition & state") and emitted by the
528
+ `ui.*()` recipes, but deliberately NOT in `cls`. Do not strip them.
187
529
  - Prefer the `ui.*()` recipes over hand-concatenating modifier strings.
188
530
  Report/layout classes added in 0.4.1 are the exception: use `cls.report*`,
189
531
  `cls.chart*`, `cls.printOnly`, or literal documented class names because
190
- there are no `ui.report()` / `ui.chart()` recipes yet.
532
+ there are no `ui.report()` / `ui.chart()` recipes yet. Annotations do have a
533
+ `ui.annotation()` recipe for variant/tone selection.
534
+ - For a standalone HTML report, never `<link>` a `@ponchia/ui/css/*.css`
535
+ package specifier (it does not resolve in a browser) and never assume
536
+ `dist/bronto.css` carries the report/chart/legend/annotation layers — it
537
+ does not. Link each opt-in leaf from `dist/css/` via a real URL
538
+ (`./node_modules/…` or a pinned CDN). See the loading note above.
191
539
  - Override framework styles by writing your own rules outside
192
540
  `@layer bronto` — not with higher specificity or `!important`.
193
541
  - Color is tiered (ADR-0001): neutral canvas · one rationed accent · locked
@@ -195,4 +543,4 @@ Read these from `node_modules/@ponchia/ui/` — no network needed:
195
543
  tokens — re-point `--accent` (or a `data-bronto-skin` colorway), use status
196
544
  tokens for status, and `--chart-*` (from `css/dataviz.css`) for charts only.
197
545
  Don't add raw hues to components; `check:color-policy` enforces this.
198
- - Pre-1.0 SemVer: breaking changes ship in the *minor*. Pin `~0.x`.
546
+ - Pre-1.0 SemVer: breaking changes ship in the _minor_. Pin `~0.x`.