@fluid-theme/core 0.4.3 → 2.0.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 (80) hide show
  1. package/AGENTS.md +6 -29
  2. package/CHANGELOG.md +543 -2
  3. package/CLAUDE.md +193 -14
  4. package/GEMINI.md +6 -45
  5. package/README.md +17 -8
  6. package/assets/js/compare.js +77 -0
  7. package/assets/js/fit-text.js +103 -0
  8. package/assets/js/lightbox.js +153 -0
  9. package/assets/js/scroll-reveal.js +72 -0
  10. package/assets/js/toc-build.mjs +86 -0
  11. package/assets/js/toc.js +384 -0
  12. package/dist/fluid-1x.min.css +4 -0
  13. package/dist/fluid-fonts.min.css +2 -0
  14. package/dist/fluid-legacy-1x.css +3 -0
  15. package/dist/fluid-nav.min.css +3 -0
  16. package/dist/fluid-toc.min.css +3 -0
  17. package/dist/fluid-zero.min.css +3 -0
  18. package/dist/fluid.min.css +3 -2
  19. package/dist/fonts/OFL-newsreader.txt +93 -0
  20. package/dist/fonts/OFL-schibsted-grotesk.txt +93 -0
  21. package/dist/fonts/newsreader-latin-opsz-italic.woff2 +0 -0
  22. package/dist/fonts/newsreader-latin-opsz-normal.woff2 +0 -0
  23. package/dist/fonts/schibsted-grotesk-latin-wght-italic.woff2 +0 -0
  24. package/dist/fonts/schibsted-grotesk-latin-wght-normal.woff2 +0 -0
  25. package/fluid-agent-kit/README.md +1 -0
  26. package/fluid-agent-kit/skills/accessibility.md +3 -1
  27. package/fluid-agent-kit/skills/css-conventions.md +22 -5
  28. package/fluid-agent-kit/skills/image-optimization.md +2 -0
  29. package/fluid-agent-kit/skills/preset-composition.md +108 -0
  30. package/package.json +29 -3
  31. package/src/animations/scroll-reveal.css +75 -193
  32. package/src/components/accordion.css +6 -47
  33. package/src/components/alert.css +47 -88
  34. package/src/components/avatar.css +4 -20
  35. package/src/components/badge.css +25 -48
  36. package/src/components/button.css +69 -175
  37. package/src/components/card.css +146 -481
  38. package/src/components/chip.css +46 -12
  39. package/src/components/compare.css +234 -0
  40. package/src/components/dropdown.css +10 -67
  41. package/src/components/empty-state.css +4 -0
  42. package/src/components/form.css +113 -81
  43. package/src/components/gallery.css +252 -0
  44. package/src/components/hero.css +203 -88
  45. package/src/components/indicator.css +23 -117
  46. package/src/components/loading.css +7 -29
  47. package/src/components/modal.css +12 -65
  48. package/src/components/nav-modes.css +261 -0
  49. package/src/components/nav.css +324 -392
  50. package/src/components/search-input.css +4 -2
  51. package/src/components/step-indicator.css +26 -27
  52. package/src/components/table.css +64 -171
  53. package/src/components/toc.css +254 -0
  54. package/src/components/tooltip.css +5 -46
  55. package/src/core/base.css +393 -547
  56. package/src/core/reset.css +17 -5
  57. package/src/core/tokens.css +426 -2276
  58. package/src/fluid.css +258 -17
  59. package/src/fonts/OFL-newsreader.txt +93 -0
  60. package/src/fonts/OFL-schibsted-grotesk.txt +93 -0
  61. package/src/fonts/fluid-fonts.css +55 -0
  62. package/src/fonts/newsreader-latin-opsz-italic.woff2 +0 -0
  63. package/src/fonts/newsreader-latin-opsz-normal.woff2 +0 -0
  64. package/src/fonts/schibsted-grotesk-latin-wght-italic.woff2 +0 -0
  65. package/src/fonts/schibsted-grotesk-latin-wght-normal.woff2 +0 -0
  66. package/src/layouts/positioning.css +6 -3
  67. package/src/legacy-1x.css +61 -0
  68. package/src/sections/cta.css +33 -101
  69. package/src/sections/features.css +42 -219
  70. package/src/sections/footer.css +53 -134
  71. package/src/sections/stats.css +40 -153
  72. package/src/sections/team.css +24 -113
  73. package/src/sections/testimonials.css +34 -148
  74. package/src/zero/base.css +166 -0
  75. package/src/zero/tokens.css +64 -0
  76. package/src/zero.css +20 -0
  77. package/src/components/scroll-progress.css +0 -104
  78. package/src/components/settings-panel.css +0 -603
  79. package/src/components/themed-images.css +0 -229
  80. package/src/components/version-badge.css +0 -70
