actual-css 0.1.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 (129) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/LICENSE +21 -0
  3. package/README.md +166 -0
  4. package/dist/actual.css +4929 -0
  5. package/dist/actual.js +3 -0
  6. package/dist/actual.js.map +31 -0
  7. package/dist/actual.min.css +1 -0
  8. package/docs/README.md +26 -0
  9. package/docs/components.md +860 -0
  10. package/docs/design-notes/accessibility-decisions.md +32 -0
  11. package/docs/design-notes/browser-support.md +93 -0
  12. package/docs/design-notes/cascade-layer.md +52 -0
  13. package/docs/design-notes/css-anchor.md +33 -0
  14. package/docs/design-notes/naming.md +37 -0
  15. package/docs/design-notes/previous-work.md +5 -0
  16. package/docs/design-notes/references.md +324 -0
  17. package/docs/forms.md +1265 -0
  18. package/docs/javascript.md +426 -0
  19. package/docs/layout.md +480 -0
  20. package/docs/mental-model.md +73 -0
  21. package/docs/patterns.md +415 -0
  22. package/docs/reserved.md +7 -0
  23. package/docs/tokens.md +455 -0
  24. package/docs/typography.md +159 -0
  25. package/docs/ui.md +937 -0
  26. package/docs/utilities.md +384 -0
  27. package/llms.txt +17 -0
  28. package/package.json +101 -0
  29. package/src/css/actual.css +17 -0
  30. package/src/css/actual.full.css +2 -0
  31. package/src/css/actual.layer.css +3 -0
  32. package/src/css/base.css +70 -0
  33. package/src/css/components/accordion.css +97 -0
  34. package/src/css/components/actions.css +21 -0
  35. package/src/css/components/alert.css +137 -0
  36. package/src/css/components/avatar.css +199 -0
  37. package/src/css/components/badge.css +143 -0
  38. package/src/css/components/breadcrumb.css +56 -0
  39. package/src/css/components/busy.css +44 -0
  40. package/src/css/components/button.css +216 -0
  41. package/src/css/components/card.css +140 -0
  42. package/src/css/components/drawer.css +122 -0
  43. package/src/css/components/flyout.css +243 -0
  44. package/src/css/components/index.css +41 -0
  45. package/src/css/components/join.css +106 -0
  46. package/src/css/components/key.css +25 -0
  47. package/src/css/components/meter.css +81 -0
  48. package/src/css/components/modal.css +162 -0
  49. package/src/css/components/navbar.css +98 -0
  50. package/src/css/components/overline.css +49 -0
  51. package/src/css/components/pagination.css +30 -0
  52. package/src/css/components/progress.css +126 -0
  53. package/src/css/components/scrollspy.css +27 -0
  54. package/src/css/components/skeleton.css +67 -0
  55. package/src/css/components/spinner.css +60 -0
  56. package/src/css/components/status-bar.css +82 -0
  57. package/src/css/components/surface.css +48 -0
  58. package/src/css/components/tab.css +128 -0
  59. package/src/css/components/table.css +64 -0
  60. package/src/css/components/tooltip.css +107 -0
  61. package/src/css/dialog-fallback.css +56 -0
  62. package/src/css/focus.css +13 -0
  63. package/src/css/forms/choice-card.css +158 -0
  64. package/src/css/forms/choice.css +196 -0
  65. package/src/css/forms/control.css +106 -0
  66. package/src/css/forms/custom-select.css +93 -0
  67. package/src/css/forms/form-actions.css +43 -0
  68. package/src/css/forms/form.css +57 -0
  69. package/src/css/forms/index.css +15 -0
  70. package/src/css/forms/input-icon.css +36 -0
  71. package/src/css/forms/native.css +68 -0
  72. package/src/css/forms/select.css +36 -0
  73. package/src/css/forms/switch.css +127 -0
  74. package/src/css/forms/validation.css +63 -0
  75. package/src/css/grid.css +95 -0
  76. package/src/css/intents.css +33 -0
  77. package/src/css/layout.css +80 -0
  78. package/src/css/optional/index.css +5 -0
  79. package/src/css/optional/layout-extra.css +55 -0
  80. package/src/css/optional/scroll-snap.css +51 -0
  81. package/src/css/optional/scroller.css +51 -0
  82. package/src/css/optional/typography-fluid.css +48 -0
  83. package/src/css/optional/utilities-extra.css +289 -0
  84. package/src/css/print.css +47 -0
  85. package/src/css/prose.css +187 -0
  86. package/src/css/reset.css +56 -0
  87. package/src/css/theme.css +186 -0
  88. package/src/css/themes/corporate.css +60 -0
  89. package/src/css/themes/cyberpunk.css +60 -0
  90. package/src/css/themes/dark.css +32 -0
  91. package/src/css/themes/dim.css +33 -0
  92. package/src/css/themes/edge.css +143 -0
  93. package/src/css/themes/forest.css +65 -0
  94. package/src/css/themes/gradient.css +97 -0
  95. package/src/css/themes/index.css +43 -0
  96. package/src/css/themes/lavender.css +66 -0
  97. package/src/css/themes/mono.css +60 -0
  98. package/src/css/themes/neon.css +66 -0
  99. package/src/css/themes/ocean.css +60 -0
  100. package/src/css/themes/petrol.css +64 -0
  101. package/src/css/themes/spruce.css +64 -0
  102. package/src/css/themes/square.css +68 -0
  103. package/src/css/themes/sunset.css +66 -0
  104. package/src/css/tokens.css +122 -0
  105. package/src/css/utilities.css +162 -0
  106. package/src/css/variants.css +118 -0
  107. package/src/js/command.js +165 -0
  108. package/src/js/context-menu.js +291 -0
  109. package/src/js/dialog-fallback.js +163 -0
  110. package/src/js/dialog.js +503 -0
  111. package/src/js/enhance.js +208 -0
  112. package/src/js/events.js +22 -0
  113. package/src/js/filter.js +122 -0
  114. package/src/js/floating.js +462 -0
  115. package/src/js/flyout.js +187 -0
  116. package/src/js/focus.js +35 -0
  117. package/src/js/index.js +26 -0
  118. package/src/js/input.js +47 -0
  119. package/src/js/keys.js +30 -0
  120. package/src/js/mask.js +184 -0
  121. package/src/js/menu.js +88 -0
  122. package/src/js/password.js +98 -0
  123. package/src/js/scrollspy.js +121 -0
  124. package/src/js/selectors.js +59 -0
  125. package/src/js/status.js +158 -0
  126. package/src/js/surface.js +358 -0
  127. package/src/js/tab.js +173 -0
  128. package/src/js/tooltip.js +374 -0
  129. package/src/js/validation.js +419 -0
