actual-css 0.1.0 → 0.3.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 (215) hide show
  1. package/CHANGELOG.md +90 -1
  2. package/README.md +25 -8
  3. package/dist/actual-themes.min.css +1 -0
  4. package/dist/actual.css +1492 -931
  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 +95 -6
  10. package/docs/design-notes/cascade-layer.md +1 -1
  11. package/docs/design-notes/enhancement-contract.md +101 -0
  12. package/docs/design-notes/forced-colors.md +105 -0
  13. package/docs/design-notes/naming.md +3 -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 +119 -0
  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 +205 -0
  25. package/docs/pages/components/card.md +183 -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 +41 -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 +92 -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 +57 -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 +21 -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 +18 -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 +31 -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 +10 -4
  103. package/package.json +30 -16
  104. package/src/css/actual.css +12 -1
  105. package/src/css/base.css +3 -9
  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 +162 -49
  109. package/src/css/components/avatar.css +16 -10
  110. package/src/css/components/badge.css +82 -39
  111. package/src/css/components/breadcrumb.css +7 -15
  112. package/src/css/components/busy.css +7 -0
  113. package/src/css/components/button.css +82 -38
  114. package/src/css/components/card.css +17 -37
  115. package/src/css/components/drawer.css +30 -13
  116. package/src/css/components/flyout.css +39 -110
  117. package/src/css/components/index.css +1 -0
  118. package/src/css/components/join.css +14 -3
  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 +17 -18
  124. package/src/css/components/overline.css +0 -7
  125. package/src/css/components/pagination.css +1 -1
  126. package/src/css/components/progress.css +8 -26
  127. package/src/css/components/scrollspy.css +2 -2
  128. package/src/css/components/skeleton.css +7 -0
  129. package/src/css/components/spinner.css +10 -11
  130. package/src/css/components/status-bar.css +18 -28
  131. package/src/css/components/surface.css +2 -8
  132. package/src/css/components/tab.css +20 -48
  133. package/src/css/components/table.css +7 -5
  134. package/src/css/components/tooltip.css +14 -7
  135. package/src/css/focus.css +16 -3
  136. package/src/css/forms/choice-card.css +13 -15
  137. package/src/css/forms/choice.css +21 -28
  138. package/src/css/forms/control.css +16 -26
  139. package/src/css/forms/custom-select.css +9 -11
  140. package/src/css/forms/form-actions.css +14 -3
  141. package/src/css/forms/form.css +7 -4
  142. package/src/css/forms/index.css +5 -4
  143. package/src/css/forms/input-icon.css +30 -12
  144. package/src/css/forms/native.css +48 -33
  145. package/src/css/forms/range.css +103 -0
  146. package/src/css/forms/select.css +8 -8
  147. package/src/css/forms/switch.css +14 -13
  148. package/src/css/forms/validation.css +32 -5
  149. package/src/css/grid.css +19 -18
  150. package/src/css/intents.css +2 -2
  151. package/src/css/layout.css +29 -1
  152. package/src/css/optional/aura.css +93 -0
  153. package/src/css/optional/chat.css +105 -0
  154. package/src/css/optional/fab.css +104 -0
  155. package/src/css/optional/floating-field.css +87 -0
  156. package/src/css/optional/index.css +5 -0
  157. package/src/css/optional/layout-extra.css +7 -4
  158. package/src/css/optional/otp.css +115 -0
  159. package/src/css/optional/scroll-snap.css +6 -0
  160. package/src/css/optional/scroller.css +19 -7
  161. package/src/css/optional/typography-fluid.css +5 -0
  162. package/src/css/optional/utilities-extra.css +17 -2
  163. package/src/css/prose.css +18 -8
  164. package/src/css/reset.css +0 -10
  165. package/src/css/theme.css +29 -13
  166. package/src/css/themes/cyberpunk.css +1 -1
  167. package/src/css/themes/dim.css +3 -3
  168. package/src/css/themes/edge.css +11 -37
  169. package/src/css/themes/index.css +3 -3
  170. package/src/css/themes/{dark.css → indigo.css} +5 -4
  171. package/src/css/themes/neon.css +5 -5
  172. package/src/css/themes/square.css +0 -3
  173. package/src/css/tokens.css +81 -21
  174. package/src/css/utilities.css +8 -10
  175. package/src/css/variants.css +37 -65
  176. package/src/js/command.js +1 -3
  177. package/src/js/context-menu.js +72 -53
  178. package/src/js/dialog.js +68 -79
  179. package/src/js/dismiss.js +15 -0
  180. package/src/js/enhance.js +76 -19
  181. package/src/js/enhancement-loader.js +301 -0
  182. package/src/js/events.js +3 -0
  183. package/src/js/filter.js +3 -3
  184. package/src/js/floating.js +101 -131
  185. package/src/js/flyout.js +106 -96
  186. package/src/js/focus-group.js +116 -0
  187. package/src/js/focus.js +6 -1
  188. package/src/js/index.js +4 -2
  189. package/src/js/input.js +1 -1
  190. package/src/js/keys.js +27 -0
  191. package/src/js/mask.js +7 -6
  192. package/src/js/menu.js +89 -35
  193. package/src/js/parse-config.js +47 -0
  194. package/src/js/password.js +9 -1
  195. package/src/js/scrollspy.js +133 -62
  196. package/src/js/selectors.js +14 -31
  197. package/src/js/status.js +16 -14
  198. package/src/js/surface.js +219 -125
  199. package/src/js/tab.js +46 -66
  200. package/src/js/tooltip.js +53 -31
  201. package/src/js/validation.js +45 -51
  202. package/dist/actual.js.map +0 -31
  203. package/docs/README.md +0 -26
  204. package/docs/components.md +0 -860
  205. package/docs/design-notes/previous-work.md +0 -5
  206. package/docs/forms.md +0 -1265
  207. package/docs/javascript.md +0 -426
  208. package/docs/layout.md +0 -480
  209. package/docs/patterns.md +0 -415
  210. package/docs/reserved.md +0 -7
  211. package/docs/tokens.md +0 -455
  212. package/docs/ui.md +0 -937
  213. package/docs/utilities.md +0 -384
  214. package/src/css/dialog-fallback.css +0 -56
  215. package/src/js/dialog-fallback.js +0 -163
