@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,229 @@
1
+ /**
2
+ * Fluid Framework - Themed Images
3
+ * @layer components
4
+ *
5
+ * Apply theme-aware duotone filters to images sitewide.
6
+ * Uses CSS filters and pseudo-element overlays for the effect.
7
+ *
8
+ * Usage:
9
+ * <figure class="themed-image">
10
+ * <img src="..." alt="...">
11
+ * </figure>
12
+ *
13
+ * Or apply to card images:
14
+ * <div class="card" data-themed-image>
15
+ * <img src="..." alt="...">
16
+ * </div>
17
+ *
18
+ * Disable with data-no-duotone attribute.
19
+ */
20
+
21
+ @layer components {
22
+ /* ========================================
23
+ THEMED IMAGE CONTAINER
24
+ Applies duotone effect via overlay
25
+ ======================================== */
26
+
27
+ .themed-image,
28
+ [data-themed-image] {
29
+ position: relative;
30
+ overflow: hidden;
31
+ }
32
+
33
+ .themed-image img,
34
+ [data-themed-image] img {
35
+ display: block;
36
+ inline-size: 100%;
37
+ block-size: auto;
38
+ /* Convert to grayscale as base for duotone */
39
+ filter: grayscale(100%) contrast(1.1);
40
+ transition: filter var(--duration-normal) var(--ease-fluid);
41
+ }
42
+
43
+ /* Duotone overlay using gradient */
44
+ .themed-image::after,
45
+ [data-themed-image]::after {
46
+ content: "";
47
+ position: absolute;
48
+ inset: 0;
49
+ background: linear-gradient(
50
+ 135deg,
51
+ var(--duotone-dark, oklch(0.3 0.1 220)) 0%,
52
+ var(--duotone-light, oklch(0.7 0.1 200)) 100%
53
+ );
54
+ mix-blend-mode: multiply;
55
+ opacity: 0.85;
56
+ pointer-events: none;
57
+ transition: opacity var(--duration-normal) var(--ease-fluid);
58
+ }
59
+
60
+ /* Hover: reduce effect to show more of original */
61
+ .themed-image:hover::after,
62
+ [data-themed-image]:hover::after {
63
+ opacity: 0.6;
64
+ }
65
+
66
+ .themed-image:hover img,
67
+ [data-themed-image]:hover img {
68
+ filter: grayscale(50%) contrast(1.05);
69
+ }
70
+
71
+ /* Disable duotone */
72
+ [data-no-duotone] img {
73
+ filter: none !important;
74
+ }
75
+
76
+ [data-no-duotone]::after {
77
+ display: none !important;
78
+ }
79
+
80
+
81
+ /* ========================================
82
+ SITEWIDE IMAGE THEMING
83
+ Auto-apply to images in certain contexts
84
+ ======================================== */
85
+
86
+ /* Apply to images in cards (opt-in) */
87
+ .card[data-themed-image] .card__image {
88
+ position: relative;
89
+ overflow: hidden;
90
+ }
91
+
92
+ .card[data-themed-image] .card__image img {
93
+ filter: grayscale(100%) contrast(1.1);
94
+ }
95
+
96
+ .card[data-themed-image] .card__image::after {
97
+ content: "";
98
+ position: absolute;
99
+ inset: 0;
100
+ background: linear-gradient(
101
+ 135deg,
102
+ var(--duotone-dark) 0%,
103
+ var(--duotone-light) 100%
104
+ );
105
+ mix-blend-mode: multiply;
106
+ opacity: 0.85;
107
+ pointer-events: none;
108
+ }
109
+
110
+
111
+ /* ========================================
112
+ HERO IMAGE THEMING
113
+ For hero sections with background images
114
+ ======================================== */
115
+
116
+ .hero[data-themed-image] {
117
+ position: relative;
118
+ }
119
+
120
+ .hero[data-themed-image]::before {
121
+ content: "";
122
+ position: absolute;
123
+ inset: 0;
124
+ background: linear-gradient(
125
+ 135deg,
126
+ var(--duotone-dark) 0%,
127
+ var(--duotone-light) 100%
128
+ );
129
+ mix-blend-mode: multiply;
130
+ opacity: 0.75;
131
+ z-index: 1;
132
+ pointer-events: none;
133
+ }
134
+
135
+ .hero[data-themed-image] > * {
136
+ position: relative;
137
+ z-index: 2;
138
+ }
139
+
140
+
141
+ /* ========================================
142
+ SECTION BACKGROUNDS
143
+ Alternating themed section colors
144
+ ======================================== */
145
+
146
+ /* Tinted section background */
147
+ .section[data-bg="tinted"],
148
+ section[data-bg="tinted"] {
149
+ background-color: var(--surface-tinted, var(--section-2, var(--color-surface)));
150
+ }
151
+
152
+ /* Accent-tinted section */
153
+ .section[data-bg="accent"],
154
+ section[data-bg="accent"] {
155
+ background-color: var(--section-accent, var(--surface-accent, var(--accent-subtle)));
156
+ }
157
+
158
+ /* Alternating sections (every other) */
159
+ .section[data-bg="alt"],
160
+ section[data-bg="alt"] {
161
+ background-color: var(--section-2, var(--section-alt, var(--color-surface)));
162
+ }
163
+
164
+ /* Specific section color slots */
165
+ .section[data-bg="1"], section[data-bg="1"] { background-color: var(--section-1, var(--color-background)); }
166
+ .section[data-bg="2"], section[data-bg="2"] { background-color: var(--section-2, var(--color-surface)); }
167
+ .section[data-bg="3"], section[data-bg="3"] { background-color: var(--section-3, var(--surface-tinted)); }
168
+
169
+ /* Auto-alternating sections - 3-color rotation */
170
+ [data-alternating-sections] > .section:nth-child(3n+1),
171
+ [data-alternating-sections] > section:nth-child(3n+1) {
172
+ background-color: var(--section-1, var(--color-background));
173
+ }
174
+
175
+ [data-alternating-sections] > .section:nth-child(3n+2),
176
+ [data-alternating-sections] > section:nth-child(3n+2) {
177
+ background-color: var(--section-2, var(--color-surface));
178
+ }
179
+
180
+ [data-alternating-sections] > .section:nth-child(3n+3),
181
+ [data-alternating-sections] > section:nth-child(3n+3) {
182
+ background-color: var(--section-3, var(--surface-tinted));
183
+ }
184
+
185
+ /* Simple 2-color alternation */
186
+ [data-alternating-sections="simple"] > .section:nth-child(odd),
187
+ [data-alternating-sections="simple"] > section:nth-child(odd) {
188
+ background-color: var(--section-1, var(--color-background));
189
+ }
190
+
191
+ [data-alternating-sections="simple"] > .section:nth-child(even),
192
+ [data-alternating-sections="simple"] > section:nth-child(even) {
193
+ background-color: var(--section-2, var(--color-surface));
194
+ }
195
+
196
+
197
+ /* ========================================
198
+ FULL-BLEED COLORED SECTIONS
199
+ Sections with strong theme presence
200
+ ======================================== */
201
+
202
+ .section[data-bg="accent-solid"] {
203
+ background-color: var(--accent);
204
+ color: var(--white);
205
+ }
206
+
207
+ .section[data-bg="accent-solid"] h1,
208
+ .section[data-bg="accent-solid"] h2,
209
+ .section[data-bg="accent-solid"] h3 {
210
+ color: var(--white);
211
+ }
212
+
213
+ .section[data-bg="accent-solid"] a {
214
+ color: var(--white);
215
+ text-decoration: underline;
216
+ }
217
+
218
+ .section[data-bg="accent-solid"] a:hover {
219
+ opacity: 0.8;
220
+ }
221
+
222
+ /* Accessibility: reduced motion */
223
+ @media (prefers-reduced-motion: reduce) {
224
+ [data-duotone] img,
225
+ [data-duotone]:hover img {
226
+ transition: none;
227
+ }
228
+ }
229
+ }
@@ -0,0 +1,247 @@
1
+ /**
2
+ * Fluid Framework - Tooltip & Popover Component
3
+ * @layer components
4
+ *
5
+ * Tooltips for brief hints; popovers for richer content.
6
+ * CSS-only tooltips via data-tooltip attribute.
7
+ * Popover uses the native popover API where supported.
8
+ *
9
+ * Tooltip Usage (CSS-only):
10
+ * <button data-tooltip="Helpful hint">Hover me</button>
11
+ * <span data-tooltip="Info" data-tooltip-pos="top">Text</span>
12
+ *
13
+ * Positions: data-tooltip-pos="top|bottom|left|right" (default: top)
14
+ *
15
+ * Popover Usage (native API):
16
+ * <button popovertarget="my-popover">Open</button>
17
+ * <div id="my-popover" popover class="popover">
18
+ * <div class="popover__content">
19
+ * <h3 class="popover__title">Title</h3>
20
+ * <p>Rich content here.</p>
21
+ * </div>
22
+ * </div>
23
+ */
24
+
25
+ @layer components {
26
+ /* ========================================
27
+ TOOLTIP (CSS-only via data attribute)
28
+ ======================================== */
29
+
30
+ [data-tooltip] {
31
+ position: relative;
32
+ }
33
+
34
+ /* Tooltip bubble */
35
+ [data-tooltip]::after {
36
+ content: attr(data-tooltip);
37
+
38
+ /* Positioning */
39
+ position: absolute;
40
+ z-index: var(--z-tooltip);
41
+ pointer-events: none;
42
+
43
+ /* Visual — inverts relative to page background */
44
+ background: var(--color-text);
45
+ color: var(--color-background);
46
+ font-size: var(--font-size-xs);
47
+ font-weight: var(--weight-medium);
48
+ line-height: var(--leading-snug);
49
+ white-space: nowrap;
50
+ max-inline-size: min(20rem, 90vw);
51
+ padding: var(--space-1-5) var(--space-3);
52
+ border-radius: var(--radius-md);
53
+ box-shadow: var(--shadow-md);
54
+
55
+ /* Hidden state */
56
+ opacity: 0;
57
+ transform: scale(0.95);
58
+ transition:
59
+ opacity var(--duration-fast) var(--ease-fluid),
60
+ transform var(--duration-fast) var(--ease-settle);
61
+ }
62
+
63
+ /* Dark mode tooltip — automatically inverts via semantic tokens above */
64
+
65
+ /* Show on hover/focus */
66
+ [data-tooltip]:hover::after,
67
+ [data-tooltip]:focus-visible::after {
68
+ opacity: 1;
69
+ transform: scale(1);
70
+ }
71
+
72
+
73
+ /* ========================================
74
+ TOOLTIP POSITIONS
75
+ ======================================== */
76
+
77
+ /* Top (default) */
78
+ [data-tooltip]::after,
79
+ [data-tooltip][data-tooltip-pos="top"]::after {
80
+ inset-block-end: calc(100% + var(--space-2));
81
+ inset-inline-start: 50%;
82
+ translate: -50% 4px;
83
+ }
84
+
85
+ [data-tooltip]:hover::after,
86
+ [data-tooltip]:focus-visible::after,
87
+ [data-tooltip][data-tooltip-pos="top"]:hover::after,
88
+ [data-tooltip][data-tooltip-pos="top"]:focus-visible::after {
89
+ translate: -50% 0;
90
+ }
91
+
92
+ /* Bottom */
93
+ [data-tooltip][data-tooltip-pos="bottom"]::after {
94
+ inset-block-start: calc(100% + var(--space-2));
95
+ inset-block-end: auto;
96
+ inset-inline-start: 50%;
97
+ translate: -50% -4px;
98
+ }
99
+
100
+ [data-tooltip][data-tooltip-pos="bottom"]:hover::after,
101
+ [data-tooltip][data-tooltip-pos="bottom"]:focus-visible::after {
102
+ translate: -50% 0;
103
+ }
104
+
105
+ /* Left */
106
+ [data-tooltip][data-tooltip-pos="left"]::after {
107
+ inset-inline-end: calc(100% + var(--space-2));
108
+ inset-inline-start: auto;
109
+ inset-block-start: 50%;
110
+ translate: 4px -50%;
111
+ }
112
+
113
+ [data-tooltip][data-tooltip-pos="left"]:hover::after,
114
+ [data-tooltip][data-tooltip-pos="left"]:focus-visible::after {
115
+ translate: 0 -50%;
116
+ }
117
+
118
+ /* Right */
119
+ [data-tooltip][data-tooltip-pos="right"]::after {
120
+ inset-inline-start: calc(100% + var(--space-2));
121
+ inset-block-start: 50%;
122
+ translate: -4px -50%;
123
+ }
124
+
125
+ [data-tooltip][data-tooltip-pos="right"]:hover::after,
126
+ [data-tooltip][data-tooltip-pos="right"]:focus-visible::after {
127
+ translate: 0 -50%;
128
+ }
129
+
130
+ /* Multiline: allow wrapping for long tooltips */
131
+ [data-tooltip][data-tooltip-wrap]::after {
132
+ white-space: normal;
133
+ inline-size: max-content;
134
+ max-inline-size: 20rem;
135
+ text-align: start;
136
+ }
137
+
138
+
139
+ /* ========================================
140
+ POPOVER (native popover API)
141
+ ======================================== */
142
+
143
+ .popover {
144
+ /* Reset native popover defaults */
145
+ border: none;
146
+ padding: 0;
147
+ margin: 0;
148
+ background: transparent;
149
+ overflow: visible;
150
+
151
+ /* Positioning handled by browser anchor API or manual JS */
152
+ z-index: var(--z-popover);
153
+
154
+ /* Hidden by default */
155
+ opacity: 0;
156
+ transform: scale(0.95) translateY(-4px);
157
+ transition:
158
+ opacity var(--duration-fast) var(--ease-fluid),
159
+ transform var(--duration-fast) var(--ease-settle),
160
+ display var(--duration-fast) allow-discrete,
161
+ overlay var(--duration-fast) allow-discrete;
162
+ }
163
+
164
+ /* Open state — JS fallback via [data-open] for browsers without :popover-open */
165
+ .popover:popover-open,
166
+ .popover[data-open] {
167
+ opacity: 1;
168
+ transform: scale(1) translateY(0);
169
+ }
170
+
171
+ /* Starting style for entry animation */
172
+ @starting-style {
173
+ .popover:popover-open {
174
+ opacity: 0;
175
+ transform: scale(0.95) translateY(-4px);
176
+ }
177
+ }
178
+
179
+ .popover__content {
180
+ background: var(--color-surface-raised);
181
+ border: var(--border-width) solid var(--color-border-subtle);
182
+ border-radius: var(--radius-xl);
183
+ box-shadow: var(--shadow-lg);
184
+ padding: var(--space-4);
185
+ min-inline-size: 12rem;
186
+ max-inline-size: 24rem;
187
+ }
188
+
189
+ .popover__title {
190
+ font-size: var(--font-size-sm);
191
+ font-weight: var(--weight-semibold);
192
+ margin: 0 0 var(--space-2);
193
+ }
194
+
195
+ .popover__content p {
196
+ font-size: var(--font-size-sm);
197
+ color: var(--color-text-muted);
198
+ margin: 0;
199
+ }
200
+
201
+
202
+ /* ========================================
203
+ THEME-SPECIFIC STYLES
204
+ ======================================== */
205
+
206
+ /* Still: no animation */
207
+ [data-motion="still"] [data-tooltip]::after {
208
+ transition: none;
209
+ }
210
+
211
+ [data-motion="still"] .popover {
212
+ transition: none;
213
+ }
214
+
215
+ /* Rapids: hard shadow */
216
+ [data-motion="rapids"] .popover__content {
217
+ box-shadow: var(--shadow-offset);
218
+ }
219
+
220
+ /* Tsunami: asymmetric */
221
+ [data-motion="tsunami"] .popover__content {
222
+ border-radius: var(--radius-asymmetric, 0 24px 0 0);
223
+ }
224
+
225
+
226
+ /* ========================================
227
+ ACCESSIBILITY
228
+ ======================================== */
229
+
230
+ /* Hide tooltips on touch-only devices */
231
+ @media (hover: none) {
232
+ [data-tooltip]::after {
233
+ display: none;
234
+ }
235
+ }
236
+
237
+ /* Reduced motion: instant show/hide */
238
+ @media (prefers-reduced-motion: reduce) {
239
+ [data-tooltip]::after {
240
+ transition: none;
241
+ }
242
+
243
+ .popover {
244
+ transition: none;
245
+ }
246
+ }
247
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Fluid Framework - Version Badge Component
3
+ * @layer components
4
+ *
5
+ * A small fixed-position badge showing the current version number.
6
+ * Subtle, semi-transparent, bottom-right corner.
7
+ *
8
+ * Toggled via data attribute on <html>:
9
+ * <html data-show-version="true"> — shows badge
10
+ * Default (no attribute) — hidden
11
+ *
12
+ * Usage:
13
+ * <span class="version-badge">v0.3.5</span>
14
+ */
15
+
16
+ @layer components {
17
+
18
+ .version-badge {
19
+ position: fixed;
20
+ inset-block-end: var(--space-3);
21
+ inset-inline-end: var(--space-3);
22
+ z-index: var(--z-sticky);
23
+
24
+ display: none;
25
+ align-items: center;
26
+
27
+ padding-block: var(--space-1);
28
+ padding-inline: var(--space-3);
29
+ border-radius: var(--radius-full);
30
+
31
+ font-size: var(--font-size-xs);
32
+ font-weight: var(--weight-medium, 500);
33
+ font-family: var(--font-mono);
34
+ line-height: 1;
35
+ letter-spacing: var(--tracking-wide);
36
+
37
+ color: var(--color-text-muted);
38
+ background-color: color-mix(in oklch, var(--color-surface) 85%, transparent);
39
+ border: var(--border-width) solid var(--color-border-subtle);
40
+ backdrop-filter: blur(8px);
41
+
42
+ opacity: 0.7;
43
+ transition: opacity var(--duration-fast) var(--ease-fluid);
44
+ pointer-events: none;
45
+ user-select: none;
46
+ }
47
+
48
+ /* Show when data attribute is set */
49
+ [data-show-version="true"] .version-badge {
50
+ display: flex;
51
+ }
52
+
53
+ .version-badge:hover {
54
+ opacity: 1;
55
+ }
56
+
57
+ /* Hide in print */
58
+ @media print {
59
+ .version-badge {
60
+ display: none;
61
+ }
62
+ }
63
+
64
+ /* Accessibility */
65
+ @media (prefers-reduced-motion: reduce) {
66
+ .version-badge {
67
+ transition: none;
68
+ }
69
+ }
70
+ }