@astralform/ui 0.0.0-stage → 0.3.7-next.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 (140) hide show
  1. package/DESIGN.md +243 -0
  2. package/LICENSE +21 -0
  3. package/README.md +128 -2
  4. package/dist/components/Alert.d.ts +7 -0
  5. package/dist/components/Alert.js +40 -0
  6. package/dist/components/Alert.js.map +1 -0
  7. package/dist/components/AvatarEditor.d.ts +13 -0
  8. package/dist/components/AvatarEditor.js +44 -0
  9. package/dist/components/AvatarEditor.js.map +1 -0
  10. package/dist/components/Badge.d.ts +16 -0
  11. package/dist/components/Badge.js +38 -0
  12. package/dist/components/Badge.js.map +1 -0
  13. package/dist/components/Button.d.ts +8 -0
  14. package/dist/components/Button.js +21 -0
  15. package/dist/components/Button.js.map +1 -0
  16. package/dist/components/Card.d.ts +10 -0
  17. package/dist/components/Card.js +22 -0
  18. package/dist/components/Card.js.map +1 -0
  19. package/dist/components/CompactResourceRow.d.ts +34 -0
  20. package/dist/components/CompactResourceRow.js +11 -0
  21. package/dist/components/CompactResourceRow.js.map +1 -0
  22. package/dist/components/ConfirmDialog.d.ts +12 -0
  23. package/dist/components/ConfirmDialog.js +7 -0
  24. package/dist/components/ConfirmDialog.js.map +1 -0
  25. package/dist/components/CookieConsent.d.ts +1 -0
  26. package/dist/components/CookieConsent.js +42 -0
  27. package/dist/components/CookieConsent.js.map +1 -0
  28. package/dist/components/DataTable.d.ts +53 -0
  29. package/dist/components/DataTable.js +79 -0
  30. package/dist/components/DataTable.js.map +1 -0
  31. package/dist/components/DevTools.d.ts +6 -0
  32. package/dist/components/DevTools.js +59 -0
  33. package/dist/components/DevTools.js.map +1 -0
  34. package/dist/components/EmptyState.d.ts +11 -0
  35. package/dist/components/EmptyState.js +6 -0
  36. package/dist/components/EmptyState.js.map +1 -0
  37. package/dist/components/ImageCropModal.d.ts +18 -0
  38. package/dist/components/ImageCropModal.js +67 -0
  39. package/dist/components/ImageCropModal.js.map +1 -0
  40. package/dist/components/InlineBanner.d.ts +20 -0
  41. package/dist/components/InlineBanner.js +53 -0
  42. package/dist/components/InlineBanner.js.map +1 -0
  43. package/dist/components/Input.d.ts +8 -0
  44. package/dist/components/Input.js +10 -0
  45. package/dist/components/Input.js.map +1 -0
  46. package/dist/components/InventoryCard.d.ts +20 -0
  47. package/dist/components/InventoryCard.js +22 -0
  48. package/dist/components/InventoryCard.js.map +1 -0
  49. package/dist/components/LoadingSpinner.d.ts +26 -0
  50. package/dist/components/LoadingSpinner.js +32 -0
  51. package/dist/components/LoadingSpinner.js.map +1 -0
  52. package/dist/components/Modal.d.ts +10 -0
  53. package/dist/components/Modal.js +38 -0
  54. package/dist/components/Modal.js.map +1 -0
  55. package/dist/components/PageHeader.d.ts +11 -0
  56. package/dist/components/PageHeader.js +5 -0
  57. package/dist/components/PageHeader.js.map +1 -0
  58. package/dist/components/PreviewModal.d.ts +24 -0
  59. package/dist/components/PreviewModal.js +69 -0
  60. package/dist/components/PreviewModal.js.map +1 -0
  61. package/dist/components/ProgressBar.d.ts +8 -0
  62. package/dist/components/ProgressBar.js +12 -0
  63. package/dist/components/ProgressBar.js.map +1 -0
  64. package/dist/components/ProviderIcon.d.ts +7 -0
  65. package/dist/components/ProviderIcon.js +34 -0
  66. package/dist/components/ProviderIcon.js.map +1 -0
  67. package/dist/components/ResizeHandle.d.ts +56 -0
  68. package/dist/components/ResizeHandle.js +166 -0
  69. package/dist/components/ResizeHandle.js.map +1 -0
  70. package/dist/components/SegmentedProgressBar.d.ts +9 -0
  71. package/dist/components/SegmentedProgressBar.js +23 -0
  72. package/dist/components/SegmentedProgressBar.js.map +1 -0
  73. package/dist/components/Select.d.ts +13 -0
  74. package/dist/components/Select.js +14 -0
  75. package/dist/components/Select.js.map +1 -0
  76. package/dist/components/SpotlightButton.d.ts +10 -0
  77. package/dist/components/SpotlightButton.js +51 -0
  78. package/dist/components/SpotlightButton.js.map +1 -0
  79. package/dist/components/StatCard.d.ts +9 -0
  80. package/dist/components/StatCard.js +8 -0
  81. package/dist/components/StatCard.js.map +1 -0
  82. package/dist/components/StatusBadge.d.ts +4 -0
  83. package/dist/components/StatusBadge.js +10 -0
  84. package/dist/components/StatusBadge.js.map +1 -0
  85. package/dist/components/TabNav.d.ts +39 -0
  86. package/dist/components/TabNav.js +25 -0
  87. package/dist/components/TabNav.js.map +1 -0
  88. package/dist/components/TableShell.d.ts +21 -0
  89. package/dist/components/TableShell.js +19 -0
  90. package/dist/components/TableShell.js.map +1 -0
  91. package/dist/components/Textarea.d.ts +7 -0
  92. package/dist/components/Textarea.js +10 -0
  93. package/dist/components/Textarea.js.map +1 -0
  94. package/dist/components/Toggle.d.ts +16 -0
  95. package/dist/components/Toggle.js +25 -0
  96. package/dist/components/Toggle.js.map +1 -0
  97. package/dist/components/Toolbar.d.ts +34 -0
  98. package/dist/components/Toolbar.js +30 -0
  99. package/dist/components/Toolbar.js.map +1 -0
  100. package/dist/components/TypeToConfirmModal.d.ts +15 -0
  101. package/dist/components/TypeToConfirmModal.js +14 -0
  102. package/dist/components/TypeToConfirmModal.js.map +1 -0
  103. package/dist/components/UnsavedChangesModal.d.ts +7 -0
  104. package/dist/components/UnsavedChangesModal.js +7 -0
  105. package/dist/components/UnsavedChangesModal.js.map +1 -0
  106. package/dist/components/UsageCard.d.ts +11 -0
  107. package/dist/components/UsageCard.js +9 -0
  108. package/dist/components/UsageCard.js.map +1 -0
  109. package/dist/components/avatar.d.ts +79 -0
  110. package/dist/components/avatar.js +88 -0
  111. package/dist/components/avatar.js.map +1 -0
  112. package/dist/components/badge-config.d.ts +16 -0
  113. package/dist/components/badge-config.js +48 -0
  114. package/dist/components/badge-config.js.map +1 -0
  115. package/dist/components/glowing-effect.d.ts +14 -0
  116. package/dist/components/glowing-effect.js +108 -0
  117. package/dist/components/glowing-effect.js.map +1 -0
  118. package/dist/index.d.ts +39 -0
  119. package/dist/index.js +42 -0
  120. package/dist/index.js.map +1 -0
  121. package/dist/lib/cookies.d.ts +36 -0
  122. package/dist/lib/cookies.js +78 -0
  123. package/dist/lib/cookies.js.map +1 -0
  124. package/dist/lib/environment.d.ts +24 -0
  125. package/dist/lib/environment.js +52 -0
  126. package/dist/lib/environment.js.map +1 -0
  127. package/dist/lib/utils.d.ts +4 -0
  128. package/dist/lib/utils.js +8 -0
  129. package/dist/lib/utils.js.map +1 -0
  130. package/dist/types.d.ts +12 -0
  131. package/dist/types.js +12 -0
  132. package/dist/types.js.map +1 -0
  133. package/package.json +89 -4
  134. package/src/styles/base.css +779 -0
  135. package/src/styles/fonts.css +25 -0
  136. package/src/styles/theme-default.css +164 -0
  137. package/src/styles/theme-default.generated.css +79 -0
  138. package/src/styles/tokens/_foundations.css +28 -0
  139. package/src/styles/tokens/_semantics.css +72 -0
  140. package/themes/chat.DESIGN.md +197 -0
