@prototyperco/ui 0.5.0-alpha.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.
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@prototyperco/ui",
3
+ "version": "0.5.0-alpha.0",
4
+ "description": "Composable, design-first React component library built on Base UI primitives",
5
+ "license": "MIT",
6
+ "author": "Protochase, Inc.",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/wavyrai/prototyper-ui.git",
10
+ "directory": "packages/ui"
11
+ },
12
+ "homepage": "https://prototyper.ai",
13
+ "bugs": {
14
+ "url": "https://github.com/wavyrai/prototyper-ui/issues"
15
+ },
16
+ "keywords": [
17
+ "prototyper-ui",
18
+ "react",
19
+ "components",
20
+ "ui",
21
+ "base-ui",
22
+ "design-system"
23
+ ],
24
+ "sideEffects": false,
25
+ "type": "module",
26
+ "exports": {
27
+ ".": {
28
+ "types": "./dist/index.d.ts",
29
+ "import": "./dist/index.js",
30
+ "require": "./dist/index.cjs"
31
+ },
32
+ "./tokens.css": "./src/prototyper-tokens.css",
33
+ "./components/*": "./src/components/*"
34
+ },
35
+ "files": [
36
+ "dist",
37
+ "src/prototyper-tokens.css",
38
+ "README.md"
39
+ ],
40
+ "engines": {
41
+ "node": ">=18.0.0"
42
+ },
43
+ "dependencies": {
44
+ "@base-ui/react": "^1.2.0",
45
+ "class-variance-authority": "^0.7.1",
46
+ "clsx": "^2.1.1",
47
+ "lucide-react": "^0.511.0",
48
+ "react-resizable-panels": "^4.7.2",
49
+ "tailwind-merge": "^3.3.0"
50
+ },
51
+ "peerDependencies": {
52
+ "react": "^19.0.0",
53
+ "react-dom": "^19.0.0"
54
+ },
55
+ "devDependencies": {
56
+ "@types/react": "^19.2.14",
57
+ "@types/react-dom": "^19.2.3",
58
+ "tsup": "^8.4.0",
59
+ "typescript": "^5.8.3",
60
+ "vitest": "^3.1.1",
61
+ "@prototyperco/typescript-config": "0.0.0"
62
+ },
63
+ "scripts": {
64
+ "build": "tsup",
65
+ "dev": "tsup --watch",
66
+ "test": "vitest run",
67
+ "lint": "eslint src/",
68
+ "typecheck": "tsc --noEmit",
69
+ "clean": "rm -rf dist"
70
+ }
71
+ }
@@ -0,0 +1,535 @@
1
+ /* ========== PROTOTYPER UI TOKENS START ========== */
2
+
3
+ /* ============================================
4
+ TAILWIND THEME REGISTRATION
5
+ All tokens registered here generate utilities:
6
+ --color-* → bg-*, text-*, border-*
7
+ --shadow-* → shadow-*
8
+ --ease-* → ease-*
9
+ --radius-* → rounded-*
10
+ --animate-* → animate-*
11
+ ============================================ */
12
+
13
+ @theme {
14
+ /* --- Font families --- */
15
+ --font-sans: var(--font-geist-sans);
16
+ --font-heading: var(--font-overpass);
17
+ --font-mono: var(--font-geist-mono);
18
+ --font-pixel: var(--font-geist-pixel-square);
19
+
20
+ /* --- Radius scale --- */
21
+ --radius-xl: calc(var(--radius) + 4px);
22
+ --radius-lg: var(--radius);
23
+ --radius-md: calc(var(--radius) - 2px);
24
+ --radius-sm: calc(var(--radius) - 4px);
25
+
26
+ /* --- Base colors --- */
27
+ --color-background: oklch(var(--background));
28
+ --color-foreground: oklch(var(--foreground));
29
+ --color-border: oklch(var(--border));
30
+ --color-border-light: oklch(var(--border-light));
31
+ --color-border-dark: oklch(var(--border-dark));
32
+ --color-input: oklch(var(--input));
33
+ --color-ring: oklch(var(--ring));
34
+
35
+ /* --- Primary --- */
36
+ --color-primary: oklch(var(--primary));
37
+ --color-primary-foreground: oklch(var(--primary-foreground));
38
+ --color-primary-light: oklch(var(--primary-light));
39
+ --color-primary-middle: oklch(var(--primary-middle));
40
+ --color-primary-dark: oklch(var(--primary-dark));
41
+
42
+ /* --- Secondary --- */
43
+ --color-secondary: oklch(var(--secondary));
44
+ --color-secondary-foreground: oklch(var(--secondary-foreground));
45
+
46
+ /* --- Muted --- */
47
+ --color-muted: oklch(var(--muted));
48
+ --color-muted-foreground: oklch(var(--muted-foreground));
49
+
50
+ /* --- Accent --- */
51
+ --color-accent: oklch(var(--accent));
52
+ --color-accent-foreground: oklch(var(--accent-foreground));
53
+
54
+ /* --- Destructive --- */
55
+ --color-destructive: oklch(var(--destructive));
56
+ --color-destructive-foreground: oklch(var(--destructive-foreground));
57
+
58
+ /* --- Status --- */
59
+ --color-success: oklch(var(--success));
60
+ --color-success-foreground: oklch(var(--success-foreground));
61
+ --color-warning: oklch(var(--warning));
62
+ --color-warning-foreground: oklch(var(--warning-foreground));
63
+ --color-info: oklch(var(--info));
64
+ --color-info-foreground: oklch(var(--info-foreground));
65
+
66
+ /* --- Surfaces --- */
67
+ --color-popover: oklch(var(--popover));
68
+ --color-popover-foreground: oklch(var(--popover-foreground));
69
+ --color-card: oklch(var(--card));
70
+ --color-card-foreground: oklch(var(--card-foreground));
71
+ --color-surface: oklch(var(--surface));
72
+ --color-surface-foreground: oklch(var(--surface-foreground));
73
+ --color-surface-secondary: var(--surface-secondary);
74
+ --color-surface-tertiary: var(--surface-tertiary);
75
+ --color-overlay: oklch(var(--overlay));
76
+ --color-overlay-foreground: oklch(var(--overlay-foreground));
77
+ --color-machine-bg: oklch(var(--machine-bg));
78
+ --color-machine-panel: oklch(var(--machine-panel));
79
+ --color-machine-panel-raised: oklch(var(--machine-panel-raised));
80
+ --color-machine-fg: oklch(var(--machine-fg));
81
+ --color-machine-fg-muted: oklch(var(--machine-fg-muted));
82
+ --color-machine-fg-subtle: oklch(var(--machine-fg-subtle));
83
+ --color-machine-border: oklch(var(--machine-border));
84
+ --color-machine-rule: oklch(var(--machine-rule));
85
+ --color-machine-inverse: oklch(var(--machine-inverse));
86
+ --color-machine-inverse-fg: oklch(var(--machine-inverse-fg));
87
+
88
+ /* --- Field --- */
89
+ --color-field-background: oklch(var(--field-background));
90
+ --color-field-border: var(--field-border);
91
+ --color-field-border-hover: var(--field-border-hover);
92
+ --color-field-border-focus: var(--field-border-focus);
93
+ --color-field-border-invalid: var(--field-border-invalid);
94
+
95
+ /* --- Derived interaction colors (auto-adapt in dark mode) --- */
96
+ --color-primary-hover: var(--primary-hover);
97
+ --color-destructive-hover: var(--destructive-hover);
98
+ --color-success-hover: var(--success-hover);
99
+ --color-warning-hover: var(--warning-hover);
100
+ --color-accent-hover: var(--accent-hover);
101
+ --color-primary-soft: var(--primary-soft);
102
+ --color-primary-soft-hover: var(--primary-soft-hover);
103
+ --color-destructive-soft: var(--destructive-soft);
104
+ --color-destructive-soft-hover: var(--destructive-soft-hover);
105
+
106
+ /* --- Shadows (3 semantic tiers, mode-adaptive via .dark override) --- */
107
+ --shadow-surface:
108
+ 0 2px 4px 0 oklch(0% 0 0 / 0.04), 0 1px 2px 0 oklch(0% 0 0 / 0.06),
109
+ 0 0 0 1px oklch(0% 0 0 / 0.04);
110
+ --shadow-field:
111
+ 0 1px 2px 0 oklch(0% 0 0 / 0.05), 0 0 0 1px oklch(0% 0 0 / 0.04);
112
+ --shadow-overlay:
113
+ 0 8px 30px oklch(0% 0 0 / 0.12), 0 2px 8px oklch(0% 0 0 / 0.06),
114
+ 0 0 0 1px oklch(0% 0 0 / 0.06);
115
+ --shadow-tooltip:
116
+ 0 2px 8px oklch(0% 0 0 / 0.12), 0 1px 3px oklch(0% 0 0 / 0.08);
117
+ --shadow-inset-track:
118
+ inset 0 1px 2px oklch(0% 0 0 / 0.06), inset 0 0 0 1px oklch(0% 0 0 / 0.04);
119
+
120
+ /* --- Easing scale --- */
121
+ --ease-smooth: cubic-bezier(0.4, 0, 0.2, 1);
122
+ --ease-out-quad: cubic-bezier(0.25, 0.46, 0.45, 0.94);
123
+ --ease-out-quart: cubic-bezier(0.165, 0.84, 0.44, 1);
124
+ --ease-out-fluid: cubic-bezier(0.32, 0.72, 0, 1);
125
+ --ease-in-quad: cubic-bezier(0.55, 0.085, 0.68, 0.53);
126
+ --ease-in-quart: cubic-bezier(0.895, 0.03, 0.685, 0.22);
127
+ --ease-in-out-quad: cubic-bezier(0.455, 0.03, 0.515, 0.955);
128
+
129
+ /* --- Keyframe animations --- */
130
+ --animate-accordion-down: accordion-down 0.2s ease-out;
131
+ --animate-accordion-up: accordion-up 0.2s ease-out;
132
+ --animate-progress-indeterminate: progress-indeterminate 1.8s ease-in-out
133
+ infinite;
134
+
135
+ @keyframes accordion-down {
136
+ from {
137
+ height: 0;
138
+ }
139
+ to {
140
+ height: var(--accordion-content-height);
141
+ }
142
+ }
143
+ @keyframes accordion-up {
144
+ from {
145
+ height: var(--accordion-content-height);
146
+ }
147
+ to {
148
+ height: 0;
149
+ }
150
+ }
151
+ @keyframes progress-indeterminate {
152
+ 0% {
153
+ transform: translateX(-100%) scaleX(0.4);
154
+ }
155
+ 50% {
156
+ transform: translateX(30%) scaleX(0.6);
157
+ }
158
+ 100% {
159
+ transform: translateX(200%) scaleX(0.4);
160
+ }
161
+ }
162
+ }
163
+
164
+ /* ============================================
165
+ COLOR TOKENS — Light Mode (OKLCH)
166
+ ============================================ */
167
+
168
+ :root {
169
+ /* Font overrides — must be outside @theme to beat Tailwind's unlayered defaults */
170
+ --font-sans: var(--font-geist-sans);
171
+ --font-heading: var(--font-overpass);
172
+
173
+ /* Base */
174
+ --background: 100% 0 0;
175
+ --foreground: 14.05% 0.004 285.8;
176
+ --radius: 0.5rem;
177
+
178
+ /* Cards & Popovers */
179
+ --card: 98.48% 0 0;
180
+ --card-foreground: 14.05% 0.004 285.8;
181
+ --popover: 100% 0 0;
182
+ --popover-foreground: 14.05% 0.004 285.8;
183
+
184
+ /* Primary ramp — metallic zinc */
185
+ --primary: 44% 0.017 286;
186
+ --primary-light: 87% 0.006 286;
187
+ --primary-middle: 55% 0.016 286;
188
+ --primary-dark: 37% 0.016 286;
189
+ --primary-foreground: 100% 0 0;
190
+
191
+ /* Secondary */
192
+ --secondary: 97% 0.003 265;
193
+ --secondary-foreground: 21% 0.006 286;
194
+
195
+ /* Muted */
196
+ --muted: 96.76% 0 0;
197
+ --muted-foreground: 55.19% 0.014 285.9;
198
+
199
+ /* Accent */
200
+ --accent: 96.76% 0 0;
201
+ --accent-foreground: 21.03% 0.006 285.9;
202
+
203
+ /* Destructive */
204
+ --destructive: 63.68% 0.208 25.3;
205
+ --destructive-foreground: 98.43% 0 0;
206
+
207
+ /* Status */
208
+ --success: 72.05% 0.192 149.5;
209
+ --success-foreground: 100% 0 0;
210
+ --warning: 76.97% 0.165 70.6;
211
+ --warning-foreground: 0% 0 0;
212
+ --info: 62.61% 0.186 259.6;
213
+ --info-foreground: 100% 0 0;
214
+
215
+ /* Borders & Input */
216
+ --border: 91.97% 0.004 286.3;
217
+ --border-light: 96.01% 0 0;
218
+ --border-dark: 79.59% 0.011 286.2;
219
+ --input: 91.97% 0.004 286.3;
220
+ --ring: 44% 0.017 286;
221
+
222
+ /* Surfaces */
223
+ --surface: 98.48% 0 0;
224
+ --surface-foreground: 14.05% 0.004 285.8;
225
+ --surface-secondary: color-mix(
226
+ in oklab,
227
+ oklch(var(--surface)) 94%,
228
+ oklch(var(--surface-foreground)) 6%
229
+ );
230
+ --surface-tertiary: color-mix(
231
+ in oklab,
232
+ oklch(var(--surface)) 88%,
233
+ oklch(var(--surface-foreground)) 12%
234
+ );
235
+ --overlay: 100% 0 0;
236
+ --overlay-foreground: 14.05% 0.004 285.8;
237
+
238
+ /* Field */
239
+ --field-background: 100% 0 0;
240
+ --field-border: oklch(0% 0 0 / 0.12);
241
+ --field-border-hover: oklch(0% 0 0 / 0.22);
242
+ --field-border-focus: oklch(0% 0 0 / 0.35);
243
+ --field-border-invalid: oklch(var(--destructive));
244
+ --machine-bg: 2.8% 0 0;
245
+ --machine-panel: 4.4% 0 0;
246
+ --machine-panel-raised: 7.2% 0 0;
247
+ --machine-fg: 98% 0 0;
248
+ --machine-fg-muted: 88% 0 0;
249
+ --machine-fg-subtle: 72% 0 0;
250
+ --machine-border: 100% 0 0 / 0.22;
251
+ --machine-rule: 100% 0 0 / 0.3;
252
+ --machine-inverse: 96% 0 0;
253
+ --machine-inverse-fg: 8% 0 0;
254
+ --machine-font-size-base: 0.95rem;
255
+ --machine-line-height-base: 1.7;
256
+ --machine-heading-weight: 640;
257
+ --machine-code-size: 0.84rem;
258
+ --machine-content-max: 76ch;
259
+ --machine-section-gap: 2.5rem;
260
+ --machine-block-gap: 1rem;
261
+ --machine-rail-offset: clamp(0.9rem, 2vw, 1.45rem);
262
+
263
+ /* Derived: semantic hover (90% base + 10% paired foreground) */
264
+ --primary-hover: color-mix(
265
+ in oklab,
266
+ oklch(var(--primary)) 90%,
267
+ oklch(var(--primary-foreground)) 10%
268
+ );
269
+ --destructive-hover: color-mix(
270
+ in oklab,
271
+ oklch(var(--destructive)) 90%,
272
+ oklch(var(--destructive-foreground)) 10%
273
+ );
274
+ --success-hover: color-mix(
275
+ in oklab,
276
+ oklch(var(--success)) 90%,
277
+ oklch(var(--success-foreground)) 10%
278
+ );
279
+ --warning-hover: color-mix(
280
+ in oklab,
281
+ oklch(var(--warning)) 90%,
282
+ oklch(var(--warning-foreground)) 10%
283
+ );
284
+
285
+ /* Derived: neutral hover (92% base + 8% paired foreground) */
286
+ --accent-hover: color-mix(
287
+ in oklab,
288
+ oklch(var(--accent)) 92%,
289
+ oklch(var(--accent-foreground)) 8%
290
+ );
291
+
292
+ /* Derived: soft variants (color on transparent) */
293
+ --primary-soft: color-mix(in oklab, oklch(var(--primary)) 15%, transparent);
294
+ --primary-soft-hover: color-mix(
295
+ in oklab,
296
+ oklch(var(--primary)) 20%,
297
+ transparent
298
+ );
299
+ --destructive-soft: color-mix(
300
+ in oklab,
301
+ oklch(var(--destructive)) 15%,
302
+ transparent
303
+ );
304
+ --destructive-soft-hover: color-mix(
305
+ in oklab,
306
+ oklch(var(--destructive)) 20%,
307
+ transparent
308
+ );
309
+ }
310
+
311
+ /* ============================================
312
+ COLOR TOKENS — Dark Mode (OKLCH)
313
+ ============================================ */
314
+
315
+ .dark {
316
+ /* Base */
317
+ --background: 14.05% 0.004 285.8;
318
+ --foreground: 98.48% 0 0;
319
+
320
+ /* Cards & Popovers */
321
+ --card: 16.3% 0.006 285.7;
322
+ --card-foreground: 98.48% 0 0;
323
+ --popover: 14.05% 0.004 285.8;
324
+ --popover-foreground: 98.48% 0 0;
325
+
326
+ /* Primary ramp — metallic zinc (brighter for dark bg) */
327
+ --primary: 55% 0.016 286;
328
+ --primary-light: 87% 0.006 286;
329
+ --primary-middle: 71% 0.015 286;
330
+ --primary-dark: 44% 0.017 286;
331
+ --primary-foreground: 100% 0 0;
332
+
333
+ /* Secondary */
334
+ --secondary: 27% 0.006 286;
335
+ --secondary-foreground: 97% 0.003 265;
336
+
337
+ /* Muted */
338
+ --muted: 27.41% 0.006 286;
339
+ --muted-foreground: 71.19% 0.013 286.1;
340
+
341
+ /* Accent */
342
+ --accent: 27.41% 0.006 286;
343
+ --accent-foreground: 98.48% 0 0;
344
+
345
+ /* Destructive */
346
+ --destructive: 58% 0.16 25.7;
347
+ --destructive-foreground: 98.43% 0 0;
348
+
349
+ /* Status */
350
+ --success: 79.99% 0.182 151.8;
351
+ --success-foreground: 38.98% 0.089 152.7;
352
+ --warning: 86.11% 0.173 92;
353
+ --warning-foreground: 42.36% 0.091 56.8;
354
+ --info: 62.61% 0.186 259.6;
355
+ --info-foreground: 38.14% 0.136 265.3;
356
+
357
+ /* Borders & Input */
358
+ --border: 31.51% 0.007 286;
359
+ --border-light: 37.27% 0.008 286;
360
+ --border-dark: 23.37% 0.004 286.1;
361
+ --input: 27.41% 0.006 286;
362
+ --ring: 55% 0.016 286;
363
+
364
+ /* Surfaces */
365
+ --surface: 16.3% 0.006 285.7;
366
+ --surface-foreground: 98.48% 0 0;
367
+ --surface-secondary: color-mix(
368
+ in oklab,
369
+ oklch(var(--surface)) 94%,
370
+ oklch(var(--surface-foreground)) 6%
371
+ );
372
+ --surface-tertiary: color-mix(
373
+ in oklab,
374
+ oklch(var(--surface)) 88%,
375
+ oklch(var(--surface-foreground)) 12%
376
+ );
377
+ --overlay: 19.5% 0.008 285.7;
378
+ --overlay-foreground: 98.48% 0 0;
379
+
380
+ /* Field */
381
+ --field-background: 16.3% 0.006 285.7;
382
+ --field-border: oklch(100% 0 0 / 0.12);
383
+ --field-border-hover: oklch(100% 0 0 / 0.22);
384
+ --field-border-focus: oklch(100% 0 0 / 0.35);
385
+ --field-border-invalid: oklch(var(--destructive));
386
+ --machine-bg: 2.8% 0 0;
387
+ --machine-panel: 4.4% 0 0;
388
+ --machine-panel-raised: 7.2% 0 0;
389
+ --machine-fg: 98% 0 0;
390
+ --machine-fg-muted: 88% 0 0;
391
+ --machine-fg-subtle: 72% 0 0;
392
+ --machine-border: 100% 0 0 / 0.22;
393
+ --machine-rule: 100% 0 0 / 0.3;
394
+ --machine-inverse: 96% 0 0;
395
+ --machine-inverse-fg: 8% 0 0;
396
+ --machine-font-size-base: 0.95rem;
397
+ --machine-line-height-base: 1.7;
398
+ --machine-heading-weight: 640;
399
+ --machine-code-size: 0.84rem;
400
+ --machine-content-max: 76ch;
401
+ --machine-section-gap: 2.5rem;
402
+ --machine-block-gap: 1rem;
403
+ --machine-rail-offset: clamp(0.9rem, 2vw, 1.45rem);
404
+
405
+ /* Dark mode shadows — reduced, tonal contrast provides depth */
406
+ --shadow-surface: none;
407
+ --shadow-field: none;
408
+ --shadow-overlay:
409
+ 0 0 0 1px oklch(100% 0 0 / 0.08), 0 8px 30px oklch(0% 0 0 / 0.35);
410
+ --shadow-tooltip:
411
+ 0 0 0 1px oklch(100% 0 0 / 0.1), 0 4px 16px oklch(0% 0 0 / 0.4);
412
+ --shadow-inset-track:
413
+ inset 0 1px 2px oklch(0% 0 0 / 0.12), inset 0 0 0 1px oklch(100% 0 0 / 0.06);
414
+ }
415
+
416
+ /* ============================================
417
+ CSS UTILITIES — Consistency Layer
418
+ Every component references these instead of
419
+ reimplementing focus/disabled/invalid patterns.
420
+ ============================================ */
421
+
422
+ /* Focus ring for buttons, toggles, links, interactive elements */
423
+ @utility focus-ring {
424
+ outline: 2px solid var(--color-ring);
425
+ outline-offset: 2px;
426
+ }
427
+
428
+ /* Focus ring for form field groups — sits on border, no offset */
429
+ @utility focus-field-ring {
430
+ outline: 2px solid var(--color-ring);
431
+ outline-offset: -1px;
432
+ }
433
+
434
+ /* Invalid field outline — destructive border + ring on focus */
435
+ @utility invalid-field-ring {
436
+ outline: 2px solid var(--color-destructive);
437
+ outline-offset: -1px;
438
+ }
439
+
440
+ /* Disabled state — universal across all components */
441
+ @utility status-disabled {
442
+ opacity: 0.5;
443
+ pointer-events: none;
444
+ cursor: not-allowed;
445
+ }
446
+
447
+ /* Pending/loading state — non-interactive but visually unchanged */
448
+ @utility status-pending {
449
+ pointer-events: none;
450
+ }
451
+
452
+ /* Remove tap highlight on mobile */
453
+ @utility no-highlight {
454
+ -webkit-tap-highlight-color: transparent;
455
+ }
456
+
457
+ /* Inset track depth for slider/progress/meter tracks */
458
+ @utility shadow-inset-track {
459
+ box-shadow: var(--shadow-inset-track);
460
+ }
461
+
462
+ /* Hide scrollbar while keeping scroll functionality */
463
+ @utility no-scrollbar {
464
+ -ms-overflow-style: none;
465
+ scrollbar-width: none;
466
+ &::-webkit-scrollbar {
467
+ display: none;
468
+ }
469
+ }
470
+
471
+ /* ============================================
472
+ CUSTOM VARIANTS
473
+ ============================================ */
474
+
475
+ /* Motion reduction — respects prefers-reduced-motion */
476
+ @custom-variant motion-reduce (@media (prefers-reduced-motion: reduce));
477
+ @custom-variant motion-safe (@media (prefers-reduced-motion: no-preference));
478
+
479
+ /* Hover gating — only applies hover styles on devices that support hover */
480
+ @custom-variant hover-only (@media (hover: hover));
481
+
482
+ /* ============================================
483
+ BASE STYLES
484
+ ============================================ */
485
+
486
+ @layer base {
487
+ * {
488
+ @apply border-border;
489
+ }
490
+ body {
491
+ @apply bg-background text-foreground antialiased;
492
+ font-feature-settings:
493
+ "rlig" 1,
494
+ "calt" 1;
495
+ font-synthesis-weight: none;
496
+ text-rendering: optimizeLegibility;
497
+ }
498
+ h1,
499
+ h2,
500
+ h3,
501
+ h4,
502
+ h5,
503
+ h6 {
504
+ font-family: var(--font-heading);
505
+ letter-spacing: -0.02em;
506
+ }
507
+ }
508
+
509
+ /* --- Inline code --- */
510
+ .prose :not(pre) > code {
511
+ border: 1px solid oklch(var(--border));
512
+ background: transparent;
513
+ padding: 0.125rem 0.25rem;
514
+ border-radius: var(--radius-sm);
515
+ font-size: 0.875em;
516
+ }
517
+
518
+ /* --- Prose headings — visual rhythm --- */
519
+ .prose h1 {
520
+ @apply text-3xl font-bold tracking-tight mt-12 mb-4;
521
+ }
522
+
523
+ .prose h2 {
524
+ @apply text-2xl font-semibold tracking-tight mt-12 mb-4;
525
+ }
526
+
527
+ .prose h3 {
528
+ @apply text-xl font-semibold mt-8 mb-3;
529
+ }
530
+
531
+ .prose h4 {
532
+ @apply text-base font-medium mt-6 mb-2;
533
+ }
534
+
535
+ /* ========== PROTOTYPER UI TOKENS END ========== */