actual-css 0.2.0 → 0.3.1

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 (214) hide show
  1. package/CHANGELOG.md +49 -1
  2. package/README.md +24 -9
  3. package/dist/actual-themes.min.css +1 -0
  4. package/dist/actual.css +1532 -1114
  5. package/dist/actual.js +1 -3
  6. package/dist/actual.min.css +1 -1
  7. package/dist/optional.css +1048 -0
  8. package/dist/optional.min.css +1 -0
  9. package/docs/design-notes/browser-support.md +94 -14
  10. package/docs/design-notes/cascade-layer.md +7 -6
  11. package/docs/design-notes/enhancement-contract.md +11 -14
  12. package/docs/design-notes/forced-colors.md +105 -0
  13. package/docs/design-notes/naming.md +2 -1
  14. package/docs/design-notes/platform-alignment.md +492 -0
  15. package/docs/design-notes/references.md +8 -0
  16. package/docs/design-notes/widget-primitives.md +37 -1
  17. package/docs/navigation.json +135 -0
  18. package/docs/pages/components/accordion.md +80 -0
  19. package/docs/pages/components/alert.md +203 -0
  20. package/docs/pages/components/aura.md +35 -0
  21. package/docs/pages/components/avatar.md +95 -0
  22. package/docs/pages/components/badge.md +102 -0
  23. package/docs/pages/components/breadcrumb.md +19 -0
  24. package/docs/pages/components/button.md +210 -0
  25. package/docs/pages/components/card.md +195 -0
  26. package/docs/pages/components/chat.md +50 -0
  27. package/docs/pages/components/dialog.md +367 -0
  28. package/docs/pages/components/drawer.md +113 -0
  29. package/docs/pages/components/fab.md +118 -0
  30. package/docs/pages/components/key.md +33 -0
  31. package/docs/pages/components/meter.md +23 -0
  32. package/docs/pages/components/navbar.md +92 -0
  33. package/docs/pages/components/pagination.md +55 -0
  34. package/docs/pages/components/progress.md +29 -0
  35. package/docs/pages/components/skeleton.md +38 -0
  36. package/docs/pages/components/spinner.md +93 -0
  37. package/docs/pages/components/table.md +102 -0
  38. package/docs/pages/enhancements/flyout.md +391 -0
  39. package/docs/pages/enhancements/overview.md +36 -0
  40. package/docs/pages/enhancements/scrollspy.md +71 -0
  41. package/docs/pages/enhancements/status-bar.md +72 -0
  42. package/docs/pages/enhancements/tabs.md +80 -0
  43. package/docs/pages/enhancements/tooltip.md +130 -0
  44. package/docs/pages/examples/overview.md +43 -0
  45. package/docs/pages/forms/choice-cards.md +102 -0
  46. package/docs/pages/forms/controls.md +32 -0
  47. package/docs/pages/forms/detached-actions.md +59 -0
  48. package/docs/pages/forms/floating-field.md +88 -0
  49. package/docs/pages/forms/form-actions.md +56 -0
  50. package/docs/pages/forms/input-policy.md +91 -0
  51. package/docs/pages/forms/joined-controls.md +37 -0
  52. package/docs/pages/forms/labels.md +42 -0
  53. package/docs/pages/forms/otp.md +50 -0
  54. package/docs/pages/forms/overview.md +188 -0
  55. package/docs/pages/forms/password.md +40 -0
  56. package/docs/pages/forms/range.md +17 -0
  57. package/docs/pages/forms/states-and-sizes.md +321 -0
  58. package/docs/pages/forms/sticky-actions.md +187 -0
  59. package/docs/pages/forms/switch.md +31 -0
  60. package/docs/pages/forms/validation.md +241 -0
  61. package/docs/{mental-model.md → pages/foundations/philosophy.md} +33 -18
  62. package/docs/pages/foundations/theming.md +99 -0
  63. package/docs/pages/foundations/tokens.md +421 -0
  64. package/docs/{typography.md → pages/foundations/typography.md} +27 -9
  65. package/docs/pages/guides/bootstrap.md +438 -0
  66. package/docs/pages/guides/introduction.md +157 -0
  67. package/docs/pages/guides/optional-components.md +33 -0
  68. package/docs/pages/guides/progressive-enhancement.md +686 -0
  69. package/docs/pages/guides/tailwind.md +455 -0
  70. package/docs/pages/layout/app-shell.md +25 -0
  71. package/docs/pages/layout/center.md +29 -0
  72. package/docs/pages/layout/cluster.md +59 -0
  73. package/docs/pages/layout/frame.md +30 -0
  74. package/docs/pages/layout/grid.md +142 -0
  75. package/docs/pages/layout/list.md +41 -0
  76. package/docs/pages/layout/media.md +28 -0
  77. package/docs/pages/layout/overview.md +37 -0
  78. package/docs/pages/layout/scroll-snap.md +54 -0
  79. package/docs/pages/layout/sidebar-layout.md +27 -0
  80. package/docs/pages/layout/stack.md +55 -0
  81. package/docs/pages/layout/switcher.md +36 -0
  82. package/docs/pages/layout/topbar.md +23 -0
  83. package/docs/pages/patterns/actions.md +52 -0
  84. package/docs/pages/patterns/code-block.md +36 -0
  85. package/docs/pages/patterns/exclusive-accordion.md +16 -0
  86. package/docs/pages/patterns/hierarchical-nav.md +26 -0
  87. package/docs/pages/patterns/icon-input.md +25 -0
  88. package/docs/pages/patterns/intent-nesting.md +3 -0
  89. package/docs/pages/patterns/navigation-list.md +235 -0
  90. package/docs/pages/patterns/overview.md +58 -0
  91. package/docs/pages/patterns/structured-lists.md +47 -0
  92. package/docs/pages/utilities/accessibility.md +34 -0
  93. package/docs/pages/utilities/flex.md +105 -0
  94. package/docs/pages/utilities/links.md +18 -0
  95. package/docs/pages/utilities/list.md +32 -0
  96. package/docs/pages/utilities/overflow.md +43 -0
  97. package/docs/pages/utilities/overview.md +18 -0
  98. package/docs/pages/utilities/shape.md +25 -0
  99. package/docs/pages/utilities/sizing-wrapping.md +115 -0
  100. package/docs/pages/utilities/spacing.md +79 -0
  101. package/docs/pages/utilities/text.md +43 -0
  102. package/llms.txt +4 -4
  103. package/package.json +21 -12
  104. package/src/css/actual.css +16 -2
  105. package/src/css/base.css +3 -5
  106. package/src/css/components/accordion.css +18 -30
  107. package/src/css/components/actions.css +4 -1
  108. package/src/css/components/alert.css +139 -102
  109. package/src/css/components/avatar.css +16 -10
  110. package/src/css/components/badge.css +69 -42
  111. package/src/css/components/breadcrumb.css +7 -15
  112. package/src/css/components/busy.css +6 -0
  113. package/src/css/components/button.css +84 -34
  114. package/src/css/components/card.css +26 -38
  115. package/src/css/components/drawer.css +30 -13
  116. package/src/css/components/flyout.css +39 -109
  117. package/src/css/components/index.css +1 -0
  118. package/src/css/components/join.css +14 -2
  119. package/src/css/components/key.css +2 -0
  120. package/src/css/components/menu.css +125 -0
  121. package/src/css/components/meter.css +0 -23
  122. package/src/css/components/modal.css +162 -7
  123. package/src/css/components/navbar.css +30 -23
  124. package/src/css/components/overline.css +8 -9
  125. package/src/css/components/pagination.css +1 -1
  126. package/src/css/components/progress.css +8 -26
  127. package/src/css/components/skeleton.css +7 -0
  128. package/src/css/components/spinner.css +6 -7
  129. package/src/css/components/status-bar.css +15 -24
  130. package/src/css/components/surface.css +2 -8
  131. package/src/css/components/tab.css +19 -48
  132. package/src/css/components/table.css +7 -5
  133. package/src/css/components/tooltip.css +14 -7
  134. package/src/css/focus.css +14 -38
  135. package/src/css/forms/choice-card.css +13 -14
  136. package/src/css/forms/choice.css +21 -27
  137. package/src/css/forms/control.css +18 -17
  138. package/src/css/forms/custom-select.css +9 -11
  139. package/src/css/forms/form-actions.css +14 -3
  140. package/src/css/forms/form.css +7 -4
  141. package/src/css/forms/index.css +4 -4
  142. package/src/css/forms/input-icon.css +30 -12
  143. package/src/css/forms/native.css +50 -11
  144. package/src/css/forms/range.css +17 -9
  145. package/src/css/forms/select.css +8 -8
  146. package/src/css/forms/switch.css +14 -12
  147. package/src/css/forms/validation.css +32 -5
  148. package/src/css/grid.css +32 -18
  149. package/src/css/intents.css +2 -2
  150. package/src/css/layout.css +45 -2
  151. package/src/css/optional/aura.css +93 -0
  152. package/src/css/optional/chat.css +105 -0
  153. package/src/css/optional/fab.css +104 -0
  154. package/src/css/optional/floating-field.css +87 -0
  155. package/src/css/optional/index.css +5 -0
  156. package/src/css/optional/layout-extra.css +7 -4
  157. package/src/css/optional/otp.css +115 -0
  158. package/src/css/optional/scroll-snap.css +6 -0
  159. package/src/css/optional/scroller.css +13 -7
  160. package/src/css/optional/typography-fluid.css +5 -0
  161. package/src/css/optional/utilities-extra.css +17 -2
  162. package/src/css/prose.css +18 -8
  163. package/src/css/reset.css +0 -10
  164. package/src/css/theme.css +21 -5
  165. package/src/css/themes/cyberpunk.css +1 -1
  166. package/src/css/themes/dim.css +3 -3
  167. package/src/css/themes/edge.css +8 -10
  168. package/src/css/themes/index.css +8 -4
  169. package/src/css/themes/{dark.css → indigo.css} +5 -4
  170. package/src/css/themes/neon.css +5 -5
  171. package/src/css/themes/square.css +0 -3
  172. package/src/css/tokens.css +74 -20
  173. package/src/css/utilities.css +8 -10
  174. package/src/css/variants.css +51 -66
  175. package/src/js/command.js +1 -3
  176. package/src/js/context-menu.js +67 -35
  177. package/src/js/dialog.js +68 -79
  178. package/src/js/dismiss.js +15 -0
  179. package/src/js/enhance.js +54 -23
  180. package/src/js/enhancement-loader.js +301 -0
  181. package/src/js/events.js +3 -0
  182. package/src/js/filter.js +3 -3
  183. package/src/js/floating.js +101 -131
  184. package/src/js/flyout.js +104 -87
  185. package/src/js/focus-group.js +116 -0
  186. package/src/js/focus.js +6 -1
  187. package/src/js/index.js +4 -2
  188. package/src/js/input.js +1 -1
  189. package/src/js/keys.js +27 -0
  190. package/src/js/mask.js +7 -6
  191. package/src/js/menu.js +87 -34
  192. package/src/js/parse-config.js +47 -0
  193. package/src/js/password.js +9 -1
  194. package/src/js/scrollspy.js +12 -4
  195. package/src/js/selectors.js +0 -7
  196. package/src/js/status.js +3 -1
  197. package/src/js/surface.js +187 -136
  198. package/src/js/tab.js +36 -53
  199. package/src/js/tooltip.js +70 -35
  200. package/src/js/validation.js +34 -8
  201. package/dist/actual.js.map +0 -31
  202. package/docs/README.md +0 -28
  203. package/docs/components.md +0 -860
  204. package/docs/design-notes/previous-work.md +0 -5
  205. package/docs/forms.md +0 -1265
  206. package/docs/javascript.md +0 -496
  207. package/docs/layout.md +0 -480
  208. package/docs/patterns.md +0 -504
  209. package/docs/reserved.md +0 -7
  210. package/docs/tokens.md +0 -455
  211. package/docs/ui.md +0 -929
  212. package/docs/utilities.md +0 -384
  213. package/src/css/dialog-fallback.css +0 -56
  214. package/src/js/dialog-fallback.js +0 -163
