@thinking.tools/teff 1.0.0 → 1.0.2

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.
@@ -0,0 +1,319 @@
1
+ @layer theme, base, components, animations, utilities;
2
+
3
+ @layer base {
4
+ *, *::before, *::after {
5
+ box-sizing: border-box;
6
+ -webkit-tap-highlight-color: transparent;
7
+ }
8
+
9
+ * {
10
+ margin: 0;
11
+ }
12
+
13
+ html {
14
+ tab-size: 4;
15
+ }
16
+
17
+ /* Top-layer elements don't inherit from body. Set explicitly. */
18
+ body, dialog, [popover] {
19
+ font-family: var(--font-sans);
20
+ font-size: var(--text-regular);
21
+ line-height: var(--leading-normal);
22
+ color: var(--foreground);
23
+ }
24
+
25
+ body {
26
+ background-color: var(--background);
27
+ color: var(--foreground);
28
+ -webkit-font-smoothing: antialiased;
29
+ -moz-osx-font-smoothing: grayscale;
30
+ }
31
+
32
+ ::selection {
33
+ background-color: light-dark(rgb(0 0 0 / 0.1), rgb(255 255 255 / 0.2));
34
+ }
35
+
36
+ * {
37
+ scrollbar-width: thin;
38
+ scrollbar-color: var(--input) transparent;
39
+ }
40
+
41
+ main {
42
+ padding-block-start: var(--space-8);
43
+ }
44
+
45
+ /* Unknown-element fallback for pre-2023 browsers (search is a landmark). */
46
+ search {
47
+ display: block;
48
+ }
49
+
50
+ img, picture, video, canvas, svg {
51
+ max-width: 100%;
52
+ }
53
+
54
+ p, h1, h2, h3, h4, h5, h6, li, dt, dd, figcaption, summary, label, td, th {
55
+ overflow-wrap: break-word;
56
+ }
57
+
58
+ h1, h2, h3, h4, h5, h6 {
59
+ font-weight: var(--font-semibold);
60
+ line-height: 1.25;
61
+ letter-spacing: var(--tracking-tight);
62
+ text-wrap: balance;
63
+
64
+ &:first-child {
65
+ margin-block-start: 0;
66
+ }
67
+ }
68
+
69
+ h1 {
70
+ font-size: var(--text-1);
71
+ margin: var(--space-10) 0 var(--space-6);
72
+ }
73
+
74
+ h2 {
75
+ font-size: var(--text-2);
76
+ margin: var(--space-8) 0 var(--space-5);
77
+ }
78
+
79
+ h3 {
80
+ font-size: var(--text-3);
81
+ margin: var(--space-6) 0 var(--space-4);
82
+ }
83
+
84
+ h4 {
85
+ font-size: var(--text-4);
86
+ margin: var(--space-5) 0 var(--space-3);
87
+ }
88
+
89
+ h5 {
90
+ font-size: var(--text-5);
91
+ margin: var(--space-4) 0 var(--space-2);
92
+ }
93
+
94
+ h6 {
95
+ font-size: var(--text-regular);
96
+ margin: var(--space-4) 0 var(--space-2);
97
+ }
98
+
99
+ p {
100
+ margin-block-end: var(--space-4);
101
+ text-wrap: pretty;
102
+
103
+ &:last-child {
104
+ margin-block-end: 0;
105
+ }
106
+ }
107
+
108
+ a {
109
+ color: var(--primary);
110
+ text-decoration: underline;
111
+ text-underline-offset: 2px;
112
+ transition: color var(--transition-fast);
113
+
114
+ &:hover {
115
+ color: rgb(from var(--primary) r g b / 0.8);
116
+ }
117
+ }
118
+
119
+ strong, b {
120
+ font-weight: var(--font-semibold);
121
+ }
122
+
123
+ em, i, dfn {
124
+ font-style: italic;
125
+ }
126
+
127
+ small {
128
+ font-size: var(--text-7);
129
+ }
130
+
131
+ kbd {
132
+ font-family: var(--font-mono);
133
+ font-size: 0.875em;
134
+ padding: calc(var(--space-1) / 2) var(--space-1);
135
+ background-color: var(--faint);
136
+ border: 1px solid var(--input);
137
+ /* Thicker bottom edge reads as keycap depth. */
138
+ border-bottom-width: 2px;
139
+ border-radius: var(--radius-small);
140
+
141
+ /* Combo wrapper: <kbd><kbd>Cmd</kbd> + <kbd>K</kbd></kbd> */
142
+ &:has(> kbd) {
143
+ font-size: 1em;
144
+ padding: 0;
145
+ background: none;
146
+ border: none;
147
+ }
148
+ }
149
+
150
+ samp, var {
151
+ font-family: var(--font-mono);
152
+ font-size: 0.875em;
153
+ }
154
+
155
+ abbr[title] {
156
+ text-decoration: underline dotted;
157
+ text-underline-offset: 2px;
158
+ cursor: help;
159
+ }
160
+
161
+ sub, sup {
162
+ /* Keep super/subscripts from expanding the line box. */
163
+ font-size: 0.75em;
164
+ line-height: 0;
165
+ }
166
+
167
+ del {
168
+ color: var(--danger);
169
+ }
170
+
171
+ ins {
172
+ color: var(--success);
173
+ text-decoration-color: rgb(from var(--success) r g b / 0.4);
174
+ }
175
+
176
+ s {
177
+ color: var(--muted-foreground);
178
+ }
179
+
180
+ u {
181
+ /* Unarticulated annotation — spec's example is marking misspellings. */
182
+ text-decoration: underline wavy var(--danger);
183
+ text-underline-offset: 2px;
184
+ }
185
+
186
+ code {
187
+ font-family: var(--font-mono);
188
+ font-size: 0.875em;
189
+ padding: calc(var(--space-1) / 2) var(--space-1);
190
+ background-color: var(--faint);
191
+ border-radius: var(--radius-small);
192
+ }
193
+
194
+ pre {
195
+ font-family: var(--font-mono);
196
+ padding: var(--space-4);
197
+ background-color: var(--faint);
198
+ border-radius: var(--radius-medium);
199
+ overflow-x: auto;
200
+ margin-block-end: var(--space-4);
201
+
202
+ code {
203
+ padding: 0;
204
+ background: none;
205
+ border-radius: 0;
206
+ }
207
+ }
208
+
209
+ blockquote {
210
+ border-inline-start: 4px solid var(--border);
211
+ padding-inline-start: var(--space-4);
212
+ margin: var(--space-4) 0;
213
+ color: var(--muted-foreground);
214
+ font-style: italic;
215
+ }
216
+
217
+ hr {
218
+ border: none;
219
+ border-top: 1px solid var(--border);
220
+ margin: var(--space-8) 0;
221
+ }
222
+
223
+ ul, ol {
224
+ padding-inline-start: var(--space-6);
225
+ margin-block-end: var(--space-4);
226
+ }
227
+
228
+ ul {
229
+ list-style-type: disc;
230
+ }
231
+
232
+ ol {
233
+ list-style-type: decimal;
234
+ }
235
+
236
+ li {
237
+ margin-block-end: var(--space-1);
238
+ }
239
+
240
+ dl {
241
+ margin-block-end: var(--space-4);
242
+
243
+ & dt {
244
+ font-weight: var(--font-medium);
245
+
246
+ &:not(:first-child) {
247
+ margin-block-start: var(--space-2);
248
+ }
249
+ }
250
+
251
+ & dd {
252
+ color: var(--muted-foreground);
253
+ }
254
+
255
+ /* Two-column key–value layout. */
256
+ &[data-grid] {
257
+ display: grid;
258
+ grid-template-columns: fit-content(40%) 1fr;
259
+ column-gap: var(--space-6);
260
+ row-gap: var(--space-1);
261
+
262
+ & dt {
263
+ margin-block-start: 0;
264
+ }
265
+ }
266
+ }
267
+
268
+ figure:not([data-variant]) {
269
+ margin-block: var(--space-6);
270
+
271
+ & > :is(img, video), & > picture > img {
272
+ display: block;
273
+ border-radius: var(--radius-medium);
274
+ outline: 1px solid light-dark(rgb(0 0 0 / 0.1), rgb(255 255 255 / 0.1));
275
+ outline-offset: -1px;
276
+ }
277
+
278
+ & > figcaption {
279
+ margin-block-start: var(--space-2);
280
+ font-size: var(--text-7);
281
+ color: var(--muted-foreground);
282
+ }
283
+ }
284
+
285
+ hgroup {
286
+ margin-block-end: var(--space-4);
287
+
288
+ & > :is(h1, h2, h3, h4, h5, h6) {
289
+ margin-block-end: var(--space-1);
290
+ }
291
+
292
+ & > p {
293
+ margin-block-end: 0;
294
+ color: var(--muted-foreground);
295
+ text-wrap: balance;
296
+ }
297
+ }
298
+
299
+ mark {
300
+ background-color: light-dark(var(--logo-citron), rgb(from var(--logo-citron) r g b / 0.3));
301
+ color: light-dark(var(--logo-pine), inherit);
302
+ padding: calc(var(--space-1) / 2) var(--space-1);
303
+ border-radius: var(--radius-small);
304
+ }
305
+
306
+ [hidden] {
307
+ display: none;
308
+ }
309
+
310
+ :focus-visible {
311
+ outline: 2px solid var(--ring);
312
+ outline-offset: 2px;
313
+ }
314
+
315
+ :disabled {
316
+ opacity: 0.5;
317
+ cursor: not-allowed;
318
+ }
319
+ }
@@ -0,0 +1,177 @@
1
+ @layer theme {
2
+ :root {
3
+ color-scheme: light dark;
4
+
5
+ /* Raw logo palette — the nine stops of the unimo conic gradient. */
6
+ --logo-plum: #330f1f;
7
+ --logo-red: #c83228;
8
+ --logo-orange: #fb8841;
9
+ --logo-citron: #d3dd92;
10
+ --logo-green: #59824f;
11
+ --logo-pine: #002414;
12
+ --logo-navy: #142847;
13
+ --logo-blue: #2874d7;
14
+ --logo-sky: #99c2ff;
15
+
16
+ /* Mono core — pure neutral scale, ink primary. Pairs verified WCAG 2.1 AA. */
17
+ --background: light-dark(#ffffff, #000000);
18
+ --foreground: light-dark(#0a0a0a, #fafafa);
19
+ --card: light-dark(#ffffff, #141414);
20
+ --card-foreground: light-dark(#0a0a0a, #fafafa);
21
+ --primary: light-dark(#171717, #fafafa);
22
+ --primary-foreground: light-dark(#fafafa, #171717);
23
+ --secondary: light-dark(#f5f5f5, #262626);
24
+ --secondary-foreground: light-dark(#171717, #fafafa);
25
+ --muted: light-dark(#f5f5f5, #262626);
26
+ /* Gray text ≥4.5:1 on every light surface incl. --muted #f5f5f5. */
27
+ --muted-foreground: light-dark(#6f6f6f, #a3a3a3);
28
+ --faint: light-dark(#fafafa, #0f0f0f);
29
+ --faint-foreground: light-dark(#707070, #8f8f8f);
30
+ --accent: light-dark(#f5f5f5, #262626);
31
+ --danger: light-dark(#c83228, #ff8a76);
32
+ --danger-foreground: light-dark(#ffffff, #0a0a0a);
33
+ --success: light-dark(#47804a, #8fd47e);
34
+ --success-foreground: light-dark(#ffffff, #0a0a0a);
35
+ --warning: light-dark(#a85000, #ffa14d);
36
+ --warning-foreground: light-dark(#ffffff, #0a0a0a);
37
+ --border: light-dark(#e5e5e5, #262626);
38
+ --input: light-dark(#d4d4d4, #3d3d3d);
39
+ --ring: light-dark(#737373, #a3a3a3);
40
+
41
+ /* Spacing — density-aware; default density is 1 (identical to static values). */
42
+ --density: 1;
43
+ --space-1: calc(0.25rem * var(--density));
44
+ --space-2: calc(0.5rem * var(--density));
45
+ --space-3: calc(0.75rem * var(--density));
46
+ --space-4: calc(1rem * var(--density));
47
+ --space-5: calc(1.25rem * var(--density));
48
+ --space-6: calc(1.5rem * var(--density));
49
+ --space-8: calc(2rem * var(--density));
50
+ --space-10: calc(2.5rem * var(--density));
51
+ --space-12: calc(3rem * var(--density));
52
+ --space-14: calc(3.5rem * var(--density));
53
+ --space-16: calc(4rem * var(--density));
54
+ --space-18: calc(4.5rem * var(--density));
55
+
56
+ /* Fully rounded by default; data-radius presets opt out. */
57
+ --radius-small: 0.5rem;
58
+ --radius-medium: 0.75rem;
59
+ --radius-large: 1.25rem;
60
+ --radius-full: 9999px;
61
+ --radius-button: var(--radius-full);
62
+ --radius-field: var(--radius-full);
63
+
64
+ --bar-height: 0.5rem;
65
+
66
+ --font-sans: system-ui, sans-serif;
67
+ --font-mono: ui-monospace, Consolas, monospace;
68
+
69
+ --text-1: clamp(1.75rem, 1.5rem + 1.1vw, 2.25rem);
70
+ --text-2: clamp(1.5rem, 1.3rem + 0.8vw, 1.875rem);
71
+ --text-3: clamp(1.25rem, 1.1rem + 0.5vw, 1.5rem);
72
+ --text-4: clamp(1.125rem, 1.05rem + 0.3vw, 1.25rem);
73
+ --text-5: 1.125rem;
74
+ --text-6: 1rem;
75
+ --text-7: 0.875rem;
76
+ --text-8: 0.75rem;
77
+ --text-regular: var(--text-6);
78
+
79
+ --leading-normal: 1.5;
80
+ --tracking-tight: -0.02em;
81
+
82
+ --font-normal: 400;
83
+ --font-medium: 500;
84
+ --font-semibold: 600;
85
+ --font-bold: 600;
86
+
87
+ /* Layered: hairline ring + lift + ambient. Light uses pure-black alphas;
88
+ dark collapses the small shadow to a single white ring. */
89
+ --shadow-ring: 0 0 0 1px light-dark(rgb(0 0 0 / 0.06), rgb(255 255 255 / 0.08));
90
+ --shadow-small:
91
+ var(--shadow-ring),
92
+ 0 1px 2px light-dark(rgb(0 0 0 / 0.05), rgb(0 0 0 / 0)),
93
+ 0 2px 4px light-dark(rgb(0 0 0 / 0.03), rgb(0 0 0 / 0));
94
+ --shadow-medium:
95
+ var(--shadow-ring),
96
+ 0 2px 4px light-dark(rgb(0 0 0 / 0.05), rgb(0 0 0 / 0.3)),
97
+ 0 6px 12px light-dark(rgb(0 0 0 / 0.06), rgb(0 0 0 / 0.3));
98
+ --shadow-large:
99
+ var(--shadow-ring),
100
+ 0 4px 8px light-dark(rgb(0 0 0 / 0.06), rgb(0 0 0 / 0.4)),
101
+ 0 16px 32px light-dark(rgb(0 0 0 / 0.1), rgb(0 0 0 / 0.5));
102
+
103
+ --transition-fast: 120ms cubic-bezier(0.4, 0, 0.2, 1);
104
+ --transition: 200ms cubic-bezier(0.4, 0, 0.2, 1);
105
+ --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
106
+
107
+ --z-dropdown: 50;
108
+ --z-modal: 200;
109
+ }
110
+
111
+ /* Force color scheme; default follows OS. */
112
+ [data-theme="light"] {
113
+ color-scheme: light;
114
+ }
115
+ [data-theme="dark"] {
116
+ color-scheme: dark;
117
+ }
118
+
119
+ /* Accent presets — logo-derived primary colour, AA-verified per scheme.
120
+ Default (no attribute) is mono ink. Mid-tone accents need their own
121
+ foreground: white in light mode, near-black in dark mode. */
122
+ [data-accent] {
123
+ --primary-foreground: light-dark(#ffffff, #0a0a0a);
124
+ }
125
+ [data-accent="blue"] {
126
+ --primary: light-dark(#2068c9, #7ab3ff);
127
+ --ring: light-dark(#2068c9, #7ab3ff);
128
+ }
129
+ [data-accent="teal"] {
130
+ --primary: light-dark(#0f766e, #5eead4);
131
+ --ring: light-dark(#0f766e, #5eead4);
132
+ }
133
+ [data-accent="green"] {
134
+ --primary: light-dark(#47804a, #8fd47e);
135
+ --ring: light-dark(#47804a, #8fd47e);
136
+ }
137
+ [data-accent="orange"] {
138
+ --primary: light-dark(#c2410c, #ffa14d);
139
+ --ring: light-dark(#c2410c, #ffa14d);
140
+ }
141
+ [data-accent="red"] {
142
+ --primary: light-dark(#c83228, #ff8a76);
143
+ --ring: light-dark(#c83228, #ff8a76);
144
+ }
145
+ [data-accent="wine"] {
146
+ --primary: light-dark(#a83a68, #f9a8d4);
147
+ --ring: light-dark(#a83a68, #f9a8d4);
148
+ }
149
+ [data-accent="navy"] {
150
+ --primary: light-dark(#3b5fa7, #99c2ff);
151
+ --ring: light-dark(#3b5fa7, #99c2ff);
152
+ }
153
+
154
+ /* Radius presets — default is fully rounded; --radius-full stays pill. */
155
+ [data-radius="soft"] {
156
+ --radius-small: 0.125rem;
157
+ --radius-medium: 0.375rem;
158
+ --radius-large: 0.75rem;
159
+ --radius-button: var(--radius-medium);
160
+ --radius-field: var(--radius-medium);
161
+ }
162
+ [data-radius="sharp"] {
163
+ --radius-small: 0;
164
+ --radius-medium: 0.125rem;
165
+ --radius-large: 0.25rem;
166
+ --radius-button: var(--radius-medium);
167
+ --radius-field: var(--radius-medium);
168
+ }
169
+
170
+ /* Density presets — scale the spacing tokens above. */
171
+ [data-density="compact"] {
172
+ --density: 0.85;
173
+ }
174
+ [data-density="comfortable"] {
175
+ --density: 1.18;
176
+ }
177
+ }
@@ -0,0 +1,62 @@
1
+ @layer components {
2
+ details {
3
+ border: 1px solid var(--border);
4
+ border-radius: var(--radius-medium);
5
+ overflow: hidden;
6
+
7
+ & + details {
8
+ margin-top: -1px;
9
+ border-start-start-radius: 0;
10
+ border-start-end-radius: 0;
11
+ }
12
+
13
+ &:has(+ details) {
14
+ border-end-start-radius: 0;
15
+ border-end-end-radius: 0;
16
+ }
17
+
18
+ &[open] summary {
19
+ border-bottom: 1px solid var(--border);
20
+ }
21
+ }
22
+
23
+ summary {
24
+ display: flex;
25
+ align-items: center;
26
+ justify-content: space-between;
27
+ gap: var(--space-2);
28
+ padding: var(--space-4);
29
+ font-weight: var(--font-medium);
30
+ cursor: pointer;
31
+ user-select: none;
32
+ transition: background-color var(--transition-fast);
33
+
34
+ &:hover {
35
+ background-color: var(--muted);
36
+ }
37
+
38
+ &::-webkit-details-marker, &::marker {
39
+ display: none;
40
+ }
41
+
42
+ &::after {
43
+ content: "";
44
+ width: 1em;
45
+ height: 1em;
46
+ flex-shrink: 0;
47
+ background-color: currentColor;
48
+ mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
49
+ mask-size: contain;
50
+ mask-repeat: no-repeat;
51
+ transition: transform var(--transition-fast);
52
+ }
53
+
54
+ details[open] &::after {
55
+ transform: rotate(180deg);
56
+ }
57
+ }
58
+
59
+ details > *:not(summary) {
60
+ margin: var(--space-4);
61
+ }
62
+ }
package/css/alert.css ADDED
@@ -0,0 +1,53 @@
1
+ @layer components {
2
+ [role="alert"] {
3
+ position: relative;
4
+ display: flex;
5
+ gap: var(--space-3);
6
+ padding: var(--space-4) var(--space-5);
7
+ background-color: var(--background);
8
+ border: 1px solid var(--border);
9
+ border-radius: var(--radius-large);
10
+ font-size: var(--text-7);
11
+
12
+ &[data-variant] {
13
+ border: none;
14
+ }
15
+
16
+ &[data-variant="error"],
17
+ &[data-variant="danger"] {
18
+ color: var(--danger);
19
+ background-color: light-dark(
20
+ color-mix(in srgb, var(--danger) 8%, transparent),
21
+ color-mix(in srgb, var(--danger) 20%, transparent)
22
+ );
23
+
24
+ & a {
25
+ color: var(--danger);
26
+ }
27
+ }
28
+
29
+ &[data-variant="success"] {
30
+ color: var(--success);
31
+ background-color: light-dark(
32
+ color-mix(in srgb, var(--success) 8%, transparent),
33
+ color-mix(in srgb, var(--success) 20%, transparent)
34
+ );
35
+
36
+ & a {
37
+ color: var(--success);
38
+ }
39
+ }
40
+
41
+ &[data-variant="warning"] {
42
+ color: var(--warning);
43
+ background-color: light-dark(
44
+ color-mix(in srgb, var(--warning) 8%, transparent),
45
+ color-mix(in srgb, var(--warning) 20%, transparent)
46
+ );
47
+
48
+ & a {
49
+ color: var(--warning);
50
+ }
51
+ }
52
+ }
53
+ }
@@ -0,0 +1,111 @@
1
+ @layer animations {
2
+ @media (prefers-reduced-motion: reduce) {
3
+ *,
4
+ *::before,
5
+ *::after {
6
+ animation-duration: 0.01ms !important;
7
+ animation-delay: 0.01ms !important;
8
+ animation-iteration-count: 1 !important;
9
+ transition-duration: 0.01ms !important;
10
+ scroll-behavior: auto !important;
11
+ }
12
+ }
13
+
14
+ /* Pop-in animation for modals/overlays - swings from above */
15
+ .animate-pop-in {
16
+ opacity: 1;
17
+ transform: perspective(1000px) rotateX(0deg) translateZ(0);
18
+ transition:
19
+ opacity 150ms cubic-bezier(0.4, 0, 0.2, 1),
20
+ transform 150ms cubic-bezier(0.4, 0, 0.2, 1),
21
+ overlay 150ms cubic-bezier(0.4, 0, 0.2, 1) allow-discrete,
22
+ display 150ms cubic-bezier(0.4, 0, 0.2, 1) allow-discrete;
23
+
24
+ /* Entry - where to animate FROM */
25
+ @starting-style {
26
+ opacity: 0;
27
+ transform: perspective(1000px) rotateX(-15deg) translateZ(-80px);
28
+ }
29
+
30
+ /* Exit - where to animate TO when closing */
31
+ &[data-state="closing"] {
32
+ opacity: 0;
33
+ transform: perspective(1000px) rotateX(-15deg) translateZ(-80px);
34
+ }
35
+
36
+ &[data-state="closing"]::backdrop {
37
+ opacity: 0;
38
+ }
39
+ }
40
+
41
+ /* Backdrop animation for dialogs */
42
+ dialog::backdrop {
43
+ opacity: 1;
44
+ transition: opacity 150ms cubic-bezier(0.4, 0, 0.2, 1);
45
+
46
+ @starting-style {
47
+ opacity: 0;
48
+ }
49
+ }
50
+
51
+ /* Opt-in one-shot enter — compositor-only properties (opacity, translate,
52
+ filter). data-enter animates the element itself; data-enter="stagger"
53
+ cascades its children 100ms apart, delay capped past the 8th child. */
54
+ @keyframes teff-enter {
55
+ from {
56
+ opacity: 0;
57
+ translate: 0 12px;
58
+ filter: blur(4px);
59
+ }
60
+ }
61
+
62
+ [data-enter]:not([data-enter="stagger"]) {
63
+ animation: teff-enter 0.4s var(--ease-out) backwards;
64
+ }
65
+
66
+ [data-enter="stagger"] > * {
67
+ animation: teff-enter 0.4s var(--ease-out) backwards;
68
+ }
69
+
70
+ [data-enter="stagger"] > :nth-child(2) { animation-delay: 100ms; }
71
+ [data-enter="stagger"] > :nth-child(3) { animation-delay: 200ms; }
72
+ [data-enter="stagger"] > :nth-child(4) { animation-delay: 300ms; }
73
+ [data-enter="stagger"] > :nth-child(5) { animation-delay: 400ms; }
74
+ [data-enter="stagger"] > :nth-child(6) { animation-delay: 500ms; }
75
+ [data-enter="stagger"] > :nth-child(7) { animation-delay: 600ms; }
76
+ [data-enter="stagger"] > :nth-child(n + 8) { animation-delay: 700ms; }
77
+
78
+ /* Denied/failed feedback — damped, translate-only. Plays once when
79
+ data-shake is added; teff.shake(el) re-triggers and cleans up. */
80
+ @keyframes teff-shake {
81
+ 20% { translate: -6px; }
82
+ 40% { translate: 5px; }
83
+ 60% { translate: -3px; }
84
+ 80% { translate: 2px; }
85
+ }
86
+
87
+ [data-shake] {
88
+ animation: teff-shake 0.35s cubic-bezier(0.36, 0.07, 0.19, 0.97);
89
+ }
90
+
91
+ /* Slide-in animation for toasts */
92
+ .animate-slide-in {
93
+ opacity: 1;
94
+ transform: translateX(0);
95
+ transition:
96
+ opacity 150ms cubic-bezier(0.16, 1, 0.3, 1),
97
+ transform 150ms cubic-bezier(0.16, 1, 0.3, 1);
98
+
99
+ /* Entry - slide in from right */
100
+ @starting-style {
101
+ opacity: 0;
102
+ transform: translateX(100%);
103
+ }
104
+
105
+ /* Exit - slide out to right */
106
+ &[data-state="closing"] {
107
+ opacity: 0;
108
+ transform: translateX(100%);
109
+ }
110
+ }
111
+ }