@hirobius/design-system 0.20.0 → 0.22.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 (130) hide show
  1. package/AGENTS.md +125 -0
  2. package/CHANGELOG.md +969 -0
  3. package/CONSUMING.md +27 -11
  4. package/DESIGN.md +28 -17
  5. package/MIGRATIONS.md +603 -0
  6. package/NOTICE.md +1 -1
  7. package/README.md +39 -5
  8. package/UPGRADING.md +222 -0
  9. package/codemods/hds-prefix.mjs +28 -13
  10. package/codemods/jsx-fold.mjs +28 -13
  11. package/codemods/lib/atomic-write.mjs +28 -0
  12. package/codemods/lib/installed-version.mjs +354 -0
  13. package/codemods/lib/project.mjs +395 -0
  14. package/codemods/lib/record.mjs +110 -0
  15. package/codemods/lib/scan.mjs +323 -0
  16. package/codemods/lib/semver.mjs +57 -0
  17. package/codemods/not-found-pattern.mjs +3 -3
  18. package/codemods/patterns-subpath.mjs +28 -12
  19. package/codemods/registry.mjs +67 -0
  20. package/codemods/tile-grid.mjs +3 -3
  21. package/codemods/upgrade.mjs +909 -0
  22. package/dist/chunks/empty-state-DNoThgfV.js +1227 -0
  23. package/dist/chunks/form-By82qZcC.js +66 -0
  24. package/dist/fonts/geist-mono-400.woff2 +0 -0
  25. package/dist/fonts/satoshi-400.woff2 +0 -0
  26. package/dist/fonts/satoshi-500.woff2 +0 -0
  27. package/dist/fonts/satoshi-700.woff2 +0 -0
  28. package/dist/fonts.css +53 -0
  29. package/dist/form.js +1 -1
  30. package/dist/hirobius-ui.js +876 -877
  31. package/dist/manifest.js +3 -3
  32. package/dist/patterns.js +189 -170
  33. package/dist/styles.css +2 -2
  34. package/dist/tokens.css +1 -1
  35. package/dist/tokens.js +136 -57
  36. package/dist/types/src/app/components/alert-dialog.d.ts +5 -0
  37. package/dist/types/src/app/components/alert.d.ts +1 -1
  38. package/dist/types/src/app/components/asset-img.d.ts +1 -0
  39. package/dist/types/src/app/components/avatar-group.d.ts +1 -0
  40. package/dist/types/src/app/components/avatar.d.ts +1 -1
  41. package/dist/types/src/app/components/badge.d.ts +2 -2
  42. package/dist/types/src/app/components/blockquote.d.ts +1 -0
  43. package/dist/types/src/app/components/breadcrumb.d.ts +1 -1
  44. package/dist/types/src/app/components/button.d.ts +3 -1
  45. package/dist/types/src/app/components/callout.d.ts +1 -1
  46. package/dist/types/src/app/components/card.d.ts +4 -3
  47. package/dist/types/src/app/components/checkbox.d.ts +1 -1
  48. package/dist/types/src/app/components/code-block.d.ts +1 -1
  49. package/dist/types/src/app/components/combobox.d.ts +1 -1
  50. package/dist/types/src/app/components/data-table-section.d.ts +1 -0
  51. package/dist/types/src/app/components/destructive-section.d.ts +1 -0
  52. package/dist/types/src/app/components/dialog.d.ts +2 -1
  53. package/dist/types/src/app/components/disclosure.d.ts +1 -1
  54. package/dist/types/src/app/components/divider.d.ts +1 -1
  55. package/dist/types/src/app/components/empty-state.d.ts +1 -1
  56. package/dist/types/src/app/components/error-pattern.d.ts +6 -1
  57. package/dist/types/src/app/components/field.d.ts +1 -1
  58. package/dist/types/src/app/components/form-actions.d.ts +1 -0
  59. package/dist/types/src/app/components/form-control.d.ts +10 -0
  60. package/dist/types/src/app/components/form.d.ts +1 -1
  61. package/dist/types/src/app/components/grid.d.ts +5 -0
  62. package/dist/types/src/app/components/hds-tooltip.d.ts +1 -1
  63. package/dist/types/src/app/components/icon.d.ts +1 -0
  64. package/dist/types/src/app/components/inline-link.d.ts +1 -1
  65. package/dist/types/src/app/components/input.d.ts +1 -1
  66. package/dist/types/src/app/components/kbd.d.ts +1 -0
  67. package/dist/types/src/app/components/menu.d.ts +1 -1
  68. package/dist/types/src/app/components/metadata-list.d.ts +1 -0
  69. package/dist/types/src/app/components/metric-tiles.d.ts +1 -0
  70. package/dist/types/src/app/components/pagination.d.ts +1 -1
  71. package/dist/types/src/app/components/popover.d.ts +1 -1
  72. package/dist/types/src/app/components/progress.d.ts +2 -2
  73. package/dist/types/src/app/components/radio.d.ts +1 -1
  74. package/dist/types/src/app/components/select.d.ts +1 -1
  75. package/dist/types/src/app/components/skeleton.d.ts +2 -2
  76. package/dist/types/src/app/components/slider.d.ts +1 -1
  77. package/dist/types/src/app/components/spinner.d.ts +1 -1
  78. package/dist/types/src/app/components/stat.d.ts +5 -4
  79. package/dist/types/src/app/components/status-list-item.d.ts +1 -1
  80. package/dist/types/src/app/components/status-tile.d.ts +4 -3
  81. package/dist/types/src/app/components/table.d.ts +6 -1
  82. package/dist/types/src/app/components/tabs.d.ts +1 -1
  83. package/dist/types/src/app/components/tag.d.ts +1 -1
  84. package/dist/types/src/app/components/text.d.ts +53 -6
  85. package/dist/types/src/app/components/textarea.d.ts +1 -1
  86. package/dist/types/src/app/components/timestamp.d.ts +1 -0
  87. package/dist/types/src/app/components/toast.d.ts +1 -1
  88. package/dist/types/src/app/components/toggle.d.ts +1 -1
  89. package/dist/types/src/app/data/manifest-types.d.ts +4 -0
  90. package/dist/types/src/app/design-system/generated-token-refs.d.ts +37 -28
  91. package/dist/types/src/app/design-system/generated-token-values.d.ts +3 -0
  92. package/dist/types/src/app/design-system/tokens.d.ts +117 -15
  93. package/dist/types/src/index.d.ts +122 -72
  94. package/dist/variables.css +41 -33
  95. package/docs/CONSUMING.md +63 -39
  96. package/hirobius.tokens.json +163 -112
  97. package/llms.txt +158 -50
  98. package/mcp/catalog.mjs +369 -0
  99. package/mcp/core-set.mjs +66 -0
  100. package/mcp/guide.mjs +272 -0
  101. package/mcp/hds-mcp.mjs +49 -0
  102. package/mcp/server.mjs +94 -0
  103. package/package.json +53 -11
  104. package/public/hds-manifest.json +430 -336
  105. package/public/llms/components.txt +4 -3
  106. package/public/llms/layout.txt +1 -1
  107. package/public/llms-full.txt +190 -70
  108. package/public/llms.txt +158 -50
  109. package/scripts/eslint-plugin-hds/index.d.mts +29 -0
  110. package/scripts/eslint-plugin-hds/index.mjs +55 -0
  111. package/scripts/eslint-plugin-hds/package.json +30 -0
  112. package/scripts/eslint-plugin-hds/rules/no-raw-controls.mjs +47 -0
  113. package/scripts/eslint-plugin-hds/rules/no-raw-hex.mjs +70 -0
  114. package/scripts/eslint-plugin-hds/rules/no-raw-px-spacing.mjs +125 -0
  115. package/scripts/eslint-plugin-hds/rules/prefer-hds-layout-primitive.mjs +54 -0
  116. package/scripts/eslint-plugin-hds/rules/sx-token-first.mjs +111 -0
  117. package/scripts/eslint-plugin-hds/rules/utils.mjs +66 -0
  118. package/src/app/data/component-api.json +154 -93
  119. package/upgrade/index.json +208 -0
  120. package/upgrade/releases/0.17.0.json +962 -0
  121. package/upgrade/releases/0.18.0.json +8 -0
  122. package/upgrade/releases/0.19.0.json +233 -0
  123. package/upgrade/releases/0.19.1.json +8 -0
  124. package/upgrade/releases/0.20.0.json +5108 -0
  125. package/upgrade/releases/0.21.0.json +538 -0
  126. package/upgrade/releases/0.22.0.json +94 -0
  127. package/upgrade/schema.json +989 -0
  128. package/dist/chunks/empty-state-BBqhCx0S.js +0 -1217
  129. package/dist/chunks/form-COP3vK9_.js +0 -66
  130. package/dist/types/src/app/components/status-dot.d.ts +0 -39
