@ponchia/ui 0.6.0 → 0.6.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 (156) hide show
  1. package/CHANGELOG.md +64 -4
  2. package/README.md +1 -1
  3. package/annotations/index.d.ts.map +1 -1
  4. package/annotations/index.js +36 -33
  5. package/behaviors/carousel.d.ts +28 -0
  6. package/behaviors/carousel.d.ts.map +1 -0
  7. package/behaviors/carousel.js +3 -0
  8. package/behaviors/combobox.d.ts +40 -0
  9. package/behaviors/combobox.d.ts.map +1 -0
  10. package/behaviors/combobox.js +71 -20
  11. package/behaviors/command.d.ts +41 -0
  12. package/behaviors/command.d.ts.map +1 -0
  13. package/behaviors/command.js +9 -0
  14. package/behaviors/connectors.d.ts +17 -0
  15. package/behaviors/connectors.d.ts.map +1 -0
  16. package/behaviors/connectors.js +3 -0
  17. package/behaviors/crosshair.d.ts +42 -0
  18. package/behaviors/crosshair.d.ts.map +1 -0
  19. package/behaviors/crosshair.js +19 -1
  20. package/behaviors/dialog.d.ts +20 -0
  21. package/behaviors/dialog.d.ts.map +1 -0
  22. package/behaviors/dialog.js +3 -0
  23. package/behaviors/disclosure.d.ts +10 -0
  24. package/behaviors/disclosure.d.ts.map +1 -0
  25. package/behaviors/disclosure.js +3 -0
  26. package/behaviors/dismissible.d.ts +10 -0
  27. package/behaviors/dismissible.d.ts.map +1 -0
  28. package/behaviors/dismissible.js +3 -0
  29. package/behaviors/forms.d.ts +27 -0
  30. package/behaviors/forms.d.ts.map +1 -0
  31. package/behaviors/forms.js +18 -5
  32. package/behaviors/glyph.d.ts +14 -0
  33. package/behaviors/glyph.d.ts.map +1 -0
  34. package/behaviors/glyph.js +24 -0
  35. package/behaviors/index.d.ts +31 -237
  36. package/behaviors/index.d.ts.map +1 -0
  37. package/behaviors/index.js +17 -0
  38. package/behaviors/inert.d.ts +20 -0
  39. package/behaviors/inert.d.ts.map +1 -0
  40. package/behaviors/inert.js +46 -0
  41. package/behaviors/internal.d.ts +25 -0
  42. package/behaviors/internal.d.ts.map +1 -0
  43. package/behaviors/internal.js +30 -1
  44. package/behaviors/legend.d.ts +35 -0
  45. package/behaviors/legend.d.ts.map +1 -0
  46. package/behaviors/legend.js +9 -0
  47. package/behaviors/menu.d.ts +16 -0
  48. package/behaviors/menu.d.ts.map +1 -0
  49. package/behaviors/menu.js +3 -0
  50. package/behaviors/modal.d.ts +41 -0
  51. package/behaviors/modal.d.ts.map +1 -0
  52. package/behaviors/modal.js +124 -0
  53. package/behaviors/popover.d.ts +28 -0
  54. package/behaviors/popover.d.ts.map +1 -0
  55. package/behaviors/popover.js +17 -17
  56. package/behaviors/spotlight.d.ts +17 -0
  57. package/behaviors/spotlight.d.ts.map +1 -0
  58. package/behaviors/spotlight.js +3 -0
  59. package/behaviors/table.d.ts +36 -0
  60. package/behaviors/table.d.ts.map +1 -0
  61. package/behaviors/table.js +48 -8
  62. package/behaviors/tabs.d.ts +20 -0
  63. package/behaviors/tabs.d.ts.map +1 -0
  64. package/behaviors/tabs.js +3 -0
  65. package/behaviors/theme.d.ts +54 -0
  66. package/behaviors/theme.d.ts.map +1 -0
  67. package/behaviors/theme.js +17 -0
  68. package/behaviors/toast.d.ts +49 -0
  69. package/behaviors/toast.d.ts.map +1 -0
  70. package/behaviors/toast.js +34 -2
  71. package/classes/classes.json +683 -13
  72. package/classes/index.d.ts +106 -2
  73. package/classes/index.js +249 -65
  74. package/connectors/index.d.ts +12 -0
  75. package/connectors/index.d.ts.map +1 -1
  76. package/connectors/index.js +23 -2
  77. package/css/app.css +26 -0
  78. package/css/bullet.css +108 -0
  79. package/css/code.css +98 -0
  80. package/css/content.css +15 -2
  81. package/css/crosshair.css +7 -7
  82. package/css/diff.css +153 -0
  83. package/css/disclosure.css +18 -4
  84. package/css/dots.css +37 -7
  85. package/css/feedback.css +39 -7
  86. package/css/forms.css +71 -3
  87. package/css/legend.css +5 -2
  88. package/css/motion.css +79 -14
  89. package/css/overlay.css +59 -2
  90. package/css/primitives.css +67 -8
  91. package/css/report.css +40 -0
  92. package/css/sidenote.css +67 -0
  93. package/css/spark.css +62 -0
  94. package/css/table.css +9 -2
  95. package/css/term.css +110 -0
  96. package/css/textref.css +63 -0
  97. package/css/toc.css +91 -0
  98. package/css/tokens.css +14 -1
  99. package/css/tree.css +134 -0
  100. package/dist/bronto.css +1 -1
  101. package/dist/css/analytical.css +1 -1
  102. package/dist/css/app.css +1 -1
  103. package/dist/css/bullet.css +1 -0
  104. package/dist/css/code.css +1 -0
  105. package/dist/css/content.css +1 -1
  106. package/dist/css/crosshair.css +1 -1
  107. package/dist/css/diff.css +1 -0
  108. package/dist/css/disclosure.css +1 -1
  109. package/dist/css/dots.css +1 -1
  110. package/dist/css/feedback.css +1 -1
  111. package/dist/css/forms.css +1 -1
  112. package/dist/css/legend.css +1 -1
  113. package/dist/css/motion.css +1 -1
  114. package/dist/css/overlay.css +1 -1
  115. package/dist/css/primitives.css +1 -1
  116. package/dist/css/report.css +1 -1
  117. package/dist/css/sidenote.css +1 -0
  118. package/dist/css/spark.css +1 -0
  119. package/dist/css/table.css +1 -1
  120. package/dist/css/term.css +1 -0
  121. package/dist/css/textref.css +1 -0
  122. package/dist/css/toc.css +1 -0
  123. package/dist/css/tokens.css +1 -1
  124. package/dist/css/tree.css +1 -0
  125. package/docs/annotations.md +39 -0
  126. package/docs/architecture.md +2 -3
  127. package/docs/bullet.md +78 -0
  128. package/docs/code.md +76 -0
  129. package/docs/d2.md +4 -3
  130. package/docs/diff.md +146 -0
  131. package/docs/legends.md +8 -4
  132. package/docs/mermaid.md +21 -4
  133. package/docs/reference.md +127 -8
  134. package/docs/reporting.md +35 -14
  135. package/docs/sidenote.md +64 -0
  136. package/docs/spark.md +78 -0
  137. package/docs/stability.md +1 -0
  138. package/docs/term.md +81 -0
  139. package/docs/textref.md +78 -0
  140. package/docs/theming.md +44 -5
  141. package/docs/toc.md +83 -0
  142. package/docs/tree.md +74 -0
  143. package/docs/usage.md +264 -23
  144. package/docs/vega.md +22 -3
  145. package/glyphs/glyphs.js +7 -1
  146. package/llms.txt +159 -13
  147. package/package.json +47 -7
  148. package/qwik/index.d.ts +4 -2
  149. package/qwik/index.d.ts.map +1 -1
  150. package/qwik/index.js +10 -0
  151. package/react/index.d.ts +4 -2
  152. package/react/index.d.ts.map +1 -1
  153. package/react/index.js +6 -0
  154. package/solid/index.d.ts +6 -2
  155. package/solid/index.d.ts.map +1 -1
  156. package/solid/index.js +6 -0
