@ponchia/ui 0.4.1 → 0.6.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 (153) hide show
  1. package/CHANGELOG.md +552 -8
  2. package/MIGRATIONS.json +106 -0
  3. package/README.md +34 -8
  4. package/annotations/index.d.ts +402 -0
  5. package/annotations/index.d.ts.map +1 -0
  6. package/annotations/index.js +792 -0
  7. package/behaviors/carousel.js +198 -0
  8. package/behaviors/combobox.js +226 -0
  9. package/behaviors/command.js +190 -0
  10. package/behaviors/connectors.js +95 -0
  11. package/behaviors/crosshair.js +57 -0
  12. package/behaviors/dialog.js +74 -0
  13. package/behaviors/disclosure.js +26 -0
  14. package/behaviors/dismissible.js +25 -0
  15. package/behaviors/forms.js +186 -0
  16. package/behaviors/glyph.js +108 -0
  17. package/behaviors/index.d.ts +79 -0
  18. package/behaviors/index.js +18 -1409
  19. package/behaviors/internal.js +97 -0
  20. package/behaviors/legend.js +67 -0
  21. package/behaviors/menu.js +47 -0
  22. package/behaviors/popover.js +179 -0
  23. package/behaviors/spotlight.js +52 -0
  24. package/behaviors/table.js +136 -0
  25. package/behaviors/tabs.js +103 -0
  26. package/behaviors/theme.js +84 -0
  27. package/behaviors/toast.js +164 -0
  28. package/classes/classes.json +1857 -0
  29. package/classes/index.d.ts +306 -13
  30. package/classes/index.js +339 -12
  31. package/classes/vscode.css-custom-data.json +12 -0
  32. package/connectors/index.d.ts +191 -0
  33. package/connectors/index.d.ts.map +1 -0
  34. package/connectors/index.js +275 -0
  35. package/css/analytical.css +21 -0
  36. package/css/annotations.css +292 -0
  37. package/css/app.css +43 -13
  38. package/css/base.css +15 -10
  39. package/css/command.css +97 -0
  40. package/css/connectors.css +110 -0
  41. package/css/content.css +7 -1
  42. package/css/crosshair.css +100 -0
  43. package/css/dataviz.css +5 -1
  44. package/css/disclosure.css +38 -6
  45. package/css/dots.css +57 -0
  46. package/css/feedback.css +111 -2
  47. package/css/fonts.css +11 -7
  48. package/css/forms.css +42 -1
  49. package/css/generated.css +117 -0
  50. package/css/legend.css +272 -0
  51. package/css/marks.css +174 -0
  52. package/css/motion.css +24 -44
  53. package/css/navigation.css +7 -0
  54. package/css/overlay.css +31 -1
  55. package/css/primitives.css +109 -5
  56. package/css/report.css +39 -81
  57. package/css/selection.css +46 -0
  58. package/css/site.css +16 -2
  59. package/css/sources.css +221 -0
  60. package/css/spotlight.css +104 -0
  61. package/css/state.css +121 -0
  62. package/css/tokens.css +60 -37
  63. package/css/workbench.css +83 -0
  64. package/dist/bronto.css +1 -1
  65. package/dist/css/analytical.css +1 -0
  66. package/dist/css/annotations.css +1 -0
  67. package/dist/css/app.css +1 -1
  68. package/dist/css/base.css +1 -1
  69. package/dist/css/command.css +1 -0
  70. package/dist/css/connectors.css +1 -0
  71. package/dist/css/content.css +1 -1
  72. package/dist/css/crosshair.css +1 -0
  73. package/dist/css/disclosure.css +1 -1
  74. package/dist/css/dots.css +1 -1
  75. package/dist/css/feedback.css +1 -1
  76. package/dist/css/fonts.css +1 -1
  77. package/dist/css/forms.css +1 -1
  78. package/dist/css/generated.css +1 -0
  79. package/dist/css/legend.css +1 -0
  80. package/dist/css/marks.css +1 -0
  81. package/dist/css/motion.css +1 -1
  82. package/dist/css/navigation.css +1 -1
  83. package/dist/css/overlay.css +1 -1
  84. package/dist/css/primitives.css +1 -1
  85. package/dist/css/report.css +1 -1
  86. package/dist/css/selection.css +1 -0
  87. package/dist/css/site.css +1 -1
  88. package/dist/css/sources.css +1 -0
  89. package/dist/css/spotlight.css +1 -0
  90. package/dist/css/state.css +1 -0
  91. package/dist/css/tokens.css +1 -1
  92. package/dist/css/workbench.css +1 -0
  93. package/docs/adr/0003-theme-model.md +7 -4
  94. package/docs/annotations.md +425 -0
  95. package/docs/architecture.md +246 -0
  96. package/docs/command.md +95 -0
  97. package/docs/connectors.md +91 -0
  98. package/docs/contrast.md +116 -92
  99. package/docs/crosshair.md +63 -0
  100. package/docs/d2.md +195 -0
  101. package/docs/generated.md +91 -0
  102. package/docs/legends.md +184 -0
  103. package/docs/marks.md +93 -0
  104. package/docs/mermaid.md +152 -0
  105. package/docs/reference.md +385 -23
  106. package/docs/reporting.md +436 -63
  107. package/docs/selection.md +40 -0
  108. package/docs/sources.md +137 -0
  109. package/docs/spotlight.md +78 -0
  110. package/docs/stability.md +24 -2
  111. package/docs/state.md +85 -0
  112. package/docs/usage.md +123 -4
  113. package/docs/vega.md +225 -0
  114. package/docs/workbench.md +78 -0
  115. package/fonts/doto-400.woff2 +0 -0
  116. package/fonts/doto-500.woff2 +0 -0
  117. package/fonts/doto-600.woff2 +0 -0
  118. package/fonts/doto-700.woff2 +0 -0
  119. package/fonts/doto-800.woff2 +0 -0
  120. package/fonts/doto-900.woff2 +0 -0
  121. package/glyphs/glyphs.js +6 -4
  122. package/llms.txt +362 -14
  123. package/package.json +115 -12
  124. package/qwik/index.d.ts +42 -54
  125. package/qwik/index.d.ts.map +1 -0
  126. package/qwik/index.js +75 -3
  127. package/react/index.d.ts +39 -56
  128. package/react/index.d.ts.map +1 -0
  129. package/react/index.js +67 -3
  130. package/solid/index.d.ts +64 -56
  131. package/solid/index.d.ts.map +1 -0
  132. package/solid/index.js +70 -3
  133. package/tokens/d2.d.ts +38 -0
  134. package/tokens/d2.js +71 -0
  135. package/tokens/d2.json +43 -0
  136. package/tokens/index.d.ts +5 -5
  137. package/tokens/index.js +23 -5
  138. package/tokens/index.json +9 -0
  139. package/tokens/mermaid.d.ts +23 -0
  140. package/tokens/mermaid.js +181 -0
  141. package/tokens/mermaid.json +163 -0
  142. package/tokens/resolved.json +45 -1
  143. package/tokens/skins.js +3 -2
  144. package/tokens/tokens.dtcg.json +26 -0
  145. package/tokens/vega.d.ts +34 -0
  146. package/tokens/vega.js +155 -0
  147. package/tokens/vega.json +179 -0
  148. package/fonts/doto-400.ttf +0 -0
  149. package/fonts/doto-500.ttf +0 -0
  150. package/fonts/doto-600.ttf +0 -0
  151. package/fonts/doto-700.ttf +0 -0
  152. package/fonts/doto-800.ttf +0 -0
  153. package/fonts/doto-900.ttf +0 -0
