@ponchia/ui 0.12.0 → 0.13.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 (48) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +3 -3
  3. package/classes/classes.json +3 -1
  4. package/classes/index.d.ts +2 -0
  5. package/classes/index.js +3 -1
  6. package/classes/vscode.css-custom-data.json +64 -0
  7. package/css/base.css +2 -2
  8. package/css/blocknote.css +61 -0
  9. package/css/clamp.css +2 -2
  10. package/css/content.css +126 -0
  11. package/css/disclosure.css +10 -10
  12. package/css/forms.css +8 -8
  13. package/css/primitives.css +5 -6
  14. package/css/row.css +2 -2
  15. package/css/term.css +2 -2
  16. package/css/textref.css +2 -2
  17. package/css/toc.css +2 -2
  18. package/css/tokens.css +43 -0
  19. package/css/workbench.css +2 -2
  20. package/dist/bronto.css +1 -1
  21. package/dist/css/base.css +1 -1
  22. package/dist/css/blocknote.css +1 -0
  23. package/dist/css/clamp.css +1 -1
  24. package/dist/css/content.css +1 -1
  25. package/dist/css/disclosure.css +1 -1
  26. package/dist/css/forms.css +1 -1
  27. package/dist/css/report-kit.css +1 -1
  28. package/dist/css/row.css +1 -1
  29. package/dist/css/term.css +1 -1
  30. package/dist/css/textref.css +1 -1
  31. package/dist/css/toc.css +1 -1
  32. package/dist/css/tokens.css +1 -1
  33. package/dist/css/workbench.css +1 -1
  34. package/docs/compositions.md +2 -2
  35. package/docs/interop/blocknote.md +60 -0
  36. package/docs/package-contract.md +6 -2
  37. package/docs/reference.md +18 -1
  38. package/docs/reporting.md +8 -8
  39. package/docs/stability.md +2 -1
  40. package/docs/theming.md +48 -1
  41. package/llms.txt +1 -1
  42. package/package.json +13 -10
  43. package/tokens/figma.variables.json +240 -0
  44. package/tokens/index.d.ts +2 -2
  45. package/tokens/index.js +30 -2
  46. package/tokens/index.json +32 -0
  47. package/tokens/resolved.json +17 -1
  48. package/tokens/tokens.dtcg.json +190 -0
package/CHANGELOG.md CHANGED
@@ -5,6 +5,57 @@
5
5
  |> `^0` / `*` wildcard does **not** protect you. See README → Versioning, and
6
6
  |> the deprecation policy in CONTRIBUTING.md.
7
7
 
