@ponti-studios/ui 0.1.2 → 0.3.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 (114) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +7 -7
  3. package/THIRD_PARTY_NOTICES.md +17 -0
  4. package/dist/index.js +1028 -638
  5. package/dist/index.js.map +1 -1
  6. package/package.json +30 -32
  7. package/src/animations.css +16 -434
  8. package/src/components/data-display/accordion.tsx +10 -7
  9. package/src/components/data-display/filter-chip.tsx +2 -2
  10. package/src/components/data-display/index.ts +5 -0
  11. package/src/components/data-display/metric-card.stories.tsx +48 -0
  12. package/src/components/data-display/metric-card.tsx +20 -0
  13. package/src/components/data-display/sort-controls.stories.tsx +45 -0
  14. package/src/components/data-display/sort-controls.tsx +99 -0
  15. package/src/components/data-display/sort-row.tsx +74 -0
  16. package/src/components/data-display/table.tsx +5 -5
  17. package/src/components/feedback/alert.tsx +4 -4
  18. package/src/components/feedback/empty-state.tsx +6 -6
  19. package/src/components/feedback/file-upload-status-badge.stories.tsx +28 -0
  20. package/src/components/feedback/file-upload-status-badge.tsx +33 -0
  21. package/src/components/feedback/file-upload-status.stories.tsx +57 -0
  22. package/src/components/feedback/file-upload-status.tsx +152 -0
  23. package/src/components/feedback/index.ts +9 -0
  24. package/src/components/feedback/progress-bar.stories.tsx +39 -0
  25. package/src/components/feedback/progress-bar.tsx +21 -0
  26. package/src/components/feedback/progress.stories.tsx +8 -6
  27. package/src/components/feedback/progress.tsx +1 -1
  28. package/src/components/feedback/skeleton.stories.tsx +36 -0
  29. package/src/components/feedback/skeleton.tsx +7 -0
  30. package/src/components/feedback/spinner.tsx +2 -2
  31. package/src/components/feedback/update-guard.stories.tsx +32 -0
  32. package/src/components/feedback/update-guard.tsx +280 -0
  33. package/src/components/forms/calendar.tsx +11 -11
  34. package/src/components/forms/date-month-select.stories.tsx +26 -0
  35. package/src/components/forms/date-month-select.tsx +70 -0
  36. package/src/components/forms/date-picker.tsx +3 -3
  37. package/src/components/forms/drop-zone.stories.tsx +56 -0
  38. package/src/components/forms/drop-zone.tsx +146 -0
  39. package/src/components/forms/entity-select.stories.tsx +65 -0
  40. package/src/components/forms/entity-select.tsx +79 -0
  41. package/src/components/forms/field.tsx +3 -3
  42. package/src/components/forms/group-by-select.stories.tsx +26 -0
  43. package/src/components/forms/group-by-select.tsx +47 -0
  44. package/src/components/forms/index.ts +10 -0
  45. package/src/components/forms/input.stories.tsx +4 -4
  46. package/src/components/forms/input.tsx +1 -1
  47. package/src/components/forms/passkey-management.stories.tsx +81 -0
  48. package/src/components/forms/passkey-management.tsx +138 -0
  49. package/src/components/forms/radio-group.tsx +14 -13
  50. package/src/components/forms/select.stories.tsx +4 -4
  51. package/src/components/forms/select.tsx +45 -53
  52. package/src/components/forms/slider.stories.tsx +5 -2
  53. package/src/components/forms/slider.tsx +27 -17
  54. package/src/components/forms/stepper.tsx +4 -4
  55. package/src/components/forms/switch.stories.tsx +1 -1
  56. package/src/components/forms/switch.tsx +2 -2
  57. package/src/components/forms/textarea.stories.tsx +2 -2
  58. package/src/components/forms/textarea.tsx +1 -1
  59. package/src/components/layout/index.ts +3 -0
  60. package/src/components/layout/scroll-area.stories.tsx +4 -4
  61. package/src/components/layout/scroll-area.tsx +23 -21
  62. package/src/components/layout/section-intro.stories.tsx +29 -0
  63. package/src/components/layout/section-intro.tsx +31 -0
  64. package/src/components/layout/surface-panel.stories.tsx +32 -0
  65. package/src/components/layout/surface-panel.tsx +15 -0
  66. package/src/components/navigation/app-navigation.stories.tsx +2 -2
  67. package/src/components/navigation/app-navigation.tsx +13 -13
  68. package/src/components/navigation/index.ts +4 -0
  69. package/src/components/navigation/pagination-controls.stories.tsx +41 -0
  70. package/src/components/navigation/pagination-controls.tsx +50 -0
  71. package/src/components/navigation/route-link.stories.tsx +30 -0
  72. package/src/components/navigation/route-link.tsx +42 -0
  73. package/src/components/navigation/tabs.stories.tsx +5 -5
  74. package/src/components/navigation/tabs.tsx +7 -7
  75. package/src/components/overlays/alert-dialog.tsx +21 -46
  76. package/src/components/overlays/command.tsx +51 -82
  77. package/src/components/overlays/dialog.tsx +5 -5
  78. package/src/components/overlays/dropdown-menu.stories.tsx +0 -5
  79. package/src/components/overlays/dropdown-menu.tsx +44 -142
  80. package/src/components/overlays/popover.stories.tsx +2 -2
  81. package/src/components/overlays/popover.tsx +34 -16
  82. package/src/components/overlays/sheet.stories.tsx +2 -2
  83. package/src/components/overlays/sheet.tsx +35 -17
  84. package/src/components/primitives/avatar.tsx +3 -3
  85. package/src/components/primitives/badge.tsx +7 -11
  86. package/src/components/primitives/button.tsx +41 -13
  87. package/src/components/primitives/card.stories.tsx +2 -2
  88. package/src/components/primitives/card.tsx +2 -2
  89. package/src/components/primitives/index.ts +2 -0
  90. package/src/components/primitives/label.stories.tsx +1 -1
  91. package/src/components/primitives/label.tsx +5 -6
  92. package/src/components/primitives/status-badge.stories.tsx +52 -0
  93. package/src/components/primitives/status-badge.tsx +33 -0
  94. package/src/constants/chart-colors.ts +5 -5
  95. package/src/hooks/index.ts +1 -0
  96. package/src/hooks/use-sort.ts +20 -0
  97. package/src/index.ts +30 -11
  98. package/src/styles.css +76 -1040
  99. package/src/tokens/color-systems.stories.tsx +9 -119
  100. package/src/tokens/foundations.stories.tsx +21 -113
  101. package/src/tokens/generated/dark.colors.generated.ts +56 -0
  102. package/src/tokens/generated/dark.css +54 -0
  103. package/src/tokens/generated/foundations.css +148 -0
  104. package/src/tokens/generated/foundations.generated.ts +443 -0
  105. package/src/tokens/generated/light.colors.generated.ts +56 -0
  106. package/src/tokens/generated/light.css +54 -0
  107. package/src/tokens/index.ts +74 -16
  108. package/src/tokens/layout.stories.tsx +3 -108
  109. package/src/tokens/colors.ts +0 -156
  110. package/src/tokens/motion.ts +0 -51
  111. package/src/tokens/radii.ts +0 -10
  112. package/src/tokens/shadows.ts +0 -34
  113. package/src/tokens/spacing.ts +0 -30
  114. package/src/tokens/typography.ts +0 -42
