# Provenance

What this design system was read from, what was deliberately excluded, and what was
derived rather than observed. Read alongside `source-context.md`.

## Scoping decision

The workspace was created from the source project with eight copied files. Partway
through generation the user gave an explicit instruction:

> "I want the design system made only from the new home page we just redesigned, so we can
> then apply that design system to the rest of the pages."

So the extraction was narrowed to **`index.html` alone** — the redesigned home page,
516 lines, self-contained HTML/CSS/JS with no external requests. Every token, scale,
component, motion value, accessibility pattern and copy rule in `DESIGN.md`,
`colors_and_type.css`, `tokens.css` and `ui_kits/app/app.css` was read from that file.

## Evidence ledger

| File | Role | Why |
|---|---|---|
| `index.html` | **Sole source** | The redesigned home page. All 20 color tokens, 3 type stacks, 13 type steps, 12 spacing steps, 7 radii, 4 shadows, 6 motion durations, 14 components and 4 breakpoints come from here. |
| `examples/source-home-page.html` | Preserved copy | Byte-identical snapshot taken at extraction time, so the derivation stays auditable if the working file changes. |
| `index-v1.html` | **Excluded** | The predecessor the redesign replaced. Including it would blend two directions. |
| `avonlake-city.html` | **Excluded — target** | Dashboard page. The system is to be applied *to* it, so reading it would be circular. Referenced only as a link destination. |
| `alerg-case-file.html` | **Excluded — target** | Same. `ui_kits/app/case-file.html` is the surface it should be rebuilt against. |
| `brand-spec.md` | **Excluded — superseded** | Documents an earlier direction: burgundy `#7c1f3f`, shoreline orange `#db7826`, warm newsprint `#f4f1ea`, charcoal structure. The redesign replaced it with forest green, volt and paper-green. None of those values appear anywhere in this package. The file is kept because the *posture* rules it recorded — eyebrows as case-file labels, structure over ornament, "every claim shows its confidence and its receipt" — survived the redesign intact, and the continuity is worth being able to see. |
| `image.png` | **Excluded** | Screenshot of the official City of Avon Lake site; it was the palette source for the superseded burgundy direction. Out of scope, and using city-site colors would also work against the project's independence disclaimer. |
| `sketch-2026-07-29T03-04-43.sketch.json` | **Excluded** | 254-byte stub with no design content. |
| `document.md` | **Excluded** | Unedited Open Design template scaffold. |
| `DESIGN.md` (previous) | **Replaced in place** | Was the empty section-header template ("Describe the visual mood…"). Rewritten, not duplicated. |

Registered design-system id `user:untitled-design-system` and project id
`fd849649-350c-46e2-8b01-74d545c78730` were preserved. No new project or system id was
created.

## Observed vs. derived

**Observed — read directly from the source (14 components):** topline ribbon, masthead +
nav + live chip, buttons (5 variants), status stamp, register legend chip, filing-card
panel, filing-tab card, annotated-document grid + margin note, method row + callout rule,
standards strip, dark band + ledger, record field, highlighter, ink footer + colophon.

**Derived — built from the tokens because the remaining pages need them (3 components):**

| Component | Derived from |
|---|---|
| `.rt` record table | `.prow` key/value row logic widened into columns; header treatment borrowed from the eyebrow, caption from `.src`. |
| `.fld` form field | The border/hover/focus language of `.btn.ghost` and `.lg`, with the eyebrow as the label style. Required marks use `--amber-ink` because "you must supply this" is the same class of signal as "not yet obtainable". |
| `.tabs` | The `.ic::before` filing tab promoted to navigation — same `6px 6px 0 0` shape, same mono `.11em` label. |

All three sit under an `EXTENSIONS` banner in `app.css`, are stamped **Extension** in
`ui_kits/app/components.html`, and are named as extensions in `DESIGN.md` §6.

**Undefined by the source, and deliberately left undefined:** dark mode (the page declares
`color-scheme: light`), modals, toasts, pagination, breadcrumbs. `DESIGN.md` §2 gives the
one safe fallback — reuse `--forest-deep` or `--ink-band` with the measured on-dark text
ramps — rather than inventing a full inversion.

## Computed, not guessed

