@fileflow/sdk 0.1.13 → 0.1.14

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.
@@ -0,0 +1,1329 @@
1
+ /* NOTE: @tailwind base is intentionally omitted to prevent global style leaks.
2
+ Preflight is disabled in tailwind.config.js. Tailwind CSS variable defaults
3
+ are scoped to .fileflow-sdk-root below.
4
+
5
+ IMPORTANT: @tailwind utilities MUST come AFTER the scoped resets below.
6
+ The scoped reset (.fileflow-sdk-root *) and Tailwind utility classes
7
+ (e.g. .ff-border) have equal specificity (0,1,0). CSS uses source order
8
+ as the tiebreaker, so utilities must come last to win. */
9
+ @tailwind components;
10
+
11
+ /* ============================================
12
+ FileFlow SDK Styles
13
+ PaySpace Design System (from Figma)
14
+
15
+ Color Token System:
16
+ - Primitives: Raw color values from Figma
17
+ - Tokens: Semantic tokens referencing primitives
18
+
19
+ Source of truth: packages/shared/src/styles/color-tokens.ts
20
+
21
+ STYLE ISOLATION:
22
+ All styles are scoped to .fileflow-sdk-root to prevent
23
+ leaking styles to or inheriting from the host application.
24
+ ============================================ */
25
+
26
+ /* ============================================
27
+ SDK Root - Style Isolation Container
28
+ Prevents host styles from affecting SDK components
29
+ and prevents SDK styles from leaking out.
30
+ ============================================ */
31
+
32
+ .fileflow-sdk-root {
33
+ /* Reset all inherited properties */
34
+ all: revert;
35
+
36
+ /* Establish new stacking context */
37
+ isolation: isolate;
38
+
39
+ /* Reset typography */
40
+ font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
41
+ font-size: 16px;
42
+ line-height: 1.5;
43
+ font-weight: 400;
44
+ -webkit-font-smoothing: antialiased;
45
+ -moz-osx-font-smoothing: grayscale;
46
+
47
+ /* Reset box model */
48
+ box-sizing: border-box;
49
+
50
+ /* Reset colors */
51
+ color: #21201d;
52
+ background-color: transparent;
53
+
54
+ /* Reset text */
55
+ text-align: left;
56
+ direction: ltr;
57
+ text-rendering: optimizeLegibility;
58
+
59
+ /* Reset spacing */
60
+ margin: 0;
61
+ padding: 0;
62
+
63
+ /* ----------------------------------------
64
+ Tailwind CSS variable defaults (scoped)
65
+ These are normally set by @tailwind base on *, ::before, ::after
66
+ but we scope them here to prevent global leaks.
67
+ ---------------------------------------- */
68
+ --tw-border-spacing-x: 0;
69
+ --tw-border-spacing-y: 0;
70
+ --tw-translate-x: 0;
71
+ --tw-translate-y: 0;
72
+ --tw-rotate: 0;
73
+ --tw-skew-x: 0;
74
+ --tw-skew-y: 0;
75
+ --tw-scale-x: 1;
76
+ --tw-scale-y: 1;
77
+ --tw-pan-x: ;
78
+ --tw-pan-y: ;
79
+ --tw-pinch-zoom: ;
80
+ --tw-scroll-snap-strictness: proximity;
81
+ --tw-gradient-from-position: ;
82
+ --tw-gradient-via-position: ;
83
+ --tw-gradient-to-position: ;
84
+ --tw-ordinal: ;
85
+ --tw-slashed-zero: ;
86
+ --tw-numeric-figure: ;
87
+ --tw-numeric-spacing: ;
88
+ --tw-numeric-fraction: ;
89
+ --tw-ring-inset: ;
90
+ --tw-ring-offset-width: 0px;
91
+ --tw-ring-offset-color: #fff;
92
+ --tw-ring-color: rgb(59 130 246 / 0.5);
93
+ --tw-ring-offset-shadow: 0 0 #0000;
94
+ --tw-ring-shadow: 0 0 #0000;
95
+ --tw-shadow: 0 0 #0000;
96
+ --tw-shadow-colored: 0 0 #0000;
97
+ --tw-blur: ;
98
+ --tw-brightness: ;
99
+ --tw-contrast: ;
100
+ --tw-grayscale: ;
101
+ --tw-hue-rotate: ;
102
+ --tw-invert: ;
103
+ --tw-saturate: ;
104
+ --tw-sepia: ;
105
+ --tw-drop-shadow: ;
106
+ --tw-backdrop-blur: ;
107
+ --tw-backdrop-brightness: ;
108
+ --tw-backdrop-contrast: ;
109
+ --tw-backdrop-grayscale: ;
110
+ --tw-backdrop-hue-rotate: ;
111
+ --tw-backdrop-invert: ;
112
+ --tw-backdrop-opacity: ;
113
+ --tw-backdrop-saturate: ;
114
+ --tw-backdrop-sepia: ;
115
+ }
116
+
117
+ /* Ensure all children inherit box-sizing and Tailwind CSS variable defaults */
118
+ .fileflow-sdk-root *,
119
+ .fileflow-sdk-root *::before,
120
+ .fileflow-sdk-root *::after {
121
+ box-sizing: border-box;
122
+ border-width: 0;
123
+ border-style: solid;
124
+ border-color: currentColor;
125
+ --tw-ring-inset: ;
126
+ --tw-ring-offset-width: 0px;
127
+ --tw-ring-offset-color: #fff;
128
+ --tw-ring-color: rgb(59 130 246 / 0.5);
129
+ --tw-ring-offset-shadow: 0 0 #0000;
130
+ --tw-ring-shadow: 0 0 #0000;
131
+ --tw-shadow: 0 0 #0000;
132
+ --tw-shadow-colored: 0 0 #0000;
133
+ }
134
+
135
+ /* Reset common elements within SDK root */
136
+ .fileflow-sdk-root button,
137
+ .fileflow-sdk-root input,
138
+ .fileflow-sdk-root select,
139
+ .fileflow-sdk-root textarea {
140
+ font-family: inherit;
141
+ font-size: inherit;
142
+ line-height: inherit;
143
+ margin: 0;
144
+ }
145
+
146
+ .fileflow-sdk-root button {
147
+ cursor: pointer;
148
+ background: none;
149
+ border: none;
150
+ padding: 0;
151
+ }
152
+
153
+ .fileflow-sdk-root img,
154
+ .fileflow-sdk-root svg {
155
+ display: block;
156
+ max-width: 100%;
157
+ }
158
+
159
+ .fileflow-sdk-root a {
160
+ color: inherit;
161
+ text-decoration: inherit;
162
+ }
163
+
164
+ .fileflow-sdk-root h1,
165
+ .fileflow-sdk-root h2,
166
+ .fileflow-sdk-root h3,
167
+ .fileflow-sdk-root h4,
168
+ .fileflow-sdk-root h5,
169
+ .fileflow-sdk-root h6 {
170
+ font-size: inherit;
171
+ font-weight: inherit;
172
+ margin: 0;
173
+ }
174
+
175
+ .fileflow-sdk-root p,
176
+ .fileflow-sdk-root ul,
177
+ .fileflow-sdk-root ol {
178
+ margin: 0;
179
+ padding: 0;
180
+ }
181
+
182
+ .fileflow-sdk-root ul,
183
+ .fileflow-sdk-root ol {
184
+ list-style: none;
185
+ }
186
+
187
+ /* CSS Variables for theming - Default Theme (Brown Theme from Figma) */
188
+ /* Scoped ONLY to SDK root to prevent conflicts with host app */
189
+ .fileflow-sdk-root {
190
+ /* ----------------------------------------
191
+ PRIMARY BLUE SCALE (Main brand color)
192
+ From Figma: primary blue palette
193
+ ---------------------------------------- */
194
+ --ff-primary-10: #f9fafb;
195
+ --ff-primary-20: #eef0f6;
196
+ --ff-primary-30: #e2e6f0;
197
+ --ff-primary-40: #dce1ec;
198
+ --ff-primary-50: #d7e1f2; /* Main primary background */
199
+ --ff-primary-60: #c6d6f0;
200
+ --ff-primary-70: #c0d0ed; /* Hover state */
201
+ --ff-primary-80: #b9cbeb;
202
+ --ff-primary-90: #728ab3;
203
+ --ff-primary-100: #6980a5;
204
+ --ff-primary-110: #4f6180;
205
+ --ff-primary-120: #132036;
206
+
207
+ /* Convenience aliases */
208
+ --ff-primary-500: #d7e1f2; /* Main for buttons */
209
+ --ff-primary-600: #c0d0ed; /* Hover for buttons */
210
+
211
+ /* ----------------------------------------
212
+ PRIMARY BROWN SCALE (Text on primary)
213
+ From Figma: primary brown palette
214
+ ---------------------------------------- */
215
+ --ff-brown-10: #f0ece8;
216
+ --ff-brown-20: #d4c4ba;
217
+ --ff-brown-30: #b59f8c;
218
+ --ff-brown-40: #a68c74;
219
+ --ff-brown-50: #97795d;
220
+ --ff-brown-60: #8a6447;
221
+ --ff-brown-70: #7a522f;
222
+ --ff-brown-80: #6b3f18; /* Main text on primary */
223
+ --ff-brown-90: #613916;
224
+ --ff-brown-100: #563213;
225
+ --ff-brown-110: #4b2c11;
226
+ --ff-brown-120: #36200c;
227
+
228
+ /* Convenience alias */
229
+ --ff-primary-text: #6b3f18;
230
+
231
+ /* ----------------------------------------
232
+ GRAY SCALE (Neutral colors)
233
+ From Figma: gray palette
234
+ ---------------------------------------- */
235
+ --ff-gray-white: #ffffff;
236
+ --ff-gray-10: #fcfcfb;
237
+ --ff-gray-20: #f9f9f7;
238
+ --ff-gray-30: #f0efed;
239
+ --ff-gray-40: #e9e8e4;
240
+ --ff-gray-50: #e2e0dd;
241
+ --ff-gray-60: #dadad5;
242
+ --ff-gray-70: #cfceca;
243
+ --ff-gray-80: #bcbbb7;
244
+ --ff-gray-90: #8e8d89;
245
+ --ff-gray-100: #848280;
246
+ --ff-gray-110: #656461;
247
+ --ff-gray-120: #21201d;
248
+
249
+ /* ----------------------------------------
250
+ SEMANTIC TOKENS
251
+ Reference primitives for consistent UI
252
+ ---------------------------------------- */
253
+
254
+ /* Background */
255
+ --ff-bg-primary: var(--ff-gray-white);
256
+ --ff-bg-secondary: var(--ff-gray-10);
257
+ --ff-bg-tertiary: var(--ff-gray-30);
258
+ --ff-bg-brand: var(--ff-primary-50);
259
+ --ff-bg-brand-light: var(--ff-primary-20);
260
+
261
+ /* Text */
262
+ --ff-text-primary: var(--ff-gray-120);
263
+ --ff-text-secondary: var(--ff-gray-110);
264
+ --ff-text-muted: var(--ff-gray-90);
265
+ --ff-text-supportive: var(--ff-gray-80);
266
+ --ff-text-inverse: var(--ff-gray-white);
267
+ --ff-text-link: var(--ff-primary-90);
268
+ --ff-text-brand: var(--ff-brown-80);
269
+
270
+ /* Border */
271
+ --ff-border-light: var(--ff-gray-30);
272
+ --ff-border-default: var(--ff-gray-40);
273
+ --ff-border-dark: var(--ff-gray-70);
274
+ --ff-border-brand: var(--ff-brown-80);
275
+ --ff-border-focus: var(--ff-primary-70);
276
+
277
+ /* Icons */
278
+ --ff-icon-default: var(--ff-gray-90);
279
+ --ff-icon-active: var(--ff-gray-120);
280
+ --ff-icon-muted: var(--ff-gray-80);
281
+ --ff-icon-brand: var(--ff-brown-80);
282
+ --ff-icon-inverse: var(--ff-gray-white);
283
+
284
+ /* System Feedback - From Figma */
285
+ --ff-success-light: #e7f5e4;
286
+ --ff-success: #298e33;
287
+ --ff-success-dark: #1f3c20;
288
+ --ff-warning-light: #ffe6c1;
289
+ --ff-warning: #a86807;
290
+ --ff-warning-dark: #4a3723;
291
+ --ff-error-light: #fcdede;
292
+ --ff-error: #d43338;
293
+ --ff-error-dark: #641a1a;
294
+
295
+ /* Focus ring */
296
+ --ff-focus-ring: rgba(192, 208, 237, 0.5); /* primary-70 at 50% */
297
+ --ff-focus-ring-accent: rgba(168, 85, 247, 0.25);
298
+
299
+ /* ----------------------------------------
300
+ ACCENT - Purple (alternate theme)
301
+ ---------------------------------------- */
302
+ --ff-accent-50: #faf5ff;
303
+ --ff-accent-100: #f3e8ff;
304
+ --ff-accent-200: #e9d5ff;
305
+ --ff-accent-300: #d8b4fe;
306
+ --ff-accent-400: #c084fc;
307
+ --ff-accent-500: #a855f7;
308
+ --ff-accent-600: #9333ea;
309
+ --ff-accent-700: #7c3aed;
310
+ --ff-accent-800: #6b21a8;
311
+ --ff-accent-900: #581c87;
312
+
313
+ /* ----------------------------------------
314
+ NAVY (for tooltips, dark elements)
315
+ ---------------------------------------- */
316
+ --ff-navy-950: #1a2029;
317
+ }
318
+
319
+ /* Container */
320
+ .ff-container {
321
+ @apply ff-font-sans;
322
+ color: var(--ff-text-primary);
323
+ font-feature-settings: 'cv02', 'cv03', 'cv04', 'cv11';
324
+ }
325
+
326
+ /* ============================================
327
+ Data Table Styles (from Figma Tables)
328
+ ============================================ */
329
+
330
+ .ff-table-container {
331
+ @apply ff-relative ff-overflow-auto ff-rounded-xl ff-border;
332
+ border-color: var(--ff-border-light);
333
+ background-color: var(--ff-bg-primary);
334
+ }
335
+
336
+ .ff-table {
337
+ @apply ff-w-full ff-text-sm;
338
+ }
339
+
340
+ .ff-table thead {
341
+ @apply ff-sticky ff-top-0 ff-z-10;
342
+ background-color: var(--ff-bg-secondary);
343
+ }
344
+
345
+ /* Rounded corners for first and last header cells to match container */
346
+ .ff-table thead tr:first-child th:first-child {
347
+ @apply ff-rounded-tl-xl;
348
+ }
349
+
350
+ .ff-table thead tr:first-child th:last-child {
351
+ @apply ff-rounded-tr-xl;
352
+ }
353
+
354
+ .ff-table th {
355
+ @apply ff-px-4 ff-py-3 ff-text-left ff-font-semibold ff-text-xs ff-uppercase ff-tracking-wider;
356
+ color: var(--ff-text-secondary);
357
+ border-bottom: 2px solid var(--ff-border-light);
358
+ }
359
+
360
+ .ff-table td {
361
+ @apply ff-px-4 ff-py-3;
362
+ color: var(--ff-text-primary);
363
+ border-bottom: 1px solid var(--ff-border-light);
364
+ }
365
+
366
+ .ff-table tbody tr {
367
+ @apply ff-transition-colors ff-duration-150;
368
+ }
369
+
370
+ .ff-table tbody tr:hover {
371
+ background-color: var(--ff-bg-secondary);
372
+ }
373
+
374
+ /* Cell States */
375
+ .ff-cell-error {
376
+ @apply ff-border-l-4;
377
+ background-color: var(--ff-error-light);
378
+ border-left-color: var(--ff-error);
379
+ }
380
+
381
+ .ff-cell-warning {
382
+ @apply ff-border-l-4;
383
+ background-color: var(--ff-warning-light);
384
+ border-left-color: var(--ff-warning);
385
+ }
386
+
387
+ .ff-cell-editing {
388
+ @apply ff-ring-2;
389
+ background-color: var(--ff-primary-50);
390
+ --tw-ring-color: var(--ff-primary-400);
391
+ }
392
+
393
+ .ff-cell-success {
394
+ background-color: var(--ff-success-light);
395
+ }
396
+
397
+ /* Row error state */
398
+ .ff-row-error {
399
+ background-color: rgba(212, 51, 56, 0.1); /* ff-error at 10% opacity */
400
+ }
401
+
402
+ /* Edit button */
403
+ .ff-edit-btn {
404
+ color: var(--ff-text-muted);
405
+ }
406
+
407
+ .ff-edit-btn:hover {
408
+ color: var(--ff-text-secondary);
409
+ }
410
+
411
+ /* ============================================
412
+ Input Styles (from Figma Inputs)
413
+ ============================================ */
414
+
415
+ .ff-input {
416
+ @apply ff-w-full ff-px-4 ff-py-3 ff-text-sm ff-border ff-rounded-lg;
417
+ border-color: var(--ff-border-default);
418
+ background-color: var(--ff-bg-primary);
419
+ color: var(--ff-text-primary);
420
+ @apply ff-transition-all ff-duration-200;
421
+ }
422
+
423
+ .ff-input::placeholder {
424
+ color: var(--ff-text-muted);
425
+ }
426
+
427
+ .ff-input:hover {
428
+ border-color: var(--ff-border-dark);
429
+ }
430
+
431
+ .ff-input:focus {
432
+ @apply ff-outline-none ff-ring-4;
433
+ border-color: var(--ff-primary-500);
434
+ --tw-ring-color: var(--ff-focus-ring);
435
+ }
436
+
437
+ .ff-input-error {
438
+ border-color: var(--ff-error);
439
+ }
440
+
441
+ .ff-input-error:focus {
442
+ border-color: var(--ff-error);
443
+ --tw-ring-color: rgba(212, 51, 56, 0.2); /* ff-error at 20% opacity */
444
+ }
445
+
446
+ /* Select */
447
+ .ff-select {
448
+ @apply ff-appearance-none ff-cursor-pointer ff-pr-10;
449
+ }
450
+
451
+ .ff-select {
452
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%2378716c' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
453
+ background-position: right 0.75rem center;
454
+ background-repeat: no-repeat;
455
+ background-size: 1.25em 1.25em;
456
+ }
457
+
458
+ /* ============================================
459
+ Button Styles (Demo-matching design)
460
+ ============================================ */
461
+
462
+ .ff-btn {
463
+ @apply ff-inline-flex ff-items-center ff-justify-center ff-gap-2;
464
+ @apply ff-font-semibold ff-text-sm;
465
+ @apply ff-px-5 ff-py-2.5;
466
+ @apply ff-rounded-lg;
467
+ @apply ff-transition-all ff-duration-150;
468
+ @apply ff-border ff-border-transparent;
469
+ @apply ff-cursor-pointer;
470
+ }
471
+
472
+ .ff-btn:focus {
473
+ @apply ff-outline-none;
474
+ }
475
+
476
+ .ff-btn:disabled {
477
+ @apply ff-opacity-50 ff-cursor-not-allowed;
478
+ }
479
+
480
+ /* Primary - Prominent dark button with white text */
481
+ .ff-btn-primary {
482
+ background-color: var(--ff-primary-110);
483
+ color: var(--ff-gray-white);
484
+ }
485
+
486
+ .ff-btn-primary:hover:not(:disabled) {
487
+ background-color: var(--ff-primary-120);
488
+ transform: translateY(-1px);
489
+ box-shadow: 0 4px 12px -2px rgba(0, 0, 0, 0.2);
490
+ }
491
+
492
+ .ff-btn-primary:active:not(:disabled) {
493
+ background-color: var(--ff-primary-130);
494
+ transform: translateY(0);
495
+ }
496
+
497
+ .ff-btn-primary:focus-visible {
498
+ box-shadow: 0 0 0 3px var(--ff-focus-ring);
499
+ }
500
+
501
+ /* Secondary - Outlined */
502
+ .ff-btn-secondary {
503
+ background-color: var(--ff-bg-primary);
504
+ color: var(--ff-text-primary);
505
+ border-color: var(--ff-border-default);
506
+ }
507
+
508
+ .ff-btn-secondary:hover:not(:disabled) {
509
+ background-color: var(--ff-bg-secondary);
510
+ border-color: var(--ff-border-dark);
511
+ }
512
+
513
+ .ff-btn-secondary:active:not(:disabled) {
514
+ background-color: var(--ff-bg-tertiary);
515
+ }
516
+
517
+ .ff-btn-secondary:focus-visible {
518
+ box-shadow: 0 0 0 3px var(--ff-focus-ring);
519
+ }
520
+
521
+ /* Ghost */
522
+ .ff-btn-ghost {
523
+ background-color: transparent;
524
+ color: var(--ff-text-secondary);
525
+ }
526
+
527
+ .ff-btn-ghost:hover:not(:disabled) {
528
+ background-color: var(--ff-bg-secondary);
529
+ color: var(--ff-text-primary);
530
+ }
531
+
532
+ /* Accent - Purple (for alternate theme) */
533
+ .ff-btn-accent {
534
+ background-color: var(--ff-accent-500);
535
+ color: var(--ff-text-inverse);
536
+ }
537
+
538
+ .ff-btn-accent:hover:not(:disabled) {
539
+ background-color: var(--ff-accent-600);
540
+ transform: translateY(-1px);
541
+ box-shadow: 0 4px 12px -2px rgba(168, 85, 247, 0.3);
542
+ }
543
+
544
+ .ff-btn-accent:active:not(:disabled) {
545
+ background-color: var(--ff-accent-700);
546
+ transform: translateY(0);
547
+ }
548
+
549
+ .ff-btn-accent:focus {
550
+ @apply ff-outline-none ff-ring-4;
551
+ --tw-ring-color: var(--ff-focus-ring-accent);
552
+ }
553
+
554
+ /* Danger */
555
+ .ff-btn-danger {
556
+ @apply ff-bg-error-500 ff-text-white;
557
+ }
558
+
559
+ .ff-btn-danger:hover:not(:disabled) {
560
+ @apply ff-bg-error-600;
561
+ transform: translateY(-1px);
562
+ }
563
+
564
+ /* Link style button */
565
+ .ff-btn-link {
566
+ background-color: transparent;
567
+ color: var(--ff-primary-text);
568
+ @apply ff-px-2 ff-py-1;
569
+ }
570
+
571
+ .ff-btn-link:hover:not(:disabled) {
572
+ color: #4a2a10; /* Darker brown */
573
+ text-decoration: underline;
574
+ }
575
+
576
+ /* Button sizes */
577
+ .ff-btn-sm {
578
+ @apply ff-px-3 ff-py-2 ff-text-sm ff-rounded-md;
579
+ }
580
+
581
+ .ff-btn-lg {
582
+ @apply ff-px-6 ff-py-3 ff-text-base ff-rounded-xl;
583
+ }
584
+
585
+ /* ============================================
586
+ Checkbox Styles (from Figma Selectors)
587
+ ============================================ */
588
+
589
+ .ff-checkbox {
590
+ @apply ff-w-5 ff-h-5 ff-rounded ff-border-2 ff-cursor-pointer;
591
+ @apply ff-transition-all ff-duration-150;
592
+ border-color: var(--ff-border-default);
593
+ background-color: var(--ff-bg-primary);
594
+ }
595
+
596
+ .ff-checkbox:hover {
597
+ border-color: var(--ff-primary-400);
598
+ }
599
+
600
+ .ff-checkbox:checked {
601
+ background-color: var(--ff-primary-500);
602
+ border-color: var(--ff-primary-500);
603
+ background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e");
604
+ }
605
+
606
+ .ff-checkbox:focus {
607
+ @apply ff-outline-none ff-ring-4;
608
+ --tw-ring-color: var(--ff-focus-ring);
609
+ }
610
+
611
+ /* Radio */
612
+ .ff-radio {
613
+ @apply ff-w-5 ff-h-5 ff-rounded-full ff-border-2 ff-cursor-pointer;
614
+ @apply ff-transition-all ff-duration-150;
615
+ border-color: var(--ff-border-default);
616
+ background-color: var(--ff-bg-primary);
617
+ }
618
+
619
+ .ff-radio:checked {
620
+ border-color: var(--ff-primary-500);
621
+ border-width: 6px;
622
+ }
623
+
624
+ .ff-radio:focus {
625
+ @apply ff-outline-none ff-ring-4;
626
+ --tw-ring-color: var(--ff-focus-ring);
627
+ }
628
+
629
+ /* Toggle Switch */
630
+ .ff-toggle {
631
+ @apply ff-relative ff-w-11 ff-h-6 ff-rounded-full ff-cursor-pointer;
632
+ @apply ff-transition-all ff-duration-200;
633
+ background-color: var(--ff-border-default);
634
+ }
635
+
636
+ .ff-toggle::after {
637
+ @apply ff-absolute ff-top-0.5 ff-left-0.5 ff-w-5 ff-h-5 ff-rounded-full;
638
+ @apply ff-transition-transform ff-duration-200;
639
+ content: '';
640
+ background-color: var(--ff-bg-primary);
641
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
642
+ }
643
+
644
+ .ff-toggle:checked {
645
+ background-color: var(--ff-primary-500);
646
+ }
647
+
648
+ .ff-toggle:checked::after {
649
+ transform: translateX(1.25rem);
650
+ }
651
+
652
+ /* ============================================
653
+ Dropzone Styles (Demo-matching design)
654
+ ============================================ */
655
+
656
+ .ff-dropzone {
657
+ @apply ff-flex ff-flex-col ff-items-center ff-justify-center;
658
+ @apply ff-p-8;
659
+ @apply ff-border-2 ff-border-dashed ff-rounded-xl;
660
+ border-color: var(--ff-border-default);
661
+ background-color: var(--ff-bg-secondary);
662
+ @apply ff-cursor-pointer;
663
+ @apply ff-transition-all ff-duration-150;
664
+ }
665
+
666
+ /* Ensure dropzone children don't block drag events */
667
+ .ff-dropzone * {
668
+ pointer-events: none;
669
+ }
670
+
671
+ .ff-dropzone input {
672
+ pointer-events: auto;
673
+ }
674
+
675
+ .ff-dropzone:hover {
676
+ border-color: var(--ff-primary-70);
677
+ background-color: var(--ff-primary-10);
678
+ }
679
+
680
+ .ff-dropzone-active {
681
+ border-color: var(--ff-primary-90);
682
+ background-color: var(--ff-primary-20);
683
+ @apply ff-scale-[1.01];
684
+ }
685
+
686
+ .ff-dropzone-icon-wrapper {
687
+ @apply ff-w-14 ff-h-14 ff-rounded-xl ff-flex ff-items-center ff-justify-center ff-mx-auto ff-mb-4;
688
+ background-color: var(--ff-primary-20);
689
+ @apply ff-transition-colors ff-duration-150;
690
+ }
691
+
692
+ .ff-dropzone-active .ff-dropzone-icon-wrapper {
693
+ background-color: var(--ff-primary-30);
694
+ }
695
+
696
+ .ff-dropzone-icon {
697
+ @apply ff-w-7 ff-h-7;
698
+ color: var(--ff-primary-90);
699
+ @apply ff-transition-colors ff-duration-150;
700
+ }
701
+
702
+ .ff-dropzone-active .ff-dropzone-icon {
703
+ color: var(--ff-primary-110);
704
+ }
705
+
706
+ .ff-dropzone-text {
707
+ @apply ff-text-base ff-font-semibold ff-mb-1;
708
+ color: var(--ff-text-primary);
709
+ }
710
+
711
+ .ff-dropzone-hint {
712
+ @apply ff-text-sm ff-mb-4;
713
+ color: var(--ff-text-muted);
714
+ }
715
+
716
+ .ff-dropzone-formats {
717
+ @apply ff-text-xs ff-mt-3;
718
+ color: var(--ff-text-muted);
719
+ }
720
+
721
+ /* ============================================
722
+ Badge Styles (from Figma status badges)
723
+ ============================================ */
724
+
725
+ .ff-badge {
726
+ @apply ff-inline-flex ff-items-center ff-px-2.5 ff-py-1 ff-text-xs ff-font-semibold ff-rounded-full;
727
+ }
728
+
729
+ .ff-badge-error {
730
+ background-color: var(--ff-error-light);
731
+ color: var(--ff-error);
732
+ }
733
+
734
+ .ff-badge-warning {
735
+ background-color: var(--ff-warning-light);
736
+ color: var(--ff-warning);
737
+ }
738
+
739
+ .ff-badge-success {
740
+ background-color: var(--ff-success-light);
741
+ color: var(--ff-success);
742
+ }
743
+
744
+ .ff-badge-info {
745
+ background-color: var(--ff-primary-20);
746
+ color: var(--ff-primary-90);
747
+ }
748
+
749
+ .ff-badge-neutral {
750
+ background-color: var(--ff-bg-tertiary);
751
+ color: var(--ff-text-secondary);
752
+ }
753
+
754
+ .ff-badge-primary {
755
+ background-color: var(--ff-primary-100);
756
+ color: var(--ff-primary-700);
757
+ }
758
+
759
+ .ff-badge-accent {
760
+ background-color: var(--ff-accent-100);
761
+ color: var(--ff-accent-700);
762
+ }
763
+
764
+ /* ============================================
765
+ Modal/Overlay Styles (Demo-matching design)
766
+ ============================================ */
767
+
768
+ .ff-overlay {
769
+ @apply ff-fixed ff-inset-0 ff-z-50;
770
+ background-color: rgba(28, 25, 23, 0.5);
771
+ backdrop-filter: blur(4px);
772
+ @apply ff-flex ff-items-center ff-justify-center;
773
+ @apply ff-p-4;
774
+ animation: ff-fade-in 0.2s ease-out;
775
+ @apply ff-overflow-y-auto;
776
+ }
777
+
778
+ @keyframes ff-fade-in {
779
+ from { opacity: 0; }
780
+ to { opacity: 1; }
781
+ }
782
+
783
+ /* Modal overlay - self-contained backdrop for modal mode */
784
+ .ff-overlay {
785
+ position: fixed;
786
+ inset: 0;
787
+ z-index: 9999;
788
+ background-color: rgba(0, 0, 0, 0.5);
789
+ @apply ff-flex ff-items-center ff-justify-center;
790
+ @apply ff-p-4;
791
+ }
792
+
793
+ .ff-modal {
794
+ background-color: var(--ff-bg-primary);
795
+ @apply ff-rounded-2xl;
796
+ @apply ff-w-full ff-max-w-4xl;
797
+ @apply ff-flex ff-flex-col;
798
+ max-height: min(90vh, calc(100vh - 2rem));
799
+ box-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25);
800
+ animation: ff-scale-in 0.2s ease-out;
801
+ @apply ff-my-auto;
802
+ }
803
+
804
+ /* Embed mode - inline component without modal chrome */
805
+ .ff-embed {
806
+ background-color: var(--ff-bg-primary);
807
+ @apply ff-w-full ff-flex ff-flex-col;
808
+ @apply ff-rounded-xl ff-border;
809
+ border-color: var(--ff-border-light);
810
+ /* No max-height, max-width, shadow, or animation - consumer controls sizing */
811
+ }
812
+
813
+ .ff-embed .ff-modal-header {
814
+ @apply ff-rounded-t-xl;
815
+ }
816
+
817
+ .ff-embed .ff-modal-footer {
818
+ @apply ff-rounded-b-xl;
819
+ }
820
+
821
+ @keyframes ff-scale-in {
822
+ from {
823
+ opacity: 0;
824
+ transform: scale(0.95);
825
+ }
826
+ to {
827
+ opacity: 1;
828
+ transform: scale(1);
829
+ }
830
+ }
831
+
832
+ .ff-modal-header {
833
+ @apply ff-flex ff-items-center ff-justify-between ff-px-6 ff-py-5;
834
+ border-bottom: 1px solid var(--ff-border-light);
835
+ @apply ff-flex-shrink-0;
836
+ @apply ff-rounded-t-2xl;
837
+ }
838
+
839
+ .ff-modal-header-left {
840
+ @apply ff-flex ff-items-center ff-gap-4;
841
+ }
842
+
843
+ .ff-modal-icon {
844
+ @apply ff-w-10 ff-h-10 ff-rounded-lg ff-flex ff-items-center ff-justify-center;
845
+ background-color: var(--ff-primary-20);
846
+ }
847
+
848
+ .ff-modal-icon svg {
849
+ @apply ff-w-5 ff-h-5;
850
+ color: var(--ff-primary-90);
851
+ }
852
+
853
+ .ff-modal-title {
854
+ @apply ff-text-lg ff-font-semibold;
855
+ color: var(--ff-text-primary);
856
+ }
857
+
858
+ .ff-modal-close {
859
+ @apply ff-p-2 ff-rounded-lg;
860
+ color: var(--ff-text-muted);
861
+ @apply ff-transition-colors ff-duration-150;
862
+ }
863
+
864
+ .ff-modal-close:hover {
865
+ color: var(--ff-text-primary);
866
+ background-color: var(--ff-bg-tertiary);
867
+ }
868
+
869
+ .ff-modal-body {
870
+ @apply ff-p-6 ff-overflow-y-auto ff-flex-1;
871
+ }
872
+
873
+ .ff-modal-footer {
874
+ @apply ff-flex ff-items-center ff-justify-between ff-px-6 ff-py-4;
875
+ background-color: var(--ff-bg-secondary);
876
+ border-top: 1px solid var(--ff-border-light);
877
+ @apply ff-flex-shrink-0;
878
+ @apply ff-rounded-b-2xl;
879
+ }
880
+
881
+ /* ============================================
882
+ Step Indicator (Demo-matching design)
883
+ ============================================ */
884
+
885
+ .ff-steps {
886
+ @apply ff-flex ff-items-center ff-gap-2;
887
+ }
888
+
889
+ .ff-step {
890
+ @apply ff-flex ff-items-center ff-justify-center;
891
+ @apply ff-w-8 ff-h-8 ff-rounded-full;
892
+ @apply ff-text-sm ff-font-semibold;
893
+ @apply ff-transition-all ff-duration-150;
894
+ }
895
+
896
+ .ff-step-pending {
897
+ background-color: var(--ff-bg-tertiary);
898
+ color: var(--ff-text-muted);
899
+ }
900
+
901
+ .ff-step-active {
902
+ background-color: var(--ff-primary-50);
903
+ color: var(--ff-primary-90);
904
+ box-shadow: 0 0 0 4px var(--ff-primary-20);
905
+ }
906
+
907
+ .ff-step-complete {
908
+ background-color: var(--ff-success);
909
+ color: white;
910
+ }
911
+
912
+ .ff-step-connector {
913
+ @apply ff-w-8 ff-h-0.5;
914
+ background-color: var(--ff-border-default);
915
+ @apply ff-transition-colors ff-duration-150;
916
+ }
917
+
918
+ .ff-step-connector-complete {
919
+ background-color: var(--ff-success);
920
+ }
921
+
922
+ /* ============================================
923
+ Progress Bar (from Figma Loaders)
924
+ ============================================ */
925
+
926
+ .ff-progress {
927
+ @apply ff-h-2 ff-rounded-full ff-overflow-hidden;
928
+ background-color: var(--ff-bg-tertiary);
929
+ }
930
+
931
+ .ff-progress-bar {
932
+ @apply ff-h-full ff-rounded-full ff-transition-all ff-duration-500 ff-ease-out;
933
+ background-color: var(--ff-primary-500);
934
+ }
935
+
936
+ .ff-progress-bar-animated {
937
+ background: linear-gradient(90deg, var(--ff-primary-400) 0%, var(--ff-primary-500) 50%, var(--ff-primary-400) 100%);
938
+ background-size: 200% 100%;
939
+ animation: shimmer 2s linear infinite;
940
+ }
941
+
942
+ @keyframes shimmer {
943
+ 0% { background-position: -200% 0; }
944
+ 100% { background-position: 200% 0; }
945
+ }
946
+
947
+ /* ============================================
948
+ Tooltip
949
+ ============================================ */
950
+
951
+ .ff-tooltip {
952
+ @apply ff-absolute ff-z-50 ff-px-3 ff-py-2 ff-text-xs ff-font-medium ff-rounded-lg;
953
+ @apply ff-opacity-0 ff-invisible ff-transition-all ff-duration-200;
954
+ background-color: var(--ff-navy-950);
955
+ color: var(--ff-text-inverse);
956
+ box-shadow: 0 4px 12px -2px rgb(0 0 0 / 0.2);
957
+ }
958
+
959
+ .ff-tooltip-visible {
960
+ @apply ff-opacity-100 ff-visible;
961
+ }
962
+
963
+ /* ============================================
964
+ Spinner (from Figma Loaders)
965
+ ============================================ */
966
+
967
+ .ff-spinner {
968
+ @apply ff-w-5 ff-h-5 ff-border-2 ff-rounded-full ff-animate-spin;
969
+ border-color: var(--ff-border-light);
970
+ border-top-color: var(--ff-primary-500);
971
+ }
972
+
973
+ .ff-spinner-lg {
974
+ @apply ff-w-8 ff-h-8;
975
+ border-width: 3px;
976
+ }
977
+
978
+ /* ============================================
979
+ Document Preview
980
+ ============================================ */
981
+
982
+ .ff-document-preview {
983
+ @apply ff-relative ff-rounded-xl ff-overflow-hidden;
984
+ background-color: var(--ff-bg-tertiary);
985
+ }
986
+
987
+ .ff-document-preview img {
988
+ @apply ff-w-full ff-h-auto ff-object-contain;
989
+ }
990
+
991
+ /* ============================================
992
+ Column Mapping Styles (Demo-matching design)
993
+ ============================================ */
994
+
995
+ .ff-mapping-header {
996
+ @apply ff-flex ff-items-center ff-justify-between ff-mb-4;
997
+ }
998
+
999
+ .ff-mapping-title {
1000
+ @apply ff-text-lg ff-font-semibold;
1001
+ color: var(--ff-text-primary);
1002
+ }
1003
+
1004
+ .ff-mapping-subtitle {
1005
+ @apply ff-text-sm;
1006
+ color: var(--ff-text-muted);
1007
+ }
1008
+
1009
+ .ff-mapping-legend {
1010
+ @apply ff-flex ff-items-center ff-gap-4 ff-text-sm;
1011
+ }
1012
+
1013
+ .ff-mapping-legend-item {
1014
+ @apply ff-flex ff-items-center ff-gap-1.5;
1015
+ }
1016
+
1017
+ .ff-mapping-legend-dot {
1018
+ @apply ff-w-2 ff-h-2 ff-rounded-full;
1019
+ }
1020
+
1021
+ .ff-mapping-row {
1022
+ @apply ff-flex ff-items-center ff-gap-4 ff-p-4 ff-border ff-rounded-xl;
1023
+ @apply ff-transition-all ff-duration-150;
1024
+ background-color: var(--ff-bg-primary);
1025
+ border-color: var(--ff-border-light);
1026
+ }
1027
+
1028
+ .ff-mapping-row:hover {
1029
+ border-color: var(--ff-border-default);
1030
+ background-color: var(--ff-bg-secondary);
1031
+ }
1032
+
1033
+ .ff-mapping-row-success {
1034
+ border-color: var(--ff-success-light);
1035
+ background-color: rgba(231, 245, 228, 0.5);
1036
+ }
1037
+
1038
+ .ff-mapping-row-warning {
1039
+ border-color: var(--ff-warning-light);
1040
+ background-color: rgba(255, 230, 193, 0.5);
1041
+ }
1042
+
1043
+ .ff-mapping-source {
1044
+ @apply ff-flex-1 ff-px-4 ff-py-2.5 ff-rounded-lg ff-font-mono ff-text-sm;
1045
+ background-color: var(--ff-bg-tertiary);
1046
+ color: var(--ff-text-secondary);
1047
+ }
1048
+
1049
+ .ff-mapping-arrow {
1050
+ @apply ff-flex-shrink-0;
1051
+ color: var(--ff-text-muted);
1052
+ }
1053
+
1054
+ .ff-mapping-target {
1055
+ @apply ff-flex-1;
1056
+ }
1057
+
1058
+ .ff-mapping-status {
1059
+ @apply ff-w-8 ff-flex ff-justify-center;
1060
+ }
1061
+
1062
+ /* ============================================
1063
+ Confidence Indicator
1064
+ ============================================ */
1065
+
1066
+ .ff-confidence {
1067
+ @apply ff-inline-flex ff-items-center ff-gap-1.5 ff-text-xs ff-font-medium;
1068
+ }
1069
+
1070
+ .ff-confidence-high {
1071
+ color: var(--ff-success);
1072
+ }
1073
+
1074
+ .ff-confidence-medium {
1075
+ color: var(--ff-warning);
1076
+ }
1077
+
1078
+ .ff-confidence-low {
1079
+ color: var(--ff-error);
1080
+ }
1081
+
1082
+ .ff-confidence-bar {
1083
+ @apply ff-h-1.5 ff-rounded-full;
1084
+ background-color: var(--ff-bg-tertiary);
1085
+ }
1086
+
1087
+ .ff-confidence-bar-fill {
1088
+ @apply ff-h-full ff-rounded-full ff-transition-all ff-duration-300;
1089
+ }
1090
+
1091
+ /* NOTE: Step Indicator styles are defined above in the "Step Indicator (Demo-matching design)" section */
1092
+
1093
+ /* ============================================
1094
+ Validation Summary
1095
+ ============================================ */
1096
+
1097
+ .ff-validation-summary {
1098
+ @apply ff-p-4 ff-rounded-xl ff-border;
1099
+ }
1100
+
1101
+ .ff-validation-summary-error {
1102
+ background-color: var(--ff-error-light);
1103
+ border-color: var(--ff-error);
1104
+ }
1105
+
1106
+ .ff-validation-summary-warning {
1107
+ background-color: var(--ff-warning-light);
1108
+ border-color: var(--ff-warning);
1109
+ }
1110
+
1111
+ .ff-validation-summary-success {
1112
+ background-color: var(--ff-success-light);
1113
+ border-color: var(--ff-success);
1114
+ }
1115
+
1116
+ /* ============================================
1117
+ Card Styles
1118
+ ============================================ */
1119
+
1120
+ .ff-card {
1121
+ @apply ff-rounded-xl ff-border;
1122
+ background-color: var(--ff-bg-primary);
1123
+ border-color: var(--ff-border-light);
1124
+ box-shadow: 0 2px 8px -2px rgb(0 0 0 / 0.04);
1125
+ }
1126
+
1127
+ .ff-card-hover {
1128
+ @apply ff-transition-all ff-duration-300;
1129
+ }
1130
+
1131
+ .ff-card-hover:hover {
1132
+ border-color: var(--ff-border-default);
1133
+ box-shadow: 0 8px 24px -4px rgb(0 0 0 / 0.08);
1134
+ transform: translateY(-2px);
1135
+ }
1136
+
1137
+ /* ============================================
1138
+ Status Indicator
1139
+ ============================================ */
1140
+
1141
+ .ff-status {
1142
+ @apply ff-inline-flex ff-items-center ff-gap-2;
1143
+ }
1144
+
1145
+ .ff-status-dot {
1146
+ @apply ff-w-2 ff-h-2 ff-rounded-full;
1147
+ }
1148
+
1149
+ .ff-status-dot-success {
1150
+ background-color: var(--ff-success);
1151
+ }
1152
+
1153
+ .ff-status-dot-warning {
1154
+ background-color: var(--ff-warning);
1155
+ }
1156
+
1157
+ .ff-status-dot-error {
1158
+ background-color: var(--ff-error);
1159
+ }
1160
+
1161
+ .ff-status-dot-pending {
1162
+ background-color: var(--ff-text-muted);
1163
+ }
1164
+
1165
+ .ff-status-dot-processing {
1166
+ @apply ff-animate-pulse;
1167
+ background-color: var(--ff-primary-90);
1168
+ }
1169
+
1170
+ /* ============================================
1171
+ Empty State
1172
+ ============================================ */
1173
+
1174
+ .ff-empty-state {
1175
+ @apply ff-flex ff-flex-col ff-items-center ff-justify-center ff-py-12 ff-text-center;
1176
+ }
1177
+
1178
+ .ff-empty-state-icon {
1179
+ @apply ff-w-16 ff-h-16 ff-mb-4;
1180
+ color: var(--ff-border-default);
1181
+ }
1182
+
1183
+ .ff-empty-state-title {
1184
+ @apply ff-text-lg ff-font-semibold ff-mb-2;
1185
+ color: var(--ff-text-primary);
1186
+ }
1187
+
1188
+ .ff-empty-state-description {
1189
+ @apply ff-text-sm ff-max-w-sm;
1190
+ color: var(--ff-text-muted);
1191
+ }
1192
+
1193
+ /* ============================================
1194
+ Skeleton Loading
1195
+ ============================================ */
1196
+
1197
+ .ff-skeleton {
1198
+ @apply ff-rounded ff-animate-pulse;
1199
+ background-color: var(--ff-bg-tertiary);
1200
+ }
1201
+
1202
+ .ff-skeleton-text {
1203
+ @apply ff-h-4 ff-rounded;
1204
+ }
1205
+
1206
+ .ff-skeleton-title {
1207
+ @apply ff-h-6 ff-rounded ff-w-3/4;
1208
+ }
1209
+
1210
+ .ff-skeleton-avatar {
1211
+ @apply ff-w-10 ff-h-10 ff-rounded-full;
1212
+ }
1213
+
1214
+ /* ============================================
1215
+ Pagination (from Figma Tables)
1216
+ ============================================ */
1217
+
1218
+ .ff-pagination {
1219
+ @apply ff-flex ff-items-center ff-gap-1;
1220
+ }
1221
+
1222
+ .ff-pagination-btn {
1223
+ @apply ff-w-9 ff-h-9 ff-flex ff-items-center ff-justify-center;
1224
+ @apply ff-rounded-lg ff-text-sm ff-font-medium;
1225
+ @apply ff-transition-colors ff-duration-150;
1226
+ color: var(--ff-text-secondary);
1227
+ }
1228
+
1229
+ .ff-pagination-btn:hover {
1230
+ background-color: var(--ff-bg-secondary);
1231
+ color: var(--ff-text-primary);
1232
+ }
1233
+
1234
+ .ff-pagination-btn-active {
1235
+ background-color: var(--ff-primary-500);
1236
+ color: var(--ff-text-inverse);
1237
+ }
1238
+
1239
+ .ff-pagination-btn-active:hover {
1240
+ background-color: var(--ff-primary-600);
1241
+ color: var(--ff-text-inverse);
1242
+ }
1243
+
1244
+ /* ============================================
1245
+ Selector Group (from Figma Selectors)
1246
+ ============================================ */
1247
+
1248
+ .ff-selector-group {
1249
+ @apply ff-inline-flex ff-flex-wrap ff-gap-2;
1250
+ }
1251
+
1252
+ .ff-selector-item {
1253
+ @apply ff-inline-flex ff-items-center ff-gap-1.5;
1254
+ @apply ff-px-3 ff-py-1.5 ff-rounded-full;
1255
+ @apply ff-text-sm ff-font-medium ff-cursor-pointer;
1256
+ @apply ff-transition-all ff-duration-150;
1257
+ background-color: var(--ff-bg-secondary);
1258
+ color: var(--ff-text-secondary);
1259
+ border: 1px solid var(--ff-border-light);
1260
+ }
1261
+
1262
+ .ff-selector-item:hover {
1263
+ background-color: var(--ff-bg-tertiary);
1264
+ border-color: var(--ff-border-default);
1265
+ }
1266
+
1267
+ .ff-selector-item-active {
1268
+ background-color: var(--ff-primary-500);
1269
+ color: var(--ff-text-inverse);
1270
+ border-color: var(--ff-primary-500);
1271
+ }
1272
+
1273
+ .ff-selector-item-active:hover {
1274
+ background-color: var(--ff-primary-600);
1275
+ border-color: var(--ff-primary-600);
1276
+ }
1277
+
1278
+ /* ============================================
1279
+ Animations
1280
+ ============================================ */
1281
+
1282
+ .ff-fade-in {
1283
+ animation: fadeIn 0.3s ease-out;
1284
+ }
1285
+
1286
+ .ff-slide-up {
1287
+ animation: slideUp 0.3s ease-out;
1288
+ }
1289
+
1290
+ @keyframes fadeIn {
1291
+ from { opacity: 0; }
1292
+ to { opacity: 1; }
1293
+ }
1294
+
1295
+ @keyframes slideUp {
1296
+ from {
1297
+ opacity: 0;
1298
+ transform: translateY(10px);
1299
+ }
1300
+ to {
1301
+ opacity: 1;
1302
+ transform: translateY(0);
1303
+ }
1304
+ }
1305
+
1306
+ /* ============================================
1307
+ Theme Variants (Purple/Accent)
1308
+ ============================================ */
1309
+
1310
+ .ff-theme-accent {
1311
+ --ff-primary-50: var(--ff-accent-50);
1312
+ --ff-primary-100: var(--ff-accent-100);
1313
+ --ff-primary-200: var(--ff-accent-200);
1314
+ --ff-primary-300: var(--ff-accent-300);
1315
+ --ff-primary-400: var(--ff-accent-400);
1316
+ --ff-primary-500: var(--ff-accent-500);
1317
+ --ff-primary-600: var(--ff-accent-600);
1318
+ --ff-primary-700: var(--ff-accent-700);
1319
+ --ff-primary-800: var(--ff-accent-800);
1320
+ --ff-primary-900: var(--ff-accent-900);
1321
+ --ff-focus-ring: var(--ff-focus-ring-accent);
1322
+ }
1323
+
1324
+ /* ============================================
1325
+ Tailwind Utilities - MUST be last!
1326
+ Utility classes used in JSX (e.g. ff-flex, ff-p-4, ff-border)
1327
+ need to come after scoped resets to win with equal specificity.
1328
+ ============================================ */
1329
+ @tailwind utilities;