@@ -7,42 +7,54 @@
7
7
  * --alert-border-inline-start-color/-width are unset extension points, mirroring
8
8
  * --btn-border-block-end-* (button.css), for themes that give alerts a
9
9
  * callout-style colored flag on the leading edge instead of a uniform border.
10
+ *
11
+ * Public hooks:
12
+ * --alert-pad-block
13
+ * --alert-pad-inline
14
+ * --alert-font-size
15
+ * --alert-radius
16
+ * --alert-icon-size
17
+ * --alert-dismiss-size
18
+ * --alert-border-inline-start-color
19
+ * --alert-border-inline-start-width
20
+ *
21
+ * Internal:
22
+ * --alert-default-bg
23
+ * --alert-default-border
24
+ * --alert-bg
25
+ * --alert-fg
26
+ * --alert-border
27
+ * --alert-dismiss-icon-size
10
28
  */
11
29
  /* Intent boundary — inherited intents do not tint this component.
12
30
  Local intent classes still win because :where() has zero specificity. */
13
31
  :where(.alert) {
14
- /* @sync intent-boundary */
15
32
  --intent: initial;
16
33
  --intent-fg: initial;
17
34
  --ui-bg: initial;
18
35
  --ui-fg: initial;
19
36
  --ui-border: initial;
20
- --ui-hover-bg: initial;
21
- /* @sync intent-boundary */
22
37
  }