package/css/bullet.css ADDED
@@ -0,0 +1,108 @@
1
+ /* ==========================================================================
2
+ bullet — opt-in Stephen-Few bullet graph (measure vs target vs bands).
3
+
4
+ The canonical "is this measure inside its qualitative budget, and how does it
5
+ compare to target?" figure: a thin measure bar over 2–3 grayscale qualitative
6
+ range bands, with a perpendicular target tick. The SLO / error-budget figure
7
+ `ui-meter` (report.css) structurally cannot encode — a meter is a single
8
+ label|bar|value reading, a bullet carries bands + target too. Few designed it
9
+ grayscale on purpose, which is exactly the Nothing palette. Pure CSS,
10
+ SSR-static, print-survivable. Not imported by core.css.
11
+
12
+ Boundary: the HOST normalises EVERY value to 0..1 and sets custom props —
13
+ `--v` (measure), `--t` (target), `--b1`/`--b2` (the band boundaries). Bronto
14
+ only paints geometry; it refuses raw values and min/max/scale computation —
15
+ the same contract as `ui-spark`. A bare bullet is opaque to assistive tech, so
16
+ `.ui-bullet` MUST carry a host-written `role="img"` + `aria-label` text
17
+ equivalent (e.g. "uptime 99.62%, inside target 99.9%, in the warning band").
18
+ Colour is never the only channel — the reading lives in that label.
19
+ ========================================================================== */
20
+
21
+ .ui-bullet {
22
+ --band-lo: 0.5;
23
+ --band-hi: 0.8;
24
+
25
+ background: linear-gradient(
26
+ to right,
27
+ var(--surface-4) 0 calc(var(--band-lo) * 100%),
28
+ var(--surface-3) calc(var(--band-lo) * 100%) calc(var(--band-hi) * 100%),
29
+ var(--surface-2) calc(var(--band-hi) * 100%) 100%
30
+ );
31
+ block-size: 1.25rem;
32
+ border-radius: var(--radius-sm);
33
+ inline-size: 100%;
34
+ position: relative;
35
+ }
36
+
37
+ /* The measure bar — a thinner dark bar centred in the track, the primary value.
38
+ `--v` is the normalised reading; with none it collapses to a hairline. */
39
+ .ui-bullet__measure {
40
+ background: var(--text);
41
+ border-radius: var(--radius-sm);
42
+ inline-size: max(2px, calc(var(--v, 0) * 100%));
43
+ inset-block: 30%;
44
+ inset-inline-start: 0;
45
+ position: absolute;
46
+ }
47
+
48
+ /* Tone a measure for emphasis or status — the meaning still has to be in the
49
+ aria-label (WCAG 1.4.1), tone is decoration. */
50
+ .ui-bullet__measure--accent {
51
+ background: var(--accent);
52
+ }
53
+
54
+ .ui-bullet__measure--pos {
55
+ background: var(--success);
56
+ }
57
+
58
+ .ui-bullet__measure--neg {
59
+ background: var(--danger);
60
+ }
61
+
62
+ /* The target tick — a full-height perpendicular mark at `--t`. Shape, not
63
+ colour, distinguishes it from the measure bar (Few's grayscale rule). */
64
+ .ui-bullet__target {
65
+ background: var(--text);
66
+ inline-size: 2px;
67
+ inset-block: 8%;
68
+ inset-inline-start: calc(var(--t, 0) * 100%);
69
+ position: absolute;
70
+ transform: translateX(-50%);
71
+ }
72
+
73
+ /* Optional caption row beneath the track — label + reading in mono, matching
74
+ the report meter's value treatment. */
75
+ .ui-bullet__label {
76
+ color: var(--text-dim);
77
+ display: flex;
78
+ font-family: var(--mono);
79
+ font-size: var(--text-2xs);
80
+ gap: var(--space-sm);
81
+ justify-content: space-between;
82
+ letter-spacing: var(--tracking-wide);
83
+ margin-block-start: 0.3rem;
84
+ }
85
+
86
+ /* Forced colours flatten the band gradient to one system surface — the bands
87
+ would merge. Re-assert a track border so the figure keeps a frame, and repaint
88
+ the marks in the system text colour so measure + target survive (the band
89
+ distinction is carried by the required aria-label). */
90
+ @media (forced-colors: active) {
91
+ .ui-bullet {
92
+ border: 1px solid CanvasText;
93
+ }
94
+
95
+ .ui-bullet__measure,
96
+ .ui-bullet__target {
97
+ background: CanvasText;
98
+ }
99
+ }
100
+
101
+ /* Print: the bands + marks are background/currentColor fills the print economy
102
+ would drop. */
103
+ @media print {
104
+ .ui-bullet {
105
+ -webkit-print-color-adjust: exact;
106
+ print-color-adjust: exact;
107
+ }
108
+ }
package/css/code.css ADDED
@@ -0,0 +1,98 @@
1
+ /* ==========================================================================
2
+ code — opt-in fenced-code evidence chrome.
3
+
4
+ Paints already-tokenized code: a head bar, an optional line-number gutter
5
+ (CSS counters), and add / del / highlight line states. It NEVER parses or
6
+ tokenizes — the host (or Shiki, via the shipped `shiki/nothing.json` token
7
+ theme) supplies the coloured spans; Bronto owns only the chrome. Code-as-
8
+ evidence for changelogs, version history, and generated reports; pairs with
9
+ the `.ui-src` provenance pill and marks. Not imported by core.css.
10
+
11
+ Long lines wrap (no horizontal scroll) so the surface prints cleanly. Put a
12
+ `.ui-code__line` around each line to opt into numbering / line states; plain
13
+ text inside `.ui-code__body` works too (no numbers).
14
+ ========================================================================== */
15
+
16
+ .ui-code {
17
+ border: 1px solid var(--line);
18
+ border-radius: var(--radius-sm);
19
+ font-family: var(--mono);
20
+ font-size: var(--text-xs);
21
+ overflow: hidden;
22
+ }
23
+
24
+ .ui-code__head {
25
+ background: var(--surface-2);
26
+ border-block-end: 1px solid var(--line);
27
+ color: var(--text-dim);
28
+ display: flex;
29
+ gap: var(--space-sm);
30
+ justify-content: space-between;
31
+ padding: var(--space-2xs) var(--space-sm);
32
+ }
33
+
34
+ .ui-code__body {
35
+ counter-reset: ui-code-ln;
36
+ margin: 0;
37
+ overflow-wrap: anywhere;
38
+ padding: var(--space-sm) 0;
39
+ white-space: pre-wrap;
40
+ }
41
+
42
+ .ui-code__line {
43
+ display: block;
44
+ padding-inline: var(--space-sm);
45
+ }
46
+
47
+ /* Opt-in line-number gutter — counts each `.ui-code__line`. */
48
+ .ui-code--numbered .ui-code__line {
49
+ padding-inline-start: 0;
50
+ }
51
+
52
+ .ui-code--numbered .ui-code__line::before {
53
+ color: var(--text-dim);
54
+ content: counter(ui-code-ln);
55
+ counter-increment: ui-code-ln;
56
+ display: inline-block;
57
+ inline-size: 3ch;
58
+ margin-inline-end: var(--space-sm);
59
+ text-align: end;
60
+ /* stylelint-disable-next-line property-no-vendor-prefix -- WebKit still requires the prefixed slot for this selection opt-out. */
61
+ -webkit-user-select: none;
62
+ user-select: none;
63
+ }
64
+
65
+ /* Line states — the host classifies; Bronto tints. Kept as a faint wash so the
66
+ token colours stay legible on top. */
67
+ .ui-code__line--add {
68
+ background: color-mix(in srgb, var(--success) 14%, transparent);
69
+ }
70
+
71
+ .ui-code__line--remove {
72
+ background: color-mix(in srgb, var(--danger) 14%, transparent);
73
+ }
74
+
75
+ .ui-code__line--hl {
76
+ background: color-mix(in srgb, var(--accent) 14%, transparent);
77
+ }
78
+
79
+ /* Forced colours drop the tint — add an inline-start border so the line state
80
+ still reads without colour. */
81
+ @media (forced-colors: active) {
82
+ .ui-code__line--add,
83
+ .ui-code__line--remove,
84
+ .ui-code__line--hl {
85
+ border-inline-start: 3px solid currentColor;
86
+ }
87
+ }
88
+
89
+ /* Print: the line-state tints are meaning-carrying backgrounds. */
90
+ @media print {
91
+ .ui-code__head,
92
+ .ui-code__line--add,
93
+ .ui-code__line--remove,
94
+ .ui-code__line--hl {
95
+ -webkit-print-color-adjust: exact;
96
+ print-color-adjust: exact;
97
+ }
98
+ }
package/css/content.css CHANGED
@@ -104,7 +104,12 @@
104
104
  color: var(--text);
