css-is-awesome 1.4.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/AGENTS.md +1 -1
  2. package/CHANGELOG.md +24 -0
  3. package/README.md +5 -3
  4. package/css-is-awesome.instructions.md +9 -4
  5. package/package.json +1 -1
  6. package/public/theme.css +210 -0
  7. package/public/themes/boilerplate/theme.css +10 -0
  8. package/public/themes/cupertino/theme.css +10 -0
  9. package/public/themes/cupertino-dark/theme.css +10 -0
  10. package/public/themes/cupertino-light/theme.css +10 -0
  11. package/public/themes/glass/theme.css +10 -0
  12. package/public/themes/glass-dark/theme.css +10 -0
  13. package/public/themes/glass-light/theme.css +10 -0
  14. package/public/themes/graphite/theme.css +10 -0
  15. package/public/themes/graphite-dark/theme.css +10 -0
  16. package/public/themes/graphite-light/theme.css +10 -0
  17. package/public/themes/press/theme.css +10 -0
  18. package/public/themes/press-dark/theme.css +10 -0
  19. package/public/themes/press-light/theme.css +10 -0
  20. package/public/themes/prism/theme.css +10 -0
  21. package/public/themes/prism-dark/theme.css +10 -0
  22. package/public/themes/prism-light/theme.css +10 -0
  23. package/public/themes/sketchbook/theme.css +10 -0
  24. package/public/themes/sketchbook-dark/theme.css +10 -0
  25. package/public/themes/terminal/theme.css +10 -0
  26. package/public/themes/terminal-dark/theme.css +10 -0
  27. package/public/themes/terminal-light/theme.css +10 -0
  28. package/scss/components/_navigation.scss +83 -0
  29. package/scss/recipes/bottom-nav.md +184 -0
  30. package/scss/recipes/combobox.md +9 -0
  31. package/scss/recipes/dialog.md +21 -0
  32. package/scss/recipes/mobile-nav.md +3 -0
  33. package/scss/themes/boilerplate.scss +11 -0
  34. package/scss/themes/cupertino-dark.scss +11 -0
  35. package/scss/themes/cupertino-light.scss +11 -0
  36. package/scss/themes/cupertino.scss +11 -0
  37. package/scss/themes/glass-dark.scss +11 -0
  38. package/scss/themes/glass-light.scss +11 -0
  39. package/scss/themes/glass.scss +11 -0
  40. package/scss/themes/graphite-dark.scss +11 -0
  41. package/scss/themes/graphite-light.scss +11 -0
  42. package/scss/themes/graphite.scss +11 -0
  43. package/scss/themes/press-dark.scss +11 -0
  44. package/scss/themes/press-light.scss +11 -0
  45. package/scss/themes/press.scss +11 -0
  46. package/scss/themes/prism-dark.scss +11 -0
  47. package/scss/themes/prism-light.scss +11 -0
  48. package/scss/themes/prism.scss +11 -0
  49. package/scss/themes/sketchbook-dark.scss +11 -0
  50. package/scss/themes/sketchbook.scss +11 -0
  51. package/scss/themes/terminal-dark.scss +11 -0
  52. package/scss/themes/terminal-light.scss +11 -0
  53. package/scss/themes/terminal.scss +11 -0
@@ -169,6 +169,16 @@
169
169
  --space-7: 3rem; /* major gap */
170
170
  --space-8: 4rem; /* page section */
171
171
  --space-9: 6rem; /* hero rhythm */
172
+ /* T-shirt aliases - var() references into this theme's numbered scale,
173
+ so re-tuning a numbered step re-tunes its alias automatically. */
174
+ --space-xs: var(--space-1);
175
+ --space-sm: var(--space-2);
176
+ --space-md: var(--space-4);
177
+ --space-lg: var(--space-5);
178
+ --space-xl: var(--space-6);
179
+ --space-2xl: var(--space-7);
180
+ --space-3xl: var(--space-8);
181
+ --space-4xl: var(--space-9);
172
182
  /* Radius alias — Press is editorial, xl stays tight (6px) */
173
183
  --radius-sm: var(--r-sm);
174
184
  --radius-md: var(--r-md);
@@ -197,6 +197,16 @@
197
197
  --space-7: 3rem; /* major gap */
198
198
  --space-8: 4rem; /* page section */
199
199
  --space-9: 6rem; /* hero rhythm */