23
38
 
24
39
  .alert {
25
- --alert-pad-block: var(--variant-pad-block, var(--space-3));
26
- --alert-pad-inline: var(--space-4);
27
- --alert-font-size: var(--variant-font-size, var(--font-size-md));
28
- --alert-icon-size: var(--variant-icon-size, 1.25rem);
29
- --alert-bg: var(--surface-subtle);
30
- --alert-border: var(--border);
31
- --ui-bg: var(--alert-bg);
32
- --ui-border: var(--alert-border);
33
- --ui-fg: var(--intent, var(--text));
40
+ --alert-pad-block: var(--space-30);
41
+ --alert-pad-inline: var(--space-40);
42
+ --alert-font-size: var(--font-size-md);
43
+ --alert-icon-size: 1.25rem;
44
+ --alert-default-bg: var(--surface-subtle);
45
+ --alert-default-border: var(--border);
46
+ --alert-bg: var(--ui-bg, var(--alert-default-bg));
47
+ --alert-fg: var(--ui-fg, var(--intent, var(--text)));
48
+ --alert-border: var(--ui-border, var(--alert-default-border));
34
49
 
35
50
  padding-block: var(--alert-pad-block);
36
51
  padding-inline: var(--alert-pad-inline);
37
- background: var(--ui-bg, transparent);
38
- color: var(--ui-fg, var(--text));
39
- border: var(--border-width) solid var(--ui-border, var(--border));
40
- border-inline-start-color: var(
41
- --alert-border-inline-start-color,
42
- var(--ui-border, var(--border))
43
- );
52
+ background: var(--alert-bg);
53
+ color: var(--alert-fg);
54
+ border: var(--border-width) solid var(--alert-border);
55
+ border-inline-start-color: var(--alert-border-inline-start-color, var(--alert-border));
44
56
  border-inline-start-width: var(--alert-border-inline-start-width, var(--border-width));
45
- border-radius: var(--radius-lg);
57
+ border-radius: var(--alert-radius, var(--radius-lg));
46
58
  font-size: var(--alert-font-size);
47
59
  }