105
105
  }
106
106
 
107
- .ui-prose mark {
107
+ /* The bare prose `<mark>` is the plain UA-reset highlight. A `<mark class="ui-mark">`
108
+ is the opt-in marks leaf (marks.css) and must win: this rule is higher-specificity
109
+ (0,1,1) than `.ui-mark` (0,1,0) and sits in the same `bronto` layer, so without the
110
+ `:not(.ui-mark)` it silently overrides every `.ui-mark` tone/draw modifier in prose —
111
+ the most-documented mark usage. (component audit C1.) */
112
+ .ui-prose mark:not(.ui-mark) {
108
113
  background: var(--accent-soft);
109
114
  color: var(--text);
110
115
  padding: 0.02em 0.22em;
@@ -242,7 +247,15 @@
242
247
  text-transform: uppercase;
243
248
  }
244
249
 
245
- /* --- Table — raw Markdown tables look like ui-table --- */
250
+ /* --- Table — raw Markdown tables look like ui-table ---
251
+ `display: block` makes a wide markdown table scroll horizontally (markdown
252
+ emits a bare <table> with no wrappable container, so the scroll has to live on
253
+ the element itself). Caveat: `display: block` can drop the implicit `table`
254
+ ARIA role in WebKit/Safari (intact in Chromium/Firefox). It is acceptable here
255
+ because `.ui-prose` is generated prose, not a data grid — but for a table whose
256
+ semantics MUST survive on WebKit, author the `.ui-table` component inside a
257
+ `.ui-table-wrap` instead (the wrap scrolls, the <table> keeps `display: table`),
258
+ or add `role="table"` to the markdown output. (component audit C29.) */
246
259
 
247
260
  .ui-prose table {
248
261
  border: 1px solid var(--line);
package/css/crosshair.css CHANGED
@@ -40,18 +40,19 @@
40
40
  position: absolute;
41
41
  }
42
42
 
43
+ /* Positioned with logical insets, not a physical translateX/Y: --crosshair-x
44
+ is the offset from the inline-start edge (initCrosshair flips it in RTL), so
45
+ the vertical rule tracks the pointer correctly in both directions. */
43
46
  .ui-crosshair__line--x {
44
47
  inline-size: 1px;
45
48
  inset-block: 0;
46
- inset-inline-start: 0;
47
- transform: translateX(var(--crosshair-x));
49
+ inset-inline-start: var(--crosshair-x);
48
50
  }
49
51
 
50
52
  .ui-crosshair__line--y {
51
53
  block-size: 1px;
52
- inset-block-start: 0;
54
+ inset-block-start: var(--crosshair-y);
53
55
  inset-inline: 0;
54
- transform: translateY(var(--crosshair-y));
55
56
  }
56
57
 
57
58
  /* An axis value chip (host sets its text + which edge it sits on). On the
@@ -84,13 +85,12 @@
84
85
  color: var(--text);
85
86
  font-family: var(--mono);
86
87
  font-size: var(--text-xs);
87
- inset-block-start: 0;
88
- inset-inline-start: 0;
88
+ inset-block-start: var(--crosshair-y);
89
+ inset-inline-start: var(--crosshair-x);
89
90
  padding-block: 0.2rem;
90
91
  padding-inline: 0.4rem;
91
92
  pointer-events: none;
92
93
  position: absolute;
93
- transform: translate(var(--crosshair-x), var(--crosshair-y));
94
94
  }
95
95
 
96
96
  @media (forced-colors: active) {
package/css/diff.css ADDED
@@ -0,0 +1,153 @@
1
+ /* ==========================================================================
2
+ diff — opt-in line/row change-review grammar.
3
+
4
+ The review counterpart to the report layer: marks call out a sentence, diff
5
+ calls out what CHANGED. A CSS-grid gutter grammar for added / removed /
6
+ context rows with a redundant +/− sign glyph (so the meaning survives forced
7
+ colours and print, where the tint is dropped), tone tints, and tabular
8
+ line-number gutters. Not imported by core.css.
9
+
10
+ Boundary: the HOST supplies pre-classified rows — it owns tokenizing, hunk
11
+ computation, and row alignment; Bronto only paints. The moment this parsed or
12
+ aligned source it would cross the line that deleted the bar renderer in
13
+ 0.6.0. Pairs with `.ui-compare--2up` and the `.ui-src` provenance pill.
14
+
15
+ Unified (default): rows are direct children of `.ui-diff` (or a
16
+ `.ui-diff__hunk` rowgroup); columns are [old-ln] [new-ln] [code].
17
+ Split: `.ui-diff--split` holds two `.ui-diff__pane` columns, each [ln] [code];
18
+ the host emits the matching rows per side.
19
+
20
+ Long lines wrap (no horizontal scroll) so the surface prints cleanly; line
21
+ numbers pin to the top of a wrapped line. Line numbers are `user-select:none`
22
+ and should be `aria-hidden` in markup — the `__code` carries the content.
23
+ ========================================================================== */
24
+
25
+ .ui-diff {
26
+ --diff-add-bg: color-mix(in srgb, var(--success) 14%, transparent);
27
+ --diff-remove-bg: color-mix(in srgb, var(--danger) 14%, transparent);
28
+ --diff-add-ink: var(--success);
29
+ --diff-remove-ink: var(--danger);
30
+
31
+ border: 1px solid var(--line);
32
+ border-radius: var(--radius-sm);
33
+ display: grid;
34
+ font-family: var(--mono);
35
+ font-size: var(--text-xs);
36
+ grid-template-columns: auto auto minmax(0, 1fr);
37
+ line-height: 1.6;
38
+ overflow: hidden;
39
+ }
40
+
41
+ /* Split view: two independent panes side by side. Each pane is its own
42
+ [ln] [code] grid; the host aligns rows across panes (its job). */
43
+ .ui-diff--split {
44
+ grid-template-columns: 1fr 1fr;
45
+ }
46
+
47
+ .ui-diff__pane {
48
+ display: grid;
49
+ grid-template-columns: auto minmax(0, 1fr);
50
+ min-inline-size: 0;
51
+ }
52
+
53
+ .ui-diff--split > .ui-diff__pane + .ui-diff__pane {
54
+ border-inline-start: 1px solid var(--line);
55
+ }
56
+
57
+ /* A hunk groups rows under an optional header without breaking the grid:
58
+ display:contents keeps its rows as the grid's own items. */
59
+ .ui-diff__hunk {
60
+ display: contents;
61
+ }
62
+
63
+ /* Rows are layout-transparent — their cells are the real grid items, so the
64
+ tone tint paints on the cells (a display:contents row generates no box, and
65
+ the custom properties still inherit down the DOM to the cells). */
66
+ .ui-diff__row {
67
+ display: contents;
68
+ }
69
+
70
+ /* The hunk / file header spans every column. */
71
+ .ui-diff__head {
72
+ background: var(--surface-2);
73
+ color: var(--text-dim);
74
+ grid-column: 1 / -1;
75
+ padding: var(--space-2xs) var(--space-sm);
76
+ }
77
+
78
+ .ui-diff__ln {
79
+ align-self: start;
80
+ color: var(--text-dim);
81
+ font-variant-numeric: tabular-nums;
82
+ padding: 0 var(--space-sm);
83
+ text-align: end;
84
+ /* stylelint-disable-next-line property-no-vendor-prefix -- WebKit still requires the prefixed slot for this selection opt-out. */
85
+ -webkit-user-select: none;
86
+ user-select: none;
87
+ }
88
+
89
+ .ui-diff__code {
90
+ overflow-wrap: anywhere;
91
+ padding: 0 var(--space-sm);
92
+ white-space: pre-wrap;
93
+ }
94
+
95
+ /* The redundant sign glyph in the code gutter — a non-colour channel, so add /
96
+ remove still read once the tint is dropped (forced colours, print economy).
97
+ Context defaults to a non-breaking space so the code column stays aligned. */
98
+ .ui-diff__code::before {
99
+ color: var(--diff-tint, var(--text-dim));
100
+ content: var(--diff-sign, '\00a0');
101
+ display: inline-block;
102
+ inline-size: 1ch;
103
+ margin-inline-end: var(--space-2xs);
104
+ /* stylelint-disable-next-line property-no-vendor-prefix -- WebKit still requires the prefixed slot for this selection opt-out. */
105
+ -webkit-user-select: none;
106
+ user-select: none;
107
+ }
108
+
109
+ .ui-diff__row--add {
110
+ --diff-sign: '+';
111
+ --diff-tint: var(--diff-add-ink);
112
+ }
113
+
114
+ .ui-diff__row--remove {
115
+ --diff-sign: '\2212'; /* − U+2212 minus sign (decorative; not copied) */
116
+ --diff-tint: var(--diff-remove-ink);
117
+ }
118
+
119
+ .ui-diff__row--context {
120
+ --diff-sign: '\00a0';
121
+ }
122
+
123
+ .ui-diff__row--add > .ui-diff__ln,
124
+ .ui-diff__row--add > .ui-diff__code {
125
+ background: var(--diff-add-bg);
126
+ }
127
+
128
+ .ui-diff__row--remove > .ui-diff__ln,
129
+ .ui-diff__row--remove > .ui-diff__code {
130
+ background: var(--diff-remove-bg);
131
+ }
132
+
133
+ /* Forced colours drop the tint — the +/− glyph already carries the channel; add
134
+ an inline-start border on the changed code cell as a second, colour-free cue. */
135
+ @media (forced-colors: active) {
136
+ .ui-diff__row--add > .ui-diff__code,
137
+ .ui-diff__row--remove > .ui-diff__code {
138
+ border-inline-start: 2px solid currentColor;
139
+ }
140
+ }
141
+
142
+ /* Print: the tints are meaning-carrying backgrounds, so force them through the
143
+ print "economy" default that would otherwise drop them. */
144
+ @media print {
145
+ .ui-diff__head,
146
+ .ui-diff__row--add > .ui-diff__ln,
147
+ .ui-diff__row--add > .ui-diff__code,
148
+ .ui-diff__row--remove > .ui-diff__ln,
149
+ .ui-diff__row--remove > .ui-diff__code {
150
+ -webkit-print-color-adjust: exact;
151
+ print-color-adjust: exact;
152
+ }
153
+ }
@@ -303,14 +303,23 @@
303
303
  color var(--duration-fast) var(--ease-standard);
304
304
  }