200
+ /* T-shirt aliases - var() references into this theme's numbered scale,
201
+ so re-tuning a numbered step re-tunes its alias automatically. */
202
+ --space-xs: var(--space-1);
203
+ --space-sm: var(--space-2);
204
+ --space-md: var(--space-4);
205
+ --space-lg: var(--space-5);
206
+ --space-xl: var(--space-6);
207
+ --space-2xl: var(--space-7);
208
+ --space-3xl: var(--space-8);
209
+ --space-4xl: var(--space-9);
200
210
  /* Radius alias — mirrors --r-* with standard names so
201
211
  `m.radius(size)` in the library finds --radius-<size>.
202
212
  Press is editorial and angular: xl stays tight (4px). */
@@ -134,6 +134,16 @@
134
134
  --space-7: 3rem; /* major gap */
135
135
  --space-8: 4rem; /* page section */
136
136
  --space-9: 6rem; /* hero rhythm */
137
+ /* T-shirt aliases - var() references into this theme's numbered scale,
138
+ so re-tuning a numbered step re-tunes its alias automatically. */
139
+ --space-xs: var(--space-1);
140
+ --space-sm: var(--space-2);
141
+ --space-md: var(--space-4);
142
+ --space-lg: var(--space-5);
143
+ --space-xl: var(--space-6);
144
+ --space-2xl: var(--space-7);
145
+ --space-3xl: var(--space-8);
146
+ --space-4xl: var(--space-9);
137
147
  --radius-sm: var(--r-sm);
138
148
  --radius-md: var(--r-md);
139
149
  --radius-lg: var(--r-lg);
@@ -157,6 +157,16 @@
157
157
  --space-7: 3rem; /* major gap */
158
158
  --space-8: 4rem; /* page section */
159
159
  --space-9: 6rem; /* hero rhythm */
160
+ /* T-shirt aliases - var() references into this theme's numbered scale,
161
+ so re-tuning a numbered step re-tunes its alias automatically. */
162
+ --space-xs: var(--space-1);
163
+ --space-sm: var(--space-2);
164
+ --space-md: var(--space-4);
165
+ --space-lg: var(--space-5);
166
+ --space-xl: var(--space-6);
167
+ --space-2xl: var(--space-7);
168
+ --space-3xl: var(--space-8);
169
+ --space-4xl: var(--space-9);
160
170
  /* Radius alias */
161
171
  --radius-sm: var(--r-sm);
162
172
  --radius-md: var(--r-md);
@@ -160,6 +160,16 @@
160
160
  --space-7: 3rem; /* major gap */
161
161
  --space-8: 4rem; /* page section */
162
162
  --space-9: 6rem; /* hero rhythm */
163
+ /* T-shirt aliases - var() references into this theme's numbered scale,
164
+ so re-tuning a numbered step re-tunes its alias automatically. */
165
+ --space-xs: var(--space-1);
166
+ --space-sm: var(--space-2);
167
+ --space-md: var(--space-4);
168
+ --space-lg: var(--space-5);
169
+ --space-xl: var(--space-6);
170
+ --space-2xl: var(--space-7);
171
+ --space-3xl: var(--space-8);
172
+ --space-4xl: var(--space-9);
163
173
  /* Radius alias */
164
174
  --radius-sm: var(--r-sm);
165
175
  --radius-md: var(--r-md);
@@ -134,6 +134,16 @@
134
134
  --space-7: 3rem; /* major gap */
135
135
  --space-8: 4rem; /* page section */
136
136
  --space-9: 6rem; /* hero rhythm */
137
+ /* T-shirt aliases - var() references into this theme's numbered scale,
138
+ so re-tuning a numbered step re-tunes its alias automatically. */
139
+ --space-xs: var(--space-1);
140
+ --space-sm: var(--space-2);
141
+ --space-md: var(--space-4);
142
+ --space-lg: var(--space-5);
143
+ --space-xl: var(--space-6);
144
+ --space-2xl: var(--space-7);
145
+ --space-3xl: var(--space-8);
146
+ --space-4xl: var(--space-9);
137
147
  --radius-sm: var(--r-sm);
138
148
  --radius-md: var(--r-md);
139
149
  --radius-lg: var(--r-lg);
@@ -173,6 +173,16 @@
173
173
  --space-7: 3rem; /* major gap */
174
174
  --space-8: 4rem; /* page section */
175
175
  --space-9: 6rem; /* hero rhythm */