- **OKLch values** in `DESIGN.md` and `colors_and_type.css` are exact conversions of the source hex values (sRGB → linear → LMS → Oklab → LCh). They are documentation of the observed colors, not a re-pick.
- **Contrast ratios** are WCAG 2.x relative-luminance computations against the specific background each token is used on. Every text pair documented in the package measures ≥4.60:1 — the lowest is dark `--ink-quiet` on `--evidence-inset`. Verified continuously by `tools/audit-readiness.py`, which recomputes every role pair from the live CSS rather than trusting these figures.
- **`assets/record-field-motif.svg`** is generated from the source's own `REG` array — the same eight registers, the same counts (70 + 44 + 39 + 13 + 6 + 5 + 4 + 16 = 197), the same hex values, the same 13px cell and 4px gutter, and the same `aria-label` string.

## Assets

The source home page **loads zero images and zero webfonts**. There is no `@font-face`, no
`<img>`, no `<svg>`, no `<link rel="icon">`, and no third-party request of any kind. That
is a posture of the system, not a gap — so nothing in `assets/` or `build/` is claimed as
preserved artwork.

| File | Basis |
|---|---|
| `assets/record-field-motif.svg` | **Data-exact** — generated from the source `REG` array. |
| `assets/register-scale.svg` | The eight ramp steps with their source hex and prototype match counts. |
| `assets/topline-ribbon.svg` | Vector of the `.topline` CSS gradient at its exact stops. |
| `assets/wordmark-light.svg` / `-dark.svg` | Vector of the `.brand` type lockup as the source sets it (serif 600, `-.025em`, tinted TLD). There is no symbol in the source — the wordmark *is* the mark. |
| `assets/mark.svg`, `build/favicon.svg`, `build/apple-touch-icon.svg`, `build/site.webmanifest` | **Derived.** The source declares no icon at all. Composed from the page's own two graphic devices (the filing tab, the volt rule) using registered tokens only. Replace if real icon artwork is ever produced, and update this row. |

No font files are preserved from source, because the source has none to preserve. All three
type stacks — `Iowan Old Style`/`Charter`/`Georgia`, `system-ui`, `ui-monospace`/`SF Mono` —
resolve locally with documented fallbacks.

### Type audit — decided (2026-07-29)

A post-assembly review tested the one claim the package made about type but had never
verified: that resolving locally is good enough. It was not, and the findings are recorded
here because they are defects in the *source*, not in the extraction:

- **The display face is unspecified in practice.** The stack lands on Iowan Old Style (macOS), Georgia (Windows), or the generic `serif`/Noto Serif (Android) — three different voices for the same brand.
- **Georgia breaks the system's own figure rule.** Classic Georgia's default numerals are old-style: `3 4 5 7 9` descend and `0 1 2` sit at x-height, so the ledger's volt `$0` — the number the lead investigation turns on — renders at roughly two-thirds of its designed size. Verified by render, not asserted.
- **`font-variant-numeric: lining-nums` does not fix it.** Classic Georgia ships no `lnum` feature, so there is nothing to switch to. Also verified by render: the corrected row is pixel-identical to the uncorrected one.
- **The mono carries ~18 distinct roles** — more than the serif and sans combined — and is equally unspecified (`ui-monospace` → SF Mono / Cascadia Mono / Roboto Mono). Its `.16em` and `.11em` tracking was tuned on one face.
- **The 9px stamp was the size floor** and the only type in the system below 10px, while carrying status information. Raised to 10px.

`preview/type-audit.html` sets all of this in live type and compared three self-hosted
candidates (Charis SIL 28 KB · Source Serif 4 119 KB · Newsreader 129 KB).

**Decision, applied 2026-07-29 — Charis SIL.** A Bitstream Charter derivative, so binding
it guarantees a face the system already named at fallback position 2 rather than
introducing a new one; and at a quarter the weight of the variable options, which matters
more to a civic project than an optical-size axis. What changed:

| Change | Where |
|---|---|
| `@font-face` ×2 + `--serif` now leads with `'Charis SIL'` | `colors_and_type.css`, `index.html` |
| `Cambria` inserted ahead of `Georgia` — lining tabular figures if the webfont fails | both stacks |
| `--t-stamp` 9px → **10px**, declared as the system's size floor | `colors_and_type.css`, `index.html` |
| Mono tracking documented as a maximum, tolerance `.12em–.16em` | `colors_and_type.css`, `DESIGN.md` §3 |
| Font files + OFL 1.1 licence | `fonts/` |
| Colophon now reads "Set in Charis SIL" | `index.html` and every kit page |