@@ -1,8 +1,11 @@
1
1
  /**
2
- * Scroll Reveal Animations
2
+ * Scroll Reveal Animations (opt-in)
3
3
  *
4
- * Add [data-reveal] attribute to elements you want to animate in on scroll.
5
- * Works with the scroll-reveal.js script or CSS-only with animation-timeline.
4
+ * Only elements that carry [data-reveal] ever animate, and only once
5
+ * assets/js/scroll-reveal.js has set data-reveal-ready on <html>. Without
6
+ * the script, with scripting off, or with reduced motion asked for, nothing
7
+ * is hidden: the hidden start state exists only under all three conditions.
8
+ * A bare .section is never hidden (that blanked the stack's pages, #61).
6
9
  *
7
10
  * Variants:
8
11
  * data-reveal="fade" - Fade in
@@ -16,209 +19,88 @@
16
19
  * Timing:
17
20
  * data-reveal-delay="100" - Delay in ms (100, 200, 300, 400, 500)
18
21
  * data-reveal-duration="slow" - Duration (fast, normal, slow)
22
+ * data-reveal-stagger on a parent staggers its [data-reveal] children
19
23
  */
20
24
 
21
25
  @layer components {
22
- /* Base reveal state - hidden by default */
23
- [data-reveal] {
24
- opacity: 0;
25
- transition:
26
- opacity var(--reveal-duration, var(--duration-slow)) var(--reveal-easing, cubic-bezier(0.16, 1, 0.3, 1)),
27
- transform var(--reveal-duration, var(--duration-slow)) var(--reveal-easing, cubic-bezier(0.16, 1, 0.3, 1)),
28
- filter var(--reveal-duration, var(--duration-slow)) var(--reveal-easing, cubic-bezier(0.16, 1, 0.3, 1));
29
- will-change: opacity, transform;
30
- }
31
-
32
- /* Revealed state */
33
- [data-reveal].revealed,
34
- [data-reveal][data-revealed] {
35
- opacity: 1;
36
- transform: none;
37
- filter: none;
38
- }
39
-
40
- /* Fade variants - starting positions */
41
- [data-reveal="fade-up"] {
42
- transform: translateY(2rem);
43
- }
44
-
45
- [data-reveal="fade-down"] {
46
- transform: translateY(-2rem);
47
- }
48
-
49
- [data-reveal="fade-left"] {
50
- transform: translateX(2rem);
51
- }
52
-
53
- [data-reveal="fade-right"] {
54
- transform: translateX(-2rem);
55
- }
56
-
57
- [data-reveal="scale"] {
58
- transform: scale(0.95);
59
- }
60
-
61
- [data-reveal="blur"] {
62
- filter: blur(8px);
63
- }
64
-
65
- /* Delays */
66
- [data-reveal-delay="100"] { transition-delay: 100ms; }
67
- [data-reveal-delay="200"] { transition-delay: 200ms; }
68
- [data-reveal-delay="300"] { transition-delay: 300ms; }
69
- [data-reveal-delay="400"] { transition-delay: 400ms; }
70
- [data-reveal-delay="500"] { transition-delay: 500ms; }
71
-
72
- /* Durations */
73
- [data-reveal-duration="fast"] { --reveal-duration: var(--duration-fast); }
74
- [data-reveal-duration="normal"] { --reveal-duration: var(--duration-slow); }
75
- [data-reveal-duration="slow"] { --reveal-duration: var(--duration-slower); }
76
-
77
- /* Stagger children - useful for grids and lists */
78
- [data-reveal-stagger] > [data-reveal]:nth-child(1) { transition-delay: calc(var(--reveal-stagger, 100ms) * 0); }
79
- [data-reveal-stagger] > [data-reveal]:nth-child(2) { transition-delay: calc(var(--reveal-stagger, 100ms) * 1); }
80
- [data-reveal-stagger] > [data-reveal]:nth-child(3) { transition-delay: calc(var(--reveal-stagger, 100ms) * 2); }
81
- [data-reveal-stagger] > [data-reveal]:nth-child(4) { transition-delay: calc(var(--reveal-stagger, 100ms) * 3); }
82
- [data-reveal-stagger] > [data-reveal]:nth-child(5) { transition-delay: calc(var(--reveal-stagger, 100ms) * 4); }
83
- [data-reveal-stagger] > [data-reveal]:nth-child(6) { transition-delay: calc(var(--reveal-stagger, 100ms) * 5); }
84
- [data-reveal-stagger] > [data-reveal]:nth-child(7) { transition-delay: calc(var(--reveal-stagger, 100ms) * 6); }
85
- [data-reveal-stagger] > [data-reveal]:nth-child(8) { transition-delay: calc(var(--reveal-stagger, 100ms) * 7); }
86
-
87
- /* ========================================
88
- AUTO-REVEAL BY MOTION STYLE
89
- Sections auto-animate based on theme motion setting
90
- ======================================== */
91
-
92
- /* Still: No animations */
93
- [data-motion="still"] [data-reveal] {
94
- opacity: 1;
95
- transform: none;
96
- filter: none;
97
- transition: none;
98
- }
99
-
100
- /* Serene: Very slow, gentle fade */
101
- [data-motion="serene"] [data-reveal] {
102
- --reveal-duration: var(--duration-slower);
103
- --reveal-easing: cubic-bezier(0.25, 0.1, 0.25, 1);
104
- }
105
-
106
- [data-motion="serene"] .section:not([data-reveal]) {
107
- opacity: 0;
108
- transform: scale(1.02);
109
- transition:
110
- opacity var(--duration-slowest) cubic-bezier(0.25, 0.1, 0.25, 1),
111
- transform var(--duration-slowest) cubic-bezier(0.25, 0.1, 0.25, 1);
112
- }
113
-
114
- [data-motion="serene"] .section:not([data-reveal]).revealed {
115
- opacity: 1;
116
- transform: none;
117
- }
118
-
119
- /* Stream: Gentle horizontal flow */
120
- [data-motion="stream"] [data-reveal] {
121
- --reveal-duration: var(--duration-slow);
122
- --reveal-easing: cubic-bezier(0.22, 1, 0.36, 1);
123
- }
124
-
125
- [data-motion="stream"] .section:not([data-reveal]) {
126
- opacity: 0;
127
- transform: translateX(-1rem);
128
- transition:
129
- opacity var(--duration-slow) cubic-bezier(0.22, 1, 0.36, 1),
130
- transform var(--duration-slow) cubic-bezier(0.22, 1, 0.36, 1);
131
- }
132
-
133
- [data-motion="stream"] .section:not([data-reveal]).revealed {
134
- opacity: 1;
135
- transform: none;
136
- }
137
-
138
- /* Flowing: Smooth ease-in-out, organic */
139
- [data-motion="flowing"] [data-reveal] {
140
- --reveal-duration: var(--duration-slow);
141
- --reveal-easing: cubic-bezier(0.16, 1, 0.3, 1);
142
- }
143
-
144
- [data-motion="flowing"] .section:not([data-reveal]) {
145
- opacity: 0;
146
- transform: translateY(1.5rem);
147
- transition:
148
- opacity var(--duration-slow) cubic-bezier(0.16, 1, 0.3, 1),
149
- transform var(--duration-slow) cubic-bezier(0.16, 1, 0.3, 1);
150
- }
151
-
152
- [data-motion="flowing"] .section:not([data-reveal]).revealed {
153
- opacity: 1;
154
- transform: none;
155
- }
26
+ @media (prefers-reduced-motion: no-preference) {
27
+ /* Hidden start state: the script is running and the element has not
28
+ been revealed yet. */
29
+ /* Headlines never animate in. A bare data-reveal rises 12px and fades. */
30
+ :root[data-reveal-ready] [data-reveal]:not(.revealed, [data-revealed], h1, h2, h3, .display, .hero__headline) {
31
+ opacity: 0;
32
+ }
156
33
 
157
- /* Cascade: Medium energy, waterfall effect */
158
- [data-motion="cascade"] [data-reveal] {
159
- --reveal-duration: var(--duration-normal);
160
- --reveal-easing: cubic-bezier(0.34, 1.56, 0.64, 1);
161
- }
34
+ :root[data-reveal-ready] [data-reveal=""]:not(.revealed, [data-revealed], h1, h2, h3, .display, .hero__headline) {
35
+ translate: 0 12px;
36
+ }
162
37
 
163
- [data-motion="cascade"] .section:not([data-reveal]) {
164
- opacity: 0;
165
- transform: translateY(2rem);
166
- transition:
167
- opacity var(--duration-normal) cubic-bezier(0.34, 1.56, 0.64, 1),
168
- transform var(--duration-normal) cubic-bezier(0.34, 1.56, 0.64, 1);
169
- }
38
+ :root[data-reveal-ready] [data-reveal="fade-up"]:not(.revealed, [data-revealed]) {
39
+ transform: translateY(2rem);
40
+ }
170
41
 
171
- [data-motion="cascade"] .section:not([data-reveal]).revealed {
172
- opacity: 1;
173
- transform: none;
174
- }
42
+ :root[data-reveal-ready] [data-reveal="fade-down"]:not(.revealed, [data-revealed]) {
43
+ transform: translateY(-2rem);
44
+ }
175
45
 
176
- /* Rapids: Fast, direct */
177
- [data-motion="rapids"] [data-reveal] {
178
- --reveal-duration: var(--duration-fast);
179
- --reveal-easing: cubic-bezier(0.25, 0.46, 0.45, 0.94);
180
- }
46
+ :root[data-reveal-ready] [data-reveal="fade-left"]:not(.revealed, [data-revealed]) {
47
+ transform: translateX(2rem);
48
+ }
181
49
 
182
- [data-motion="rapids"] .section:not([data-reveal]) {
183
- opacity: 0;
184
- transform: scale(0.98);
185
- transition:
186
- opacity var(--duration-fast) cubic-bezier(0.25, 0.46, 0.45, 0.94),
187
- transform var(--duration-fast) cubic-bezier(0.25, 0.46, 0.45, 0.94);
188
- }
50
+ :root[data-reveal-ready] [data-reveal="fade-right"]:not(.revealed, [data-revealed]) {
51
+ transform: translateX(-2rem);
52
+ }
189
53
 
190
- [data-motion="rapids"] .section:not([data-reveal]).revealed {
191
- opacity: 1;
192
- transform: none;
193
- }
54
+ :root[data-reveal-ready] [data-reveal="scale"]:not(.revealed, [data-revealed]) {
55
+ transform: scale(0.95);
56
+ }
194
57
 
195
- /* Tsunami: Dramatic, bold sweep */
196
- [data-motion="tsunami"] [data-reveal] {
197
- --reveal-duration: var(--duration-normal);
198
- --reveal-easing: cubic-bezier(0.68, -0.2, 0.32, 1.2);
199
- }
58
+ :root[data-reveal-ready] [data-reveal="blur"]:not(.revealed, [data-revealed]) {
59
+ filter: blur(8px);
60
+ }
200
61
 
201
- [data-motion="tsunami"] .section:not([data-reveal]) {
202
- opacity: 0;
203
- transform: translateY(3rem) scale(0.97);
204
- transition:
205
- opacity var(--duration-normal) cubic-bezier(0.68, -0.2, 0.32, 1.2),
206
- transform var(--duration-normal) cubic-bezier(0.68, -0.2, 0.32, 1.2);
207
- }
62
+ [data-reveal] {
63
+ transition:
64
+ opacity var(--reveal-duration, var(--duration-slow)) var(--reveal-easing, var(--ease-settle)),
65
+ translate var(--reveal-duration, var(--duration-slow)) var(--reveal-easing, var(--ease-settle)),
66
+ transform var(--reveal-duration, var(--duration-slow)) var(--reveal-easing, var(--ease-settle)),
67
+ filter var(--reveal-duration, var(--duration-slow)) var(--reveal-easing, var(--ease-settle));
68
+ }
208
69
 
209
- [data-motion="tsunami"] .section:not([data-reveal]).revealed {
210
- opacity: 1;
211
- transform: none;
212
- }
70
+ /* While the script switches the page to ready, below-the-fold content
71
+ goes to its hidden start state at once instead of fading out. */
72
+ [data-reveal-init] [data-reveal] {
73
+ transition: none;
74
+ }
213
75
 
214
- /* Reduced motion preference */
215
- @media (prefers-reduced-motion: reduce) {
216
- [data-reveal],
217
- .section {
218
- opacity: 1 !important;
219
- transform: none !important;
220
- filter: none !important;
221
- transition: none !important;
76
+ /* A sideways start position adds 2rem of horizontal overflow until the
77
+ element is revealed, so a phone could scroll sideways (services
78
+ template: 32px at every width up to 1024px). Sections holding one clip
79
+ it; clip, unlike hidden, leaves vertical overflow and sticky alone. */
80
+ .section:has([data-reveal="fade-left"], [data-reveal="fade-right"]) {
81
+ overflow-x: clip;
222
82
  }
83
+
84
+ /* Delays */
85
+ [data-reveal-delay="100"] { transition-delay: 100ms; }
86
+ [data-reveal-delay="200"] { transition-delay: 200ms; }
87
+ [data-reveal-delay="300"] { transition-delay: 300ms; }
88
+ [data-reveal-delay="400"] { transition-delay: 400ms; }
89
+ [data-reveal-delay="500"] { transition-delay: 500ms; }
90
+
91
+ /* Durations */
92
+ [data-reveal-duration="fast"] { --reveal-duration: var(--duration-fast); }
93
+ [data-reveal-duration="normal"] { --reveal-duration: var(--duration-slow); }
94
+ [data-reveal-duration="slow"] { --reveal-duration: var(--duration-slower); }
95
+
96
+ /* Stagger children - useful for grids and lists */
97
+ [data-reveal-stagger] > [data-reveal]:nth-child(1) { transition-delay: calc(var(--reveal-stagger, 100ms) * 0); }
98
+ [data-reveal-stagger] > [data-reveal]:nth-child(2) { transition-delay: calc(var(--reveal-stagger, 100ms) * 1); }
99
+ [data-reveal-stagger] > [data-reveal]:nth-child(3) { transition-delay: calc(var(--reveal-stagger, 100ms) * 2); }
100
+ [data-reveal-stagger] > [data-reveal]:nth-child(4) { transition-delay: calc(var(--reveal-stagger, 100ms) * 3); }
101
+ [data-reveal-stagger] > [data-reveal]:nth-child(5) { transition-delay: calc(var(--reveal-stagger, 100ms) * 4); }
102
+ [data-reveal-stagger] > [data-reveal]:nth-child(6) { transition-delay: calc(var(--reveal-stagger, 100ms) * 5); }
103
+ [data-reveal-stagger] > [data-reveal]:nth-child(7) { transition-delay: calc(var(--reveal-stagger, 100ms) * 6); }
104
+ [data-reveal-stagger] > [data-reveal]:nth-child(8) { transition-delay: calc(var(--reveal-stagger, 100ms) * 7); }
223
105
  }
224
106
  }
@@ -57,7 +57,7 @@
57
57
  /* Bordered variant: each item is a card */
58
58
  .accordion[data-variant="bordered"] .accordion__item {
59
59
  border: var(--border-width) solid var(--color-border-subtle);
60
- border-radius: var(--radius-lg);
60
+ border-radius: var(--radius-card);
61
61
  overflow: hidden;
62
62
  }
63
63
 
@@ -68,9 +68,8 @@
68
68
  /* Separated variant: elevated card items */
69
69
  .accordion[data-variant="separated"] .accordion__item {
70
70
  border: var(--border-width) solid var(--color-border-subtle);
71
- border-radius: var(--radius-lg);
71
+ border-radius: var(--radius-card);
72
72
  background: var(--color-surface-raised);
73
- box-shadow: var(--shadow-xs);
74
73
  overflow: hidden;
75
74
  }
76
75
 
@@ -137,15 +136,15 @@
137
136
 
138
137
  /* Hover */
139
138
  .accordion__trigger:hover {
140
- color: var(--accent);
139
+ color: var(--accent-ink);
141
140
  background-color: color-mix(in oklch, var(--accent) 5%, transparent);
142
141
  }
143
142
 
144
143
  /* Focus */
145
144
  .accordion__trigger:focus-visible {
146
- outline: 2px solid var(--color-focus);
145
+ outline: var(--focus-ring-width) solid var(--color-focus);
147
146
  outline-offset: -2px;
148
- border-radius: var(--radius-sm);
147
+ border-radius: calc(var(--radius-control) * 0.6);
149
148
  }
150
149
 
151
150
 
@@ -201,50 +200,10 @@
201
200
  }
202
201
 
203
202
 
204
- /* ========================================
205
- THEME-SPECIFIC STYLES
206
- ======================================== */
207
-
208
- /* Still: no animation */
209
- [data-motion="still"] .accordion__trigger::after {
210
- transition: none;
211
- }
212
-
213
- /* Serene: rounded, soft */
214
- [data-motion="serene"] .accordion[data-variant="separated"] .accordion__item,
215
- [data-motion="serene"] .accordion[data-variant="bordered"] .accordion__item {
216
- border-radius: var(--radius-xl);
217
- }
218
-
219
- /* Cascade: bouncy, bubbly */
220
- [data-motion="cascade"] .accordion[data-variant="separated"] .accordion__item,
221
- [data-motion="cascade"] .accordion[data-variant="bordered"] .accordion__item {
222
- border-radius: var(--radius-xl);
223
- }
224
-
225
- /* Rapids: hard shadow on separated */
226
- [data-motion="rapids"] .accordion[data-variant="separated"] .accordion__item {
227
- box-shadow: var(--shadow-offset);
228
- }
229
-
230
- /* Tsunami: asymmetric corners */
231
- [data-motion="tsunami"] .accordion[data-variant="separated"] .accordion__item,
232
- [data-motion="tsunami"] .accordion[data-variant="bordered"] .accordion__item {
233
- border-radius: var(--radius-asymmetric, 0 24px 0 0);
234
- }
235
-
236
203
 
237
204
  /* ========================================
238
205
  REDUCED MOTION
239
206
  ======================================== */
240
207
 
241
- @media (prefers-reduced-motion: reduce) {
242
- .accordion__trigger {
243
- transition: none;
244
- }
245
-
246
- .accordion__trigger::after {
247
- transition: none;
248
- }
249
- }
208
+ /* Reduced motion: the reset shortens every transition. */
250
209
  }