@@ -0,0 +1,779 @@
1
+ /* ==============================================
2
+ @astralform/ui — base.css (brand-agnostic structure)
3
+ ==============================================
4
+
5
+ Everything that does NOT change per brand: radius scale, layout
6
+ dimensions, base element styles, the @utility set the components
7
+ rely on (focus-ring, type-*, page-content), and the full animation /
8
+ keyframe / enhancement library.
9
+
10
+ Pair this with EXACTLY ONE theme file (theme-default.css or your own
11
+ product theme generated from a DESIGN.md). Consumer order:
12
+
13
+ @import "tailwindcss";
14
+ @import "@astralform/ui/styles/base.css";
15
+ @import "@astralform/ui/styles/theme-default.css";
16
+ @source "../node_modules/@astralform/ui/dist"; // Tailwind v4 must scan our classes
17
+ ============================================== */
18
+
19
+ @import "./tokens/_foundations.css";
20
+ @import "./tokens/_semantics.css";
21
+
22
+ /* ============================================
23
+ STRUCTURAL DESIGN TOKENS (brand-independent)
24
+ ============================================ */
25
+
26
+ @theme inline {
27
+ /* Semantic Radius */
28
+ --radius-input: 0.5rem;
29
+ --radius-button: 0.5rem;
30
+ --radius-card: 1.25rem;
31
+ --radius-modal: 0.75rem;
32
+ --radius-badge: 9999px;
33
+ --radius-alert: 0.5rem;
34
+
35
+ /* Layout Dimensions — app-shell widths consumed by each product's layout.
36
+ Tailwind v4 maps --width-* to w-* and --spacing-* to padding utilities. */
37
+ --width-sidebar: 12rem;
38
+ --width-sidebar-collapsed: 3.25rem;
39
+ --width-workspace: 28rem;
40
+ --height-header: 4rem;
41
+ --spacing-sidebar: 12rem;
42
+ --spacing-sidebar-collapsed: 3.25rem;
43
+ --spacing-workspace: 28rem;
44
+ }
45
+
46
+ @layer base {
47
+ html {
48
+ scroll-behavior: smooth;
49
+ color-scheme: dark;
50
+ }
51
+
52
+ body {
53
+ @apply bg-surface-base text-text-primary antialiased;
54
+ font-family: var(--font-body);
55
+ }
56
+
57
+ h1, h2, h3, h4, h5, h6 {
58
+ font-family: var(--font-heading);
59
+ @apply tracking-tight;
60
+ }
61
+ }
62
+
63
+ /* ============================================
64
+ DESIGN SYSTEM UTILITIES
65
+ ============================================ */
66
+
67
+ /* Unified focus ring — replaces 4+ different focus ring patterns */
68
+ @utility focus-ring {
69
+ &:focus-visible {
70
+ outline: var(--focus-ring-width) solid var(--focus-ring-color);
71
+ outline-offset: var(--focus-ring-offset);
72
+ }
73
+ }
74
+
75
+ /* Typography role utilities */
76
+ @utility type-page-title {
77
+ font-size: var(--type-page-title-size);
78
+ font-weight: var(--type-page-title-weight);
79
+ line-height: var(--type-page-title-leading);
80
+ font-family: var(--type-page-title-family);
81
+ color: var(--color-text-primary);
82
+ }
83
+
84
+ @utility type-card-title {
85
+ font-size: var(--type-card-title-size);
86
+ font-weight: var(--type-card-title-weight);
87
+ line-height: var(--type-card-title-leading);
88
+ letter-spacing: var(--type-card-title-tracking);
89
+ font-family: var(--type-card-title-family);
90
+ color: var(--color-text-primary);
91
+ }
92
+
93
+ @utility type-label {
94
+ font-size: var(--type-label-size);
95
+ font-weight: var(--type-label-weight);
96
+ line-height: var(--type-label-leading);
97
+ color: var(--color-text-secondary);
98
+ }
99
+
100
+ /* Page content padding utility — replaces repeated `px-6 lg:px-16` */
101
+ @utility page-content {
102
+ padding-left: clamp(1rem, 4%, 4rem);
103
+ padding-right: clamp(1rem, 4%, 4rem);
104
+ }
105
+
106
+ /* ============================================
107
+ ANIMATION KEYFRAMES
108
+ ============================================ */
109
+
110
+ @keyframes fadeInUp {
111
+ from { opacity: 0; transform: translateY(20px); }
112
+ to { opacity: 1; transform: translateY(0); }
113
+ }
114
+
115
+ @keyframes fadeInScale {
116
+ from { opacity: 0; transform: scale(0.95); }
117
+ to { opacity: 1; transform: scale(1); }
118
+ }
119
+
120
+ @keyframes float {
121
+ 0%, 100% { transform: translateY(0px) rotate(0deg); }
122
+ 50% { transform: translateY(-10px) rotate(1deg); }
123
+ }
124
+
125
+ @keyframes pulseGlow {
126
+ 0%, 100% { box-shadow: 0 0 20px rgba(255, 255, 255, 0.2); }
127
+ 50% { box-shadow: 0 0 40px rgba(255, 255, 255, 0.4); }
128
+ }
129
+
130
+ @keyframes gradientShift {
131
+ 0%, 100% { background-position: 0% 50%; }
132
+ 50% { background-position: 100% 50%; }
133
+ }
134
+
135
+ @keyframes drawCheck {
136
+ 0% { stroke-dashoffset: 100; }
137
+ 100% { stroke-dashoffset: 0; }
138
+ }
139
+
140
+ @keyframes scaleBounce {
141
+ 0% { transform: scale(0); }
142
+ 50% { transform: scale(1.2); }
143
+ 100% { transform: scale(1); }
144
+ }
145
+
146
+ @keyframes confettiFall {
147
+ 0% { transform: translateY(-100%) rotate(0deg); opacity: 1; }
148
+ 100% { transform: translateY(100vh) rotate(720deg); opacity: 0; }
149
+ }
150
+
151
+ @keyframes shimmer {
152
+ 0% { background-position: 200% 0; }
153
+ 100% { background-position: -200% 0; }
154
+ }
155
+
156
+ @keyframes blink {
157
+ 0%, 50% { opacity: 1; }
158
+ 51%, 100% { opacity: 0; }
159
+ }
160
+
161
+ @keyframes staggerFadeIn {
162
+ from { opacity: 0; transform: translateY(10px); }
163
+ to { opacity: 1; transform: translateY(0); }
164
+ }
165
+
166
+ /* ============================================
167
+ UTILITY CLASSES
168
+ ============================================ */
169
+
170
+ .animate-fade-in-up {
171
+ opacity: 0;
172
+ animation: fadeInUp 0.6s var(--ease-out-expo) forwards;
173
+ }
174
+
175
+ .animate-fade-in-scale {
176
+ opacity: 0;
177
+ animation: fadeInScale 0.5s var(--ease-out-expo) forwards;
178
+ }
179
+
180
+ .animate-float { animation: float 6s ease-in-out infinite; }
181
+ .animate-pulse-glow { animation: pulseGlow 3s ease-in-out infinite; }
182
+
183
+ .animate-gradient {
184
+ background-size: 200% 200%;
185
+ animation: gradientShift 8s ease infinite;
186
+ }
187
+
188
+ .animate-draw-check {
189
+ stroke-dasharray: 100;
190
+ stroke-dashoffset: 100;
191
+ animation: drawCheck 0.5s var(--ease-out-expo) 0.2s forwards;
192
+ }
193
+
194
+ .animate-scale-bounce { animation: scaleBounce 0.5s var(--ease-out-back) forwards; }
195
+
196
+ .animate-shimmer {
197
+ background: linear-gradient(
198
+ 90deg,
199
+ transparent 0%,
200
+ rgba(255, 255, 255, 0.1) 50%,
201
+ transparent 100%
202
+ );
203
+ background-size: 200% 100%;
204
+ animation: shimmer 2s infinite;
205
+ }
206
+
207
+ /* Text shimmer for ThinkingBlock — gradient sweeps across text */
208
+ .thinking-shimmer-text {
209
+ background: linear-gradient(
210
+ 90deg,
211
+ var(--color-text-muted) 0%,
212
+ var(--color-text-muted) 40%,
213
+ var(--color-text-secondary) 50%,
214
+ var(--color-text-muted) 60%,
215
+ var(--color-text-muted) 100%
216
+ );
217
+ background-size: 200% 100%;
218
+ -webkit-background-clip: text;
219
+ background-clip: text;
220
+ -webkit-text-fill-color: transparent;
221
+ animation: shimmer 2s ease-in-out infinite;
222
+ }
223
+
224
+ /* Stagger delays */
225
+ .stagger-1 { animation-delay: 0.1s; }
226
+ .stagger-2 { animation-delay: 0.2s; }
227
+ .stagger-3 { animation-delay: 0.3s; }
228
+ .stagger-4 { animation-delay: 0.4s; }
229
+ .stagger-5 { animation-delay: 0.5s; }
230
+ .stagger-6 { animation-delay: 0.6s; }
231
+
232
+ .animate-on-load { opacity: 0; }
233
+
234
+ /* ============================================
235
+ BACKGROUND PATTERNS & TEXTURES
236
+ ============================================ */
237
+
238
+ .bg-dot-pattern {
239
+ background-image: radial-gradient(circle, rgba(255, 255, 255, 0.08) 1px, transparent 1px);
240
+ background-size: 24px 24px;
241
+ }
242
+
243
+ .bg-gradient-orbs::before,
244
+ .bg-gradient-orbs::after {
245
+ content: '';
246
+ position: absolute;
247
+ border-radius: 50%;
248
+ filter: blur(80px);
249
+ opacity: 0.3;
250
+ pointer-events: none;
251
+ }
252
+
253
+ .bg-gradient-orbs::before {
254
+ width: 400px;
255
+ height: 400px;
256
+ background: linear-gradient(135deg, rgba(63, 63, 70, 0.6), rgba(39, 39, 42, 0.4));
257
+ top: -100px;
258
+ right: -100px;
259
+ }
260
+
261
+ .bg-gradient-orbs::after {
262
+ width: 300px;
263
+ height: 300px;
264
+ background: linear-gradient(135deg, rgba(63, 63, 70, 0.4), rgba(39, 39, 42, 0.3));
265
+ bottom: -50px;
266
+ left: -50px;
267
+ }
268
+
269
+ .bg-noise::before {
270
+ content: '';
271
+ position: absolute;
272
+ inset: 0;
273
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
274
+ opacity: 0.03;
275
+ pointer-events: none;
276
+ }
277
+
278
+ /* ============================================
279
+ COMPONENT ENHANCEMENTS
280
+ ============================================ */
281
+
282
+ .btn-press { transition: all 0.15s var(--ease-out-expo); }
283
+ .btn-press:active { transform: scale(0.97); }
284
+
285
+ .btn-gradient {
286
+ position: relative;
287
+ overflow: hidden;
288
+ transition: all 0.3s var(--ease-out-expo);
289
+ }
290
+
291
+ .btn-gradient::before {
292
+ content: '';
293
+ position: absolute;
294
+ inset: 0;
295
+ background: linear-gradient(135deg, rgba(255,255,255,0.2) 0%, transparent 50%, rgba(255,255,255,0.1) 100%);
296
+ opacity: 0;
297
+ transition: opacity 0.3s ease;
298
+ }
299
+
300
+ .btn-gradient:hover::before { opacity: 1; }
301
+
302
+ .btn-gradient:hover {
303
+ box-shadow: 0 10px 40px -10px rgba(255, 255, 255, 0.3);
304
+ transform: translateY(-2px);
305
+ }
306
+
307
+ .card-hover { transition: all 0.3s var(--ease-out-expo); }
308
+
309
+ .card-hover:hover {
310
+ transform: translateY(-4px);
311
+ box-shadow: 0 20px 40px -15px rgba(255, 255, 255, 0.1);
312
+ }
313
+
314
+ .feature-card {
315
+ position: relative;
316
+ transition: transform 0.4s var(--ease-out-expo), box-shadow 0.4s var(--ease-out-expo);
317
+ }
318
+
319
+ .feature-card:hover {
320
+ transform: translateY(-2px);
321
+ box-shadow: 0 12px 32px -8px rgba(255, 255, 255, 0.1);
322
+ }
323
+
324
+ .animated-border {
325
+ --border-width: 2px;
326
+ --border-progress: 0;
327
+ transition: opacity 0.3s ease;
328
+ }
329
+
330
+ .animated-border::before {
331
+ content: '';
332
+ position: absolute;
333
+ inset: 0;
334
+ border-radius: inherit;
335
+ padding: var(--border-width);
336
+ background: conic-gradient(
337
+ from -90deg,
338
+ #ffffff 0%,
339
+ #a1a1aa calc(var(--border-progress) * 50%),
340
+ #71717a calc(var(--border-progress) * 100%),
341
+ transparent calc(var(--border-progress) * 100%),
342
+ transparent 100%
343
+ );
344
+ -webkit-mask:
345
+ linear-gradient(#fff 0 0) content-box,
346
+ linear-gradient(#fff 0 0);
347
+ mask:
348
+ linear-gradient(#fff 0 0) content-box,
349
+ linear-gradient(#fff 0 0);
350
+ -webkit-mask-composite: xor;
351
+ mask-composite: exclude;
352
+ animation: border-fill 0.6s var(--ease-out-expo) forwards;
353
+ }
354
+
355
+ @keyframes border-fill {
356
+ from { --border-progress: 0; }
357
+ to { --border-progress: 1; }
358
+ }
359
+
360
+ @property --border-progress {
361
+ syntax: '<number>';
362
+ initial-value: 0;
363
+ inherits: false;
364
+ }
365
+
366
+ @property --active {
367
+ syntax: '<number>';
368
+ initial-value: 0;
369
+ inherits: false;
370
+ }
371
+
372
+ @property --start {
373
+ syntax: '<number>';
374
+ initial-value: 0;
375
+ inherits: false;
376
+ }
377
+
378
+ .icon-container {
379
+ @apply relative flex items-center justify-center rounded-xl;
380
+ transition: all 0.3s var(--ease-out-expo);
381
+ }
382
+
383
+ .feature-card:hover .icon-container { transform: scale(1.1); }
384
+
385
+ /* ============================================
386
+ SUCCESS CELEBRATION STYLES
387
+ ============================================ */
388
+
389
+ .success-circle {
390
+ @apply relative flex items-center justify-center;
391
+ width: 80px;
392
+ height: 80px;
393
+ }
394
+
395
+ .success-circle::before {
396
+ content: '';
397
+ position: absolute;
398
+ width: 96px;
399
+ height: 96px;
400
+ top: 50%;
401
+ left: 50%;
402
+ transform: translate(-50%, -50%);
403
+ border-radius: 50%;
404
+ background: linear-gradient(135deg, color-mix(in srgb, var(--_success-muted) 20%, transparent), color-mix(in srgb, var(--_success) 10%, transparent));
405
+ animation: successCircleBounce 0.6s var(--ease-out-back) forwards;
406
+ }
407
+
408
+ @keyframes successCircleBounce {
409
+ 0% { transform: translate(-50%, -50%) scale(0); }
410
+ 50% { transform: translate(-50%, -50%) scale(1.2); }
411
+ 100% { transform: translate(-50%, -50%) scale(1); }
412
+ }
413
+
414
+ .confetti-container {
415
+ position: fixed;
416
+ inset: 0;
417
+ pointer-events: none;
418
+ overflow: hidden;
419
+ z-index: 100;
420
+ }
421
+
422
+ .confetti-piece {
423
+ position: absolute;
424
+ width: 10px;
425
+ height: 10px;
426
+ top: -20px;
427
+ animation: confettiFall 3s linear forwards;
428
+ }
429
+
430
+ /* ============================================
431
+ HERO CHAT MOCKUP ENHANCEMENTS
432
+ ============================================ */
433
+
434
+ .chat-mockup {
435
+ @apply relative;
436
+ animation: float 6s ease-in-out infinite, fadeInScale 0.8s var(--ease-out-expo) 0.3s forwards;
437
+ opacity: 0;
438
+ }
439
+
440
+ .chat-mockup::before {
441
+ content: '';
442
+ position: absolute;
443
+ inset: -20px;
444
+ background: linear-gradient(135deg, rgba(63, 63, 70, 0.3), rgba(39, 39, 42, 0.2));
445
+ border-radius: 30px;
446
+ filter: blur(20px);
447
+ z-index: -1;
448
+ }
449
+
450
+ .typing-indicator { @apply flex gap-1; }
451
+
452
+ .typing-indicator span {
453
+ @apply w-2 h-2 rounded-full bg-text-muted;
454
+ animation: typingBounce 1.4s infinite ease-in-out;
455
+ }
456
+
457
+ .typing-indicator span:nth-child(1) { animation-delay: 0s; }
458
+ .typing-indicator span:nth-child(2) { animation-delay: 0.2s; }
459
+ .typing-indicator span:nth-child(3) { animation-delay: 0.4s; }
460
+
461
+ @keyframes typingBounce {
462
+ 0%, 60%, 100% { transform: translateY(0); }
463
+ 30% { transform: translateY(-4px); }
464
+ }
465
+
466
+ /* ============================================
467
+ MODAL ENHANCEMENTS
468
+ ============================================ */
469
+
470
+ .modal-backdrop {
471
+ @apply fixed inset-0 bg-surface-overlay backdrop-blur-sm;
472
+ animation: fadeIn 0.2s ease forwards;
473
+ }
474
+
475
+ .modal-content {
476
+ animation: modalEnter 0.3s var(--ease-out-back) forwards;
477
+ }
478
+
479
+ @keyframes fadeIn {
480
+ from { opacity: 0; }
481
+ to { opacity: 1; }
482
+ }
483
+
484
+ @keyframes modalEnter {
485
+ from { opacity: 0; transform: scale(0.95) translateY(10px); }
486
+ to { opacity: 1; transform: scale(1) translateY(0); }
487
+ }
488
+
489
+ /* ============================================
490
+ NAVIGATION ENHANCEMENTS
491
+ ============================================ */
492
+
493
+ .nav-link { @apply relative; }
494
+
495
+ .nav-link::after {
496
+ content: '';
497
+ position: absolute;
498
+ bottom: -2px;
499
+ left: 0;
500
+ width: 0;
501
+ height: 2px;
502
+ background: linear-gradient(90deg, rgb(255, 255, 255), rgb(161, 161, 170));
503
+ transition: width 0.3s var(--ease-out-expo);
504
+ }
505
+
506
+ .nav-link:hover::after { width: 100%; }
507
+
508
+ /* Sidebar group connector lines */
509
+ .sidebar-connector-item {
510
+ position: relative;
511
+ padding-left: 28px;
512
+ }
513
+
514
+ .sidebar-connector-item::before {
515
+ content: '';
516
+ position: absolute;
517
+ left: 14px;
518
+ top: 0;
519
+ bottom: 0;
520
+ border-left: 1.5px dashed rgb(63, 63, 70);
521
+ pointer-events: none;
522
+ }
523
+
524
+ .sidebar-connector-item:last-child::before { bottom: 50%; }
525
+
526
+ .sidebar-connector-item::after {
527
+ content: '';
528
+ position: absolute;
529
+ left: 14px;
530
+ top: 50%;
531
+ width: 10px;
532
+ border-top: 1.5px dashed rgb(63, 63, 70);
533
+ pointer-events: none;
534
+ }
535
+
536
+ .ease-out-expo { transition-timing-function: var(--ease-out-expo); }
537
+
538
+ .logo-hover { transition: all 0.3s var(--ease-out-expo); }
539
+ .logo-hover:hover { transform: scale(1.05); }
540
+ .logo-hover:hover .logo-icon { box-shadow: 0 0 20px rgba(255, 255, 255, 0.3); }
541
+
542
+ /* ============================================
543
+ INPUT ENHANCEMENTS
544
+ ============================================ */
545
+
546
+ .input-enhanced { @apply transition-all duration-300; }
547
+
548
+ .input-enhanced:focus {
549
+ @apply ring-2 ring-white/30;
550
+ box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.1);
551
+ }
552
+
553
+ /* ============================================
554
+ SCROLLBAR HIDE UTILITY
555
+ ============================================ */
556
+
557
+ .scrollbar-hide {
558
+ -ms-overflow-style: none;
559
+ scrollbar-width: none;
560
+ }
561
+ .scrollbar-hide::-webkit-scrollbar { display: none; }
562
+
563
+ /* ============================================
564
+ SCROLLBAR STYLING
565
+ ============================================ */
566
+
567
+ ::-webkit-scrollbar { width: 8px; height: 8px; }
568
+ ::-webkit-scrollbar-track { background: rgb(23, 23, 23); border-radius: 4px; }
569
+ ::-webkit-scrollbar-thumb { background: rgb(63, 63, 70); border-radius: 4px; }
570
+ ::-webkit-scrollbar-thumb:hover { background: rgb(82, 82, 91); }
571
+
572
+ /* ============================================
573
+ SELECTION STYLING
574
+ ============================================ */
575
+
576
+ ::selection {
577
+ background: rgba(255, 255, 255, 0.2);
578
+ color: rgb(255, 255, 255);
579
+ }
580
+
581
+ /* ============================================
582
+ GLOWING EFFECT COMPONENT
583
+ ============================================ */
584
+
585
+ .glow {
586
+ position: absolute;
587
+ inset: 0;
588
+ border-radius: inherit;
589
+ }
590
+
591
+ /* ============================================
592
+ MARQUEE ANIMATION
593
+ ============================================ */
594
+
595
+ @keyframes marquee {
596
+ from { transform: translateX(0); }
597
+ to { transform: translateX(calc(-100% - var(--gap))); }
598
+ }
599
+
600
+ .animate-marquee { animation: marquee var(--duration) linear infinite; }
601
+
602
+ /* ============================================
603
+ SCROLL SNAP UTILITIES
604
+ ============================================ */
605
+
606
+ .scroll-snap-y-mandatory { scroll-snap-type: y mandatory; }
607
+ .scroll-snap-start { scroll-snap-align: start; }
608
+ .scroll-snap-stop { scroll-snap-stop: always; }
609
+
610
+ /* ============================================
611
+ DOT INDICATOR ANIMATIONS
612
+ ============================================ */
613
+
614
+ @keyframes dotPulse {
615
+ 0%, 100% { box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.4); }
616
+ 50% { box-shadow: 0 0 0 6px rgba(255, 255, 255, 0); }
617
+ }
618
+
619
+ .animate-dot-pulse { animation: dotPulse 2s ease-in-out infinite; }
620
+
621
+ /* ============================================
622
+ LIQUID GLOB — animated highlight inside a rounded square
623
+ ============================================ */
624
+
625
+ @keyframes liquid-move {
626
+ 0%, 100% { top: 0px; left: 0px; }
627
+ 25% { top: 0px; left: 4px; }
628
+ 50% { top: 4px; left: 3px; }
629
+ 75% { top: 3px; left: 0px; }
630
+ }
631
+
632
+ @keyframes morphDot {
633
+ 0% { border-radius: 50%; }
634
+ 50% { border-radius: 25%; }
635
+ 100% { border-radius: 50%; }
636
+ }
637
+
638
+ @keyframes spinDot {
639
+ from { transform: rotate(0deg); }
640
+ to { transform: rotate(360deg); }
641
+ }
642
+
643
+ .thinking-morph-dot {
644
+ display: inline-block;
645
+ width: 14px;
646
+ height: 14px;
647
+ background: radial-gradient(circle at 35% 35%, var(--color-accent-hover), var(--color-accent) 50%, var(--color-accent-muted));
648
+ border-radius: 50%;
649
+ animation: morphDot 2s ease-in-out infinite, spinDot 3s linear infinite;
650
+ flex-shrink: 0;
651
+ }
652
+
653
+ @keyframes pill-shimmer {
654
+ 0% { transform: translateX(-100%); }
655
+ 100% { transform: translateX(100%); }
656
+ }
657
+
658
+ .animate-pill-shimmer::after {
659
+ content: "";
660
+ position: absolute;
661
+ inset: 0;
662
+ border-radius: inherit;
663
+ background: linear-gradient(
664
+ 90deg,
665
+ transparent 0%,
666
+ rgba(255, 255, 255, 0.06) 45%,
667
+ rgba(255, 255, 255, 0.1) 50%,
668
+ rgba(255, 255, 255, 0.06) 55%,
669
+ transparent 100%
670
+ );
671
+ animation: pill-shimmer 2s ease-in-out infinite;
672
+ }
673
+
674
+ .animate-dot-enter { animation: fadeInScale 0.3s var(--ease-out-expo) forwards; }
675
+
676
+ /* ============================================
677
+ CHROMA BUTTON ANIMATION
678
+ ============================================ */
679
+
680
+ @property --chroma-angle {
681
+ syntax: '<angle>';
682
+ initial-value: 0deg;
683
+ inherits: false;
684
+ }
685
+
686
+ @keyframes chromaSpin {
687
+ from { --chroma-angle: 0deg; }
688
+ to { --chroma-angle: 360deg; }
689
+ }
690
+
691
+ .animate-chroma-spin { animation: chromaSpin 3s linear infinite; }
692
+
693
+ /* ============================================
694
+ SONNER TOAST OVERRIDES
695
+ ============================================ */
696
+
697
+ [data-sonner-toaster] {
698
+ font-family: var(--font-body), system-ui, sans-serif !important;
699
+ }
700
+
701
+ [data-sonner-toast] {
702
+ --normal-bg: var(--color-surface-secondary) !important;
703
+ --normal-border: var(--color-border-primary) !important;
704
+ --normal-text: var(--color-text-primary) !important;
705
+ border-radius: 10px !important;
706
+ padding: 12px 16px !important;
707
+ font-size: 13px !important;
708
+ line-height: 1.5 !important;
709
+ gap: 8px !important;
710
+ align-items: center !important;
711
+ box-shadow: 0 8px 24px -4px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(63, 63, 70, 0.4) !important;
712
+ }
713
+
714
+ [data-sonner-toast] [data-icon] { flex-shrink: 0 !important; }
715
+
716
+ [data-sonner-toast] [data-content] {
717
+ display: flex !important;
718
+ flex-direction: column !important;
719
+ gap: 2px !important;
720
+ }
721
+
722
+ [data-sonner-toast] [data-title] {
723
+ font-weight: 500 !important;
724
+ font-size: 13px !important;
725
+ line-height: 1.4 !important;
726
+ }
727
+
728
+ [data-sonner-toast] [data-description] {
729
+ font-size: 12px !important;
730
+ opacity: 0.7 !important;
731
+ line-height: 1.4 !important;
732
+ }
733
+
734
+ [data-sonner-toast][data-type="success"] {
735
+ --normal-bg: var(--_toast-success-bg) !important;
736
+ --normal-border: var(--_toast-success-border) !important;
737
+ --normal-text: var(--_toast-success-text) !important;
738
+ }
739
+
740
+ [data-sonner-toast][data-type="error"] {
741
+ --normal-bg: var(--_toast-error-bg) !important;
742
+ --normal-border: var(--_toast-error-border) !important;
743
+ --normal-text: var(--_toast-error-text) !important;
744
+ }
745
+
746
+ [data-sonner-toast][data-type="warning"] {
747
+ --normal-bg: var(--_toast-warning-bg) !important;
748
+ --normal-border: var(--_toast-warning-border) !important;
749
+ --normal-text: var(--_toast-warning-text) !important;
750
+ }
751
+
752
+ [data-sonner-toast][data-type="info"] {
753
+ --normal-bg: var(--_toast-info-bg) !important;
754
+ --normal-border: var(--_toast-info-border) !important;
755
+ --normal-text: var(--_toast-info-text) !important;
756
+ }
757
+
758
+ [data-sonner-toast] [data-close-button] {
759
+ background: transparent !important;
760
+ border: 1px solid var(--color-border-secondary) !important;
761
+ color: var(--color-text-tertiary) !important;
762
+ }
763
+
764
+ [data-sonner-toast] [data-close-button]:hover {
765
+ background: var(--color-surface-tertiary) !important;
766
+ color: var(--color-text-primary) !important;
767
+ }
768
+
769
+ /* ============================================
770
+ REDUCED MOTION
771
+ ============================================ */
772
+
773
+ @media (prefers-reduced-motion: reduce) {
774
+ *, *::before, *::after {
775
+ animation-duration: 0.01ms !important;
776
+ animation-iteration-count: 1 !important;
777
+ transition-duration: 0.01ms !important;
778
+ }
779
+ }