**This is the one place the package edits its own evidence file.** `index.html` gained the
`@font-face` binding and the 10px stamp, growing 516 → 519 lines; the two script-range
references in `ui_kits/app/components.html` and `ui_kits/app/README.md` were recomputed
(431–480 → 434–483, 482–511 → 485–514). `examples/source-home-page.html` still holds the
**pre-binding** 516-line original, so the extraction audit trail is intact and the delta is
inspectable.

The two rejected faces stay in `fonts/candidates/` so the comparison remains re-renderable
— a decision record you can re-check rather than take on trust, which is the standard this
system applies to every other figure it publishes.

## Sample data in the applied kit

Figures on the `ui_kits/app/` surfaces are drawn from the source home page and its ALERG
prototype (197 keyword matches across its early 14-source case fixture, 43.23 ac split
23.22/20.01, $15M, 90.6% roll-calls, four 2021 exempt deeds, 25 declared conflict
mentions). The match and source figures are not live registry or warehouse totals.
Beyond that, the sampled table rows,
parcel numbers and open-request dates are demonstration content, scoped as such in each
page's own caption; the forms are not wired to a backend and say so. Nothing is presented
as a real metric that isn't one — which is the system's own rule, applied to itself.

---

## Refinement pass — re-measured against the linked source (2026-07-29)

The source project's metadata named a linked directory,
`/Users/nicholas/develop/lorain-data`, that no earlier pass had opened. It exists: a
Phoenix/Elixir civic-data pipeline with its own `PRODUCT.md`, `CONTEXT.md` and a 341-line
`DESIGN.md`. Reading it is what this pass added.

**Scope discipline held.** The user's standing instruction — derive the visual system from
`index.html` only — still governs **tokens**. The linked repo carries a *different*
registered design system ("The Map Room": paper/manila/recorder-red, Source Serif 4 + IBM
Plex) for the private operator surface. **None of its colour or type values entered this
package**, and none should: avonlake.city is the public face, the Map Room is the private
explorer. What the repo did supply is authoritative **domain, terminology and
accessibility** evidence, which is not a visual token.

### What the re-measurement changed

| Finding | Source | Change |
|---|---|---|
| `--forest` was doing three unrelated jobs with no name for any | Token-usage inventory of this package | Added a **semantic role layer**; migrated all of `app.css` and `preview/card.css` to roles |
| 8 tokens declared but never referenced (`--reg-3…6`, `--moss`, `--sp-8/11/12`, `--d-count`) | Same inventory | Register colours now **read from `--reg-*`** in `app.js` and `RecordField.jsx` instead of hardcoded hex; `--moss` became the dark-theme action colour |
| Product defines a **seven-state claim lifecycle**, not two | `CONTEXT.md` § Claim card | Status mapped onto three role tokens — still two colours, no new hue |
| Product defines a **four-step identity grade**, and retired the word *confidence* | `CONTEXT.md` § Identity grade | Added `--grade-1…4` on the shared ordinal ramp; documented "weakest endpoint, never strongest" |
| "Receipt" is stricter than this package claimed | `CONTEXT.md` § Receipts | Redefined as source · date · count · caveat; *"a mutable record id alone is not a receipt"* |
| Closed vocabulary with explicit *avoid* lists | `CONTEXT.md` § Language | DESIGN.md §8 rebuilt as a terminology table with an "never say" column |
| Stated bar is **WCAG 2.2 AA**, and a structurally complete **390px** layout | `PRODUCT.md` § Accessibility | New DESIGN.md §10; 390px checklist in IMPLEMENTATION.md (below every declared breakpoint) |
| Explicit anti-references | `PRODUCT.md` § Anti-references | Added to DESIGN.md §9 |
| Dark mode was documented as undefined | This package | Defined as an **opt-in extension** built from `--ink-band` and the source's own measured text ramps; three new values, each forced by a measurement |

### Still honestly out of scope

- **The Map Room's palette and type.** A different surface with a different audience.
- **`avonlake-city.html` / `alerg-case-file.html`.** Still targets, not sources.
- **`prefers-color-scheme`.** The source declares `color-scheme: light`; dark stays opt-in until a product decision says otherwise.
- **The terminology split.** The pipeline says *source*; the published page says *register*. Both are recorded as correct for their surface rather than one being "fixed" to match the other.