package/CONSUMING.md CHANGED
@@ -29,6 +29,7 @@ version keeps the `LucideIcon` type identical).
29
29
  ```tsx
30
30
  import { Button, Card, Dialog } from '@hirobius/design-system';
31
31
  import '@hirobius/design-system/tokens.css'; // required — design tokens as CSS vars
32
+ import '@hirobius/design-system/fonts.css'; // optional — the HDS brand fonts (Satoshi, Geist Mono)
32
33
 
33
34
  export function Example() {
34
35
  return (
@@ -43,7 +44,8 @@ Available subpaths:
43
44
 
44
45
  | Import | What |
45
46
  | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
46
- | `@hirobius/design-system` | The core components and templates (the `pattern` tier is only in `/patterns`) |
47
+ | `@hirobius/design-system` | The 43-component core set ([README → What belongs in the system](README.md#what-belongs-in-the-system)), the rest of the allow-list and the templates; the `pattern` tier is only in `/patterns` |
48
+ | `@hirobius/design-system/fonts.css` | Optional brand fonts (Satoshi, Geist Mono); woff2 files ship in the package, relative URLs, `font-display: swap` |
47
49
  | `@hirobius/design-system/tokens.css` | Token CSS variables (import once at app root) |
48
50
  | `@hirobius/design-system/tokens` | Token values as TS constants |
49
51
  | `@hirobius/design-system/cn` | `cn()` class-merge helper |
@@ -51,7 +53,7 @@ Available subpaths:
51
53
  | `@hirobius/design-system/contexts` | Theme / language / tenant / font providers |
52
54
  | `@hirobius/design-system/brand` | Palette → HDS-semantic overlay bridge (static / SSR / Astro; see [`docs/CONSUMING.md` §12](docs/CONSUMING.md#12-static-astro-sites--the-brand-overlay-bridge)) |
53
55
  | `@hirobius/design-system/scroll` | Opt-in scroll-motion primitives — `SmoothScroll` (Lenis), `useScrollProgress` (Motion). Requires the optional peer `lenis`. See [`docs/CONSUMING.md` §13](docs/CONSUMING.md#13-scroll-motion-the-scroll-subpath) |
54
- | `@hirobius/design-system/patterns` | The `pattern`-tier components (nav shells, feeds, rails, pickers — see hds#254). The only entry that exports them: 0.20.0 removed their root re-exports (the `hds-patterns-subpath` codemod, see MIGRATIONS.md). |
56
+ | `@hirobius/design-system/patterns` | The 12 pattern modules: the hds#254 `pattern` tier (page shells, forms, code blocks, page sections). The only entry that exports them: 0.20.0 removed their root re-exports (the `hds-patterns-subpath` codemod, see MIGRATIONS.md). |
55
57
  | `@hirobius/design-system/icons` | Curated Lucide icon set for `Icon`, and so for `Button iconOnly` (`Ellipsis`, `Pencil`, `Trash2`, `X`, …). Names listed in the manifest `iconSet`. |
56
58
  | `@hirobius/design-system/static.css` | CSS-only static-primitive layer — `.hds-badge`/`.hds-card`/`.hds-alert`/`.hds-divider`/`.hds-tag` classes, no React. See [`docs/CONSUMING.md` §14](docs/CONSUMING.md#14-css-only-static-primitives--badgecardalertdividertag-with-no-react) |
57
59
 
@@ -106,18 +108,32 @@ The same files are served at <https://hirobius-design-system.vercel.app/llms.txt
106
108
 
107
109
  ## 3. Receiving updates
108
110
 
109
- Releases follow [semver](https://semver.org/) and are tracked in
110
- `CHANGELOG.md`. To update:
111
+ Releases follow [semver](https://semver.org/). Below 1.0 a breaking change
112
+ ships in a 0.x minor, which `pnpm update` and a caret range such as `^0.21`
113
+ never pick up, so upgrade to an exact version.
114
+
115
+ From 0.22.0, one command does it:
111
116
 
112
117
  ```bash