176
+ /* T-shirt aliases - var() references into this theme's numbered scale,
177
+ so re-tuning a numbered step re-tunes its alias automatically. */
178
+ --space-xs: var(--space-1);
179
+ --space-sm: var(--space-2);
180
+ --space-md: var(--space-4);
181
+ --space-lg: var(--space-5);
182
+ --space-xl: var(--space-6);
183
+ --space-2xl: var(--space-7);
184
+ --space-3xl: var(--space-8);
185
+ --space-4xl: var(--space-9);
176
186
  /* Radius alias */
177
187
  --radius-sm: var(--r-sm);
178
188
  --radius-md: var(--r-md);
@@ -135,6 +135,16 @@
135
135
  --space-7: 3rem; /* major gap */
136
136
  --space-8: 4rem; /* page section */
137
137
  --space-9: 6rem; /* hero rhythm */
138
+ /* T-shirt aliases - var() references into this theme's numbered scale,
139
+ so re-tuning a numbered step re-tunes its alias automatically. */
140
+ --space-xs: var(--space-1);
141
+ --space-sm: var(--space-2);
142
+ --space-md: var(--space-4);
143
+ --space-lg: var(--space-5);
144
+ --space-xl: var(--space-6);
145
+ --space-2xl: var(--space-7);
146
+ --space-3xl: var(--space-8);
147
+ --space-4xl: var(--space-9);
138
148
  --radius-sm: 0;
139
149
  --radius-md: 0;
140
150
  --radius-lg: 0;
@@ -196,6 +196,16 @@
196
196
  --space-7: 3rem; /* major gap */
197
197
  --space-8: 4rem; /* page section */
198
198
  --space-9: 6rem; /* hero rhythm */
199
+ /* T-shirt aliases - var() references into this theme's numbered scale,
200
+ so re-tuning a numbered step re-tunes its alias automatically. */
201
+ --space-xs: var(--space-1);
202
+ --space-sm: var(--space-2);
203
+ --space-md: var(--space-4);
204
+ --space-lg: var(--space-5);
205
+ --space-xl: var(--space-6);
206
+ --space-2xl: var(--space-7);
207
+ --space-3xl: var(--space-8);
208
+ --space-4xl: var(--space-9);
199
209
  /* Radius alias — CRT has hard pixel corners, so every slot is 0 */
200
210
  --radius-sm: 0;
201
211
  --radius-md: 0;
@@ -134,6 +134,16 @@
134
134
  --space-7: 3rem; /* major gap */
135
135
  --space-8: 4rem; /* page section */
136
136
  --space-9: 6rem; /* hero rhythm */
137
+ /* T-shirt aliases - var() references into this theme's numbered scale,
138
+ so re-tuning a numbered step re-tunes its alias automatically. */
139
+ --space-xs: var(--space-1);
140
+ --space-sm: var(--space-2);
141
+ --space-md: var(--space-4);
142
+ --space-lg: var(--space-5);
143
+ --space-xl: var(--space-6);
144
+ --space-2xl: var(--space-7);
145
+ --space-3xl: var(--space-8);
146
+ --space-4xl: var(--space-9);
137
147
  --radius-sm: 0;
138
148
  --radius-md: 0;
139
149
  --radius-lg: 0;
@@ -320,3 +320,86 @@
320
320
  transition: none;
321
321
  }
322
322
  }