package/css/base.css CHANGED
@@ -12,7 +12,10 @@ html {
12
12
  background: var(--bg);
13
13
  color: var(--text);
14
14
  font-family: var(--sans);
15
- font-size: 15px;
15
+
16
+ /* = 15px at the 16px default, but rem honours a user's browser font-size
17
+ preference (which a px root would ignore). */
18
+ font-size: 0.9375rem;
16
19
  line-height: 1.55;
17
20
  scroll-behavior: smooth;
18
21
  text-rendering: optimizeLegibility;
@@ -24,12 +27,16 @@ body {
24
27
  background: var(--bg);
25
28
  color: var(--text);
26
29
  margin: 0;
27
- min-block-size: 100vh;
30
+ min-block-size: 100dvh;
28
31
  position: relative;
29
32
  }
30
33
 
34
+ :root {
35
+ --scroll-offset: 6rem;
36
+ }
37
+
31
38
  main [id] {
32
- scroll-margin-top: 6rem;
39
+ scroll-margin-block-start: var(--scroll-offset);
33
40
  }
34
41
 
35
42
  ::selection {
@@ -176,6 +183,7 @@ textarea:focus-visible,
176
183
 
177
184
  .ui-display {
178
185
  font-family: var(--display);
186
+ font-weight: var(--display-weight);
179
187
  text-transform: uppercase;
180
188
  }
181
189
 
@@ -219,13 +227,10 @@ textarea:focus-visible,
219
227
  outline-offset: -2px;
220
228
  }
221
229
 
222
- /* The active tab signals selection only via accent colour/border, both
223
- flattened by the forced palettere-assert it with a system colour
224
- so the selected tab stays distinguishable (a11y review L3). */
225
- .ui-tab.is-active {
226
- border-block-end-color: Highlight;
227
- color: Highlight;
228
- }
230
+ /* NB: the active-tab forced-colors re-assert lives in disclosure.css, right
231
+ after the `.ui-tab.is-active` defaultplacing it here (an earlier bundle
232
+ leaf) let the later default win even in forced-colors mode, since @media
233
+ adds no specificity. (a11y review C10.) */
229
234
 
230
235
  /* Keyboard focus must never depend on a colour that gets overridden. */
231
236
  a:focus-visible,
@@ -0,0 +1,97 @@
1
+ /* ==========================================================================
2
+ command — opt-in command-palette shell (the command-first tier).
3
+
4
+ A filter input over a listbox of commands, grouped, with shortcut hints. The
5
+ CSS shell only; `initCommand` (behaviors) does the filtering + roving focus +
6
+ selection event. Bronto navigates a DOM-authored list; the HOST owns the
7
+ action registry, routing, and execution. Open it yourself (e.g. inside a
8
+ native <dialog> via initDialog) — there is no global Cmd/Ctrl+K. Pairs with
9
+ the `.ui-shortcut` hint. Not imported by core.css.
10
+ ========================================================================== */
11
+
12
+ .ui-command {
13
+ background: var(--panel-strong);
14
+ border: 1px solid var(--line-strong);
15
+ border-radius: var(--radius-md);
16
+ display: grid;
17
+ grid-template-rows: auto 1fr auto;
18
+ max-block-size: min(28rem, 70vh);
19
+ overflow: hidden;
20
+ }
21
+
22
+ .ui-command__input {
23
+ background: transparent;
24
+ border: 0;
25
+ border-block-end: 1px solid var(--line);
26
+ color: var(--text);
27
+ font-family: inherit;
28
+ font-size: var(--text-base);
29
+ inline-size: 100%;
30
+ padding: 0.85rem 1rem;
31
+ }
32
+
33
+ .ui-command__input::placeholder {
34
+ color: var(--text-dim);
35
+ }
36
+
37
+ .ui-command__list {
38
+ list-style: none;
39
+ margin: 0;
40
+ overflow-y: auto;
41
+ padding: var(--space-2xs);
42
+ }
43
+
44
+ .ui-command__group {
45
+ color: var(--text-dim);
46
+ font-family: var(--mono);
47
+ font-size: var(--text-2xs);
48
+ letter-spacing: var(--tracking-wide);
49
+ padding: 0.5rem 0.6rem 0.25rem;
50
+ text-transform: uppercase;
51
+ }
52
+
53
+ .ui-command__item {
54
+ align-items: center;
55
+ border-radius: var(--radius-sm);
56
+ color: var(--text-soft);
57
+ cursor: pointer;
58
+ display: flex;
59
+ gap: 0.6rem;
60
+ padding: 0.5rem 0.6rem;
61
+ }
62
+
63
+ /* `display: flex` would otherwise beat the UA `[hidden]` rule, so a
64
+ filtered-out item stays visible — re-assert none for hidden items/groups. */
65
+ .ui-command__item[hidden],
66
+ .ui-command__group[hidden] {
67
+ display: none;
68
+ }
69
+
70
+ .ui-command__item.is-active {
71
+ background: color-mix(in srgb, var(--accent) 14%, transparent);
72
+ color: var(--text);
73
+ }
74
+
75
+ .ui-command__shortcut {
76
+ color: var(--text-dim);
77
+ margin-inline-start: auto;
78
+ }
79
+
80
+ .ui-command__meta {
81
+ color: var(--text-dim);
82
+ font-family: var(--mono);
83
+ font-size: var(--text-2xs);
84
+ margin-inline-start: auto;
85
+ }
86
+
87
+ .ui-command__empty {
88
+ color: var(--text-dim);
89
+ padding: 0.85rem 1rem;
90
+ }
91
+
92
+ @media (forced-colors: active) {
93
+ .ui-command__item.is-active {
94
+ background: Highlight;
95
+ color: HighlightText;
96
+ }
97
+ }
@@ -0,0 +1,110 @@
1
+ /* ==========================================================================
2
+ connectors — opt-in leader lines between two DOM elements.
3
+
4
+ An overlay SVG (`.ui-connector`) sits inside a positioned container and draws
5
+ a line from one element to another — connect a note to a card, a card to a
6
+ chart point, two related regions. Bronto styles and (optionally, via
7
+ `initConnectors`) draws/tracks the line; the geometry helpers in
8
+ `@ponchia/ui/connectors` compute the path. Not imported by core.css.
9
+
10
+ Monochrome by default; the rationed accent and status tones are opt-in.
11
+ ========================================================================== */
12
+
13
+ .ui-connector {
14
+ --connector-color: var(--line-strong);
15
+
16
+ color: var(--connector-color);
17
+ inset: 0;
18
+ overflow: visible;
19
+ pointer-events: none;
20
+ position: absolute;
21
+ }
22
+
23
+ .ui-connector__path {
24
+ fill: none;
25
+ stroke: var(--connector-color);
26
+ stroke-linecap: round;
27
+ stroke-linejoin: round;
28
+ stroke-width: var(--connector-width, 1.5);
29
+ vector-effect: non-scaling-stroke;
30
+ }
31
+
32
+ .ui-connector__end {
33
+ fill: var(--connector-color);
34
+ stroke: none;
35
+ }
36
+
37
+ .ui-connector--dashed .ui-connector__path {
38
+ stroke-dasharray: 4 3;
39
+ }
40
+
41
+ .ui-connector--accent {
42
+ --connector-color: var(--accent);
43
+ }
44
+
45
+ .ui-connector--muted {
46
+ --connector-color: var(--line);
47
+ }
48
+
49
+ .ui-connector--success {
50
+ --connector-color: var(--success);
51
+ }
52
+
53
+ .ui-connector--warning {
54
+ --connector-color: var(--warning);
55
+ }
56
+
57
+ .ui-connector--danger {
58
+ --connector-color: var(--danger);
59
+ }
60
+
61
+ .ui-connector--info {
62
+ --connector-color: var(--info);
63
+ }
64
+
65
+ /* Draw-on: the path strokes in once. Requires pathLength="1" on the path
66
+ (initConnectors sets it); reduced motion shows the finished line. */
67
+ @media (prefers-reduced-motion: no-preference) {
68
+ .ui-connector--draw .ui-connector__path {
69
+ animation: ui-connector-draw 0.6s ease both;
70
+ stroke-dasharray: 1;
71
+ }
72
+ }
73
+
74
+ @keyframes ui-connector-draw {
75
+ from {
76
+ stroke-dashoffset: 1;
77
+ }
78
+
79
+ to {
80
+ stroke-dashoffset: 0;
81
+ }
82
+ }
83
+
84
+ /* Forced colours: keep the line visible as a system colour. */
85
+ @media (forced-colors: active) {
86
+ .ui-connector__path {
87
+ stroke: CanvasText;
88
+ }
89
+
90
+ .ui-connector__end {
91
+ fill: CanvasText;
92
+ }
93
+ }
94
+
95
+ /* Print: keep the relationship lines and arrowheads in their meaning-carrying
96
+ colour, and settle any draw-on to a solid line (the draw needs JS to set
97
+ pathLength, which never runs for a static PDF). */
98
+ @media print {
99
+ .ui-connector__path,
100
+ .ui-connector__end {
101
+ -webkit-print-color-adjust: exact;
102
+ print-color-adjust: exact;
103
+ }
104
+
105
+ .ui-connector--draw .ui-connector__path {
106
+ animation: none;
107
+ stroke-dasharray: none;
108
+ stroke-dashoffset: 0;
109
+ }
110
+ }
package/css/content.css CHANGED
@@ -13,6 +13,11 @@
13
13
  font-size: var(--text-base);
14
14
  line-height: 1.7;
15
15
 
16
+ /* Machine-generated Markdown carries long unbreakable tokens (URLs, hashes,
17
+ code) that otherwise force horizontal page scroll on the prose surface
18
+ itself. Break them. (css-robustness review C9; the table cell already does.) */
19
+ overflow-wrap: break-word;
20
+
16
21
  /* Readable measure; the container can still be wider for tables/media. */
17
22
  --prose-measure: 72ch;
18
23
  }