package/src/styles.css CHANGED
@@ -1,1052 +1,88 @@
1
1
  @import "tailwindcss";
2
+ @import "./tokens/generated/foundations.css";
3
+ @import "./tokens/generated/light.css";
4
+ @import "./tokens/generated/dark.css" (prefers-color-scheme: dark);
2
5
  @import "./animations.css";
3
6
 
4
- /* Shared page and content rhythm primitives. These are CSS-only layout
5
- * patterns so feature pages can compose them without adding component APIs. */
6
- .page-shell {
7
- @apply relative mx-auto flex w-full flex-col gap-12 px-4 py-16 md:gap-16 md:px-6 md:py-20;
8
- }
9
-
10
- .page-shell-detail {
11
- @apply relative mx-auto flex w-full flex-col gap-10 px-4 py-16 md:gap-12 md:px-6 md:py-20;
12
- }
13
-
14
- .page-bleed {
15
- @apply flex w-full flex-col;
16
- }
17
-
18
- .layout-stack {
19
- @apply flex flex-col gap-4;
20
- }
21
-
22
- .list-row {
23
- @apply flex gap-4 px-0 py-6 md:gap-6 md:py-8;
24
- }
25
-
26
- .list-media {
27
- @apply border-subtle bg-panel relative isolate flex shrink-0 items-center justify-center overflow-hidden rounded-md border p-2 shadow-none;
28
- }
29
-
30
- .list-media-wide {
31
- @apply h-14 w-32;
32
- }
33
-
34
- .list-media-square {
35
- @apply size-10 sm:size-12;
36
- }
37
-
38
- .list-media-placeholder {
39
- @apply pointer-events-none absolute inset-0 flex items-center justify-center gap-1.5 transition-opacity duration-150;
40
- }
41
-
42
- .section {
43
- @apply border-subtle flex flex-col gap-4 border-b px-4 py-12 md:px-6 md:py-16;
44
- }
45
-
46
- .section-hero {
47
- @apply gap-6 py-16 md:py-20;
48
- }
49
-
50
- .detail-hero {
51
- @apply gap-4 py-10 md:gap-6 md:py-16;
52
- }
53
-
54
- .section-compact {
55
- @apply gap-4 py-8 md:py-12;
56
- }
57
-
58
- .detail-navigation {
59
- @apply flex flex-col gap-6 sm:flex-row sm:justify-between;
60
- }
61
-
62
- .detail-navigation-link {
63
- @apply flex min-h-11 flex-col justify-center gap-1;
64
- }
65
-
66
- .navigation-shell {
67
- @apply bg-canvas/80 border-subtle sticky top-0 z-50 flex w-full justify-center border-b px-4 backdrop-blur-sm backdrop-saturate-150;
68
- }
69
-
70
- .navigation {
71
- @apply w-full max-w-7xl;
72
- }
73
-
74
- .navigation-inner {
75
- @apply flex min-h-14 items-center justify-between gap-6;
76
- }
77
-
78
- .navigation-start,
79
- .navigation-end,
80
- .navigation-mobile {
81
- @apply flex items-center;
82
- }
83
-
84
- .navigation-start {
85
- @apply min-w-0;
86
- }
87
-
88
- .navigation-end {
89
- @apply ml-auto hidden min-w-0 gap-1 sm:flex;
90
- }
91
-
92
- .navigation-mobile {
93
- @apply sm:hidden;
94
- }
95
-
96
- .navigation-panel-links {
97
- @apply mt-8 flex flex-1 flex-col gap-1;
98
- }
99
-
100
- .navigation-panel-end {
101
- @apply border-default flex flex-col gap-4 border-t pt-4;
102
- }
103
-
104
- .navigation-panel-content {
105
- @apply flex items-center gap-3;
106
- }
107
-
108
- .navigation-link {
109
- @apply inline-flex min-h-11 shrink-0 items-center justify-center gap-1.5 rounded-md border border-transparent px-3 py-1.5 text-sm leading-5 font-medium whitespace-nowrap transition-colors duration-150;
110
- }
111
-
112
- .navigation-link:hover {
113
- @apply bg-surface-hover text-primary;
114
- }
115
-
116
- .navigation-link:active {
117
- @apply bg-surface-pressed;
118
- }
119
-
120
- .navigation-link[aria-current="page"] {
121
- @apply bg-panel text-primary;
122
- }
123
-
124
- .navigation-link[aria-current="page"]:hover {
125
- @apply bg-surface-hover;
126
- }
127
-
128
- .navigation-brand {
129
- @apply border-transparent bg-transparent px-2;
130
- }
131
-
132
- .navigation-cta {
133
- @apply inline-flex min-h-11 shrink-0 items-center justify-center gap-1.5 rounded-md border px-3 py-1.5 text-sm leading-5 font-medium whitespace-nowrap transition-colors duration-150;
134
- }
135
-
136
- .navigation-end > .navigation-cta {
137
- @apply ml-2;
138
- }
139
-
140
- .navigation-panel-links .navigation-link,
141
- .navigation-panel-links .navigation-cta,
142
- .navigation-panel-end .navigation-cta {
143
- @apply w-full justify-start;
144
- }
145
-
146
- .navigation-cta[data-variant="outline"] {
147
- @apply border-default text-primary bg-transparent;
148
- }
149
-
150
- .navigation-cta[data-variant="outline"]:hover {
151
- @apply bg-surface-hover;
152
- }
153
-
154
- .navigation-cta[data-variant="outline"]:active {
155
- @apply bg-surface-pressed;
156
- }
157
-
158
- .navigation-cta:not([data-variant="outline"]) {
159
- @apply bg-accent text-on-accent border-transparent;
160
- }
161
-
162
- .navigation-cta:not([data-variant="outline"]):hover {
163
- @apply bg-accent-hover;
164
- }
165
-
166
- .navigation-cta:not([data-variant="outline"]):active {
167
- @apply bg-accent-pressed;
168
- }
169
-
170
- /* Overlay material: an intentional surface, not a raw token name in markup. */
171
- .overlay-backdrop {
172
- background: var(--color-overlay-scrim);
173
- backdrop-filter: blur(8px) saturate(85%);
174
- }
175
-
176
- .sheet-edge-left::before,
177
- .sheet-edge-right::before {
178
- top: 0;
179
- bottom: 0;
180
- width: 9rem;
181
- background: radial-gradient(
182
- ellipse at center,
183
- color-mix(in srgb, var(--color-accent) 14%, transparent),
184
- transparent 70%
185
- );
186
- }
187
-
188
- .sheet-edge-left::before {
189
- left: -5rem;
190
- }
191
-
192
- .sheet-edge-right::before {
193
- right: -5rem;
194
- }
195
-
196
- .sheet-edge-top::before,
197
- .sheet-edge-bottom::before {
198
- right: 0;
199
- left: 0;
200
- height: 9rem;
201
- background: radial-gradient(
202
- ellipse at center,
203
- color-mix(in srgb, var(--color-accent) 14%, transparent),
204
- transparent 70%
205
- );
206
- }
207
-
208
- .sheet-edge-top::before {
209
- top: -5rem;
210
- }
211
-
212
- .sheet-edge-bottom::before {
213
- bottom: -5rem;
214
- }
215
-
216
- .sheet-edge-top::after,
217
- .sheet-edge-bottom::after {
218
- right: 8%;
219
- left: 8%;
220
- height: 1px;
221
- background: linear-gradient(
222
- 90deg,
223
- transparent,
224
- color-mix(in srgb, var(--color-text-primary) 24%, transparent) 32%,
225
- color-mix(in srgb, var(--color-accent) 40%, transparent) 50%,
226
- color-mix(in srgb, var(--color-text-primary) 24%, transparent) 68%,
227
- transparent
228
- );
229
- }
230
-
231
- .sheet-edge-top::after {
232
- top: 0;
233
- }
234
-
235
- .sheet-edge-bottom::after {
236
- bottom: 0;
237
- }
238
-
239
- .sheet-edge-left::after,
240
- .sheet-edge-right::after {
241
- top: 8%;
242
- bottom: 8%;
243
- width: 1px;
244
- background: linear-gradient(
245
- 180deg,
246
- transparent,
247
- color-mix(in srgb, var(--color-text-primary) 24%, transparent) 32%,
248
- color-mix(in srgb, var(--color-accent) 40%, transparent) 50%,
249
- color-mix(in srgb, var(--color-text-primary) 24%, transparent) 68%,
250
- transparent
251
- );
252
- }
253
-
254
- .sheet-edge-left::after {
255
- left: 0;
256
- }
257
-
258
- .sheet-edge-right::after {
259
- right: 0;
260
- }
261
-
262
- .sheet-edge-responsive::before {
263
- top: -5rem;
264
- right: 0;
265
- left: 0;
266
- height: 9rem;
267
- background: radial-gradient(
268
- ellipse at center,
269
- color-mix(in srgb, var(--color-accent) 14%, transparent),
270
- transparent 70%
271
- );
272
- }
273
-
274
- .sheet-edge-responsive::after {
275
- top: 0;
276
- right: 8%;
277
- left: 8%;
278
- height: 1px;
279
- background: linear-gradient(
280
- 90deg,
281
- transparent,
282
- color-mix(in srgb, var(--color-text-primary) 24%, transparent) 32%,
283
- color-mix(in srgb, var(--color-accent) 40%, transparent) 50%,
284
- color-mix(in srgb, var(--color-text-primary) 24%, transparent) 68%,
285
- transparent
286
- );
287
- }
288
-
289
- @media (min-width: 768px) {
290
- .sheet-edge-responsive::before {
291
- top: 0;
292
- right: -5rem;
293
- bottom: 0;
294
- left: auto;
295
- width: 9rem;
296
- height: auto;
297
- }
298
-
299
- .sheet-edge-responsive::after {
300
- top: 8%;
301
- right: 0;
302
- bottom: 8%;
303
- left: auto;
304
- width: 1px;
305
- height: auto;
306
- background: linear-gradient(
307
- 180deg,
308
- transparent,
309
- color-mix(in srgb, var(--color-text-primary) 24%, transparent) 32%,
310
- color-mix(in srgb, var(--color-accent) 40%, transparent) 50%,
311
- color-mix(in srgb, var(--color-text-primary) 24%, transparent) 68%,
312
- transparent
313
- );
314
- }
315
- }
316
-
317
- .sheet-glass-control {
318
- background: color-mix(in srgb, var(--color-surface-raised) 62%, transparent);
319
- backdrop-filter: blur(12px);
320
- }
321
-
322
- @theme {
323
- --font-family-primary: -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
324
- --font-family-mono: ui-monospace, monospace;
325
-
326
- /* Public utility names for the canonical surface roles. */
327
- --color-canvas: var(--color-surface-canvas);
328
- --color-panel: var(--color-surface-panel);
329
- --color-raised: var(--color-surface-raised);
330
- --color-inset: var(--color-surface-inset);
331
- --color-focus: var(--color-ring-focus);
332
-
333
- --font-size-large-title: 34px;
334
- --font-size-title-1: 28px;
335
- --font-size-title-2: 22px;
336
- --font-size-title-3: 20px;
337
- --font-size-headline: 17px;
338
- --font-size-body: 17px;
339
- --font-size-callout: 16px;
340
- --font-size-subhead: 15px;
341
- --font-size-footnote: 13px;
342
- --font-size-caption-1: 12px;
343
- --font-size-caption-2: 11px;
344
-
345
- --font-size-xs: 12px;
346
- --font-size-sm: 14px;
347
- --font-size-md: 16px;
348
- --font-size-lg: 18px;
349
- --font-size-xl: 20px;
350
- --font-size-display: 34px;
351
-
352
- --font-weight-regular: 400;
353
- --font-weight-medium: 500;
354
- --font-weight-semibold: 600;
355
- --font-weight-bold: 700;
356
-
357
- --line-height-tight: 1.2;
358
- --line-height-normal: 1.4;
359
- --line-height-relaxed: 1.6;
360
-
361
- --letter-spacing-tight: -0.025em;
362
- --letter-spacing-normal: 0;
363
- --letter-spacing-relaxed: 0.01em;
364
-
365
- /* Canonical Ponti light fallback values used for utility generation. */
366
- --color-surface-canvas: #ffffff;
367
- --color-surface-panel: #f6f8fa;
368
- --color-surface-raised: #ffffff;
369
- --color-surface-inset: color-mix(
370
- in srgb,
371
- var(--color-surface-canvas) 94%,
372
- var(--color-text-primary) 6%
373
- );
374
- --color-overlay-scrim: rgba(31, 35, 40, 0.18);
375
-
376
- --color-text-primary: #25292e;
377
- --color-text-secondary: #59636e;
378
- --color-text-tertiary: #818b98;
379
- --color-text-disabled: #9ea7b3;
380
- --color-text-accent: var(--color-accent);
381
- --color-text-destructive: var(--color-destructive);
382
- --color-text-success: var(--color-success);
383
- --color-text-warning: var(--color-warning);
384
- --color-text-on-success: #ffffff;
385
- --color-text-on-warning: #1c1c1e;
386
-
387
- --color-border-default: #d1d9e0;
388
- --color-border-subtle: rgba(129, 139, 152, 0.2);
389
- --color-border-strong: #8c959f;
390
- --color-border-focus: #0969da;
391
- --color-border-accent: var(--color-accent);
392
- --color-border-destructive: var(--color-destructive);
393
-
394
- --color-success: #1f883d;
395
- --color-warning: #9a6700;
396
- --color-destructive: #cf222e;
397
- --color-destructive-hover: color-mix(in srgb, var(--color-destructive) 88%, white 12%);
398
- --color-destructive-pressed: color-mix(in srgb, var(--color-destructive) 78%, black 22%);
399
- --color-destructive-subtle: color-mix(in srgb, var(--color-destructive) 14%, transparent);
400
-
401
- --color-accent: #0969da;
402
- --color-text-on-accent: #ffffff;
403
- --color-accent-hover: color-mix(in srgb, var(--color-accent) 88%, white 12%);
404
- --color-accent-pressed: color-mix(in srgb, var(--color-accent) 78%, black 22%);
405
- --color-accent-subtle: color-mix(in srgb, var(--color-accent) 14%, transparent);
406
-
407
- --color-text-on-destructive: #ffffff;
408
- --color-ring-focus: #0969da;
409
-
410
- --color-chart-1: #0969da;
411
- --color-chart-2: #1a7f37;
412
- --color-chart-3: #8250df;
413
- --color-chart-4: #bc4c00;
414
- --color-chart-5: #59636e;
415
- --color-chart-positive: #1a7f37;
416
- --color-chart-negative: #cf222e;
417
- --color-chart-neutral: #59636e;
418
-
419
- --color-surface-hover: color-mix(
420
- in srgb,
421
- var(--color-surface-panel) 88%,
422
- var(--color-text-primary) 12%
423
- );
424
- --color-surface-pressed: color-mix(
425
- in srgb,
426
- var(--color-surface-panel) 78%,
427
- var(--color-text-primary) 22%
428
- );
429
- --color-surface-selected: var(--color-accent-subtle);
430
- --color-surface-disabled: var(--color-surface-inset);
431
-
432
- --spacing-1: 4px;
433
- --spacing-2: 8px;
434
- --spacing-3: 12px;
435
- --spacing-4: 16px;
436
- --spacing-5: 24px;
437
- --spacing-6: 32px;
438
- --spacing-7: 48px;
439
- --spacing-8: 64px;
440
-
441
- --content-width-bubble: 36rem;
442
- --content-width-transcript: 44rem;
443
- --content-width-note-preview: 32ch;
444
-
445
- --radius-sm: 4px;
446
- --radius-md: 6px;
447
- --radius-lg: 8px;
448
- --radius-xl: 12px;
449
- --radius-icon: 22%;
450
- --radius: 4px;
451
-
452
- --shadow-low: 0 1px 3px rgba(0, 0, 0, 0.2), 0 1px 2px rgba(0, 0, 0, 0.12);
453
- --shadow-medium: 0 4px 16px rgba(0, 0, 0, 0.24), 0 2px 4px rgba(0, 0, 0, 0.12);
454
- --shadow-high: 0 16px 48px rgba(0, 0, 0, 0.32), 0 4px 12px rgba(0, 0, 0, 0.18);
455
-
456
- --duration-fast: 120ms;
457
- --duration-default: 200ms;
458
- --duration-slow: 320ms;
459
- --ease-default: cubic-bezier(0.25, 0.46, 0.45, 0.94);
460
- --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
461
- --ease-out: cubic-bezier(0, 0, 0.2, 1);
462
- }
463
-
7
+ /* Keep generated token names isolated from Tailwind's standard role names. */
464
8
  :root {
465
- color-scheme: light dark;
466
- --color-surface-canvas: #ffffff;
467
- --color-surface-panel: #f6f8fa;
468
- --color-surface-raised: #ffffff;
469
- --color-overlay-scrim: rgba(31, 35, 40, 0.42);
470
- --color-text-primary: #25292e;
471
- --color-text-secondary: #59636e;
472
- --color-text-tertiary: #818b98;
473
- --color-text-disabled: #9ea7b3;
474
- --color-border-default: #d1d9e0;
475
- --color-border-subtle: rgba(129, 139, 152, 0.2);
476
- --color-border-strong: #8c959f;
477
- --color-border-focus: #0969da;
478
- --color-border-accent: #0969da;
479
- --color-border-destructive: #cf222e;
480
- --color-text-accent: #0969da;
481
- --color-text-destructive: #cf222e;
482
- --color-text-success: #1f883d;
483
- --color-text-warning: #9a6700;
484
- --color-text-on-accent: #ffffff;
485
- --color-text-on-destructive: #ffffff;
486
- --color-text-on-success: #ffffff;
487
- --color-text-on-warning: #1c1c1e;
488
- --color-success: #1f883d;
489
- --color-success-subtle: rgba(31, 136, 61, 0.12);
490
- --color-warning: #9a6700;
491
- --color-warning-subtle: rgba(154, 103, 0, 0.12);
492
- --color-destructive: #cf222e;
493
- --color-destructive-hover: #a40e26;
494
- --color-destructive-pressed: #82071e;
495
- --color-destructive-subtle: rgba(207, 34, 46, 0.12);
496
- --color-accent: #0969da;
497
- --color-accent-hover: #0550ae;
498
- --color-accent-pressed: #033d8b;
499
- --color-accent-subtle: rgba(9, 105, 218, 0.1);
500
- --color-ring-focus: #0969da;
501
- --color-chart-1: #0969da;
502
- --color-chart-2: #1a7f37;
503
- --color-chart-3: #8250df;
504
- --color-chart-4: #bc4c00;
505
- --color-chart-5: #59636e;
506
- --color-chart-positive: #1a7f37;
507
- --color-chart-negative: #cf222e;
508
- --color-chart-neutral: #59636e;
509
- }
510
-
511
- :root[data-color-mode="dark"] {
512
- color-scheme: dark;
513
- --color-surface-canvas: #0d1117;
514
- --color-surface-panel: #161b22;
515
- --color-surface-raised: #21262d;
516
- --color-overlay-scrim: rgba(1, 4, 9, 0.78);
517
- --color-text-primary: #f0f6fc;
518
- --color-text-secondary: #8b949e;
519
- --color-text-tertiary: #6e7681;
520
- --color-text-disabled: #484f58;
521
- --color-border-default: #30363d;
522
- --color-border-subtle: rgba(240, 246, 252, 0.14);
523
- --color-border-strong: #6e7681;
524
- --color-border-focus: #2f81f7;
525
- --color-border-accent: #2f81f7;
526
- --color-border-destructive: #da3633;
527
- --color-text-accent: #58a6ff;
528
- --color-text-destructive: #ff7b72;
529
- --color-text-success: #3fb950;
530
- --color-text-warning: #d29922;
531
- --color-text-on-warning: #0d1117;
532
- --color-success: #238636;
533
- --color-success-subtle: rgba(35, 134, 54, 0.18);
534
- --color-warning: #9e6a03;
535
- --color-warning-subtle: rgba(158, 106, 3, 0.18);
536
- --color-destructive: #da3633;
537
- --color-destructive-hover: #f85149;
538
- --color-destructive-pressed: #b62324;
539
- --color-destructive-subtle: rgba(218, 54, 51, 0.18);
540
- --color-accent: #2f81f7;
541
- --color-accent-hover: #58a6ff;
542
- --color-accent-pressed: #1f6feb;
543
- --color-accent-subtle: rgba(47, 129, 247, 0.18);
544
- --color-ring-focus: #2f81f7;
545
- --color-chart-1: #2f81f7;
546
- --color-chart-2: #3fb950;
547
- --color-chart-3: #a371f7;
548
- --color-chart-4: #d29922;
549
- --color-chart-5: #8b949e;
550
- --color-chart-positive: #3fb950;
551
- --color-chart-negative: #f85149;
552
- --color-chart-neutral: #8b949e;
553
- }
554
-
555
- @media (prefers-color-scheme: dark) {
556
- :root:not([data-color-mode]) {
557
- color-scheme: dark;
558
- --color-surface-canvas: #0d1117;
559
- --color-surface-panel: #161b22;
560
- --color-surface-raised: #21262d;
561
- --color-overlay-scrim: rgba(1, 4, 9, 0.78);
562
- --color-text-primary: #f0f6fc;
563
- --color-text-secondary: #8b949e;
564
- --color-text-tertiary: #6e7681;
565
- --color-text-disabled: #484f58;
566
- --color-border-default: #30363d;
567
- --color-border-subtle: rgba(240, 246, 252, 0.14);
568
- --color-border-strong: #6e7681;
569
- --color-border-focus: #2f81f7;
570
- --color-border-accent: #2f81f7;
571
- --color-border-destructive: #da3633;
572
- --color-text-accent: #58a6ff;
573
- --color-text-destructive: #ff7b72;
574
- --color-text-success: #3fb950;
575
- --color-text-warning: #d29922;
576
- --color-text-on-warning: #0d1117;
577
- --color-success: #238636;
578
- --color-success-subtle: rgba(35, 134, 54, 0.18);
579
- --color-warning: #9e6a03;
580
- --color-warning-subtle: rgba(158, 106, 3, 0.18);
581
- --color-destructive: #da3633;
582
- --color-destructive-hover: #f85149;
583
- --color-destructive-pressed: #b62324;
584
- --color-destructive-subtle: rgba(218, 54, 51, 0.18);
585
- --color-accent: #2f81f7;
586
- --color-accent-hover: #58a6ff;
587
- --color-accent-pressed: #1f6feb;
588
- --color-accent-subtle: rgba(47, 129, 247, 0.18);
589
- --color-ring-focus: #2f81f7;
590
- --color-chart-1: #2f81f7;
591
- --color-chart-2: #3fb950;
592
- --color-chart-3: #a371f7;
593
- --color-chart-4: #d29922;
594
- --color-chart-5: #8b949e;
595
- --color-chart-positive: #3fb950;
596
- --color-chart-negative: #f85149;
597
- --color-chart-neutral: #8b949e;
598
- }
599
- }
600
- @utility pb-safe-area-inset-bottom {
601
- padding-bottom: env(safe-area-inset-bottom);
602
- }
603
-
604
- @utility mb-safe-area-inset-bottom {
605
- margin-bottom: env(safe-area-inset-bottom);
606
- }
607
-
608
- @utility min-h-screen {
609
- min-height: 100vh;
610
- min-height: 100dvh;
611
- }
612
-
613
- @utility min-h-screen-dynamic {
614
- min-height: 100dvh;
615
- }
616
-
617
- @utility h-screen {
618
- height: 100vh;
619
- height: 100dvh;
620
- }
9
+ --ponti-primary: var(--color-accent);
10
+ --ponti-primary-foreground: var(--color-text-on-accent);
11
+ --ponti-destructive: var(--color-destructive);
12
+ --ponti-destructive-foreground: var(--color-text-on-destructive);
13
+ --ponti-foreground: var(--color-text-primary);
14
+ --ponti-muted-foreground: var(--color-text-secondary);
15
+ --ponti-border: var(--color-border-default);
16
+ --ponti-ring: var(--color-ring-focus);
17
+ }
18
+
19
+ /* shadcn New York semantic contract. Values are generated from the DTCG
20
+ * source; this file only names the roles consumed by web components. */
21
+ @theme inline {
22
+ --color-background: var(--color-surface-canvas);
23
+ --color-foreground: var(--ponti-foreground);
24
+ --color-card: var(--color-surface-panel);
25
+ --color-card-foreground: var(--color-text-primary);
26
+ --color-popover: var(--color-surface-raised);
27
+ --color-popover-foreground: var(--color-text-primary);
28
+ --color-primary: var(--ponti-primary);
29
+ --color-primary-foreground: var(--ponti-primary-foreground);
30
+ --color-secondary: var(--color-surface-panel);
31
+ --color-secondary-foreground: var(--color-text-primary);
32
+ --color-muted: var(--color-surface-inset);
33
+ --color-muted-foreground: var(--ponti-muted-foreground);
34
+ --color-accent-foreground: var(--color-text-primary);
35
+ --color-destructive-foreground: var(--ponti-destructive-foreground);
36
+ --color-border: var(--ponti-border);
37
+ --color-input: var(--ponti-border);
38
+ --color-ring: var(--ponti-ring);
39
+ --color-chart-1: var(--color-border-focus);
40
+ --color-chart-2: var(--color-chart-positive);
41
+ --color-chart-3: var(--color-border-focus);
42
+ --color-chart-4: var(--color-text-warning);
43
+ --color-chart-5: var(--color-border-strong);
44
+ }
45
+
46
+ @utility pb-safe-area-inset-bottom { padding-bottom: env(safe-area-inset-bottom); }
47
+ @utility mb-safe-area-inset-bottom { margin-bottom: env(safe-area-inset-bottom); }
48
+ @utility min-h-screen { min-height: 100vh; min-height: 100dvh; }
49
+ @utility min-h-screen-dynamic { min-height: 100dvh; }
50
+ @utility h-screen { height: 100vh; height: 100dvh; }
51
+
52
+ /* Shared layout rhythm. Product components own their layout; this does not
53
+ * define visual component families. */
54
+ .page-shell { @apply relative mx-auto flex w-full flex-col gap-12 px-4 py-16 md:gap-16 md:px-6 md:py-20; }
55
+ .page-shell-detail { @apply relative mx-auto flex w-full flex-col gap-10 px-4 py-16 md:gap-12 md:px-6 md:py-20; }
56
+ .page-bleed { @apply flex w-full flex-col; }
57
+ .layout-stack { @apply flex flex-col gap-4; }
58
+ .list-row { @apply flex gap-4 px-0 py-6 md:gap-6 md:py-8; }
59
+ .list-media { @apply relative isolate flex shrink-0 items-center justify-center overflow-hidden rounded-md border border-border bg-card p-2 shadow-none; }
60
+ .list-media-wide { @apply h-14 w-32; }
61
+ .list-media-square { @apply size-10 sm:size-12; }
62
+ .list-media-placeholder { @apply pointer-events-none absolute inset-0 flex items-center justify-center gap-1.5 transition-opacity duration-150; }
63
+ .section { @apply flex flex-col gap-4 border-b border-border px-4 py-12 md:px-6 md:py-16; }
64
+ .section-hero { @apply gap-6 py-16 md:py-20; }
65
+ .detail-hero { @apply gap-4 py-10 md:gap-6 md:py-16; }
66
+ .section-compact { @apply gap-4 py-8 md:py-12; }
67
+ .detail-navigation { @apply flex flex-col gap-6 sm:flex-row sm:justify-between; }
68
+ .detail-navigation-link { @apply flex min-h-11 flex-col justify-center gap-1; }
621
69
 