@@ -39,6 +39,8 @@
39
39
 
40
40
  .alert {
41
41
  --_alert-color: var(--color-info);
42
+ --_alert-fill: var(--color-info-fill);
43
+ --_alert-on: var(--color-info-on);
42
44
  --_alert-bg: var(--color-info-subtle);
43
45
  --_alert-border: var(--color-info);
44
46
 
@@ -46,16 +48,15 @@
46
48
  align-items: flex-start;
47
49
  gap: var(--space-3);
48
50
  padding: var(--space-4) var(--space-5);
49
- border-radius: var(--radius-lg);
50
- border-inline-start: 3px solid var(--_alert-border);
51
+ border-radius: var(--radius-card);
52
+ border-inline-start: var(--border-width-thick) solid var(--_alert-border);
51
53
  background: var(--_alert-bg);
52
54
  color: var(--color-text);
53
- font-size: var(--font-size-sm);
54
- line-height: var(--leading-normal);
55
-
55
+ font-size: var(--step--1);
56
+ line-height: 1.5;
56
57
  transition:
57
58
  opacity var(--duration-normal) var(--ease-fluid),
58
- transform var(--duration-normal) var(--ease-settle);
59
+ translate var(--duration-normal) var(--ease-settle);
59
60
  }
60
61
 
