@fluid-theme/core 0.4.3

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 (48) hide show
  1. package/AGENTS.md +32 -0
  2. package/CHANGELOG.md +159 -0
  3. package/CLAUDE.md +104 -0
  4. package/GEMINI.md +48 -0
  5. package/LICENSE +21 -0
  6. package/README.md +253 -0
  7. package/dist/fluid.min.css +2 -0
  8. package/fluid-agent-kit/README.md +57 -0
  9. package/fluid-agent-kit/skills/accessibility.md +41 -0
  10. package/fluid-agent-kit/skills/css-conventions.md +51 -0
  11. package/fluid-agent-kit/skills/image-optimization.md +115 -0
  12. package/fluid-agent-kit/skills/ux-rules.md +43 -0
  13. package/package.json +68 -0
  14. package/src/animations/scroll-reveal.css +224 -0
  15. package/src/components/accordion.css +250 -0
  16. package/src/components/alert.css +453 -0
  17. package/src/components/avatar.css +192 -0
  18. package/src/components/badge.css +182 -0
  19. package/src/components/button.css +387 -0
  20. package/src/components/card.css +650 -0
  21. package/src/components/chip.css +143 -0
  22. package/src/components/dropdown.css +335 -0
  23. package/src/components/empty-state.css +105 -0
  24. package/src/components/form.css +508 -0
  25. package/src/components/hero.css +293 -0
  26. package/src/components/indicator.css +455 -0
  27. package/src/components/loading.css +274 -0
  28. package/src/components/modal.css +364 -0
  29. package/src/components/nav.css +726 -0
  30. package/src/components/scroll-progress.css +104 -0
  31. package/src/components/search-input.css +125 -0
  32. package/src/components/settings-panel.css +603 -0
  33. package/src/components/step-indicator.css +188 -0
  34. package/src/components/table.css +350 -0
  35. package/src/components/themed-images.css +229 -0
  36. package/src/components/tooltip.css +247 -0
  37. package/src/components/version-badge.css +70 -0
  38. package/src/core/base.css +884 -0
  39. package/src/core/reset.css +159 -0
  40. package/src/core/tokens.css +2416 -0
  41. package/src/fluid.css +242 -0
  42. package/src/layouts/positioning.css +626 -0
  43. package/src/sections/cta.css +210 -0
  44. package/src/sections/features.css +356 -0
  45. package/src/sections/footer.css +283 -0
  46. package/src/sections/stats.css +234 -0
  47. package/src/sections/team.css +181 -0
  48. package/src/sections/testimonials.css +251 -0