---

## Interface face bound (2026-07-29, round two)

Reviewing the applied kit, the user flagged Arial in the dark ledger's row labels and asked
for a more dynamic face plus "any needed follow on changes for consistency of design."

**The finding was the one round one had already made, left unapplied to a second role.** The
sans was still resolving to whatever the OS owned — SF Pro, Segoe UI, Roboto, or a
Liberation/Arial metric clone — with `Arial` at the end of the declared chain. The earlier
reasoning for leaving it ("the sans carries short strings that benefit from feeling native")
does not survive contact with the actual usage: the sans carries every lede, all card prose,
every panel key and every ledger label. It is the most-read face in the system.

**Bound to IBM Plex Sans** (IBM Corp., OFL 1.1), one variable file, 400–600, **40 KB**.
Total font payload is now 68 KB across two faces.

| Why this face | Evidence |
|---|---|
| Humanist rather than neutral-grotesque — flared terminals, tailed `l`, distinctly drawn `a`/`g` | Answers the "more dynamic than Arial" brief without becoming decorative |
| Comfortable at 13.5px UI density | The system's dominant interface size |
| **The sibling product already declares it** | `lorain-data/DESIGN.md` names `"IBM Plex Sans"` for body — the public site and the private Map Room now share an interface voice while keeping their own display faces |

Libre Franklin (29 KB) was the runner-up — lighter and arguably more editorial, but tighter
at small sizes and with nothing outside this package pointing at it. Evidence beat 11 KB.

`Arial` was removed from the `--sans` chain outright; `system-ui` covers every modern
platform and the generic `sans-serif` tail is a better last resort.

**Scope note.** The change was requested against one marked element in `ui_kits/app/index.html`,
but the user explicitly asked for follow-on changes "for consistency of design" — so it was
applied at the token layer and propagated. Changing one component's face would have produced
exactly the inconsistency the instruction asked to avoid.

`index.html` grew 519 → **521 lines** (the second `@font-face`), so the two script-range
references shifted again: record field `434–483` → **`437–485`**, count-up + reveal
`485–514` → **`487–516`**. `examples/source-home-page.html` still holds the pre-binding
516-line original.

---

## Readiness audit (2026-07-29)

Before publishing or reusing the system elsewhere, it was audited by a written
tool rather than by eye — `tools/audit-readiness.py`, ten checks, no dependencies,
each one comparing what the package *claims* against what it *does*. The tool
ships with the package so readiness stays re-checkable.

**Five failures found and fixed:**

| Failure | Detail | Fix |
|---|---|---|
| Broken reference | `DESIGN.md`, `index.html` and `colors_and_type.css` still pointed at `fonts/OFL-CharisSIL.txt`, renamed to `OFL-CharisSIL.txt` when the second face was bound | Paths corrected |
| Contrast, light | `--ink-margin` **was** 4.31:1 on `--evidence-inset` — a text role failing AA on one of the three surfaces it may legally sit on | `--meta` darkened `#5f7368` → `#596d62`; now 5.14 / 5.54 / 4.71 |
| Contrast, dark | `--ink-margin` **was** 3.89:1 on the dark inset | Lifted `#8ba489` → `#9fb2a3`; now 6.86 / 5.68 / 4.69 |
| Contrast, dark — **live, not theoretical** | `--action` (`--moss`) **was** 3.74:1 on `--evidence-inset`, and the record table's header text is `--action` on exactly that surface | Lifted past moss to `#7fbc8a` (6.93 / 5.74 / 4.73); `--action-strong` moved to `#a1cea9` so hover still goes lighter in dark |
| Size floor | `.panel-top .pl` was 9.5px, below the 10px floor declared in the previous pass | Raised to 10px in `app.css` and `index.html` |

**Docs-vs-code drift found by the upgraded anchored check** — stale ratios printed
beside the tokens whose values had just moved, in `DESIGN.md`, `IMPLEMENTATION.md`,
`colors_and_type.css`, `preview/colors-primary.html`, `preview/theme-light-dark.html`
and this file. All corrected. The checker now anchors each printed figure to the
tokens named on its line, so a stale number can no longer survive by coincidentally
matching an unrelated pair.