61
62
 
@@ -65,24 +66,32 @@
65
66
 
66
67
  .alert[data-status="success"] {
67
68
  --_alert-color: var(--color-success);
69
+ --_alert-fill: var(--color-success-fill);
70
+ --_alert-on: var(--color-success-on);
68
71
  --_alert-bg: var(--color-success-subtle);
69
72
  --_alert-border: var(--color-success);
70
73
  }
71
74
 
72
75
  .alert[data-status="warning"] {
73
76
  --_alert-color: var(--color-warning);
77
+ --_alert-fill: var(--color-warning-fill);
78
+ --_alert-on: var(--color-warning-on);
74
79
  --_alert-bg: var(--color-warning-subtle);
75
80
  --_alert-border: var(--color-warning);
76
81
  }
77
82
 
78
83
  .alert[data-status="error"] {
79
84
  --_alert-color: var(--color-error);
85
+ --_alert-fill: var(--color-error-fill);
86
+ --_alert-on: var(--color-error-on);
80
87
  --_alert-bg: var(--color-error-subtle);
81
88
  --_alert-border: var(--color-error);
82
89
  }
83
90
 
84
91
  .alert[data-status="info"] {
85
92
  --_alert-color: var(--color-info);
93
+ --_alert-fill: var(--color-info-fill);
94
+ --_alert-on: var(--color-info-on);
86
95
  --_alert-bg: var(--color-info-subtle);
87
96
  --_alert-border: var(--color-info);
88
97
  }
