@codellyson/framely-cli 0.1.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 (40) hide show
  1. package/commands/compositions.js +135 -0
  2. package/commands/preview.js +889 -0
  3. package/commands/render.js +295 -0
  4. package/commands/still.js +165 -0
  5. package/index.js +93 -0
  6. package/package.json +60 -0
  7. package/studio/App.css +605 -0
  8. package/studio/App.jsx +185 -0
  9. package/studio/CompositionsView.css +399 -0
  10. package/studio/CompositionsView.jsx +327 -0
  11. package/studio/PropsEditor.css +195 -0
  12. package/studio/PropsEditor.tsx +176 -0
  13. package/studio/RenderDialog.tsx +476 -0
  14. package/studio/ShareDialog.tsx +200 -0
  15. package/studio/index.ts +19 -0
  16. package/studio/player/Player.css +199 -0
  17. package/studio/player/Player.jsx +355 -0
  18. package/studio/styles/design-system.css +592 -0
  19. package/studio/styles/dialogs.css +420 -0
  20. package/studio/templates/AnimatedGradient.jsx +99 -0
  21. package/studio/templates/InstagramStory.jsx +172 -0
  22. package/studio/templates/LowerThird.jsx +139 -0
  23. package/studio/templates/ProductShowcase.jsx +162 -0
  24. package/studio/templates/SlideTransition.jsx +211 -0
  25. package/studio/templates/SocialIntro.jsx +122 -0
  26. package/studio/templates/SubscribeAnimation.jsx +186 -0
  27. package/studio/templates/TemplateCard.tsx +58 -0
  28. package/studio/templates/TemplateFilters.tsx +97 -0
  29. package/studio/templates/TemplatePreviewDialog.tsx +196 -0
  30. package/studio/templates/TemplatesMarketplace.css +686 -0
  31. package/studio/templates/TemplatesMarketplace.tsx +172 -0
  32. package/studio/templates/TextReveal.jsx +134 -0
  33. package/studio/templates/UseTemplateDialog.tsx +154 -0
  34. package/studio/templates/index.ts +45 -0
  35. package/utils/browser.js +188 -0
  36. package/utils/codecs.js +200 -0
  37. package/utils/logger.js +35 -0
  38. package/utils/props.js +42 -0
  39. package/utils/render.js +447 -0
  40. package/utils/validate.js +148 -0
