@echodial/deck 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 (93) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1327 -0
  3. package/bin/deck.mjs +219 -0
  4. package/build.mjs +338 -0
  5. package/dist/api-buckets.json +10486 -0
  6. package/dist/api.json +57896 -0
  7. package/dist/brand/deck-apple-touch-icon.png +0 -0
  8. package/dist/brand/deck-logo-dark.svg +1 -0
  9. package/dist/brand/deck-logo-light.svg +1 -0
  10. package/dist/brand/deck-logo-stacked.svg +1 -0
  11. package/dist/brand/deck-logo.svg +1 -0
  12. package/dist/brand/deck-mark.svg +7 -0
  13. package/dist/brand/deck-og.png +0 -0
  14. package/dist/collisions.json +223 -0
  15. package/dist/deck-adapters.js +482 -0
  16. package/dist/deck-adapters.min.js +23 -0
  17. package/dist/deck-extras.js +823 -0
  18. package/dist/deck-extras.min.js +5 -0
  19. package/dist/deck-icons.svg +184 -0
  20. package/dist/deck.bundle.js +2638 -0
  21. package/dist/deck.bundle.min.js +86 -0
  22. package/dist/deck.css +7904 -0
  23. package/dist/deck.esm.js +2644 -0
  24. package/dist/deck.js +1331 -0
  25. package/dist/deck.min.css +32 -0
  26. package/dist/deck.min.js +60 -0
  27. package/dist/layers/anchor.css +192 -0
  28. package/dist/layers/buttons.css +210 -0
  29. package/dist/layers/charts.css +337 -0
  30. package/dist/layers/combobox.css +248 -0
  31. package/dist/layers/components.css +868 -0
  32. package/dist/layers/container.css +199 -0
  33. package/dist/layers/datagrid.css +335 -0
  34. package/dist/layers/datepicker.css +305 -0
  35. package/dist/layers/forms.css +401 -0
  36. package/dist/layers/gradients.css +302 -0
  37. package/dist/layers/inputs.css +522 -0
  38. package/dist/layers/layers.css +87 -0
  39. package/dist/layers/layout.css +235 -0
  40. package/dist/layers/logical.css +226 -0
  41. package/dist/layers/media.css +400 -0
  42. package/dist/layers/mobile.css +245 -0
  43. package/dist/layers/motion.css +379 -0
  44. package/dist/layers/nav.css +771 -0
  45. package/dist/layers/perf.css +234 -0
  46. package/dist/layers/print.css +198 -0
  47. package/dist/layers/reset.css +103 -0
  48. package/dist/layers/space3d.css +280 -0
  49. package/dist/layers/toasts.css +201 -0
  50. package/dist/layers/tokens.css +229 -0
  51. package/dist/layers/type.css +114 -0
  52. package/dist/layers/utilities.css +241 -0
  53. package/dist/sizes.json +52 -0
  54. package/dist/usage.json +6340 -0
  55. package/package.json +94 -0
  56. package/src/00-layers.css +87 -0
  57. package/src/01-tokens.css +229 -0
  58. package/src/02-reset.css +103 -0
  59. package/src/03-type.css +114 -0
  60. package/src/04-layout.css +235 -0
  61. package/src/05-buttons.css +210 -0
  62. package/src/06-forms.css +401 -0
  63. package/src/07-components.css +868 -0
  64. package/src/08-mobile.css +245 -0
  65. package/src/09-utilities.css +241 -0
  66. package/src/10-datepicker.css +305 -0
  67. package/src/11-combobox.css +248 -0
  68. package/src/12-datagrid.css +335 -0
  69. package/src/13-toasts.css +201 -0
  70. package/src/14-charts.css +337 -0
  71. package/src/16-motion.css +379 -0
  72. package/src/18-container.css +199 -0
  73. package/src/19-logical.css +226 -0
  74. package/src/20-gradients.css +302 -0
  75. package/src/21-space3d.css +280 -0
  76. package/src/22-nav.css +771 -0
  77. package/src/23-inputs.css +522 -0
  78. package/src/24-media.css +400 -0
  79. package/src/25-anchor.css +192 -0
  80. package/src/26-perf.css +234 -0
  81. package/src/99-print.css +198 -0
  82. package/src/brand/deck-apple-touch-icon.png +0 -0
  83. package/src/brand/deck-logo-dark.svg +1 -0
  84. package/src/brand/deck-logo-light.svg +1 -0
  85. package/src/brand/deck-logo-stacked.svg +1 -0
  86. package/src/brand/deck-logo.svg +1 -0
  87. package/src/brand/deck-mark.svg +7 -0
  88. package/src/brand/deck-og.png +0 -0
  89. package/src/brand/sources.json +7 -0
  90. package/src/deck-icons.svg +184 -0
  91. package/src/js/deck-adapters.js +482 -0
  92. package/src/js/deck-extras.js +823 -0
  93. package/src/js/deck.js +1331 -0
