@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,143 @@
1
+ /**
2
+ * Fluid Framework - Chip / Filter Tag Component
3
+ * @layer components
4
+ *
5
+ * Dismissable tags for active filters, selections, and removable items.
6
+ *
7
+ * Usage:
8
+ * <span class="chip">
9
+ * <span class="chip__label">Color: Blue</span>
10
+ * <button class="chip__remove" aria-label="Remove Color: Blue filter">&times;</button>
11
+ * </span>
12
+ *
13
+ * <!-- Non-dismissable (no remove button) -->
14
+ * <span class="chip">
15
+ * <span class="chip__label">Category</span>
16
+ * </span>
17
+ *
18
+ * <!-- Active filter bar -->
19
+ * <div class="chip-group">
20
+ * <span class="chip">...</span>
21
+ * <span class="chip">...</span>
22
+ * <button class="chip-group__clear" data-variant="ghost" data-size="sm">Clear All</button>
23
+ * </div>
24
+ *
25
+ * Variants: data-variant="filled|outline"
26
+ */
27
+
28
+ @layer components {
29
+ .chip {
30
+ display: inline-flex;
31
+ align-items: center;
32
+ gap: var(--space-1);
33
+ padding: var(--space-1) var(--space-3);
34
+ font-size: var(--font-size-sm);
35
+ line-height: var(--leading-tight);
36
+ color: var(--color-text);
37
+ background: var(--color-surface);
38
+ border: var(--border-width) solid var(--color-border);
39
+ border-radius: var(--radius-full);
40
+ white-space: nowrap;
41
+ transition: background-color var(--duration-fast) var(--ease-fluid);
42
+ }
43
+
44
+ .chip:hover {
45
+ background: var(--color-surface-raised);
46
+ }
47
+
48
+ .chip__label {
49
+ padding-inline-end: var(--space-1);
50
+ }
51
+
52
+ .chip__remove {
53
+ --_btn-bg: transparent;
54
+ --_btn-shadow: none;
55
+
56
+ position: relative;
57
+ display: inline-flex;
58
+ align-items: center;
59
+ justify-content: center;
60
+ inline-size: 1.25rem;
61
+ block-size: 1.25rem;
62
+ padding: 0;
63
+ border-radius: var(--radius-full);
64
+ font-size: var(--font-size-sm);
65
+ line-height: 1;
66
+ color: var(--color-text-muted);
67
+ cursor: pointer;
68
+ transition: color var(--duration-fast) var(--ease-fluid),
69
+ background-color var(--duration-fast) var(--ease-fluid);
70
+ }
71
+
72
+ .chip__remove:hover {
73
+ color: var(--color-error);
74
+ background: var(--color-error-subtle);
75
+ }
76
+
77
+ .chip__remove:focus-visible {
78
+ color: var(--color-error);
79
+ box-shadow: var(--shadow-glow);
80
+ }
81
+
82
+ /* Extend touch target to 44px minimum */
83
+ .chip__remove::before {
84
+ content: "";
85
+ position: absolute;
86
+ inset: -0.75rem;
87
+ }
88
+
89
+
90
+ /* ========================================
91
+ VARIANTS
92
+ ======================================== */
93
+
94
+ .chip[data-variant="filled"] {
95
+ background: var(--accent-subtle);
96
+ border-color: transparent;
97
+ color: var(--accent);
98
+ }
99
+
100
+ .chip[data-variant="filled"]:hover {
101
+ background: var(--accent);
102
+ color: var(--white);
103
+ }
104
+
105
+ .chip[data-variant="filled"]:hover .chip__remove:hover {
106
+ color: var(--white);
107
+ background: oklch(from var(--accent) calc(l - 0.1) c h);
108
+ }
109
+
110
+ .chip[data-variant="outline"] {
111
+ background: transparent;
112
+ }
113
+
114
+
115
+ /* ========================================
116
+ CHIP GROUP
117
+ Container for active filter chips
118
+ ======================================== */
119
+
120
+ .chip-group {
121
+ display: flex;
122
+ flex-wrap: wrap;
123
+ align-items: center;
124
+ gap: var(--space-2);
125
+ }
126
+
127
+ .chip-group__clear {
128
+ font-size: var(--font-size-sm);
129
+ color: var(--color-text-muted);
130
+ }
131
+
132
+
133
+ /* ========================================
134
+ REDUCED MOTION
135
+ ======================================== */
136
+
137
+ @media (prefers-reduced-motion: reduce) {
138
+ .chip,
139
+ .chip__remove {
140
+ transition: none;
141
+ }
142
+ }
143
+ }
@@ -0,0 +1,335 @@
1
+ /**
2
+ * Fluid Framework - Dropdown/Select Component
3
+ * @layer components
4
+ *
5
+ * Standalone dropdown menus for actions, selections, and context menus.
6
+ * Separate from nav dropdowns — usable anywhere in the page.
7
+ *
8
+ * Usage:
9
+ * <div class="dropdown">
10
+ * <button class="dropdown__trigger">
11
+ * Options
12
+ * <svg class="dropdown__chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"/></svg>
13
+ * </button>
14
+ * <div class="dropdown__menu">
15
+ * <a href="#" class="dropdown__item">Edit</a>
16
+ * <a href="#" class="dropdown__item">Duplicate</a>
17
+ * <div class="dropdown__divider"></div>
18
+ * <a href="#" class="dropdown__item" data-danger>Delete</a>
19
+ * </div>
20
+ * </div>
21
+ *
22
+ * Positions: data-position="top|bottom-end|top-end"
23
+ * Widths: data-width="auto|full|fixed"
24
+ */
25
+
26
+ @layer components {
27
+ /* ========================================
28
+ DROPDOWN CONTAINER
29
+ ======================================== */
30
+
31
+ .dropdown {
32
+ position: relative;
33
+ display: inline-block;
34
+ }
35
+
36
+
37
+ /* ========================================
38
+ DROPDOWN TRIGGER
39
+ ======================================== */
40
+
41
+ .dropdown__trigger {
42
+ display: inline-flex;
43
+ align-items: center;
44
+ gap: var(--space-2);
45
+ }
46
+
47
+ .dropdown__chevron {
48
+ inline-size: 1rem;
49
+ block-size: 1rem;
50
+ flex-shrink: 0;
51
+ transition: transform var(--duration-fast) var(--ease-settle);
52
+ }
53
+
54
+ /* Rotate chevron when open */
55
+ .dropdown[open] .dropdown__chevron,
56
+ .dropdown[data-open] .dropdown__chevron {
57
+ transform: rotate(180deg);
58
+ }
59
+
60
+
61
+ /* ========================================
62
+ DROPDOWN MENU
63
+ ======================================== */
64
+
65
+ .dropdown__menu {
66
+ /* Positioning */
67
+ position: absolute;
68
+ z-index: var(--z-dropdown);
69
+ inset-block-start: calc(100% + var(--space-1));
70
+ inset-inline-start: 0;
71
+
72
+ /* Sizing */
73
+ min-inline-size: 12rem;
74
+ max-inline-size: min(calc(100vw - 2rem), 20rem);
75
+ max-block-size: 20rem;
76
+ overflow-y: auto;
77
+
78
+ /* Visual */
79
+ background: var(--color-surface-raised);
80
+ border: var(--border-width) solid var(--color-border-subtle);
81
+ border-radius: var(--radius-lg);
82
+ box-shadow: var(--shadow-lg);
83
+ padding: var(--space-1);
84
+
85
+ /* Hidden by default */
86
+ opacity: 0;
87
+ visibility: hidden;
88
+ transform: translateY(-4px) scale(0.98);
89
+ pointer-events: none;
90
+
91
+ /* Transitions */
92
+ transition:
93
+ opacity var(--duration-fast) var(--ease-fluid),
94
+ transform var(--duration-fast) var(--ease-settle),
95
+ visibility var(--duration-fast) var(--ease-fluid);
96
+ }
97
+
98
+ /* Show on hover or when open attribute/data-open is present */
99
+ .dropdown:hover > .dropdown__menu,
100
+ .dropdown:focus-within > .dropdown__menu,
101
+ .dropdown[open] > .dropdown__menu,
102
+ .dropdown[data-open] > .dropdown__menu {
103
+ opacity: 1;
104
+ visibility: visible;
105
+ transform: translateY(0) scale(1);
106
+ pointer-events: auto;
107
+ }
108
+
109
+ /* Scrollbar styling */
110
+ .dropdown__menu::-webkit-scrollbar {
111
+ inline-size: 4px;
112
+ }
113
+
114
+ .dropdown__menu::-webkit-scrollbar-thumb {
115
+ background: var(--color-border);
116
+ border-radius: var(--radius-full);
117
+ }
118
+
119
+
120
+ /* ========================================
121
+ POSITION VARIANTS
122
+ ======================================== */
123
+
124
+ /* Bottom-end (right-aligned) */
125
+ .dropdown[data-position="bottom-end"] .dropdown__menu {
126
+ inset-inline-start: auto;
127
+ inset-inline-end: 0;
128
+ }
129
+
130
+ /* Top (above trigger) */
131
+ .dropdown[data-position="top"] .dropdown__menu {
132
+ inset-block-start: auto;
133
+ inset-block-end: calc(100% + var(--space-1));
134
+ transform: translateY(4px) scale(0.98);
135
+ }
136
+
137
+ .dropdown[data-position="top"]:hover > .dropdown__menu,
138
+ .dropdown[data-position="top"]:focus-within > .dropdown__menu,
139
+ .dropdown[data-position="top"][open] > .dropdown__menu,
140
+ .dropdown[data-position="top"][data-open] > .dropdown__menu {
141
+ transform: translateY(0) scale(1);
142
+ }
143
+
144
+ /* Top-end */
145
+ .dropdown[data-position="top-end"] .dropdown__menu {
146
+ inset-block-start: auto;
147
+ inset-block-end: calc(100% + var(--space-1));
148
+ inset-inline-start: auto;
149
+ inset-inline-end: 0;
150
+ transform: translateY(4px) scale(0.98);
151
+ }
152
+
153
+ .dropdown[data-position="top-end"]:hover > .dropdown__menu,
154
+ .dropdown[data-position="top-end"]:focus-within > .dropdown__menu,
155
+ .dropdown[data-position="top-end"][open] > .dropdown__menu,
156
+ .dropdown[data-position="top-end"][data-open] > .dropdown__menu {
157
+ transform: translateY(0) scale(1);
158
+ }
159
+
160
+
161
+ /* ========================================
162
+ WIDTH VARIANTS
163
+ ======================================== */
164
+
165
+ .dropdown[data-width="full"] .dropdown__menu {
166
+ inline-size: 100%;
167
+ min-inline-size: 100%;
168
+ }
169
+
170
+ .dropdown[data-width="fixed"] .dropdown__menu {
171
+ inline-size: 16rem;
172
+ }
173
+
174
+
175
+ /* ========================================
176
+ DROPDOWN ITEMS
177
+ ======================================== */
178
+
179
+ .dropdown__item {
180
+ display: flex;
181
+ align-items: center;
182
+ gap: var(--space-3);
183
+ padding: var(--space-2) var(--space-3);
184
+ border-radius: var(--radius-md);
185
+ font-size: var(--font-size-sm);
186
+ color: var(--color-text);
187
+ text-decoration: none;
188
+ cursor: pointer;
189
+ white-space: nowrap;
190
+ transition:
191
+ background-color var(--duration-fast) var(--ease-fluid),
192
+ color var(--duration-fast) var(--ease-fluid);
193
+ }
194
+
195
+ .dropdown__item:hover {
196
+ background: color-mix(in oklch, var(--accent) 10%, var(--color-background));
197
+ color: var(--accent);
198
+ }
199
+
200
+ .dropdown__item:focus-visible {
201
+ outline: 2px solid var(--color-focus);
202
+ outline-offset: -2px;
203
+ }
204
+
205
+ /* Active/selected item */
206
+ .dropdown__item[aria-selected="true"],
207
+ .dropdown__item[data-active] {
208
+ background: color-mix(in oklch, var(--accent) 12%, var(--color-background));
209
+ color: var(--accent);
210
+ font-weight: var(--weight-medium);
211
+ }
212
+
213
+ /* Disabled item */
214
+ .dropdown__item[aria-disabled="true"],
215
+ .dropdown__item[disabled] {
216
+ opacity: 0.5;
217
+ pointer-events: none;
218
+ }
219
+
220
+ /* Danger item */
221
+ .dropdown__item[data-danger] {
222
+ color: var(--color-error);
223
+ }
224
+
225
+ .dropdown__item[data-danger]:hover {
226
+ background: var(--color-error-subtle);
227
+ color: var(--color-error);
228
+ }
229
+
230
+
231
+ /* ========================================
232
+ DROPDOWN EXTRAS
233
+ ======================================== */
234
+
235
+ /* Divider line */
236
+ .dropdown__divider {
237
+ block-size: 1px;
238
+ margin: var(--space-1) 0;
239
+ background: var(--color-border-subtle);
240
+ }
241
+
242
+ /* Section header */
243
+ .dropdown__header {
244
+ padding: var(--space-2) var(--space-3);
245
+ font-size: var(--font-size-xs);
246
+ font-weight: var(--weight-semibold);
247
+ color: var(--color-text-subtle);
248
+ text-transform: uppercase;
249
+ letter-spacing: var(--tracking-wider);
250
+ }
251
+
252
+ /* Item icon slot */
253
+ .dropdown__item-icon {
254
+ inline-size: 1rem;
255
+ block-size: 1rem;
256
+ flex-shrink: 0;
257
+ color: var(--color-text-muted);
258
+ }
259
+
260
+ .dropdown__item:hover .dropdown__item-icon {
261
+ color: inherit;
262
+ }
263
+
264
+ /* Item description (secondary text) */
265
+ .dropdown__item-desc {
266
+ font-size: var(--font-size-xs);
267
+ color: var(--color-text-subtle);
268
+ font-weight: var(--weight-normal);
269
+ }
270
+
271
+ /* Keyboard shortcut hint */
272
+ .dropdown__shortcut {
273
+ margin-inline-start: auto;
274
+ font-size: var(--font-size-xs);
275
+ color: var(--color-text-subtle);
276
+ font-family: var(--font-mono);
277
+ }
278
+
279
+
280
+ /* ========================================
281
+ THEME-SPECIFIC STYLES
282
+ ======================================== */
283
+
284
+ /* Still: no animation */
285
+ [data-motion="still"] .dropdown__menu {
286
+ transition: none;
287
+ }
288
+
289
+ [data-motion="still"] .dropdown__chevron {
290
+ transition: none;
291
+ }
292
+
293
+ /* Serene: extra rounded */
294
+ [data-motion="serene"] .dropdown__menu {
295
+ border-radius: var(--radius-xl);
296
+ }
297
+
298
+ [data-motion="serene"] .dropdown__item {
299
+ border-radius: var(--radius-lg);
300
+ }
301
+
302
+ /* Cascade: bouncy */
303
+ [data-motion="cascade"] .dropdown__menu {
304
+ border-radius: var(--radius-xl);
305
+ }
306
+
307
+ /* Rapids: offset shadow */
308
+ [data-motion="rapids"] .dropdown__menu {
309
+ box-shadow: var(--shadow-offset);
310
+ }
311
+
312
+ /* Tsunami: asymmetric */
313
+ [data-motion="tsunami"] .dropdown__menu {
314
+ border-radius: var(--radius-asymmetric, 0 24px 0 0);
315
+ }
316
+
317
+
318
+ /* ========================================
319
+ REDUCED MOTION
320
+ ======================================== */
321
+
322
+ @media (prefers-reduced-motion: reduce) {
323
+ .dropdown__menu {
324
+ transition: none;
325
+ }
326
+
327
+ .dropdown__chevron {
328
+ transition: none;
329
+ }
330
+
331
+ .dropdown__item {
332
+ transition: none;
333
+ }
334
+ }
335
+ }
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Fluid Framework - Empty State Component
3
+ * @layer components
4
+ *
5
+ * Empty states appear when lists, tables, or content areas have no items.
6
+ * They guide the user toward their first action.
7
+ *
8
+ * Usage:
9
+ * <div class="empty-state">
10
+ * <div class="empty-state__icon">🔍</div>
11
+ * <h3 class="empty-state__title">No results found</h3>
12
+ * <p class="empty-state__description">Try adjusting your search or clearing filters.</p>
13
+ * <div class="empty-state__actions">
14
+ * <button>Clear Filters</button>
15
+ * </div>
16
+ * </div>
17
+ *
18
+ * Variants: data-size="sm|lg"
19
+ */
20
+
21
+ @layer components {
22
+ .empty-state {
23
+ display: flex;
24
+ flex-direction: column;
25
+ align-items: center;
26
+ text-align: center;
27
+ padding: var(--space-10) var(--space-5);
28
+ gap: var(--space-3);
29
+ max-inline-size: 28rem;
30
+ margin-inline: auto;
31
+ }
32
+
33
+ .empty-state__icon {
34
+ display: flex;
35
+ align-items: center;
36
+ justify-content: center;
37
+ inline-size: 4rem;
38
+ block-size: 4rem;
39
+ border-radius: var(--radius-full);
40
+ background: var(--color-surface);
41
+ color: var(--color-text-muted);
42
+ font-size: var(--font-size-2xl);
43
+ margin-block-end: var(--space-2);
44
+ }
45
+
46
+ .empty-state__icon svg {
47
+ inline-size: 2rem;
48
+ block-size: 2rem;
49
+ }
50
+
51
+ .empty-state__title {
52
+ font-size: var(--font-size-lg);
53
+ font-weight: var(--weight-semibold);
54
+ color: var(--color-text);
55
+ margin: 0;
56
+ }
57
+
58
+ .empty-state__description {
59
+ font-size: var(--font-size-sm);
60
+ color: var(--color-text-muted);
61
+ max-inline-size: 24rem;
62
+ margin: 0;
63
+ }
64
+
65
+ .empty-state__actions {
66
+ display: flex;
67
+ gap: var(--space-3);
68
+ margin-block-start: var(--space-3);
69
+ }
70
+
71
+
72
+ /* ========================================
73
+ SIZE VARIANTS
74
+ ======================================== */
75
+
76
+ .empty-state[data-size="sm"] {
77
+ padding: var(--space-6) var(--space-4);
78
+ gap: var(--space-2);
79
+ }
80
+
81
+ .empty-state[data-size="sm"] .empty-state__icon {
82
+ inline-size: 2.5rem;
83
+ block-size: 2.5rem;
84
+ font-size: var(--font-size-lg);
85
+ }
86
+
87
+ .empty-state[data-size="sm"] .empty-state__title {
88
+ font-size: var(--font-size-base);
89
+ }
90
+
91
+ .empty-state[data-size="lg"] {
92
+ padding: var(--space-16) var(--space-6);
93
+ gap: var(--space-4);
94
+ }
95
+
96
+ .empty-state[data-size="lg"] .empty-state__icon {
97
+ inline-size: 5rem;
98
+ block-size: 5rem;
99
+ font-size: var(--font-size-3xl);
100
+ }
101
+
102
+ .empty-state[data-size="lg"] .empty-state__title {
103
+ font-size: var(--font-size-xl);
104
+ }
105
+ }