@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,508 @@
1
+ /**
2
+ * Fluid Framework - Form Components
3
+ * @layer components
4
+ *
5
+ * Forms should feel welcoming, not like paperwork.
6
+ * Clear labels, gentle feedback, graceful validation.
7
+ *
8
+ * Includes:
9
+ * - Form groups and layouts
10
+ * - Custom checkboxes and radios
11
+ * - Toggle switches
12
+ * - Input groups and addons
13
+ * - Form validation states
14
+ */
15
+
16
+ @layer components {
17
+ /* ========================================
18
+ FORM GROUP
19
+ Label + input combinations
20
+ ======================================== */
21
+
22
+ .form-group {
23
+ display: flex;
24
+ flex-direction: column;
25
+ gap: var(--space-2);
26
+ }
27
+
28
+ /* Stack form groups vertically with spacing (but not inside grid rows) */
29
+ .form-group + .form-group:not(.form-row .form-group) {
30
+ margin-block-start: var(--space-5);
31
+ }
32
+
33
+ /* Inside form-row, remove margin to let grid handle spacing */
34
+ .form-row .form-group {
35
+ margin-block-start: 0;
36
+ }
37
+
38
+ /* Inline form group */
39
+ .form-group[data-inline] {
40
+ flex-direction: row;
41
+ align-items: center;
42
+ gap: var(--space-4);
43
+ }
44
+
45
+ .form-group[data-inline] label {
46
+ flex-shrink: 0;
47
+ margin-block-end: 0;
48
+ }
49
+
50
+ /* Label styling */
51
+ .form-label {
52
+ font-size: var(--font-size-sm);
53
+ font-weight: var(--weight-medium);
54
+ color: var(--color-text);
55
+ }
56
+
57
+ /* Required indicator */
58
+ .form-label[data-required]::after {
59
+ content: " *";
60
+ color: var(--color-error);
61
+ }
62
+
63
+ /* Help text */
64
+ .form-help {
65
+ font-size: var(--font-size-sm);
66
+ color: var(--color-text-muted);
67
+ margin-block-start: var(--space-1);
68
+ }
69
+
70
+ /* Error message */
71
+ .form-error {
72
+ font-size: var(--font-size-sm);
73
+ color: var(--color-error);
74
+ margin-block-start: var(--space-1);
75
+ }
76
+
77
+
78
+ /* ========================================
79
+ INPUT GROUP
80
+ Inputs with addons
81
+ ======================================== */
82
+
83
+ .input-group {
84
+ display: flex;
85
+ align-items: stretch;
86
+ }
87
+
88
+ .input-group > input,
89
+ .input-group > select {
90
+ flex: 1;
91
+ min-inline-size: 0;
92
+ border-radius: 0;
93
+ }
94
+
95
+ .input-group > input:first-child,
96
+ .input-group > select:first-child {
97
+ border-start-start-radius: var(--radius-md);
98
+ border-end-start-radius: var(--radius-md);
99
+ }
100
+
101
+ .input-group > input:last-child,
102
+ .input-group > select:last-child {
103
+ border-start-end-radius: var(--radius-md);
104
+ border-end-end-radius: var(--radius-md);
105
+ }
106
+
107
+ .input-group__addon {
108
+ display: flex;
109
+ align-items: center;
110
+ padding-inline: var(--space-3);
111
+ font-size: var(--font-size-sm);
112
+ color: var(--color-text-muted);
113
+ background-color: var(--color-surface);
114
+ border: 1px solid var(--color-border);
115
+ }
116
+
117
+ .input-group__addon:first-child {
118
+ border-inline-end: none;
119
+ border-start-start-radius: var(--radius-md);
120
+ border-end-start-radius: var(--radius-md);
121
+ }
122
+
123
+ .input-group__addon:last-child {
124
+ border-inline-start: none;
125
+ border-start-end-radius: var(--radius-md);
126
+ border-end-end-radius: var(--radius-md);
127
+ }
128
+
129
+
130
+ /* ========================================
131
+ CUSTOM CHECKBOX
132
+ Beautiful checkmarks
133
+ ======================================== */
134
+
135
+ .checkbox {
136
+ display: inline-flex;
137
+ align-items: flex-start;
138
+ gap: var(--space-3);
139
+ cursor: pointer;
140
+ user-select: none;
141
+ }
142
+
143
+ .checkbox__input {
144
+ /* Hide native but keep accessible */
145
+ position: absolute;
146
+ opacity: 0;
147
+ inline-size: 0;
148
+ block-size: 0;
149
+ }
150
+
151
+ .checkbox__box {
152
+ flex-shrink: 0;
153
+ inline-size: 1.25rem;
154
+ block-size: 1.25rem;
155
+ border: var(--border-width-thick) solid var(--color-border);
156
+ border-radius: var(--radius-sm);
157
+ background-color: var(--color-background);
158
+ display: flex;
159
+ align-items: center;
160
+ justify-content: center;
161
+ transition:
162
+ background-color var(--duration-normal) var(--ease-fluid),
163
+ border-color var(--duration-normal) var(--ease-fluid),
164
+ transform var(--duration-fast) var(--ease-settle);
165
+ }
166
+
167
+ /* Checkmark icon */
168
+ .checkbox__box::after {
169
+ content: "";
170
+ inline-size: 0.5rem;
171
+ block-size: 0.25rem;
172
+ border-inline-start: 2px solid var(--white);
173
+ border-block-end: 2px solid var(--white);
174
+ transform: rotate(-45deg) scale(0);
175
+ transition: transform var(--duration-fast) var(--ease-settle);
176
+ }
177
+
178
+ /* Hover state */
179
+ .checkbox:hover .checkbox__box {
180
+ border-color: var(--accent);
181
+ }
182
+
183
+ /* Focus state */
184
+ .checkbox__input:focus-visible + .checkbox__box {
185
+ box-shadow: var(--shadow-glow);
186
+ }
187
+
188
+ /* Checked state */
189
+ .checkbox__input:checked + .checkbox__box {
190
+ background-color: var(--accent);
191
+ border-color: var(--accent);
192
+ }
193
+
194
+ .checkbox__input:checked + .checkbox__box::after {
195
+ transform: rotate(-45deg) scale(1);
196
+ }
197
+
198
+ /* Indeterminate state */
199
+ .checkbox__input:indeterminate + .checkbox__box::after {
200
+ inline-size: 0.5rem;
201
+ block-size: 0;
202
+ border-inline-start: none;
203
+ transform: rotate(0) scale(1);
204
+ }
205
+
206
+ /* Disabled state */
207
+ .checkbox__input:disabled + .checkbox__box {
208
+ opacity: 0.5;
209
+ cursor: not-allowed;
210
+ }
211
+
212
+ .checkbox__input:disabled ~ .checkbox__label {
213
+ opacity: 0.5;
214
+ cursor: not-allowed;
215
+ }
216
+
217
+ .checkbox__label {
218
+ font-size: var(--font-size-base);
219
+ line-height: 1.25rem;
220
+ }
221
+
222
+
223
+ /* ========================================
224
+ CUSTOM RADIO
225
+ Circular selection
226
+ ======================================== */
227
+
228
+ .radio {
229
+ display: inline-flex;
230
+ align-items: flex-start;
231
+ gap: var(--space-3);
232
+ cursor: pointer;
233
+ user-select: none;
234
+ }
235
+
236
+ .radio__input {
237
+ position: absolute;
238
+ opacity: 0;
239
+ inline-size: 0;
240
+ block-size: 0;
241
+ }
242
+
243
+ .radio__circle {
244
+ flex-shrink: 0;
245
+ inline-size: 1.25rem;
246
+ block-size: 1.25rem;
247
+ border: var(--border-width-thick) solid var(--color-border);
248
+ border-radius: var(--radius-full);
249
+ background-color: var(--color-background);
250
+ display: flex;
251
+ align-items: center;
252
+ justify-content: center;
253
+ transition:
254
+ border-color var(--duration-normal) var(--ease-fluid);
255
+ }
256
+
257
+ .radio__circle::after {
258
+ content: "";
259
+ inline-size: 0.5rem;
260
+ block-size: 0.5rem;
261
+ border-radius: var(--radius-full);
262
+ background-color: var(--accent);
263
+ transform: scale(0);
264
+ transition: transform var(--duration-fast) var(--ease-settle);
265
+ }
266
+
267
+ .radio:hover .radio__circle {
268
+ border-color: var(--accent);
269
+ }
270
+
271
+ .radio__input:focus-visible + .radio__circle {
272
+ box-shadow: var(--shadow-glow);
273
+ }
274
+
275
+ .radio__input:checked + .radio__circle {
276
+ border-color: var(--accent);
277
+ }
278
+
279
+ .radio__input:checked + .radio__circle::after {
280
+ transform: scale(1);
281
+ }
282
+
283
+ .radio__input:disabled + .radio__circle {
284
+ opacity: 0.5;
285
+ cursor: not-allowed;
286
+ }
287
+
288
+ .radio__input:disabled ~ .radio__label {
289
+ opacity: 0.5;
290
+ cursor: not-allowed;
291
+ }
292
+
293
+ .radio__label {
294
+ font-size: var(--font-size-base);
295
+ line-height: 1.25rem;
296
+ }
297
+
298
+ /* Radio group */
299
+ .radio-group {
300
+ display: flex;
301
+ flex-direction: column;
302
+ gap: var(--space-3);
303
+ }
304
+
305
+ .radio-group[data-inline] {
306
+ flex-direction: row;
307
+ flex-wrap: wrap;
308
+ gap: var(--space-5);
309
+ }
310
+
311
+
312
+ /* ========================================
313
+ TOGGLE SWITCH
314
+ On/off control
315
+ Add role="switch" to <input> for ARIA compliance
316
+ ======================================== */
317
+
318
+ .switch {
319
+ display: inline-flex;
320
+ align-items: center;
321
+ gap: var(--space-3);
322
+ cursor: pointer;
323
+ user-select: none;
324
+ }
325
+
326
+ .switch__input {
327
+ position: absolute;
328
+ opacity: 0;
329
+ inline-size: 0;
330
+ block-size: 0;
331
+ }
332
+
333
+ .switch__track {
334
+ position: relative;
335
+ inline-size: 2.75rem;
336
+ block-size: 1.5rem;
337
+ background-color: var(--color-border);
338
+ border-radius: var(--radius-full);
339
+ transition: background-color var(--duration-normal) var(--ease-fluid);
340
+ }
341
+
342
+ .switch__thumb {
343
+ position: absolute;
344
+ inset-block-start: 0.125rem;
345
+ inset-inline-start: 0.125rem;
346
+ inline-size: 1.25rem;
347
+ block-size: 1.25rem;
348
+ background-color: var(--white);
349
+ border-radius: var(--radius-full);
350
+ box-shadow: var(--shadow-sm);
351
+ transition:
352
+ transform var(--duration-normal) var(--ease-settle),
353
+ box-shadow var(--duration-fast) var(--ease-fluid);
354
+ }
355
+
356
+ .switch:hover .switch__track {
357
+ background-color: var(--color-text-subtle);
358
+ }
359
+
360
+ .switch__input:focus-visible + .switch__track {
361
+ box-shadow: var(--shadow-glow);
362
+ }
363
+
364
+ .switch__input:checked + .switch__track {
365
+ background-color: var(--accent);
366
+ }
367
+
368
+ .switch__input:checked + .switch__track .switch__thumb {
369
+ transform: translateX(1.25rem);
370
+ }
371
+
372
+ .switch__input:disabled + .switch__track {
373
+ opacity: 0.5;
374
+ cursor: not-allowed;
375
+ }
376
+
377
+ .switch__input:disabled ~ .switch__label {
378
+ opacity: 0.5;
379
+ cursor: not-allowed;
380
+ }
381
+
382
+ .switch__label {
383
+ font-size: var(--font-size-base);
384
+ }
385
+
386
+ /* Small switch */
387
+ .switch[data-size="sm"] .switch__track {
388
+ inline-size: 2rem;
389
+ block-size: 1.125rem;
390
+ }
391
+
392
+ .switch[data-size="sm"] .switch__thumb {
393
+ inline-size: 0.875rem;
394
+ block-size: 0.875rem;
395
+ }
396
+
397
+ .switch[data-size="sm"] .switch__input:checked + .switch__track .switch__thumb {
398
+ transform: translateX(0.875rem);
399
+ }
400
+
401
+
402
+ /* ========================================
403
+ VALIDATION STATES
404
+ Clear feedback
405
+ ======================================== */
406
+
407
+ /* Valid/Success state */
408
+ input[data-valid],
409
+ textarea[data-valid],
410
+ select[data-valid],
411
+ .form-group[data-valid] input,
412
+ .form-group[data-valid] textarea,
413
+ .form-group[data-valid] select {
414
+ border-color: var(--color-success);
415
+ }
416
+
417
+ input[data-valid]:focus,
418
+ textarea[data-valid]:focus,
419
+ select[data-valid]:focus {
420
+ box-shadow: 0 0 0 3px color-mix(in oklch, var(--color-success) 20%, transparent);
421
+ }
422
+
423
+ /* Invalid/Error state */
424
+ input[data-invalid],
425
+ textarea[data-invalid],
426
+ select[data-invalid],
427
+ input[aria-invalid="true"],
428
+ textarea[aria-invalid="true"],
429
+ select[aria-invalid="true"],
430
+ input:invalid:not(:placeholder-shown),
431
+ textarea:invalid:not(:placeholder-shown),
432
+ .form-group[data-invalid] input,
433
+ .form-group[data-invalid] textarea,
434
+ .form-group[data-invalid] select {
435
+ border-color: var(--color-error);
436
+ }
437
+
438
+ input[data-invalid]:focus,
439
+ textarea[data-invalid]:focus,
440
+ select[data-invalid]:focus,
441
+ input[aria-invalid="true"]:focus,
442
+ textarea[aria-invalid="true"]:focus,
443
+ select[aria-invalid="true"]:focus,
444
+ input:invalid:not(:placeholder-shown):focus,
445
+ textarea:invalid:not(:placeholder-shown):focus {
446
+ box-shadow: 0 0 0 3px color-mix(in oklch, var(--color-error) 20%, transparent);
447
+ }
448
+
449
+
450
+ /* ========================================
451
+ FORM LAYOUT
452
+ Multi-column forms
453
+ ======================================== */
454
+
455
+ .form-row {
456
+ display: grid;
457
+ gap: var(--space-5);
458
+ grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
459
+ }
460
+
461
+ .form-actions {
462
+ display: flex;
463
+ gap: var(--space-3);
464
+ margin-block-start: var(--space-6);
465
+ padding-block-start: var(--space-6);
466
+ border-block-start: 1px solid var(--color-border-subtle);
467
+ }
468
+
469
+ .form-actions[data-align="end"] {
470
+ justify-content: flex-end;
471
+ }
472
+
473
+ .form-actions[data-align="between"] {
474
+ justify-content: space-between;
475
+ }
476
+
477
+
478
+ /* ========================================
479
+ FIELDSET & LEGEND
480
+ Grouped form sections
481
+ ======================================== */
482
+
483
+ fieldset.form-fieldset {
484
+ border: 1px solid var(--color-border-subtle);
485
+ border-radius: var(--radius-lg);
486
+ padding: var(--space-5);
487
+ margin-block-end: var(--space-6);
488
+ }
489
+
490
+ fieldset.form-fieldset legend {
491
+ font-size: var(--font-size-sm);
492
+ font-weight: var(--weight-semibold);
493
+ padding-inline: var(--space-2);
494
+ color: var(--color-text);
495
+ }
496
+
497
+ /* Accessibility: reduced motion */
498
+ @media (prefers-reduced-motion: reduce) {
499
+ input,
500
+ textarea,
501
+ select,
502
+ .checkbox__toggle,
503
+ .checkbox__label::before,
504
+ .radio__label::before {
505
+ transition: none;
506
+ }
507
+ }
508
+ }