package/docs/layout.md ADDED
@@ -0,0 +1,480 @@
1
+ # Layout
2
+
3
+ Layout provides a small set of composable building blocks for common page, app, and content structure. It is not a utility-first framework and it is not a twelve-column grid system.
4
+
5
+ - Layout classes compose components; components do not own page spacing.
6
+ - Use custom properties to tune a layout instance.
7
+ - Prefer intrinsic and container-friendly behavior over breakpoint-heavy APIs.
8
+ - Keep class names semantic enough to remember and generic enough to reuse.
9
+ - Add a new layout primitive only when a pattern appears often and is awkward to express with existing primitives.
10
+
11
+ ## Tokens
12
+
13
+ > Layout shares the global spacing surface and exposes a small set of gap and rhythm tokens.
14
+
15
+ Layout uses the shared spacing surface.
16
+
17
+ ```css
18
+ :root {
19
+ --gap: 0.75rem;
20
+ --space-1: 0.25rem;
21
+ --space-2: 0.5rem;
22
+ --space-3: 0.75rem;
23
+ --space-4: 1rem;
24
+ --space-5: 1.5rem;
25
+ --space-6: 2rem;
26
+ }
27
+ ```
28
+
29
+ Most layout primitives should read `--gap` and allow local overrides.
30
+
31
+ ```css
32
+ .settings-form {
33
+ --gap: var(--space-5);
34
+ }
35
+ ```
36
+
37
+ Prefer a local custom property over adding many one-off utility classes. Use inline styles only for demos, prototypes, or truly dynamic values.
38
+
39
+ ## Stack
40
+
41
+ > Vertical flow with consistent spacing, ideal for forms, card content, and content blocks.
42
+
43
+ Use `.stack` for vertical flow with consistent spacing.
44
+
45
+ ```html
46
+ <section class="stack">
47
+ <h2>Account</h2>
48
+ <p class="muted">Manage profile and billing settings.</p>
49
+ <form>
50
+ <label class="field">
51
+ <span class="field-label">Email</span>
52
+ <input type="email" placeholder="you@example.com" />
53
+ </label>
54
+ </form>
55
+ </section>
56
+ ```
57
+
58
+ Use stack for forms, card content, modal bodies, side panels, and documentation blocks.
59
+
60
+ ## Cluster
61
+
62
+ > Inline groups that wrap naturally, useful for action rows, tags, and toolbars.
63
+
64
+ Use `.cluster` for inline groups that wrap naturally.
65
+
66
+ ```html
67
+ <div class="cluster">
68
+ <button class="btn primary" type="button">Save</button>
69
+ <button class="btn outline" type="button">Cancel</button>
70
+ <a href="/docs">Read docs</a>
71
+ </div>
72
+ ```
73
+
74
+ Use cluster for action rows, tags, toolbar sections, metadata, and compact navigation.
75
+
76
+ ## Center
77
+
78
+ > Constrain readable content and center it in the viewport, with width and padding tunable per instance.
79
+
80
+ Use `.center` to constrain readable page content and center it in the viewport.
81
+
82
+ ```html
83
+ <main class="center stack">
84
+ <header class="prose">
85
+ <h1>Documentation</h1>
86
+ <p>Guides and API notes for Actual CSS.</p>
87
+ </header>
88
+ <section class="card">
89
+ <h2>Getting started</h2>
90
+ <p>Install the stylesheet and use semantic HTML.</p>
91
+ </section>
92
+ </main>
93
+ ```
94
+
95
+ Tune width and side padding with local variables.
96
+
97
+ ```css
98
+ .docs-page {
99
+ --center-size: 48rem;
100
+ --center-pad: var(--space-4);
101
+ }
102
+ ```
103
+
104
+ `.center` intentionally uses `box-sizing: content-box`. The max inline size is
105
+ the content measure, while inline padding is added outside that measure. This is
106
+ deliberate even though the global reset uses `border-box`.
107
+
108
+ ## List
109
+
110
+ > Lists stay native by default. Compose visual list rows from existing primitives.
111
+
112
+ Use `.list-reset` only when markers are not part of the content. Combine `.stack`, `.media`, `.cluster`, spacing helpers, and local styles for application-style rows.
113
+
114
+ ```html
115
+ <figure class="stack">
116
+ <figcaption><strong>Most played songs this week</strong></figcaption>
117
+
118
+ <ul class="list-reset stack gap-none">
119
+ <li class="media items-center py" style="border-block-end: var(--border-width) solid var(--border)">
120
+ <div class="avatar">
121
+ <img src="https://i.pravatar.cc/48?img=5" alt="Dio Lupa" />
122
+ </div>
123
+ <div class="cluster">
124
+ <div class="stack grow" style="--gap: var(--space-1)">
125
+ <strong>Dio Lupa</strong>
126
+ <span class="muted">Remaining Reason</span>
127
+ </div>
128
+ <span class="muted">3:45</span>
129
+ </div>
130
+ </li>
131
+
132
+ <li class="media items-center py" style="border-block-end: var(--border-width) solid var(--border)">
133
+ <div class="avatar">
134
+ <img src="https://i.pravatar.cc/48?img=10" alt="Astral Planes" />
135
+ </div>
136
+ <div class="cluster">
137
+ <div class="stack grow" style="--gap: var(--space-1)">
138
+ <strong>Astral Planes</strong>
139
+ <span class="muted">Neon Drift</span>
140
+ </div>
141
+ <span class="muted">4:12</span>
142
+ </div>
143
+ </li>
144
+ </ul>
145
+ </figure>
146
+ ```
147
+
148
+ Keep semantic lists unstyled when the markers carry meaning.
149
+
150
+ ## Grid
151
+
152
+ > Responsive equal-width item grids with a tunable minimum item width.
153
+
154
+ Use `.grid` for responsive equal-width item grids.
155
+
156
+ ```html
157
+ <section class="grid">
158
+ <article class="card">
159
+ <h3>Starter</h3>
160
+ <p>For small projects.</p>
161
+ </article>
162
+ <article class="card">
163
+ <h3>Team</h3>
164
+ <p>For shared products.</p>
165
+ </article>
166
+ <article class="card">
167
+ <h3>Scale</h3>
168
+ <p>For larger systems.</p>
169
+ </article>
170
+ </section>
171
+ ```
172
+
173
+ Tune the minimum item width with `--grid-min`.
174
+
175
+ ```css
176
+ .pricing-grid {
177
+ --grid-min: 20rem;
178
+ }
179
+ ```
180
+
181
+ ### Fixed Columns
182
+
183
+ Predictable 2/3/4/6-column grids. Full count by default; wrap in `.container-query` to make the column count collapse on narrow wrappers.
184
+
185
+ Use `.grid-2`, `.grid-3`, `.grid-4`, and `.grid-6` when the column count matters more than the item minimum width — for example, when a row should always read as "three items side by side", or when an empty cell should not stretch to fill space. Unlike `.grid`, the columns are fixed; if you have only two items in a `.grid-3`, the third cell stays empty rather than redistributing.
186
+
187
+ A `.grid-2/3/4/6` without a wrapper is a **fixed grid** (always at its full column count); with a `.container-query` wrapper, it's a **responsive grid** (the column count collapses on narrow wrappers). The wrapper is the query container; the grid itself is a plain block grid.
188
+
189
+ ```html
190
+ <div class="container-query">
191
+ <div class="grid-3">
192
+ <article class="card">
193
+ <h3>Starter</h3>
194
+ <p>For small projects.</p>
195
+ </article>
196
+ <article class="card">
197
+ <h3>Team</h3>
198
+ <p>For shared products.</p>
199
+ </article>
200
+ <article class="card">
201
+ <h3>Scale</h3>
202
+ <p>For larger systems.</p>
203
+ </article>
204
+ </div>
205
+ </div>
206
+ ```
207
+
208
+ A `grid-4` demo
209
+
210
+ ```html
211
+ <div class="container-query">
212
+ <div class="grid-4">
213
+ <article class="card">
214
+ <h3>Starter</h3>
215
+ <p>For small projects.</p>
216
+ </article>
217
+ <article class="card">
218
+ <h3>Team</h3>
219
+ <p>For shared products.</p>
220
+ </article>
221
+ <article class="card">
222
+ <h3>Scale</h3>
223
+ <p>For larger systems.</p>
224
+ </article>
225
+ <article class="card">
226
+ <h3>Enterprise</h3>
227
+ <p>Contact us.</p>
228
+ </article>
229
+ </div>
230
+ </div>
231
+ ```
232
+
233
+ A `grid-6` demo for compact items:
234
+
235
+ ```html
236
+ <div class="container-query">
237
+ <div class="grid-6">
238
+ <article class="card compact">
239
+ <span class="muted">Open</span>
240
+ <strong>18</strong>
241
+ </article>
242
+ <article class="card compact">
243
+ <span class="muted">Queued</span>
244
+ <strong>7</strong>
245
+ </article>
246
+ <article class="card compact">
247
+ <span class="muted">Blocked</span>
248
+ <strong>2</strong>
249
+ </article>
250
+ <article class="card compact">
251
+ <span class="muted">Shipped</span>
252
+ <strong>41</strong>
253
+ </article>
254
+ <article class="card compact">
255
+ <span class="muted">Owners</span>
256
+ <strong>6</strong>
257
+ </article>
258
+ <article class="card compact">
259
+ <span class="muted">SLA</span>
260
+ <strong>99%</strong>
261
+ </article>
262
+ </div>
263
+ </div>
264
+ ```
265
+
266
+ Behavior:
267
+ - Without `.container-query`: `.grid-2` is always 2 cols, `.grid-3` is always 3 cols, `.grid-4` is always 4 cols, and `.grid-6` is always 6 cols.
268
+ - With `.container-query`: `.grid-2`, `.grid-3`, and `.grid-4` collapse to one column on a narrow wrapper (under 28rem). `.grid-3` and `.grid-4` step through 2 columns between 28rem and 48rem. `.grid-6` starts at 2 columns under 28rem, steps through 3 columns between 28rem and 64rem, then returns to 6 columns.
269
+ - The intermediate 2-col step is useful for lists of items divisible by both 2 and 3 (or 4) — a 12-item list reads as 12 lines, then 6 lines of 2, then 4 lines of 3 (or 3 lines of 4), depending on the grid.
270
+ - `.grid-6` is for compact items such as stats, shortcut tiles, swatches, avatar summaries, and small settings cards. It does not collapse to one column by default. If item width matters more than an exact six-column rhythm, prefer `.grid` with a smaller `--grid-min`.
271
+ - The wrapper is the query container, so the same class behaves differently in a narrow sidebar than in a wide main area. No viewport breakpoints are involved.
272
+
273
+ Do not add `.row`, `.col-6`, `.offset-2`, or other fixed grid-system classes unless the project later proves it needs a formal grid system.
274
+
275
+ ## Sidebar
276
+
277
+ > Two-column layout where one side has a preferred width and the other takes the remaining space.
278
+
279
+ Use `.sidebar-layout` for two-column layouts where the aside should align to the top of the content, stay sticky, or keep a predictable declared width.
280
+
281
+ Wrap it in `.container-query` to make the switch depend on the container width. Below 64rem the columns stack; at and above it the aside takes `--sidebar-layout-size` and the content takes the remaining space. Older browsers use the viewport fallback.
282
+
283
+ ```html
284
+ <div class="container-query">
285
+ <div class="sidebar-layout" style="--sidebar-layout-size: 18rem">
286
+ <article class="stack">
287
+ <h1>Long-form article</h1>
288
+ <p>Article body that benefits from a sticky table of contents.</p>
289
+ </article>
290
+
291
+ <aside class="stack">
292
+ <h3>On this page</h3>
293
+ <ol class="list-reset">
294
+ <li><a class="link-muted" href="#section">Section</a></li>
295
+ </ol>
296
+ </aside>
297
+ </div>
298
+ </div>
299
+ ```
300
+
301
+ Tune the side width with `--sidebar-layout-size`.
302
+
303
+ ## Media Object
304
+
305
+ > Fixed-width leading element (avatar, icon, image) paired with flexible trailing content.
306
+
307
+ `.media` is the media object: a grid with `auto minmax(0, 1fr)` columns. Use it for author cards, comments, meta rows, and any composition that pairs a small leading element with a flexible content block. The trailing column takes the remaining space and never overflows.
308
+
309
+ Give `.media` exactly two children. Trailing metadata or actions go inside the content column — nest a `.cluster` and put `.grow` on the flexible part — never as additional children, which silently wrap onto a second grid row.
310
+
311
+ Add `.items-center` to align the leading element with short trailing content. For multi-line content, the default `align-items: start` is more comfortable.
312
+
313
+ ```html
314
+ <article class="card media items-center">
315
+ <span class="avatar"><abbr>AM</abbr></span>
316
+ <div class="stack">
317
+ <strong>Ada Meridian</strong>
318
+ <p class="muted">Senior designer working on design systems.</p>
319
+ </div>
320
+ </article>
321
+ ```
322
+
323
+ The media object is the underlying pattern of `.blog-author`, `.blog-comment`, and similar compositions in templates. Components can adopt it instead of repeating the grid rule.
324
+
325
+ ## Switcher
326
+
327
+ > Row that becomes a column when space gets tight, useful for small sets of panels.
328
+ > **Optional** — import `actual-css/css/optional/layout-extra` or `actual-css/css/optional/index`.
329
+
330
+ Use `.switcher` for rows that should become columns when space gets tight.
331
+
332
+ ```html
333
+ <section class="switcher">
334
+ <article class="card">
335
+ <h3>Profile</h3>
336
+ <p>Personal details and preferences.</p>
337
+ </article>
338
+ <article class="card">
339
+ <h3>Security</h3>
340
+ <p>Password and login settings.</p>
341
+ </article>
342
+ <article class="card">
343
+ <h3>Billing</h3>
344
+ <p>Invoices and payment methods.</p>
345
+ </article>
346
+ </section>
347
+ ```
348
+
349
+ This is useful for small sets of panels, not large card collections. Use `.grid` for repeatable collections.
350
+
351
+ The `.switcher` class is defined in `src/css/optional/layout-extra.css`. Import it when needed.
352
+
353
+ ## Topbar
354
+
355
+ > Sticky, frosted top bar shell for app/dashboard layouts with a persistent sidebar.
356
+ > **Optional** — import `actual-css/css/optional/layout-extra` or `actual-css/css/optional/index`.
357
+
358
+ Use `.topbar` for the structural shell of an app-shell header: sticky positioning, stacking, and a frosted background. Row content — search, breadcrumb, actions — stays local to the page.
359
+
360
+ ```html
361
+ <header class="topbar">
362
+ <button class="btn neutral ghost" type="button" aria-label="Open navigation">
363
+ <i class="ti ti-menu-2" aria-hidden="true"></i>
364
+ </button>
365
+ <ol class="breadcrumb" aria-label="Breadcrumb">
366
+ <li><a href="#overview">Overview</a></li>
367
+ <li aria-current="page">Accounts</li>
368
+ </ol>
369
+ <div class="grow"></div>
370
+ <span class="avatar sm"><abbr>LW</abbr></span>
371
+ </header>
372
+ ```
373
+
374
+ This is for the app-shell topbar specifically — a structural need that recurs unchanged across app UIs regardless of brand. It is not for marketing or editorial site headers, which are one-off visual identity per page (see [Patterns → Header Navigation](patterns.md#header-navigation)).
375
+
376
+ The `.topbar` class is defined in `src/css/optional/layout-extra.css`. Import it when needed.
377
+
378
+ ## Scroll Snap
379
+
380
+ > Horizontal rails that stay useful without JavaScript and snap in modern browsers.
381
+ > **Optional** — import `actual-css/css/optional/scroll-snap` or `actual-css/css/optional/index`.
382
+
383
+ Use `.scroll-snap` for a niche row of items that should scroll horizontally, such as card rails, media strips, overflow tabs, or a simple touch-friendly carousel baseline. Scrolling only appears when the items are wider than the container; set `--scroll-snap-item-size` for card rails.
384
+
385
+ ```html
386
+ <section class="stack" aria-labelledby="featured-title">
387
+ <h2 id="featured-title">Featured articles</h2>
388
+
389
+ <ul class="scroll-snap list-reset" style="--scroll-snap-item-size: min(85%, 18rem)">
390
+ <li class="card">Article one</li>
391
+ <li class="card">Article two</li>
392
+ <li class="card">Article three</li>
393
+ <li class="card">Article four</li>
394
+ <li class="card">Article five</li>
395
+ </ul>
396
+ </section>
397
+ ```
398
+
399
+ The baseline is flex layout plus `overflow-x: auto`, so older browsers still get a usable horizontal scroll area. Browsers with scroll snap support add `scroll-snap-type` and item alignment.
400
+
401
+ Items snap to the inline start edge by default. Use `data-snap="center"` for visual rails where centered cards are the better fit.
402
+
403
+ ```html
404
+ <div class="scroll-snap" data-snap="center" style="--scroll-snap-item-size: min(85%, 18rem)">
405
+ <article class="card">One</article>
406
+ <article class="card">Two</article>
407
+ <article class="card">Three</article>
408
+ <article class="card">Four</article>
409
+ <article class="card">Five</article>
410
+ </div>
411
+ ```
412
+
413
+ Keep scrollbars visible by default. If a product deliberately hides them, make that choice explicit with `data-scrollbar="hidden"`.
414
+
415
+ ```html
416
+ <div class="scroll-snap" data-scrollbar="hidden">
417
+ ...
418
+ </div>
419
+ ```
420
+
421
+ `.scroll-snap` is not a full interactive carousel. For previous/next controls, pagination, active state, mouse drag, looping, autoplay, or robust accessibility behavior, use a dedicated carousel library such as Swiper and compose it with Actual components.
422
+
423
+ ## Frame
424
+
425
+ > Media container that holds a stable aspect ratio for images, video, or embeds.
426
+
427
+ Use `.frame` for media that needs a stable aspect ratio.
428
+
429
+ ```html
430
+ <figure class="frame">
431
+ <img src="https://picsum.photos/seed/actual-css-frame/1600/900" alt="Preview placeholder" width="1600" height="900" />
432
+ </figure>
433
+ ```
434
+
435
+ ```css
436
+ .frame {
437
+ aspect-ratio: var(--frame-ratio, 16 / 9);
438
+ overflow: hidden;
439
+ }
440
+
441
+ .frame > :where(img, video, iframe) {
442
+ inline-size: 100%;
443
+ block-size: 100%;
444
+ object-fit: cover;
445
+ }
446
+ ```
447
+
448
+ Use local variables for common ratios.
449
+
450
+ ```css
451
+ .avatar-preview {
452
+ --frame-ratio: 1;
453
+ }
454
+ ```
455
+
456
+ ## Header And Footer
457
+
458
+ > Document landmarks for top and bottom regions, composed with layout primitives.
459
+
460
+ Header and footer are document landmarks, not required layout classes.
461
+
462
+ Use semantic elements by default.
463
+
464
+ ```html
465
+ <body class="app-shell">
466
+ <header>Actual CSS</header>
467
+ <main class="grow">Main content</main>
468
+ <footer>Footer links</footer>
469
+ </body>
470
+ ```
471
+
472
+ ```css
473
+ .app-shell {
474
+ min-block-size: 100vh;
475
+ display: flex;
476
+ flex-direction: column;
477
+ }
478
+ ```
479
+
480
+ Sticky header/footer behavior should be opt-in and documented only if it becomes part of the shipped layout API.
@@ -0,0 +1,73 @@
1
+ # Mental model
2
+
3
+ ## Components
4
+
5
+ Components are semantic boxes: `.btn`, `.badge`, `.alert`, `.card`, `.avatar`, etc. Each component owns its intrinsic layout and visual defaults.
6
+
7
+ ## Intents
8
+
9
+ `.primary`, `.secondary`, `.success`, `.warning`, `.danger` do not style elements directly. They only expose `--intent` and `--intent-fg`. Components and variants decide how to consume them.
10
+
11
+ ```html
12
+ <button class="btn primary">Primary</button>
13
+ <span class="badge success">Success</span>
14
+ ```
15
+
16
+ There is no `.btn-primary` or `.badge-success`. Intents are generic and reusable across any component that supports them.
17
+
18
+ Components fall back to their own default intent when no intent class is set. Buttons, badges, and alerts use the neutral palette (`--neutral` / `--neutral-fg`) by default.
19
+
20
+ Custom intents need no framework support — define `--intent` and `--intent-fg` on a class:
21
+
22
+ ```css
23
+ .tertiary {
24
+ --intent: var(--tertiary);
25
+ --intent-fg: var(--tertiary-fg);
26
+ }
27
+ ```
28
+
29
+ ```html
30
+ <button class="btn tertiary">Tertiary</button>
31
+ <span class="badge tertiary">Tertiary</span>
32
+ ```
33
+
34
+ ## Variants
35
+
36
+ `.solid`, `.soft`, `.outline` define the visual treatment by setting `--ui-bg`, `--ui-fg`, `--ui-border` (and optionally `--ui-hover-bg`). Components consume these tokens with sensible fallbacks.
37
+
38
+ `.btn` and `.badge` default to `.solid`. `.alert` defaults to `.soft`.
39
+
40
+ `.ghost` and `.link` are button-only variants.
41
+
42
+ ```html
43
+ <button class="btn soft primary">Soft primary</button>
44
+ <span class="badge outline success">Outline success</span>
45
+ <div class="alert solid warning">Solid warning</div>
46
+ ```
47
+
48
+ ## Sizes
49
+
50
+ `.sm` and `.lg` are contextual modifiers. They set inherited size tokens (`--control-size`, `--variant-font-size`, etc.) that components opt into.
51
+
52
+ ```html
53
+ <div class="sm">
54
+ <button class="btn">Small button</button>
55
+ <span class="badge">Small badge</span>
56
+ </div>
57
+ ```
58
+
59
+ Works locally too:
60
+
61
+ ```html
62
+ <button class="btn sm">Small button</button>
63
+ <span class="badge lg">Large badge</span>
64
+ ```
65
+
66
+ Components with bespoke sizing (`.avatar`, `.spinner`) define local `.sm`/`.lg` instead.
67
+
68
+ ## Child semantics
69
+
70
+ When using a component, child elements follow the semantic pattern of that component. For example, `.avatar` accepts `<img>`, `<picture>`, text content, an empty `.badge` for status dots, and can be a `<button>` or `<a>`.
71
+
72
+ No child classes like `.avatar-img` are needed.
73
+