305
305
 
306
- .ui-pagination__item.is-active {
306
+ /* Active page keys on BOTH `.is-active` and `[aria-current]` — usage.md calls
307
+ aria-current "the framework rule", and every nav sibling (breadcrumb, sitenav,
308
+ app-nav) highlights on it, so a pagination author who sets only aria-current
309
+ must still get the highlight. (component audit C17.) */
310
+ .ui-pagination__item.is-active,
311
+ .ui-pagination__item[aria-current]:not([aria-current='false']) {
307
312
  border-color: var(--accent);
308
313
  color: var(--accent-text);
309
314
  }
310
315
 
311
316
  /* Disabled covers BOTH the native `<button disabled>` the demo ships and the
312
- `aria-disabled="true"` ARIA path; `pointer-events: none` makes the
313
- aria-disabled item genuinely inert (it was clickable before C5). */
317
+ `aria-disabled="true"` ARIA path. `pointer-events: none` blocks POINTER
318
+ activation only a focused aria-disabled item still fires on Enter/Space
319
+ (CSS can't intercept keys). For a fully-inert control prefer native
320
+ `<button disabled>`, run `initDisabledGuard()` (intercepts Enter/Space), or
321
+ pair aria-disabled with `tabindex="-1"`. See docs/usage.md "Disabled vs
322
+ aria-disabled". (audit C4.) */
314
323
  .ui-pagination__item[aria-disabled='true'],
315
324
  .ui-pagination__item:disabled {
316
325
  cursor: not-allowed;
@@ -319,7 +328,12 @@
319
328
  }
320
329
 
321
330
  @media (hover: hover) {
322
- .ui-pagination__item:not(.is-active, [aria-disabled='true'], :disabled):hover {
331
+ .ui-pagination__item:not(
332
+ .is-active,
333
+ [aria-current]:not([aria-current='false']),
334
+ [aria-disabled='true'],
335
+ :disabled
336
+ ):hover {
323
337
  border-color: var(--line-strong);
324
338
  color: var(--text);
325
339
  }
package/css/dots.css CHANGED
@@ -348,14 +348,20 @@
348
348
  animation-delay: 0.63s;
349
349
  }
350
350
 
351
- /* Matrix-reveal wrapper — content wipes in left→right on .is-in. */
352
- .ui-matrix {
353
- clip-path: inset(0 100% 0 0);
354
- transition: clip-path var(--duration-slow) var(--ease-out);
355
- }
351
+ /* Matrix-reveal wrapper — content wipes in left→right on .is-in. Gate the
352
+ clipped from-state on `scripting: enabled`: with JS off, `.is-in` is never
353
+ toggled, so without the gate the content stays permanently clipped away and
354
+ invisible to every no-JS/static/print reader. Same graceful default as
355
+ `.ui-reveal`. (component audit C12.) */
356
+ @media (scripting: enabled) {
357
+ .ui-matrix {
358
+ clip-path: inset(0 100% 0 0);
359
+ transition: clip-path var(--duration-slow) var(--ease-out);
360
+ }
356
361
 
357
- .ui-matrix.is-in {
358
- clip-path: inset(0 0 0 0);
362
+ .ui-matrix.is-in {
363
+ clip-path: inset(0 0 0 0);
364
+ }
359
365
  }
360
366
 
361
367
  @media (prefers-reduced-motion: reduce) {
@@ -404,6 +410,30 @@
404
410
  background: ButtonText;
405
411
  }
406
412
 
413
+ /* Brand/live dots aren't status tones, but they still encode meaning via
414
+ background-color alone, which HCM flattens. Keep them on a distinct,
415
+ opted-out system colour for completeness. (audit C31.) */
416
+ .ui-dot--accent,
417
+ .ui-dot--live {
418
+ forced-color-adjust: none;
419
+ background: LinkText;
420
+ }
421
+
422
+ .ui-dot--live::after {
423
+ border-color: LinkText;
424
+ }
425
+
426
+ /* The masked one-node icon paints `background: currentcolor` through an SVG
427
+ mask. Under HCM, forced-color-adjust:auto can drop the mask fill so the
428
+ glyph vanishes (white-on-white) — yet .ui-icon is the recommended
429
+ icon-at-scale path AND backs .ui-legend__symbol, and the print block
430
+ already special-cases it. Opt out and pin the fill to the system text
431
+ colour so the glyph stays visible. (audit C1.) */
432
+ .ui-icon {
433
+ forced-color-adjust: none;
434
+ background: CanvasText;
435
+ }
436
+
407
437
  .ui-dotmatrix__cell--hot {
408
438
  forced-color-adjust: none;
409
439
  background: Highlight;
package/css/feedback.css CHANGED
@@ -4,6 +4,19 @@
4
4
  never a fill. Nothing-flat, hairline, sharp.
5
5
  ========================================================================== */
6
6
 
7
+ /* `--value` drives the progress/meter fill width: a UNITLESS number 0–100,
8
+ never a percentage. Registering it as `<number>` makes that contract real —
9
+ a stray `--value: 50%` is invalid against the typed syntax and falls back to
10
+ the initial `0` (empty bar) instead of poisoning the `clamp()` and painting a
11
+ FULL bar (the old failure mode). It inherits so the value set on the host
12
+ `.ui-meter` / `.ui-progress` cascades to the inner `__fill`/`__bar`.
13
+ (component audit C8.) */
14
+ @property --value {
15
+ syntax: '<number>';
16
+ inherits: true;
17
+ initial-value: 0;
18
+ }
19
+
7
20
  /* --- Alert / callout — inline, dismissible-compatible --- */
8
21
 
9
22
  .ui-alert {
@@ -50,7 +63,7 @@
50
63
  margin: 0;
51
64
  }
52
65
 
53
- .ui-alert__dismiss {
66
+ .ui-alert__close {
54
67
  background: transparent;
55
68
  border: 0;
56
69
  color: var(--text-dim);
@@ -62,7 +75,7 @@
62
75
  padding: 0.1rem 0.3rem;
63
76
  }
64
77
 
65
- .ui-alert:has(.ui-alert__dismiss) {
78
+ .ui-alert:has(.ui-alert__close) {
66
79
  grid-template-columns: auto 1fr auto;
67
80
  }
68
81
 
@@ -107,7 +120,7 @@
107
120
  }
108
121
 
109
122
  @media (hover: hover) {
110
- .ui-alert__dismiss:hover {
123
+ .ui-alert__close:hover {
111
124
  color: var(--text);
112
125
  }
113
126
  }
@@ -216,7 +229,7 @@
216
229
  tap-target floor (2.9rem, as in primitives.css / forms.css) without changing
217
230
  the desktop glyph size. The box is centred so the glyph stays put. */
218
231
  @media (pointer: coarse) {
219
- .ui-alert__dismiss,
232
+ .ui-alert__close,
220
233
  .ui-toast__close {
221
234
  display: inline-grid;
222
235
  place-items: center;
@@ -224,7 +237,7 @@
224
237
  min-inline-size: 2.9rem;
225
238
  }
226
239
 
227
- .ui-alert__dismiss {
240
+ .ui-alert__close {
228
241
  padding: 0;
229
242
  }
230
243
  }
@@ -453,6 +466,18 @@
453
466
  @media (prefers-reduced-motion: reduce) {
454
467
  .ui-progress--indeterminate .ui-progress__bar {
455
468
  animation-duration: 0.01ms;
469
+
470
+ /* A still, solid, full-width bar reads as "100% complete" — the opposite of
471
+ indeterminate. Fall back to a static diagonal hatch that fills the track
472
+ (so it's clearly active) but doesn't read as done. AT is covered via
473
+ aria-busy. (audit C26.) */
474
+ background: repeating-linear-gradient(
475
+ -45deg,
476
+ var(--accent) 0,
477
+ var(--accent) 0.3rem,
478
+ color-mix(in srgb, var(--accent) 35%, transparent) 0.3rem,
479
+ color-mix(in srgb, var(--accent) 35%, transparent) 0.6rem
480
+ );
456
481
  inset-inline-start: 0;
457
482
  inline-size: 100%;
458
483
  }
@@ -467,7 +492,9 @@
467
492
  (task progress, can be indeterminate), a meter shows a measured static
468
493
  value for data display (coverage, capacity, a KPI against a target).
469
494
  Drive the fill with the same --value knob as progress; tone the fill by
470
- threshold. Author role="meter" + aria-valuenow/min/max for AT. --- */
495
+ threshold. Author role="meter" + aria-valuenow/min/max for AT but role=meter
496
+ has uneven AT support, so keep the visible .ui-meter__label/__value (they are
497
+ the real channel, not just decoration). (component audit C25.) --- */
471
498
 
472
499
  .ui-meter {
473
500
  background: var(--panel-soft);
@@ -534,7 +561,12 @@
534
561
  font-size: var(--text-xs);
535
562
  gap: 0.5rem;
536
563
  letter-spacing: var(--tracking-wide);
537
- min-inline-size: max-content;
564
+
565
+ /* Prefer the natural one-line width, but never wider than the container: a
566
+ long step label at `max-content` couldn't shrink and overflowed the page on
567
+ narrow viewports (tabs scroll; steps didn't). Capping at 100% lets an
568
+ over-long label wrap instead of overflowing. (component audit C18.) */
569
+ min-inline-size: min(100%, max-content);
538
570
  text-transform: uppercase;
539
571
  }
540
572