@ponchia/ui 0.6.4 → 0.6.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/docs/reference.md CHANGED
@@ -9,7 +9,7 @@ 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
- - 540 classes across 167 component groups
12
+ - 593 classes across 171 component groups
13
13
  - Import the typed registry: `import { cls, ui, cx } from '@ponchia/ui/classes'`
14
14
  - Validate markup as data (no JS/TS): `@ponchia/ui/classes.json` — the same
15
15
  vocabulary as language-neutral JSON (`groups`, `classes`, `states`,
@@ -330,6 +330,24 @@ each one matches a real selector in the stylesheet.
330
330
  | `cls.citation` | `ui-citation` | base |
331
331
  | `cls.citationChip` | `ui-citation--chip` | modifier |
332
332
 
333
+ ### `.ui-claim`
334
+
335
+ | Registry key | Class | Kind |
336
+ | --- | --- | --- |
337
+ | `cls.claim` | `ui-claim` | base |
338
+ | `cls.claimBasis` | `ui-claim__basis` | part |
339
+ | `cls.claimCaveat` | `ui-claim__caveat` | part |
340
+ | `cls.claimLimits` | `ui-claim__limits` | part |
341
+ | `cls.claimRefs` | `ui-claim__refs` | part |
342
+ | `cls.claimScope` | `ui-claim__scope` | part |
343
+ | `cls.claimStatement` | `ui-claim__statement` | part |
344
+ | `cls.claimStatus` | `ui-claim__status` | part |
345
+ | `cls.claimDisputed` | `ui-claim--disputed` | modifier |
346
+ | `cls.claimPartial` | `ui-claim--partial` | modifier |
347
+ | `cls.claimSupported` | `ui-claim--supported` | modifier |
348
+ | `cls.claimUnknown` | `ui-claim--unknown` | modifier |
349
+ | `cls.claimUnsupported` | `ui-claim--unsupported` | modifier |
350
+
333
351
  ### `.ui-cluster`
334
352
 
335
353
  | Registry key | Class | Kind |
@@ -557,6 +575,33 @@ each one matches a real selector in the stylesheet.
557
575
  | `cls.errorSummaryList` | `ui-error-summary__list` | part |
558
576
  | `cls.errorSummaryTitle` | `ui-error-summary__title` | part |
559
577
 
578
+ ### `.ui-evidence-grid`
579
+
580
+ | Registry key | Class | Kind |
581
+ | --- | --- | --- |
582
+ | `cls.evidenceGrid` | `ui-evidence-grid` | base |
583
+
584
+ ### `.ui-evidence-item`
585
+
586
+ | Registry key | Class | Kind |
587
+ | --- | --- | --- |
588
+ | `cls.evidenceItem` | `ui-evidence-item` | base |
589
+ | `cls.evidenceItemBody` | `ui-evidence-item__body` | part |
590
+ | `cls.evidenceItemCaveat` | `ui-evidence-item__caveat` | part |
591
+ | `cls.evidenceItemKind` | `ui-evidence-item__kind` | part |
592
+ | `cls.evidenceItemMeta` | `ui-evidence-item__meta` | part |
593
+ | `cls.evidenceItemMethod` | `ui-evidence-item__method` | part |
594
+ | `cls.evidenceItemSource` | `ui-evidence-item__source` | part |
595
+ | `cls.evidenceItemTitle` | `ui-evidence-item__title` | part |
596
+ | `cls.evidenceItemValue` | `ui-evidence-item__value` | part |
597
+ | `cls.evidenceItemWindow` | `ui-evidence-item__window` | part |
598
+
599
+ ### `.ui-evidence-ledger`
600
+
601
+ | Registry key | Class | Kind |
602
+ | --- | --- | --- |
603
+ | `cls.evidenceLedger` | `ui-evidence-ledger` | base |
604
+
560
605
  ### `.ui-eyebrow`
561
606
 
562
607
  | Registry key | Class | Kind |
@@ -939,13 +984,41 @@ each one matches a real selector in the stylesheet.
939
984
  | Registry key | Class | Kind |
940
985
  | --- | --- | --- |
941
986
  | `cls.report` | `ui-report` | base |
987
+ | `cls.reportAction` | `ui-report__action` | part |
988
+ | `cls.reportActionCriteria` | `ui-report__action-criteria` | part |
989
+ | `cls.reportActionDue` | `ui-report__action-due` | part |
990
+ | `cls.reportActionOwner` | `ui-report__action-owner` | part |
991
+ | `cls.reportActionPriority` | `ui-report__action-priority` | part |
992
+ | `cls.reportActionSource` | `ui-report__action-source` | part |
993
+ | `cls.reportActionStatus` | `ui-report__action-status` | part |
994
+ | `cls.reportActionTitle` | `ui-report__action-title` | part |
995
+ | `cls.reportActions` | `ui-report__actions` | part |
942
996
  | `cls.reportAppendix` | `ui-report__appendix` | part |
943
997
  | `cls.reportCaption` | `ui-report__caption` | part |
944
998
  | `cls.reportCover` | `ui-report__cover` | part |
945
999
  | `cls.reportCoverCompact` | `ui-report__cover--compact` | modifier |
1000
+ | `cls.reportDecision` | `ui-report__decision` | part |
1001
+ | `cls.reportDecisionBody` | `ui-report__decision-body` | part |
1002
+ | `cls.reportDecisionGrid` | `ui-report__decision-grid` | part |
1003
+ | `cls.reportDecisionItem` | `ui-report__decision-item` | part |
1004
+ | `cls.reportDecisionKicker` | `ui-report__decision-kicker` | part |
1005
+ | `cls.reportDecisionLabel` | `ui-report__decision-label` | part |
1006
+ | `cls.reportDecisionMeta` | `ui-report__decision-meta` | part |
1007
+ | `cls.reportDecisionTitle` | `ui-report__decision-title` | part |
1008
+ | `cls.reportDecisionValue` | `ui-report__decision-value` | part |
946
1009
  | `cls.reportEvidence` | `ui-report__evidence` | part |
947
1010
  | `cls.reportFigure` | `ui-report__figure` | part |
948
1011
  | `cls.reportFinding` | `ui-report__finding` | part |
1012
+ | `cls.reportFindingCritical` | `ui-report__finding--critical` | modifier |
1013
+ | `cls.reportFindingMajor` | `ui-report__finding--major` | modifier |
1014
+ | `cls.reportFindingMinor` | `ui-report__finding--minor` | modifier |
1015
+ | `cls.reportFindingResolved` | `ui-report__finding--resolved` | modifier |
1016
+ | `cls.reportFindingCaveat` | `ui-report__finding-caveat` | part |
1017
+ | `cls.reportFindingClaim` | `ui-report__finding-claim` | part |
1018
+ | `cls.reportFindingEvidence` | `ui-report__finding-evidence` | part |
1019
+ | `cls.reportFindingImpact` | `ui-report__finding-impact` | part |
1020
+ | `cls.reportFindingRemediation` | `ui-report__finding-remediation` | part |
1021
+ | `cls.reportFindingTitle` | `ui-report__finding-title` | part |
949
1022
  | `cls.reportFootnotes` | `ui-report__footnotes` | part |
950
1023
  | `cls.reportHead` | `ui-report__head` | part |
951
1024
  | `cls.reportMeta` | `ui-report__meta` | part |
@@ -1472,7 +1545,7 @@ works in any framework without a binding layer:
1472
1545
  - **Opt-in component CSS** — a few classes are not in the core bundle and need
1473
1546
  their leaf imported, or they render unstyled: `ui-property`/`ui-readout` →
1474
1547
  `@ponchia/ui/css/workbench.css`; `ui-mark`/`ui-bracket-note` →
1475
- `@ponchia/ui/css/marks.css`; the analytical leaves (`ui-annotations`,
1548
+ `@ponchia/ui/css/marks.css`; the analytical leaves (`ui-annotation`,
1476
1549
  `ui-crosshair`, `ui-spotlight`, …) → their matching leaf.
1477
1550
  - **Loaders need their children** — `ui-dotspinner` requires exactly eight
1478
1551
  `<i>` children, `ui-dotloader` three `<span>`, and a static `ui-dotbar`
package/docs/reporting.md CHANGED
@@ -37,11 +37,11 @@ No install? Link the same files from a CDN. Pin the version — pre-1.0, breakin
37
37
  changes ship in the minor (see [stability.md](./stability.md)):
38
38
 
39
39
  ```html
40
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.4/dist/bronto.css" />
41
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.4/dist/css/report.css" />
42
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.4/dist/css/dataviz.css" />
43
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.4/dist/css/annotations.css" />
44
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.4/dist/css/legend.css" />
40
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.6/dist/bronto.css" />
41
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.6/dist/css/report.css" />
42
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.6/dist/css/dataviz.css" />
43
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.6/dist/css/annotations.css" />
44
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.6/dist/css/legend.css" />
45
45
  ```
46
46
 
47
47
  The CDN serves the package's own `fonts/` next to the CSS, so font URLs resolve
@@ -59,8 +59,11 @@ sanitize that content before rendering it and do not initialize
59
59
  `css/report.css` gives you the document grammar (covers, sections, findings,
60
60
  evidence). The _content_ inside those sections is where the rest of the
61
61
  analytical layer earns its place. Each one is an opt-in import that stays out of
62
- the default bundle — add the leaves a given report actually needs, or pull the
63
- whole set with `@ponchia/ui/css/analytical.css`. Reach for:
62
+ the default bundle — add the leaves a given report actually needs.
63
+ `@ponchia/ui/css/analytical.css` is a convenience roll-up of the **seven
64
+ figure-layer leaves only** (annotations, legends, marks, connectors, spotlight,
65
+ crosshair, selection) — sources, generated, state, and the prose/evidence
66
+ leaves below are NOT in it and must be linked individually. Reach for:
64
67
 
65
68
  | Layer | Import | Reach for it when… |
66
69
  | --- | --- | --- |
@@ -72,6 +75,16 @@ whole set with `@ponchia/ui/css/analytical.css`. Reach for:
72
75
  | **D2 theme** (`@ponchia/ui/d2`) | _(JS/JSON, no CSS)_ | The report embeds a [D2](https://d2lang.com) diagram and you want it on-brand. Resolved theme-override slots (monochrome base + one rationed accent) projected from the same tokens; annotate the rendered SVG. See [d2.md](./d2.md). |
73
76
  | **Generated-content trust** (`.ui-generated`, `.ui-origin-label`, `.ui-reasoning`, `.ui-tool-log`) | `css/generated.css` | The report (or a section of it) is AI/system-authored and should _say so_ — an origin label plus quiet, collapsible reasoning / tool-call logs. Pairs with the sources layer. See [generated.md](./generated.md). |
74
77
  | **Lifecycle / system state** (`.ui-state`, `.ui-syncbar`) | `css/state.css` | A status report needs to show the state a thing is in — saving / queued / stale / conflict / reviewed — as a labelled object, not a bare coloured dot. See [state.md](./state.md). |
78
+ | **Spark** (`.ui-spark*`) | `css/spark.css` | A trend belongs _inside a sentence or table cell_ — a word-sized inline microchart, the inline counterpart to `ui-delta`/`ui-num`/`ui-stat`. See [spark.md](./spark.md). |
79
+ | **Bullet graph** (`.ui-bullet*`) | `css/bullet.css` | A measure needs "inside budget? vs target?" at a glance — the canonical SLO / error-budget figure that `ui-meter` structurally cannot express. See [bullet.md](./bullet.md). |
80
+ | **Diff** (`.ui-diff*`) | `css/diff.css` | The report shows what _changed_ — code review, changelogs, version history, config diffs. Marks call out a sentence; diff calls out a line. See [diff.md](./diff.md). |
81
+ | **Code** (`.ui-code*`) | `css/code.css` | Code-as-evidence: fenced snippets with an optional gutter and add/remove/highlight line states, sharing diff's change vocabulary. On-brand syntax colours via the [Shiki theme](./code.md). See [code.md](./code.md). |
82
+ | **Sidenotes** (`.ui-sidenote`, `.ui-marginnote`) | `css/sidenote.css` | Evidence, caveats, and provenance asides that belong _beside_ the prose, Tufte-style, instead of interrupting it. See [sidenote.md](./sidenote.md). |
83
+ | **Textref** (`.ui-textref`) | `css/textref.css` | A citation should deep-link to the _exact quoted sentence_ (URL text fragments, on-brand `::target-text` paint) — the inline counterpart to the source-card layer. See [textref.md](./textref.md). |
84
+ | **Term / glossary** (`.ui-term`, `.ui-glossary`) | `css/term.css` | Jargon should explain itself inline (native popover definition) and gather into an end-of-report glossary. See [term.md](./term.md). |
85
+ | **Contents rail** (`.ui-toc*`) | `css/toc.css` | A long report needs a sticky table of contents with the in-view section highlighted; degrades to a plain anchored list with zero JS. Distinct from the in-flow `ui-report__toc` block. See [toc.md](./toc.md). |
86
+ | **Tree** (`.ui-tree*`) | `css/tree.css` | Nested structure — file trees, object graphs, nested provenance — as a depth-indented outline on native `<details>`. See [tree.md](./tree.md). |
87
+ | **Dot surfaces** (`.ui-waffle`, `.ui-activity`, `.ui-level`, `.ui-dotgauge`, `.ui-readout`, …) | _(in the core bundle)_ | A count, rate, level, or gauge wants the library's signature dot-matrix expression — waffle units, activity strips, dot gauges, readouts. See [dots.md](./dots.md). |
75
88
 
76
89
  These compose with the report-native primitives already called out in
77
90
  [Composition rules](#composition-rules): `ui-statgrid`, `ui-alert`, `ui-table`,
@@ -106,6 +119,24 @@ they are all safe in the static, PDF-first report path.
106
119
  <div class="ui-report__summary">
107
120
  <p>The summary block is for the decision-level conclusion.</p>
108
121
  </div>
122
+ <aside class="ui-report__decision" aria-labelledby="decision-title">
123
+ <p class="ui-report__decision-kicker">Decision</p>
124
+ <h3 class="ui-report__decision-title" id="decision-title">Ship the low-risk path</h3>
125
+ <p class="ui-report__decision-body">
126
+ State the operator-facing call first, then list the evidence below it.
127
+ </p>
128
+ <dl class="ui-report__decision-grid">
129
+ <div class="ui-report__decision-item">
130
+ <dt class="ui-report__decision-label">Basis</dt>
131
+ <dd class="ui-report__decision-value">Two verified sources support the call.</dd>
132
+ </div>
133
+ <div class="ui-report__decision-item">
134
+ <dt class="ui-report__decision-label">Next action</dt>
135
+ <dd class="ui-report__decision-value">Owner rechecks the remaining caveat by Jun 8.</dd>
136
+ </div>
137
+ </dl>
138
+ <p class="ui-report__decision-meta">Evidence state: supported · Checked: 2026-06-01</p>
139
+ </aside>
109
140
  <div class="ui-statgrid">
110
141
  <div class="ui-stat">
111
142
  <span class="ui-stat__label">Open risks</span>
@@ -127,6 +158,147 @@ they are all safe in the static, PDF-first report path.
127
158
  </main>
128
159
  ```
129
160
 
161
+ ## Report-specific primitives
162
+
163
+ Use these report-layer primitives before inventing custom card layouts. They are
164
+ generic, static, and PDF-safe; the host still owns the content, scoring, source
165
+ fetching, and claim wording.
166
+
167
+ - `ui-report__decision` is the above-the-fold call. Pair it with
168
+ `ui-report__decision-kicker`, `ui-report__decision-title`,
169
+ `ui-report__decision-body`, optional `ui-report__decision-grid` /
170
+ `ui-report__decision-item` detail rows, and optional
171
+ `ui-report__decision-meta`. It should answer "what should the reader do or
172
+ believe now?" before the deep evidence. Good rows are basis, impact, next
173
+ action, owner, recheck date, and evidence state.
174
+ - `ui-report__finding` is the repeated finding block. Add
175
+ `ui-report__finding--critical`, `--major`, `--minor`, or `--resolved` only
176
+ when the written finding label also states the severity/status. The colour
177
+ band is a scanning aid, not the data of record. For dense reports, use
178
+ `ui-report__finding-title`, `ui-report__finding-claim`,
179
+ `ui-report__finding-impact`, `ui-report__finding-remediation`,
180
+ `ui-report__finding-evidence`, and `ui-report__finding-caveat` so impact,
181
+ evidence, caveat, and remediation do not collapse into one paragraph.
182
+ - `ui-claim` is the smallest claim/evidence contract. Use
183
+ `ui-claim--supported`, `--partial`, `--disputed`, `--unsupported`, or
184
+ `--unknown` only when the written `ui-claim__status` says the same thing.
185
+ Use `ui-claim__statement`, `__scope`, `__basis`, `__limits`, `__refs`, and
186
+ `__caveat` to show what the report asserts, where it applies, what supports
187
+ it, what would limit or change it, and which sources/evidence entries it maps
188
+ to.
189
+ - `ui-evidence-grid` and `ui-evidence-item` are for compact evidence packets:
190
+ one source, check, observation, counterexample, or assumption per item. Use
191
+ `ui-evidence-item__title`, `__meta`, and `__body` for simple cards; add
192
+ `__kind`, `__method`, `__window`, `__value`, `__source`, and `__caveat` when
193
+ the evidence needs to say how it was gathered. Link to source cards or a table
194
+ when the evidence is more than a sentence.
195
+ - `ui-evidence-ledger` is a wrapper for a claim/evidence/source matrix. Put a
196
+ normal `ui-table` inside it with columns such as claim, evidence, source,
197
+ trust, freshness, relation, and caveat.
198
+ - `ui-report__actions`, `ui-report__action`, and
199
+ `ui-report__action-status` are for follow-up rows in status, incident, and
200
+ audit reports. Add `ui-report__action-title`, `__action-owner`,
201
+ `__action-due`, `__action-priority`, `__action-criteria`, and
202
+ `__action-source` when the action is a real workflow item. The status text
203
+ must be written out; do not rely on tone alone.
204
+
205
+ Decision brief pattern:
206
+
207
+ ```html
208
+ <aside class="ui-report__decision" aria-labelledby="decision-title">
209
+ <p class="ui-report__decision-kicker">Decision</p>
210
+ <h3 class="ui-report__decision-title" id="decision-title">Adopt the safer option</h3>
211
+ <p class="ui-report__decision-body">
212
+ The current evidence supports the lower-risk path while the disputed source is rechecked.
213
+ </p>
214
+ <dl class="ui-report__decision-grid">
215
+ <div class="ui-report__decision-item">
216
+ <dt class="ui-report__decision-label">Basis</dt>
217
+ <dd class="ui-report__decision-value">Verified metrics support the call; one source is stale.</dd>
218
+ </div>
219
+ <div class="ui-report__decision-item">
220
+ <dt class="ui-report__decision-label">Recheck</dt>
221
+ <dd class="ui-report__decision-value"><time datetime="2026-06-08">2026-06-08</time></dd>
222
+ </div>
223
+ </dl>
224
+ <p class="ui-report__decision-meta">Evidence state: partial · Sources: 4 · Checked: 2026-06-01</p>
225
+ </aside>
226
+ ```
227
+
228
+ Finding + evidence pattern:
229
+
230
+ ```html
231
+ <article class="ui-report__finding ui-report__finding--major" aria-labelledby="finding-cache">
232
+ <p class="ui-eyebrow" id="finding-cache">Major finding — cache pressure is rising</p>
233
+ <p class="ui-report__finding-claim">
234
+ Claim: cache pressure is rising during the refresh window.
235
+ </p>
236
+ <p class="ui-report__finding-impact">Impact: p95 latency is likely to breach target if volume rises.</p>
237
+ <p class="ui-report__finding-remediation">Remediation: lower the refresh batch size before the next rollout.</p>
238
+ <p class="ui-report__finding-caveat">
239
+ Caveat: the conclusion assumes comparable traffic shape in the next window.
240
+ </p>
241
+ </article>
242
+ <div class="ui-evidence-grid" aria-label="Evidence summary">
243
+ <article class="ui-evidence-item">
244
+ <h3 class="ui-evidence-item__title">Metric trend</h3>
245
+ <p class="ui-evidence-item__kind">Observation</p>
246
+ <p class="ui-evidence-item__meta">Prometheus · 24 h window</p>
247
+ <p class="ui-evidence-item__body">p95 latency rose 18% while request volume stayed flat.</p>
248
+ </article>
249
+ <article class="ui-evidence-item">
250
+ <h3 class="ui-evidence-item__title">Log sample</h3>
251
+ <p class="ui-evidence-item__meta">Application logs · reviewed</p>
252
+ <p class="ui-evidence-item__body">Timeouts cluster around cache refresh intervals.</p>
253
+ </article>
254
+ </div>
255
+ ```
256
+
257
+ Claim block pattern:
258
+
259
+ ```html
260
+ <article class="ui-claim ui-claim--partial" id="claim-latency">
261
+ <p class="ui-claim__statement">The migration improved latency without reducing availability.</p>
262
+ <p class="ui-claim__status">Evidence state: partial</p>
263
+ <p class="ui-claim__scope">Scope: last 7 days, production traffic only</p>
264
+ <p class="ui-claim__basis">Basis: metrics export S1 and incident note S2 support the claim.</p>
265
+ <p class="ui-claim__limits">Limit: retry volume still needs a separate review.</p>
266
+ <p class="ui-claim__refs">Sources: <a class="ui-citation" href="#source-metrics">S1</a></p>
267
+ </article>
268
+ ```
269
+
270
+ Evidence ledger pattern:
271
+
272
+ ```html
273
+ <div class="ui-evidence-ledger">
274
+ <div class="ui-table-wrap">
275
+ <table class="ui-table ui-table--dense">
276
+ <caption>Claim, evidence, and caveat ledger</caption>
277
+ <thead>
278
+ <tr>
279
+ <th>Claim</th>
280
+ <th>Evidence</th>
281
+ <th>Source</th>
282
+ <th>Trust</th>
283
+ <th>Relation</th>
284
+ <th>Caveat</th>
285
+ </tr>
286
+ </thead>
287
+ <tbody>
288
+ <tr>
289
+ <td><a href="#claim-latency">Latency improved</a></td>
290
+ <td>p95 fell 48 ms</td>
291
+ <td><a class="ui-citation" href="#source-metrics">S1</a></td>
292
+ <td>Verified</td>
293
+ <td>Supports</td>
294
+ <td>Last 7 days only</td>
295
+ </tr>
296
+ </tbody>
297
+ </table>
298
+ </div>
299
+ </div>
300
+ ```
301
+
130
302
  ## Composition rules
131
303
 
132
304
  - Use `ui-report` as the page-level wrapper. Add `ui-report--numbered` when
@@ -150,6 +322,12 @@ they are all safe in the static, PDF-first report path.
150
322
  `ui-alert` for persistent notices, `ui-table` for structured evidence,
151
323
  `ui-timeline` for events, `ui-meter` for measured values, and `ui-num` for
152
324
  non-table numeric values.
325
+ - Put a `ui-report__decision` near the start of decision reports, audits, and
326
+ incident reviews. If the report is intentionally exploratory and has no
327
+ decision yet, say so in the summary instead of leaving the reader to infer it.
328
+ - Use severity modifiers on `ui-report__finding` only for scanability. The
329
+ label should still include the severity/status in text, for example
330
+ "Major finding — …" or "Resolved finding — …".
153
331
  - In alerts, put the readable message in `<p class="ui-alert__body">…</p>`
154
332
  and use `ui-alert__title` only for a separate title line. `ui-alert` is a
155
333
  grid with a leading status dot; raw text or loose inline children such as
@@ -579,14 +757,100 @@ the target theme, or use the frozen inline `<svg>` route, which has no runtime.
579
757
 
580
758
  ## Common templates
581
759
 
582
- - Executive brief: compact cover, one summary block, KPI `ui-statgrid`, short
583
- findings, and sources.
584
- - Research brief: compact header, decision frame, evidence table, quotes or
585
- prose excerpts, and sources.
586
- - Incident review: compact cover, summary, `ui-timeline`, corrective-action
587
- evidence table, and footnotes.
588
- - Project status: compact header, KPI `ui-statgrid`, chart figure with fallback
589
- data, print-only notes, and unnumbered appendix.
760
+ - Executive brief: compact cover, above-fold reader outcome, KPI
761
+ `ui-statgrid`, short findings, evidence-state disclosure, and sources.
762
+ - Decision report: decision frame, options considered, chosen option, rationale,
763
+ tradeoffs, revisit trigger, next actions, evidence ledger, and sources.
764
+ - Research brief: compact header, scope/method block, claim cards, evidence
765
+ table, quotes or prose excerpts, limitations, and sources.
766
+ - Incident review: compact cover, impact summary, `ui-timeline`, root-cause
767
+ claim, corrective-action register, evidence ledger, and footnotes.
768
+ - Audit: summary, finding cards with severity in text, evidence/caveat rows,
769
+ remediation owner/due dates, accepted risk, and sources.
770
+ - Project status: compact header, KPI `ui-statgrid`, current state, blocked
771
+ decisions, action register, chart figure with fallback data, print-only notes,
772
+ and unnumbered appendix.
773
+
774
+ Minimum blocks by report type:
775
+
776
+ | Type | Required shape |
777
+ | --- | --- |
778
+ | Executive | Summary, above-fold outcome, evidence-state disclosure, source cards. |
779
+ | Decision | Decision frame, options/tradeoffs, claim cards, evidence ledger, next actions, sources. |
780
+ | Research | Scope/method, explicit claims, evidence table, limitations, sources. |
781
+ | Primer | Scope, teaching sequence, key claims, examples, caveats, sources. |
782
+ | Incident | Impact, root-cause claim, timeline, evidence ledger, corrective actions, footnotes. |
783
+ | Audit | Severity-labelled findings, evidence/caveat rows, remediation owners/dates, accepted risk, sources. |
784
+ | Status | Current state, risks/blockers, decision requests, action register, recheck timing, sources. |
785
+
786
+ ## Semantic contract
787
+
788
+ The report layer is not a fact checker, but it should make a report's reasoning
789
+ auditable. A useful report separates:
790
+
791
+ - **Reader outcome** — what the reader should do or believe now.
792
+ - **Claim** — the actual assertion, with scope and evidence state.
793
+ - **Evidence** — observation, metric, log, quote, sample, method, assumption,
794
+ counterevidence, or limitation.
795
+ - **Source** — where the evidence came from, with trust/freshness written in
796
+ text.
797
+ - **Action** — who does what next, by when, and how completion is checked.
798
+
799
+ Use inline citations and stable IDs to connect those layers:
800
+
801
+ ```html
802
+ <article class="ui-claim ui-claim--supported" id="claim-1" data-source-ids="source-metrics">
803
+ <p class="ui-claim__statement">Availability remained above target.</p>
804
+ <p class="ui-claim__status">Evidence state: supported</p>
805
+ <p class="ui-claim__refs">Source: <a class="ui-citation" href="#source-metrics">S1</a></p>
806
+ </article>
807
+
808
+ <article class="ui-source-card ui-src--verified" id="source-metrics">
809
+ <h3 class="ui-source-card__title">Metrics export</h3>
810
+ <p class="ui-source-card__origin">Verified operational export</p>
811
+ </article>
812
+ ```
813
+
814
+ If a claim is generated, inferred, stale, disputed, or uncited, say so near the
815
+ claim, not only in the source appendix. Do not use a numeric confidence widget
816
+ unless the number has a real model, sample, or scoring method behind it.
817
+
818
+ Generator-side tools should keep a machine-readable claim/source sidecar beside
819
+ important reports. The HTML stays the readable artifact; the sidecar lets a
820
+ checker prove that claim IDs, source IDs, trust states, retrieval dates and
821
+ high-risk decisions still line up after editing.
822
+
823
+ ```json
824
+ {
825
+ "schemaVersion": "bronto-report-claims.v1",
826
+ "report": { "title": "Decision readiness", "type": "decision" },
827
+ "claims": [
828
+ {
829
+ "id": "claim-primary",
830
+ "status": "supported",
831
+ "risk": "medium",
832
+ "statement": "The guarded option reduces operational risk.",
833
+ "scope": "Current release window",
834
+ "sourceIds": ["source-primary"]
835
+ }
836
+ ],
837
+ "sources": [
838
+ {
839
+ "id": "source-primary",
840
+ "state": "verified",
841
+ "title": "Release metrics export",
842
+ "origin": "Verified operational export",
843
+ "retrievedAt": "2026-06-08T10:00:00Z",
844
+ "supports": ["claim-primary"]
845
+ }
846
+ ]
847
+ }
848
+ ```
849
+
850
+ For source archives, keep the same source IDs and add any available immutable
851
+ handles: URL, artifact path, content hash, retrieval timestamp, collection
852
+ method and caveats. A report is more useful when the source appendix, inline
853
+ citations, evidence ledger and sidecar all name the same IDs.
590
854
 
591
855
  ## Print and PDF
592
856
 
@@ -594,6 +858,11 @@ The supported export target is modern Chromium print/PDF. A bronto report is
594
858
  static and zero-JS, so producing the PDF is just _load → print_ — you do not
595
859
  need a full automatable browser, only a Chromium-class layout+print pass.
596
860
 
861
+ Chromium's generated PDF is a visual/export artifact, not a tagged accessible
862
+ PDF. Keep the HTML report as the accessible artifact unless the host application
863
+ adds a separate tagged-PDF pipeline and verifies it with PDF accessibility
864
+ tooling.
865
+
597
866
  - **By hand:** open the report in Chrome/Edge → Print (Cmd/Ctrl+P) → "Save as
598
867
  PDF". In **More settings**, enable **Background graphics** (the dialog's
599
868
  equivalent of `printBackground` — without it chart fills and swatches drop
@@ -620,6 +889,14 @@ need a full automatable browser, only a Chromium-class layout+print pass.
620
889
  (Puppeteer ships its own). The repo's `scripts/render-pdf.mjs` is a working
621
890
  copy of this (`npm run report:pdf -- report.html`); it is a dev/example
622
891
  helper, not part of the published API — bronto does not own rendering.
892
+
893
+ **If the report renders figures from `<script type="module">`, do not load
894
+ it over `file://`** — browsers block relative module imports from `file://`
895
+ (CORS, opaque `null` origin), so the figures silently render empty in the
896
+ PDF. Serve the report over HTTP first; `render-pdf.mjs --serve` does this
897
+ (loopback server + load over `http://127.0.0.1`), waits for the report's
898
+ `data-report-ready` signal if it sets one, and logs page errors instead of
899
+ swallowing them.
623
900
  - **As a service / from another language:** run Chromium-as-a-service
624
901
  (e.g. **Gotenberg**'s `POST /forms/chromium/convert/html`, or a hosted CDP
625
902
  endpoint) and POST the HTML + the `dist/css/*` assets. A Python/Go/any host
@@ -666,6 +943,19 @@ Before returning a report, an LLM should verify:
666
943
  cells and `.ui-stat` deltas, `is-open`/`is-active`) are valid but live
667
944
  outside `cls` by design — keep them.
668
945
  - The document has one `h1`, ordered headings, and a single main report region.
946
+ - The report type is clear: executive, decision, research, incident, audit,
947
+ primer, or status. The above-fold block answers what the reader should do or
948
+ believe now, unless the report explicitly says it is exploratory.
949
+ - Every decision, major finding, quantitative claim, and recommendation has a
950
+ nearby citation, claim block, evidence packet, evidence ledger row, or an
951
+ explicit assumption/uncited/generated label.
952
+ - Claim/source sidecars, when present, resolve every claim ID and source ID back
953
+ to visible HTML. High-risk claims have at least one verified or reviewed
954
+ source.
955
+ - Stale, conflicting, unverified, or generated inputs are surfaced near the
956
+ affected claim or decision, not buried only in the source appendix.
957
+ - Actions that represent real follow-up include owner, due/recheck date, status,
958
+ and success criteria, or explicitly say why those fields are unassigned.
669
959
  - Tables have captions and header cells.
670
960
  - Charts have captions, direct labels or legends, and fallback data.
671
961
  - No raw chromatic colors appear in inline styles.
package/docs/sources.md CHANGED
@@ -102,6 +102,35 @@ A references section: a reset list of source cards (or rows).
102
102
  </ol>
103
103
  ```
104
104
 
105
+ ## Optional behavior — `initSources`
106
+
107
+ When you want citations to jump back to their source cards with a visible focus
108
+ cue, wrap the report or article in `data-bronto-sources` and initialize the
109
+ behavior:
110
+
111
+ ```html
112
+ <main data-bronto-sources>
113
+ <p>Latency fell 38%<a class="ui-citation" href="#s1" aria-label="Source 1">[1]</a>.</p>
114
+ <article id="s1" class="ui-source-card ui-src--verified">…</article>
115
+ </main>
116
+
117
+ <script type="module">
118
+ import { initSources } from '@ponchia/ui/behaviors';
119
+ const stop = initSources();
120
+ </script>
121
+ ```
122
+
123
+ `initSources()` is progressive enhancement over authored IDs. It resolves
124
+ `.ui-citation[href^="#"]` and `[data-bronto-source-ref]` controls inside each
125
+ `[data-bronto-sources]` island, adds preview metadata (`title` and
126
+ `aria-describedby`) when the author did not already provide it, and activation
127
+ focuses the matching source card with a temporary `.is-source-active` highlight.
128
+ It emits `bronto:source:focus` with `{ id, citation, source }`.
129
+
130
+ The host still owns fetching, numbering, permission checks, trust decisions, and
131
+ any rich preview popover. Generated/static reports can stay behavior-free:
132
+ hash-link navigation and `.ui-source-card:target` still provide a CSS-only cue.
133
+
105
134
  ## Provenance — `.ui-provenance`
106
135
 
107
136
  A compact metadata row beside generated content — each `__item` carries a trust
@@ -130,6 +159,9 @@ ui.provenance({ state: 'reviewed' }); // "ui-provenance ui-src--reviewed"
130
159
 
131
160
  - A citation must be a real link or button with a stable accessible name; the
132
161
  bracketed index alone is not enough.
162
+ - `initSources()` is optional. Initialize it only on trusted markup; the
163
+ delegated `data-bronto-source-ref` / `href="#…"` relationships focus elements
164
+ inside the source island.
133
165
  - The trust state must be readable as text — the tone dot/border is decorative
134
166
  reinforcement. Under `forced-colors`, dots and borders fall back to
135
167
  `CanvasText`, so the label remains the channel.
package/docs/stability.md CHANGED
@@ -1,12 +1,15 @@
1
1
  # Public API Stability
2
2
 
3
3
  `@ponchia/ui` is pre-1.0. Breaking changes ship in the minor (`0.x.0`), and
4
- patches are non-breaking. In practical terms: **PATCH releases (`0.5.x`) are
4
+ patches are non-breaking. In practical terms: **PATCH releases (`0.6.x`) are
5
5
  non-breaking bug-fixes and additive changes — safe to upgrade without review;
6
6
  MINOR releases (`0.x.0`) may include breaking changes and consumers should
7
7
  review the CHANGELOG before upgrading.** Pin `~0.x` (tilde) to accept only
8
8
  patches, or `^0.x` only if you accept minor-level churn. This policy holds
9
9
  until `1.0.0` is tagged. This matrix defines what counts as public API.
10
+ For the exhaustive package-manifest inventory — every `exports` key, every
11
+ shipped `files` entry, and the generated artifact provenance map — see
12
+ [package-contract.md](./package-contract.md).
10
13
 
11
14
  | Surface | Stability | Contract |
12
15
  | --- | --- | --- |
@@ -18,7 +21,7 @@ until `1.0.0` is tagged. This matrix defines what counts as public API.
18
21
  | Design tokens | Stable names/roles | Token names and documented roles are public. Exact values and generated colour math outputs may change for visual tuning before 1.0. |
19
22
  | `--accent-1..6` | Stable names/roles | A subtle-to-bold accent ramp derived from `--accent`. Exact resolved values are visual tuning; algorithm changes require release-note visibility and resolver/browser checks. |
20
23
  | Tokens as data (`tokens.json`, `tokens.dtcg.json`, `tokens/resolved.json`) | Stable additive | The JSON shapes are public for non-CSS/non-JS consumers. `resolved.json` exposes `light`/`dark` (resolved colours) and `scale` (resolved non-colour scales). Token names/roles are stable; exact resolved values are visual tuning (pin `~0.x`). |
21
- | Theme axes | Mixed | `data-theme` (light/dark) is the **contractual** base. `data-surface="oled"`, `data-density`, and `data-contrast` are **convenience presets** — best-effort visual variants, **not** part of the stability contract; their presence and exact values may change for tuning. (A computed-style smoke test guards the OLED `--bg` flip; the others are unverified.) |
24
+ | Theme axes | Mixed | `data-theme` (light/dark) is the **contractual** base. `data-surface="oled"`, `data-density`, and `data-contrast` are **convenience presets** — best-effort visual variants, **not** part of the stability contract; their presence and exact values may change for tuning. Computed-style smoke tests guard that the presets apply to their intended token families. |
22
25
  | Behavior attributes (`data-bronto-*`) | Stable | Attribute names and documented markup relationships are public. Behavior internals are not. |
23
26
  | Behavior functions (`@ponchia/ui/behaviors`) | Stable | Exported function names, option names, custom events, SSR no-op behavior, idempotency, and cleanup-returning contract are public. |
24
27
  | Glyph registry/renderers (`@ponchia/ui/glyphs`) | Stable additive | Existing glyph names stay valid. New glyphs are additive. Renderer option names and accessibility defaults are public. |
@@ -35,7 +38,7 @@ until `1.0.0` is tagged. This matrix defines what counts as public API.
35
38
  | Crosshair (`css/crosshair.css`, `.ui-crosshair*`, `.ui-readout`, `initCrosshair`) | Stable additive | Crosshair/readout class names, the `--crosshair-x/y` properties, the `data-bronto-crosshair` attribute, and the `bronto:crosshair:move`/`:leave` event contract are public. Opt-in. Reports pointer position only — no data mapping. |
36
39
  | Selection states (`css/selection.css`, `.ui-sel*`) | Stable additive | The `.ui-sel`/`--on`/`--off`/`--maybe` emphasis classes and recipe options are public. Opt-in, cross-cutting. The host owns selection logic; Bronto only styles the states. |
37
40
  | Analytical roll-up (`css/analytical.css`) | Stable additive | A convenience `@import` of the seven analytical leaves (annotations, legend, marks, connectors, spotlight, crosshair, selection). The set of leaves it bundles may grow additively; each leaf also stays individually exported. Opt-in, not in the default bundle. |
38
- | Sources / provenance (`css/sources.css`, `.ui-citation*`, `.ui-source-card*`, `.ui-source-list*`, `.ui-provenance*`, `.ui-src--*`) | Stable additive | Citation/source/provenance class names, the cross-cutting `.ui-src--*` trust-state modifiers (always paired with an author label), and the `ui.citation`/`ui.source`/`ui.provenance` recipes + `cls.sourceList` are public. Opt-in, not in the default bundle. |
41
+ | Sources / provenance (`css/sources.css`, `.ui-citation*`, `.ui-source-card*`, `.ui-source-list*`, `.ui-provenance*`, `.ui-src--*`, `initSources`) | Stable additive | Citation/source/provenance class names, the cross-cutting `.ui-src--*` trust-state modifiers (always paired with an author label), the optional `data-bronto-sources` / `data-bronto-source-ref` behavior contract, `bronto:source:focus`, and the `ui.citation`/`ui.source`/`ui.provenance` recipes + `cls.sourceList` are public. Opt-in, not in the default bundle. |
39
42
  | Lifecycle state (`css/state.css`, `.ui-state*`, `.ui-syncbar`) | Stable additive | The `.ui-state`/`__label`/`__detail`/`--busy` classes, the canonical lifecycle state modifiers, `.ui-syncbar`, and the `ui.state` recipe are public. Opt-in, not in the default bundle. |
40
43
  | Generated / AI-trust (`css/generated.css`, `.ui-generated*`, `.ui-origin-label*`, `.ui-reasoning*`, `.ui-tool-log`, `.ui-tool-call*`) | Stable additive | The generated-content, origin-label (incl. `--ai`), reasoning-trace and tool-log/tool-call class names and the `ui.originLabel` recipe are public. Opt-in, not in the default bundle. Not a chat kit; no confidence widget. |
41
44
  | Workbench (`css/workbench.css`, `.ui-inspector*`, `.ui-property*`, `.ui-selectionbar*`) | Stable additive | Inspector, property-row and selection-bar class + BEM part names are public (class-only — no recipe). Opt-in, not in the default bundle. Splitters/drag handles are out of scope. |