@@ -0,0 +1,125 @@
1
+ /*
2
+ * Menu — action list primitive consumed by flyout and context-menu.
3
+ *
4
+ * Strict anatomy: .menu > li > .menu-item. Separators and section labels
5
+ * sit directly under .menu as siblings of <li>.
6
+ *
7
+ * Public hooks:
8
+ * --menu-item-icon-size
9
+ */
10
+
11
+ .menu {
12
+ display: grid;
13
+ gap: var(--space-10);
14
+ margin: 0;
15
+ padding: var(--space-10);
16
+ list-style: none;
17
+ }
18
+
19
+ .menu > li {
20
+ margin: 0;
21
+ }
22
+
23
+ .menu-item {
24
+ --menu-item-icon-size: 1.25em;
25
+
26
+ display: flex;
27
+ align-items: center;
28
+ gap: var(--space-20);
29
+ inline-size: 100%;
30
+ min-block-size: var(--menu-item-size, var(--control-size));
31
+ padding-inline: var(--space-20);
32
+ border: 0;
33
+ border-radius: var(--radius-sm);
34
+ background: transparent;
35
+ color: var(--text);
36
+ font: inherit;
37
+ text-align: start;
38
+ text-decoration: none;
39
+ white-space: nowrap;
40
+ cursor: pointer;
41
+ }
42
+
43
+ .menu-item-icon {
44
+ display: grid;
45
+ flex: 0 0 var(--menu-item-icon-size);
46
+ inline-size: var(--menu-item-icon-size);
47
+ place-items: center;
48
+ }
49
+
50
+ .menu-item-text {
51
+ flex: 1;
52
+ min-inline-size: 0;
53
+ overflow: hidden;
54
+ text-overflow: ellipsis;
55
+ }
56
+
57
+ .menu-item-end {
58
+ display: inline-flex;
59
+ align-items: center;
60
+ gap: var(--space-10);
61
+ margin-inline-start: auto;
62
+ color: var(--text-muted);
63
+ }
64
+
65
+ /* Checkable menu items are one command with one accessible state. Their
66
+ indicator is generated so authors do not add a second interactive input. */
67
+ .menu-item:is([role="menuitemcheckbox"], [role="menuitemradio"])::before {
68
+ display: grid;
69
+ flex: 0 0 var(--menu-item-icon-size);
70
+ inline-size: var(--menu-item-icon-size);
71
+ place-items: center;
72
+ }
73
+
74
+ .menu-item[role="menuitemcheckbox"]::before {
75
+ content: "";
76
+ }
77
+
78
+ .menu-item[role="menuitemcheckbox"][aria-checked="true"]::before {
79
+ content: "✓";
80
+ }
81
+
82
+ .menu-item[role="menuitemcheckbox"][aria-checked="mixed"]::before {
83
+ content: "−";
84
+ }
85
+
86
+ .menu-item[role="menuitemradio"]::before {
87
+ content: "○";
88
+ }
89
+
90
+ .menu-item[role="menuitemradio"][aria-checked="true"]::before {
91
+ content: "●";
92
+ }
93
+
94
+ .menu-item:focus-visible {
95
+ background: var(--surface-subtle);
96
+ }
97
+
98
+ .menu-item:hover:not(:where(:disabled, [aria-disabled="true"])) {
99
+ background: var(--surface-subtle);
100
+ }
101
+
102
+ .menu-item:is(:disabled, [aria-disabled="true"]) {
103
+ cursor: not-allowed;
104
+ opacity: var(--disabled-opacity);
105
+ }
106
+
107
+ .menu-label {
108
+ padding: var(--space-20);
109
+ color: var(--text-muted);
110
+ font-size: var(--font-size-xs);
111
+ font-weight: var(--font-weight-strong);
112
+ }
113
+
114
+ .menu-separator {
115
+ margin: 0;
116
+ border: 0;
117
+ border-block-start: var(--border-width) solid var(--border);
118
+ }
119
+
120
+ @media (forced-colors: active) {
121
+ .menu-item:focus-visible {
122
+ outline: var(--border-width) solid ButtonText;
123
+ outline-offset: -1px;
124
+ }
125
+ }
@@ -4,18 +4,6 @@
4
4
  * Maps the three standard meter zones (optimum / suboptimum / even-less-good)