**Two warnings resolved:** eleven layout/sub-part selectors were styled but
undocumented (now a table in `DESIGN.md` §6); and the kit index used a second
`.feat` band as a decorative surround for the React demo, violating the
one-dark-band-per-page rule (now `.demo-dark`).

**One warning left standing, by design:** this package does not use the generic
`brand.json` / `variables.css` / `theme.json` / `kit.html` / `kit.dark.html`
filenames. The mapping is documented at the top of `README.md`. Renaming was
rejected — the current names say what each file holds, and the audit reports the
mapping every run so nobody has to guess.

Result: **9 passed · 1 informational warning · 0 failures.**

---

## Gap closure (2026-07-29)

The readiness audit shipped with seven stated gaps. All seven are now closed or
converted into a standing decision, and each fix is verified rather than asserted.

| Gap | Closed by |
|---|---|
| **390px never verified** | `preview/narrow-390.html` renders all six surfaces in real 390px frames. It exposed three failures that only exist at that width — the record table pushed the *page* sideways (its `overflow-x` started at 960px), panel rows crowded their 21px serif figure, and filing-tab labels could clip. Fixed at a new **≤430px** breakpoint, the fifth and the first one designed rather than inherited. The auditor now fails the package if that breakpoint or `.rt-scroll` disappears. |
| **Target pages unmigrated** | `avonlake-city.html` and `alerg-case-file.html` both migrated off the superseded burgundy direction: legacy `:root` replaced by a documented migration shim that aliases their old names onto system **roles**, plus 37 hardcoded literals mapped. **Zero superseded hex survives in either file.** Both now consume `colors_and_type.css` + `tokens.css` and both bound faces. Their *components* are still the old markup — this was a token and type migration, and the shim is designed to be deleted alias-by-alias as components are rebuilt. |
| **Dark unproven on 4 kit surfaces** | The persisted, no-flash theme toggle is now on every kit page, not just the index. |
| **React binding had no SRI** | All three pinned scripts carry `integrity="sha384-…"` + `crossorigin="anonymous"`. |
| **Touch targets asserted, not measured** | The auditor now computes rendered control height from padding + font-size + border. It immediately disproved the docs: buttons are **40px**, not the 42px claimed. Corrected in `DESIGN.md` and `IMPLEMENTATION.md` — WCAG 2.2 AA's real bar is 24×24 CSS px, cleared comfortably, and the 44px touch surface comes from the 44–52px row, not the control. The source's `12px 18px` button padding was preserved rather than inflated to hit a number. |
| **`--rule` at 1.29:1** | Converted from a caveat into a token. **`--rule-strong`** (`--leaf`, 3.70:1 canvas / 3.99:1 evidence) now carries form-control edges and the selected tab — a genuine WCAG 1.4.11 gap, since a 1.29:1 hairline was standing in for "this is an input". `--sage` was the obvious pick and was rejected at 2.11:1. |
| **`prefers-color-scheme` unwired** | Unchanged, and staying that way: it is a product decision, not a defect. The one-line change is documented in `IMPLEMENTATION.md` §3. |

### Also surfaced while closing them

- **A blue was hiding in the dashboard.** The map used `#d7e2ea` for water — a second hue, which is this system's first anti-pattern. Both map fills are now roles (`--map-water` → `--pale`, `--map-land` → `--border-soft`), so the map stays inside the one-hue rule with 1.39:1 separation and no new colour.
- **The auditor grew from ten checks to thirteen**: the narrow breakpoint, computed target size, and focus-ring presence. Each was added because the corresponding gap could otherwise silently reappear.
- **Two false claims were caught by the upgraded checker and corrected before shipping** — a `--rule-strong` comment that previously asserted 3.36:1 for a value which was really 2.11:1, and a map-separation figure that was written as 1.50:1 when it was actually 1.39:1. Both were caught by the tool, not by eye, which is the point of shipping the tool.

Final state: **13 passed · 1 informational warning · 0 failures** (`tools/audit-readiness.py`),
and the OD package audit clean across 158 files.

---

## Closing what was left (2026-07-29, later pass)

The gap-closure pass ended with two things still open, both stated plainly rather
than hidden: the target pages carried system tokens but legacy component markup,
and the audit still emitted one informational warning about filenames. Both are
now closed, and neither was closed by lowering the bar.

### 1. The target pages are rebuilt, not re-coloured