@@ -75,7 +80,7 @@
75
80
 
76
81
  /* Anchored headings clear a sticky chrome and expose a dot on hover. */
77
82
  .ui-prose :is(h1, h2, h3, h4, h5, h6)[id] {
78
- scroll-margin-block-start: 6rem;
83
+ scroll-margin-block-start: var(--scroll-offset);
79
84
  }
80
85
 
81
86
  /* --- Text-level --- */
@@ -300,6 +305,7 @@
300
305
  display: grid;
301
306
  font-family: var(--display);
302
307
  font-size: var(--text-xl);
308
+ font-weight: var(--display-weight);
303
309
  gap: var(--space-sm);
304
310
  line-height: 1.2;
305
311
  margin-block: var(--space-xl);
@@ -0,0 +1,100 @@
1
+ /* ==========================================================================
2
+ crosshair — opt-in ruler + readout for reading a value off a plot.
3
+
4
+ A pointer-tracking crosshair (vertical/horizontal rules), axis value badges,
5
+ and a pinned readout chip — the *visual* language of precise reading. Bronto
6
+ draws the rules and (via `initCrosshair`) tracks the pointer, setting
7
+ `--crosshair-x/y` (pixels within the plot) and emitting the pointer position
8
+ as a fraction. It does NOT find the nearest data point or map pixels to data
9
+ — that needs the host's scales. Not imported by core.css.
10
+ ========================================================================== */
11
+
12
+ .ui-crosshair {
13
+ --crosshair-x: 0;
14
+ --crosshair-y: 0;
15
+ --crosshair-color: var(--accent);
16
+
17
+ inset: 0;
18
+ opacity: 0;
19
+ pointer-events: none;
20
+ position: absolute;
21
+ transition: opacity 0.12s ease;
22
+ }
23
+
24
+ .ui-crosshair.is-active {
25
+ opacity: 1;
26
+ }
27
+
28
+ @media (prefers-reduced-motion: reduce) {
29
+ .ui-crosshair {
30
+ transition: none;
31
+ }
32
+ }
33
+
34
+ .ui-crosshair--muted {
35
+ --crosshair-color: var(--line-strong);
36
+ }
37
+
38
+ .ui-crosshair__line {
39
+ background: var(--crosshair-color);
40
+ position: absolute;
41
+ }
42
+
43
+ .ui-crosshair__line--x {
44
+ inline-size: 1px;
45
+ inset-block: 0;
46
+ inset-inline-start: 0;
47
+ transform: translateX(var(--crosshair-x));
48
+ }
49
+
50
+ .ui-crosshair__line--y {
51
+ block-size: 1px;
52
+ inset-block-start: 0;
53
+ inset-inline: 0;
54
+ transform: translateY(var(--crosshair-y));
55
+ }
56
+
57
+ /* An axis value chip (host sets its text + which edge it sits on). On the
58
+ accent fill it uses the tested on-accent text (same as buttons). */
59
+ .ui-crosshair__badge {
60
+ background: var(--crosshair-color);
61
+ border-radius: var(--radius-sm);
62
+ color: var(--button-text);
63
+ font-family: var(--mono);
64
+ font-size: var(--text-2xs);
65
+ padding-block: 0.05rem;
66
+ padding-inline: 0.3rem;
67
+ position: absolute;
68
+ white-space: nowrap;
69
+ }
70
+
71
+ /* The muted crosshair's grey fill can't carry on-accent text — use a neutral chip. */
72
+ .ui-crosshair--muted .ui-crosshair__badge {
73
+ background: var(--panel);
74
+ border: 1px solid var(--line-strong);
75
+ color: var(--text);
76
+ }
77
+
78
+ /* A pinned readout chip — host fills the content; it follows the crosshair. */
79
+ .ui-readout {
80
+ background: var(--panel);
81
+ border: 1px solid var(--line);
82
+ border-radius: var(--radius-sm);
83
+ box-shadow: var(--shadow-raised);
84
+ color: var(--text);
85
+ font-family: var(--mono);
86
+ font-size: var(--text-xs);
87
+ inset-block-start: 0;
88
+ inset-inline-start: 0;
89
+ padding-block: 0.2rem;
90
+ padding-inline: 0.4rem;
91
+ pointer-events: none;
92
+ position: absolute;
93
+ transform: translate(var(--crosshair-x), var(--crosshair-y));
94
+ }
95
+
96
+ @media (forced-colors: active) {
97
+ .ui-crosshair__line {
98
+ background: CanvasText;
99
+ }
100
+ }
package/css/dataviz.css CHANGED
@@ -30,7 +30,11 @@
30
30
  --chart-div-6: oklch(66% 0.13 55deg);