113
- pnpm update @hirobius/design-system # latest within your version range
118
+ npx @hirobius/design-system@latest upgrade
114
119
  ```
115
120
 
116
- For a breaking release, bump the version explicitly and review the CHANGELOG
117
- entry. Before 1.0 a breaking change (a removed export or token) ships in a 0.x
118
- minor, which a caret range such as `^0.19` never picks up; from 1.0 on it ships
119
- in a major. Each removal is listed in [MIGRATIONS.md](MIGRATIONS.md) with its
120
- replacement and, where one applies, a codemod (ADR-014).
121
+ It finds the version you have, moves you to the newest release, runs the
122
+ codemods and lists what is left to do by hand.
123
+
124
+ Until then, upgrade by hand with [UPGRADING.md](UPGRADING.md), which also ships
125
+ in the package:
126
+
127
+ 1. Install the exact version: `pnpm add @hirobius/design-system@<version>`.
128
+ 2. For each release you cross, run the codemods UPGRADING.md lists under
129
+ "Fixed for you".
130
+ 3. Work through its "Do by hand" list.
131
+
132
+ UPGRADING.md covers every release after 0.16.0. From an older version, first
133
+ reach 0.16.0 with the notes in [CHANGELOG.md](CHANGELOG.md);
134
+ [MIGRATIONS.md](MIGRATIONS.md) has longer guides for the big releases.
135
+ `CHANGELOG.md` has the full notes, and each section from 0.22.0 on opens with
136
+ an Upgrade block.
121
137
 
122
138
  ---
123
139
 
@@ -125,7 +141,7 @@ replacement and, where one applies, a codemod (ADR-014).
125
141
 
126
142
  ```bash