The migration shim is **deleted** from both `avonlake-city.html` and
`alerg-case-file.html`. Each page now loads
`colors_and_type.css` → `tokens.css` → `ui_kits/app/app.css` and is composed from
system components. What remains in a page-local `<style>` is composition plus two
devices that belong to one page only — the council calendar and the schematic
context map — and it declares no colour and no type of its own.

The rebuild was not a translation. Several things the old markup was doing turned
out to contradict documents this package had already published:

| Found | Why it was wrong | Now |
|---|---|---|
| "Confidence: High / Medium" on every KPI card | The product **retired the word "confidence"** — `IMPLEMENTATION.md` §4 says it conflated identity with assertion strength — yet the flagship page led with it four times. | `.stamp` carrying a real lifecycle state: `Corroborated`, `Records requested`, `Open`. |
| A conic-gradient donut for "90.6% parseable" | A decorative chart with no denominator on screen; `DESIGN.md` §9 names both. | A labelled `.sbar` — 96 of 106, stated above and below. |
| KPI cards *and* a tab bar both driving the same panels | Two controls for one state, neither with tab semantics. | One `.cat.four` tablist of filing-tab cards with `role="tab"`, `aria-controls`, roving `tabIndex`, ←/→ keys, and panels toggled by the native `hidden` attribute. |
| `#4a6274` on the map and `font-family="Georgia"` in the SVG | A **blue** and an unbound face, inside an SVG where no palette review would ever look. This is the second hidden hue this file has produced. | `--ink-quiet` and `var(--serif)`. |
| A colophon describing "civic burgundy, shoreline orange and charcoal… Iowan Old Style / Charter / Georgia… see `brand-spec.md`" | Every word of it had been false since the redesign, on the page that claims to document the system. | A colophon describing the system that actually ships, pointing at `DESIGN.md`. |

**Four components were added, each because a real page could not be built without
it** — never speculatively, which is the rule `DESIGN.md` §6 now states:

- `.brow` — the labelled bar row. The `.sbar` fill logic unrolled into a list; every row states its own value so it reads without an axis.
- `.gaps` — the stated-limits list. The source's method step 06 is *"What we can't show"*, so the shape was already the system's; it just wasn't a component, which meant every page re-invented it.
- `.ic[aria-selected]` + `.fig` — the filing-tab card promoted to a track selector, with an optional serif tabular figure slot.
- `.stamp.quiet` — **the neutral chip that had been specified but never built.** `IMPLEMENTATION.md` §4 has mapped `draft` / `open` / `withdrawn` onto a neutral chip since the refinement pass, and `--status-quiet` / `--status-quiet-bg` were measured at 4.60:1 — but no class consumed them. It was a documented state with no implementation until a rebuilt page needed to render an absent council member.

### 2. The filename warning is answered, not argued with

The previous pass considered generating `brand.json` / `variables.css` /
`theme.json` / `kit.html` / `kit.dark.html` and rejected it, on the grounds that
the canonical names say what each file holds. That reasoning still stands — and
it was the wrong conclusion, because it answered a tooling question with a
naming argument.

All five now exist at the package root as **generated exports**, written by
`tools/export-artifacts.py` from the canonical sources:

- `brand.json` — every primitive and role with its resolved hex and **contrast measured on all three surfaces**, the type stacks and scale, spacing/radius/motion, the five breakpoints, and the six rules parsed out of `README.md` so the prose and the JSON cannot disagree.
- `variables.css` — the flattened variable surface, extracted from the live `:root` and `[data-theme="dark"]` blocks.
- `theme.json` — both themes' resolved roles, the measured contrast grid, and the persistence contract.
- `kit.html` / `kit.dark.html` — the kit, path-rewritten for the root; the dark one forced rather than persisted.

The thing that makes this safe rather than a second copy of the truth is check
14: the auditor **regenerates all five in memory and fails if what is on disk
differs**. An export edited by hand, or left behind when a token moved, is a
build failure. There is exactly one source of truth for every value in them, and
it is never the export.

### Verified

- `python3 tools/audit-readiness.py` → **14 passed · 0 warnings · 0 failures**
- Both rebuilt pages rendered and reviewed at full length; tag balance checked on all four generated and rebuilt HTML files.
- Component count synchronised across `README.md`, `ui_kits/app/README.md`, `ui_kits/app/index.html`, `ui_kits/app/components.html` and `preview/applied-ui.html`: **21 components, 14 read from the source, 7 derived.**
