baseline-foundry 0.1.3

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 (145) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +588 -0
  3. package/config/experiments/ibm-plex-engine-smoke.json +115 -0
  4. package/config/experiments/ubuntu-engine-smoke.json +115 -0
  5. package/config/foundation-theme.json +117 -0
  6. package/config/tiers/app.json +120 -0
  7. package/config/tiers/documentation.json +120 -0
  8. package/config/tiers/editorial.json +120 -0
  9. package/config/tiers/os.json +120 -0
  10. package/dist/accordion.d.ts +5 -0
  11. package/dist/accordion.js +32 -0
  12. package/dist/application-layout.d.ts +4 -0
  13. package/dist/application-layout.js +181 -0
  14. package/dist/baseline-grid-overlay.d.ts +5 -0
  15. package/dist/baseline-grid-overlay.js +50 -0
  16. package/dist/baseline-grid-theme.d.ts +3 -0
  17. package/dist/baseline-grid-theme.js +3 -0
  18. package/dist/baseline-grid.d.ts +7 -0
  19. package/dist/baseline-grid.js +35 -0
  20. package/dist/build.d.ts +21 -0
  21. package/dist/build.js +440 -0
  22. package/dist/code-snippet.d.ts +6 -0
  23. package/dist/code-snippet.js +95 -0
  24. package/dist/contextual-menu.d.ts +4 -0
  25. package/dist/contextual-menu.js +156 -0
  26. package/dist/css-app-tier.d.ts +1 -0
  27. package/dist/css-app-tier.js +77 -0
  28. package/dist/css-components/article-pagination.d.ts +13 -0
  29. package/dist/css-components/article-pagination.js +151 -0
  30. package/dist/css-components/button-actions.d.ts +7 -0
  31. package/dist/css-components/button-actions.js +165 -0
  32. package/dist/css-components/cards-options.d.ts +6 -0
  33. package/dist/css-components/cards-options.js +180 -0
  34. package/dist/css-components/chip-badge-status.d.ts +10 -0
  35. package/dist/css-components/chip-badge-status.js +162 -0
  36. package/dist/css-components/content-card.d.ts +25 -0
  37. package/dist/css-components/content-card.js +517 -0
  38. package/dist/css-components/control-row.d.ts +2 -0
  39. package/dist/css-components/control-row.js +18 -0
  40. package/dist/css-components/cta-figure-aspect.d.ts +1 -0
  41. package/dist/css-components/cta-figure-aspect.js +123 -0
  42. package/dist/css-components/document-navigation.d.ts +13 -0
  43. package/dist/css-components/document-navigation.js +400 -0
  44. package/dist/css-components/editorial-content.d.ts +6 -0
  45. package/dist/css-components/editorial-content.js +52 -0
  46. package/dist/css-components/icon.d.ts +1 -0
  47. package/dist/css-components/icon.js +75 -0
  48. package/dist/css-components/interactive-feedback.d.ts +2 -0
  49. package/dist/css-components/interactive-feedback.js +230 -0
  50. package/dist/css-components/interactive-tables.d.ts +7 -0
  51. package/dist/css-components/interactive-tables.js +164 -0
  52. package/dist/css-components/linked-logo-site-layout.d.ts +21 -0
  53. package/dist/css-components/linked-logo-site-layout.js +214 -0
  54. package/dist/css-components/list-tree.d.ts +5 -0
  55. package/dist/css-components/list-tree.js +98 -0
  56. package/dist/css-components/list.d.ts +3 -0
  57. package/dist/css-components/list.js +119 -0
  58. package/dist/css-components/logo-media.d.ts +16 -0
  59. package/dist/css-components/logo-media.js +219 -0
  60. package/dist/css-components/navigation-layout.d.ts +5 -0
  61. package/dist/css-components/navigation-layout.js +151 -0
  62. package/dist/css-components/panel.d.ts +6 -0
  63. package/dist/css-components/panel.js +148 -0
  64. package/dist/css-components/search-box-and-filter.d.ts +9 -0
  65. package/dist/css-components/search-box-and-filter.js +267 -0
  66. package/dist/css-components/sites-editorial-ports.d.ts +19 -0
  67. package/dist/css-components/sites-editorial-ports.js +264 -0
  68. package/dist/css-components/sites-foundation.d.ts +17 -0
  69. package/dist/css-components/sites-foundation.js +173 -0
  70. package/dist/css-components/sites-rich-lists.d.ts +18 -0
  71. package/dist/css-components/sites-rich-lists.js +364 -0
  72. package/dist/css-components/static-content-ports.d.ts +14 -0
  73. package/dist/css-components/static-content-ports.js +206 -0
  74. package/dist/css-components/tab-section.d.ts +19 -0
  75. package/dist/css-components/tab-section.js +103 -0
  76. package/dist/css-components/table.d.ts +7 -0
  77. package/dist/css-components/table.js +79 -0
  78. package/dist/css-components/tabs-choice-breadcrumbs.d.ts +9 -0
  79. package/dist/css-components/tabs-choice-breadcrumbs.js +307 -0
  80. package/dist/css-components/tiered-list-equal-height-row.d.ts +1 -0
  81. package/dist/css-components/tiered-list-equal-height-row.js +286 -0
  82. package/dist/css-components.d.ts +2 -0
  83. package/dist/css-components.js +2701 -0
  84. package/dist/css-grid.d.ts +1 -0
  85. package/dist/css-grid.js +179 -0
  86. package/dist/css.d.ts +6 -0
  87. package/dist/css.js +431 -0
  88. package/dist/experiments/ibm-plex-engine-smoke/styles.css +8969 -0
  89. package/dist/experiments/ibm-plex-engine-smoke/surfaces.json +604 -0
  90. package/dist/experiments/ibm-plex-engine-smoke/tokens.json +217 -0
  91. package/dist/in-page-navigation.d.ts +7 -0
  92. package/dist/in-page-navigation.js +136 -0
  93. package/dist/index.d.ts +37 -0
  94. package/dist/index.js +18 -0
  95. package/dist/interactive-feedback.d.ts +14 -0
  96. package/dist/interactive-feedback.js +96 -0
  97. package/dist/interactive-tables.d.ts +28 -0
  98. package/dist/interactive-tables.js +184 -0
  99. package/dist/list-tree.d.ts +4 -0
  100. package/dist/list-tree.js +44 -0
  101. package/dist/panel-drawer.d.ts +4 -0
  102. package/dist/panel-drawer.js +171 -0
  103. package/dist/presets/app-tier/styles.css +9459 -0
  104. package/dist/presets/app-tier/surfaces.json +1225 -0
  105. package/dist/presets/app-tier/tokens.json +221 -0
  106. package/dist/presets/prose/styles.css +9442 -0
  107. package/dist/presets/prose/surfaces.json +1225 -0
  108. package/dist/presets/prose/tokens.json +221 -0
  109. package/dist/presets.d.ts +6 -0
  110. package/dist/presets.js +27 -0
  111. package/dist/range-controls.d.ts +9 -0
  112. package/dist/range-controls.js +73 -0
  113. package/dist/resizable-aside.d.ts +4 -0
  114. package/dist/resizable-aside.js +328 -0
  115. package/dist/side-navigation.d.ts +4 -0
  116. package/dist/side-navigation.js +219 -0
  117. package/dist/styles.css +9442 -0
  118. package/dist/surfaces.json +1225 -0
  119. package/dist/tabs.d.ts +4 -0
  120. package/dist/tabs.js +88 -0
  121. package/dist/tier-registry.d.ts +10 -0
  122. package/dist/tier-registry.js +25 -0
  123. package/dist/tiers/app/styles.css +9459 -0
  124. package/dist/tiers/app/surfaces.json +1225 -0
  125. package/dist/tiers/app/tokens.json +221 -0
  126. package/dist/tiers/documentation/styles.css +9442 -0
  127. package/dist/tiers/documentation/surfaces.json +1225 -0
  128. package/dist/tiers/documentation/tokens.json +221 -0
  129. package/dist/tiers/editorial/styles.css +9442 -0
  130. package/dist/tiers/editorial/surfaces.json +1225 -0
  131. package/dist/tiers/editorial/tokens.json +221 -0
  132. package/dist/tiers/os/styles.css +9442 -0
  133. package/dist/tiers/os/surfaces.json +1225 -0
  134. package/dist/tiers/os/tokens.json +221 -0
  135. package/dist/tokens.json +221 -0
  136. package/dist/tooltip.d.ts +4 -0
  137. package/dist/tooltip.js +70 -0
  138. package/dist/top-navigation.d.ts +4 -0
  139. package/dist/top-navigation.js +354 -0
  140. package/dist/types.d.ts +155 -0
  141. package/dist/types.js +1 -0
  142. package/dist/vanilla-theme-colors.d.ts +5 -0
  143. package/dist/vanilla-theme-colors.js +208 -0
  144. package/docs/publishing.md +66 -0
  145. package/package.json +108 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Lyubomir Popov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,588 @@