127
143
  pnpm changeset add # record a patch/minor/major bump + notes
128
- pnpm changeset:version # apply bumps + regenerate CHANGELOG.md + refresh docs/api/api-baseline.json
144
+ pnpm changeset:version # apply bumps, regenerate CHANGELOG.md, record the release (scripts/upgrade/compile.mjs) and refresh docs/api/api-baseline.json
129
145
  # commit + push to main → the Release workflow publishes to public npm
130
146
  ```
131
147
 
package/DESIGN.md CHANGED
@@ -28,28 +28,29 @@ Feedback hues are never decorative; do not use them as accents. Light and dark m
28
28
  <!-- auto:start:typography -->
29
29
  HDS ships three typefaces — each with a distinct and exclusive role:
30
30
 
31
- - **Display / Heading font**: Satoshi. Bound exclusively to `display`, `h1`, `h2`, and `h3` styles. Never used for body copy or UI labels.
31
+ - **Display / Heading font**: Satoshi. Bound exclusively to the `display` and `title` styles. Never used for body copy or UI labels.
32
32
  - **Body / UI font**: Satoshi. All prose, labels, small text, captions, and UI copy.
33
33
  - **Mono font**: Geist Mono. Reserved for tokens, code, technical callouts, and metric readouts.
34
34
 
35
- Weights declared: `400` regular, `500` medium, `700` bold. Heading styles (display · h1 · h2 · h3) use `700` bold; body, UI, and caption use `500` medium. Declared but unused by any semantic role: `400` regular.
35
+ Weights declared: `400` regular, `500` medium, `700` bold. Heading styles (display · title) use `700` bold; body, UI, and caption use `400` regular / `500` medium.
36
36
 
37
37
  ### Type ramp
38
38
 
39
39
  | Role | Size (desktop max) | Weight | Use |
40
40
  | --- | --- | --- | --- |
41
- | `semantic.typography.display` | 60px | 700 | Display headline |
42
- | `semantic.typography.h1` | 48px | 700 | Primary section headings (h1) |
43
- | `semantic.typography.h2` | 30px | 700 | Secondary section headings (h2) |
44
- | `semantic.typography.h3` | 20px | 700 | Component and card headers (h3) |
45
- | `semantic.typography.body` | 16px | 500 | Body prose |
46
- | `semantic.typography.ui` | 14px | 500 | UI text for nav, labels, captions |
47
- | `semantic.typography.caption` | 12px | 500 | Caption / helper text |
48
- | `semantic.typography.eyebrow` | 12px | 500 | Eyebrow / kicker label |
49
- | `semantic.typography.mono` | 14px | 400 | Monospace for code, token names, shortcuts |
41
+ | `semantic.typography.display` | 48px | 700 | One per page, hero only |
42
+ | `semantic.typography.title` | 24px | 700 | Section and card headings |
43
+ | `semantic.typography.body` | 16px | 400 | Prose |
44
+ | `semantic.typography.ui` | 14px | 500 | Controls, nav, table text, values |
45
+ | `semantic.typography.caption` | 12px | 500 | Metadata, help text and labels, in sentence case |
46
+ | `semantic.typography.mono` | 13px | 400 | Code and ids |
47
+ | `semantic.typography.h1` | 24px | 700 | deprecated: use semantic.typography.title |
48
+ | `semantic.typography.h2` | 24px | 700 | deprecated: use semantic.typography.title |
49
+ | `semantic.typography.h3` | 24px | 700 | deprecated: use semantic.typography.title |
50
+ | `semantic.typography.eyebrow` | 12px | 500 | deprecated: use semantic.typography.caption |
50
51
  | `semantic.typography.lineHeight.none` | | | Semantic alias for leading-none (1) |
51
52
 
52
- > Responsive `clamp()` overrides live in `src/styles/theme.css`; tokens store the desktop-max static value.
53
+ > The ramp is static: tokens store the value every surface renders. `h1`, `h2`, `h3` and `eyebrow` are deprecated aliases and go in 1.0.0.
53
54
  <!-- auto:end:typography -->
54
55
 
55
56
  ## Spacing
@@ -59,9 +60,19 @@ Weights declared: `400` regular, `500` medium, `700` bold. Heading styles (displ
59
60
 
60
61
  Scale: `0px` (`primitive.space.0`) · `1px` (`primitive.space.px1`) · `2px` (`primitive.space.px2`) · `4px` (`primitive.space.1`) · `6px` (`primitive.space.px6`) · `8px` (`primitive.space.2`) · `10px` (`primitive.space.px10`) · `12px` (`primitive.space.3`) · `16px` (`primitive.space.4`) · `20px` (`primitive.space.5`) · `24px` (`primitive.space.6`) · `28px` (`primitive.space.7`) · `32px` (`primitive.space.8`) · `40px` (`primitive.space.10`) · `48px` (`primitive.space.12`) · `64px` (`primitive.space.16`) · `80px` (`primitive.space.20`) · `96px` (`primitive.space.24`) · `128px` (`primitive.space.32`)
61
62
 
62
- Use `primitive.space.*` for layout rhythm, padding, and gaps. Use `semantic.space.*` aliases (e.g. `semantic.space.surface.padding`) when the purpose is established. `data-density="compact"` (on `<html>` or the `[data-hds]` scope element) remaps `semantic.space.scale.*`, `semantic.space.surface.padding` and `semantic.space.region.gutter` one step down the scale, and `Table` follows it. The `--hds-space-{xs…4xl}` vars are a legacy bridge that no component reads.
63
+ Layout rhythm, padding, and gaps use the `semantic.space.scale.{xs…xl}` steps (and `none`), never a raw `primitive.space.*` value or a numeric Tailwind class; `primitive.space.*` is the ramp behind the scale. Use `semantic.space.*` aliases (e.g. `semantic.space.surface.padding`) when the purpose is established. `data-density="compact"` (on `<html>` or the `[data-hds]` scope element) remaps `semantic.space.scale.*`, `semantic.space.surface.padding` and `semantic.space.region.gutter` one step down the scale, and `Table` follows it. The `--hds-space-{xs…4xl}` vars are a legacy bridge that no component reads.
63
64
  <!-- auto:end:spacing -->
64
65
 
66
+ ## Layout contract (v1)
67
+
68
+ Approved 2026-10-07. Data: `docs/guardrails/layout-contract.json`; gates: `pnpm check:layout-contract` and `pnpm check:spacing-scale` (warn mode; baseline in `docs/audits/layout-contract-baseline.md`).
69
+
70
+ 1. **Sizing.** Every component declares `fill` or `hug` on each axis. Leaves hug. Input, Textarea, Select, Combobox, Table, Progress and Divider fill width. One override prop, `width="hug|fill"`, on every component. Height always hugs; stretching is the parent's job (`align="stretch"`). No component sets `h-full`, `height: 100%` or `self-*` on its root.
71
+ 2. **Padding.** Only containers pad: Card, Surface, Alert, Callout, Dialog, Page. Compound parts (`Card.Header`, `Body`, `Footer`, `Metric`) have zero padding and the container's `gap` spaces them. Padding is `none | sm | md`, default `md`, density-aware. A padded container directly inside a padded container is an error unless the inner one is `padding="none"`.
72
+ 3. **Spacing.** One scale, `xs…xl` (plus `none`), for every `gap` and `padding` prop. Every gap defaults to `md`. No outer margins on any component; space between siblings is the parent's `gap`.
73
+ 4. **Primitives.** Stack, Grid, Page (absorbs Container) and Surface compose layouts. Box and Pin are escape hatches. Sidebar and Switcher fold into Stack and Grid.
74
+ 5. **Forms.** A form control in a form context has a max width (`40rem` by default) and siblings share one width.
75
+
65
76
  ## Corner-Radius Policy
66
77
 
67
78
  Shape is one knob. `semantic.radius.action` is the system's single shape value — interactive controls (buttons, inputs, badges, alerts, segmented items) all resolve to it, and Tailwind's `rounded-md` maps to it exactly so the utility and the token cannot disagree. Containers sit one step above at `rounded-lg` (`action + 4px`); `rounded-sm` (`action - 2px`) is for chrome nested inside a control. `full` is reserved for pills and circular forms, and `0px` only for intentional outer canvas or substrate boundaries, never everyday UI controls. Reshaping the whole system means overriding `role.radius` in one tenant overlay — that is how `brutalist-demo` goes square in a single value.
@@ -152,7 +163,7 @@ Every HDS card surface must conform to this anatomy exactly. No creative interpr
152
163
  | Border radius | `rounded-lg` (`role.radius` + 4 px: 12 px by default, follows the tenant) | `var(--component-card-radius)`, `rounded-full`, or any hard-coded value |
153
164
  | Padding | `var(--semantic-space-component-padding)` or `<HdsSurface padding="component">` | Raw pixel values or ad hoc insets |
154
165
  | Shadow | Resting cards: none (`elevation.flat`). Interactive lifted state: `shadow.subtle` via `elevation.raised` | Raw `box-shadow` values, `drop-shadow`, glow, or any depth effect not bound to a role token |
155
- | Title | `hds.typeStyles.heading3` / `<HdsText variant="heading3">` | Any other type style for the primary card heading |
166
+ | Title | `hds.typeStyles.title` / `<Text variant="title">` | Any other type style for the primary card heading |
156
167
  | Subtitle / meta | `hds.typeStyles.caption` + `var(--semantic-color-content-secondary)` | Primary content color or body size for secondary text |
157
168
  | Hover (interactive only) | `transform: scale(1.02)` | Background fill change, border color shift, or opacity fade on hover |
158
169
 
@@ -164,7 +175,7 @@ Five patterns sit above the primitives so that every screen is composed the same
164
175
 
165
176
  ### Page title rule
166
177
 
167
- Every screen has exactly one `PageHeader`. The page title is `heading2` (30px), a fixed size with no size prop; `level` changes only the DOM heading element. `display` and `h1` are reserved for marketing and landing surfaces and are never a screen title. Breadcrumb goes in the `breadcrumb` slot, one status `Badge` in `status`, screen-level actions in `actions`.
178
+ Every screen has exactly one `PageHeader`. The page title is `title` (24px), a fixed size with no size prop; `level` changes only the DOM heading element. `display` is reserved for marketing and landing surfaces and is never a screen title. Breadcrumb goes in the `breadcrumb` slot, one status `Badge` in `status`, screen-level actions in `actions`.
168
179
 
169
180
  ### Which one, when
170
181
 
@@ -185,7 +196,7 @@ Three more needs are props on an existing component, not components of their own
185
196
 
186
197
  `Card` and `Surface` share one container radius, `rounded-lg` (`role.radius` + 4 px: 12 px by default, 4 px under `brutalist-demo`). Dialogs and alert dialogs use it too. Never read `--component-card-radius` for a container; it ignores the tenant.
187
198
 
188
- `MetricTiles` has `min(tiles, 4)` columns, so a row never leaves an empty column, and every tile has one fixed min-height with the value in `heading2`, the label as an eyebrow and the sub line in `caption`. Its tone comes from the fixed feedback vocabulary: `neutral | success | warning | danger | info`.
199
+ `MetricTiles` has `min(tiles, 4)` columns, so a row never leaves an empty column, and every tile has one fixed min-height with the value in `title`, the label in `caption` and the sub line in `caption`. Its tone comes from the fixed feedback vocabulary: `neutral | success | warning | danger | info`.
189
200
 
190
201
  ### Destructive and table sections
191
202
 
@@ -217,6 +228,6 @@ Unresolved rules that the live repo cannot yet answer confidently are tracked in
217
228
  <!-- auto:start:build-meta -->
218
229
  ---
219
230
 
220
- > Generated from `hirobius.tokens.json` (385 tokens) and `public/hds-manifest.json` by `scripts/build-design-md.mjs`.
231
+ > Generated from `hirobius.tokens.json` (389 tokens) and `public/hds-manifest.json` by `scripts/build-design-md.mjs`.
221
232
  > Hand-edit `DESIGN.source.md`; this file (`DESIGN.md`) is overwritten by `pnpm tokens`.
222
233
  <!-- auto:end:build-meta -->