clampography 2.0.0-beta.3 → 2.0.0-beta.30

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.
package/src/base.js CHANGED
@@ -1,432 +1,632 @@
1
- /**
2
- * Base typography and layout styles (structure only, no colors).
3
- * Converted from base.css.
4
- */
5
- export default {
6
- // Global CSS Variables (Spacing & Fonts)
7
- "@layer base": {
8
- ":root": {
9
- "--spacing-sm": "clamp(0.75rem, 0.5625rem + 0.9375vw, 1.25rem)",
10
- "--spacing-md": "clamp(1rem, 0.75rem + 1.25vw, 1.5rem)",
11
- "--spacing-lg": "clamp(1.5rem, 1.125rem + 1.875vw, 2.5rem)",
12
- "--spacing-xl": "clamp(2rem, 1.5rem + 2.5vw, 3rem)",
1
+ export default (options = {}) => {
2
+ const root = options.root || ":root";
3
+
4
+ // Helper to scope selectors safely (ignoring commas inside parentheses)
5
+ const scope = (selector) => {
6
+ const parts = [];
7
+ let current = "";
8
+ let depth = 0;
9
+
10
+ for (let i = 0; i < selector.length; i++) {
11
+ const char = selector[i];
12
+ if (char === "(") depth++;
13
+ if (char === ")") depth--;
14
+
15
+ if (char === "," && depth === 0) {
16
+ parts.push(current.trim());
17
+ current = "";
18
+ } else {
19
+ current += char;
20
+ }
21
+ }
22
+ parts.push(current.trim());
23
+
24
+ const typographyPrefix = options.typography && options.typography !== "global" ? ` ${options.typography}` : "";
25
+
26
+ return parts
27
+ .filter(Boolean) // Remove empty strings
28
+ .map((part) => {
29
+ if (part === ":root" || part === "body") return root;
30
+
31
+ // Apply typography scope isolation if configured
32
+ if (typographyPrefix) {
33
+ return `${root}${typographyPrefix} ${part}`;
34
+ }
35
+
36
+ // Avoid double spacing
37
+ return `${root} ${part}`;
38
+ })
39
+ .join(", ");
40
+ };
41
+
42
+ // Fluid math engine: Generates mathematically perfect clamp() strings
43
+ // dynamically based on the configured min and max screen sizes.
44
+ const minScreenRem = (options.fluidMin || 320) / 16;
45
+ const maxScreenRem = (options.fluidMax || 1280) / 16;
46
+
47
+ const makeFluid = (minRem, maxRem) => {
48
+ // If min and max are the same, or if we have invalid screens, just return the static value
49
+ if (minRem === maxRem || minScreenRem >= maxScreenRem) return `${minRem}rem`;
50
+
51
+ const slope = (maxRem - minRem) / (maxScreenRem - minScreenRem);
52
+ const intersection = minRem - slope * minScreenRem;
53
+
54
+ const format = (num) => parseFloat(num.toFixed(4));
55
+
56
+ return `clamp(${minRem}rem, ${format(intersection)}rem + ${format(slope * 100)}vw, ${maxRem}rem)`;
57
+ };
58
+
59
+ return {
60
+ // ROOT CONFIGURATION (CSS variables)
61
+ // Uses :where() for zero specificity so user overrides always win regardless of layer/source order
62
+ [`:where(${root})`]: {
63
+ // FLUID SPACING SYSTEM
64
+ "--spacing-xs": makeFluid(0.25, 0.75),
65
+ "--spacing-sm": makeFluid(0.375, 1.25),
66
+ "--spacing-md": makeFluid(0.5, 1.5),
67
+ "--spacing-lg": makeFluid(0.75, 2.5),
68
+ "--spacing-xl": makeFluid(1, 3),
69
+ "--list-indent": makeFluid(1.5, 2),
13
70
  "--scroll-offset": "5rem",
14
71
  "--font-family-base":
15
- "system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif",
72
+ "Inter, system-ui, -apple-system, 'Segoe UI Variable Display', 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif",
16
73
  "--font-family-mono":
17
- "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace",
18
- },
19
- },
20
-
21
- // Body Structure
22
- "body": {
23
- "font-family": "var(--font-family-base)",
24
- "font-size": "clamp(1rem, 0.95rem + 0.25vw, 1.125rem)",
25
- "line-height": "1.75",
26
- "text-rendering": "optimizeLegibility",
27
- "-webkit-font-smoothing": "antialiased",
28
- "-moz-osx-font-smoothing": "grayscale",
29
- "text-wrap": "pretty",
30
- },
31
-
32
- // Headings Structure
33
- ":where(h1, h2, h3, h4, h5, h6)": {
34
- "font-weight": "700",
35
- "scroll-margin-top": "var(--scroll-offset)",
36
- "font-size": "1rem",
37
- "line-height": "1.5",
38
- "margin-top": "0",
39
- "margin-bottom": "var(--spacing-xs)",
40
- "text-decoration": "none",
41
- "break-after": "avoid",
42
- },
43
-
44
- "h1": {
45
- "font-size": "clamp(2.25rem, 1.95rem + 1.5vw, 3rem)",
46
- "line-height": "1.1111",
47
- "font-weight": "800",
48
- "margin-top": "0",
49
- "margin-bottom": "var(--spacing-xl)",
50
- },
51
-
52
- "h6": {
53
- "font-size": "0.875rem",
54
- "line-height": "1.5",
55
- "margin-top": "0",
56
- "margin-bottom": "var(--spacing-xs)",
57
- },
58
-
59
- // Links
60
- "a": {
61
- "text-decoration-line": "underline",
62
- "text-decoration-thickness": "0.0625em",
63
- "text-underline-offset": "0.15em",
64
- "cursor": "pointer",
65
- "text-decoration": "underline",
66
- },
67
-
68
- ":where(h1, h2, h3, h4, h5, h6) a": {
69
- "text-decoration": "none",
70
- },
71
-
72
- // Lists & Menus
73
- "menu": {
74
- "list-style": "none",
75
- "margin-bottom": "var(--spacing-md)",
76
- "padding-left": "0",
77
- },
78
-
79
- "menu > li::before": {
80
- "display": "none",
81
- },
82
-
83
- "hgroup": {
84
- "margin-bottom": "var(--spacing-lg)",
85
- },
86
-
87
- "hgroup :where(h1, h2, h3, h4, h5, h6)": {
88
- "margin-bottom": "var(--spacing-xs)",
89
- },
90
-
91
- "hgroup :where(p)": {
92
- "margin-top": "0",
93
- "margin-bottom": "0",
94
- "font-size": "0.875em",
95
- "font-weight": "400",
96
- "line-height": "1.5",
97
- },
98
-
99
- "p": {
100
- "line-height": "1.75",
101
- "margin-bottom": "var(--spacing-md)",
102
- "margin-top": "0",
103
- },
104
-
105
- // Inline elements
106
- ":where(strong, b)": {
107
- "font-weight": "700",
108
- },
109
-
110
- ":where(em, i, cite, var)": {
111
- "font-style": "italic",
112
- },
113
-
114
- "dfn": {
115
- "font-style": "normal",
116
- "font-weight": "600",
117
- },
118
-
119
- "small": {
120
- "font-size": "0.875em",
121
- "line-height": "1.5",
122
- },
123
-
124
- ":where(code, kbd, samp)": {
125
- "font-family": "var(--font-family-mono)",
126
- "padding":
127
- "clamp(0.0625rem, 0.05rem + 0.0625vw, 0.125rem) clamp(0.1875rem, 0.15rem + 0.1875vw, 0.3125rem)",
128
- },
129
-
130
- ":where(code:not(pre code))": {
131
- "padding":
132
- "clamp(0.0625rem, 0.05rem + 0.0625vw, 0.125rem) clamp(0.1875rem, 0.15rem + 0.1875vw, 0.3125rem)",
133
- },
134
-
135
- ":where(sub, sup)": {
136
- "font-size": "0.75em",
137
- "line-height": "0",
138
- "position": "relative",
139
- "vertical-align": "baseline",
140
- },
141
-
142
- "sup": {
143
- "top": "-0.5em",
144
- },
145
-
146
- "sub": {
147
- "bottom": "-0.25em",
148
- },
149
-
150
- "abbr[title]": {
151
- "text-decoration": "underline dotted",
152
- "cursor": "help",
153
- },
154
-
155
- "del": {
156
- "text-decoration": "line-through",
157
- },
158
-
159
- "ins": {
160
- "text-decoration": "underline",
161
- },
162
-
163
- "s": {
164
- "text-decoration": "line-through",
165
- },
166
-
167
- "u": {
168
- "text-decoration": "underline",
169
- },
170
-
171
- "mark": {
172
- "font-style": "normal",
173
- "font-weight": "inherit",
174
- },
175
-
176
- "address": {
177
- "font-style": "normal",
178
- "margin-top": "var(--spacing-md)",
179
- "margin-bottom": "var(--spacing-md)",
180
- },
181
-
182
- "time": {
183
- "font-style": "normal",
184
- "font-variant-numeric": "tabular-nums",
185
- },
186
-
187
- // Blockquotes
188
- "blockquote": {
189
- "margin-top": "0",
190
- "margin-bottom": "0",
191
- "padding-left": "var(--spacing-md)",
192
- },
193
-
194
- "blockquote blockquote": {
195
- "margin-top": "var(--spacing-sm)",
196
- "margin-bottom": "var(--spacing-sm)",
197
- "padding-left": "var(--spacing-sm)",
198
- },
199
-
200
- "q": {
201
- "font-style": "inherit",
202
- },
203
-
204
- // Lists
205
- ":where(ul, ol)": {
206
- "list-style": "none",
207
- "margin-bottom": "0",
208
- "padding-left": "var(--spacing-md)",
209
- "margin-top": "var(--spacing-xs)",
210
- },
211
-
212
- "li": {
213
- "position": "relative",
214
- "padding-left": "0.375em",
215
- },
216
-
217
- "li + li": {
218
- "margin-top": "var(--spacing-xs)",
219
- },
220
-
221
- "li > :where(ul, ol):first-child": {
222
- "margin-top": "var(--spacing-xs)",
223
- },
224
-
225
- "ul > li::before": {
226
- "content": "''",
227
- "position": "absolute",
228
- "left": "-1.125em",
229
- "top": "calc(0.875em - 0.1875em)",
230
- "width": "0.375em",
231
- "height": "0.375em",
232
- "border-radius": "50%",
233
- },
234
-
235
- "ol": {
236
- "counter-reset": "list-counter",
237
- "margin-top": "0",
238
- "margin-bottom": "0",
239
- },
240
-
241
- "ol > li": {
242
- "counter-increment": "list-counter",
243
- },
244
-
245
- "ol > li::before": {
246
- "content": "counter(list-counter) '.'",
247
- "position": "absolute",
248
- "left": "-2.5em",
249
- "width": "1.75em",
250
- "text-align": "right",
251
- "font-weight": "600",
252
- },
253
-
254
- ":where(ul, ol) :where(ul, ol)": {
255
- "margin-bottom": "0",
256
- "padding-left": "var(--spacing-md)",
257
- },
258
-
259
- "dl": {
260
- "margin-top": "0",
261
- "margin-bottom": "0",
262
- },
263
-
264
- "dt": {
265
- "font-weight": "600",
266
- "margin-top": "var(--spacing-sm)",
267
- },
268
-
269
- "dt:first-child": {
270
- "margin-top": "0",
271
- },
272
-
273
- "dd": {
274
- "margin-left": "var(--spacing-md)",
275
- },
276
-
277
- "dt + dd": {
278
- "margin-top": "var(--spacing-xs)",
279
- },
280
-
281
- "dd + dd": {
282
- "margin-top": "var(--spacing-xs)",
283
- },
284
-
285
- "dd:last-child": {
286
- "margin-bottom": "0",
287
- },
288
-
289
- // Pre / Code
290
- "pre": {
291
- "margin-top": "var(--spacing-md)",
292
- "margin-bottom": "var(--spacing-md)",
293
- "font-family": "var(--font-family-mono)",
294
- "line-height": "1.6",
295
- "overflow-x": "auto",
296
- "break-inside": "avoid",
297
- },
298
-
299
- "pre code": {
300
- "font-size": "inherit",
301
- "padding": "0",
302
- "border-radius": "0",
303
- },
304
-
305
- // Fieldset & Form
306
- "fieldset": {
307
- "margin-top": "var(--spacing-md)",
308
- "margin-bottom": "var(--spacing-md)",
309
- "padding": "var(--spacing-md)",
310
- "border": "0",
311
- },
312
-
313
- "legend": {
314
- "font-weight": "600",
315
- "padding": "0 var(--spacing-xs)",
316
- },
317
-
318
- "output": {
319
- "display": "inline-block",
320
- "font-variant-numeric": "tabular-nums",
321
- },
322
-
323
- ":where(meter, progress)": {
324
- "display": "inline-block",
325
- "vertical-align": "middle",
326
- },
327
-
328
- // Media
329
- ":where(img, video)": {
330
- "max-width": "100%",
331
- "height": "auto",
332
- "break-inside": "avoid",
333
- },
334
-
335
- "figure": {
336
- "margin-top": "0",
337
- "margin-bottom": "0",
338
- "break-inside": "avoid",
339
- },
340
-
341
- "figcaption": {
342
- "margin-top": "0.375rem",
343
- "font-size": "0.875em",
344
- "line-height": "1.5",
345
- },
346
-
347
- // Tables
348
- "table": {
349
- "width": "100%",
350
- "margin-top": "0",
351
- "margin-bottom": "0",
352
- "border-collapse": "collapse",
353
- "font-size": "0.9375em",
354
- "line-height": "1.6",
355
- },
356
-
357
- "caption": {
358
- "margin-bottom": "var(--spacing-xs)",
359
- "font-size": "0.875em",
360
- "font-weight": "600",
361
- "text-align": "left",
362
- },
363
-
364
- "th, td": {
365
- "padding": "var(--spacing-xs) var(--spacing-sm)",
366
- "text-align": "left",
367
- "font-weight": "600",
368
- },
369
-
370
- "thead th, tbody th, tbody td, tfoot th, tfoot td": {
371
- "vertical-align": "top",
372
- },
373
-
374
- "thead th": {
375
- "vertical-align": "bottom",
376
- },
377
-
378
- "tbody + tbody": {
379
- "border-top-width": "2px",
380
- },
381
-
382
- // Horizontal Rule
383
- "hr": {
384
- "margin-top": "var(--spacing-xl)",
385
- "margin-bottom": "var(--spacing-xl)",
386
- "border": "0",
387
- },
388
-
389
- // Interactive
390
- ":where(:focus, :focus-visible)": {
391
- "outline-offset": "2px",
392
- },
393
-
394
- "details": {
395
- "margin-top": "var(--spacing-md)",
396
- "margin-bottom": "var(--spacing-md)",
397
- },
398
-
399
- "summary": {
400
- "cursor": "pointer",
401
- "font-weight": "600",
402
- },
403
-
404
- "details[open] > summary": {
405
- "margin-bottom": "var(--spacing-xs)",
406
- },
407
-
408
- "dialog": {
409
- "font-size": "inherit",
410
- "line-height": "inherit",
411
- },
412
-
413
- // Resets
414
- "ul": {
415
- "margin-top": "0",
416
- "margin-bottom": "0",
417
- },
418
-
419
- ":where(p, pre):first-child": {
420
- "margin-top": "0",
421
- },
422
-
423
- ":where(p, pre):last-child": {
424
- "margin-bottom": "0",
425
- },
426
-
427
- "@media print": {
428
- "table": {
429
- "break-inside": "avoid",
430
- },
431
- },
74
+ "ui-monospace, 'Cascadia Code', 'Cascadia Mono', 'Segoe UI Mono', 'Ubuntu Mono', SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace",
75
+
76
+ // FLUID TYPOGRAPHY ENGINE — Viewport Bounds
77
+ // Unitless rem values derived from plugin options: fluid-min and fluid-max.
78
+ // e.g. 320px → 20rem, 1280px → 80rem
79
+ "--clampography-v-min": String(minScreenRem),
80
+ "--clampography-v-max": String(maxScreenRem),
81
+
82
+ // HEADINGS FLUID TYPOGRAPHY
83
+ // Each heading exposes --min and --max as unitless rem values.
84
+ // Override these in :root to change font-size bounds without rewriting the full clamp().
85
+ //
86
+ // Example — reduce H1 max size on large screens:
87
+ // :root { --clampography-h1-max: 3; }
88
+ //
89
+ // Example increase H2 minimum size on mobile:
90
+ // :root { --clampography-h2-min: 1.5; }
91
+ //
92
+ // --clampography-h*-slope and --clampography-h*-base are computed automatically via CSS calc().
93
+ // --clampography-h*-size is the final fluid clamp() value used by the heading element.
94
+
95
+ // H1
96
+ "--clampography-h1-min": "1.875",
97
+ "--clampography-h1-max": "4",
98
+ "--clampography-h1-slope": "calc((var(--clampography-h1-max) - var(--clampography-h1-min)) / (var(--clampography-v-max) - var(--clampography-v-min)))",
99
+ "--clampography-h1-base": "calc(var(--clampography-h1-min) - var(--clampography-h1-slope) * var(--clampography-v-min))",
100
+ "--clampography-h1-size": "clamp(calc(var(--clampography-h1-min) * 1rem), calc(var(--clampography-h1-base) * 1rem + var(--clampography-h1-slope) * 100vw), calc(var(--clampography-h1-max) * 1rem))",
101
+
102
+ // H2
103
+ "--clampography-h2-min": "1.25",
104
+ "--clampography-h2-max": "3",
105
+ "--clampography-h2-slope": "calc((var(--clampography-h2-max) - var(--clampography-h2-min)) / (var(--clampography-v-max) - var(--clampography-v-min)))",
106
+ "--clampography-h2-base": "calc(var(--clampography-h2-min) - var(--clampography-h2-slope) * var(--clampography-v-min))",
107
+ "--clampography-h2-size": "clamp(calc(var(--clampography-h2-min) * 1rem), calc(var(--clampography-h2-base) * 1rem + var(--clampography-h2-slope) * 100vw), calc(var(--clampography-h2-max) * 1rem))",
108
+
109
+ // H3
110
+ "--clampography-h3-min": "1.125",
111
+ "--clampography-h3-max": "2.25",
112
+ "--clampography-h3-slope": "calc((var(--clampography-h3-max) - var(--clampography-h3-min)) / (var(--clampography-v-max) - var(--clampography-v-min)))",
113
+ "--clampography-h3-base": "calc(var(--clampography-h3-min) - var(--clampography-h3-slope) * var(--clampography-v-min))",
114
+ "--clampography-h3-size": "clamp(calc(var(--clampography-h3-min) * 1rem), calc(var(--clampography-h3-base) * 1rem + var(--clampography-h3-slope) * 100vw), calc(var(--clampography-h3-max) * 1rem))",
115
+
116
+ // H4
117
+ "--clampography-h4-min": "1",
118
+ "--clampography-h4-max": "1.5",
119
+ "--clampography-h4-slope": "calc((var(--clampography-h4-max) - var(--clampography-h4-min)) / (var(--clampography-v-max) - var(--clampography-v-min)))",
120
+ "--clampography-h4-base": "calc(var(--clampography-h4-min) - var(--clampography-h4-slope) * var(--clampography-v-min))",
121
+ "--clampography-h4-size": "clamp(calc(var(--clampography-h4-min) * 1rem), calc(var(--clampography-h4-base) * 1rem + var(--clampography-h4-slope) * 100vw), calc(var(--clampography-h4-max) * 1rem))",
122
+
123
+ // H5 — static by default (min === max); set --clampography-h5-max to a different value to make it fluid
124
+ "--clampography-h5-min": "1",
125
+ "--clampography-h5-max": "1",
126
+ "--clampography-h5-slope": "calc((var(--clampography-h5-max) - var(--clampography-h5-min)) / (var(--clampography-v-max) - var(--clampography-v-min)))",
127
+ "--clampography-h5-base": "calc(var(--clampography-h5-min) - var(--clampography-h5-slope) * var(--clampography-v-min))",
128
+ "--clampography-h5-size": "clamp(calc(var(--clampography-h5-min) * 1rem), calc(var(--clampography-h5-base) * 1rem + var(--clampography-h5-slope) * 100vw), calc(var(--clampography-h5-max) * 1rem))",
129
+
130
+ // H6 — static by default (min === max)
131
+ "--clampography-h6-min": "0.875",
132
+ "--clampography-h6-max": "0.875",
133
+ "--clampography-h6-slope": "calc((var(--clampography-h6-max) - var(--clampography-h6-min)) / (var(--clampography-v-max) - var(--clampography-v-min)))",
134
+ "--clampography-h6-base": "calc(var(--clampography-h6-min) - var(--clampography-h6-slope) * var(--clampography-v-min))",
135
+ "--clampography-h6-size": "clamp(calc(var(--clampography-h6-min) * 1rem), calc(var(--clampography-h6-base) * 1rem + var(--clampography-h6-slope) * 100vw), calc(var(--clampography-h6-max) * 1rem))",
136
+
137
+ // Global heading scale multiplier (default: 1 = no scaling).
138
+ // Override in :root to proportionally scale all headings at once.
139
+ // Example: :root { --clampography-heading-scale: 0.85; }
140
+ "--clampography-heading-scale": "1",
141
+
142
+ // Individual heading scales (default to global scale)
143
+ "--clampography-h1-scale": "var(--clampography-heading-scale)",
144
+ "--clampography-h2-scale": "var(--clampography-heading-scale)",
145
+ "--clampography-h3-scale": "var(--clampography-heading-scale)",
146
+ "--clampography-h4-scale": "var(--clampography-heading-scale)",
147
+ "--clampography-h5-scale": "var(--clampography-heading-scale)",
148
+ "--clampography-h6-scale": "var(--clampography-heading-scale)",
149
+ },
150
+
151
+ // BODY STYLES (Typography baseline)
152
+ // Note: font-family is intentionally NOT set here.
153
+ // It is applied in extra.js with user-font priority via --font-sans.
154
+ [(() => {
155
+ const typographyPrefix = options.typography && options.typography !== "global" ? ` ${options.typography}` : "";
156
+ const bodyBase = root === ":root" ? "body" : root;
157
+ return typographyPrefix ? `${bodyBase}${typographyPrefix}` : bodyBase;
158
+ })()]: {
159
+ "font-size": makeFluid(0.875, 1.125),
160
+ "line-height": "1.75",
161
+ "text-rendering": "optimizeLegibility",
162
+ "-webkit-font-smoothing": "antialiased",
163
+ "-moz-osx-font-smoothing": "grayscale",
164
+ "text-wrap": "pretty",
165
+ },
166
+
167
+ // HEADINGS (H1-H6)
168
+ [scope(":where(h1, h2, h3, h4, h5, h6)")]: {
169
+ "font-weight": "600",
170
+ "scroll-margin-top": "var(--scroll-offset)",
171
+ },
172
+
173
+ [scope("h1")]: {
174
+ "font-size": "calc(var(--clampography-h1-size) * var(--clampography-h1-scale))",
175
+ "line-height": "1.1111",
176
+ "font-weight": "800",
177
+ "margin-top": "0",
178
+ "margin-bottom": "var(--spacing-xl)",
179
+ },
180
+
181
+ [scope("h2")]: {
182
+ "font-size": "calc(var(--clampography-h2-size) * var(--clampography-h2-scale))",
183
+ "line-height": "1.3333",
184
+ "font-weight": "700",
185
+ "margin-top": "var(--spacing-xl)",
186
+ "margin-bottom": "var(--spacing-md)",
187
+ },
188
+
189
+ [scope("h3")]: {
190
+ "font-size": "calc(var(--clampography-h3-size) * var(--clampography-h3-scale))",
191
+ "line-height": "1.5",
192
+ "margin-top": "var(--spacing-lg)",
193
+ "margin-bottom": "var(--spacing-sm)",
194
+ },
195
+
196
+ [scope("h4")]: {
197
+ "font-size": "calc(var(--clampography-h4-size) * var(--clampography-h4-scale))",
198
+ "line-height": "1.5",
199
+ "margin-top": "var(--spacing-lg)",
200
+ "margin-bottom": "var(--spacing-sm)",
201
+ },
202
+
203
+ [scope("h5")]: {
204
+ "font-size": "calc(var(--clampography-h5-size) * var(--clampography-h5-scale))",
205
+ "line-height": "1.5",
206
+ "margin-top": "var(--spacing-md)",
207
+ "margin-bottom": "var(--spacing-xs)",
208
+ },
209
+
210
+ [scope("h6")]: {
211
+ "font-size": "calc(var(--clampography-h6-size) * var(--clampography-h6-scale))",
212
+ "line-height": "1.5",
213
+ "margin-top": "var(--spacing-md)",
214
+ "margin-bottom": "var(--spacing-xs)",
215
+ },
216
+
217
+ [scope(":is(h1, h2, h3, h4, h5, h6):first-child")]: {
218
+ "margin-top": "0",
219
+ },
220
+
221
+ // LINKS
222
+ [scope("a")]: {
223
+ "text-decoration-line": "underline",
224
+ cursor: "pointer",
225
+ },
226
+
227
+ [scope(":where(h1, h2, h3, h4, h5, h6) a")]: {
228
+ "text-decoration": "none",
229
+ },
230
+
231
+ // MENU
232
+ [scope("menu")]: {
233
+ "list-style": "none",
234
+ "margin-bottom": "var(--spacing-md)",
235
+ "padding-inline-start": "0",
236
+ },
237
+
238
+ [scope("menu > li::before")]: {
239
+ display: "none",
240
+ },
241
+
242
+ // HGROUP
243
+ [scope("hgroup")]: {
244
+ "margin-bottom": "var(--spacing-lg)",
245
+ },
246
+
247
+ [scope("hgroup :where(h1, h2, h3, h4, h5, h6)")]: {
248
+ "margin-bottom": "var(--spacing-xs)",
249
+ },
250
+
251
+ [scope("hgroup :where(p)")]: {
252
+ "margin-top": "0",
253
+ "margin-bottom": "0",
254
+ "font-size": "0.875em",
255
+ "font-weight": "400",
256
+ "line-height": "1.5",
257
+ },
258
+
259
+ // TEXT CONTENT
260
+ [scope("p")]: {
261
+ "line-height": "1.75",
262
+ "margin-bottom": "var(--spacing-md)",
263
+ },
264
+
265
+ [scope(":where(strong, b)")]: {
266
+ "font-weight": "700",
267
+ },
268
+
269
+ [scope(":where(em, i, cite, var)")]: {
270
+ "font-style": "italic",
271
+ },
272
+
273
+ [scope("dfn")]: {
274
+ "font-style": "italic",
275
+ "font-weight": "600",
276
+ },
277
+
278
+ [scope("small")]: {
279
+ "font-size": "0.875em",
280
+ "line-height": "1.5",
281
+ },
282
+
283
+ [scope(":where(code, kbd, samp)")]: {
284
+ "font-family": "var(--font-family-mono)",
285
+ "font-size": "0.875em",
286
+ "-webkit-font-smoothing": "auto",
287
+ "-moz-osx-font-smoothing": "auto",
288
+ },
289
+
290
+ [scope("kbd")]: {
291
+ "font-weight": "600",
292
+ },
293
+
294
+ [scope("data")]: {
295
+ "font-variant-numeric": "tabular-nums",
296
+ },
297
+
298
+ [scope(":where(sub, sup)")]: {
299
+ "font-size": "0.75em",
300
+ "line-height": "0",
301
+ position: "relative",
302
+ "vertical-align": "baseline",
303
+ },
304
+
305
+ [scope("sup")]: {
306
+ top: "-0.5em",
307
+ },
308
+
309
+ [scope("sub")]: {
310
+ bottom: "-0.25em",
311
+ },
312
+
313
+ [scope("abbr[title]")]: {
314
+ "text-decoration": "underline dotted",
315
+ "text-underline-offset": "4px",
316
+ cursor: "help",
317
+ },
318
+
319
+ [scope("del")]: {
320
+ "text-decoration": "line-through",
321
+ },
322
+
323
+ [scope("ins")]: {
324
+ "text-decoration": "underline",
325
+ },
326
+
327
+ [scope("s")]: {
328
+ "text-decoration": "line-through",
329
+ },
330
+
331
+ [scope("u")]: {
332
+ "text-decoration": "underline",
333
+ },
334
+
335
+ [scope("mark")]: {
336
+ "font-style": "normal",
337
+ "font-weight": "inherit",
338
+ },
339
+
340
+ [scope("address")]: {
341
+ "font-style": "italic",
342
+ "margin-top": "var(--spacing-md)",
343
+ "margin-bottom": "var(--spacing-md)",
344
+ },
345
+
346
+ [scope("time")]: {
347
+ "font-style": "normal",
348
+ "font-variant-numeric": "tabular-nums",
349
+ },
350
+
351
+ // BLOCKQUOTES
352
+ [scope("blockquote")]: {
353
+ "margin-top": "var(--spacing-lg)",
354
+ "margin-bottom": "var(--spacing-lg)",
355
+ "padding-inline-start": "var(--spacing-md)",
356
+ },
357
+
358
+ [scope("blockquote blockquote")]: {
359
+ "margin-top": "var(--spacing-sm)",
360
+ "margin-bottom": "var(--spacing-sm)",
361
+ "padding-inline-start": "var(--spacing-sm)",
362
+ },
363
+
364
+ [scope("q")]: {
365
+ "font-style": "inherit",
366
+ },
367
+
368
+ // LISTS
369
+ [scope(":where(ul, ol)")]: {
370
+ "list-style": "none",
371
+ "margin-bottom": "var(--spacing-md)",
372
+ "padding-inline-start": "var(--list-indent)",
373
+ },
374
+
375
+ [scope("li")]: {
376
+ position: "relative",
377
+ },
378
+
379
+ [scope("li + li")]: {
380
+ "margin-top": "var(--spacing-xs)",
381
+ },
382
+
383
+ // Collapse margins for text-like block elements inside li
384
+ // to prevent them from creating extra gaps around nested lists.
385
+ [scope("li > :where(p, dl, figure, table, pre)")]: {
386
+ "margin-top": "0",
387
+ "margin-bottom": "0",
388
+ },
389
+
390
+ [scope("li > blockquote")]: {
391
+ "margin-top": "var(--spacing-sm)",
392
+ "margin-bottom": "var(--spacing-sm)",
393
+ },
394
+
395
+ // Nested lists: top gap matches sibling spacing (--spacing-xs).
396
+ // No bottom margin — the next li already gets margin-top from li+li.
397
+ [scope("li > :where(ul, ol)")]: {
398
+ "margin-top": "var(--spacing-xs)",
399
+ "margin-bottom": "0",
400
+ },
401
+
402
+ [scope("ul > li::before")]: {
403
+ content: "''",
404
+ position: "absolute",
405
+ "inset-inline-end": "100%",
406
+ "margin-inline-end": "0.75em",
407
+ top: "0.65em",
408
+ width: "0.375em",
409
+ height: "0.375em",
410
+ "background-color": "currentColor",
411
+ "border-radius": "50%",
412
+ },
413
+
414
+ [scope("ol")]: {
415
+ "counter-reset": "list-counter",
416
+ },
417
+
418
+ [scope("ol > li")]: {
419
+ "counter-increment": "list-counter",
420
+ },
421
+
422
+ [scope("ol > li::before")]: {
423
+ content: "counter(list-counter) '.'",
424
+ position: "absolute",
425
+ "inset-inline-end": "100%",
426
+ "margin-inline-end": "0.5em",
427
+ "font-weight": "600",
428
+ "font-variant-numeric": "tabular-nums",
429
+ "text-align": "end",
430
+ color: "currentColor",
431
+ },
432
+
433
+ // DEFINITION LISTS
434
+ [scope("dl")]: {
435
+ "margin-top": "var(--spacing-md)",
436
+ "margin-bottom": "var(--spacing-md)",
437
+ },
438
+
439
+ [scope("dt")]: {
440
+ "font-weight": "600",
441
+ "margin-top": "var(--spacing-sm)",
442
+ },
443
+
444
+ [scope("dt:first-child")]: {
445
+ "margin-top": "0",
446
+ },
447
+
448
+ [scope("dd")]: {
449
+ "margin-inline-start": "var(--spacing-md)",
450
+ },
451
+
452
+ [scope("dt + dd")]: {
453
+ "margin-top": "var(--spacing-xs)",
454
+ },
455
+
456
+ [scope("dd + dd")]: {
457
+ "margin-top": "var(--spacing-xs)",
458
+ },
459
+
460
+ [scope("dd:last-child")]: {
461
+ "margin-bottom": "0",
462
+ },
463
+
464
+ // CODE BLOCKS
465
+ [scope("pre")]: {
466
+ "margin-top": "var(--spacing-md)",
467
+ "margin-bottom": "var(--spacing-md)",
468
+ "font-family": "var(--font-family-mono)",
469
+ "line-height": "1.6",
470
+ "overflow-x": "auto",
471
+ "-webkit-font-smoothing": "auto",
472
+ "-moz-osx-font-smoothing": "auto",
473
+ },
474
+
475
+ [scope("pre code")]: {
476
+ "font-size": "inherit",
477
+ padding: "0",
478
+ background: "none",
479
+ "border-radius": "0",
480
+ },
481
+
482
+ // FORMS
483
+ // Structural resets — inherit typography from root, no visual styling here.
484
+ // Visual styling (colors, borders, padding) is handled by forms.js.
485
+ [scope("input, button, textarea, select, optgroup")]: {
486
+ "font-family": "inherit",
487
+ "font-size": "100%",
488
+ "line-height": "inherit",
489
+ },
490
+
491
+ [scope("textarea")]: {
492
+ "line-height": "1.5",
493
+ },
494
+
495
+ [scope("button, [type='button'], [type='reset'], [type='submit']")]: {
496
+ cursor: "pointer",
497
+ },
498
+
499
+ [scope("fieldset")]: {
500
+ "margin-top": "var(--spacing-md)",
501
+ "margin-bottom": "var(--spacing-md)",
502
+ padding: "var(--spacing-sm)",
503
+ },
504
+
505
+ [scope("legend")]: {
506
+ "font-weight": "600",
507
+ padding: "0 var(--spacing-xs)",
508
+ },
509
+
510
+ [scope("label")]: {
511
+ display: "inline-block",
512
+ "font-weight": "600",
513
+ "margin-bottom": "var(--spacing-xs)",
514
+ },
515
+
516
+ [scope("output")]: {
517
+ display: "inline-block",
518
+ "font-variant-numeric": "tabular-nums",
519
+ },
520
+
521
+ [scope(":where(meter, progress)")]: {
522
+ display: "inline-block",
523
+ "vertical-align": "middle",
524
+ },
525
+
526
+ // MEDIA
527
+ [scope(":where(img, video, canvas, audio, iframe, svg)")]: {
528
+ "max-width": "100%",
529
+ height: "auto",
530
+ "vertical-align": "middle",
531
+ },
532
+
533
+ [scope("figure")]: {
534
+ "margin-top": "var(--spacing-lg)",
535
+ "margin-bottom": "var(--spacing-lg)",
536
+ },
537
+
538
+ [scope("figcaption")]: {
539
+ "margin-top": "0.375rem",
540
+ "font-size": "0.875em",
541
+ "line-height": "1.5",
542
+ },
543
+
544
+ // TABLES
545
+ [scope("table")]: {
546
+ width: "100%",
547
+ "margin-top": "var(--spacing-md)",
548
+ "margin-bottom": "var(--spacing-md)",
549
+ "border-collapse": "collapse",
550
+ "font-size": "1em",
551
+ "line-height": "1.6",
552
+ },
553
+
554
+ [scope("caption")]: {
555
+ "margin-bottom": "var(--spacing-xs)",
556
+ "font-size": "0.875em",
557
+ "font-weight": "600",
558
+ "text-align": "start",
559
+ },
560
+
561
+ [scope("th, td")]: {
562
+ padding: "var(--spacing-xs) var(--spacing-sm)",
563
+ "text-align": "start",
564
+ },
565
+
566
+ [scope("th")]: {
567
+ "font-weight": "600",
568
+ },
569
+
570
+ [scope("thead th")]: {
571
+ "vertical-align": "bottom",
572
+ },
573
+
574
+ [scope("tbody th, tbody td")]: {
575
+ "vertical-align": "top",
576
+ },
577
+
578
+ [scope("tfoot th, tfoot td")]: {
579
+ "vertical-align": "top",
580
+ },
581
+
582
+ [scope("tbody + tbody")]: {
583
+ "border-top-width": "2px",
584
+ },
585
+
586
+ // SEPARATORS
587
+ [scope("hr")]: {
588
+ "margin-top": "var(--spacing-xl)",
589
+ "margin-bottom": "var(--spacing-xl)",
590
+ border: "0",
591
+ "border-top": "1px solid",
592
+ },
593
+
594
+ // INTERACTIVE ELEMENTS
595
+ [scope(":where(:focus, :focus-visible)")]: {
596
+ "outline-offset": "2px",
597
+ },
598
+
599
+ [scope("details")]: {
600
+ "margin-top": "var(--spacing-md)",
601
+ "margin-bottom": "var(--spacing-md)",
602
+ },
603
+
604
+ [scope("summary")]: {
605
+ cursor: "pointer",
606
+ "font-weight": "600",
607
+ },
608
+
609
+ [scope("details[open] > summary")]: {
610
+ "margin-bottom": "var(--spacing-xs)",
611
+ },
612
+
613
+ [scope("dialog")]: {
614
+ "font-size": "inherit",
615
+ "line-height": "inherit",
616
+ },
617
+
618
+ // UTILITIES
619
+ [
620
+ scope(
621
+ ":where(h1, h2, h3, h4, h5, h6, p, ul:not(li > ul, li > ol), ol:not(li > ul, li > ol), dl, blockquote, figure, table, pre):first-child",
622
+ )
623
+ ]: {
624
+ "margin-top": "0",
625
+ },
626
+
627
+ [scope(":where(p, ul, ol, dl, blockquote, figure, table, pre):last-child")]:
628
+ {
629
+ "margin-bottom": "0",
630
+ },
631
+ };
432
632
  };