@@ -0,0 +1,650 @@
1
+ /**
2
+ * Fluid Framework - Card Component
3
+ * @layer components
4
+ *
5
+ * Cards are containers that group related content.
6
+ * They provide subtle elevation and visual boundaries.
7
+ * Uses container queries for truly responsive behavior.
8
+ *
9
+ * Usage:
10
+ * <article class="card">...</article>
11
+ * <div class="card" data-variant="elevated">...</div>
12
+ * <article class="card" data-variant="outlined">...</article>
13
+ * <a href="#" class="card" data-interactive>Clickable card</a>
14
+ *
15
+ * Structure (optional):
16
+ * <article class="card">
17
+ * <img class="card__media" src="..." alt="...">
18
+ * <div class="card__content">
19
+ * <h3 class="card__title">Title</h3>
20
+ * <p class="card__description">Description</p>
21
+ * </div>
22
+ * <footer class="card__footer">Actions</footer>
23
+ * </article>
24
+ */
25
+
26
+ @layer components {
27
+ /* Base card */
28
+ .card {
29
+ /* Container for queries - only when explicitly enabled */
30
+ container-name: card;
31
+
32
+ /* Layout */
33
+ display: flex;
34
+ flex-direction: column;
35
+
36
+ /* Prevent collapse in grid/flex layouts */
37
+ min-inline-size: 0;
38
+
39
+ /* Visual */
40
+ background-color: var(--_card-bg, var(--color-surface-raised));
41
+ border: var(--border-width) solid var(--_card-border, var(--color-border-subtle));
42
+ border-radius: var(--radius-card, var(--radius-xl));
43
+
44
+ /* Overflow: clip media but allow focus rings and shadows to paint */
45
+ overflow: clip;
46
+ overflow-clip-margin: 4px;
47
+
48
+ /* Transitions */
49
+ transition:
50
+ box-shadow var(--duration-normal) var(--ease-fluid),
51
+ border-color var(--duration-normal) var(--ease-fluid),
52
+ transform var(--duration-normal) var(--ease-settle);
53
+ }
54
+
55
+ /* Enable container queries only when needed */
56
+ .card[data-container] {
57
+ container-type: inline-size;
58
+ }
59
+
60
+
61
+ /* ========================================
62
+ VARIANTS
63
+ Different visual treatments
64
+ ======================================== */
65
+
66
+ /* Elevated - floating appearance */
67
+ .card[data-variant="elevated"] {
68
+ --_card-border: transparent;
69
+ box-shadow: var(--shadow-md);
70
+ }
71
+
72
+ .card[data-variant="elevated"]:hover {
73
+ box-shadow: var(--shadow-lg);
74
+ }
75
+
76
+ /* Dark mode: use accent glow since shadows are barely visible on dark */
77
+ @media (prefers-color-scheme: dark) {
78
+ .card[data-variant="elevated"] {
79
+ box-shadow:
80
+ 0 0 0 1px oklch(from var(--accent) l c h / 0.15),
81
+ 0 4px 20px oklch(from var(--accent) l c h / 0.1);
82
+ }
83
+
84
+ .card[data-variant="elevated"]:hover {
85
+ box-shadow:
86
+ 0 0 0 1px oklch(from var(--accent) l c h / 0.25),
87
+ 0 8px 30px oklch(from var(--accent) l c h / 0.15);
88
+ }
89
+ }
90
+
91
+ /* Also support explicit dark theme */
92
+ [data-theme="dark"] .card[data-variant="elevated"] {
93
+ box-shadow:
94
+ 0 0 0 1px oklch(from var(--accent) l c h / 0.15),
95
+ 0 4px 20px oklch(from var(--accent) l c h / 0.1);
96
+ }
97
+
98
+ [data-theme="dark"] .card[data-variant="elevated"]:hover {
99
+ box-shadow:
100
+ 0 0 0 1px oklch(from var(--accent) l c h / 0.25),
101
+ 0 8px 30px oklch(from var(--accent) l c h / 0.15);
102
+ }
103
+
104
+ /* Outlined - border emphasis */
105
+ .card[data-variant="outlined"] {
106
+ --_card-bg: transparent;
107
+ --_card-border: var(--color-border);
108
+ }
109
+
110
+ /* Ghost - minimal, content-focused */
111
+ .card[data-variant="ghost"] {
112
+ --_card-bg: transparent;
113
+ --_card-border: transparent;
114
+ }
115
+
116
+ /* Filled - solid background */
117
+ .card[data-variant="filled"] {
118
+ --_card-bg: var(--color-surface);
119
+ --_card-border: transparent;
120
+ }
121
+
122
+
123
+ /* ========================================
124
+ INTERACTIVE CARDS
125
+ Clickable/hoverable cards
126
+ ======================================== */
127
+
128
+ .card[data-interactive],
129
+ a.card {
130
+ cursor: pointer;
131
+ text-decoration: none;
132
+ color: inherit;
133
+ }
134
+
135
+ .card[data-interactive]:hover,
136
+ a.card:hover {
137
+ --_card-border: var(--accent);
138
+ box-shadow: var(--shadow-sm);
139
+ }
140
+
141
+ .card[data-interactive]:active,
142
+ a.card:active {
143
+ transform: scale(0.99);
144
+ }
145
+
146
+ .card[data-interactive]:focus-visible,
147
+ a.card:focus-visible {
148
+ outline: 2px solid transparent;
149
+ box-shadow:
150
+ var(--shadow-glow),
151
+ 0 0 0 2px var(--color-background),
152
+ 0 0 0 4px var(--accent);
153
+ }
154
+
155
+
156
+ /* ========================================
157
+ CARD STRUCTURE
158
+ Optional semantic sections
159
+ ======================================== */
160
+
161
+ /* Media - images, video, etc. */
162
+ .card__media {
163
+ /* Full width, maintain aspect */
164
+ inline-size: 100%;
165
+ block-size: auto;
166
+ object-fit: cover;
167
+
168
+ /* Remove from flow for overlay positioning */
169
+ flex-shrink: 0;
170
+
171
+ /* Auto-apply theme-aware duotone tint */
172
+ filter: grayscale(100%) contrast(1.1);
173
+ transition: filter var(--duration-normal) var(--ease-fluid);
174
+ }
175
+
176
+ /* Duotone wrapper for blend mode overlay */
177
+ .card__media-wrap {
178
+ position: relative;
179
+ overflow: hidden;
180
+ }
181
+
182
+ .card__media-wrap::after {
183
+ content: "";
184
+ position: absolute;
185
+ inset: 0;
186
+ background: linear-gradient(
187
+ 135deg,
188
+ var(--duotone-dark, oklch(0.3 0.1 220)) 0%,
189
+ var(--duotone-light, oklch(0.7 0.1 200)) 100%
190
+ );
191
+ mix-blend-mode: multiply;
192
+ opacity: 0.85;
193
+ pointer-events: none;
194
+ transition: opacity var(--duration-normal) var(--ease-fluid);
195
+ }
196
+
197
+ /* Hover: reveal more of original image */
198
+ .card:hover .card__media {
199
+ filter: grayscale(60%) contrast(1.05);
200
+ }
201
+
202
+ .card:hover .card__media-wrap::after {
203
+ opacity: 0.6;
204
+ }
205
+
206
+ /* Opt-out of duotone effect */
207
+ .card__media[data-no-duotone],
208
+ .card[data-no-duotone] .card__media {
209
+ filter: none;
210
+ }
211
+
212
+ /* Focal point control for card media */
213
+ .card__media[data-focus="top"] { object-position: center top; }
214
+ .card__media[data-focus="bottom"] { object-position: center bottom; }
215
+ .card__media[data-focus="left"] { object-position: left center; }
216
+ .card__media[data-focus="right"] { object-position: right center; }
217
+ .card__media[data-focus="center"] { object-position: center center; }
218
+
219
+ /* Custom focal point via CSS custom properties */
220
+ .card__media[style*="--focus"] {
221
+ object-position: var(--focus-x, 50%) var(--focus-y, 50%);
222
+ }
223
+
224
+ /* Aspect ratio variants for media */
225
+ .card__media[data-aspect="square"] {
226
+ aspect-ratio: 1;
227
+ }
228
+
229
+ .card__media[data-aspect="video"] {
230
+ aspect-ratio: 16 / 9;
231
+ }
232
+
233
+ .card__media[data-aspect="portrait"] {
234
+ aspect-ratio: 3 / 4;
235
+ }
236
+
237
+ .card__media[data-aspect="wide"] {
238
+ aspect-ratio: 21 / 9;
239
+ }
240
+
241
+ /* Content area */
242
+ .card__content {
243
+ flex: 1;
244
+ padding: var(--space-5);
245
+ display: flex;
246
+ flex-direction: column;
247
+ gap: var(--space-3);
248
+ }
249
+
250
+ /* Title */
251
+ .card__title {
252
+ font-size: var(--font-size-lg);
253
+ font-weight: var(--weight-semibold);
254
+ line-height: var(--leading-tight);
255
+ margin: 0;
256
+ }
257
+
258
+ /* Description */
259
+ .card__description {
260
+ color: var(--color-text-muted);
261
+ margin: 0;
262
+ }
263
+
264
+ /* Metadata - tags, dates, etc. */
265
+ .card__meta {
266
+ display: flex;
267
+ flex-wrap: wrap;
268
+ gap: var(--space-2);
269
+ font-size: var(--font-size-sm);
270
+ color: var(--color-text-subtle);
271
+ }
272
+
273
+ /* Footer - actions, links */
274
+ .card__footer {
275
+ padding: var(--space-4) var(--space-5);
276
+ border-block-start: 1px solid var(--color-border-subtle);
277
+ display: flex;
278
+ gap: var(--space-3);
279
+ align-items: center;
280
+ }
281
+
282
+ /* Push footer actions to end */
283
+ .card__footer[data-align="end"] {
284
+ justify-content: flex-end;
285
+ }
286
+
287
+ .card__footer[data-align="between"] {
288
+ justify-content: space-between;
289
+ }
290
+
291
+
292
+ /* ========================================
293
+ SIZE VARIANTS
294
+ Compact for lists, spacious for features
295
+ ======================================== */
296
+
297
+ .card[data-size="sm"] .card__content {
298
+ padding: var(--space-4);
299
+ gap: var(--space-2);
300
+ }
301
+
302
+ .card[data-size="sm"] .card__title {
303
+ font-size: var(--font-size-base);
304
+ }
305
+
306
+ .card[data-size="sm"] .card__footer {
307
+ padding: var(--space-3) var(--space-4);
308
+ }
309
+
310
+ .card[data-size="lg"] .card__content {
311
+ padding: var(--space-6);
312
+ gap: var(--space-4);
313
+ }
314
+
315
+ .card[data-size="lg"] .card__title {
316
+ font-size: var(--font-size-xl);
317
+ }
318
+
319
+ .card[data-size="lg"] .card__footer {
320
+ padding: var(--space-5) var(--space-6);
321
+ }
322
+
323
+
324
+ /* ========================================
325
+ CONTAINER QUERY RESPONSIVE
326
+ Cards adapt to their container, not viewport
327
+ ======================================== */
328
+
329
+ /* Compact card in narrow containers */
330
+ @container card (max-width: 20rem) {
331
+ .card__content {
332
+ padding: var(--space-4);
333
+ }
334
+
335
+ .card__title {
336
+ font-size: var(--font-size-base);
337
+ }
338
+
339
+ .card__footer {
340
+ padding: var(--space-3) var(--space-4);
341
+ flex-direction: column;
342
+ align-items: stretch;
343
+ }
344
+ }
345
+
346
+ /* Horizontal layout in wider containers */
347
+ @container card (min-width: 30rem) {
348
+ .card[data-layout="horizontal"] {
349
+ flex-direction: row;
350
+ }
351
+
352
+ .card[data-layout="horizontal"] .card__media {
353
+ inline-size: 40%;
354
+ max-inline-size: 16rem;
355
+ block-size: auto;
356
+ }
357
+
358
+ .card[data-layout="horizontal"] .card__content {
359
+ justify-content: center;
360
+ }
361
+ }
362
+
363
+
364
+ /* ========================================
365
+ SPECIAL CARD TYPES
366
+ Common card patterns
367
+ ======================================== */
368
+
369
+ /* Profile card */
370
+ .card[data-type="profile"] {
371
+ text-align: center;
372
+ }
373
+
374
+ .card[data-type="profile"] .card__media {
375
+ inline-size: 6rem;
376
+ block-size: 6rem;
377
+ border-radius: var(--radius-full);
378
+ margin: var(--space-5) auto 0;
379
+ }
380
+
381
+ /* Stat card */
382
+ .card[data-type="stat"] .card__content {
383
+ text-align: center;
384
+ gap: var(--space-2);
385
+ }
386
+
387
+ .card[data-type="stat"] .card__value {
388
+ font-size: var(--font-size-3xl);
389
+ font-weight: var(--weight-bold);
390
+ line-height: var(--leading-none);
391
+ color: var(--accent);
392
+ }
393
+
394
+ .card[data-type="stat"] .card__title {
395
+ font-size: var(--font-size-sm);
396
+ font-weight: var(--weight-normal);
397
+ color: var(--color-text-muted);
398
+ }
399
+
400
+ /* Feature card - emphasized */
401
+ .card[data-type="feature"] {
402
+ text-align: center;
403
+ padding: var(--space-6);
404
+ }
405
+
406
+ .card[data-type="feature"] .card__icon {
407
+ inline-size: 3rem;
408
+ block-size: 3rem;
409
+ margin-inline: auto;
410
+ margin-block-end: var(--space-4);
411
+ color: var(--accent);
412
+ }
413
+
414
+ /* Testimonial card - quote with attribution */
415
+ .card[data-type="testimonial"] .card__content {
416
+ gap: var(--space-4);
417
+ }
418
+
419
+ .card[data-type="testimonial"] .card__rating {
420
+ display: flex;
421
+ gap: 0.125rem;
422
+ color: var(--color-rating);
423
+ }
424
+
425
+ .card[data-type="testimonial"] .card__quote {
426
+ font-style: italic;
427
+ line-height: var(--leading-relaxed);
428
+ color: var(--color-text);
429
+ }
430
+
431
+ .card[data-type="testimonial"] .card__quote::before {
432
+ content: "\201C";
433
+ font-size: var(--font-size-3xl);
434
+ font-style: normal;
435
+ line-height: 0;
436
+ vertical-align: -0.35em;
437
+ color: var(--accent);
438
+ margin-inline-end: var(--space-1);
439
+ }
440
+
441
+ .card[data-type="testimonial"] .card__attribution {
442
+ display: flex;
443
+ align-items: center;
444
+ gap: var(--space-3);
445
+ font-size: var(--font-size-sm);
446
+ }
447
+
448
+ .card[data-type="testimonial"] .card__author {
449
+ font-weight: var(--weight-semibold);
450
+ font-style: normal;
451
+ color: var(--color-text);
452
+ }
453
+
454
+ .card[data-type="testimonial"] .card__role {
455
+ color: var(--color-text-muted);
456
+ }
457
+
458
+ /* Pricing card - plan comparison */
459
+ .card[data-type="pricing"] {
460
+ text-align: center;
461
+ overflow: visible;
462
+ position: relative;
463
+ }
464
+
465
+ .card[data-type="pricing"] .card__price {
466
+ font-size: var(--font-size-4xl);
467
+ font-weight: var(--weight-bold);
468
+ line-height: var(--leading-none);
469
+ margin-block-end: var(--space-1);
470
+ }
471
+
472
+ .card[data-type="pricing"] .card__price-period {
473
+ font-size: var(--font-size-sm);
474
+ color: var(--color-text-muted);
475
+ font-weight: var(--weight-normal);
476
+ }
477
+
478
+ /* Featured/popular pricing card */
479
+ .card[data-type="pricing"][data-featured] {
480
+ border: 2px solid var(--accent);
481
+ transform: scale(1.03);
482
+ }
483
+
484
+ .card[data-type="pricing"][data-featured] > .badge {
485
+ position: absolute;
486
+ inset-block-start: 0;
487
+ inset-inline-start: 50%;
488
+ transform: translate(-50%, -50%);
489
+ }
490
+
491
+ /* Pricing feature list */
492
+ .card[data-type="pricing"] .card__features {
493
+ list-style: none;
494
+ padding: 0;
495
+ margin: 0;
496
+ text-align: start;
497
+ }
498
+
499
+ .card[data-type="pricing"] .card__features li {
500
+ display: flex;
501
+ align-items: center;
502
+ gap: var(--space-2);
503
+ padding-block: var(--space-2);
504
+ border-block-end: var(--border-width) solid var(--color-border-subtle);
505
+ }
506
+
507
+ .card[data-type="pricing"] .card__features li:last-child {
508
+ border-block-end: none;
509
+ }
510
+
511
+ .card[data-type="pricing"] .card__features .check {
512
+ color: var(--color-success);
513
+ flex-shrink: 0;
514
+ }
515
+
516
+
517
+ /* ========================================
518
+ CARD GROUPS
519
+ Multiple cards together
520
+ ======================================== */
521
+
522
+ .card-group {
523
+ display: grid;
524
+ gap: var(--space-5);
525
+ grid-template-columns: repeat(
526
+ auto-fit,
527
+ minmax(min(100%, var(--card-min-width, 18rem)), 1fr)
528
+ );
529
+ }
530
+
531
+ /* Equal height cards */
532
+ .card-group[data-equal-height] > .card {
533
+ block-size: 100%;
534
+ }
535
+
536
+ .card-group[data-equal-height] > .card .card__content {
537
+ flex: 1;
538
+ }
539
+
540
+
541
+ /* ========================================
542
+ THEME-SPECIFIC CARD STYLES
543
+ Motion styles affect card appearance
544
+ ======================================== */
545
+
546
+ /* Still: Crisp, no-nonsense borders */
547
+ [data-motion="still"] .card {
548
+ border-width: 1px;
549
+ border-color: var(--color-border);
550
+ box-shadow: none;
551
+ }
552
+
553
+ /* Serene: Extra soft, pillowy cards with gentle shadows */
554
+ [data-motion="serene"] .card {
555
+ box-shadow: var(--shadow-sm);
556
+ }
557
+ [data-motion="serene"] .card[data-variant="elevated"] {
558
+ box-shadow: var(--shadow-md);
559
+ }
560
+ [data-motion="serene"] .card:hover {
561
+ box-shadow: var(--shadow-md);
562
+ }
563
+
564
+ /* Cascade: Prominent layered shadows, bubbly elevated feel */
565
+ [data-motion="cascade"] .card {
566
+ box-shadow:
567
+ 0 4px 12px oklch(0 0 0 / 0.06),
568
+ 0 12px 28px oklch(0 0 0 / 0.1);
569
+ }
570
+ [data-motion="cascade"] .card:hover {
571
+ transform: translateY(-4px);
572
+ box-shadow:
573
+ 0 8px 20px oklch(0 0 0 / 0.08),
574
+ 0 20px 40px oklch(0 0 0 / 0.14);
575
+ }
576
+ [data-motion="cascade"] .card[data-variant="elevated"] {
577
+ box-shadow:
578
+ 0 8px 20px oklch(0 0 0 / 0.08),
579
+ 0 24px 48px oklch(0 0 0 / 0.12);
580
+ }
581
+
582
+ /* Rapids: Hard offset shadows, energetic hover */
583
+ [data-motion="rapids"] .card {
584
+ box-shadow: var(--shadow-offset);
585
+ transition:
586
+ transform 150ms var(--ease-fluid),
587
+ box-shadow 150ms var(--ease-fluid);
588
+ }
589
+ [data-motion="rapids"] .card:hover {
590
+ transform: translate(-2px, -2px);
591
+ box-shadow: var(--shadow-offset-hover);
592
+ }
593
+ [data-motion="rapids"] .card:active {
594
+ transform: translate(1px, 1px);
595
+ box-shadow: 2px 2px 0 oklch(0 0 0 / 0.15);
596
+ }
597
+
598
+ /* Tsunami: 3D depth effect with dramatic shadows */
599
+ [data-motion="tsunami"] .card {
600
+ transform-style: preserve-3d;
601
+ transition: transform 0.4s var(--ease-fluid), box-shadow 0.4s var(--ease-fluid);
602
+ box-shadow:
603
+ 0 15px 35px oklch(0 0 0 / 0.2),
604
+ 0 5px 15px oklch(0 0 0 / 0.1);
605
+ }
606
+ [data-motion="tsunami"] .card:hover {
607
+ transform: translateY(-8px) scale(1.01);
608
+ box-shadow:
609
+ 0 25px 50px oklch(0 0 0 / 0.25),
610
+ 0 10px 20px oklch(0 0 0 / 0.15),
611
+ 0 0 40px oklch(from var(--accent) l c h / 0.15);
612
+ }
613
+
614
+
615
+ /* ========================================
616
+ REDUCED MOTION
617
+ ======================================== */
618
+
619
+ @media (prefers-reduced-motion: reduce) {
620
+ .card {
621
+ transition: none;
622
+ }
623
+
624
+ .card[data-interactive]:active,
625
+ a.card:active {
626
+ transform: none;
627
+ }
628
+
629
+ [data-motion="cascade"] .card:hover,
630
+ [data-motion="rapids"] .card:hover,
631
+ [data-motion="rapids"] .card:active,
632
+ [data-motion="tsunami"] .card:hover {
633
+ transform: none;
634
+ transition: none;
635
+ }
636
+
637
+ [data-motion="rapids"] .card {
638
+ transition: none;
639
+ }
640
+
641
+ [data-motion="tsunami"] .card {
642
+ transition: none;
643
+ }
644
+
645
+ .card__media,
646
+ .card__media-wrap::after {
647
+ transition: none;
648
+ }
649
+ }
650
+ }