@@ -94,8 +103,8 @@
94
103
 
95
104
  /* Filled: solid background */
96
105
  .alert[data-variant="filled"] {
97
- background: var(--_alert-color);
98
- color: var(--white);
106
+ background: var(--_alert-fill);
107
+ color: var(--_alert-on);
99
108
  border-inline-start: none;
100
109
  }
101
110
 
@@ -107,7 +116,7 @@
107
116
  .alert[data-variant="outline"] {
108
117
  background: transparent;
109
118
  border: var(--border-width) solid var(--_alert-border);
110
- border-inline-start-width: 3px;
119
+ border-inline-start-width: var(--border-width-thick);
111
120
  }
112
121
 
113
122
 
@@ -130,7 +139,7 @@
130
139
  }
131
140
 
132
141
  .alert__title {
133
- font-weight: var(--weight-semibold);
142
+ font-weight: calc(700 + var(--_dark-weight));
134
143
  color: var(--_alert-color);
135
144
  margin-block-end: var(--space-1);
136
145
  display: block;
@@ -142,7 +151,7 @@
142
151
 
143
152
  .alert__close {
144
153
  --_btn-bg: transparent;
145
- --_btn-shadow: none;
154
+ --_btn-bg-hover: transparent;
146
155
 
147
156
  position: relative;
148
157
  flex-shrink: 0;
@@ -152,7 +161,6 @@
152
161
  inline-size: 1.5rem;
153
162
  block-size: 1.5rem;
154
163
  padding: 0;
155
- border-radius: var(--radius-sm);
156
164
  font-size: var(--font-size-lg);
157
165
  line-height: 1;
158
166
  color: var(--color-text-muted);
@@ -174,9 +182,11 @@
174
182
  /* Dismissing animation */
175
183
  .alert[data-dismissing] {
176
184
  opacity: 0;
177
- transform: translateX(var(--space-4));
185
+ translate: var(--space-4);
178
186
  }
179
187
 
188
+ .alert[data-dismissing]:dir(rtl) { translate: calc(-1 * var(--space-4)); }
189
+
180
190
 
181
191
  /* ========================================
182
192
  TOAST CONTAINER
@@ -218,14 +228,14 @@
218
228
 
219
229
  .toast-container[data-position="top-center"] {
220
230
  inset-block-start: 0;
221
- inset-inline-start: 50%;
222
- translate: -50% 0;
231
+ inset-inline: 0;
232
+ margin-inline: auto;
223
233
  }
224
234
 
225
235
  .toast-container[data-position="bottom-center"] {
226
236
  inset-block-end: 0;
227
- inset-inline-start: 50%;
228
- translate: -50% 0;
237
+ inset-inline: 0;
238
+ margin-inline: auto;
229
239
  }
230
240
 
231
241
 
@@ -235,18 +245,19 @@
235
245
 
236
246
  .toast {
237
247
  --_toast-accent: var(--color-info);
238
-
248
+ --_toast-fill: var(--color-info-fill);
249
+ --_toast-on: var(--color-info-on);
250
+ --_toast-bg: var(--color-info-subtle);
251
+ --_dir: 1;
239
252
  position: relative;
240
253
  overflow: hidden;
241
254
  display: flex;
242
255
  align-items: flex-start;
243
256
  gap: var(--space-3);
244
257
  padding: var(--space-4);
245
- padding-inline-start: calc(var(--space-4) + 3px);
246
- background: var(--color-surface-raised);
247
- border: var(--border-width) solid var(--color-border-subtle);
248
- border-radius: var(--radius-lg);
249
- box-shadow: var(--shadow-lg);
258
+ background: var(--_toast-bg);
259
+ border-inline-start: var(--border-width-thick) solid var(--_toast-accent);
260
+ border-radius: var(--radius-card);
250
261
  pointer-events: auto;
251
262
  inline-size: 100%;
252
263
 
@@ -254,22 +265,12 @@
254
265
  animation: toast-in var(--duration-normal) var(--ease-settle) both;
255
266
  }
256
267
 
257
- .toast[data-status="success"] { --_toast-accent: var(--color-success); }
258
- .toast[data-status="warning"] { --_toast-accent: var(--color-warning); }
259
- .toast[data-status="error"] { --_toast-accent: var(--color-error); }
260
- .toast[data-status="info"] { --_toast-accent: var(--color-info); }
268
+ .toast[data-status="success"] { --_toast-accent: var(--color-success); --_toast-fill: var(--color-success-fill); --_toast-on: var(--color-success-on); --_toast-bg: var(--color-success-subtle); }
269
+ .toast[data-status="warning"] { --_toast-accent: var(--color-warning); --_toast-fill: var(--color-warning-fill); --_toast-on: var(--color-warning-on); --_toast-bg: var(--color-warning-subtle); }
270
+ .toast[data-status="error"] { --_toast-accent: var(--color-error); --_toast-fill: var(--color-error-fill); --_toast-on: var(--color-error-on); --_toast-bg: var(--color-error-subtle); }
271
+ .toast[data-status="info"] { --_toast-accent: var(--color-info); --_toast-fill: var(--color-info-fill); --_toast-on: var(--color-info-on); --_toast-bg: var(--color-info-subtle); }
261
272
 
262
- /* Accent bar */
263
- .toast::before {
264
- content: "";
265
- position: absolute;
266
- inset-block-start: 0;
267
- inset-inline-start: 0;
268
- inline-size: 3px;
269
- block-size: 100%;
270
- background: var(--_toast-accent);
271
- border-radius: var(--radius-full) 0 0 var(--radius-full);
272
- }
273
+ .toast:dir(rtl) { --_dir: -1; }
273
274
 
274
275
  .toast__icon {
275
276
  flex-shrink: 0;
@@ -286,7 +287,7 @@
286
287
 
287
288
  .toast__content strong {
288
289
  display: block;
289
- font-weight: var(--weight-semibold);
290
+ font-weight: calc(700 + var(--_dark-weight));
290
291
  margin-block-end: var(--space-1);
291
292
  }
292
293
 
@@ -298,7 +299,7 @@
298
299
 
299
300
  .toast__close {
300
301
  --_btn-bg: transparent;
301
- --_btn-shadow: none;
302
+ --_btn-bg-hover: transparent;
302
303
 
303
304
  position: relative;
304
305
  flex-shrink: 0;
@@ -308,7 +309,6 @@
308
309
  inline-size: 1.5rem;
309
310
  block-size: 1.5rem;
310
311
  padding: 0;
311
- border-radius: var(--radius-sm);
312
312
  font-size: var(--font-size-base);
313
313
  color: var(--color-text-subtle);
314
314
  cursor: pointer;
@@ -336,15 +336,15 @@
336
336
  color: var(--_toast-accent);
337
337
  background: transparent;
338
338
  border: var(--border-width) solid var(--_toast-accent);
339
- border-radius: var(--radius-sm);
339
+ border-radius: var(--radius-control);
340
340
  cursor: pointer;
341
341
  text-decoration: none;
342
342
  transition: background-color var(--duration-fast) var(--ease-fluid);
343
343
  }
344
344
 
345
345
  .toast__action:hover {
346
- background: var(--_toast-accent);
347
- color: var(--white);
346
+ background: var(--_toast-fill);
347
+ color: var(--_toast-on);
348
348
  }
349
349
 
350
350
  /* Auto-dismiss progress bar */
@@ -373,50 +373,13 @@
373
373
  TOAST ANIMATIONS
374
374
  ======================================== */
375
375
 
376
+ /* Logical: the toast slides from and to the inline end (:dir sets --_dir). */
376
377
  @keyframes toast-in {
377
- from {
378
- opacity: 0;
379
- transform: translateY(-8px) scale(0.96);
380
- }
381
- to {
382
- opacity: 1;
383
- transform: translateY(0) scale(1);
384
- }
378
+ from { opacity: 0; translate: calc(var(--space-4) * var(--_dir)) 0; }
385
379
  }
386
380
 
387
381
  @keyframes toast-out {
388
- to {
389
- opacity: 0;
390
- transform: translateX(100%) scale(0.96);
391
- }
392
- }
393
-
394
-
395
- /* ========================================
396
- THEME-SPECIFIC STYLES
397
- ======================================== */
398
-
399
- /* Still: no animations */
400
- [data-motion="still"] .toast {
401
- animation: none;
402
- }
403
-
404
- /* Rapids: offset shadow */
405
- [data-motion="rapids"] .toast {
406
- box-shadow: var(--shadow-offset);
407
- }
408
-
409
- [data-motion="rapids"] .alert {
410
- border-inline-start-width: 4px;
411
- }
412
-
413
- /* Tsunami: asymmetric */
414
- [data-motion="tsunami"] .toast {
415
- border-radius: var(--radius-asymmetric, 0 24px 0 0);
416
- }
417
-
418
- [data-motion="tsunami"] .alert {
419
- border-radius: var(--radius-asymmetric, 0 24px 0 0);
382
+ to { opacity: 0; translate: calc(100% * var(--_dir)) 0; }
420
383
  }
421
384
 
422
385
 
@@ -437,10 +400,6 @@
437
400
  ======================================== */
438
401
 
439
402
  @media (prefers-reduced-motion: reduce) {
440
- .alert {
441
- transition: none;
442
- }
443
-
444
403
  .toast {
445
404
  animation: none;
446
405
  }