1
+ # Baseline Foundry
2
+
3
+ Lean baseline-aligned design system focused on:
4
+
5
+ - editorial typescale
6
+ - container-owned semantic spacing
7
+ - grid primitives
8
+ - page and section rhythm
9
+ - a small amount of demo/runtime support
10
+
11
+ This repo is the clean sibling to `portable-vertical-rhythm`.
12
+ That older package remains the compatibility line for `design-foundry`.
13
+ This repo is the forward-looking line: smaller, more versatile, and centered on baseline, prose flow, and grid rather than broad component parity.
14
+
15
+ ## Workflow Map
16
+
17
+ - Always-on invariants and cold start: `AGENTS.md`
18
+ - Live state and handover: `AGENT-INBOX.md`
19
+ - Operational commands and source routing: `docs/agent-index.md`
20
+ - Cross-spec order and short backlog: `TODO.md`
21
+ - Spec catalog and status: `docs/specs.md`
22
+ - Durable architecture: `docs/architecture.md`
23
+ - Active feature intent, tasks, and evidence: `specs/<id>-<slug>/`
24
+ - Human async notes: `INBOX.md`
25
+
26
+ Spec Kit packages are the source of truth for feature work. Closed packages move
27
+ to `docs/spec-archive/`; Git is the chronological history.
28
+
29
+ ## LLM Efficiency Notes
30
+
31
+ These habits matter more than prompt cleverness when you are using a coding agent in this repo.
32
+
33
+ - Pick one model per task. Model switches often invalidate caches and force the tool to reprocess the same context again.
34
+ - Keep permanent instructions short. Durable invariants belong in `AGENTS.md`;
35
+ task detail and evidence belong in one active Spec Kit package.
36
+ - Keep project memory in the repo, not only in chat, but give each fact one
37
+ owner. Avoid global status, roadmap, and history narratives.
38
+ - Prefer markdown, plain text, and lists over complex pages or dense tables when accuracy matters.
39
+ - Search in smaller passes instead of one giant query, then verify against the owning file or spec.
40
+ - Checkpoint and restart freely. Short resumable sessions are usually cheaper and more reliable than preserving one huge thread.
41
+
42
+ ## Source Of Truth
43
+
44
+ When sources disagree, this repo follows:
45
+
46
+ 1. Current user direction and the active local spec
47
+ 2. `.specify/memory/constitution.md`
48
+ 3. `AGENTS.md` and `docs/architecture.md`
49
+ 4. Accepted archived local specs
50
+ 5. External design references catalogued in `docs/specs.md`
51
+ 6. Public README/API documentation
52
+ 7. Undocumented local implementation details
53
+
54
+ Pragma and the Canonical official design system are related products, not BF
55
+ authorities. BF's container-owned spacing contract is an explicit local owner
56
+ decision recorded in the active spec and constitution.
57
+
58
+ ## Linked Specs
59
+
60
+ See `docs/specs.md` for the concrete linked spec paths and the legacy/reference boundaries.
61
+
62
+ ## Principles
63
+
64
+ See `AGENTS.md` and `docs/architecture.md` for the full set. Summary:
65
+
66
+ - Baseline alignment is non-negotiable.
67
+ - Semantic spacing is owned by nested stacks in editorial, documentation, app, and OS.
68
+ - Text keeps metric top-nudge and bottom-margin compensation for baseline alignment.
69
+ - OS is the fourth first-class built-in tier.
70
+ - Grid and layout primitives are small and composable.
71
+ - Dogfooding: demos use only `bf-*` classes.
72
+
73
+ For a longer write-up on empirical nudges, cap-unit alignment, raw metrics, and compensated metrics, see `docs/comparing-baseline-alignment-techniques.md`. Its visual companion lives at `demo/components/engine-illustration.html`.
74
+
75
+ ## Output
76
+
77
+ Build output includes:
78
+
79
+ - `dist/styles.css`
80
+ - `dist/tokens.json`
81
+ - `dist/surfaces.json`
82
+ - `dist/experiments/ibm-plex-engine-smoke/styles.css`
83
+ - `dist/experiments/ibm-plex-engine-smoke/tokens.json`
84
+ - `dist/experiments/ibm-plex-engine-smoke/surfaces.json`
85
+ - `dist/tiers/editorial/styles.css`
86
+ - `dist/tiers/editorial/tokens.json`
87
+ - `dist/tiers/editorial/surfaces.json`
88
+ - `dist/tiers/documentation/styles.css`
89
+ - `dist/tiers/documentation/tokens.json`
90
+ - `dist/tiers/documentation/surfaces.json`
91
+ - `dist/tiers/app/styles.css`
92
+ - `dist/tiers/app/tokens.json`
93
+ - `dist/tiers/app/surfaces.json`
94
+ - `dist/tiers/os/styles.css`
95
+ - `dist/tiers/os/tokens.json`
96
+ - `dist/tiers/os/surfaces.json`
97
+ - `dist/presets/prose/styles.css`
98
+ - `dist/presets/prose/tokens.json`
99
+ - `dist/presets/prose/surfaces.json`
100
+ - `dist/presets/app-tier/styles.css`
101
+ - `dist/presets/app-tier/tokens.json`
102
+ - `dist/presets/app-tier/surfaces.json`
103
+ - `dist/index.js`
104
+ - `dist/build.js`
105
+
106
+ ## Install
107
+
108
+ Install the public package from npm:
109
+
110
+ ```bash
111
+ npm install baseline-foundry
112
+ ```
113
+
114
+ The verified GitHub release artifact remains available as a fallback for
115
+ environments that cannot reach the npm registry:
116
+
117
+ ```bash
118
+ npm install https://github.com/lyubomir-popov/baseline-foundry/releases/download/v0.1.3/baseline-foundry-0.1.3.tgz
119
+ ```
120
+
121
+ Use the attached `.tgz`, not the GitHub source archive: generated `dist/`
122
+ artifacts are intentionally absent from Git history and are included in the
123
+ package tarball.
124
+
125
+ The package name stays unscoped so existing imports such as
126
+ `baseline-foundry/styles.css` and `baseline-foundry/build` do not change. See
127
+ [`docs/publishing.md`](docs/publishing.md) for the publication and downstream
128
+ migration contract.
129
+
130
+ ## Repository quick start
131
+
132
+ ```bash
133
+ npm install
134
+ npm run setup:demo-font
135
+ npm run playwright:install
136
+ npm run build
137
+ npm run test
138
+ npm run screenshots:components
139
+ npm run demo
140
+ ```
141
+
142
+ List or build tiers directly with:
143
+
144
+ ```bash
145
+ npm run build:theme -- --list-tiers
146
+ npm run build:theme -- --tier=os
147
+ ```
148
+
149
+ List or build presets directly with:
150
+
151
+ ```bash
152
+ npm run build:theme -- --list-presets
153
+ npm run build:theme -- --preset=prose
154
+ ```
155
+
156
+ While `npm run demo` is running, edits under `config/**/*.json` now rerun `npm run build:theme` automatically and force a full page reload.
157
+
158
+ `npm run setup:demo-font` downloads the Ubuntu Sans development font plus the IBM Plex Sans variable asset required by the engine-smoke experiment.
159
+
160
+ Built-in CSS does not emit `@font-face`: consumers own the runtime font URL and
161
+ must declare the same Ubuntu Sans variable face measured by BF. The repository
162
+ demo declares its downloaded development asset separately. Custom
163
+ `buildThemeFromConfig` outputs may still emit the face declared by a
164
+ consumer-owned config.
165
+
166
+ The demo runs at:
167
+
168
+ - [http://127.0.0.1:4174/](http://127.0.0.1:4174/) — Living spec home
169
+ - [http://127.0.0.1:4174/demo/spec/typography.html](http://127.0.0.1:4174/demo/spec/typography.html)
170
+ - [http://127.0.0.1:4174/demo/panel.html](http://127.0.0.1:4174/demo/panel.html) — OS tier
171
+ - [http://127.0.0.1:4174/demo/components/index.html](http://127.0.0.1:4174/demo/components/index.html) — BF foundations and component primitives
172
+ - [http://127.0.0.1:4174/demo/patterns/index.html](http://127.0.0.1:4174/demo/patterns/index.html) — Patterns, site compositions, recipes, layouts, and documented exclusions
173
+ - [http://127.0.0.1:4174/demo/components/engine-illustration.html](http://127.0.0.1:4174/demo/components/engine-illustration.html) — Three-way raw / compensated / cap comparison
174
+
175
+ Standalone historical Canonical example batches also live under `examples/grid/` and `examples/spacing/`. Each family has one shared stylesheet (`grid-examples.css` / `spacing-examples.css`); current decisions live in the active Spec Kit package rather than one-off root prompts.
176
+
177
+ ## Component and pattern QA
178
+
179
+ The repo includes isolated demo pages for visual rhythm and interaction checks.
180
+ `demo/components/index.html` catalogs BF foundations and component primitives;
181
+ `demo/patterns/index.html` catalogs patterns, site compositions, and layouts while
182
+ linking to the same isolated QA routes. The authoritative saved-page inventory
183
+ lives in `scripts/component-demo-shared.ts`, so the README does not mirror that
184
+ detail list.
185
+
186
+ All component/spec/control pages now share the same thin page chrome: hamburger page list plus tone, baseline-grid, and tier controls. That chrome is excluded from screenshot comparisons and disabled during Playwright hit-testing so behavior checks interact with the component under test rather than the surrounding shell.
187
+
188
+ Component QA currently covers:
189
+
190
+ - Playwright screenshot capture for the saved demo inventory
191
+ - baseline verification for baseline-aligned component surfaces across all four built-in tiers and non-tier locked-manifest variants
192
+ - behavior verification for pinned-aside resize, drawer overlay, and application-layout interactions
193
+ - the narrow-panel regression page so dense controls and media must still fit a tight rail
194
+
195
+ The grouped overview pages still exist as convenience entry points:
196
+
197
+ - `demo/components/controls.html`
198
+ - `demo/components/surfaces-navigation.html`
199
+
200
+ Install Playwright once with:
201
+
202
+ ```bash
203
+ npm run playwright:install
204
+ ```
205
+
206
+ Then capture the current component screenshots with:
207
+
208
+ ```bash
209
+ npm run screenshots:components
210
+ ```
211
+
212
+ Run the browser-enforced baseline verification with:
213
+
214
+ ```bash
215
+ npm run verify:components
216
+ ```
217
+
218
+ Run the browser-enforced resize behavior verification with:
219
+
220
+ ```bash
221
+ npm run verify:behavior
222
+ ```
223
+
224
+ Or do both in one pass:
225
+
226
+ ```bash
227
+ npm run qa:components
228
+ ```
229
+
230
+ The screenshots and manifest are written to:
231
+
232
+ - `tmp/screenshots/components/`
233
+
234
+ Those screenshots power both visual atlases at `demo/components/index.html` and
235
+ `demo/patterns/index.html`, so run `npm run screenshots:components` when new
236
+ demos are added or the saved preview set changes. Atlas frames use
237
+ `object-fit: contain`, so saved previews remain legible when different surfaces
238
+ naturally want different capture widths.
239
+
240
+ The baseline verification report is also written to:
241
+
242
+ - `tmp/screenshots/components/baseline-report.json`
243
+
244
+ That report records one entry per verified component surface, not just one per
245
+ route. Shared-tier pages are walked through `editorial`, `documentation`,
246
+ `app`, and `os`; app-authored pages stay app-only unless they explicitly opt
247
+ into a broader tier set.
248
+
249
+ `npm test` now includes this Playwright baseline check, so once Chromium is installed the grid-alignment gate is part of the normal regression suite.
250
+
251
+ ## Theme Model
252
+
253
+ The default theme uses Ubuntu Sans Variable and generates metric-driven typography tokens, spacing tokens, layout values, component density tokens, and a published surface manifest. Four first-class tiers plus two legacy preset aliases:
254
+
255
+ | Tier/Preset | Purpose |
256
+ |---|---|
257
+ | `editorial` | Root default, widest long-form composition |
258
+ | `documentation` | Tighter chapter-reading tier |
259
+ | `app` | Canonical-facing application chrome |
260
+ | `os` | Dense OS-style tier with metric alignment and compact control geometry |
261
+
262
+ Legacy aliases: `prose` → editorial, `app-tier` → app.
263
+
264
+ Independent surface contract:
265
+
266
+ - each built-in tier emits a complete scoped token surface instead of inheriting editorial defaults through diffs
267
+ - tier choice is a top-level class on any `.bf-theme` container: `.bf-tier-editorial`, `.bf-tier-documentation`, `.bf-tier-app`, `.bf-tier-os`
268
+ - multiple containers can coexist side by side under the same stylesheet
269
+ - `dist/surfaces.json` stores the runtime tokens and the font-metric artifact that produced each shipped surface — see [docs/surfaces-manifest.md](docs/surfaces-manifest.md) for the full schema, stability guarantees, and consumer recipes
270
+ - the published manifest omits local build-machine config/baseline file paths, so the shipped JSON stays portable
271
+ - every tier keeps metric-derived runtime alignment while nested stacks own semantic spacing
272
+
273
+ Example:
274
+
275
+ ```html
276
+ <section class="bf-theme bf-tier-editorial bf-stack is-section">
277
+ <div class="bf-prose bf-stack">
278
+ <h1>Editorial surface</h1>
279
+ <p>Metric-derived nudges stay on.</p>
280
+ </div>
281
+ </section>
282
+
283
+ <section class="bf-theme bf-tier-app bf-stack is-section">
284
+ <div class="bf-prose bf-stack">
285
+ <h1>App surface</h1>
286
+ <p>Metric-derived compensation and container-owned gaps remain active at application density.</p>
287
+ </div>
288
+ </section>
289
+
290
+ <section class="bf-theme bf-tier-os bf-stack is-section">
291
+ <div class="bf-prose bf-stack">
292
+ <h1>OS surface</h1>
293
+ <p>Metrics stay on, but the measure and control geometry compress toward dense system surfaces.</p>
294
+ </div>
295
+ </section>
296
+ ```
297
+
298
+ Engine choice remains separate: `.bf-engine-metrics` is the default production path, `.bf-engine-cap` is demo-only.
299
+
300
+ See `config/tiers/` for the four canonical source configs. Compatibility preset names resolve to those same owners rather than duplicate JSON files.
301
+
302
+ ## Public API
303
+
304
+ Package root exports:
305
+
306
+ - `initAccordions`
307
+ - `toggleAccordionButton`
308
+ - `initApplicationLayouts`
309
+ - `initBaselineGridToggles`
310
+ - `setupBaselineGridToggle`
311
+ - `generateBaselineGridOverlayCss`
312
+ - `generateBaselineGridThemeOverrideCss`
313
+ - `initCodeSnippets`
314
+ - `initContextualMenus`
315
+ - `initInPageNavigations`
316
+ - `initInteractiveFeedback`
317
+ - `initNotificationDismissals`
318
+ - `initPasswordReveals`
319
+ - `initInteractiveTables`
320
+ - `initSortableTables`
321
+ - `initExpandingTables`
322
+ - `initMobileCardTables`
323
+ - `initListTree`
324
+ - `initPanelDrawers`
325
+ - `initRangeControls`
326
+ - `setupRangeControl`
327
+ - `updateRangeFill`
328
+ - `initResizableAsides`
329
+ - `initSideNavigations`
330
+ - `initTopNavigations`
331
+ - `initTabs`
332
+ - `initTooltips`
333
+ - `tierNames`, `tierDescriptions`, and `isTierName`
334
+ - `TierName`, `BuiltInThemeName`, `ThemeSurfaceManifest`, and related public types
335
+
336
+ Node/build exports:
337
+
338
+ - `buildThemeFromConfig`
339
+ - `buildThemeFromTier`
340
+ - `buildThemeFromPreset`
341
+ - `deriveBaselineTokensFromConfig`
342
+ - `readThemeConfig`
343
+
344
+ Static assets:
345
+
346
+ - `baseline-foundry/styles.css`
347
+ - `baseline-foundry/tokens.json`
348
+ - `baseline-foundry/surfaces.json`
349
+ - `baseline-foundry/tiers/editorial.css`
350
+ - `baseline-foundry/tiers/editorial.tokens.json`
351
+ - `baseline-foundry/tiers/editorial.surfaces.json`
352
+ - `baseline-foundry/tiers/documentation.css`
353
+ - `baseline-foundry/tiers/documentation.tokens.json`
354
+ - `baseline-foundry/tiers/documentation.surfaces.json`
355
+ - `baseline-foundry/tiers/app.css`
356
+ - `baseline-foundry/tiers/app.tokens.json`
357
+ - `baseline-foundry/tiers/app.surfaces.json`
358
+ - `baseline-foundry/tiers/os.css`
359
+ - `baseline-foundry/tiers/os.tokens.json`
360
+ - `baseline-foundry/tiers/os.surfaces.json`
361
+ - `baseline-foundry/presets/prose.css`
362
+ - `baseline-foundry/presets/prose.tokens.json`
363
+ - `baseline-foundry/presets/prose.surfaces.json`
364
+ - `baseline-foundry/presets/app-tier.css`
365
+ - `baseline-foundry/presets/app-tier.tokens.json`
366
+ - `baseline-foundry/presets/app-tier.surfaces.json`
367
+ - `baseline-foundry/presets`
368
+ - `baseline-foundry/types`
369
+
370
+ ### Entry point guidance
371
+
372
+ Downstream consumers have two supported ways to load the built-in OS surface, depending on whether they need a neutral shared bundle or an OS-only default surface.
373
+
374
+ - Use `baseline-foundry/styles.css` as the neutral entrypoint when the consumer wants the shared root bundle and will opt into OS with class switching such as `.bf-theme.bf-tier-os`.
375
+ - Use `baseline-foundry/tiers/os.css` only when the consumer wants OS to be the unscoped default surface for that stylesheet import.
376
+ - Do not import `baseline-foundry/presets/app-tier.css` just to preload the shared bundle before switching to `bf-tier-os`; that preset remains the legacy app alias, not the neutral OS entrypoint.
377
+
378
+ Example neutral entrypoint for a downstream such as `a4-generator`:
379
+
380
+ ```html
381
+ <link rel="stylesheet" href="baseline-foundry/styles.css" />
382
+
383
+ <section class="bf-theme bf-tier-os">
384
+ <div class="bf-prose">
385
+ <h1>OS surface</h1>
386
+ <p>The shared root bundle is loaded once, and the container opts into the OS tier explicitly.</p>
387
+ </div>
388
+ </section>
389
+ ```
390
+
391
+ Example OS-default entrypoint when class switching is not needed:
392
+
393
+ ```html
394
+ <link rel="stylesheet" href="baseline-foundry/tiers/os.css" />
395
+ ```
396
+
397
+ ## Downstream Fonts
398
+
399
+ The built-in default is Ubuntu Sans Variable, but downstream repos are not locked to it.
400
+ Point the build at a downstream theme config and derive fresh nudges from that font's real metrics.
401
+
402
+ The npm package does not ship BF's development font file and built-in CSS does
403
+ not guess a URL for it. A consumer using a built-in tier must serve Ubuntu Sans
404
+ Variable and declare one normal variable face covering weights 100 through
405
+ 800 and stretches 75% through 100%. The manifest's relative
406
+ `fontFiles[*].path` records the source asset used for metric generation; it is
407
+ not a package runtime URL.
408
+
409
+ The key rule is simple:
410
+
411
+ - **do not reuse nudges from a different font**
412
+ - **do not switch font-family in CSS without regenerating tokens**
413
+ - **derive a fresh `nudgeTop` set for the actual font files that will ship**
414
+
415
+ ### What the downstream config needs
416
+
417
+ Create a theme JSON that follows the same shape as the tier configs under `config/tiers/`.
418
+ The font files are resolved relative to that config file, so a downstream repo can keep its own font assets and still use the same build path.
419
+
420
+ At minimum, define:
421
+
422
+ - `baselineUnit`
423
+ - `fontFiles`
424
+ - `fontStacks`
425
+ - `elements`
426
+ - `roles`
427
+ - `layout`
428
+ - `components`
429
+
430
+ Example sketch for a downstream Ubuntu Sans theme:
431
+
432
+ ```json
433
+ {
434
+ "baselineUnit": 0.25,
435
+ "fontFiles": [
436
+ {
437
+ "family": "ubuntu-sans",
438
+ "path": "../apps/overlay-preview/public/assets/fonts/UbuntuSans-Regular.ttf",
439
+ "cssFamily": "Ubuntu Sans",
440
+ "fontStyle": "normal",
441
+ "fontWeight": "100 800",
442
+ "fontDisplay": "swap"
443
+ }
444
+ ],
445
+ "fontStacks": {
446
+ "ubuntu-sans": "\"Ubuntu Sans\", \"Ubuntu\", system-ui, sans-serif"
447
+ },
448
+ "elements": [
449
+ {
450
+ "identifier": "body",
451
+ "fontSize": 0.75,
452
+ "lineHeight": 4,
453
+ "spaceAfter": 1,
454
+ "fontFamily": "ubuntu-sans",
455
+ "fontWeight": 400,
456
+ "fontStyle": "normal"
457
+ }
458
+ ],
459
+ "roles": {
460
+ "body": "body"
461
+ },
462
+ "layout": {
463
+ "contentMaxWidthRem": 90,
464
+ "contentPaddingInlineRem": 1,
465
+ "measureRem": 40,
466
+ "sectionSpaceBaselineUnits": 8,
467
+ "sectionSpaceDeepBaselineUnits": 16,
468
+ "stripSpaceBaselineUnits": 8,
469
+ "gridGapInlineBaselineUnits": 2,
470
+ "gridGapBlockBaselineUnits": 2,
471
+ "pageMarginBaselineUnits": 2
472
+ },
473
+ "components": {
474
+ "borderWidthPx": 1,
475
+ "radiusRem": 0,
476
+ "controlBlockPaddingRem": 0.5,
477
+ "controlCompactBlockPaddingRem": 0.25,
478
+ "controlInlinePaddingRem": 1,
479
+ "controlVisualSizeRem": 0.75,
480
+ "fieldGapBaselineUnits": 1,
481
+ "panelPaddingInlineBaselineUnits": 2,
482
+ "panelPaddingBlockBaselineUnits": 2,
483
+ "accordionIndentBaselineUnits": 3
484
+ }
485
+ }
486
+ ```
487
+
488
+ ### Generate full downstream CSS and tokens
489
+
490
+ Use the Node/build subpath so the downstream repo does not need to duplicate any build logic:
491
+
492
+ ```ts
493
+ import { buildThemeFromConfig } from "baseline-foundry/build";
494
+
495
+ await buildThemeFromConfig("config/ubuntu-foundry-theme.json", {
496
+ distDir: "generated/foundry/ubuntu",
497
+ baselineDir: ".generated/baseline/ubuntu"
498
+ });
499
+ ```
500
+
501
+ If a downstream surface bundle should ship multiple named fonts or brand variants in one stylesheet, pass a label for the default surface plus sibling named surfaces:
502
+
503
+ Baseline Foundry does not ship IBM Plex as a built-in tier or preset. Ubuntu Sans remains the only built-in tier font. For non-Ubuntu downstream bundles, provide your own config file and treat `config/experiments/ibm-plex-engine-smoke.json` as a reference/example rather than as a published preset.
504
+
505
+ ```ts
506
+ await buildThemeFromConfig("config/brand-ibm-plex-theme.json", {
507
+ distDir: "generated/foundry/smoke",
508
+ baselineDir: ".generated/baseline/smoke",
509
+ surfaceLabel: "IBM Plex Sans",
510
+ additionalSurfaces: [
511
+ {
512
+ name: "ubuntu-smoke",
513
+ label: "Ubuntu Sans",
514
+ className: "bf-surface-ubuntu-smoke",
515
+ configPath: "config/ubuntu-foundry-theme.json"
516
+ }
517
+ ]
518
+ });
519
+ ```
520
+
521
+ That does three things:
522
+
523
+ 1. writes the reduced baseline-generator input JSON
524
+ 2. runs `@lyubomir-popov/baseline-nudge-generator`
525
+ 3. emits `tokens.json`, `styles.css`, and `surfaces.json` for the downstream font or surface set
526
+
527
+ `surfaces.json` will then expose each named surface's runtime tokens, stored metrics, and optional UI label under one manifest-backed bundle.
528
+
529
+ ### Derive nudges only
530
+
531
+ If the downstream repo wants the font metrics and `nudgeTop` values but plans to own CSS generation itself, use `deriveBaselineTokensFromConfig`:
532
+
533
+ ```ts
534
+ import { deriveBaselineTokensFromConfig } from "baseline-foundry/build";
535
+
536
+ const result = await deriveBaselineTokensFromConfig("config/ubuntu-foundry-theme.json", {
537
+ baselineDir: ".generated/baseline/ubuntu"
538
+ });
539
+
540
+ console.log(result.tokens.elements.body.nudgeTop);
541
+ console.log(result.baselineConfigPath);
542
+ console.log(result.baselineTokensPath);
543
+ ```
544
+
545
+ ### Direct utility usage
546
+
547
+ `baseline-foundry` uses `@lyubomir-popov/baseline-nudge-generator` under the hood.
548
+ The reduced config passed to that utility contains only:
549
+
550
+ - `baselineUnit`
551
+ - `fontFiles` with build-time font paths
552
+ - `elements` with `identifier`, `fontSize`, `lineHeight`, `spaceAfter`, `fontFamily`, `fontWeight`, and `fontStyle`
553
+
554
+ Equivalent direct usage looks like this:
555
+
556
+ ```ts
557
+ import { generateFromConfig } from "@lyubomir-popov/baseline-nudge-generator";
558
+
559
+ await generateFromConfig(".generated/baseline/ubuntu/ubuntu-foundry-theme.baseline.json", ".generated/baseline/ubuntu");
560
+ ```
561
+
562
+ The generated `tokens.json` then contains the derived metric nudges per element, including `nudgeTop`, which `baseline-foundry` turns into the scoped `--bf-<role>-nudge-start` / `--bf-<role>-nudge-end` variables inside each emitted surface.
563
+
564
+ ### Practical downstream advice
565
+
566
+ - Regenerate tokens whenever the downstream font files change.
567
+ - Regenerate tokens whenever font size, line-height, or baseline unit changes.
568
+ - Keep at least one non-`runtimeOnly` font file in `fontFiles`; that is the file the nudge generator reads for metrics.
569
+ - If a downstream repo ships multiple runtime faces, mark only the non-metric extras as `runtimeOnly`.
570
+ - Keep metrics as the default engine for production fonts; `.bf-engine-cap` remains an opt-in fallback, not the default path.
571
+
572
+ ## Demo
573
+
574
+ The demo surface at `/` shows editorial prose rhythm, tier switching, dark
575
+ theme, grid, spacing, and component specimens. BF primitives are indexed at
576
+ `demo/components/index.html`; patterns, site compositions, and layouts are
577
+ indexed separately at `demo/patterns/index.html`. Their isolated test routes
578
+ remain under `demo/components/`, and the authoritative saved-page inventory is
579
+ in `scripts/component-demo-shared.ts`.
580
+
581
+ ## Start Here
582
+
583
+ If you resume this repo in a new chat, read:
584
+
585
+ 1. `AGENTS.md`
586
+ 2. `AGENT-INBOX.md`
587
+ 3. `docs/agent-index.md`
588
+ 4. `docs/specs.md`