@@ -0,0 +1,245 @@
1
+ /* ==========================================================================
2
+ Deck — 08 Mobile
3
+ The parts Tailwind makes you build yourself every time.
4
+ ========================================================================== */
5
+
6
+ @layer deck.mobile {
7
+
8
+ /* --- Bottom sheet -------------------------------------------------------
9
+ <dialog class="sheet"> on a phone, a centred modal from 40rem up.
10
+ ---------------------------------------------------------------------- */
11
+ .sheet {
12
+ inline-size: 100%;
13
+ max-inline-size: 100%;
14
+ max-block-size: 88dvh;
15
+ margin: 0;
16
+ margin-block-start: auto;
17
+ padding: 0;
18
+ border: 0;
19
+ border-start-start-radius: var(--r-lg);
20
+ border-start-end-radius: var(--r-lg);
21
+ background: var(--surface);
22
+ color: var(--text);
23
+ box-shadow: var(--shadow-4);
24
+ overflow: clip;
25
+ translate: 0 100%;
26
+ transition: translate var(--dur-3) var(--ease-out),
27
+ display var(--dur-3) allow-discrete,
28
+ overlay var(--dur-3) allow-discrete;
29
+ }
30
+ .sheet[open] { translate: 0; }
31
+ @starting-style { .sheet[open] { translate: 0 100%; } }
32
+
33
+ .sheet::backdrop {
34
+ background: oklch(18% .02 var(--hue-neutral) / .5);
35
+ opacity: 0;
36
+ transition: opacity var(--dur-3) var(--ease-out),
37
+ display var(--dur-3) allow-discrete,
38
+ overlay var(--dur-3) allow-discrete;
39
+ }
40
+ .sheet[open]::backdrop { opacity: 1; }
41
+ @starting-style { .sheet[open]::backdrop { opacity: 0; } }
42
+
43
+ /* The drag handle at the top of a bottom sheet. Deck draws it and does not
44
+ implement the drag — swiping down does nothing — so always ship a real
45
+ close button as well. */
46
+ .sheet-grip {
47
+ inline-size: 38px;
48
+ block-size: 4px;
49
+ border-radius: var(--r-full);
50
+ background: var(--ink-300);
51
+ margin: var(--space-3) auto var(--space-1);
52
+ }
53
+ /* The title row of a sheet. */
54
+ .sheet-header { padding: var(--space-3) var(--space-5); display: flex; align-items: center; gap: var(--space-3); }
55
+ /* The sheet's heading. Point aria-labelledby at it. */
56
+ .sheet-title { font-size: var(--text-md); font-weight: 640; }
57
+ /* The scrolling region. Pads for the home indicator, and contains its
58
+ overscroll so reaching the end does not scroll the page behind. */
59
+ .sheet-body {
60
+ padding: var(--space-2) var(--space-5) calc(var(--space-6) + env(safe-area-inset-bottom));
61
+ overflow-y: auto;
62
+ overscroll-behavior: contain;
63
+ display: flex;
64
+ flex-direction: column;
65
+ gap: var(--space-4);
66
+ }
67
+
68
+ @media (min-width: 40rem) {
69
+ .sheet {
70
+ inline-size: min(30rem, calc(100vw - var(--space-8)));
71
+ margin: auto;
72
+ border-radius: var(--r-lg);
73
+ translate: 0;
74
+ opacity: 0;
75
+ scale: .97;
76
+ transition: opacity var(--dur-2) var(--ease-out), scale var(--dur-2) var(--ease-spring),
77
+ display var(--dur-2) allow-discrete, overlay var(--dur-2) allow-discrete;
78
+ }
79
+ .sheet[open] { opacity: 1; scale: 1; }
80
+ @starting-style { .sheet[open] { opacity: 0; scale: .97; } }
81
+ }
82
+
83
+ /* --- Bottom tab bar ----------------------------------------------------- */
84
+ .tabbar {
85
+ position: fixed;
86
+ inset-inline: 0;
87
+ inset-block-end: 0;
88
+ z-index: var(--z-nav);
89
+ display: flex;
90
+ background: color-mix(in oklab, var(--surface) 88%, transparent);
91
+ backdrop-filter: saturate(1.8) blur(16px);
92
+ -webkit-backdrop-filter: saturate(1.8) blur(16px);
93
+ border-block-start: 1px solid var(--line);
94
+ padding-block-end: env(safe-area-inset-bottom);
95
+ }
96
+ @media (min-width: 48rem) { .tabbar { display: none; } }
97
+
98
+ .tabbar-item {
99
+ flex: 1 1 0;
100
+ min-block-size: var(--tap);
101
+ padding-block: var(--space-2);
102
+ display: flex;
103
+ flex-direction: column;
104
+ align-items: center;
105
+ justify-content: center;
106
+ gap: 3px;
107
+ color: var(--text-faint);
108
+ font-size: var(--text-2xs);
109
+ font-weight: 560;
110
+ text-decoration: none;
111
+ -webkit-tap-highlight-color: transparent;
112
+ transition: color var(--dur-1) var(--ease-out);
113
+ }
114
+ .tabbar-item[aria-current] { color: var(--brand); }
115
+ .tabbar-item[aria-current] .icon { scale: 1.06; }
116
+ .tabbar-item .icon { transition: scale var(--dur-2) var(--ease-spring); }
117
+
118
+ /* Give the page room so the tab bar never covers the last row */
119
+ body:has(.tabbar) { padding-block-end: calc(var(--tap) + var(--space-4) + env(safe-area-inset-bottom)); }
120
+ @media (min-width: 48rem) { body:has(.tabbar) { padding-block-end: 0; } }
121
+
122
+ /* --- Safe area helpers --------------------------------------------------- */
123
+ .safe-top { padding-block-start: env(safe-area-inset-top); }
124
+ .safe-bottom { padding-block-end: env(safe-area-inset-bottom); }
125
+ .safe-x { padding-inline: max(var(--space-gutter), env(safe-area-inset-left)) max(var(--space-gutter), env(safe-area-inset-right)); }
126
+
127
+ /* --- Icons --------------------------------------------------------------
128
+ <svg class="icon"><use href="deck-icons.svg#check"></use></svg>
129
+ Icons inherit color and font-size, so they line up with text by default.
130
+ ---------------------------------------------------------------------- */
131
+ /* An SVG icon sized in em, so it scales with the text it sits beside and
132
+ lands on the baseline. Icons are filled with currentColor and inherit
133
+ the surrounding colour. */
134
+ .icon {
135
+ inline-size: 1.25em;
136
+ block-size: 1.25em;
137
+ flex: 0 0 auto;
138
+ fill: none;
139
+ stroke: currentColor;
140
+ stroke-width: 1.75;
141
+ stroke-linecap: round;
142
+ stroke-linejoin: round;
143
+ vertical-align: -.22em;
144
+ }
145
+ /* Small icons reference the heavier cut of the sprite, not a thicker stroke:
146
+ the symbols are filled outlines, so stroke-width does nothing to them.
147
+ Every icon ships twice, #name at wght 400 and #name-sm at wght 500, and
148
+ .icon-sm goes with the -sm symbol. CSS cannot rewrite a <use href>, so the
149
+ pairing lives in the markup:
150
+ <svg class="icon icon-sm"><use href="deck-icons.svg#check-sm"></use></svg> */
151
+ .icon-sm { inline-size: 1em; block-size: 1em; }
152
+ /* A 1.6em icon, for icon tiles and empty states where the default would
153
+ look undersized. */
154
+ .icon-lg { inline-size: 1.6em; block-size: 1.6em; stroke-width: 1.6; }
155
+ .icon-xl { inline-size: 2.25em; block-size: 2.25em; stroke-width: 1.4; }
156
+ .icon-fill { fill: currentColor; stroke: none; }
157
+ .icon-muted { color: var(--text-faint); }
158
+ .icon-spin { animation: dk-spin 1.1s linear infinite; }
159
+
160
+ /* Icon in a tinted tile — for feature rows and empty states */
161
+ .icon-tile {
162
+ inline-size: 40px;
163
+ block-size: 40px;
164
+ border-radius: var(--r-sm);
165
+ display: grid;
166
+ place-items: center;
167
+ background: var(--brand-soft);
168
+ color: var(--brand);
169
+ flex: 0 0 auto;
170
+ }
171
+ .icon-tile-good { background: var(--good-100); color: var(--good-700); }
172
+ .icon-tile-warn { background: var(--warn-100); color: var(--warn-700); }
173
+ .icon-tile-bad { background: var(--bad-100); color: var(--bad-700); }
174
+ .icon-tile-lg { inline-size: 52px; block-size: 52px; border-radius: var(--r-md); }
175
+
176
+ /* --- Emoji --------------------------------------------------------------
177
+ Emoji render at wildly different sizes and baselines across platforms.
178
+ .emoji pins the font stack and the metrics so they sit on the line.
179
+ ---------------------------------------------------------------------- */
180
+ /* Pins the emoji font stack and metrics so an emoji renders at the same
181
+ size and baseline on Windows, iOS and Android instead of jumping
182
+ between them. */
183
+ .emoji {
184
+ font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji",
185
+ "Twemoji Mozilla", "Android Emoji", sans-serif;
186
+ font-size: 1.05em;
187
+ line-height: 1;
188
+ font-style: normal;
189
+ font-weight: 400;
190
+ vertical-align: -.12em;
191
+ display: inline-block;
192
+ text-rendering: auto;
193
+ -webkit-font-smoothing: auto;
194
+ }
195
+ .emoji-lg { font-size: 1.6em; vertical-align: -.2em; }
196
+ .emoji-xl { font-size: 2.5em; vertical-align: -.24em; }
197
+ .emoji-hero { font-size: 3.5rem; line-height: 1; }
198
+
199
+ /* Emoji as an avatar or a status marker */
200
+ .emoji-tile {
201
+ inline-size: 40px;
202
+ block-size: 40px;
203
+ border-radius: var(--r-sm);
204
+ background: var(--surface-2);
205
+ border: 1px solid var(--line);
206
+ display: grid;
207
+ place-items: center;
208
+ font-size: 20px;
209
+ flex: 0 0 auto;
210
+ }
211
+ .emoji-tile-round { border-radius: var(--r-full); }
212
+
213
+ /* Emoji picker grid — drop your own set in */
214
+ .emoji-grid {
215
+ display: grid;
216
+ grid-template-columns: repeat(auto-fill, minmax(40px, 1fr));
217
+ gap: 2px;
218
+ }
219
+ .emoji-grid > button {
220
+ aspect-ratio: 1;
221
+ border-radius: var(--r-xs);
222
+ font-size: 21px;
223
+ line-height: 1;
224
+ cursor: pointer;
225
+ transition: background-color var(--dur-1) var(--ease-out), scale var(--dur-1) var(--ease-spring);
226
+ }
227
+ .emoji-grid > button:hover { background: var(--surface-hover); scale: 1.16; }
228
+
229
+ /* Reaction pill, like a Slack or Teams reaction */
230
+ .reaction {
231
+ display: inline-flex;
232
+ align-items: center;
233
+ gap: var(--space-1);
234
+ min-block-size: 28px;
235
+ padding-inline: var(--space-2);
236
+ border-radius: var(--r-full);
237
+ border: 1px solid var(--line);
238
+ background: var(--surface);
239
+ font-size: var(--text-xs);
240
+ font-variant-numeric: tabular-nums;
241
+ color: var(--text-muted);
242
+ cursor: pointer;
243
+ }
244
+ .reaction[aria-pressed="true"] { background: var(--brand-soft); border-color: var(--brand-300); color: var(--brand-soft-text); }
245
+ }
@@ -0,0 +1,241 @@
1
+ /* ==========================================================================
2
+ Deck — 09 Utilities
3
+ A short list on purpose. Utilities are for the last 10 percent of a layout,
4
+ not for rebuilding a button out of fourteen class names.
5
+ ========================================================================== */
6
+
7
+ @layer deck.utilities {
8
+
9
+ /* --- Display ------------------------------------------------------------ */
10
+ .hidden { display: none; }
11
+ .block { display: block; }
12
+ .inline-block { display: inline-block; }
13
+ .flex { display: flex; }
14
+ .inline-flex { display: inline-flex; }
15
+ .contents { display: contents; }
16
+
17
+ /* --- Flex and grid ------------------------------------------------------ */
18
+ .flex-row { flex-direction: row; }
19
+ .flex-col { flex-direction: column; }
20
+ .wrap { flex-wrap: wrap; }
21
+ .nowrap { flex-wrap: nowrap; white-space: nowrap; }
22
+ .items-start { align-items: flex-start; }
23
+ .items-center { align-items: center; }
24
+ .items-end { align-items: flex-end; }
25
+ .items-stretch { align-items: stretch; }
26
+ .items-baseline { align-items: baseline; }
27
+ .justify-start { justify-content: flex-start; }
28
+ .justify-center { justify-content: center; }
29
+ .justify-end { justify-content: flex-end; }
30
+ .justify-between { justify-content: space-between; }
31
+ .place-center { place-items: center; }
32
+ .grow { flex: 1 1 auto; min-inline-size: 0; }
33
+ .shrink-0 { flex: 0 0 auto; }
34
+ /* Pushes this element and everything after it to the far end of a flex
35
+ row. The one-class replacement for a spacer div. */
36
+ .push { margin-inline-start: auto; }
37
+
38
+ .gap-0 { gap: 0; }
39
+ .gap-1 { gap: var(--space-1); }
40
+ .gap-2 { gap: var(--space-2); }
41
+ .gap-3 { gap: var(--space-3); }
42
+ .gap-4 { gap: var(--space-4); }
43
+ .gap-6 { gap: var(--space-6); }
44
+ .gap-8 { gap: var(--space-8); }
45
+
46
+ /* --- Spacing ------------------------------------------------------------ */
47
+ /* The scale is 0 1 2 3 4 6 8, declared in 04-layout.css. Every family below
48
+ implements all seven, so a step that exists anywhere exists everywhere. */
49
+ .p-0 { padding: 0; } .p-1 { padding: var(--space-1); }
50
+ .p-2 { padding: var(--space-2); } .p-3 { padding: var(--space-3); }
51
+ .p-4 { padding: var(--space-4); } .p-6 { padding: var(--space-6); }
52
+ .p-8 { padding: var(--space-8); }
53
+
54
+ .px-0 { padding-inline: 0; } .px-1 { padding-inline: var(--space-1); }
55
+ .px-2 { padding-inline: var(--space-2); } .px-3 { padding-inline: var(--space-3); }
56
+ .px-4 { padding-inline: var(--space-4); } .px-6 { padding-inline: var(--space-6); }
57
+ .px-8 { padding-inline: var(--space-8); }
58
+
59
+ .py-0 { padding-block: 0; } .py-1 { padding-block: var(--space-1); }
60
+ .py-2 { padding-block: var(--space-2); } .py-3 { padding-block: var(--space-3); }
61
+ .py-4 { padding-block: var(--space-4); } .py-6 { padding-block: var(--space-6); }
62
+ .py-8 { padding-block: var(--space-8); }
63
+
64
+ .m-0 { margin: 0; }
65
+ .mt-0 { margin-block-start: 0; } .mt-1 { margin-block-start: var(--space-1); }
66
+ .mt-2 { margin-block-start: var(--space-2); } .mt-3 { margin-block-start: var(--space-3); }
67
+ .mt-4 { margin-block-start: var(--space-4); } .mt-6 { margin-block-start: var(--space-6); }
68
+ .mt-8 { margin-block-start: var(--space-8); }
69
+ .mb-0 { margin-block-end: 0; } .mb-1 { margin-block-end: var(--space-1); }
70
+ .mb-2 { margin-block-end: var(--space-2); } .mb-3 { margin-block-end: var(--space-3); }
71
+ .mb-4 { margin-block-end: var(--space-4); } .mb-6 { margin-block-end: var(--space-6); }
72
+ .mb-8 { margin-block-end: var(--space-8); }
73
+ .mx-auto { margin-inline: auto; }
74
+
75
+ /* --- Sizing ------------------------------------------------------------- */
76
+ .w-full { inline-size: 100%; }
77
+ .w-auto { inline-size: auto; }
78
+ .h-full { block-size: 100%; }
79
+ .min-h-screen { min-block-size: 100dvh; }
80
+ .max-w-prose { max-inline-size: var(--measure); }
81
+ .max-w-sm { max-inline-size: 24rem; }
82
+ .max-w-md { max-inline-size: 34rem; }
83
+ .max-w-lg { max-inline-size: 48rem; }
84
+ .square { aspect-ratio: 1; }
85
+
86
+ /* --- Type --------------------------------------------------------------- */
87
+ .text-2xs { font-size: var(--text-2xs); }
88
+ .text-xs { font-size: var(--text-xs); }
89
+ /* One step down the type scale, for secondary text and dense rows. */
90
+ .text-sm { font-size: var(--text-sm); }
91
+ .text-base { font-size: var(--text-base); }
92
+ .text-md { font-size: var(--text-md); }
93
+ .text-lg { font-size: var(--text-lg); }
94
+ .text-xl { font-size: var(--text-xl); }
95
+ .text-2xl { font-size: var(--text-2xl); }
96
+
97
+ .fw-normal { font-weight: 400; }
98
+ .fw-medium { font-weight: 540; }
99
+ /* Semibold. The weight for a label or a name that needs to lead without
100
+ becoming a heading. */
101
+ .fw-semi { font-weight: 620; }
102
+ .fw-bold { font-weight: 700; }
103
+
104
+ .text-start { text-align: start; }
105
+ .text-center { text-align: center; }
106
+ .text-end { text-align: end; }
107
+
108
+ /* Secondary text colour. Still meets contrast against every surface Deck
109
+ defines, so it is safe for body copy rather than decoration only. */
110
+ .text-muted { color: var(--text-muted); }
111
+ .text-faint { color: var(--text-faint); }
112
+ .text-brand { color: var(--brand); }
113
+ .text-good { color: var(--good-700); }
114
+ .text-warn { color: var(--warn-700); }
115
+ .text-bad { color: var(--bad-700); }
116
+ .text-inherit { color: inherit; }
117
+
118
+ /* Tabular figures, so numbers line up in a column and do not jitter when
119
+ they change. */
120
+ .nums { font-variant-numeric: tabular-nums; }
121
+ .mono { font-family: var(--font-mono); }
122
+ .uppercase { text-transform: uppercase; letter-spacing: .04em; }
123
+ .capitalize { text-transform: capitalize; }
124
+ .no-underline { text-decoration: none; }
125
+
126
+ .truncate {
127
+ overflow: hidden;
128
+ text-overflow: ellipsis;
129
+ white-space: nowrap;
130
+ min-inline-size: 0;
131
+ }
132
+ .clamp-2, .clamp-3 {
133
+ display: -webkit-box;
134
+ -webkit-box-orient: vertical;
135
+ overflow: hidden;
136
+ }
137
+ .clamp-2 { -webkit-line-clamp: 2; line-clamp: 2; }
138
+ .clamp-3 { -webkit-line-clamp: 3; line-clamp: 3; }
139
+
140
+ /* --- Surfaces ----------------------------------------------------------- */
141
+ .bg-surface { background: var(--surface); }
142
+ .bg-sunken { background: var(--bg-sunken); }
143
+ .bg-brand { background: var(--brand-600); color: var(--text-on-brand); }
144
+ .bg-soft { background: var(--brand-soft); color: var(--brand-soft-text); }
145
+ .bg-none { background: none; }
146
+
147
+ .border { border: 1px solid var(--line); }
148
+ .border-t { border-block-start: 1px solid var(--line); }
149
+ .border-b { border-block-end: 1px solid var(--line); }
150
+ .border-brand { border-color: var(--brand-400); }
151
+ .border-0 { border: 0; }
152
+
153
+ .r-xs { border-radius: var(--r-xs); }
154
+ .r-sm { border-radius: var(--r-sm); }
155
+ .r-md { border-radius: var(--r-md); }
156
+ .r-lg { border-radius: var(--r-lg); }
157
+ .r-full { border-radius: var(--r-full); }
158
+
159
+ .shadow-0 { box-shadow: none; }
160
+ .shadow-1 { box-shadow: var(--shadow-1); }
161
+ .shadow-2 { box-shadow: var(--shadow-2); }
162
+ .shadow-3 { box-shadow: var(--shadow-3); }
163
+ .shadow-4 { box-shadow: var(--shadow-4); }
164
+
165
+ /* --- Position and overflow ---------------------------------------------- */
166
+ .relative { position: relative; }
167
+ .absolute { position: absolute; }
168
+ .fixed { position: fixed; }
169
+ .sticky { position: sticky; }
170
+ .inset-0 { inset: 0; }
171
+ .z-1 { z-index: 1; }
172
+ .overflow-hidden { overflow: hidden; }
173
+ .overflow-auto { overflow: auto; }
174
+ .overflow-clip { overflow: clip; }
175
+
176
+ .opacity-60 { opacity: .6; }
177
+ .pointer-none { pointer-events: none; }
178
+ .no-select { user-select: none; }
179
+ .cursor-pointer { cursor: pointer; }
180
+
181
+ /* --- Accessibility ------------------------------------------------------ */
182
+ .sr-only {
183
+ position: absolute;
184
+ inline-size: 1px;
185
+ block-size: 1px;
186
+ padding: 0;
187
+ margin: -1px;
188
+ overflow: hidden;
189
+ clip-path: inset(50%);
190
+ white-space: nowrap;
191
+ border: 0;
192
+ }
193
+ .skip-link {
194
+ position: absolute;
195
+ inset-block-start: -100%;
196
+ inset-inline-start: var(--space-4);
197
+ z-index: var(--z-toast);
198
+ background: var(--brand-600);
199
+ color: var(--text-on-brand);
200
+ padding: var(--space-3) var(--space-4);
201
+ border-radius: var(--r-sm);
202
+ }
203
+ .skip-link:focus { inset-block-start: var(--space-4); }
204
+
205
+ /* --- Responsive variants (mobile first: these turn ON at the breakpoint) - */
206
+ @media (min-width: 40rem) {
207
+ .sm\:hidden { display: none; }
208
+ .sm\:block { display: block; }
209
+ .sm\:flex { display: flex; }
210
+ .sm\:row { flex-direction: row; }
211
+ .sm\:w-auto { inline-size: auto; }
212
+ .sm\:text-start { text-align: start; }
213
+ }
214
+ @media (min-width: 48rem) {
215
+ .md\:hidden { display: none; }
216
+ .md\:block { display: block; }
217
+ .md\:flex { display: flex; }
218
+ .md\:grid-d { display: grid; }
219
+ .md\:row { flex-direction: row; }
220
+ .md\:col { flex-direction: column; }
221
+ .md\:items-center { align-items: center; }
222
+ .md\:justify-between { justify-content: space-between; }
223
+ .md\:w-auto { inline-size: auto; }
224
+ .md\:text-center { text-align: center; }
225
+ .md\:p-8 { padding: var(--space-8); }
226
+ .md\:gap-6 { gap: var(--space-6); }
227
+ }
228
+ @media (min-width: 64rem) {
229
+ .lg\:hidden { display: none; }
230
+ .lg\:block { display: block; }
231
+ .lg\:flex { display: flex; }
232
+ .lg\:grid-d { display: grid; }
233
+ .lg\:row { flex-direction: row; }
234
+ .lg\:gap-8 { gap: var(--space-8); }
235
+ }
236
+
237
+ /* Show only to one input type */
238
+ @media (pointer: fine) { .touch-only { display: none; } }
239
+ @media (pointer: coarse) { .mouse-only { display: none; } }
240
+ @media print { .no-print { display: none !important; } }
241
+ }