622
70
  @layer base {
623
- html,
624
- body {
625
- font-family: var(--font-family-primary);
626
- color-scheme: light dark;
627
- background-color: var(--color-surface-canvas);
628
- color: var(--color-text-primary);
71
+ :root { color-scheme: light; }
72
+ @media (prefers-color-scheme: dark) { :root { color-scheme: dark; } }
73
+ html, body {
74
+ background-color: var(--color-background);
75
+ color: var(--color-foreground);
76
+ font-family: var(--font-sans);
629
77
  -webkit-font-smoothing: antialiased;
630
78
  -moz-osx-font-smoothing: grayscale;
631
79
  }
632
-
633
- *:focus {
634
- outline: none;
635
- }
636
-
637
- *:focus-visible {
638
- outline: 2px solid var(--color-ring-focus);
639
- outline-offset: 2px;
640
- border-radius: inherit;
641
- }
642
-
643
- * {
644
- transition: none;
645
- }
646
-
647
- *:is(button, a, input, select, textarea, [role="button"], [role="link"]) {
648
- transition-property: background-color, color, border-color, opacity;
649
- transition-duration: var(--duration-fast);
650
- transition-timing-function: var(--ease-default);
651
- }
652
-
653
- *,
654
- ::after,
655
- ::before,
656
- ::backdrop,
657
- ::file-selector-button {
658
- border-color: var(--color-border-default, currentColor);
659
- }
660
-
661
- button {
662
- cursor: pointer;
663
- font-family: inherit;
664
- }
665
-
666
- [data-radix-portal] {
667
- z-index: 9999;
668
- }
669
-
670
- h1,
671
- h2,
672
- h3,
673
- h4,
674
- h5,
675
- h6 {
676
- font-family: var(--font-family-primary);
677
- font-weight: var(--font-weight-semibold);
678
- letter-spacing: var(--letter-spacing-tight);
679
- }
680
-
80
+ * { border-color: var(--color-border, currentColor); }
81
+ *:focus { outline: none; }
82
+ *:focus-visible { outline: 2px solid var(--color-ring); outline-offset: 2px; border-radius: inherit; }
83
+ button { cursor: pointer; font-family: inherit; }
84
+ h1, h2, h3, h4, h5, h6 { font-family: var(--font-sans); font-weight: 600; letter-spacing: var(--tracking-tight); }
681
85
  @media (prefers-reduced-motion: reduce) {
682
- * {
683
- animation-duration: 0.01ms !important;
684
- animation-iteration-count: 1 !important;
685
- transition-duration: 0.01ms !important;
686
- }
86
+ *, ::before, ::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; }
687
87
  }
688
88
  }