8
+ ## 0.13.0 — 2026-10-01
9
+
10
+ ### Added
11
+
12
+ - **`ui-prose--blocks`: prose on a block editor's geometry.** A read view that
13
+ must put every line where a block editor (BlockNote's model) draws it: 3px
14
+ block padding instead of flow margins, line-height 1.5, headings with an 18px
15
+ lead and a 1.6/1.3/1.15em scale at weight 600, a 24px list column with disc,
16
+ circle and square, and the editor's task-row geometry. The px are exposed as
17
+ `--prose-block`, `--prose-heading-lead` and `--prose-list-column`.
18
+ `recipes.prose({ blocks: true })` emits it.
19
+ - **`css/blocknote.css`: BlockNote interop.** Maps BlockNote's `--bn-*` theme
20
+ variables (editor, menus, tooltips, side menu, selection, border, font,
21
+ radius) to bronto tokens, and its nine text highlights to the categorical
22
+ identity inks and tints, so the editor follows theme, skins, contrast and the
23
+ OLED surface. Import the unlayered build after BlockNote's stylesheet. See
24
+ [BlockNote interop](docs/interop/blocknote.md).
25
+ - **Half spacing steps for dense tool chrome.** `--space-0-5`, `--space-0-75`,
26
+ `--space-1-5` and `--space-2-5` (2, 3, 6 and 10px at a 16px root), scaled by
27
+ the density presets with the rest of the scale.
28
+ - **Workspace layers.** `--z-canvas`, `--z-chrome`, `--z-panel`, `--z-modal`,
29
+ `--z-menu`, `--z-tooltip` and `--z-navigation` name the stack of a tool drawn
30
+ over a canvas, aliased to the page layers where they mean the same.
31
+ - **Zoom-aware hairlines and focus rings.** A host that scales bronto UI marks
32
+ the scaled element `[data-ui-zoom]` and sets `--ui-zoom`; inside it `--ui-px`
33
+ is one screen pixel and `--hairline`, `--focus-ring-width` and
34
+ `--focus-ring-offset` are re-declared in it.
35
+
36
+ ### Changed
37
+
38
+ - Every bronto focus ring reads `--focus-ring-width` and `--focus-ring-offset`
39
+ instead of literal px. At the default zoom they are the same 2px, so nothing
40
+ moves; inside a `[data-ui-zoom]` surface a ring keeps its on-screen width.
41
+ - The default bundle grows from 92.8 kB / 16.0 kB gzip to 95.8 kB / 16.6 kB:
42
+ 1.9 kB is the block prose variant, the rest the new tokens and the focus-ring
43
+ variables. Notes are now the main reading surface, so block prose ships in
44
+ the core prose vocabulary rather than a leaf.
45
+
46
+ ### Internal
47
+
48
+ - `npm run check` runs every gate and ends with one line naming each gate
49
+ that failed; `npm run check -- --bail` stops at the first. It was an `&&`
50
+ chain that stopped at the first failure: since 0.8, 13 of the 20 failed CI
51
+ runs were the Dependabot dev-dependency group stopping at `check:exports`
52
+ on TypeScript 7, so no run measured the rest of the group. The gate list is
53
+ the `check:*` scripts themselves, so `check:chain`, which checked that the
54
+ hand-kept chain named every gate, is gone.
55
+ - The package contract no longer lists `react/`, `solid/`, `qwik/`,
56
+ `svelte/` and `vue/` as authored JS directories; the package has none. The
57
+ list is now read from `tsconfig.dts.json`.
58
+
8
59
  ## 0.12.0 — 2026-10-01
9
60
 
10
61
  ### Changed
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![npm](https://img.shields.io/npm/v/@ponchia/ui?logo=npm)](https://www.npmjs.com/package/@ponchia/ui)
4
4
  [![npm provenance](https://img.shields.io/badge/npm-provenance-blue?logo=npm)](https://www.npmjs.com/package/@ponchia/ui#provenance)
5
5
  [![runtime deps](https://img.shields.io/badge/runtime%20deps-0-brightgreen)](https://github.com/Ponchia/bronto-ui/blob/main/package.json)
6
- [![default CSS](https://img.shields.io/badge/default%20CSS-~93kB%20%2F%20~16kB%20gzip-informational)](https://github.com/Ponchia/bronto-ui/blob/main/scripts/check-dist.mjs)
6
+ [![default CSS](https://img.shields.io/badge/default%20CSS-~96kB%20%2F%20~17kB%20gzip-informational)](https://github.com/Ponchia/bronto-ui/blob/main/scripts/check-dist.mjs)
7
7
  [![CI](https://github.com/Ponchia/bronto-ui/actions/workflows/ci.yml/badge.svg)](https://github.com/Ponchia/bronto-ui/actions/workflows/ci.yml)
8
8
  [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/Ponchia/bronto-ui/badge)](https://scorecard.dev/viewer/?uri=github.com/Ponchia/bronto-ui)
9
9
  [![license: MIT](https://img.shields.io/badge/license-MIT-blue)](https://github.com/Ponchia/bronto-ui/blob/main/LICENSE)
@@ -93,12 +93,12 @@ Or drop it in with no build step, straight from a CDN (replace the version only
93
93
  when deliberately upgrading across a breaking pre-1.0 minor):
94
94
 
95
95
  ```html
96
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.12.0/dist/bronto.css">
96
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.13.0/dist/bronto.css">
97
97
  ```
98
98
 
99
99
  ## Quick start
100
100
 
101
- **1. Load the CSS.** One flattened, minified default CSS bundle — the standard component set, one request (~93 kB raw / ~16 kB gzip) — that is `dist/bronto.css`, not the whole package tarball:
101
+ **1. Load the CSS.** One flattened, minified default CSS bundle — the standard component set, one request (~96 kB raw / ~17 kB gzip) — that is `dist/bronto.css`, not the whole package tarball:
102
102
 
103
103
  ```css
104
104
  @import '@ponchia/ui'; /* via a bundler */
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$comment": "@ponchia/ui class vocabulary as language-neutral data — validate emitted markup without executing the ESM cls map or parsing the .d.ts. Generated from classes/index.js — do not edit by hand; run `npm run classes:json:build`. Drift-checked in CI. `groups[].base` is null for a parts-only namespace (no standalone base class — do NOT emit it). A modifier whose name contains `__` (e.g. `ui-spark__bar--pos`) attaches to THAT part, not the base host. `states` is the author-applied `is-*` hooks (runtime/behavior-managed hooks are excluded); `behaviorAttributes` are the `data-bronto-*` wiring hooks the optional behaviors delegate on; `requiredAria` is the role/aria a generator must emit per component. `states` + `customProperties` are documented in docs/reference.md and ship outside `cls` by design.",
3
3
  "counts": {
4
- "classes": 695,
4
+ "classes": 696,
5
5
  "groups": 187
6
6
  },
7
7
  "groups": {
@@ -993,6 +993,7 @@
993
993
  "ui-prose": {
994
994
  "base": "ui-prose",
995
995
  "modifiers": [
996
+ "ui-prose--blocks",
996
997
  "ui-prose--compact"
997
998
  ],
998
999
  "parts": []
@@ -2040,6 +2041,7 @@
2040
2041
  "ui-property__label",
2041
2042
  "ui-property__value",
2042
2043
  "ui-prose",
2044
+ "ui-prose--blocks",
2043
2045
  "ui-prose--compact",
2044
2046
  "ui-provenance",
2045
2047
  "ui-provenance__item",
@@ -241,6 +241,7 @@ export declare const cls: {
241
241
  readonly eyebrowSm: 'ui-eyebrow--sm';
242
242
  readonly prose: 'ui-prose';
243
243
  readonly proseCompact: 'ui-prose--compact';
244
+ readonly proseBlocks: 'ui-prose--blocks';
244
245
  readonly quote: 'ui-quote';
245
246
  readonly quoteCite: 'ui-quote__cite';
246
247
  readonly container: 'ui-container';
@@ -822,6 +823,7 @@ export interface AvatarOpts {
822
823
  }
823
824
  export interface ProseOpts {
824
825
  compact?: boolean;
826
+ blocks?: boolean;
825
827
  }
826
828
  export interface ContainerOpts {
827
829
  narrow?: boolean;
package/classes/index.js CHANGED
@@ -255,6 +255,7 @@ export const cls = Object.freeze({
255
255
  eyebrowSm: 'ui-eyebrow--sm',
256
256
  prose: 'ui-prose',
257
257
  proseCompact: 'ui-prose--compact',
258
+ proseBlocks: 'ui-prose--blocks',
258
259
  quote: 'ui-quote',
259
260
  quoteCite: 'ui-quote__cite',
260
261
  // site shell
@@ -1036,7 +1037,8 @@ export const ui = {
1036
1037
  tab: ({ active } = {}) => j(cls.tab, active && 'is-active'),
1037
1038
  avatar: ({ size } = {}) =>
1038
1039
  j(cls.avatar, size === 'sm' && cls.avatarSm, size === 'lg' && cls.avatarLg),
1039
- prose: ({ compact } = {}) => j(cls.prose, compact && cls.proseCompact),
1040
+ prose: ({ compact, blocks } = {}) =>
1041
+ j(cls.prose, compact && cls.proseCompact, blocks && cls.proseBlocks),
1040
1042
  container: ({ narrow, wide } = {}) =>
1041
1043
  j(cls.container, narrow && cls.containerNarrow, wide && cls.containerWide),
1042
1044
  tag: ({ accent } = {}) => j(cls.tag, accent && cls.tagAccent),
@@ -201,6 +201,18 @@
201
201
  "name": "--focus-ring",
202
202
  "description": "Theme token. Light: `var(--accent)` · Dark: `var(--accent)`"
203
203
  },
204
+ {
205
+ "name": "--focus-ring-offset",
206
+ "description": "Global scale token. Value: `2px`"
207
+ },
208
+ {
209
+ "name": "--focus-ring-width",
210
+ "description": "Global scale token. Value: `2px`"
211
+ },
212
+ {
213
+ "name": "--hairline",
214
+ "description": "Global scale token. Value: `1px`"
215
+ },
204
216
  {
205
217
  "name": "--info",
206
218
  "description": "Theme token. Light: `#1f63c4` · Dark: `#6fb0e6`"
@@ -285,6 +297,22 @@
285
297
  "name": "--shadow-raised",
286
298
  "description": "Theme token. Light: `0 0 0 1px var(--line-strong)` · Dark: `0 0 0 1px var(--line-strong)`"
287
299
  },
300
+ {
301
+ "name": "--space-0-5",
302
+ "description": "Global scale token. Value: `0.125rem`"
303
+ },
304
+ {
305
+ "name": "--space-0-75",
306
+ "description": "Global scale token. Value: `0.1875rem`"
307
+ },
308
+ {
309
+ "name": "--space-1-5",
310
+ "description": "Global scale token. Value: `0.375rem`"
311
+ },
312
+ {
313
+ "name": "--space-2-5",
314
+ "description": "Global scale token. Value: `0.625rem`"
315
+ },
288
316
  {
289
317
  "name": "--space-2xl",
290
318
  "description": "Global scale token. Value: `2.5rem`"
@@ -409,6 +437,14 @@
409
437
  "name": "--tracking-wider",
410
438
  "description": "Global scale token. Value: `0.22em`"
411
439
  },
440
+ {
441
+ "name": "--ui-px",
442
+ "description": "Global scale token. Value: `1px`"
443
+ },
444
+ {
445
+ "name": "--ui-zoom",
446
+ "description": "Global scale token. Value: `1`"
447
+ },
412
448
  {
413
449
  "name": "--warning",
414
450
  "description": "Theme token. Light: `#806414` · Dark: `#d8bd72`"
@@ -421,10 +457,34 @@
421
457
  "name": "--z-base",
422
458
  "description": "Global scale token. Value: `0`"
423
459
  },
460
+ {
461
+ "name": "--z-canvas",
462
+ "description": "Global scale token. Value: `var(--z-base)`"
463
+ },
464
+ {
465
+ "name": "--z-chrome",
466
+ "description": "Global scale token. Value: `var(--z-sticky)`"
467
+ },
468
+ {
469
+ "name": "--z-menu",
470
+ "description": "Global scale token. Value: `var(--z-popover)`"
471
+ },
472
+ {
473
+ "name": "--z-modal",
474
+ "description": "Global scale token. Value: `var(--z-overlay)`"
475
+ },
476
+ {
477
+ "name": "--z-navigation",
478
+ "description": "Global scale token. Value: `80`"
479
+ },
424
480
  {
425
481
  "name": "--z-overlay",
426
482
  "description": "Global scale token. Value: `30`"
427
483
  },
484
+ {
485
+ "name": "--z-panel",
486
+ "description": "Global scale token. Value: `25`"
487
+ },
428
488
  {
429
489
  "name": "--z-popover",
430
490
  "description": "Global scale token. Value: `50`"
@@ -440,6 +500,10 @@
440
500
  {
441
501
  "name": "--z-toast",
442
502
  "description": "Global scale token. Value: `60`"
503
+ },
504
+ {
505
+ "name": "--z-tooltip",
506
+ "description": "Global scale token. Value: `70`"
443
507
  }
444
508
  ],
445
509
  "atDirectives": [
package/css/base.css CHANGED
@@ -164,8 +164,8 @@ input:focus-visible,
164
164
  select:focus-visible,
165
165
  textarea:focus-visible,
166
166
  [tabindex]:focus-visible {
167
- outline: 2px solid var(--focus-ring);
168
- outline-offset: 2px;
167
+ outline: var(--focus-ring-width) solid var(--focus-ring);
168
+ outline-offset: var(--focus-ring-offset);
169
169
  }
170
170
 
171
171
  /* Small global helpers reused across apps. */
@@ -0,0 +1,61 @@
1
+ /* ==========================================================================
2
+ blocknote — BlockNote's theme variables, mapped to bronto tokens.
3
+
4
+ INTEROP LEAF, opt-in. BlockNote (https://www.blocknotejs.org) themes its
5
+ editor, menus, side menu, toolbar and text highlights through `--bn-*`
6
+ custom properties on `.bn-root`, with its own light and dark values. Point
7
+ them at the bronto tokens and the editor follows the theme, skins, contrast
8
+ and the OLED surface like the rest of the page.
9
+
10
+ BlockNote's stylesheet is unlayered, and an unlayered rule outranks any
11
+ layered one, so import this leaf's UNLAYERED build, after BlockNote's:
12
+
13
+ @import '@blocknote/mantine/style.css';
14
+ @import '@ponchia/ui/css/unlayered/blocknote.css';
15
+
16
+ Text and background highlights are categorical identity (a colour a person
17
+ chose for a span), so they take `--cat-N-ink` and `--cat-N-tint` from
18
+ css/dataviz.css. Without that leaf they fall back to the status colours.
19
+ ========================================================================== */
20
+
21
+ .bn-root,
22
+ .bn-root[data-color-scheme] {
23
+ --bn-font-family: var(--sans);
24
+ --bn-border-radius: var(--radius-lg);
25
+ --bn-colors-editor-text: var(--text);
26
+ --bn-colors-editor-background: var(--panel);
27
+ --bn-colors-menu-text: var(--text);
28
+ --bn-colors-menu-background: var(--panel-strong);
29
+ --bn-colors-tooltip-text: var(--text);
30
+ --bn-colors-tooltip-background: var(--panel-soft);
31
+ --bn-colors-hovered-text: var(--text);
32
+ --bn-colors-hovered-background: var(--panel-soft);
33
+ --bn-colors-selected-text: var(--on-accent);
34
+ --bn-colors-selected-background: var(--accent);
35
+ --bn-colors-disabled-text: var(--text-dim);
36
+ --bn-colors-disabled-background: var(--panel-soft);
37
+ --bn-colors-shadow: var(--line);
38
+ --bn-colors-border: var(--line);
39
+ --bn-colors-side-menu: var(--text-dim);
40
+
41
+ /* Highlights: BlockNote's nine names onto the categorical hues. Gray is the
42
+ neutral ink; brown, which the palette has no hue for, is the orange ink. */
43
+ --bn-colors-highlights-gray-text: var(--text-dim);
44
+ --bn-colors-highlights-gray-background: var(--panel-soft);
45
+ --bn-colors-highlights-brown-text: var(--cat-2-ink, var(--warning));
46
+ --bn-colors-highlights-brown-background: var(--panel-soft);
47
+ --bn-colors-highlights-red-text: var(--cat-8-ink, var(--danger));
48
+ --bn-colors-highlights-red-background: var(--cat-8-tint, var(--panel-soft));
49
+ --bn-colors-highlights-orange-text: var(--cat-2-ink, var(--warning));
50
+ --bn-colors-highlights-orange-background: var(--cat-2-tint, var(--panel-soft));
51
+ --bn-colors-highlights-yellow-text: var(--cat-4-ink, var(--warning));
52
+ --bn-colors-highlights-yellow-background: var(--cat-4-tint, var(--panel-soft));
53
+ --bn-colors-highlights-green-text: var(--cat-6-ink, var(--success));
54
+ --bn-colors-highlights-green-background: var(--cat-6-tint, var(--panel-soft));
55
+ --bn-colors-highlights-blue-text: var(--cat-1-ink, var(--info));
56
+ --bn-colors-highlights-blue-background: var(--cat-1-tint, var(--panel-soft));
57
+ --bn-colors-highlights-purple-text: var(--cat-7-ink, var(--info));
58
+ --bn-colors-highlights-purple-background: var(--cat-7-tint, var(--panel-soft));
59
+ --bn-colors-highlights-pink-text: var(--cat-5-ink, var(--danger));
60
+ --bn-colors-highlights-pink-background: var(--cat-5-tint, var(--panel-soft));
61
+ }
package/css/clamp.css CHANGED
@@ -55,8 +55,8 @@
55
55
  }
56
56
 
57
57
  .ui-clamp__toggle:focus-visible + .ui-clamp__body + .ui-clamp__control {
58
- outline: 2px solid var(--focus-ring);
59
- outline-offset: 2px;
58
+ outline: var(--focus-ring-width) solid var(--focus-ring);
59
+ outline-offset: var(--focus-ring-offset);
60
60
  }
61
61
 
62
62
  .ui-clamp__less {
package/css/content.css CHANGED
@@ -308,6 +308,132 @@
308
308
  margin-block-start: var(--space-lg);
309
309
  }
310
310
 
311
+ /* --- Blocks variant — the block editor's geometry ---
312
+ For a surface that is both read and edited, where the editor is a block
313
+ editor (BlockNote's model): the read view has to put every line where the
314
+ editor will draw it, or the text jumps when the surface switches mode.
315
+ Blocks carry a small padding instead of flow margins; headings a lead above
316
+ and a 1.6/1.3/1.15em scale at weight 600; lists a fixed marker column with
317
+ disc, circle and square; a task row the editor's checkbox geometry. The
318
+ measure is released: a block surface is as wide as its container. The
319
+ geometry is the editor's own px, exposed so a host can retune it. */
320
+
321
+ .ui-prose--blocks {
322
+ --prose-measure: none;
323
+ --prose-block: 3px;
324
+ --prose-heading-lead: 18px;
325
+ --prose-list-column: 24px;
326
+
327
+ color: var(--text);
328
+ line-height: 1.5;
329
+ }
330
+
331
+ .ui-prose--blocks > *,
332
+ .ui-prose--blocks > * + *,
333
+ .ui-prose--blocks > * + :is(h1, h2, h3, h4, h5, h6),
334
+ .ui-prose--blocks li,
335
+ .ui-prose--blocks li + li,
336
+ .ui-prose--blocks li > *,
337
+ .ui-prose--blocks :is(ul, ol) :is(ul, ol),
338
+ .ui-prose--blocks blockquote > *,
339
+ .ui-prose--blocks blockquote > * + * {
340
+ margin-block: 0;
341
+ }
342
+
343
+ .ui-prose--blocks > :not(ul, ol),
344
+ .ui-prose--blocks li {
345
+ padding-block: var(--prose-block);
346
+ }
347
+
348
+ /* An item's own block ends before its nested list, as the editor nests it. */
349
+ .ui-prose--blocks li:has(> :is(ul, ol)) {
350
+ padding-block-end: 0;
351
+ }
352
+
353
+ .ui-prose--blocks li > :is(ul, ol) {
354
+ padding-block-start: var(--prose-block);
355
+ }
356
+
357
+ .ui-prose--blocks :is(h1, h2, h3, h4, h5, h6) {
358
+ padding-block: var(--prose-heading-lead) var(--prose-block);
359
+ border: 0;
360
+ font-size: 1em;
361
+ font-weight: 600;
362
+ line-height: 1.25;
363
+ }
364
+
365
+ .ui-prose--blocks h1 {
366
+ font-size: 1.6em;
367
+ }
368
+
369
+ .ui-prose--blocks h2 {
370
+ font-size: 1.3em;
371
+ }
372
+
373
+ .ui-prose--blocks h3 {
374
+ font-size: 1.15em;
375
+ }
376
+
377
+ .ui-prose--blocks :is(ul, ol) {
378
+ padding-inline-start: var(--prose-list-column);
379
+ }
380
+
381
+ .ui-prose--blocks ul {
382
+ list-style: disc;
383
+ }
384
+
385
+ .ui-prose--blocks ul ul {
386
+ list-style: circle;
387
+ }
388
+
389
+ .ui-prose--blocks ul ul ul {
390
+ list-style: square;
391
+ }
392
+
393
+ .ui-prose--blocks li::marker {
394
+ color: inherit;
395
+ }
396
+
397
+ /* A task row is the editor's: the checkbox centred in a hit area at the text
398
+ column, the text padded inside the block. A loose list may put the checkbox
399
+ in the item's paragraph rather than the item. */
400
+ .ui-prose--blocks li:has(> input[type='checkbox'], > p > input[type='checkbox']) {
401
+ margin-inline-start: calc(-1 * var(--prose-list-column));
402
+ padding-block: 10px;
403
+ list-style: none;
404
+ }
405
+
406
+ .ui-prose--blocks :is(li, li > p):has(> input[type='checkbox']) {
407
+ display: flex;
408
+ align-items: flex-start;
409
+ }
410
+
411
+ .ui-prose--blocks :is(li, li > p) > input[type='checkbox'] {
412
+ flex: none;
413
+ inline-size: 20px;
414
+ block-size: 20px;
415
+ margin: 2px 6px 0;
416
+ }
417
+
418
+ @media (pointer: coarse) {
419
+ .ui-prose--blocks li:has(> input[type='checkbox'], > p > input[type='checkbox']) {
420
+ padding-block: 16px;
421
+ }
422
+
423
+ .ui-prose--blocks :is(li, li > p) > input[type='checkbox'] {
424
+ margin-inline: 12px;
425
+ }
426
+ }
427
+
428
+ /* A quote is one block: its text on the body's line, its rule at the column. */
429
+ .ui-prose--blocks blockquote {
430
+ margin-inline: 0;
431
+ }
432
+
433
+ .ui-prose--blocks blockquote > * {
434
+ line-height: inherit;
435
+ }
436
+
311
437
  /* ==========================================================================
312
438
  ui-quote — pull-quote with attribution. A long-form companion to
313
439
  .ui-prose (works inside it or standalone). Emphasis via scale + a
@@ -75,8 +75,8 @@
75
75
  distinction — colour stays the solid accent used by every other
76
76
  control's ring (the --focus-ring token wiring is decided globally,
77
77
  not per-component). */
78
- outline: 2px solid var(--focus-ring);
79
- outline-offset: -3px;
78
+ outline: var(--focus-ring-width) solid var(--focus-ring);
79
+ outline-offset: calc(-1.5 * var(--focus-ring-offset));
80
80
  }
81
81
 
82
82
  .ui-tabs__panel[hidden] {
@@ -216,8 +216,8 @@
216
216
  }
217
217
 
218
218
  .ui-segmented__option:has(input:focus-visible) {
219
- outline: 2px solid var(--focus-ring);
220
- outline-offset: -2px;
219
+ outline: var(--focus-ring-width) solid var(--focus-ring);
220
+ outline-offset: calc(-1 * var(--focus-ring-offset));
221
221
  }
222
222
 
223
223
  @media (hover: hover) {
@@ -439,8 +439,8 @@
439
439
  }
440
440
 
441
441
  .ui-carousel__viewport:focus-visible {
442
- outline: 2px solid var(--focus-ring);
443
- outline-offset: -2px;
442
+ outline: var(--focus-ring-width) solid var(--focus-ring);
443
+ outline-offset: calc(-1 * var(--focus-ring-offset));
444
444
  }
445
445
 
446
446
  .ui-carousel__slide {
@@ -519,8 +519,8 @@
519
519
 
520
520
  .ui-carousel__prev:focus-visible,
521
521
  .ui-carousel__next:focus-visible {
522
- outline: 2px solid var(--focus-ring);
523
- outline-offset: 2px;
522
+ outline: var(--focus-ring-width) solid var(--focus-ring);
523
+ outline-offset: var(--focus-ring-offset);
524
524
  }
525
525
 
526
526
  /* Position counter ("3 / 12") — initCarousel fills the text; aria-live. */
@@ -584,8 +584,8 @@
584
584
  }
585
585
 
586
586
  .ui-carousel__thumb:focus-visible {
587
- outline: 2px solid var(--focus-ring);
588
- outline-offset: 2px;
587
+ outline: var(--focus-ring-width) solid var(--focus-ring);
588
+ outline-offset: var(--focus-ring-offset);
589
589
  }
590
590
 
591
591
  @media (prefers-reduced-motion: reduce) {
package/css/forms.css CHANGED
@@ -66,8 +66,8 @@
66
66
  .ui-input:focus-visible,
67
67
  .ui-select:focus-visible,
68
68
  .ui-textarea:focus-visible {
69
- outline: 2px solid var(--focus-ring);
70
- outline-offset: 1px;
69
+ outline: var(--focus-ring-width) solid var(--focus-ring);
70
+ outline-offset: calc(var(--focus-ring-offset) / 2);
71
71
  }
72
72
 
73
73
  .ui-input:disabled,
@@ -292,8 +292,8 @@
292
292
  }
293
293
 
294
294
  .ui-range:focus-visible {
295
- outline: 2px solid var(--focus-ring);
296
- outline-offset: 4px;
295
+ outline: var(--focus-ring-width) solid var(--focus-ring);
296
+ outline-offset: calc(2 * var(--focus-ring-offset));
297
297
  }
298
298
 
299
299
  /* --- Error summary: one focusable, assertive list of form errors --- */
@@ -358,8 +358,8 @@
358
358
  border-colour shift alone read markedly fainter on this one control. Keyed to
359
359
  :focus-visible on the inner input so it stays keyboard-only. */
360
360
  .ui-search:has(input:focus-visible) {
361
- outline: 2px solid var(--focus-ring);
362
- outline-offset: 1px;
361
+ outline: var(--focus-ring-width) solid var(--focus-ring);
362
+ outline-offset: calc(var(--focus-ring-offset) / 2);
363
363
  }
364
364
 
365
365
  .ui-search:focus-within::before {
@@ -429,8 +429,8 @@
429
429
  }
430
430
 
431
431
  .ui-switch input:focus-visible + .ui-switch__track {
432
- outline: 2px solid var(--focus-ring);
433
- outline-offset: 2px;
432
+ outline: var(--focus-ring-width) solid var(--focus-ring);
433
+ outline-offset: var(--focus-ring-offset);
434
434
  }
435
435
 
436
436
  /* ARIA contract: `.ui-switch` is a visually-styled checkbox. Author
@@ -812,12 +812,11 @@
812
812
 
813
813
  /* --- Touch: comfortable hit targets on coarse pointers.
814
814
 
815
- The floor is `--tap-target`, not a bare rem. Bronto's own base sets
816
- `html { font-size: 0.9375rem }`, so the 2.9rem this family used to carry
817
- resolved to 43.5px — half a pixel under the 44px WCAG 2.5.5 / platform-HIG
818
- target, and under any host that shrinks the root further it drifted further
819
- still. The token clamps in px against the rem so the standard holds however
820
- the root is re-pointed. --- */
815
+ The floor is `--tap-target`, not a bare rem. Under a 15px root the 2.9rem
816
+ this family used to carry resolved to 43.5px — half a pixel under the 44px
817
+ WCAG 2.5.5 / platform-HIG target, and under any host that shrinks the root
818
+ further it drifted further still. The token clamps in px against the rem so
819
+ the standard holds however the root is re-pointed. --- */
821
820
 
822
821
  @media (pointer: coarse) {
823
822
  .ui-button {
package/css/row.css CHANGED
@@ -126,8 +126,8 @@
126
126
  .ui-row:focus-visible {
127
127
  background: var(--bg-accent);
128
128
  color: var(--text);
129
- outline: 2px solid var(--focus-ring);
130
- outline-offset: -2px;
129
+ outline: var(--focus-ring-width) solid var(--focus-ring);
130
+ outline-offset: calc(-1 * var(--focus-ring-offset));
131
131
  }
132
132
 
133
133
  /* Touch: a row is a primary target in a list, so it floats to the full
package/css/term.css CHANGED
@@ -39,8 +39,8 @@
39
39
  }
40
40
 
41
41
  .ui-term:focus-visible {
42
- outline: 2px solid var(--focus-ring);
43
- outline-offset: 2px;
42
+ outline: var(--focus-ring-width) solid var(--focus-ring);
43
+ outline-offset: var(--focus-ring-offset);
44
44
  }
45
45
 
46
46
  /* The definition — a native popover. Reset the UA popover chrome to the Bronto
package/css/textref.css CHANGED
@@ -39,8 +39,8 @@
39
39
  }
40
40
 
41
41
  .ui-textref:focus-visible {
42
- outline: 2px solid var(--focus-ring);
43
- outline-offset: 2px;
42
+ outline: var(--focus-ring-width) solid var(--focus-ring);
43
+ outline-offset: var(--focus-ring-offset);
44
44
  }
45
45
 
46
46
  /* The browser-painted highlight on the matched fragment. Scoped to the page
package/css/toc.css CHANGED
@@ -64,8 +64,8 @@
64
64
  }
65
65
 
66
66
  .ui-toc__link:focus-visible {
67
- outline: 2px solid var(--focus-ring);
68
- outline-offset: -2px;
67
+ outline: var(--focus-ring-width) solid var(--focus-ring);
68
+ outline-offset: calc(-1 * var(--focus-ring-offset));
69
69
  }
70
70
 
71
71
  @media (hover: hover) {