@nonext/husk 0.2.3

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 (89) hide show
  1. package/CHANGELOG.md +148 -0
  2. package/LICENSE +166 -0
  3. package/README.md +140 -0
  4. package/api/public-api.md +1070 -0
  5. package/dist/adapter-C_0mhENy.d.ts +320 -0
  6. package/dist/admin/admin.css +5 -0
  7. package/dist/admin/index.d.ts +265 -0
  8. package/dist/admin/index.js +393 -0
  9. package/dist/admin/index.js.map +1 -0
  10. package/dist/admin/tokens.css +597 -0
  11. package/dist/admin/ui.d.ts +3013 -0
  12. package/dist/admin/ui.js +9783 -0
  13. package/dist/admin/ui.js.map +1 -0
  14. package/dist/auth/index.d.ts +4 -0
  15. package/dist/auth/index.js +9 -0
  16. package/dist/auth/index.js.map +1 -0
  17. package/dist/auth-B2gBtHl5.d.ts +28 -0
  18. package/dist/can-Chy7zmx7.d.ts +69 -0
  19. package/dist/chunk-3I6337WJ.js +83 -0
  20. package/dist/chunk-3I6337WJ.js.map +1 -0
  21. package/dist/chunk-4Z6P3XCE.js +62 -0
  22. package/dist/chunk-4Z6P3XCE.js.map +1 -0
  23. package/dist/chunk-6E3ZS5Z5.js +1007 -0
  24. package/dist/chunk-6E3ZS5Z5.js.map +1 -0
  25. package/dist/chunk-77JDRXXU.js +3 -0
  26. package/dist/chunk-77JDRXXU.js.map +1 -0
  27. package/dist/chunk-FHYWJCG6.js +171 -0
  28. package/dist/chunk-FHYWJCG6.js.map +1 -0
  29. package/dist/chunk-JAE7HHMM.js +506 -0
  30. package/dist/chunk-JAE7HHMM.js.map +1 -0
  31. package/dist/chunk-NPDBQBLW.js +68 -0
  32. package/dist/chunk-NPDBQBLW.js.map +1 -0
  33. package/dist/chunk-ORMYARXD.js +6 -0
  34. package/dist/chunk-ORMYARXD.js.map +1 -0
  35. package/dist/chunk-R4O7APIX.js +51 -0
  36. package/dist/chunk-R4O7APIX.js.map +1 -0
  37. package/dist/chunk-ROLKRJWI.js +187 -0
  38. package/dist/chunk-ROLKRJWI.js.map +1 -0
  39. package/dist/chunk-SOTQ3WP5.js +31 -0
  40. package/dist/chunk-SOTQ3WP5.js.map +1 -0
  41. package/dist/chunk-TCFFHTY3.js +97 -0
  42. package/dist/chunk-TCFFHTY3.js.map +1 -0
  43. package/dist/chunk-TS7Y7GEZ.js +7 -0
  44. package/dist/chunk-TS7Y7GEZ.js.map +1 -0
  45. package/dist/chunk-VLGR5PZX.js +3 -0
  46. package/dist/chunk-VLGR5PZX.js.map +1 -0
  47. package/dist/chunk-ZW2PUSVS.js +40 -0
  48. package/dist/chunk-ZW2PUSVS.js.map +1 -0
  49. package/dist/chunk-ZYNBMYJ6.js +392 -0
  50. package/dist/chunk-ZYNBMYJ6.js.map +1 -0
  51. package/dist/cli/nonext-husk.js +3360 -0
  52. package/dist/cli/nonext-husk.js.map +1 -0
  53. package/dist/cli/templates/firestore.rules +393 -0
  54. package/dist/cli/templates/storage.rules +165 -0
  55. package/dist/client/index.d.ts +27 -0
  56. package/dist/client/index.js +15 -0
  57. package/dist/client/index.js.map +1 -0
  58. package/dist/cms-9fSA3uQV.d.ts +158 -0
  59. package/dist/core/index.d.ts +1267 -0
  60. package/dist/core/index.js +12 -0
  61. package/dist/core/index.js.map +1 -0
  62. package/dist/entry-D3kiE8T1.d.ts +163 -0
  63. package/dist/field-Diyf5siF.d.ts +158 -0
  64. package/dist/field-type-D25Vojb0.d.ts +157 -0
  65. package/dist/firebase/index.d.ts +251 -0
  66. package/dist/firebase/index.js +991 -0
  67. package/dist/firebase/index.js.map +1 -0
  68. package/dist/index-5ylaMBUH.d.ts +155 -0
  69. package/dist/index.d.ts +14 -0
  70. package/dist/index.js +17 -0
  71. package/dist/index.js.map +1 -0
  72. package/dist/permissions/index.d.ts +101 -0
  73. package/dist/permissions/index.js +7 -0
  74. package/dist/permissions/index.js.map +1 -0
  75. package/dist/registry-CUC25qay.d.ts +59 -0
  76. package/dist/richtext/index.d.ts +85 -0
  77. package/dist/richtext/index.js +127 -0
  78. package/dist/richtext/index.js.map +1 -0
  79. package/dist/schema/index.d.ts +50 -0
  80. package/dist/schema/index.js +5 -0
  81. package/dist/schema/index.js.map +1 -0
  82. package/dist/server/index.d.ts +39 -0
  83. package/dist/server/index.js +25 -0
  84. package/dist/server/index.js.map +1 -0
  85. package/dist/types/index.d.ts +36 -0
  86. package/dist/types/index.js +6 -0
  87. package/dist/types/index.js.map +1 -0
  88. package/dist/write-limits-Djmm6L3R.d.ts +215 -0
  89. package/package.json +136 -0