689
-
690
- @utility bg-canvas {
691
- background-color: var(--color-surface-canvas);
692
- }
693
-
694
- @utility bg-panel {
695
- background-color: var(--color-surface-panel);
696
- }
697
-
698
- @utility bg-raised {
699
- background-color: var(--color-surface-raised);
700
- }
701
-
702
- @utility bg-inset {
703
- background-color: var(--color-surface-inset);
704
- }
705
-
706
- @utility bg-overlay-scrim {
707
- background-color: var(--color-overlay-scrim);
708
- }
709
-
710
- @utility text-primary {
711
- color: var(--color-text-primary);
712
- }
713
-
714
- @utility text-secondary {
715
- color: var(--color-text-secondary);
716
- }
717
-
718
- @utility text-tertiary {
719
- color: var(--color-text-tertiary);
720
- }
721
-
722
- @utility text-disabled {
723
- color: var(--color-text-disabled);
724
- }
725
-
726
- @utility text-on-accent {
727
- color: var(--color-text-on-accent);
728
- }
729
-
730
- @utility text-on-destructive {
731
- color: var(--color-text-on-destructive);
732
- }
733
-
734
- @utility ring-focus {
735
- --tw-ring-color: var(--color-ring-focus);
736
- }
737
-
738
- @utility border-default {
739
- border-color: var(--color-border-default);
740
- }
741
-
742
- @utility border-subtle {
743
- border-color: var(--color-border-subtle);
744
- }
745
-
746
- @utility border-focus {
747
- border-color: var(--color-border-focus);
748
- }
749
-
750
- @utility display-1 {
751
- font-size: clamp(2.5rem, 5vw, 6rem);
752
- font-family: var(--font-family-primary);
753
- font-weight: var(--font-weight-bold);
754
- line-height: 1.1;
755
- letter-spacing: var(--letter-spacing-tight);
756
- }
757
-
758
- @utility display-2 {
759
- font-size: clamp(2rem, 3vw, 3.5rem);
760
- font-family: var(--font-family-primary);
761
- font-weight: var(--font-weight-bold);
762
- line-height: 1.15;
763
- letter-spacing: var(--letter-spacing-tight);
764
- }
765
-
766
- @utility heading-1 {
767
- font-size: clamp(2rem, 3vw, 2.75rem);
768
- font-family: var(--font-family-primary);
769
- font-weight: var(--font-weight-semibold);
770
- line-height: 1.2;
771
- letter-spacing: var(--letter-spacing-tight);
772
- }
773
-
774
- @utility heading-2 {
775
- font-size: clamp(1.375rem, 2vw, 1.75rem);
776
- font-family: var(--font-family-primary);
777
- font-weight: var(--font-weight-semibold);
778
- line-height: 1.25;
779
- letter-spacing: -0.02em;
780
- }
781
-
782
- @utility heading-3 {
783
- font-size: clamp(1.125rem, 1.5vw, 1.375rem);
784
- font-family: var(--font-family-primary);
785
- font-weight: var(--font-weight-semibold);
786
- line-height: 1.3;
787
- letter-spacing: -0.015em;
788
- }
789
-
790
- @utility heading-4 {
791
- font-size: clamp(1rem, 1.25vw, 1.125rem);
792
- font-family: var(--font-family-primary);
793
- font-weight: var(--font-weight-semibold);
794
- line-height: 1.4;
795
- letter-spacing: -0.01em;
796
- }
797
-
798
- @utility largeTitle {
799
- font-size: var(--font-size-large-title);
800
- font-family: var(--font-family-primary);
801
- font-weight: var(--font-weight-bold);
802
- line-height: 1.1;
803
- letter-spacing: var(--letter-spacing-tight);
804
- }
805
-
806
- @utility title1 {
807
- font-size: var(--font-size-title-1);
808
- font-family: var(--font-family-primary);
809
- font-weight: var(--font-weight-bold);
810
- line-height: 1.2;
811
- letter-spacing: var(--letter-spacing-tight);
812
- }
813
-
814
- @utility headline {
815
- font-size: var(--font-size-headline);
816
- font-family: var(--font-family-primary);
817
- font-weight: var(--font-weight-semibold);
818
- line-height: 1.3;
819
- letter-spacing: -0.01em;
820
- }
821
-
822
- @utility body {
823
- font-size: var(--font-size-body);
824
- font-family: var(--font-family-primary);
825
- font-weight: var(--font-weight-regular);
826
- line-height: 1.4;
827
- letter-spacing: var(--letter-spacing-normal);
828
- }
829
-
830
- @utility callout {
831
- font-size: var(--font-size-callout);
832
- font-family: var(--font-family-primary);
833
- font-weight: var(--font-weight-regular);
834
- line-height: 1.38;
835
- letter-spacing: var(--letter-spacing-normal);
836
- }
837
-
838
- @utility subhead {
839
- font-size: var(--font-size-subhead);
840
- font-family: var(--font-family-primary);
841
- font-weight: var(--font-weight-regular);
842
- line-height: 1.33;
843
- letter-spacing: var(--letter-spacing-normal);
844
- }
845
-
846
- @utility footnote {
847
- font-size: var(--font-size-footnote);
848
- font-family: var(--font-family-primary);
849
- font-weight: var(--font-weight-regular);
850
- line-height: 1.38;
851
- letter-spacing: var(--letter-spacing-normal);
852
- }
853
-
854
- @utility caption1 {
855
- font-size: var(--font-size-caption-1);
856
- font-family: var(--font-family-primary);
857
- font-weight: var(--font-weight-regular);
858
- line-height: 1.33;
859
- letter-spacing: var(--letter-spacing-normal);
860
- }
861
-
862
- @utility caption2 {
863
- font-size: var(--font-size-caption-2);
864
- font-family: var(--font-family-primary);
865
- font-weight: var(--font-weight-medium);
866
- line-height: 1.27;
867
- letter-spacing: var(--letter-spacing-normal);
868
- }
869
-
870
- @utility mono {
871
- font-size: var(--font-size-caption-1);
872
- font-family: var(--font-family-mono);
873
- font-weight: var(--font-weight-regular);
874
- line-height: 1.33;
875
- letter-spacing: var(--letter-spacing-normal);
876
- }
877
-
878
- @utility body-1 {
879
- font-size: clamp(1rem, 1.25vw, 1.0625rem);
880
- font-family: var(--font-family-primary);
881
- font-weight: var(--font-weight-regular);
882
- line-height: 1.6;
883
- letter-spacing: var(--letter-spacing-normal);
884
- }
885
-
886
- @utility body-2 {
887
- font-size: clamp(0.875rem, 1vw, 1rem);
888
- font-family: var(--font-family-primary);
889
- font-weight: var(--font-weight-regular);
890
- line-height: 1.5;
891
- letter-spacing: var(--letter-spacing-normal);
892
- }
893
-
894
- @utility body-3 {
895
- font-size: 0.9375rem;
896
- font-family: var(--font-family-primary);
897
- font-weight: var(--font-weight-regular);
898
- line-height: 1.47;
899
- letter-spacing: -0.015em;
900
- }
901
-
902
- @utility body-4 {
903
- font-size: 0.8125rem;
904
- font-family: var(--font-family-primary);
905
- font-weight: var(--font-weight-regular);
906
- line-height: 1.38;
907
- letter-spacing: -0.005em;
908
- }
909
-
910
- @utility subheading-1 {
911
- font-size: clamp(1.125rem, 1.5vw, 1.375rem);
912
- font-family: var(--font-family-primary);
913
- font-weight: var(--font-weight-medium);
914
- line-height: 1.35;
915
- letter-spacing: -0.02em;
916
- }
917
-
918
- @utility subheading-2 {
919
- font-size: clamp(1rem, 1.25vw, 1.25rem);
920
- font-family: var(--font-family-primary);
921
- font-weight: var(--font-weight-medium);
922
- line-height: 1.4;
923
- letter-spacing: -0.015em;
924
- }
925
-
926
- @utility subheading-3 {
927
- font-size: 1rem;
928
- font-family: var(--font-family-primary);
929
- font-weight: var(--font-weight-medium);
930
- line-height: 1.33;
931
- letter-spacing: -0.01em;
932
- }
933
-
934
- @utility subheading-4 {
935
- font-size: 0.9375rem;
936
- font-family: var(--font-family-primary);
937
- font-weight: var(--font-weight-medium);
938
- line-height: 1.33;
939
- letter-spacing: -0.008em;
940
- }
941
-
942
- @utility hover-surface {
943
- transition-property: background-color, color, border-color, opacity;
944
- transition-duration: var(--duration-fast);
945
- transition-timing-function: var(--ease-default);
946
-
947
- @media (hover: hover) {
948
- &:not(:disabled):not([data-disabled]):hover {
949
- background-color: var(--color-surface-hover);
950
- border-color: var(--color-border-default);
951
- color: var(--color-text-primary);
952
- }
953
- }
954
- }
955
-
956
- @utility list-row {
957
- display: flex;
958
- align-items: stretch;
959
-
960
- & > * {
961
- display: flex;
962
- align-items: center;
963
- }
964
- }
965
-
966
- @utility content-width-bubble {
967
- max-inline-size: var(--content-width-bubble);
968
- }
969
-
970
- @utility content-width-transcript {
971
- max-inline-size: var(--content-width-transcript);
972
- }
973
-
974
- @utility content-width-note-preview {
975
- max-inline-size: var(--content-width-note-preview);
976
- }
977
-
978
- @utility ui-eyebrow {
979
- font-size: var(--font-size-caption-1);
980
- font-weight: var(--font-weight-medium);
981
- text-transform: uppercase;
982
- letter-spacing: 0.16em;
983
- color: var(--color-text-secondary);
984
- }
985
-
986
- @utility ui-plain-card {
987
- border: 1px solid var(--color-border-default);
988
- padding: 1.75rem;
989
- }
990
-
991
- @utility ui-flat-card {
992
- border: 1px solid var(--color-border-default);
993
- background-color: var(--color-surface-panel);
994
- border-radius: var(--radius-md);
995
- padding: 1rem;
996
- }
997
-
998
- @utility ui-data-value {
999
- font-size: 1.5rem;
1000
- font-weight: var(--font-weight-regular);
1001
- font-variant-numeric: tabular-nums;
1002
- color: var(--color-text-primary);
1003
- }
1004
-
1005
- @utility ui-data-label {
1006
- font-size: var(--font-size-caption-1);
1007
- font-weight: var(--font-weight-medium);
1008
- text-transform: uppercase;
1009
- letter-spacing: 0.16em;
1010
- color: var(--color-text-secondary);
1011
- }
1012
-
1013
- @utility ui-dash-list-item {
1014
- display: flex;
1015
- gap: 0.5rem;
1016
- font-size: var(--font-size-sm);
1017
- line-height: 1.5rem;
1018
- color: var(--color-text-primary);
1019
- }
1020
-
1021
- @utility ui-dash-marker {
1022
- margin-top: 0.125rem;
1023
- flex-shrink: 0;
1024
- color: var(--color-text-secondary);
1025
- }
1026
-
1027
- @utility scrollbar-hide {
1028
- -ms-overflow-style: none;
1029
- scrollbar-width: none;
1030
- &::-webkit-scrollbar {
1031
- display: none;
1032
- }
1033
- }
1034
-
1035
- @layer utilities {
1036
- .container {
1037
- width: 100%;
1038
- padding-inline: 1rem;
1039
- margin-inline: auto;
1040
- }
1041
-
1042
- @media (min-width: 640px) {
1043
- .container {
1044
- padding-inline: 1.5rem;
1045
- }
1046
- }
1047
- }
1048
-
1049
- /* Links share one focus language; individual links should not need to opt in. */
1050
- a:focus-visible {
1051
- @apply ring-focus ring-2 ring-offset-2 outline-none;
1052
- }