5
5
  * to the shared success / warning / danger intent colors.
6
6
  */
7
- /* Intent boundary — inherited intents do not tint this component.
8
- Local intent classes still win because :where() has zero specificity. */
9
- :where(.meter) {
10
- /* @sync intent-boundary */
11
- --intent: initial;
12
- --intent-fg: initial;
13
- --ui-bg: initial;
14
- --ui-fg: initial;
15
- --ui-border: initial;
16
- --ui-hover-bg: initial;
17
- /* @sync intent-boundary */
18
- }
19
7
 
20
8
  .meter {
21
9
  appearance: none;
@@ -61,21 +49,10 @@
61
49
  }
62
50
 
63
51
  @media (forced-colors: active) {
64
- .meter {
65
- border: var(--border-width) solid ButtonText;
66
- background: Canvas;
67
- }
68
-
69
- .meter::-webkit-meter-bar {
70
- border: 0;
71
- background: Canvas;
72
- }
73
-
74
52
  .meter::-webkit-meter-optimum-value,
75
53
  .meter::-webkit-meter-suboptimum-value,
76
54
  .meter::-webkit-meter-even-less-good-value,
77
55
  .meter::-moz-meter-bar {
78
56
  background: Highlight;
79
- forced-color-adjust: none;
80
57
  }
81
58
  }
@@ -3,12 +3,30 @@
3
3
  *
4
4
  * Spacing, radius, transitions, and focus treatment come from shared tokens.
5
5
  * Opening behavior and intent-specific decisions stay outside this component.
6
+ *
7
+ * Public hooks:
8
+ * --modal-size
9
+ * --dialog-viewport-gap
10
+ * --dialog-icon-size
11
+ * --dialog-icon-glyph-size
12
+ *
13
+ * Internal:
14
+ * --dialog-close-icon-size
15
+ * --dialog-viewport-gap-2x
6
16
  */