48
60
 
@@ -58,24 +70,17 @@
58
70
  margin-block-end: 0;
59
71
  }
60
72
 
61
- /* Alerts are soft by default. Use .solid or .outline for stronger emphasis. */
62
- .alert.solid {
63
- --ui-bg: var(--intent, var(--neutral));
64
- --ui-fg: var(--intent-fg, var(--neutral-fg));
65
- --ui-border: transparent;
66
- }
67
-
68
- .alert.outline {
69
- --ui-bg: transparent;
70
- --ui-fg: var(--intent, var(--text));
71
- --ui-border: var(--intent, var(--border));
72
- }
73
-
73
+ /* Alerts are soft by default. The recipe writes local defaults rather than
74
+ --ui-* so an explicit shared treatment always wins without exclusions. */
74
75
  @supports (color: color-mix(in oklch, red, white)) {
75
- .alert:where(:not(.solid, .outline, .callout)) {
76
+ .alert {
76
77
  /* @sync soft-recipe */
77
- --ui-bg: color-mix(in oklch, var(--surface) var(--soft-bg-mix), var(--intent, var(--neutral)));
78
- --ui-border: color-mix(
78
+ --alert-default-bg: color-mix(
79
+ in oklch,
80
+ var(--surface) var(--soft-bg-mix),
81
+ var(--intent, var(--neutral))
82
+ );
83
+ --alert-default-border: color-mix(
79
84
  in oklch,
80
85
  var(--surface) var(--soft-border-mix),
81
86
  var(--intent, var(--neutral))
@@ -84,8 +89,8 @@
84
89
  }
85
90
  }
86
91
 
87
- /* Decorative leading icon */
88
- .alert > :first-child[aria-hidden="true"] {
92
+ /* Decorative leading icon — use .alert-icon on the icon element. */
93
+ .alert > .alert-icon {
89
94
  display: inline-block;
90
95
  flex: none;
91
96
  inline-size: var(--alert-icon-size);
@@ -95,33 +100,84 @@
95
100
  vertical-align: -0.125em;
96
101
  }
97
102
 
103
+ /* Dismiss — compact close button for inline alerts. Transparent at rest with
104
+ a reduced opacity glyph so it stays secondary inside an already-colored
105
+ alert; hover reinforces it via the shared overlay. Uses the shared
106
+ --icon-close mask, so no icon font or text glyph is required in the markup.
107
+ Standard alerts place it as a direct trailing child; admonitions place it
108
+ inside .alert-title (see below). */
109
+ .alert-dismiss {
110
+ --alert-dismiss-size: 1.75rem;
111
+ --alert-dismiss-icon-size: 0.875rem;
112
+
113
+ display: inline-grid;
114
+ place-items: center;
115
+ inline-size: var(--alert-dismiss-size);
116
+ block-size: var(--alert-dismiss-size);
117
+ flex: none;
118
+ padding: 0;
119
+ border: 0;
120
+ border-radius: var(--radius);
121
+ background: transparent;
122
+ color: currentColor;
123
+ opacity: 0.65;
124
+ cursor: pointer;
125
+ }
126
+
127
+ .alert-dismiss::before {
128
+ content: "";
129
+ inline-size: var(--alert-dismiss-icon-size);
130
+ block-size: var(--alert-dismiss-icon-size);
131
+ background: currentColor;
132
+ -webkit-mask: var(--icon-close) center / contain no-repeat;
133
+ mask: var(--icon-close) center / contain no-repeat;
134
+ }
135
+
136
+ @media (hover: hover) {
137
+ .alert-dismiss:hover {
138
+ background: var(--hover-overlay);
139
+ opacity: 1;
140
+ }
141
+ }
142
+
143
+ /* Grid anatomy — activated by a leading icon, a trailing dismiss button, or
144
+ both. Icon and dismiss are pinned to the outer columns; anything else (the
145
+ message content) flows into the remaining text column. */
98
146
  @supports selector(.alert:has(> *)) {
99
- .alert:has(> :first-child[aria-hidden="true"]) {
147
+ .alert:has(> .alert-icon, > .alert-dismiss) {
100
148
  display: grid;
101
- grid-template-columns: auto minmax(0, 1fr);
149
+ grid-template-columns: minmax(0, 1fr);
102
150
  align-items: var(--items-align, start);
103
- column-gap: var(--space-3);
151
+ column-gap: var(--space-30);
152
+ }
153
+
154
+ .alert:has(> .alert-icon) {
155
+ grid-template-columns: auto minmax(0, 1fr);
104
156
  }
105
157
 
106
- .alert:has(> :first-child[aria-hidden="true"]) > :first-child {
158
+ .alert:has(> .alert-icon) > .alert-icon {
107
159
  grid-column: 1;
108
160
  grid-row: 1 / -1;
109
161
  display: inline-grid;
110
162
  place-items: center;
111
- inline-size: var(--alert-icon-size);
112
- block-size: var(--alert-icon-size);
113
163
  margin-block-start: 0.125em;
114
- font-size: var(--alert-icon-size);
115
- line-height: 1;
116
164
  }
117
165
 
118
- .alert:has(> :first-child[aria-hidden="true"]) > :first-child:is(svg, i) {
119
- inline-size: var(--alert-icon-size);
120
- block-size: var(--alert-icon-size);
166
+ .alert:has(> .alert-icon) > :not(.alert-icon, .alert-dismiss) {
167
+ grid-column: 2;
121
168
  }
122
169
 
123
- .alert:has(> :first-child[aria-hidden="true"]) > :not(:first-child) {
124
- grid-column: 2;
170
+ .alert:has(> .alert-dismiss) {
171
+ grid-template-columns: minmax(0, 1fr) auto;
172
+ }
173
+
174
+ .alert:has(> .alert-icon):has(> .alert-dismiss) {
175
+ grid-template-columns: auto minmax(0, 1fr) auto;
176
+ }
177
+
178
+ .alert:has(> .alert-dismiss) > .alert-dismiss {
179
+ grid-column: -2 / -1;
180
+ grid-row: 1;
125
181
  }
126
182
  }
127
183
 
@@ -136,88 +192,69 @@
136
192
  Canvas backplate (unreadable) — so .solid intentionally falls back to the
137
193
  default look. */
138
194
 
139
- /* Callout — neutral surface with an inset accent band on the leading edge.
140
- The ::before pseudo is absolutely positioned and inset to respect the
141
- outer border-radius, so it never needs its own radius. */
195
+ /* Callout — neutral surface with a thick accent border on the leading edge.
196
+ The thickness follows the shared --alert-border-inline-start-width hook. */
142
197
  .alert.callout {
143
198
  --alert-bg: var(--surface-subtle);
144
- --ui-bg: var(--alert-bg);
145
- --ui-fg: var(--text);
146
- --ui-border: var(--border);
147
- position: relative;
148
- padding-inline-start: calc(var(--alert-pad-inline) + var(--space-3));
199
+ --alert-fg: var(--text);
200
+ border: 0;
201
+ border-inline-start: var(--alert-border-inline-start-width, 4px) solid
202
+ var(--alert-border-inline-start-color, var(--intent, var(--neutral)));
149
203
  }
150
204
 
151
- .alert.callout::before {
152
- content: "";
153
- position: absolute;
154
- inset-block: var(--space-2);
155
- inset-inline-start: var(--space-2);
156
- inline-size: 0.25rem;
157
- border-radius: var(--radius-full);
158
- background: var(--intent, var(--neutral));
159
- }
160
-
161
- /* Admonition — structured title/body anatomy with a tinted title band.
162
- The root is layout-neutralized: no padding, no gap, no icon grid. */
205
+ /* Admonition — structured static box with a tinted title bar and a body
206
+ that rests on the page surface. Not collapsible — use .accordion inside
207
+ the body if the content needs to be expandable. */
163
208
  .alert.admonition {
164
209
  padding: 0;
165
- gap: 0;
166
210
  display: block;
167
211
  overflow: clip;
212
+ border-color: var(--intent, var(--border));
168
213
  }
169
214
 
170
- .alert-title {
215
+ .alert.admonition > .alert-title {
216
+ display: flex;
217
+ align-items: center;
218
+ gap: var(--space-20);
171
219
  padding-block: var(--alert-pad-block);
172
220
  padding-inline: var(--alert-pad-inline);
221
+ border-start-start-radius: calc(var(--alert-radius, var(--radius-lg)) - var(--border-width));
222
+ border-start-end-radius: calc(var(--alert-radius, var(--radius-lg)) - var(--border-width));
223
+ }
224
+
225
+ /* Dismiss inside an admonition title bar rides the inline end. */
226
+ .alert.admonition > .alert-title > .alert-dismiss {
227
+ margin-inline-start: auto;
228
+ }
173
229
 
174
- @supports (color: color-mix(in oklch, red, white)) {
230
+ @supports (color: color-mix(in oklch, red, white)) {
231
+ .alert.admonition > .alert-title {
175
232
  background: color-mix(
176
233
  in oklch,
177
234
  var(--surface) var(--soft-bg-mix),
178
235
  var(--intent, var(--neutral))
179
236
  );
180
237
  }
238
+ }
181
239
 
182
- @supports not (color: color-mix(in oklch, red, white)) {
240
+ @supports not (color: color-mix(in oklch, red, white)) {
241
+ .alert.admonition > .alert-title {
183
242
  background: var(--intent, var(--neutral));
243
+ color: var(--intent-fg, var(--neutral-fg));
184
244
  }
185
-
186
- border-start-start-radius: calc(var(--radius-lg) - var(--border-width));
187
- border-start-end-radius: calc(var(--radius-lg) - var(--border-width));
188
245
  }
189
246
 
190
- .alert-title:where(summary) {
191
- cursor: pointer;
192
- user-select: none;
193
- list-style: none;
194
- }
195
-
196
- .alert-title:where(summary)::-webkit-details-marker {
197
- display: none;
198
- }
199
-
200
- .alert-title[aria-hidden] {
201
- display: inline-flex;
202
- gap: var(--space-2);
203
- align-items: center;
204
- }
205
-
206
- .alert-body {
247
+ .alert.admonition > .alert-body {
207
248
  padding-block: var(--alert-pad-block);
208
249
  padding-inline: var(--alert-pad-inline);
250
+ background: var(--surface);
209
251
  color: var(--text);
210
252
  }
211
253
 
212
- .alert-body > :first-child {
254
+ .alert.admonition > .alert-body > :first-child {
213
255
  margin-block-start: 0;
214
256
  }
215
257
 
216
- .alert-body > :last-child {
258
+ .alert.admonition > .alert-body > :last-child {
217
259
  margin-block-end: 0;
218
260
  }
219
-
220
- details.alert.admonition[open] .alert-title {
221
- border-end-start-radius: 0;
222
- border-end-end-radius: 0;
223
- }
@@ -4,18 +4,26 @@
4
4
  * The visual box stays the same across semantic elements. Grouping and status
5
5
  * dots (an empty .badge child) compose around the avatar without changing its
6
6
  * meaning.
7
+ *
8
+ * Public hooks:
9
+ * --avatar-size
10
+ * --avatar-radius
11
+ * --avatar-font-size
12
+ * --avatar-stack-size
13
+ * --avatar-stack-font-size
14
+ * --avatar-stack-overlap
15
+ * --avatar-stack-ring
16
+ *
17
+ * Internal:
18
+ * --avatar-bg
19
+ * --avatar-fg
20
+ * --avatar-status-translate-x
7
21
  */
8
22
  /* Intent boundary — inherited intents do not tint this component.
9
23
  Local intent classes still win because :where() has zero specificity. */
10
24
  :where(.avatar) {
11
- /* @sync intent-boundary */
12
25
  --intent: initial;
13
26
  --intent-fg: initial;
14
- --ui-bg: initial;
15
- --ui-fg: initial;
16
- --ui-border: initial;
17
- --ui-hover-bg: initial;
18
- /* @sync intent-boundary */
19
27
  }
20
28
 
21
29
  .avatar {
@@ -107,10 +115,8 @@ button.avatar {
107
115
  transition: opacity var(--duration);
108
116
  }
109
117
 
110
- @media (hover: hover) {
111
- :where(a.avatar, button.avatar):not(:where(:disabled, [aria-disabled="true"])):hover::after {
112
- opacity: 1;
113
- }
118
+ :where(a.avatar, button.avatar):not(:where(:disabled, [aria-disabled="true"])):hover::after {
119
+ opacity: 1;
114
120
  }
115
121
 
116
122
  :where(a.avatar, button.avatar):not(:where(:disabled, [aria-disabled="true"])):active {
@@ -4,34 +4,54 @@
4
4
  * Soft by default. .solid for counters and notification badges. The dot
5
5
  * (.badge:empty) stays solid regardless — a soft dot is pointless.
6
6
  * Shared .outline variant stays available.
7
+ *
8
+ * Public hooks:
9
+ * --badge-size
10
+ * --badge-pad-x
11
+ * --badge-font-size
12
+ * --badge-dot-size
13
+ * --badge-radius
14
+ *
15
+ * Internal:
16
+ * --badge-default-bg
17
+ * --badge-default-fg
18
+ * --badge-default-border
19
+ * --badge-default-hover-bg
20
+ * --badge-bg
21
+ * --badge-fg
22
+ * --badge-border
7
23
  */
8
24
  /* Intent boundary — inherited intents do not tint this component.
9
25
  Local intent classes still win because :where() has zero specificity. */
10
26
  :where(.badge) {
11
- /* @sync intent-boundary */
12
27
  --intent: initial;
13
28
  --intent-fg: initial;
14
29
  --ui-bg: initial;
15
30
  --ui-fg: initial;
16
31
  --ui-border: initial;
17
32
  --ui-hover-bg: initial;
18
- /* @sync intent-boundary */
19
33
  }
20
34
 
21
35
  .badge {
22
- --badge-size: var(--variant-compact-size, 1.5rem);
36
+ --badge-size: var(--density-compact-size);
23
37
  --badge-pad-x: 0.55em;
24
- --badge-font-size: var(--variant-compact-font-size, 0.8125rem);
38
+ --badge-font-size: 0.8125rem;
25
39
  --badge-dot-size: 0.5rem;
26
- --badge-bg: var(--ui-bg, transparent);
27
- --badge-fg: var(--ui-fg, var(--intent, var(--text)));
28
- --badge-border: var(--ui-border, var(--intent, var(--border)));
29
- --badge-radius: 999px;
40
+ --badge-default-bg: var(--surface-subtle);
41
+ --badge-default-fg: var(--intent, var(--text));
42
+ --badge-default-border: var(--border);
43
+ --badge-default-hover-bg: var(--badge-bg);
44
+ --badge-bg: var(--ui-bg, var(--badge-default-bg));
45
+ --badge-fg: var(--ui-fg, var(--badge-default-fg));
46
+ --badge-border: var(--ui-border, var(--badge-default-border));
47
+ --badge-radius: var(--radius-full);
30
48
 
31
49
  display: inline-flex;
32
50
  align-items: center;
33
51
  justify-content: center;
34
52
  gap: 0.35em;
53
+ inline-size: fit-content;
54
+ max-inline-size: 100%;
35
55
  min-block-size: var(--badge-size);
36
56
  padding-inline: var(--badge-pad-x);
37
57
  border: var(--border-width) solid var(--badge-border);
@@ -50,18 +70,17 @@
50
70
  box-shadow var(--duration);
51
71
  }
52
72
 
53
- /* Soft by default — duplicated here with @sync markers for check-sync.js
54
- to guard, the same way alert.css guards its own soft recipe. */
73
+ /* Soft by default. Local defaults remain behind --ui-* in the resolution
74
+ chain, so explicit shared treatments compose without selector exclusions. */
55
75
  @supports (color: color-mix(in oklch, red, white)) {
56
- .badge:where(:not(.solid, .outline)) {
76
+ .badge {
57
77
  /* @sync soft-recipe */
58
- --badge-bg: color-mix(
78
+ --badge-default-bg: color-mix(
59
79
  in oklch,
60
80
  var(--surface) var(--soft-bg-mix),
61
81
  var(--intent, var(--neutral))
62
82
  );
63
- --badge-fg: var(--intent, var(--text));
64
- --badge-border: color-mix(
83
+ --badge-default-border: color-mix(
65
84
  in oklch,
66
85
  var(--surface) var(--soft-border-mix),
67
86
  var(--intent, var(--neutral))
@@ -100,27 +119,44 @@
100
119
  cursor: pointer;
101
120
  }
102
121
 
103
- @media (hover: hover) {
104
- .badge > button:not(:disabled):hover {
105
- background: var(--hover-overlay);
106
- }
122
+ .badge > button:not(:disabled):hover {
123
+ background: var(--hover-overlay);
124
+ }
125
+
126
+ /* Hover recipes — sets --ui-hover-bg consumed by the hover rule below.
127
+ Declared outside :hover like button.css for the same reason. */
128
+ :is(a.badge, button.badge).outline {
129
+ --ui-hover-bg: transparent;
107
130
  }
108
131
 
109
- /* .solid/.soft/.outline are shared via variants.css, including the
110
- .soft/.outline hover recipe (--ui-hover-bg). */
111
- @media (hover: hover) {
112
- :where(a.badge, button.badge):not(:where(:disabled, [aria-disabled="true"])):hover {
113
- background: var(--ui-hover-bg, var(--badge-bg));
132
+ @supports (color: color-mix(in oklch, red, white)) {
133
+ :is(a.badge, button.badge):is(.solid, :empty) {
134
+ --ui-hover-bg: color-mix(in oklch, var(--intent, var(--neutral)) 88%, black);
135
+ }
136
+
137
+ :is(a.badge, button.badge):where(:not(.solid, .outline, :empty)) {
138
+ --badge-default-hover-bg: color-mix(
139
+ in oklch,
140
+ var(--surface) calc(var(--soft-bg-mix) - var(--soft-hover-alpha)),
141
+ var(--intent, var(--neutral))
142
+ );
114
143
  }
115
144
 
116
- :where(a.badge, button.badge):not(:where(:disabled, [aria-disabled="true"], .outline)):hover {
117
- box-shadow: inset 0 0 0 999px var(--hover-overlay);
145
+ :is(a.badge, button.badge).outline {
146
+ --ui-hover-bg: color-mix(in oklch, currentColor 10%, transparent);
118
147
  }
119
148
  }
120
149
 
150
+ :where(a.badge, button.badge):not(:where(:disabled, [aria-disabled="true"])):hover {
151
+ background: var(--ui-hover-bg, var(--badge-default-hover-bg));
152
+ }
153
+
154
+ :where(a.badge, button.badge):not(:where(:disabled, [aria-disabled="true"], .outline)):hover {
155
+ box-shadow: inset 0 0 0 999px var(--hover-overlay);
156
+ }
157
+
121
158
  button.badge {
122
159
  cursor: pointer;
123
- font: inherit;
124
160
  }
125
161
 
126
162
  button.badge:disabled,
@@ -134,27 +170,18 @@ a.badge[aria-disabled="true"] {
134
170
  }
135
171
 
136
172
  @media (forced-colors: active) {
137
- .badge {
138
- border-color: ButtonText;
139
- background: Canvas;
140
- color: CanvasText;
141
- box-shadow: none;
142
- }
143
-
144
173
  .badge:empty {
145
174
  background: ButtonText;
146
175
  }
147
176
 
148
- @media (hover: hover) {
149
- :where(a.badge, button.badge):hover:not(:where(:disabled, [aria-disabled="true"])) {
150
- outline: var(--border-width) solid ButtonText;
151
- outline-offset: 2px;
152
- }
177
+ :where(a.badge, button.badge):hover:not(:where(:disabled, [aria-disabled="true"])) {
178
+ outline: var(--border-width) solid ButtonText;
179
+ outline-offset: 2px;
180
+ }
153
181
 
154
- .badge > button:not(:disabled):hover {
155
- outline: var(--border-width) solid currentColor;
156
- outline-offset: 1px;
157
- }
182
+ .badge > button:not(:disabled):hover {
183
+ outline: var(--border-width) solid currentColor;
184
+ outline-offset: 1px;
158
185
  }
159
186
 
160
187
  button.badge:disabled,
@@ -8,7 +8,7 @@
8
8
  display: flex;
9
9
  flex-wrap: wrap;
10
10
  align-items: center;
11
- gap: var(--space-1);
11
+ gap: var(--space-10);
12
12
  margin: 0;
13
13
  padding: 0;
14
14
  color: var(--text-subtle);
@@ -19,7 +19,7 @@
19
19
  .breadcrumb li {
20
20
  display: inline-flex;
21
21
  align-items: center;
22
- gap: var(--space-1);
22
+ gap: var(--space-10);
23
23
  }
24
24
 
25
25
  .breadcrumb li + li::before {
@@ -32,25 +32,17 @@
32
32
  text-decoration: none;
33
33
  }
34
34
 
35
- @media (hover: hover) {
36
- .breadcrumb
37
- li:not(:where([aria-current]:not([aria-current="false"])))
38
- > a:hover:not(:where([aria-current]:not([aria-current="false"]))) {
39
- color: var(--text);
40
- text-decoration: underline;
41
- }
35
+ .breadcrumb a:not([aria-current]):hover,
36
+ .breadcrumb a[aria-current="false"]:hover {
37
+ color: var(--text);
38
+ text-decoration: underline;
42
39
  }
43
40
 
44
41
  .breadcrumb a:focus-visible {
45
42
  border-radius: var(--radius-sm);
46
43
  }
47
44
 
48
- .breadcrumb a:where([aria-current]:not([aria-current="false"])) {
49
- color: var(--text);
50
- font-weight: var(--font-weight-medium);
51
- }
52
-
53
- .breadcrumb li:where([aria-current]:not([aria-current="false"])) > :where(a, span) {
45
+ .breadcrumb :where(a, span):where([aria-current]:not([aria-current="false"])) {
54
46
  color: var(--text);
55
47
  font-weight: var(--font-weight-medium);
56
48
  }
@@ -4,6 +4,12 @@
4
4
  * A non-button element with aria-busy="true" and a direct last-child .spinner
5
5
  * shows that spinner as a centered overlay over a faded surface. Buttons keep
6
6
  * their spinners inline (e.g. .btn[aria-busy] > .spinner stays inline-flex).
7
+ *
8
+ * Public hooks:
9
+ * --busy-overlay-bg
10
+ *
11
+ * Internal:
12
+ * --spinner-size (overlay copy of the shared spinner hook)
7
13
  */
8
14
  [aria-busy] > .spinner:last-child {
9
15
  display: none;