323
+
324
+ // ----------------------------------------------------------------------------
325
+ // SHEET — bottom drawer with rounded shoulders; the mobile-app panel.
326
+ // ----------------------------------------------------------------------------
327
+ // A preset of drawer($side: bottom): slides up from the bottom edge,
328
+ // caps its height so the page stays visible behind it (dvh survives
329
+ // mobile URL-bar resizing), rounds the top corners, and pads for the
330
+ // home-indicator safe area. Same zero-JS popover mechanics as drawer.
331
+ //
332
+ // Usage:
333
+ // .docs-sheet { @include sheet; }
334
+ // <section id="docs-sheet" class="docs-sheet" popover aria-label="Docs">…</section>
335
+
336
+ @mixin sheet(
337
+ $size: auto,
338
+ $max: 72dvh,
339
+ $bg: surface-default,
340
+ $backdrop: rgba(0, 0, 0, 0.4),
341
+ $p: 5,
342
+ $r: xl
343
+ ) {
344
+ @include drawer($side: bottom, $size: $size, $bg: $bg, $backdrop: $backdrop, $p: $p);
345
+ max-block-size: $max;
346
+ border-start-start-radius: m.radius($r);
347
+ border-start-end-radius: m.radius($r);
348
+ padding-block-end: calc(#{m.space($p)} + env(safe-area-inset-bottom));
349
+ }
350
+
351
+ // ----------------------------------------------------------------------------
352
+ // DOCK — fixed bottom bar; the mobile-app layout's navigation.
353
+ // ----------------------------------------------------------------------------
354
+ // The pattern the cia docs site runs on phones: a thumb-reach bar whose
355
+ // slots open popover sheets (pair dock-item buttons with sheet() panels
356
+ // via popovertarget — the browser manages aria-expanded, Esc, and light
357
+ // dismiss; zero JavaScript). CSS Grid gives every slot an equal track.
358
+ //
359
+ // Usage:
360
+ // .dock { @include dock(3); }
361
+ // .dock button { @include dock-item; }
362
+ // <nav class="dock" aria-label="Quick menu">
363
+ // <button popovertarget="docs-sheet">Docs</button>
364
+ // …
365
+ // </nav>
366
+
367
+ @mixin dock($slots: 3, $bg: surface-default) {
368
+ @include m.print-hidden;
369
+ position: fixed;
370
+ inset-inline: 0;
371
+ inset-block-end: 0;
372
+ z-index: m.z(fixed);
373
+ display: grid;
374
+ grid-template-columns: repeat($slots, minmax(0, 1fr));
375
+ background: m.color($bg);
376
+ border-block-start: 1px solid m.color(border-default);
377
+ padding-block-end: env(safe-area-inset-bottom);
378
+ }
379
+
380
+ @mixin dock-item($accent: action-primary-default) {
381
+ @include m.button-reset;
382
+ @include m.focus-ring;
383
+ cursor: pointer;
384
+ display: grid;
385
+ justify-items: center;
386
+ align-content: center;
387
+ gap: m.space(1);
388
+ min-height: 3.5rem; /* 56px — comfortable thumb target */
389
+ padding: m.space(1) m.space(2);
390
+ color: m.color(text-secondary);
391
+ @include m.font(medium, 1);
392
+ @include m.transition(color, background-color);
393
+
394
+ > svg {
395
+ width: 1.35em;
396
+ height: 1.35em;
397
+ }
398
+
399
+ // Semantic state lives in ARIA: the browser sets aria-expanded on
400
+ // popovertarget invokers; aria-current marks a routed slot.
401
+ &[aria-expanded="true"],
402
+ &[aria-current] {
403
+ color: m.color($accent);
404
+ }
405
+ }
@@ -0,0 +1,184 @@
1
+ ---
2
+ name: bottom-nav
3
+ description: Mobile-app layout — a fixed bottom dock whose slots open slide-up sheets, zero JavaScript on the Popover API.
4
+ category: navigation
5
+ complexity: medium
6
+ cia-version: ">=1.5.0"
7
+ ---
8
+
9
+ ## Use this when
10
+
11
+ Your page is a **tool** on mobile — docs with a section tree, a dashboard, an
12
+ editor — and navigation belongs in thumb reach, app-style, instead of behind a
13
+ top hamburger. This is the layout the cia docs site itself runs on phones.
14
+ For simple site navigation (a menu of links), use the `mobile-nav` recipe's
15
+ drawer instead.
16
+
17
+ ## Structure (raw HTML)
18
+
19
+ A fixed bottom dock of buttons, each pointing at its own sheet via
20
+ `popovertarget`. The browser manages open state, Esc, and light dismiss.
21
+
22
+ ```html
23
+ <div data-cia-recipe="bottom-nav">
24
+ <!-- slide-up sheets — one per dock slot -->
25
+ <section id="nav-sheet" class="app-sheet" popover aria-label="Navigation">
26
+ <nav data-slot="nav">…section links…</nav>
27
+ </section>
28
+ <section id="tools-sheet" class="app-sheet" popover aria-label="Tools">
29
+ <div data-slot="tools">…controls…</div>
30
+ </section>
31
+
32
+ <!-- the dock -->
33
+ <nav class="app-dock" aria-label="Quick menu">
34
+ <button popovertarget="nav-sheet">Menu</button>
35
+ <button popovertarget="tools-sheet">Tools</button>
36
+ <a href="/search" aria-current="false">Search</a>
37
+ </nav>
38
+ </div>
39
+ ```
40
+
41
+ ## Styling (cia mixins)
42
+
43
+ ```scss
44
+ // AppDock.module.scss — component stylesheet, so import the zero-emit barrel.
45
+ @use 'css-is-awesome/api' as cia;
46
+
47
+ .app-dock {
48
+ // Hide above the mobile breakpoint — desktop has the full chrome.
49
+ display: none;
50
+
51
+ @include cia.media-down(lg) {
52
+ @include cia.dock(3); // CSS Grid: one equal track per slot
53
+ }
54
+ }
55
+ .app-dock button,
56
+ .app-dock a {
57
+ @include cia.dock-item; // 56px thumb targets, ARIA-driven accent
58
+ }
59
+
60
+ .app-sheet {
61
+ @include cia.media-down(lg) {
62
+ @include cia.sheet; // bottom drawer, 72dvh cap, rounded shoulders
63
+ }
64
+ }
65
+ ```
66
+
67
+ Give the page's scrollable content bottom padding so the fixed dock never
68
+ covers the last lines: `padding-block-end: calc(6rem + env(safe-area-inset-bottom))`
69
+ on the content region of your page layout.
70
+
71
+ ## Interactivity
72
+
73
+ **Zero JavaScript.** Each dock button is a `popovertarget` invoker for its
74
+ sheet; the browser keeps `aria-expanded` in sync (which is what lights the
75
+ active slot via `cia.dock-item`), closes on Esc or outside tap, and stacks
76
+ the sheet in the top layer above the dock. Opening one sheet auto-closes
77
+ another (`popover="auto"` is exclusive). The slide-up animation rides
78
+ `@starting-style` and degrades to an instant open on older engines.
79
+ Popover is Baseline 2024 (Chrome 114, Firefox 125, Safari 17).
80
+
81
+ ## A11y checklist
82
+
83
+ - [ ] The dock is a `<nav>` with an `aria-label`, discoverable as a landmark
84
+ ([WAI-ARIA APG: Landmark regions](https://www.w3.org/WAI/ARIA/apg/practices/landmark-regions/))
85
+ - [ ] Every slot is a real `<button>` (sheet openers) or `<a>` (route links)
86
+ with a visible text label — icons alone don't name a control
87
+ ([WCAG 4.1.2 Name, Role, Value](https://www.w3.org/WAI/WCAG22/Understanding/name-role-value.html))
88
+ - [ ] `aria-expanded` reflects each sheet's state — browser-managed for
89
+ `popovertarget` invokers; verify with an inspector
90
+ ([WAI-ARIA APG: Disclosure pattern](https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/))
91
+ - [ ] Sheets carry `aria-label`s describing their content
92
+ ([WCAG 2.4.6 Headings and Labels](https://www.w3.org/WAI/WCAG22/Understanding/headings-and-labels.html))
93
+ - [ ] Esc closes the open sheet and focus returns to its dock button (native
94
+ popover behavior — verify if you've added scripts)
95
+ ([WAI-ARIA APG: Dialog (Modal) keyboard](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/))
96
+ - [ ] Slots are ≥ 44px targets; `cia.dock-item` defaults to 56px
97
+ ([WCAG 2.5.8 Target Size (Minimum)](https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum.html))
98
+ - [ ] Reduced motion honored — the sheet's slide disables under
99
+ `prefers-reduced-motion` (baked into `cia.drawer`)
100
+ ([WCAG 2.3.3 Animation from Interactions](https://www.w3.org/WAI/WCAG22/Understanding/animation-from-interactions.html))
101
+
102
+ ## Framework examples
103
+
104
+ ### React
105
+
106
+ ```jsx
107
+ export function AppDock() {
108
+ return (
109
+ <>
110
+ <section id="nav-sheet" className={styles.appSheet} popover="auto" aria-label="Navigation">
111
+ <nav>…</nav>
112
+ </section>
113
+ <nav className={styles.appDock} aria-label="Quick menu">
114
+ <button popoverTarget="nav-sheet">Menu</button>
115
+ </nav>
116
+ </>
117
+ );
118
+ }
119
+ // React 19 forwards popover / popoverTarget as attributes — still no JS of yours.
120
+ ```
121
+
122
+ ### Vue
123
+
124
+ ```vue
125
+ <template>
126
+ <section id="nav-sheet" class="app-sheet" popover aria-label="Navigation">
127
+ <nav>…</nav>
128
+ </section>
129
+ <nav class="app-dock" aria-label="Quick menu">
130
+ <button popovertarget="nav-sheet">Menu</button>
131
+ </nav>
132
+ </template>
133
+ ```
134
+
135
+ ### Svelte
136
+
137
+ ```svelte
138
+ <section id="nav-sheet" class="app-sheet" popover aria-label="Navigation">
139
+ <nav>…</nav>
140
+ </section>
141
+ <nav class="app-dock" aria-label="Quick menu">
142
+ <button popovertarget="nav-sheet">Menu</button>
143
+ </nav>
144
+ ```
145
+
146
+ ### Vanilla (Web Component)
147
+
148
+ ```html
149
+ <!-- The pattern IS vanilla HTML — the popover attributes are the whole
150
+ mechanism. Drop the Structure markup in as-is. -->
151
+ <script type="module">
152
+ // Intentionally empty. Optional nicety: close the open sheet when a
153
+ // same-page link inside it is tapped —
154
+ // sheet.querySelectorAll('a[href^="#"]').forEach(a =>
155
+ // a.addEventListener('click', () => sheet.hidePopover()));
156
+ </script>
157
+ ```
158
+
159
+ ## Variants
160
+
161
+ - **Mixed dock**: route links (`<a aria-current="page">`) and sheet openers
162
+ (`<button popovertarget>`) share the dock; `cia.dock-item` lights either
163
+ via its ARIA state.
164
+ - **Two-slot / five-slot**: pass the count — `cia.dock(5)` — and the grid
165
+ redistributes; keep it ≤5 so labels stay readable.
166
+
167
+ ## Pitfalls
168
+
169
+ - **`popover` hides sheets everywhere**, including desktop. If a sheet's
170
+ content should exist in desktop chrome instead (a sidebar, say), render it
171
+ twice — desktop region + mobile sheet — or move the node with CSS only.
172
+ - **Padding under the dock**: forgetting the content's bottom padding hides
173
+ the page's last lines behind the bar (see Styling).
174
+ - **Don't z-index against the sheets** — popovers live in the top layer; the
175
+ dock's `z-index` only matters against page content.
176
+ - The dock is `position: fixed` — inside a transformed ancestor it will pin
177
+ to that ancestor, not the viewport. Keep it at the page level.
178
+
179
+ ## Related recipes
180
+
181
+ - `mobile-nav` — hamburger + drawer for plain site navigation (the "flex
182
+ layout": one fluid shell that reshapes with the screen; this recipe is
183
+ the "app layout").
184
+ - `dialog` — modal overlays on native `<dialog>`.
@@ -501,6 +501,15 @@ Committed values render as removable chips before the input; the input clears af
501
501
  - **`<datalist>` styling is a dead end.** No browser lets you style the native popup. Don't burn time on it — if the design needs styled options, that's the signal to move to the custom variant.
502
502
  - **Filtering resets the active index.** After re-filtering, old indices point at different options. Reset `active` to `-1` on every `input` event (all examples above do).
503
503
  - **Scroll the active option into view** when the list overflows: `option.scrollIntoView({ block: "nearest" })` after moving the active index — omitted from the examples for brevity, needed in production with long lists.
504
+ - **Phones: cap the listbox, thumb-size the options.** The `max-block-size: 16rem; overflow-y: auto` in the Styling section is what keeps a long list from running past the bottom of a small viewport — don't delete it when trimming. And `cia.dropdown-item` is padded for pointers (≥24px, the WCAG minimum); at touch widths, bump options to a comfortable 44px thumb target:
505
+
506
+ ```scss
507
+ [role="option"] {
508
+ @include cia.media-down(md) {
509
+ min-block-size: 44px;
510
+ }
511
+ }
512
+ ```
504
513
 
505
514
  ## Related recipes
506
515
 
@@ -251,6 +251,26 @@ Override `.my-dialog` with `inset-inline-end: 0; margin-inline: auto 0; block-si
251
251
 
252
252
  cia's built-in keyframes are small entrance nudges, so a full-width drawer needs its own `@keyframes`. If an 8px slide is enough, skip the custom keyframe and use `@include cia.animate(slide-left);` — it reads the same duration/easing tokens and handles `prefers-reduced-motion` for you.
253
253
 
254
+ ### Bottom sheet on phones
255
+
256
+ At phone widths a centered modal can feel cramped; the mobile-app convention is a bottom sheet. `cia.sheet` gives `<dialog>` the sheet's **box styling** — full-width at the bottom edge, 72dvh height cap, rounded shoulders, home-indicator safe-area padding — but its slide-up motion is built for `[popover]` elements: both the entry transition and the closed-state off-screen offset key on `:popover-open`, which a `<dialog>` never matches. So on `<dialog>` you must reset that offset for the `[open]` state, and the sheet opens in place instead of sliding:
257
+
258
+ ```scss
259
+ .my-dialog {
260
+ @include cia.modal;
261
+
262
+ @include cia.media-down(md) {
263
+ @include cia.sheet; // box styles only on <dialog> — see note above
264
+
265
+ &[open] {
266
+ translate: 0 0; // undo the sheet's :popover-open-keyed offset
267
+ }
268
+ }
269
+ }
270
+ ```
271
+
272
+ If the slide-up entrance matters to you, use a `[popover]` element with the `bottom-nav` recipe's sheet pattern instead of `<dialog>` — you trade `.showModal()`'s focus trap for light dismiss and the full animation.
273
+
254
274
  ## Pitfalls
255
275
 
256
276
  - **Form inside dialog with another method:** Setting `<form method="get">` etc. inside a `<dialog>` breaks the native close-on-submit. Either nest a separate `<form method="dialog">` around the close buttons OR handle submission explicitly with `event.preventDefault()` + `dialogEl.close()`.
@@ -261,5 +281,6 @@ cia's built-in keyframes are small entrance nudges, so a full-width drawer needs
261
281
  ## Related recipes
262
282
 
263
283
  - [`bare-tags`](./_bare-tags.scss) — base bare `<dialog>` styling that applies if you skip a custom class name
284
+ - `bottom-nav` — slide-up sheets on `[popover]` with the full animation; the alternative named in the bottom-sheet variant above
264
285
  - (planned v1.1) `command-palette.md` — Cmd+K palette built on `<dialog>` + combobox pattern
265
286
  - (planned v1.1) `toast.md` — non-modal transient notifications (`[popover]` based)
@@ -226,6 +226,9 @@ standalone mixin, so state can come from `:checked` instead of
226
226
 
227
227
  ## Related recipes
228
228
 
229
+ - `bottom-nav` — bottom dock + slide-up sheets for pages that are tools on
230
+ mobile (the "app layout"; this recipe is the "flex layout": one fluid
231
+ shell that reshapes with the screen).
229
232
  - `dialog` — modal overlays for content (native `<dialog>`, same zero-JS
230
233
  philosophy).
231
234
  - `combobox` — another browser-native disclosure pattern.
@@ -172,6 +172,17 @@
172
172
  --space-8: 4rem; /* page section */
173
173
  --space-9: 6rem; /* hero rhythm */
174
174
 
175
+ /* T-shirt aliases - var() references into this theme's numbered scale,
176
+ so re-tuning a numbered step re-tunes its alias automatically. */
177
+ --space-xs: var(--space-1);
178
+ --space-sm: var(--space-2);
179
+ --space-md: var(--space-4);
180
+ --space-lg: var(--space-5);
181
+ --space-xl: var(--space-6);
182
+ --space-2xl: var(--space-7);
183
+ --space-3xl: var(--space-8);
184
+ --space-4xl: var(--space-9);
185
+
175
186
  --radius-sm: var(--r-sm); --radius-md: var(--r-md); --radius-lg: var(--r-lg);
176
187
  --radius-xl: 12px; --radius-full: 9999px;
177
188
  --font-primary: var(--font-sans);
@@ -201,6 +201,17 @@
201
201
  --space-8: 4rem; /* page section */
202
202
  --space-9: 6rem; /* hero rhythm */
203
203
 
204
+ /* T-shirt aliases - var() references into this theme's numbered scale,
205
+ so re-tuning a numbered step re-tunes its alias automatically. */
206
+ --space-xs: var(--space-1);
207
+ --space-sm: var(--space-2);
208
+ --space-md: var(--space-4);
209
+ --space-lg: var(--space-5);
210
+ --space-xl: var(--space-6);
211
+ --space-2xl: var(--space-7);
212
+ --space-3xl: var(--space-8);
213
+ --space-4xl: var(--space-9);
214
+
204
215
 
205
216
 
206
217
 
@@ -219,6 +219,17 @@
219
219
  --space-8: 4rem; /* page section */
220
220
  --space-9: 6rem; /* hero rhythm */
221
221
 
222
+ /* T-shirt aliases - var() references into this theme's numbered scale,
223
+ so re-tuning a numbered step re-tunes its alias automatically. */
224
+ --space-xs: var(--space-1);
225
+ --space-sm: var(--space-2);
226
+ --space-md: var(--space-4);
227
+ --space-lg: var(--space-5);
228
+ --space-xl: var(--space-6);
229
+ --space-2xl: var(--space-7);
230
+ --space-3xl: var(--space-8);
231
+ --space-4xl: var(--space-9);
232
+
222
233
 
223
234
 
224
235
 
@@ -177,6 +177,17 @@
177
177
  --space-8: 4rem; /* page section */
178
178
  --space-9: 6rem; /* hero rhythm */
179
179
 
180
+ /* T-shirt aliases - var() references into this theme's numbered scale,
181
+ so re-tuning a numbered step re-tunes its alias automatically. */
182
+ --space-xs: var(--space-1);
183
+ --space-sm: var(--space-2);
184
+ --space-md: var(--space-4);
185
+ --space-lg: var(--space-5);
186
+ --space-xl: var(--space-6);
187
+ --space-2xl: var(--space-7);
188
+ --space-3xl: var(--space-8);
189
+ --space-4xl: var(--space-9);
190
+
180
191
  --radius-sm: var(--r-sm); --radius-md: var(--r-md); --radius-lg: var(--r-lg);
181
192
  --radius-xl: 0.75rem; --radius-full: 9999px;
182
193
  --font-primary: var(--font-sans);
@@ -211,6 +211,17 @@
211
211
  --space-8: 4rem; /* page section */
212
212
  --space-9: 6rem; /* hero rhythm */
213
213
 
214
+ /* T-shirt aliases - var() references into this theme's numbered scale,
215
+ so re-tuning a numbered step re-tunes its alias automatically. */
216
+ --space-xs: var(--space-1);
217
+ --space-sm: var(--space-2);
218
+ --space-md: var(--space-4);
219
+ --space-lg: var(--space-5);
220
+ --space-xl: var(--space-6);
221
+ --space-2xl: var(--space-7);
222
+ --space-3xl: var(--space-8);
223
+ --space-4xl: var(--space-9);
224
+
214
225
 
215
226
 
216
227
 
@@ -238,6 +238,17 @@
238
238
  --space-8: 4rem; /* page section */
239
239
  --space-9: 6rem; /* hero rhythm */
240
240
 
241
+ /* T-shirt aliases - var() references into this theme's numbered scale,
242
+ so re-tuning a numbered step re-tunes its alias automatically. */
243
+ --space-xs: var(--space-1);
244
+ --space-sm: var(--space-2);
245
+ --space-md: var(--space-4);
246
+ --space-lg: var(--space-5);
247
+ --space-xl: var(--space-6);
248
+ --space-2xl: var(--space-7);
249
+ --space-3xl: var(--space-8);
250
+ --space-4xl: var(--space-9);
251
+
241
252
 
242
253
 
243
254
 
@@ -211,6 +211,17 @@
211
211
  --space-8: 4rem; /* page section */
212
212
  --space-9: 6rem; /* hero rhythm */
213
213
 
214
+ /* T-shirt aliases - var() references into this theme's numbered scale,
215
+ so re-tuning a numbered step re-tunes its alias automatically. */
216
+ --space-xs: var(--space-1);
217
+ --space-sm: var(--space-2);
218
+ --space-md: var(--space-4);
219
+ --space-lg: var(--space-5);
220
+ --space-xl: var(--space-6);
221
+ --space-2xl: var(--space-7);
222
+ --space-3xl: var(--space-8);
223
+ --space-4xl: var(--space-9);
224
+
214
225
  --radius-sm: var(--r-sm); --radius-md: var(--r-md); --radius-lg: var(--r-lg);
215
226
  --radius-xl: 0.75rem; --radius-full: 9999px;
216
227
  --font-primary: var(--font-sans);
@@ -232,6 +232,17 @@
232
232
  --space-8: 4rem; /* page section */
233
233
  --space-9: 6rem; /* hero rhythm */
234
234
 
235
+ /* T-shirt aliases - var() references into this theme's numbered scale,
236
+ so re-tuning a numbered step re-tunes its alias automatically. */
237
+ --space-xs: var(--space-1);
238
+ --space-sm: var(--space-2);
239
+ --space-md: var(--space-4);
240
+ --space-lg: var(--space-5);
241
+ --space-xl: var(--space-6);
242
+ --space-2xl: var(--space-7);
243
+ --space-3xl: var(--space-8);
244
+ --space-4xl: var(--space-9);
245
+
235
246
 
236
247
 
237
248