31
31
  --chart-div-7: oklch(56% 0.15 45deg);
32
32
 
33
- /* Dot-matrix pattern fills — pair with the matching colour (WCAG 1.4.1). */
33
+ /* Dot-matrix pattern fills — pair with the matching colour (WCAG 1.4.1).
34
+ Series 1 (the accent) is intentionally `none`: absence-of-pattern IS its
35
+ redundant channel. The colour palette is CVD-safe on its own (gated by
36
+ check:charts), so a colour+pattern chart stays distinguishable; a
37
+ pattern-ONLY chart must still give series 1 a fill or a labelled legend. */
34
38
  --chart-pattern-size: 8px;
35
39
  --chart-pattern-ink: rgb(0 0 0 / 0.34);
36
40
  --chart-pattern-1: none;
@@ -44,11 +44,29 @@
44
44
  border-color var(--duration-fast) var(--ease-standard);
45
45
  }
46
46
 
47
+ /* Coarse-pointer tap-target floor (~2.9rem ≈ 44px), matching inputs/sitenav —
48
+ tabs are easy to mis-tap on touch (WCAG 2.5.8 — C24). */
49
+ @media (pointer: coarse) {
50
+ .ui-tab {
51
+ min-block-size: 2.9rem;
52
+ }
53
+ }
54
+
47
55
  .ui-tab.is-active {
48
56
  border-block-end-color: var(--accent);
49
57
  color: var(--accent-text);
50
58
  }