@@ -0,0 +1,597 @@
1
+ /* Husk design tokens.
2
+ Canonical source: .docs/styleguide/02-tokens.md section 2, 3 and the z-index utilities.
3
+ Values are copied, never invented. Changing one means changing the style guide in the
4
+ same commit. This file is imported by the admin stylesheet and by the playground. */
5
+
6
+ :root {
7
+ /* Surfaces */
8
+ --color-surface-base: #111214;
9
+ --color-surface-sidebar: #101113;
10
+ --color-surface-raised: #191a1e;
11
+ --color-surface-card: #121315;
12
+ --color-surface-hover: #1c1e22;
13
+ --color-surface-active: #202227;
14
+ --color-surface-overlay: #18191d;
15
+ --color-surface-input: #151619;
16
+ --color-surface-disabled: #141517;
17
+
18
+ /* Text */
19
+ --color-text-primary: #f3f4f6;
20
+ --color-text-secondary: #bfc2c8;
21
+ --color-text-muted: #7b8089;
22
+ --color-text-faint: #575c65;
23
+ --color-text-disabled: #484c54;
24
+ --color-text-inverse: #111214;
25
+
26
+ /* Borders */
27
+ --color-border-subtle: rgba(255, 255, 255, 0.045);
28
+ --color-border-default: rgba(255, 255, 255, 0.07);
29
+ --color-border-strong: rgba(255, 255, 255, 0.11);
30
+ --color-border-active: rgba(255, 255, 255, 0.16);
31
+
32
+ /* Accent */
33
+ --color-accent-primary: #c52b8a;
34
+ --color-accent-magenta: #e32d7d;
35
+ --color-accent-violet: #7541d8;
36
+ --color-accent-violet-bright: #8547ee;
37
+ --color-accent-soft: rgba(197, 43, 138, 0.18);
38
+ --color-accent-hover: #d43796;
39
+ --color-accent-active: #b92580;
40
+
41
+ /* Semantic */
42
+ --color-success: #35b85a;
43
+ --color-success-muted: rgba(53, 184, 90, 0.14);
44
+ --color-warning: #d98b26;
45
+ --color-warning-muted: rgba(217, 139, 38, 0.14);
46
+ --color-danger: #d94b5f;
47
+ --color-danger-muted: rgba(217, 75, 95, 0.14);
48
+ --color-info: #5b8def;
49
+ --color-info-muted: rgba(91, 141, 239, 0.14);
50
+
51
+ /* Data series, fixed order */
52
+ --color-series-1: #c52b8a;
53
+ --color-series-2: #7541d8;
54
+ --color-series-3: #e32d7d;
55
+ --color-series-4: #5b8def;
56
+ --color-series-5: #35b85a;
57
+ --color-series-6: #d98b26;
58
+
59
+ /* Radius */
60
+ --radius-none: 0px;
61
+ --radius-xs: 3px;
62
+ --radius-sm: 5px;
63
+ --radius-md: 8px;
64
+ --radius-lg: 12px;
65
+ --radius-full: 9999px;
66
+
67
+ /* Spacing */
68
+ --space-0: 0px;
69
+ --space-1: 4px;
70
+ --space-2: 8px;
71
+ --space-3: 12px;
72
+ --space-4: 16px;
73
+ --space-5: 20px;
74
+ --space-6: 24px;
75
+ --space-8: 32px;
76
+ --space-10: 40px;
77
+ --space-12: 48px;
78
+ --space-16: 64px;
79
+
80
+ /* Motion */
81
+ --motion-fast: 100ms;
82
+ --motion-normal: 160ms;
83
+ --motion-slow: 220ms;
84
+ --ease-standard: cubic-bezier(0.2, 0, 0, 1);
85
+
86
+ /* Elevation */
87
+ --shadow-overlay: 0 12px 32px rgba(0, 0, 0, 0.28);
88
+
89
+ /* Focus */
90
+ --focus-ring-color: rgba(255, 255, 255, 0.14);
91
+ --focus-ring-width: 2px;
92
+ --focus-ring-offset: 2px;
93
+ --focus-field-ring-color: rgba(255, 255, 255, 0.06);
94
+ --focus-field-ring-offset: 1px;
95
+
96
+ /* Z-index */
97
+ --z-base: 0;
98
+ --z-sticky: 10;
99
+ --z-dropdown: 30;
100
+ --z-overlay: 40;
101
+ --z-modal: 50;
102
+ --z-toast: 60;
103
+ --z-tooltip: 70;
104
+
105
+ /* Component dimensions */
106
+ --control-sm: 30px;
107
+ --control-md: 36px;
108
+ --control-lg: 40px;
109
+ --sidebar-width: 280px;
110
+ --entry-sidebar-width: 280px;
111
+ --sidebar-item-height: 36px;
112
+ --menu-item-height: 34px;
113
+ --table-header-height: 36px;
114
+ --table-row-height: 40px;
115
+ --badge-height: 22px;
116
+ --status-dot-size: 6px;
117
+ --button-padding-inline: 14px;
118
+ --menu-padding-inline: 10px;
119
+ --toast-width: 360px;
120
+ --modal-width-sm: 420px;
121
+ --modal-width-md: 560px;
122
+ --modal-width-lg: 720px;
123
+ --modal-width-xl: 960px;
124
+ --scrollbar-width: 8px;
125
+ --icon-size: 16px;
126
+ --icon-stroke: 1.5;
127
+ }
128
+
129
+ @theme {
130
+ --font-sans:
131
+ var(--font-inter), ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
132
+ "Segoe UI", sans-serif;
133
+
134
+ /* One 4px step, so p-1=4, p-2=8, p-3=12, p-4=16, p-5=20, p-6=24,
135
+ p-8=32, p-10=40, p-12=48, p-16=64. Only those steps are permitted. */
136
+ --spacing: 4px;
137
+
138
+ --color-surface-base: #111214;
139
+ --color-surface-sidebar: #101113;
140
+ --color-surface-raised: #191a1e;
141
+ --color-surface-card: #121315;
142
+ --color-surface-hover: #1c1e22;
143
+ --color-surface-active: #202227;
144
+ --color-surface-overlay: #18191d;
145
+ --color-surface-input: #151619;
146
+ --color-surface-disabled: #141517;
147
+
148
+ --color-text-primary: #f3f4f6;
149
+ --color-text-secondary: #bfc2c8;
150
+ --color-text-muted: #7b8089;
151
+ --color-text-faint: #575c65;
152
+ --color-text-disabled: #484c54;
153
+ --color-text-inverse: #111214;
154
+
155
+ --color-border-subtle: rgba(255, 255, 255, 0.045);
156
+ --color-border-default: rgba(255, 255, 255, 0.07);
157
+ --color-border-strong: rgba(255, 255, 255, 0.11);
158
+ --color-border-active: rgba(255, 255, 255, 0.16);
159
+
160
+ --color-accent-primary: #c52b8a;
161
+ --color-accent-magenta: #e32d7d;
162
+ --color-accent-violet: #7541d8;
163
+ --color-accent-violet-bright: #8547ee;
164
+ --color-accent-soft: rgba(197, 43, 138, 0.18);
165
+ --color-accent-hover: #d43796;
166
+ --color-accent-active: #b92580;
167
+
168
+ --color-success: #35b85a;
169
+ --color-success-muted: rgba(53, 184, 90, 0.14);
170
+ --color-warning: #d98b26;
171
+ --color-warning-muted: rgba(217, 139, 38, 0.14);
172
+ --color-danger: #d94b5f;
173
+ --color-danger-muted: rgba(217, 75, 95, 0.14);
174
+ --color-info: #5b8def;
175
+ --color-info-muted: rgba(91, 141, 239, 0.14);
176
+
177
+ --color-series-1: #c52b8a;
178
+ --color-series-2: #7541d8;
179
+ --color-series-3: #e32d7d;
180
+ --color-series-4: #5b8def;
181
+ --color-series-5: #35b85a;
182
+ --color-series-6: #d98b26;
183
+
184
+ --radius-xs: 3px;
185
+ --radius-sm: 5px;
186
+ --radius-md: 8px;
187
+ --radius-lg: 12px;
188
+
189
+ --text-display-sm: 28px;
190
+ --text-display-sm--line-height: 34px;
191
+ --text-display-sm--font-weight: 700;
192
+ --text-display-sm--letter-spacing: -0.02em;
193
+
194
+ --text-heading-lg: 24px;
195
+ --text-heading-lg--line-height: 30px;
196
+ --text-heading-lg--font-weight: 700;
197
+ --text-heading-lg--letter-spacing: -0.015em;
198
+
199
+ --text-heading-md: 18px;
200
+ --text-heading-md--line-height: 24px;
201
+ --text-heading-md--font-weight: 600;
202
+ --text-heading-md--letter-spacing: -0.01em;
203
+
204
+ --text-heading-sm: 15px;
205
+ --text-heading-sm--line-height: 20px;
206
+ --text-heading-sm--font-weight: 600;
207
+
208
+ --text-body: 14px;
209
+ --text-body--line-height: 20px;
210
+ --text-body--font-weight: 400;
211
+
212
+ --text-body-medium: 14px;
213
+ --text-body-medium--line-height: 20px;
214
+ --text-body-medium--font-weight: 500;
215
+
216
+ --text-body-sm: 13px;
217
+ --text-body-sm--line-height: 18px;
218
+ --text-body-sm--font-weight: 400;
219
+
220
+ --text-label: 12px;
221
+ --text-label--line-height: 16px;
222
+ --text-label--font-weight: 500;
223
+
224
+ --text-caption: 11px;
225
+ --text-caption--line-height: 15px;
226
+ --text-caption--font-weight: 400;
227
+
228
+ --text-micro: 10px;
229
+ --text-micro--line-height: 14px;
230
+ --text-micro--font-weight: 500;
231
+ --text-micro--letter-spacing: 0.04em;
232
+
233
+ --text-metric-lg: 30px;
234
+ --text-metric-lg--line-height: 34px;
235
+ --text-metric-lg--font-weight: 700;
236
+ --text-metric-lg--letter-spacing: -0.02em;
237
+
238
+ --text-metric-md: 24px;
239
+ --text-metric-md--line-height: 29px;
240
+ --text-metric-md--font-weight: 700;
241
+ --text-metric-md--letter-spacing: -0.015em;
242
+
243
+ --shadow-overlay: 0 12px 32px rgba(0, 0, 0, 0.28);
244
+
245
+ --ease-standard: cubic-bezier(0.2, 0, 0, 1);
246
+
247
+ --breakpoint-sm: 640px;
248
+ --breakpoint-md: 768px;
249
+ --breakpoint-lg: 1024px;
250
+ --breakpoint-xl: 1280px;
251
+ --breakpoint-2xl: 1536px;
252
+ }
253
+
254
+ @layer utilities {
255
+ .z-sticky {
256
+ z-index: var(--z-sticky);
257
+ }
258
+ .z-dropdown {
259
+ z-index: var(--z-dropdown);
260
+ }
261
+ .z-overlay {
262
+ z-index: var(--z-overlay);
263
+ }
264
+ .z-modal {
265
+ z-index: var(--z-modal);
266
+ }
267
+ .z-toast {
268
+ z-index: var(--z-toast);
269
+ }
270
+ .z-tooltip {
271
+ z-index: var(--z-tooltip);
272
+ }
273
+ }
274
+
275
+ /* Focus rings as utilities, so a component never restates the values.
276
+ Canonical source: .docs/styleguide/01-foundations.md section 8. */
277
+ @utility focus-ring {
278
+ outline: var(--focus-ring-width) solid var(--focus-ring-color);
279
+ outline-offset: var(--focus-ring-offset);
280
+ }
281
+
282
+ @utility focus-field-ring {
283
+ border-color: var(--color-border-active);
284
+ outline: var(--focus-ring-width) solid var(--focus-field-ring-color);
285
+ outline-offset: var(--focus-field-ring-offset);
286
+ }
287
+
288
+ /* The one spinner animation: 800ms continuous linear rotation.
289
+ Canonical source: .docs/styleguide/04-components.md section 16. */
290
+ @theme {
291
+ --animate-spinner: husk-spin 800ms linear infinite;
292
+
293
+ @keyframes husk-spin {
294
+ to {
295
+ transform: rotate(360deg);
296
+ }
297
+ }
298
+ }
299
+
300
+ /* The one state transition every interactive component uses.
301
+ Canonical source: .docs/styleguide/04-components.md section 1. */
302
+ @utility state-transition {
303
+ transition:
304
+ background-color var(--motion-fast) var(--ease-standard),
305
+ border-color var(--motion-fast) var(--ease-standard),
306
+ color var(--motion-fast) var(--ease-standard),
307
+ opacity var(--motion-fast) var(--ease-standard);
308
+ }
309
+
310
+ /* The empty state description measure, 42ch, as a container token so no component has to
311
+ write it. Canonical source: .docs/styleguide/04-components.md section 15. */
312
+ @theme {
313
+ --container-empty-state: 42ch;
314
+ }
315
+
316
+ /* The modal backdrop, the one place the system allows near-black.
317
+ Canonical source: .docs/styleguide/04-components.md section 12. */
318
+ @theme {
319
+ --color-backdrop: rgba(0, 0, 0, 0.62);
320
+ }
321
+
322
+ /* Fixed overlay measures, as container tokens so max-w-* and min-w-* can name them
323
+ instead of a component restating the pixel value.
324
+ Canonical source: .docs/styleguide/04-components.md sections 11, 12, 13, 14. */
325
+ @theme {
326
+ --container-menu: 180px;
327
+ --container-tooltip: 240px;
328
+ --container-toast: 360px;
329
+ --container-modal-sm: 420px;
330
+ --container-modal-md: 560px;
331
+ --container-modal-lg: 720px;
332
+ --container-modal-xl: 960px;
333
+ }
334
+
335
+ /* The modal body measure. A calc cannot live in @theme, so it is a utility.
336
+ Canonical source: .docs/styleguide/04-components.md section 12. */
337
+ @utility modal-max-height {
338
+ max-height: calc(100dvh - 96px);
339
+ }
340
+
341
+ /* The focus ring for elements whose own edge would clip an outset ring: table rows and
342
+ tabs. Same ring, negative offset.
343
+ Canonical source: .docs/styleguide/01-foundations.md section 8,
344
+ .docs/styleguide/04-components.md sections 4 and 5. */
345
+ @utility focus-ring-inset {
346
+ outline: var(--focus-ring-width) solid var(--focus-ring-color);
347
+ outline-offset: calc(-1 * var(--focus-ring-offset));
348
+ }
349
+
350
+ /* Skeleton pulse and the two overlay entrances. No component writes a duration or an
351
+ easing of its own.
352
+ Canonical source: .docs/styleguide/04-components.md sections 11, 14, 16. */
353
+ @theme {
354
+ --animate-skeleton: husk-skeleton 1.4s var(--ease-standard) infinite;
355
+ --animate-menu-in: husk-menu-in var(--motion-slow) var(--ease-standard);
356
+ --animate-menu-in-up: husk-menu-in-up var(--motion-slow) var(--ease-standard);
357
+ --animate-toast-in: husk-toast-in var(--motion-slow) var(--ease-standard);
358
+
359
+ @keyframes husk-skeleton {
360
+ 0%,
361
+ 100% {
362
+ background-color: var(--color-surface-raised);
363
+ }
364
+ 50% {
365
+ background-color: var(--color-surface-hover);
366
+ }
367
+ }
368
+
369
+ @keyframes husk-menu-in {
370
+ from {
371
+ opacity: 0;
372
+ transform: translateY(-4px);
373
+ }
374
+ to {
375
+ opacity: 1;
376
+ transform: translateY(0);
377
+ }
378
+ }
379
+
380
+ /* Same entrance as husk-menu-in, direction inverted: a menu opening upward (side="top",
381
+ 04 Components section 11) grows from the trigger toward negative Y, so the panel starts
382
+ below its resting position instead of above it. */
383
+ @keyframes husk-menu-in-up {
384
+ from {
385
+ opacity: 0;
386
+ transform: translateY(4px);
387
+ }
388
+ to {
389
+ opacity: 1;
390
+ transform: translateY(0);
391
+ }
392
+ }
393
+
394
+ @keyframes husk-toast-in {
395
+ from {
396
+ opacity: 0;
397
+ transform: translateY(8px);
398
+ }
399
+ to {
400
+ opacity: 1;
401
+ transform: translateY(0);
402
+ }
403
+ }
404
+ }
405
+
406
+ /* The switch thumb transition. The global state-transition does not cover transform, and
407
+ the switch is the only control in the system whose thumb moves.
408
+ Canonical source: .docs/styleguide/04-components.md section 3.6. */
409
+ @utility switch-transition {
410
+ transition:
411
+ background-color var(--motion-fast) var(--ease-standard),
412
+ transform var(--motion-fast) var(--ease-standard);
413
+ }
414
+
415
+ /* The application shell: the sidebar measure as a container token so a component can say
416
+ `w-sidebar`, and the two-column grid as a utility because a grid template cannot be a
417
+ container token. Canonical source: .docs/styleguide/03-layout.md section 1. */
418
+ @theme {
419
+ --container-sidebar: 280px;
420
+ }
421
+
422
+ @utility shell-grid {
423
+ grid-template-columns: var(--sidebar-width) minmax(0, 1fr);
424
+ }
425
+
426
+ /* The entry editor's two columns: the generated field stack, then the metadata sidebar.
427
+ A grid template cannot be a container token, so it is a utility, like shell-grid.
428
+ Canonical source: .docs/styleguide/03-layout.md section 5.2. */
429
+ @utility entry-grid {
430
+ grid-template-columns: minmax(0, 1fr) var(--entry-sidebar-width);
431
+ }
432
+
433
+ /* The one reading measure in the system, 72ch, as a container token so a page header or a
434
+ settings description can say `max-w-reading` instead of restating it.
435
+ Canonical source: .docs/styleguide/03-layout.md section 1. */
436
+ @theme {
437
+ --container-reading: 72ch;
438
+ }
439
+
440
+ /* Rich text body typography, and the minimum height of the editable surface.
441
+ Canonical source: .docs/styleguide/04-components.md section 3.9.
442
+
443
+ It is CSS rather than Tailwind utilities because the editor writes real elements into a
444
+ contenteditable element at runtime: there is no JSX to hang a class on. Every value below
445
+ is a token, and the table in section 3.9 is the whole permitted set. A selector that is not
446
+ in that table does not belong here, because a mark with no styling is a mark the format
447
+ does not have. */
448
+ @theme {
449
+ --richtext-min-height: 160px;
450
+ }
451
+
452
+ @utility richtext-content {
453
+ min-height: var(--richtext-min-height);
454
+ padding: calc(var(--spacing) * 3);
455
+ font-size: var(--text-body);
456
+ line-height: var(--text-body--line-height);
457
+ color: var(--color-text-primary);
458
+ cursor: text;
459
+
460
+ & > :first-child {
461
+ margin-top: 0;
462
+ }
463
+
464
+ & > :last-child {
465
+ margin-bottom: 0;
466
+ }
467
+
468
+ & p {
469
+ margin-bottom: calc(var(--spacing) * 3);
470
+ }
471
+
472
+ & h2 {
473
+ margin-top: calc(var(--spacing) * 5);
474
+ margin-bottom: calc(var(--spacing) * 2);
475
+ font-size: var(--text-heading-md);
476
+ line-height: var(--text-heading-md--line-height);
477
+ font-weight: var(--text-heading-md--font-weight);
478
+ letter-spacing: var(--text-heading-md--letter-spacing);
479
+ }
480
+
481
+ & h3 {
482
+ margin-top: calc(var(--spacing) * 5);
483
+ margin-bottom: calc(var(--spacing) * 2);
484
+ font-size: var(--text-heading-sm);
485
+ line-height: var(--text-heading-sm--line-height);
486
+ font-weight: var(--text-heading-sm--font-weight);
487
+ }
488
+
489
+ & ul,
490
+ & ol {
491
+ margin-bottom: calc(var(--spacing) * 3);
492
+ padding-inline-start: calc(var(--spacing) * 5);
493
+ color: var(--color-text-muted);
494
+ }
495
+
496
+ & ul {
497
+ list-style-type: disc;
498
+ }
499
+
500
+ & ol {
501
+ list-style-type: decimal;
502
+ }
503
+
504
+ & li {
505
+ margin-bottom: var(--spacing);
506
+ }
507
+
508
+ /* The marker takes text-muted from the list; the content goes back to body colour. */
509
+ & li > * {
510
+ color: var(--color-text-primary);
511
+ margin-bottom: 0;
512
+ }
513
+
514
+ & blockquote {
515
+ margin-bottom: calc(var(--spacing) * 3);
516
+ border-inline-start: 2px solid var(--color-border-strong);
517
+ padding-inline-start: calc(var(--spacing) * 3);
518
+ color: var(--color-text-secondary);
519
+ }
520
+
521
+ & strong {
522
+ font-weight: 600;
523
+ }
524
+
525
+ & em {
526
+ font-style: italic;
527
+ }
528
+
529
+ & s {
530
+ text-decoration: line-through;
531
+ color: var(--color-text-muted);
532
+ }
533
+
534
+ & a {
535
+ color: var(--color-text-primary);
536
+ text-decoration: underline;
537
+ text-underline-offset: 2px;
538
+ text-decoration-color: var(--color-border-strong);
539
+ }
540
+
541
+ /* The editor's own placeholder node, shown while the document is empty. */
542
+ & p.is-editor-empty:first-child::before {
543
+ content: attr(data-placeholder);
544
+ color: var(--color-text-faint);
545
+ float: inline-start;
546
+ height: 0;
547
+ pointer-events: none;
548
+ }
549
+
550
+ &:focus {
551
+ outline: none;
552
+ }
553
+ }
554
+
555
+ /* Reduced motion. Canonical source: .docs/styleguide/01-foundations.md section 6, which
556
+ asks for motion-fast opacity-only transitions, no icon morphs and no skeleton shimmer.
557
+
558
+ The declarations sit outside every @layer on purpose: unlayered CSS outranks Tailwind's
559
+ utility layer, so this wins without !important on any of it.
560
+
561
+ MorphIcon handles its own half through the library's reducedMotion="user", and the
562
+ spinner keeps turning: the guide names the shimmer and the morphs, and a spinner that
563
+ freezes stops reporting that anything is still happening. */
564
+ @media (prefers-reduced-motion: reduce) {
565
+ *,
566
+ *::before,
567
+ *::after {
568
+ transition-property: opacity;
569
+ transition-duration: var(--motion-fast);
570
+ }
571
+
572
+ .animate-skeleton,
573
+ .animate-menu-in,
574
+ .animate-menu-in-up,
575
+ .animate-toast-in {
576
+ animation: none;
577
+ }
578
+ }
579
+
580
+ /* The upload progress bar's fill. The global state-transition does not cover width, and
581
+ the progress bar is the only control in the system whose width is a measured value.
582
+ Canonical source: .docs/styleguide/04-components.md section 16. */
583
+ @utility progress-transition {
584
+ transition: width var(--motion-normal) var(--ease-standard);
585
+ }
586
+
587
+ /* The media library grid, and the aspect ratio of a tile's image area. A grid template
588
+ cannot be a container token, so it is a utility, like shell-grid and entry-grid.
589
+ Canonical source: .docs/styleguide/03-layout.md section 5.3. */
590
+ @theme {
591
+ --container-media-tile: 180px;
592
+ --aspect-media: 4 / 3;
593
+ }
594
+
595
+ @utility media-grid {
596
+ grid-template-columns: repeat(auto-fill, minmax(var(--container-media-tile), 1fr));
597
+ }