7
17
  dialog.modal {
8
18
  --modal-size: 32rem;
19
+ --dialog-viewport-gap: var(--space-40);
20
+ /* calc() multiplication is not in the supported browser range, so the
21
+ doubled gap is spelled out with an additive calc. */
22
+ --dialog-viewport-gap-2x: calc(var(--dialog-viewport-gap) + var(--dialog-viewport-gap));
23
+
24
+ /* Keep the surface anchored to the viewport in the top layer. This also
25
+ provides the containing block for the absolutely positioned close button. */
26
+ position: fixed;
9
27
 
10
- max-inline-size: min(100% - 2rem, var(--modal-size));
11
- max-block-size: calc(var(--viewport-block) - 2rem);
28
+ max-inline-size: min(calc(100% - var(--dialog-viewport-gap-2x)), var(--modal-size));
29
+ max-block-size: calc(var(--viewport-block) - var(--dialog-viewport-gap-2x));
12
30
  border: var(--border-width) solid var(--border);
13
31
  border-radius: var(--radius-lg);
14
32
  background: var(--surface-raised);
@@ -32,11 +50,18 @@ dialog.modal {
32
50
  dialog.modal > form,
33
51
  dialog.modal > .stack {
34
52
  display: grid;
35
- gap: var(--space-4);
36
- max-block-size: calc(var(--viewport-block) - 2rem);
53
+ gap: var(--space-40);
54
+ max-block-size: calc(var(--viewport-block) - var(--dialog-viewport-gap-2x));
37
55
  overflow: auto;
38
56
  overscroll-behavior: contain;
39
- padding: var(--space-4);
57
+ padding: var(--space-40);
58
+ }
59
+
60
+ /* Keep the dialog off the viewport edges on small screens. */
61
+ @media (max-width: 30rem) {
62
+ dialog.modal {
63
+ --dialog-viewport-gap: var(--space-30);
64
+ }
40
65
  }
41
66
 
42
67
  dialog.modal.scrollable > form,
@@ -62,6 +87,13 @@ dialog.modal footer > :last-child {
62
87
  margin-block-end: 0;
63
88
  }
64
89
 
90
+ /* The close button is anchored to the dialog at top inline-end, out of the
91
+ content flow; headers reserve inline room so titles never run under it. */
92
+ dialog.modal > form > header,
93
+ dialog.modal > .stack > header {
94
+ padding-inline-end: calc(var(--control-size) + var(--space-30));
95
+ }
96
+
65
97
  dialog.modal footer {
66
98
  display: flex;
67
99
  flex-wrap: wrap;
@@ -69,6 +101,65 @@ dialog.modal footer {
69
101
  gap: var(--gap);
70
102
  }
71
103
 
104
+ /* Confirmation layout — a focused message followed by a visually distinct
105
+ action band. The media primitive owns icon/content alignment; this variant
106
+ only removes the standard form inset so both regions can own their padding. */
107
+ dialog.modal.dialog-confirmation > form {
108
+ gap: 0;
109
+ padding: 0;
110
+ }
111
+
112
+ dialog.modal.dialog-confirmation > form > .media {
113
+ gap: var(--space-40);
114
+ padding: var(--space-50);
115
+ }
116
+
117
+ dialog.modal.dialog-confirmation > form > footer {
118
+ padding: var(--space-40) var(--space-50);
119
+ border-end-start-radius: calc(var(--radius-lg) - var(--border-width));
120
+ border-end-end-radius: calc(var(--radius-lg) - var(--border-width));
121
+ background: var(--surface-subtle);
122
+ }
123
+
124
+ /* Intent boundary — inherited intents do not tint the icon well. A local
125
+ intent plus .soft opts into the shared soft-variant recipe. */
126
+ :where(.dialog-icon) {
127
+ --intent: initial;
128
+ --intent-fg: initial;
129
+ --ui-bg: initial;
130
+ --ui-fg: initial;
131
+ }
132
+
133
+ .dialog-icon {
134
+ --dialog-icon-size: 3rem;
135
+ --dialog-icon-glyph-size: 1.5rem;
136
+
137
+ display: inline-grid;
138
+ place-items: center;
139
+ inline-size: var(--dialog-icon-size);
140
+ block-size: var(--dialog-icon-size);
141
+ flex: none;
142
+ border-radius: var(--radius-full);
143
+ background: var(--ui-bg, var(--surface-subtle));
144
+ color: var(--ui-fg, var(--intent, var(--text-muted)));
145
+ }
146
+
147
+ .dialog-icon > * {
148
+ display: inline-grid;
149
+ place-items: center;
150
+ inline-size: var(--dialog-icon-glyph-size);
151
+ block-size: var(--dialog-icon-glyph-size);
152
+ font-size: var(--dialog-icon-glyph-size);
153
+ line-height: 1;
154
+ }
155
+
156
+ @media (max-width: 30rem) {
157
+ dialog.modal.dialog-confirmation > form > .media,
158
+ dialog.modal.dialog-confirmation > form > footer {
159
+ padding: var(--space-40);
160
+ }
161
+ }
162
+
72
163
  dialog.modal[open] {
73
164
  opacity: 1;
74
165
  transform: none;
@@ -124,7 +215,7 @@ html.has-modal-open.had-scrollbar {
124
215
 
125
216
  @media (prefers-reduced-motion: no-preference) {
126
217
  dialog.modal.is-static {
127
- animation: actual-modal-static 180ms var(--ease);
218
+ animation: actual-dialog-static var(--duration-slow) var(--ease);
128
219
  }
129
220
 
130
221
  ::view-transition-group(actual-dialog) {
@@ -133,7 +224,7 @@ html.has-modal-open.had-scrollbar {
133
224
  }
134
225
  }
135
226
 
136
- @keyframes actual-modal-static {
227
+ @keyframes actual-dialog-static {
137
228
  0%,
138
229
  100% {
139
230
  transform: none;
@@ -159,4 +250,68 @@ html.has-modal-open.had-scrollbar {
159
250
  dialog.modal::backdrop {
160
251
  background: Canvas;
161
252
  }
253
+
254
+ .dialog-icon {
255
+ border: var(--border-width) solid CanvasText;
256
+ }
257
+ }
258
+
259
+ /* Close controls. A close button is an action attached to a surface, so it
260
+ never participates in the content flow. The modal and the drawer share the
261
+ same simple placement — absolute at the panel's top inline-end, inside the
262
+ surface — so both close buttons look and behave identically. The glyph comes
263
+ from --icon-close, masked to currentColor, so no icon font or text glyph is
264
+ required in the markup. */
265
+ .dialog-close,
266
+ .drawer-close {
267
+ --dialog-close-icon-size: 1rem;
268
+
269
+ display: inline-grid;
270
+ place-items: center;
271
+ padding: 0;
272
+ border: 0;
273
+ border-radius: var(--radius);
274
+ color: var(--text-muted);
275
+ cursor: pointer;
276
+
277
+ /* Out of flow, anchored to the positioned dialog surface, not the header or
278
+ any scroll container inside it. */
279
+ position: absolute;
280
+ z-index: 1;
281
+ inset-block-start: var(--space-20);
282
+ inset-inline-end: var(--space-20);
283
+
284
+ inline-size: var(--control-size);
285
+ block-size: var(--control-size);
286
+
287
+ background: var(--surface-subtle);
288
+ }
289
+
290
+ .dialog-close::before,
291
+ .drawer-close::before {
292
+ content: "";
293
+ inline-size: var(--dialog-close-icon-size);
294
+ block-size: var(--dialog-close-icon-size);
295
+ background: currentColor;
296
+ -webkit-mask: var(--icon-close) center / contain no-repeat;
297
+ mask: var(--icon-close) center / contain no-repeat;
298
+ }
299
+
300
+ @media (hover: hover) {
301
+ .dialog-close:hover,
302
+ .drawer-close:hover {
303
+ box-shadow: inset 0 0 0 999px var(--hover-overlay);
304
+ color: var(--text);
305
+ }
306
+ }
307
+
308
+ .dialog-close:active,
309
+ .drawer-close:active {
310
+ box-shadow: inset 0 0 0 999px var(--hover-overlay);
311
+ }
312
+
313
+ .dialog-close:focus-visible,
314
+ .drawer-close:focus-visible {
315
+ outline: 2px solid transparent;
316
+ box-shadow: var(--focus-ring-shadow);
162
317
  }
@@ -4,6 +4,9 @@
4
4
  * .navbar is a horizontal bar; .navbar-brand is the brand link; .navbar-nav is
5
5
  * the inline link list using .nav-link items. .nav-list is the vertical nav
6
6
  * list shared with .drawer, fed by the shared --gap token.
7
+ *
8
+ * Internal:
9
+ * --gap (local value for the shared gap token)
7
10
  */
8
11
  .navbar {
9
12
  display: flex;
@@ -11,8 +14,8 @@
11
14
  align-items: center;
12
15
  justify-content: space-between;
13
16
  gap: var(--gap);
14
- padding-block: var(--space-3);
15
- padding-inline: var(--space-4);
17
+ padding-block: var(--space-30);
18
+ padding-inline: var(--space-40);
16
19
  border: var(--border-width) solid var(--border);
17
20
  border-radius: var(--radius-lg);
18
21
  background: var(--surface-raised);
@@ -22,7 +25,7 @@
22
25
  .navbar-brand {
23
26
  display: inline-flex;
24
27
  align-items: center;
25
- gap: var(--space-2);
28
+ gap: var(--space-20);
26
29
  color: var(--text);
27
30
  font-weight: var(--font-weight-bold);
28
31
  text-decoration: none;
@@ -36,7 +39,7 @@
36
39
  display: flex;
37
40
  flex-wrap: wrap;
38
41
  align-items: center;
39
- gap: var(--space-1);
42
+ gap: var(--space-10);
40
43
  margin: 0;
41
44
  padding: 0;
42
45
  list-style: none;
@@ -46,7 +49,7 @@
46
49
  display: inline-flex;
47
50
  align-items: center;
48
51
  min-block-size: var(--control-size-sm);
49
- padding-inline: var(--space-2);
52
+ padding-inline: var(--space-20);
50
53
  border-radius: var(--radius);
51
54
  color: var(--text-muted);
52
55
  font-weight: var(--font-weight-medium);
@@ -58,21 +61,19 @@
58
61
  color: var(--text);
59
62
  }
60
63
 
61
- @media (hover: hover) {
62
- .nav-link:hover {
63
- background: var(--surface-subtle);
64
- color: var(--text);
65
- }
64
+ .nav-link:hover {
65
+ background: var(--surface-subtle);
66
+ color: var(--text);
66
67
  }
67
68
 
68
69
  /* Nav list — a vertical navigation list. Used by .drawer for stacked links. */
69
70
  .nav-list {
70
71
  display: grid;
72
+ --gap: var(--space-20);
71
73
  gap: var(--gap);
72
74
  margin: 0;
73
75
  padding: 0;
74
76
  list-style: none;
75
- --gap: var(--space-2);
76
77
  }
77
78
 
78
79
  .nav-list > li {
@@ -87,12 +88,10 @@
87
88
  forced-color-adjust: none;
88
89
  }
89
90
 
90
- @media (hover: hover) {
91
- .nav-link:hover:not(:where([aria-current]:not([aria-current="false"]))) {
92
- outline: var(--border-width) solid ButtonText;
93
- outline-offset: 2px;
94
- background: Canvas;
95
- color: CanvasText;
96
- }
91
+ .nav-link:hover:not(:where([aria-current]:not([aria-current="false"]))) {
92
+ outline: var(--border-width) solid ButtonText;
93
+ outline-offset: 2px;
94
+ background: Canvas;
95
+ color: CanvasText;
97
96
  }
98
97
  }
@@ -8,14 +8,7 @@
8
8
  /* Intent boundary — inherited intents do not tint this component.
9
9
  Local intent classes still win because :where() has zero specificity. */
10
10
  :where(.overline) {
11
- /* @sync intent-boundary */
12
11
  --intent: initial;
13
- --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
12
  }
20
13
 
21
14
  .overline {
@@ -12,7 +12,7 @@
12
12
  display: flex;
13
13
  flex-wrap: wrap;
14
14
  align-items: center;
15
- gap: var(--space-1);
15
+ gap: var(--space-10);
16
16
  margin: 0;
17
17
  padding: 0;
18
18
  list-style: none;
@@ -3,26 +3,21 @@
3
3
  *
4
4
  * Consumes the shared --intent/--primary for the value bar and --bar-height
5
5
  * for thickness. Indeterminate state animates a shimmer using --duration-shimmer.
6
+ *
7
+ * Public hooks:
8
+ * --progress-track
9
+ * --progress-value
6
10
  */
7
11
  /* Intent boundary — inherited intents do not tint this component.
8
12
  Local intent classes still win because :where() has zero specificity. */
9
13
  :where(.progress) {
10
- /* @sync intent-boundary */
11
14
  --intent: initial;
12
- --intent-fg: initial;
13
- --ui-bg: initial;
14
- --ui-fg: initial;
15
- --ui-border: initial;
16
- --ui-hover-bg: initial;
17
- /* @sync intent-boundary */
18
15
  }
19
16
 
20
17
  .progress {
21
18
  --progress-track: var(--surface-subtle);
22
19
  --progress-value: var(--intent, var(--primary));
23
- }
24
20
 
25
- .progress {
26
21
  appearance: none;
27
22
  -webkit-appearance: none;
28
23
  display: block;
@@ -101,26 +96,13 @@
101
96
  }
102
97
 
103
98
  @media (forced-colors: active) {
104
- .progress {
105
- border: var(--border-width) solid ButtonText;
106
- background: Canvas;
107
- }
108
-
109
- .progress::-webkit-progress-bar {
110
- background: Canvas;
111
- }
112
-
113
- .progress::-webkit-progress-value {
99
+ .progress::-webkit-progress-value,
100
+ .progress:indeterminate::-webkit-progress-value {
114
101
  background: Highlight;
115
- forced-color-adjust: none;
116
102
  }
117
103
 
118
- .progress::-moz-progress-bar {
104
+ .progress::-moz-progress-bar,
105
+ .progress:indeterminate::-moz-progress-bar {
119
106
  background: Highlight;
120
- forced-color-adjust: none;
121
- }
122
-
123
- .progress:indeterminate {
124
- background: Canvas;
125
107
  }
126
108
  }
@@ -11,8 +11,8 @@
11
11
  * Progressive enhancement: on browsers that support :target-current,
12
12
  * this file enables the native target group and marks the active link.
13
13
  *
14
- * Falls back gracefully: links still work when IntersectionObserver or
15
- * :target-current is unavailable.
14
+ * Falls back gracefully: links still work when :target-current is unavailable
15
+ * and when the JavaScript enhancer is not loaded at all.
16
16
  */
17
17
 
18
18
  @supports selector(.scrollspy a:target-current) {
@@ -3,6 +3,13 @@
3
3
  *
4
4
  * Shows approximate loading structure without implying real content hierarchy.
5
5
  * Geometry, animation, and color stay theme-aware.
6
+ *
7
+ * Public hooks:
8
+ * --skeleton-size
9
+ * --skeleton-width
10
+ * --skeleton-radius
11
+ * --skeleton-track
12
+ * --skeleton-highlight
6
13
  */
7
14
  .skeleton {
8
15
  --skeleton-size: 1rem;
@@ -3,23 +3,22 @@
3
3
  *
4
4
  * Uses currentColor so it adapts to buttons, alerts, badges, and text. The
5
5
  * [aria-busy] overlay composition lives in components/busy.css.
6
+ *
7
+ * Public hooks:
8
+ * --spinner-size
9
+ * --spinner-width
10
+ * --spinner-track
11
+ * --spinner-value
6
12
  */
7
13
  /* Intent boundary — inherited intents do not tint this component.
8
14
  Local intent classes still win because :where() has zero specificity. */
9
15
  :where(.spinner) {
10
- /* @sync intent-boundary */
11
16
  --intent: initial;
12
- --intent-fg: initial;
13
- --ui-bg: initial;
14
- --ui-fg: initial;
15
- --ui-border: initial;
16
- --ui-hover-bg: initial;
17
- /* @sync intent-boundary */
18
17
  }
19
18
 
20
19
  .spinner {
21
- --spinner-size: 1.5rem;
22
- --spinner-width: 2px;
20
+ --spinner-size: 1em;
21
+ --spinner-width: 0.125em;
23
22
  --spinner-track: currentColor;
24
23
  --spinner-value: transparent;
25
24
 
@@ -45,11 +44,11 @@
45
44
  }
46
45
 
47
46
  .spinner.sm {
48
- --spinner-size: 1rem;
47
+ --spinner-size: 0.75em;
49
48
  }
50
49
 
51
50
  .spinner.lg {
52
- --spinner-size: 3rem;
51
+ --spinner-size: 2rem;
53
52
  --spinner-width: 3px;
54
53
  }
55
54