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
@@ -0,0 +1,210 @@
1
+ # Button
2
+
3
+ Actions and navigation with shared intents, variants, sizes, and loading, pressed, and disabled states.
4
+
5
+ ## Class reference
6
+
7
+ | Class | Kind | Description |
8
+ |---|---|---|
9
+ | `.btn` | Component | Base button. Solid by default; works on `<button>`, `<a href>`, and button-like `<input>`. |
10
+ | `.primary` | Intent | Primary action. |
11
+ | `.secondary` | Intent | Secondary action. |
12
+ | `.success` | Intent | Positive outcome. |
13
+ | `.warning` | Intent | Caution. |
14
+ | `.danger` | Intent | Destructive action. |
15
+ | `.neutral` | Intent | Neutral tone (the `.btn` default). |
16
+ | `.soft` | Variant | Muted intent-tinted surface. |
17
+ | `.outline` | Variant | Transparent with an intent-colored border. |
18
+ | `.solid` | Variant | Filled intent background — the `.btn` default. |
19
+ | `.ghost` | Variant | Borderless text button (button-only). |
20
+ | `.link` | Variant | Underlined text button (button-only). |
21
+ | `.sm` / `.lg` | Size | Compact or large control height. |
22
+ | `.icon-only` | Variant | Square icon button sized to the control height. |
23
+
24
+ ## Basic usage
25
+
26
+ Use `.btn` on actionable elements: `<button>`, `<a href>`, or
27
+ `input[type="button"|"submit"|"reset"]`. Use a real `<button>` for actions and
28
+ `<a class="btn">` for navigation.
29
+
30
+ ```html demo
31
+ <div class="cluster">
32
+ <button class="btn" type="button">Default</button>
33
+ <button class="btn primary" type="button">Primary</button>
34
+ <a class="btn primary" href="#">Account</a>
35
+ <input class="btn" type="button" value="Input button" />
36
+ </div>
37
+ ```
38
+
39
+ ## Intents
40
+
41
+ Shared intent classes set color meaning. They compose with every variant.
42
+
43
+ ```html demo
44
+ <div class="cluster">
45
+ <button class="btn primary" type="button">Primary</button>
46
+ <button class="btn secondary" type="button">Secondary</button>
47
+ <button class="btn success" type="button">Success</button>
48
+ <button class="btn warning" type="button">Warning</button>
49
+ <button class="btn danger" type="button">Danger</button>
50
+ <button class="btn neutral" type="button">Neutral</button>
51
+ </div>
52
+ ```
53
+
54
+ ## Variants
55
+
56
+ `.ghost` and `.link` are button-only; `.soft`, `.outline`, and `.solid` are
57
+ shared with other components.
58
+
59
+ Transparent treatments (`.outline`, `.ghost`, `.link`) follow the surrounding
60
+ foreground by default, including on a contrasting `.inverted` surface. A local
61
+ intent class still wins: `.danger.outline` uses the danger color in either
62
+ context. Filled buttons own their surface and keep their normal intent recipe.
63
+
64
+ ```html demo
65
+ <div class="cluster">
66
+ <button class="btn outline" type="button">Outline</button>
67
+ <button class="btn danger outline" type="button">Danger outline</button>
68
+ <button class="btn soft" type="button">Soft</button>
69
+ <button class="btn danger soft" type="button">Danger soft</button>
70
+ <button class="btn ghost" type="button">Ghost</button>
71
+ <button class="btn link" type="button">Button as link</button>
72
+ </div>
73
+ ```
74
+
75
+ ### Icon and icon-only buttons
76
+
77
+ ```html demo
78
+ <div class="cluster">
79
+ <button class="btn" type="button"><i class="ti ti-star" aria-hidden="true"></i> With an icon</button>
80
+ <button class="btn icon-only" type="button" aria-label="Add">
81
+ <i class="ti ti-plus" aria-hidden="true"></i>
82
+ </button>
83
+ <button class="btn primary icon-only" type="button" aria-label="Search">
84
+ <i class="ti ti-search" aria-hidden="true"></i>
85
+ </button>
86
+ </div>
87
+ ```
88
+
89
+ Use `.btn.icon-only` for a square icon button sized to the control height.
90
+ Always name it with an `aria-label` since there is no visible text.
91
+
92
+ ### Button groups
93
+
94
+ Join adjacent buttons with `.join`. The joined group is not a new component —
95
+ the buttons keep their own variants.
96
+
97
+ ```html demo
98
+ <div class="join" role="group" aria-label="Text alignment">
99
+ <button class="btn" type="button">Left</button>
100
+ <button class="btn outline" type="button">Center</button>
101
+ <button class="btn soft" type="button">Right</button>
102
+ </div>
103
+ ```
104
+
105
+ ## Sizes
106
+
107
+ Prefer `.sm` and `.lg` over setting sizes directly. Density variants never
108
+ change typography.
109
+
110
+ ```html demo
111
+ <div class="cluster">
112
+ <button class="btn sm" type="button">Small</button>
113
+ <button class="btn" type="button">Regular</button>
114
+ <button class="btn lg" type="button">Large</button>
115
+ </div>
116
+ ```
117
+
118
+ ## States
119
+
120
+ ### Disabled
121
+
122
+ Disable a `<button>` or `<input>` with the native `disabled` attribute. Anchors
123
+ have no native disabled state, so `<a class="btn" aria-disabled="true">` is the
124
+ supported way to style a disabled link button; application code must also
125
+ prevent the click since `aria-disabled` does not stop navigation on its own.
126
+
127
+ ```html demo
128
+ <div class="cluster">
129
+ <button class="btn primary" type="button" disabled>Disabled</button>
130
+ <button class="btn outline" type="button" disabled>Disabled outline</button>
131
+ <a class="btn outline" href="#" aria-disabled="true">Disabled link</a>
132
+ </div>
133
+ ```
134
+
135
+ ### Loading
136
+
137
+ Set `aria-busy="true"` on the button and add a `.spinner`. The spinner inherits
138
+ the button size.
139
+
140
+ ```html demo
141
+ <div class="cluster">
142
+ <button class="btn primary" type="button" aria-busy="true" disabled>
143
+ <span class="spinner" aria-hidden="true"></span>
144
+ Saving…
145
+ </button>
146
+ </div>
147
+ ```
148
+
149
+ ### Toggle
150
+
151
+ Use `aria-pressed` for toggle buttons. Actual styles the pressed state;
152
+ application code owns changing the attribute. The example scopes its script to
153
+ its own preview so repeated demos on a page cannot cross-bind.
154
+
155
+ ```html demo
156
+ <div class="cluster">
157
+ <button class="btn" type="button" aria-pressed="false">Bold</button>
158
+ <button class="btn" type="button" aria-pressed="false">Italic</button>
159
+ </div>
160
+ <script>
161
+ (() => {
162
+ const preview = document.currentScript.closest(".docs-preview");
163
+ for (const button of preview.querySelectorAll("button")) {
164
+ button.addEventListener("click", () => {
165
+ const pressed = button.getAttribute("aria-pressed") === "true";
166
+ button.setAttribute("aria-pressed", String(!pressed));
167
+ });
168
+ }
169
+ })();
170
+ </script>
171
+ ```
172
+
173
+ For exclusive groups, manage a single pressed button:
174
+
175
+ ```html demo
176
+ <div class="join" role="group" aria-label="Text alignment" data-docs-toggle-group>
177
+ <button class="btn" type="button" aria-pressed="true">Left</button>
178
+ <button class="btn outline" type="button" aria-pressed="false">Center</button>
179
+ <button class="btn outline" type="button" aria-pressed="false">Right</button>
180
+ </div>
181
+ <script>
182
+ (() => {
183
+ const preview = document.currentScript.closest(".docs-preview");
184
+ const group = preview.querySelector("[data-docs-toggle-group]");
185
+ group.addEventListener("click", (event) => {
186
+ const button = event.target.closest("button[aria-pressed]");
187
+ if (!button || !group.contains(button)) return;
188
+ for (const item of group.querySelectorAll("button[aria-pressed]")) {
189
+ item.setAttribute("aria-pressed", String(item === button));
190
+ }
191
+ });
192
+ })();
193
+ </script>
194
+ ```
195
+
196
+ ## Accessibility
197
+
198
+ - Always set `type="button"` when a button is not submitting a form.
199
+ - Use a real `<button>` for actions and `<a class="btn">` for navigation.
200
+ - Toggle buttons expose their state with `aria-pressed`; the component styles
201
+ the pressed state but application code owns toggling the attribute.
202
+ - Disabled `<button>` and `<input>` use the native `disabled` attribute;
203
+ disabled link buttons use `aria-disabled="true"` plus an app-side
204
+ activation guard.
205
+
206
+ ## CSS hooks
207
+
208
+ - `--btn-radius` — corner radius.
209
+ - `--btn-focus-color` — focus ring base color; the ring itself is derived from it.
210
+ - `--btn-gap` — space between an icon and the label text (default `0.375em`).
@@ -0,0 +1,195 @@
1
+ # Card
2
+
3
+ Flexible content container with optional header, body, and footer regions, plus full-bleed children.
4
+
5
+ ## Class reference
6
+
7
+ | Class | Kind | Description |
8
+ |---|---|---|
9
+ | `.card` | Component | Neutral raised surface for grouped content. |
10
+ | `.raised` | Variant | Elevated surface with a soft shadow. |
11
+ | `.subtle` | Variant | Lower contrast against the page surface. |
12
+ | `.inverted` | Surface modifier | Inverse surface treatment: paints `--surface-solid` and swaps the foreground to `--surface`, so it inverts in dark themes instead of always reading as dark. Apply as `class="card inverted"`, or on any block. |
13
+ | `.compact` | Variant | Tighter padding for dense contexts. |
14
+
15
+ ## Basic usage
16
+
17
+ Use semantic elements inside the card. A direct `<header>` or `<footer>` is the
18
+ card's structural slot. Cards do not own page spacing — compose them with
19
+ layout primitives like `.grid`.
20
+
21
+ ```html demo
22
+ <div style="max-inline-size: 32rem">
23
+ <article class="card stack">
24
+ <header>
25
+ <hgroup>
26
+ <h3>Understanding Semantic HTML</h3>
27
+ <p class="muted">A quick primer for new contributors</p>
28
+ </hgroup>
29
+ </header>
30
+
31
+ <p>Using the right HTML tags improves both SEO and accessibility. Lean on landmarks and live lists.</p>
32
+
33
+ <ul class="cluster" style="list-style: none; padding: 0; margin: 0; gap: 0.5rem" aria-label="Tags">
34
+ <li><span class="badge primary soft secondary">HTML</span></li>
35
+ <li><span class="badge soft primary">Accessibility</span></li>
36
+ <li><span class="badge outline">5 min read</span></li>
37
+ </ul>
38
+
39
+ <footer>
40
+ <time datetime="2026-06-12" class="muted">June 12, 2026</time>
41
+ <button type="button" class="btn outline">Read more</button>
42
+ </footer>
43
+ </article>
44
+ </div>
45
+ ```
46
+
47
+ ## Bleed
48
+
49
+ Use `.bleed` on a direct child to escape the card padding — full-width images,
50
+ colored headers, or footers.
51
+
52
+ ```html demo
53
+ <div style="max-inline-size: 32rem">
54
+ <article class="card stack">
55
+ <img class="bleed" src="https://picsum.photos/seed/actual-css-card/600/300" alt="Coastal cliffs at dusk" />
56
+ <header>
57
+ <h3>Coastal cliffs at dusk</h3>
58
+ </header>
59
+ <section class="stack" aria-label="Summary">
60
+ <p>A short caption that wraps across a few lines. The image bleeds to the card edges.</p>
61
+ </section>
62
+ <footer>
63
+ <span class="badge primary soft">Photo</span>
64
+ <button type="button" class="btn outline">View</button>
65
+ </footer>
66
+ </article>
67
+ </div>
68
+ ```
69
+
70
+ ```html demo
71
+ <article class="card stack" style="--card-max-inline-size: 24rem">
72
+ <header class="bleed stack items-center text-center" style="background: var(--surface-subtle)">
73
+ <hgroup>
74
+ <h3>Team</h3>
75
+ <p class="muted">For growing products</p>
76
+ </hgroup>
77
+ <p>
78
+ <span style="font-size: 2rem; font-weight: var(--font-weight-strong); line-height: 1">$24</span>
79
+ <span class="muted">/ user / month</span>
80
+ </p>
81
+ </header>
82
+
83
+ <ul class="stack items-center" style="list-style: none; padding: 0">
84
+ <li>Unlimited projects</li>
85
+ <li>Up to 25 seats</li>
86
+ <li>Shared workspaces</li>
87
+ <li>Priority support</li>
88
+ </ul>
89
+
90
+ <footer class="bleed" style="background: var(--surface-subtle); justify-content: center">
91
+ <a class="btn primary" href="#">Upgrade</a>
92
+ </footer>
93
+ </article>
94
+ ```
95
+
96
+ ## In grids
97
+
98
+ Cards display nicely in grids with equal-height behavior.
99
+
100
+ ```html demo
101
+ <section class="grid">
102
+ <article class="card">
103
+ <header>
104
+ <h3>Components</h3>
105
+ </header>
106
+ <p>Buttons, alerts, dialogs — all opt-in.</p>
107
+ <footer>
108
+ <a class="btn outline" href="#">Browse</a>
109
+ </footer>
110
+ </article>
111
+
112
+ <article class="card">
113
+ <header>
114
+ <h3>Layout</h3>
115
+ </header>
116
+ <p>Stack, cluster, grid, switcher, sidebar.</p>
117
+ <footer>
118
+ <a class="btn outline" href="#">Browse</a>
119
+ </footer>
120
+ </article>
121
+
122
+ <article class="card">
123
+ <header>
124
+ <h3>Patterns</h3>
125
+ </header>
126
+ <p>Actions, nav-list — small structural helpers.</p>
127
+ <footer>
128
+ <a class="btn outline" href="#">Browse</a>
129
+ </footer>
130
+ </article>
131
+ </section>
132
+ ```
133
+
134
+ ## Surfaces
135
+
136
+ `.inverted` creates a contrasting surface context, not a complete theme island.
137
+ On a bare block (`<header class="inverted">`, `<section class="inverted">`) it
138
+ paints the surface directly; contextual content and transparent treatments such
139
+ as `.btn.outline`, `.btn.ghost`, and `.btn.link` follow its foreground.
140
+
141
+ Apply it directly to a component that consumes the shared `--ui-*` surface
142
+ contract (`.card`, `.navbar`, `.alert`, `.badge`) to treat that component as the
143
+ contrasting surface. A surface-owning component nested inside an inverted block
144
+ keeps its own surface and establishes a new context for its descendants. Use a
145
+ `data-theme` island when every component and form control in a subtree must use
146
+ another theme.
147
+
148
+ More specific component states or explicit surface variants still take
149
+ precedence: `.card.inverted.subtle` keeps the `.subtle` background while the
150
+ foreground stays inverted.
151
+
152
+ `.inverted` and `.subtle` are competing surface treatments — do not combine
153
+ them. `.subtle` paints the card's background directly while `.inverted` swaps
154
+ the surface tokens, so `.card.subtle.inverted` renders a subtle background with
155
+ inverted foreground. Treat them as mutually exclusive, like two competing
156
+ variants.
157
+
158
+ ```html demo
159
+ <section class="grid">
160
+ <article class="card raised">
161
+ <hgroup>
162
+ <h3>Raised</h3>
163
+ <p class="muted">Elevated surface with a soft shadow.</p>
164
+ </hgroup>
165
+ </article>
166
+
167
+ <article class="card subtle">
168
+ <hgroup>
169
+ <h3>Subtle</h3>
170
+ <p class="muted">Lower contrast against the page surface.</p>
171
+ </hgroup>
172
+ </article>
173
+
174
+ <article class="card inverted stack">
175
+ <hgroup>
176
+ <h3>Inverted</h3>
177
+ <p>Inverse surface for emphasis. Text inherits the contrasting surface color.</p>
178
+ </hgroup>
179
+ <button type="button" class="btn">Action</button>
180
+ </article>
181
+
182
+ <article class="card compact">
183
+ <hgroup>
184
+ <h3>Compact</h3>
185
+ <p class="muted">Tighter padding for dense contexts.</p>
186
+ </hgroup>
187
+ </article>
188
+ </section>
189
+ ```
190
+
191
+ ## CSS hooks
192
+
193
+ - `--card-radius` — corner radius.
194
+ - `--card-max-inline-size` — maximum width.
195
+ - `--card-pad` — inner padding; also drives the negative offsets that let a `.bleed` child reach the card edge. `.compact` lowers it.
@@ -0,0 +1,50 @@
1
+ # Chat
2
+
3
+ > **Optional** — import `actual-css/css/optional/chat` or `actual-css/css/optional/index`.
4
+
5
+ Chat lays out message metadata, an optional avatar, and a content-sized bubble
6
+ at either edge of a conversation.
7
+
8
+ ```html demo
9
+ <div class="stack" aria-label="Conversation">
10
+ <div class="chat chat-start">
11
+ <div class="chat-avatar avatar sm" role="img" aria-label="Thomas">
12
+ <span aria-hidden="true">T</span>
13
+ </div>
14
+ <div class="chat-header">
15
+ Thomas <time datetime="2026-08-18T21:30">21:30</time>
16
+ </div>
17
+ <div class="chat-bubble">Are we still shipping today?</div>
18
+ <div class="chat-footer">Delivered</div>
19
+ </div>
20
+
21
+ <div class="chat chat-end">
22
+ <div class="chat-header">You</div>
23
+ <div class="chat-bubble primary">Yes, the checks are green.</div>
24
+ </div>
25
+ </div>
26
+ ```
27
+
28
+ Use `.chat-start` and `.chat-end` for logical inline placement, so the layout
29
+ also follows right-to-left writing direction. The avatar is optional. Bubble
30
+ colors compose with intents and shared variants: `.primary`, `.primary.soft`,
31
+ and `.primary.outline` all work without chat-specific color classes.
32
+
33
+ For a live conversation, put an appropriate live-region or `role="log"` on the
34
+ conversation container according to the product's announcement needs. Do not
35
+ put `role="log"` on individual messages.
36
+
37
+ ## Class reference
38
+
39
+ | Class | Description |
40
+ |---|---|
41
+ | `.chat` | Message row grid. |
42
+ | `.chat-start` / `.chat-end` | Logical inline placement. |
43
+ | `.chat-avatar` | Avatar grid slot; compose it with `.avatar`. |
44
+ | `.chat-header` / `.chat-footer` | Muted message metadata. |
45
+ | `.chat-bubble` | Content-sized message surface. |
46
+
47
+ ## CSS hooks
48
+
49
+ - `--chat-gap` — gap between the avatar and message content.
50
+ - `--chat-max-size` — maximum inline size of a bubble.