51
59
 
60
+ /* Forced-colors re-assert MUST sit after the default above (same specificity,
61
+ @media adds none) or the accent default wins and the selected tab loses its
62
+ only cue. Moved here from base.css, an earlier bundle leaf. (a11y review C10.) */
63
+ @media (forced-colors: active) {
64
+ .ui-tab.is-active {
65
+ border-block-end-color: Highlight;
66
+ color: Highlight;
67
+ }
68
+ }
69
+
52
70
  .ui-tab:focus-visible {
53
71
  /* An inset box, deliberately distinct from the .is-active bottom-border
54
72
  so focus ≠ selection for low-vision keyboard users: the global
@@ -199,7 +217,7 @@
199
217
 
200
218
  .ui-segmented__option:has(input:focus-visible) {
201
219
  outline: 2px solid var(--focus-ring);
202
- outline-offset: 2px;
220
+ outline-offset: -2px;
203
221
  }
204
222
 
205
223
  @media (hover: hover) {
@@ -240,7 +258,7 @@
240
258
  inline-size: 0.22rem;
241
259
  }
242
260
 
243
- .ui-breadcrumb__item[aria-current] {
261
+ .ui-breadcrumb__item[aria-current]:not([aria-current='false']) {
244
262
  color: var(--text);
245
263
  }
246
264
 
@@ -290,18 +308,32 @@
290
308
  color: var(--accent-text);
291
309
  }
292
310
 
293
- .ui-pagination__item[aria-disabled='true'] {
311
+ /* 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). */
314
+ .ui-pagination__item[aria-disabled='true'],
315
+ .ui-pagination__item:disabled {
294
316
  cursor: not-allowed;
295
317
  opacity: 0.4;
318
+ pointer-events: none;
296
319
  }
297
320
 
298
321
  @media (hover: hover) {
299
- .ui-pagination__item:not(.is-active, [aria-disabled='true']):hover {
322
+ .ui-pagination__item:not(.is-active, [aria-disabled='true'], :disabled):hover {
300
323
  border-color: var(--line-strong);
301
324
  color: var(--text);
302
325
  }
303
326
  }
304
327
 
328
+ /* Coarse-pointer tap-target floor, matching inputs/sitenav (~2.9rem ≈ 44px) —
329
+ pagination controls are easy to mis-tap on touch (WCAG 2.5.8 — C24). */
330
+ @media (pointer: coarse) {
331
+ .ui-pagination__item {
332
+ min-block-size: 2.9rem;
333
+ min-inline-size: 2.9rem;
334
+ }
335
+ }
336
+
305
337
  /* --- Avatar — sharp, monospace initials or image --- */
306
338
 
307
339
  .ui-avatar {
@@ -429,8 +461,8 @@
429
461
  .ui-carousel__prev::before,
430
462
  .ui-carousel__next::before {
431
463
  block-size: 0.5rem;
432
- border-block-start: 1.5px solid currentColor;
433
- border-inline-end: 1.5px solid currentColor;
464
+ border-block-start: 1.5px solid currentcolor;
465
+ border-inline-end: 1.5px solid currentcolor;
434
466
  content: '';
435
467
  inline-size: 0.5rem;
436
468
  }
package/css/dots.css CHANGED
@@ -281,6 +281,13 @@
281
281
  transform: rotate(315deg) translateY(calc(var(--ds-box) / -2 + var(--ds-dot) / 2));
282
282
  }
283
283
 
284
+ /* The comet expects exactly 8 `<i>`; a 9th+ child has no rotation rule and
285
+ would pile up dead-centre. Hide the overflow so extra children fail safe
286
+ rather than rendering a stray static dot (C26). */
287
+ .ui-dotspinner i:nth-child(n + 9) {
288
+ display: none;
289
+ }
290
+
284
291
  .ui-dotspinner--sm {
285
292
  --ds-box: 1.05rem;
286
293
  --ds-dot: 0.18rem;
@@ -370,3 +377,53 @@
370
377
  clip-path: none;
371
378
  }
372
379
  }
380
+
381
+ /* Forced-colors (Windows HCM): semantic status dots and hot/accent matrix
382
+ cells encode meaning purely via background-color, which collapses to one
383
+ system colour under HCM (WCAG 1.4.1). Opt out of forced-color remapping and
384
+ apply four visually-distinct system colours so the signals stay
385
+ differentiable. */
386
+ @media (forced-colors: active) {
387
+ .ui-dot--success {
388
+ forced-color-adjust: none;
389
+ background: LinkText;
390
+ }
391
+
392
+ .ui-dot--warning {
393
+ forced-color-adjust: none;
394
+ background: Mark;
395
+ }
396
+
397
+ .ui-dot--danger {
398
+ forced-color-adjust: none;
399
+ background: Highlight;
400
+ }
401
+
402
+ .ui-dot--info {
403
+ forced-color-adjust: none;
404
+ background: ButtonText;
405
+ }
406
+
407
+ .ui-dotmatrix__cell--hot {
408
+ forced-color-adjust: none;
409
+ background: Highlight;
410
+ }
411
+
412
+ .ui-dotmatrix__cell--accent {
413
+ forced-color-adjust: none;
414
+ background: LinkText;
415
+ }
416
+ }
417
+
418
+ /* Print: the dot surfaces carry data (heatmap cells, the segmented meter, the
419
+ status dot, the masked glyph), so their painted fills must survive the print
420
+ "economy" default that drops backgrounds. */
421
+ @media print {
422
+ .ui-dotmatrix__cell,
423
+ .ui-dotbar i,
424
+ .ui-dot,
425
+ .ui-icon {
426
+ -webkit-print-color-adjust: exact;
427
+ print-color-adjust: exact;
428
+ }
429
+ }