@@ -0,0 +1,686 @@
1
+ /* ─── Templates Marketplace ─── */
2
+
3
+ .templates-marketplace {
4
+ display: flex;
5
+ flex-direction: column;
6
+ height: 100%;
7
+ padding: var(--space-6, 24px);
8
+ overflow-y: auto;
9
+ background: var(--zinc-950, #09090b);
10
+ font-family: var(--font-sans, 'Inter', system-ui, sans-serif);
11
+ }
12
+
13
+ .templates-header {
14
+ margin-bottom: var(--space-6, 24px);
15
+ }
16
+
17
+ .templates-header h2 {
18
+ margin: 0 0 var(--space-2, 8px);
19
+ font-size: var(--text-2xl, 24px);
20
+ font-weight: 600;
21
+ color: var(--zinc-100, #f4f4f5);
22
+ letter-spacing: -0.01em;
23
+ }
24
+
25
+ .templates-subtitle {
26
+ margin: 0;
27
+ font-size: var(--text-sm, 14px);
28
+ color: var(--zinc-500, #71717a);
29
+ }
30
+
31
+ /* ─── Filters ─── */
32
+
33
+ .templates-filters {
34
+ display: flex;
35
+ flex-wrap: wrap;
36
+ align-items: center;
37
+ gap: var(--space-3, 12px);
38
+ margin-bottom: var(--space-6, 24px);
39
+ padding-bottom: var(--space-4, 16px);
40
+ border-bottom: 1px solid rgba(255, 255, 255, 0.06);
41
+ }
42
+
43
+ .filter-search {
44
+ position: relative;
45
+ flex-shrink: 0;
46
+ }
47
+
48
+ .filter-search-icon {
49
+ position: absolute;
50
+ left: var(--space-3, 12px);
51
+ top: 50%;
52
+ transform: translateY(-50%);
53
+ color: var(--zinc-600, #52525b);
54
+ pointer-events: none;
55
+ }
56
+
57
+ .filter-search input {
58
+ width: 220px;
59
+ padding: var(--space-2, 8px) var(--space-3, 12px) var(--space-2, 8px) 36px;
60
+ background: var(--zinc-800, #27272a);
61
+ border: 1px solid rgba(255, 255, 255, 0.06);
62
+ border-radius: var(--radius-md, 6px);
63
+ color: var(--zinc-100, #f4f4f5);
64
+ font-size: var(--text-sm, 13px);
65
+ font-family: var(--font-sans, 'Inter', system-ui, sans-serif);
66
+ transition: border-color var(--transition-fast, 0.15s ease);
67
+ }
68
+
69
+ .filter-search input::placeholder {
70
+ color: var(--zinc-600, #52525b);
71
+ }
72
+
73
+ .filter-search input:focus {
74
+ outline: none;
75
+ border-color: var(--indigo-500, #6366f1);
76
+ }
77
+
78
+ .filter-categories {
79
+ display: flex;
80
+ flex-wrap: wrap;
81
+ gap: var(--space-1-5, 6px);
82
+ flex: 1;
83
+ }
84
+
85
+ .filter-category {
86
+ display: flex;
87
+ align-items: center;
88
+ gap: var(--space-1-5, 6px);
89
+ padding: var(--space-1-5, 6px) var(--space-3, 12px);
90
+ background: transparent;
91
+ border: 1px solid rgba(255, 255, 255, 0.06);
92
+ border-radius: var(--radius-full, 16px);
93
+ color: var(--zinc-400, #a1a1aa);
94
+ font-size: var(--text-xs, 12px);
95
+ font-family: var(--font-sans, 'Inter', system-ui, sans-serif);
96
+ cursor: pointer;
97
+ transition: all var(--transition-fast, 0.15s ease);
98
+ }
99
+
100
+ .filter-category:hover {
101
+ border-color: var(--indigo-500, #6366f1);
102
+ color: var(--zinc-100, #f4f4f5);
103
+ }
104
+
105
+ .filter-category.active {
106
+ background: var(--indigo-500, #6366f1);
107
+ border-color: var(--indigo-500, #6366f1);
108
+ color: white;
109
+ }
110
+
111
+ .filter-category-count {
112
+ font-size: 10px;
113
+ font-family: var(--font-mono, 'JetBrains Mono', monospace);
114
+ opacity: 0.7;
115
+ }
116
+
117
+ .filter-sort select {
118
+ padding: var(--space-2, 8px) var(--space-3, 12px);
119
+ background: var(--zinc-800, #27272a);
120
+ border: 1px solid rgba(255, 255, 255, 0.06);
121
+ border-radius: var(--radius-md, 6px);
122
+ color: var(--zinc-100, #f4f4f5);
123
+ font-size: var(--text-sm, 13px);
124
+ font-family: var(--font-sans, 'Inter', system-ui, sans-serif);
125
+ cursor: pointer;
126
+ }
127
+
128
+ .filter-sort select:focus {
129
+ outline: none;
130
+ border-color: var(--indigo-500, #6366f1);
131
+ }
132
+
133
+ /* ─── Templates Grid ─── */
134
+
135
+ .templates-grid {
136
+ display: grid;
137
+ grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
138
+ gap: var(--space-5, 20px);
139
+ }
140
+
141
+ /* ─── Template Card ─── */
142
+
143
+ .template-card {
144
+ display: flex;
145
+ flex-direction: column;
146
+ background: var(--zinc-900, #18181b);
147
+ border: 1px solid rgba(255, 255, 255, 0.06);
148
+ border-radius: var(--radius-xl, 12px);
149
+ overflow: hidden;
150
+ cursor: pointer;
151
+ transition: all var(--transition-fast, 0.15s ease);
152
+ text-align: left;
153
+ font-family: var(--font-sans, 'Inter', system-ui, sans-serif);
154
+ }
155
+
156
+ .template-card:hover {
157
+ border-color: var(--indigo-500, #6366f1);
158
+ transform: translateY(-2px);
159
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
160
+ }
161
+
162
+ .template-card-preview {
163
+ position: relative;
164
+ aspect-ratio: 16/9;
165
+ background: var(--zinc-800, #27272a);
166
+ overflow: hidden;
167
+ }
168
+
169
+ .template-card-preview img {
170
+ width: 100%;
171
+ height: 100%;
172
+ object-fit: cover;
173
+ transition: transform var(--transition-base, 0.3s ease);
174
+ }
175
+
176
+ .template-card:hover .template-card-preview img {
177
+ transform: scale(1.05);
178
+ }
179
+
180
+ .template-card-badge {
181
+ position: absolute;
182
+ top: var(--space-2, 8px);
183
+ right: var(--space-2, 8px);
184
+ padding: var(--space-1, 4px) var(--space-2, 8px);
185
+ background: var(--indigo-500, #6366f1);
186
+ border-radius: var(--radius-sm, 4px);
187
+ font-size: 10px;
188
+ font-weight: 600;
189
+ color: white;
190
+ text-transform: uppercase;
191
+ letter-spacing: 0.5px;
192
+ }
193
+
194
+ .template-card-info {
195
+ padding: var(--space-3-5, 14px);
196
+ }
197
+
198
+ .template-card-name {
199
+ margin: 0 0 var(--space-1, 4px);
200
+ font-size: var(--text-sm, 14px);
201
+ font-weight: 600;
202
+ color: var(--zinc-100, #f4f4f5);
203
+ white-space: nowrap;
204
+ overflow: hidden;
205
+ text-overflow: ellipsis;
206
+ }
207
+
208
+ .template-card-meta {
209
+ margin: 0 0 var(--space-2-5, 10px);
210
+ font-size: var(--text-xs, 12px);
211
+ color: var(--zinc-600, #52525b);
212
+ }
213
+
214
+ .template-card-footer {
215
+ display: flex;
216
+ justify-content: space-between;
217
+ align-items: center;
218
+ }
219
+
220
+ .template-card-author {
221
+ display: flex;
222
+ align-items: center;
223
+ gap: var(--space-1, 4px);
224
+ font-size: 11px;
225
+ color: var(--zinc-500, #71717a);
226
+ }
227
+
228
+ .template-verified-icon {
229
+ color: var(--indigo-500, #6366f1);
230
+ }
231
+
232
+ .template-card-rating {
233
+ display: flex;
234
+ align-items: center;
235
+ gap: var(--space-1, 4px);
236
+ font-size: 11px;
237
+ font-family: var(--font-mono, 'JetBrains Mono', monospace);
238
+ color: var(--amber-400, #fbbf24);
239
+ }
240
+
241
+ /* ─── Skeleton Loading ─── */
242
+
243
+ .template-card-skeleton {
244
+ aspect-ratio: 16/11;
245
+ background: linear-gradient(
246
+ 90deg,
247
+ var(--zinc-900, #18181b) 25%,
248
+ var(--zinc-800, #27272a) 50%,
249
+ var(--zinc-900, #18181b) 75%
250
+ );
251
+ background-size: 200% 100%;
252
+ animation: skeleton-shimmer 1.5s infinite;
253
+ border-radius: var(--radius-xl, 12px);
254
+ }
255
+
256
+ @keyframes skeleton-shimmer {
257
+ 0% {
258
+ background-position: 200% 0;
259
+ }
260
+ 100% {
261
+ background-position: -200% 0;
262
+ }
263
+ }
264
+
265
+ /* ─── Empty & Error States ─── */
266
+
267
+ .templates-empty,
268
+ .templates-error {
269
+ display: flex;
270
+ flex-direction: column;
271
+ align-items: center;
272
+ justify-content: center;
273
+ padding: var(--space-12, 48px);
274
+ color: var(--zinc-500, #71717a);
275
+ text-align: center;
276
+ }
277
+
278
+ .templates-empty-hint {
279
+ margin-top: var(--space-2, 8px);
280
+ font-size: var(--text-sm, 13px);
281
+ color: var(--zinc-600, #52525b);
282
+ }
283
+
284
+ .templates-error button {
285
+ margin-top: var(--space-4, 16px);
286
+ padding: var(--space-2, 8px) var(--space-4, 16px);
287
+ background: var(--indigo-500, #6366f1);
288
+ border: none;
289
+ border-radius: var(--radius-md, 6px);
290
+ color: white;
291
+ font-size: var(--text-sm, 13px);
292
+ font-family: var(--font-sans, 'Inter', system-ui, sans-serif);
293
+ cursor: pointer;
294
+ transition: background var(--transition-fast, 0.15s ease);
295
+ }
296
+
297
+ .templates-error button:hover {
298
+ background: var(--indigo-400, #818cf8);
299
+ }
300
+
301
+ /* ─── Load More ─── */
302
+
303
+ .templates-load-more {
304
+ display: flex;
305
+ justify-content: center;
306
+ margin-top: var(--space-6, 24px);
307
+ }
308
+
309
+ .templates-load-more button {
310
+ padding: var(--space-2-5, 10px) var(--space-6, 24px);
311
+ background: var(--zinc-800, #27272a);
312
+ border: 1px solid rgba(255, 255, 255, 0.06);
313
+ border-radius: var(--radius-lg, 8px);
314
+ color: var(--zinc-100, #f4f4f5);
315
+ font-size: var(--text-sm, 13px);
316
+ font-family: var(--font-sans, 'Inter', system-ui, sans-serif);
317
+ cursor: pointer;
318
+ transition: all var(--transition-fast, 0.15s ease);
319
+ }
320
+
321
+ .templates-load-more button:hover {
322
+ background: var(--indigo-500, #6366f1);
323
+ border-color: var(--indigo-500, #6366f1);
324
+ }
325
+
326
+ /* ─── Preview Dialog ─── */
327
+
328
+ .template-preview-overlay {
329
+ position: fixed;
330
+ inset: 0;
331
+ background: rgba(0, 0, 0, 0.8);
332
+ display: flex;
333
+ align-items: center;
334
+ justify-content: center;
335
+ z-index: 1000;
336
+ padding: var(--space-6, 24px);
337
+ }
338
+
339
+ .template-preview-dialog {
340
+ width: 100%;
341
+ max-width: 900px;
342
+ max-height: 90vh;
343
+ background: var(--zinc-900, #18181b);
344
+ border-radius: var(--radius-2xl, 16px);
345
+ overflow: hidden;
346
+ display: flex;
347
+ flex-direction: column;
348
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
349
+ font-family: var(--font-sans, 'Inter', system-ui, sans-serif);
350
+ }
351
+
352
+ .template-preview-header {
353
+ display: flex;
354
+ justify-content: space-between;
355
+ align-items: center;
356
+ padding: var(--space-4, 16px) var(--space-5, 20px);
357
+ border-bottom: 1px solid rgba(255, 255, 255, 0.06);
358
+ }
359
+
360
+ .template-preview-header h2 {
361
+ margin: 0;
362
+ font-size: var(--text-lg, 18px);
363
+ font-weight: 600;
364
+ color: var(--zinc-100, #f4f4f5);
365
+ letter-spacing: -0.01em;
366
+ }
367
+
368
+ .template-dialog-close {
369
+ display: flex;
370
+ align-items: center;
371
+ justify-content: center;
372
+ width: 32px;
373
+ height: 32px;
374
+ background: transparent;
375
+ border: none;
376
+ border-radius: var(--radius-md, 6px);
377
+ color: var(--zinc-600, #52525b);
378
+ cursor: pointer;
379
+ transition: all var(--transition-fast, 0.15s ease);
380
+ }
381
+
382
+ .template-dialog-close:hover {
383
+ background: var(--zinc-800, #27272a);
384
+ color: var(--zinc-100, #f4f4f5);
385
+ }
386
+
387
+ .template-preview-content {
388
+ display: flex;
389
+ flex: 1;
390
+ overflow: hidden;
391
+ }
392
+
393
+ .template-preview-media {
394
+ flex: 1;
395
+ background: black;
396
+ display: flex;
397
+ align-items: center;
398
+ justify-content: center;
399
+ min-height: 300px;
400
+ }
401
+
402
+ .template-preview-media video,
403
+ .template-preview-media img {
404
+ max-width: 100%;
405
+ max-height: 100%;
406
+ object-fit: contain;
407
+ }
408
+
409
+ .template-preview-details {
410
+ width: 280px;
411
+ padding: var(--space-5, 20px);
412
+ overflow-y: auto;
413
+ border-left: 1px solid rgba(255, 255, 255, 0.06);
414
+ display: flex;
415
+ flex-direction: column;
416
+ gap: var(--space-4, 16px);
417
+ }
418
+
419
+ .template-preview-description {
420
+ margin: 0;
421
+ font-size: var(--text-sm, 13px);
422
+ line-height: 1.6;
423
+ color: var(--zinc-400, #a1a1aa);
424
+ }
425
+
426
+ .template-preview-info-grid {
427
+ display: grid;
428
+ grid-template-columns: 1fr 1fr;
429
+ gap: var(--space-3, 12px);
430
+ }
431
+
432
+ .template-preview-info-item {
433
+ display: flex;
434
+ flex-direction: column;
435
+ gap: 2px;
436
+ }
437
+
438
+ .template-preview-info-item .label {
439
+ font-size: 11px;
440
+ color: var(--zinc-600, #52525b);
441
+ text-transform: uppercase;
442
+ letter-spacing: 0.5px;
443
+ }
444
+
445
+ .template-preview-info-item .value {
446
+ font-size: var(--text-sm, 14px);
447
+ font-weight: 500;
448
+ font-family: var(--font-mono, 'JetBrains Mono', monospace);
449
+ color: var(--zinc-100, #f4f4f5);
450
+ }
451
+
452
+ .template-preview-author {
453
+ display: flex;
454
+ flex-direction: column;
455
+ gap: var(--space-1-5, 6px);
456
+ }
457
+
458
+ .template-preview-author .label {
459
+ font-size: 11px;
460
+ color: var(--zinc-600, #52525b);
461
+ text-transform: uppercase;
462
+ letter-spacing: 0.5px;
463
+ }
464
+
465
+ .template-preview-author-info {
466
+ display: flex;
467
+ align-items: center;
468
+ gap: var(--space-2, 8px);
469
+ }
470
+
471
+ .template-preview-author-avatar {
472
+ width: 24px;
473
+ height: 24px;
474
+ border-radius: 50%;
475
+ }
476
+
477
+ .template-preview-author-name {
478
+ display: flex;
479
+ align-items: center;
480
+ gap: var(--space-1, 4px);
481
+ font-size: var(--text-sm, 13px);
482
+ color: var(--zinc-100, #f4f4f5);
483
+ }
484
+
485
+ .template-preview-tags {
486
+ display: flex;
487
+ flex-wrap: wrap;
488
+ gap: var(--space-1-5, 6px);
489
+ }
490
+
491
+ .template-preview-tag {
492
+ padding: var(--space-1, 4px) var(--space-2, 8px);
493
+ background: var(--zinc-800, #27272a);
494
+ border-radius: var(--radius-sm, 4px);
495
+ font-size: 11px;
496
+ color: var(--zinc-400, #a1a1aa);
497
+ }
498
+
499
+ .template-preview-stats {
500
+ display: flex;
501
+ gap: var(--space-4, 16px);
502
+ }
503
+
504
+ .template-preview-stat {
505
+ display: flex;
506
+ align-items: center;
507
+ gap: var(--space-1-5, 6px);
508
+ font-size: var(--text-xs, 12px);
509
+ font-family: var(--font-mono, 'JetBrains Mono', monospace);
510
+ color: var(--zinc-500, #71717a);
511
+ }
512
+
513
+ .template-preview-footer {
514
+ display: flex;
515
+ justify-content: flex-end;
516
+ gap: var(--space-3, 12px);
517
+ padding: var(--space-4, 16px) var(--space-5, 20px);
518
+ border-top: 1px solid rgba(255, 255, 255, 0.06);
519
+ }
520
+
521
+ /* ─── Use Template Dialog ─── */
522
+
523
+ .use-template-dialog {
524
+ width: 100%;
525
+ max-width: 480px;
526
+ background: var(--zinc-900, #18181b);
527
+ border-radius: var(--radius-2xl, 16px);
528
+ overflow: hidden;
529
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
530
+ font-family: var(--font-sans, 'Inter', system-ui, sans-serif);
531
+ }
532
+
533
+ .use-template-content {
534
+ padding: var(--space-5, 20px);
535
+ display: flex;
536
+ flex-direction: column;
537
+ gap: var(--space-4, 16px);
538
+ }
539
+
540
+ .use-template-intro {
541
+ margin: 0;
542
+ font-size: var(--text-sm, 14px);
543
+ color: var(--zinc-400, #a1a1aa);
544
+ }
545
+
546
+ .use-template-intro strong {
547
+ color: var(--zinc-100, #f4f4f5);
548
+ }
549
+
550
+ .use-template-form-group {
551
+ display: flex;
552
+ flex-direction: column;
553
+ gap: var(--space-1-5, 6px);
554
+ }
555
+
556
+ .use-template-form-group label {
557
+ font-size: var(--text-xs, 12px);
558
+ font-weight: 500;
559
+ color: var(--zinc-400, #a1a1aa);
560
+ }
561
+
562
+ .use-template-form-group input {
563
+ padding: var(--space-2-5, 10px) var(--space-3, 12px);
564
+ background: var(--zinc-800, #27272a);
565
+ border: 1px solid rgba(255, 255, 255, 0.06);
566
+ border-radius: var(--radius-md, 6px);
567
+ color: var(--zinc-100, #f4f4f5);
568
+ font-size: var(--text-sm, 14px);
569
+ font-family: var(--font-mono, 'JetBrains Mono', monospace);
570
+ }
571
+
572
+ .use-template-form-group input:focus {
573
+ outline: none;
574
+ border-color: var(--indigo-500, #6366f1);
575
+ }
576
+
577
+ .use-template-form-group input.has-error {
578
+ border-color: var(--red-500, #ef4444);
579
+ }
580
+
581
+ .use-template-error {
582
+ font-size: var(--text-xs, 12px);
583
+ color: var(--red-500, #ef4444);
584
+ }
585
+
586
+ .use-template-hint {
587
+ font-size: 11px;
588
+ color: var(--zinc-600, #52525b);
589
+ }
590
+
591
+ .use-template-props {
592
+ display: flex;
593
+ flex-direction: column;
594
+ gap: var(--space-2, 8px);
595
+ }
596
+
597
+ .use-template-props h4 {
598
+ margin: 0;
599
+ font-size: var(--text-xs, 12px);
600
+ font-weight: 500;
601
+ color: var(--zinc-400, #a1a1aa);
602
+ }
603
+
604
+ .use-template-props-code {
605
+ margin: 0;
606
+ padding: var(--space-3, 12px);
607
+ background: var(--zinc-800, #27272a);
608
+ border: 1px solid rgba(255, 255, 255, 0.06);
609
+ border-radius: var(--radius-md, 6px);
610
+ font-size: var(--text-xs, 12px);
611
+ font-family: var(--font-mono, 'JetBrains Mono', monospace);
612
+ color: var(--zinc-400, #a1a1aa);
613
+ overflow-x: auto;
614
+ max-height: 120px;
615
+ }
616
+
617
+ /* ─── Shared Button Styles ─── */
618
+
619
+ .template-btn-primary {
620
+ padding: var(--space-2-5, 10px) var(--space-5, 20px);
621
+ background: var(--indigo-500, #6366f1);
622
+ border: none;
623
+ border-radius: var(--radius-lg, 8px);
624
+ color: white;
625
+ font-size: var(--text-sm, 14px);
626
+ font-weight: 500;
627
+ font-family: var(--font-sans, 'Inter', system-ui, sans-serif);
628
+ cursor: pointer;
629
+ transition: all var(--transition-fast, 0.15s ease);
630
+ }
631
+
632
+ .template-btn-primary:hover:not(:disabled) {
633
+ background: var(--indigo-400, #818cf8);
634
+ }
635
+
636
+ .template-btn-primary:disabled {
637
+ opacity: 0.5;
638
+ cursor: not-allowed;
639
+ }
640
+
641
+ .template-btn-secondary {
642
+ padding: var(--space-2-5, 10px) var(--space-5, 20px);
643
+ background: transparent;
644
+ border: 1px solid rgba(255, 255, 255, 0.06);
645
+ border-radius: var(--radius-lg, 8px);
646
+ color: var(--zinc-100, #f4f4f5);
647
+ font-size: var(--text-sm, 14px);
648
+ font-family: var(--font-sans, 'Inter', system-ui, sans-serif);
649
+ cursor: pointer;
650
+ transition: all var(--transition-fast, 0.15s ease);
651
+ }
652
+
653
+ .template-btn-secondary:hover {
654
+ background: var(--zinc-800, #27272a);
655
+ }
656
+
657
+ /* ─── Responsive ─── */
658
+
659
+ @media (max-width: 768px) {
660
+ .template-preview-content {
661
+ flex-direction: column;
662
+ }
663
+
664
+ .template-preview-details {
665
+ width: 100%;
666
+ border-left: none;
667
+ border-top: 1px solid rgba(255, 255, 255, 0.06);
668
+ }
669
+
670
+ .filter-search input {
671
+ width: 100%;
672
+ }
673
+
674
+ .templates-filters {
675
+ flex-direction: column;
676
+ align-items: stretch;
677
+ }
678
+
679
+ .filter-categories {
680
+ order: 2;
681
+ }
682
+
683
+ .filter-sort {
684
+ order: 1;
685
+ }
686
+ }