@dorsk/tsumikit 0.79.0 → 0.80.1

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 (53) hide show
  1. package/dist/components/atoms/Artwork.svelte +14 -10
  2. package/dist/components/atoms/Artwork.svelte.d.ts +1 -1
  3. package/dist/components/atoms/Badge.svelte +1 -4
  4. package/dist/components/atoms/Button.svelte +303 -9
  5. package/dist/components/atoms/Button.svelte.d.ts +4 -1
  6. package/dist/components/atoms/Card.svelte +142 -0
  7. package/dist/components/atoms/Checkbox.svelte +177 -1
  8. package/dist/components/atoms/Input.svelte +35 -0
  9. package/dist/components/atoms/Link.svelte +61 -0
  10. package/dist/components/atoms/Progress.svelte +74 -1
  11. package/dist/components/atoms/Progress.svelte.d.ts +1 -0
  12. package/dist/components/atoms/Select.svelte +30 -0
  13. package/dist/components/atoms/Skeleton.svelte +54 -3
  14. package/dist/components/atoms/Skeleton.svelte.d.ts +1 -0
  15. package/dist/components/atoms/Spinner.svelte +152 -3
  16. package/dist/components/atoms/Spinner.svelte.d.ts +1 -1
  17. package/dist/components/atoms/Switch.svelte +135 -0
  18. package/dist/components/atoms/Textarea.svelte +36 -0
  19. package/dist/components/atoms/Thinking.svelte +130 -0
  20. package/dist/components/atoms/Thinking.svelte.d.ts +15 -0
  21. package/dist/components/molecules/CopyButton.svelte +146 -5
  22. package/dist/components/molecules/Field.svelte +55 -1
  23. package/dist/components/molecules/FileButton.svelte +4 -2
  24. package/dist/components/molecules/InputGroup.svelte +1 -1
  25. package/dist/components/molecules/LookPicker.svelte +100 -0
  26. package/dist/components/molecules/LookPicker.svelte.d.ts +17 -0
  27. package/dist/components/molecules/MotionSettings.svelte +166 -0
  28. package/dist/components/molecules/MotionSettings.svelte.d.ts +18 -0
  29. package/dist/components/molecules/RadioGroup.svelte +61 -0
  30. package/dist/components/molecules/SectionHeader.svelte +2 -0
  31. package/dist/components/molecules/Tabs.svelte +157 -4
  32. package/dist/components/molecules/ThemePicker.svelte +8 -3
  33. package/dist/fx.d.ts +149 -0
  34. package/dist/fx.js +111 -0
  35. package/dist/fx.md +58 -0
  36. package/dist/index.d.ts +8 -2
  37. package/dist/index.js +8 -2
  38. package/dist/looks/README.md +101 -0
  39. package/dist/looks/depth.css +939 -0
  40. package/dist/looks/editorial.css +545 -0
  41. package/dist/looks/tactile.css +871 -0
  42. package/dist/markdown.js +47 -21
  43. package/dist/pointer.d.ts +3 -0
  44. package/dist/pointer.js +40 -0
  45. package/dist/stores/fx.svelte.d.ts +17 -0
  46. package/dist/stores/fx.svelte.js +64 -0
  47. package/dist/stores/theme.svelte.d.ts +8 -2
  48. package/dist/stores/theme.svelte.js +33 -7
  49. package/dist/styles/themes.css +249 -249
  50. package/dist/styles/tokens.css +4 -3
  51. package/dist/theme-mode.d.ts +31 -0
  52. package/dist/theme-mode.js +19 -0
  53. package/package.json +3 -2
@@ -0,0 +1,871 @@
1
+ /* Soft tactile: rounder, tinted surfaces instead of borders, real press depth, springy motion.
2
+ Structure only: every color derives from the active theme's tokens. */
3
+
4
+ :root[data-look="tactile"] {
5
+ --r-xs: 4px;
6
+ --r-sm: 8px;
7
+ --r-md: 12px;
8
+ --r-lg: 20px;
9
+
10
+ --font-rounded: ui-rounded, "SF Pro Rounded", "Nunito", "Quicksand", "Varela Round", var(--font-sans);
11
+
12
+ --focus-ring-width: 3px;
13
+ --focus-ring: 3px solid var(--accent);
14
+ --focus-ring-offset: 1px;
15
+
16
+ --press-scale: 0.97;
17
+ --press-scale-sm: 0.94;
18
+ --press-scale-lg: 0.99;
19
+
20
+ /* Dark: shadows are the page background pushed darker; highlights are the text color. */
21
+ --look-ink: oklch(from var(--bg) calc(l * 0.3) c h);
22
+ --look-tint: var(--text);
23
+ --look-hi: color-mix(in oklab, var(--look-tint) 7%, transparent);
24
+ --look-hi-soft: color-mix(in oklab, var(--look-tint) 5%, transparent);
25
+ --look-drop: color-mix(in oklab, var(--look-ink) 50%, transparent);
26
+ --look-well: color-mix(in oklab, var(--bg) 85%, var(--look-ink));
27
+ --look-well-shadow:
28
+ inset 0 2px 4px color-mix(in oklab, var(--look-ink) 45%, transparent),
29
+ inset 0 -1px 0 color-mix(in oklab, var(--look-tint) 4%, transparent);
30
+ --look-field-ring: inset 0 0 0 1px var(--border-strong);
31
+ --look-track-shadow: inset 0 1px 2px color-mix(in oklab, var(--look-ink) 40%, transparent);
32
+ --look-elev-1:
33
+ inset 0 1px 0 var(--look-hi-soft),
34
+ 0 1px 2px color-mix(in oklab, var(--look-ink) 30%, transparent),
35
+ 0 10px 28px -14px color-mix(in oklab, var(--look-ink) 65%, transparent);
36
+ --look-elev-2:
37
+ inset 0 1px 0 var(--look-hi),
38
+ 0 2px 4px color-mix(in oklab, var(--look-ink) 28%, transparent),
39
+ 0 18px 40px -16px color-mix(in oklab, var(--look-ink) 75%, transparent);
40
+ --look-spot: color-mix(in oklab, var(--accent) 9%, transparent);
41
+ --look-knob-c: var(--text);
42
+ --look-knob-edge: var(--text-faint);
43
+ --look-knob: radial-gradient(
44
+ circle at 50% 30%,
45
+ var(--look-knob-c) 0%,
46
+ color-mix(in oklab, var(--look-knob-c) 92%, var(--look-knob-edge)) 60%,
47
+ color-mix(in oklab, var(--look-knob-c) 80%, var(--look-knob-edge)) 100%
48
+ );
49
+ --look-knob-shadow:
50
+ 0 1px 0 color-mix(in oklab, var(--look-knob-c) 50%, transparent) inset,
51
+ 0 2px 0 color-mix(in oklab, var(--look-ink) 35%, transparent),
52
+ 0 3px 8px color-mix(in oklab, var(--look-ink) 45%, transparent);
53
+ --look-lip: 3px;
54
+ --look-lip-pct: 50%;
55
+ --look-lip-ink: var(--look-ink);
56
+ --look-pastel: 12%;
57
+ --look-hairline: color-mix(in oklab, var(--text) 6%, transparent);
58
+
59
+ --shadow-sm: 0 1px 2px color-mix(in oklab, var(--look-ink) 35%, transparent);
60
+ --shadow-md:
61
+ 0 2px 4px color-mix(in oklab, var(--look-ink) 25%, transparent),
62
+ 0 14px 32px -10px color-mix(in oklab, var(--look-ink) 60%, transparent);
63
+ --shadow-lg:
64
+ 0 4px 10px color-mix(in oklab, var(--look-ink) 30%, transparent),
65
+ 0 28px 64px -16px color-mix(in oklab, var(--look-ink) 70%, transparent);
66
+
67
+ --surface-fill: var(--bg-elevated);
68
+ --surface-edge: var(--look-hairline);
69
+ --surface-edge-strong: var(--look-hairline);
70
+ --surface-shadow: var(--look-elev-1);
71
+ --surface-shadow-hover: var(--look-elev-2);
72
+ --raised-fill: var(--surface);
73
+ --raised-edge: transparent;
74
+ --raised-shadow: var(--look-elev-2), 0 0 0 1px color-mix(in oklab, var(--text) 5%, transparent);
75
+ --overlay-edge: transparent;
76
+ --overlay-shadow: var(--look-elev-2), var(--shadow-lg);
77
+ --control-fill: var(--look-well);
78
+ --control-edge: transparent;
79
+ --control-edge-hover: transparent;
80
+ --control-shadow: var(--look-well-shadow), var(--look-field-ring);
81
+ --track-fill: var(--look-well);
82
+ --track-edge: transparent;
83
+ --thumb-fill: var(--look-knob);
84
+ --thumb-shadow: var(--look-knob-shadow);
85
+ --btn-edge: transparent;
86
+ --btn-primary-edge: transparent;
87
+ --hover-lift: 1px;
88
+ --focus-glow: 0 0 0 6px color-mix(in oklab, var(--accent) 18%, transparent);
89
+ }
90
+
91
+ /* Light: shadows are the text color, highlights the elevated background. */
92
+ :root[data-look="tactile"][data-mode="light"] {
93
+ --look-ink: var(--text);
94
+ --look-tint: var(--bg-elevated);
95
+ --look-hi: color-mix(in oklab, var(--look-tint) 85%, transparent);
96
+ --look-hi-soft: color-mix(in oklab, var(--look-tint) 60%, transparent);
97
+ --look-drop: color-mix(in oklab, var(--look-ink) 20%, transparent);
98
+ --look-well: color-mix(in oklab, var(--bg-elevated-2) 55%, var(--bg-elevated));
99
+ --look-well-shadow:
100
+ inset 0 2px 3px color-mix(in oklab, var(--look-ink) 12%, transparent),
101
+ inset 0 -1px 0 color-mix(in oklab, var(--look-tint) 70%, transparent);
102
+ --look-field-ring: inset 0 0 0 1px var(--border-strong);
103
+ --look-track-shadow: inset 0 1px 1.5px color-mix(in oklab, var(--look-ink) 16%, transparent);
104
+ --look-elev-1:
105
+ 0 1px 2px color-mix(in oklab, var(--look-ink) 6%, transparent),
106
+ 0 10px 26px -14px color-mix(in oklab, var(--look-ink) 22%, transparent);
107
+ --look-elev-2:
108
+ 0 2px 4px color-mix(in oklab, var(--look-ink) 7%, transparent),
109
+ 0 18px 40px -16px color-mix(in oklab, var(--look-ink) 30%, transparent);
110
+ --look-spot: color-mix(in oklab, var(--accent) 10%, transparent);
111
+ --look-knob-c: var(--bg-elevated);
112
+ --look-knob-edge: var(--border-strong);
113
+ --look-knob-shadow:
114
+ 0 1px 0 color-mix(in oklab, var(--look-knob-c) 90%, transparent) inset,
115
+ 0 2px 0 color-mix(in oklab, var(--look-ink) 18%, transparent),
116
+ 0 3px 8px color-mix(in oklab, var(--look-ink) 25%, transparent);
117
+ --look-lip-pct: 72%;
118
+ --look-lip-ink: var(--text-faint);
119
+ --look-pastel: 9%;
120
+
121
+ --shadow-sm: 0 1px 2px color-mix(in oklab, var(--look-ink) 10%, transparent);
122
+ --shadow-md:
123
+ 0 2px 4px color-mix(in oklab, var(--look-ink) 6%, transparent),
124
+ 0 14px 32px -12px color-mix(in oklab, var(--look-ink) 25%, transparent);
125
+ --shadow-lg:
126
+ 0 4px 10px color-mix(in oklab, var(--look-ink) 8%, transparent),
127
+ 0 28px 64px -18px color-mix(in oklab, var(--look-ink) 35%, transparent);
128
+ }
129
+
130
+ /* ---------- Type ---------- */
131
+
132
+ :root[data-look="tactile"] :is(.heading, .callout-title, .sheet-title, .metric-num) {
133
+ font-family: var(--font-rounded);
134
+ letter-spacing: -0.012em;
135
+ }
136
+ :root[data-look="tactile"] .heading {
137
+ font-weight: var(--fw-bold);
138
+ }
139
+ :root[data-look="tactile"] .metric-value {
140
+ font-family: var(--font-rounded);
141
+ }
142
+ :root[data-look="tactile"] .metric-num {
143
+ font-weight: var(--fw-bold);
144
+ }
145
+ :root[data-look="tactile"] .metric-label {
146
+ font-family: var(--font-sans);
147
+ letter-spacing: 0.04em;
148
+ }
149
+
150
+ /* ---------- Buttons ---------- */
151
+
152
+ :root[data-look="tactile"] :is(.btn:not(.btn-link, .btn-icon-inline, .btn-ghost), .pop-trigger.canonical:not(.trigger-ghost), .pop-trigger.trigger-primary) {
153
+ --look-face: var(--surface);
154
+ --look-lip-c: color-mix(in oklab, var(--look-face) var(--look-lip-pct), var(--look-lip-ink));
155
+ border-color: transparent;
156
+ border-radius: var(--btn-radius, var(--pop-trigger-radius, var(--r-pill)));
157
+ background: var(--btn-bg, var(--pop-trigger-bg, linear-gradient(to bottom, color-mix(in oklab, var(--look-face) 94%, var(--look-tint)), var(--look-face))));
158
+ box-shadow:
159
+ inset 0 1px 0 var(--look-hi),
160
+ 0 var(--look-lip) 0 var(--look-lip-c),
161
+ 0 calc(var(--look-lip) + 2px) 8px -3px var(--look-drop);
162
+ transition:
163
+ background-color var(--dur-fast) var(--ease),
164
+ color var(--dur-fast) var(--ease),
165
+ opacity var(--dur-fast) var(--ease),
166
+ box-shadow var(--dur-fast) var(--ease-spring-bounce),
167
+ translate var(--dur-fast) var(--ease-spring-bounce),
168
+ scale var(--dur-fast) var(--ease-spring-bounce);
169
+ }
170
+ :root[data-look="tactile"] :is(.btn-primary, .pop-trigger.trigger-primary):not(.btn-link, .btn-ghost) {
171
+ --look-face: var(--accent);
172
+ background: var(--btn-bg, var(--pop-trigger-bg, var(--look-face)));
173
+ --look-lip-c: color-mix(in oklab, var(--accent) 62%, var(--look-ink));
174
+ --look-hi: color-mix(in oklab, var(--look-tint) 30%, transparent);
175
+ }
176
+ :root[data-look="tactile"] .btn-primary.btn-tone-success {
177
+ --look-face: var(--ok);
178
+ --look-lip-c: color-mix(in oklab, var(--ok) 60%, var(--look-ink));
179
+ }
180
+ :root[data-look="tactile"] .btn-primary:is(.btn-tone-accent, .btn-tone-info, .btn-tone-warn, .btn-tone-danger) {
181
+ --look-face: color-mix(in oklab, var(--btn-tone) 35%, var(--accent));
182
+ }
183
+ :root[data-look="tactile"] :is(.btn-danger, .pop-trigger.trigger-danger):not(.btn-ghost, .btn-link) {
184
+ --look-tone: var(--danger);
185
+ }
186
+ :root[data-look="tactile"] :is(.btn-tone-accent, .btn-tone-success, .btn-tone-info, .btn-tone-warn, .btn-tone-danger):not(.btn-primary, .btn-ghost, .btn-link) {
187
+ --look-tone: var(--btn-tone);
188
+ }
189
+ :root[data-look="tactile"] :is(.btn, .pop-trigger):not(.btn-primary, .trigger-primary, .btn-ghost, .trigger-ghost, .btn-link)[class*="tone"],
190
+ :root[data-look="tactile"] :is(.btn-danger, .trigger-danger):not(.btn-ghost, .trigger-ghost, .btn-link) {
191
+ --look-face: color-mix(in oklab, var(--look-tone, var(--danger)) var(--look-pastel), var(--bg-elevated));
192
+ --look-lip-c: color-mix(in oklab, var(--look-tone, var(--danger)) 22%, var(--look-well));
193
+ color: color-mix(in oklab, var(--look-tone, var(--danger)) 70%, var(--text));
194
+ }
195
+
196
+ :root[data-look="tactile"] :is(.btn-ghost, .pop-trigger.trigger-ghost) {
197
+ border-color: transparent;
198
+ border-radius: var(--btn-radius, var(--pop-trigger-radius, var(--r-pill)));
199
+ transition:
200
+ background-color var(--dur-fast) var(--ease),
201
+ color var(--dur-fast) var(--ease),
202
+ scale var(--dur-fast) var(--ease-spring-bounce);
203
+ }
204
+ :root[data-look="tactile"] .btn-ghost.btn-danger {
205
+ color: color-mix(in oklab, var(--danger) 70%, var(--text));
206
+ }
207
+
208
+ :root[data-look="tactile"] .split-main {
209
+ --btn-radius: var(--r-pill) var(--r-xs) var(--r-xs) var(--r-pill);
210
+ }
211
+ :root[data-look="tactile"] .split-caret {
212
+ --pop-trigger-radius: var(--r-xs) var(--r-pill) var(--r-pill) var(--r-xs);
213
+ }
214
+
215
+ :root[data-look="tactile"] .btn-shortcut {
216
+ left: var(--sp-4);
217
+ }
218
+
219
+ :root[data-look="tactile"] :is(.btn, .pop-trigger):is(:disabled, [aria-disabled="true"], .is-disabled):not(.btn-link, .btn-ghost, .trigger-ghost) {
220
+ box-shadow: none;
221
+ }
222
+
223
+ /* Press: depth collapse, fast in, springy out. */
224
+ :root[data-look="tactile"] :is(.btn:not(.btn-link, .btn-icon-inline, .btn-ghost), .pop-trigger.canonical:not(.trigger-ghost), .pop-trigger.trigger-primary):active:not(:disabled, [aria-disabled="true"], .loading, .is-disabled) {
225
+ scale: 1;
226
+ translate: 0 calc(var(--look-lip) - 1px);
227
+ box-shadow:
228
+ inset 0 1px 0 var(--look-hi),
229
+ 0 1px 0 var(--look-lip-c),
230
+ 0 1px 2px var(--look-drop);
231
+ transition-duration: var(--dur-press);
232
+ transition-timing-function: var(--ease-out);
233
+ }
234
+ :root[data-look="tactile"] :is(.btn-ghost, .pop-trigger.trigger-ghost, .btn-icon-inline):active:not(:disabled, [aria-disabled="true"], .loading) {
235
+ scale: var(--press-scale-sm);
236
+ transition-duration: var(--dur-press);
237
+ transition-timing-function: var(--ease-out);
238
+ }
239
+
240
+ /* ---------- Text fields ---------- */
241
+
242
+ :root[data-look="tactile"] :is(.input, .select:not(.ghost, .embedded), .textarea, .rich-select .rs-trigger, .rich-select > button) {
243
+ border-color: transparent;
244
+ border-radius: var(--r-md);
245
+ background: var(--look-well);
246
+ box-shadow: var(--look-well-shadow), var(--look-field-ring);
247
+ transition:
248
+ background-color var(--dur-fast) var(--ease),
249
+ box-shadow var(--dur-fast) var(--ease-spring);
250
+ }
251
+ :root[data-look="tactile"] :is(.input, .select:not(.ghost, .embedded), .textarea):focus,
252
+ :root[data-look="tactile"] .rich-select :is(.rs-trigger:focus-visible, .is-open .rs-trigger),
253
+ :root[data-look="tactile"] .rich-select.is-open .rs-trigger {
254
+ border-color: transparent;
255
+ box-shadow:
256
+ var(--look-well-shadow),
257
+ 0 0 0 2px var(--accent),
258
+ var(--focus-glow);
259
+ }
260
+ :root[data-look="tactile"] :is(.input, .select, .textarea):focus-visible {
261
+ outline: none;
262
+ }
263
+ :root[data-look="tactile"] :is(.input, .select, .textarea)[aria-invalid="true"] {
264
+ border-color: transparent;
265
+ background: color-mix(in oklab, var(--danger) 10%, var(--look-well));
266
+ box-shadow: var(--look-well-shadow), 0 0 0 1.5px color-mix(in oklab, var(--danger) 75%, transparent);
267
+ }
268
+ :root[data-look="tactile"] :is(.input, .select, .textarea)[aria-invalid="true"]:focus {
269
+ box-shadow:
270
+ var(--look-well-shadow),
271
+ 0 0 0 2px var(--danger),
272
+ 0 0 0 6px color-mix(in oklab, var(--danger) 18%, transparent);
273
+ }
274
+ :root[data-look="tactile"] .ig-bar::before {
275
+ border: 0;
276
+ background: var(--look-well);
277
+ }
278
+
279
+ /* ---------- Checkbox / radio ---------- */
280
+
281
+ :root[data-look="tactile"] .checkbox .box,
282
+ :root[data-look="tactile"] .dot-ctl {
283
+ border-color: transparent;
284
+ background: linear-gradient(to bottom, color-mix(in oklab, var(--surface) 90%, var(--look-tint)), var(--surface));
285
+ box-shadow:
286
+ inset 0 0 0 1px color-mix(in oklab, var(--border-strong) 55%, transparent),
287
+ inset 0 1px 0 var(--look-hi),
288
+ 0 2px 0 color-mix(in oklab, var(--surface) var(--look-lip-pct), var(--look-lip-ink));
289
+ transition:
290
+ background-color var(--dur-fast) var(--ease),
291
+ box-shadow var(--dur-fast) var(--ease),
292
+ translate var(--dur-spring) var(--ease-spring-bounce),
293
+ scale var(--dur-spring) var(--ease-spring-bounce);
294
+ }
295
+ :root[data-look="tactile"] .checkbox .box {
296
+ border-radius: 7px;
297
+ }
298
+ :root[data-look="tactile"] .checkbox input:is(:checked, :indeterminate) + .box,
299
+ :root[data-look="tactile"] .radio input:checked + .dot-ctl {
300
+ background: linear-gradient(to bottom, color-mix(in oklab, var(--accent) 88%, var(--look-tint)), var(--accent));
301
+ box-shadow:
302
+ inset 0 1px 0 color-mix(in oklab, var(--look-tint) 30%, transparent),
303
+ 0 2px 0 color-mix(in oklab, var(--accent) 60%, var(--look-ink));
304
+ }
305
+ :root[data-look="tactile"] .radio input:checked + .dot-ctl::after {
306
+ background: var(--look-knob);
307
+ box-shadow: 0 1px 1px color-mix(in oklab, var(--look-ink) 30%, transparent);
308
+ width: 0.5rem;
309
+ height: 0.5rem;
310
+ }
311
+ :root[data-look="tactile"] .checkbox:active:not(:has(input:disabled)) .box,
312
+ :root[data-look="tactile"] .radio:active:not(.disabled) .dot-ctl {
313
+ scale: 1;
314
+ translate: 0 1px;
315
+ box-shadow: inset 0 1px 2px color-mix(in oklab, var(--look-ink) 25%, transparent);
316
+ transition-duration: var(--dur-press);
317
+ transition-timing-function: var(--ease-out);
318
+ }
319
+ :root[data-look="tactile"] [data-tsu="RadioGroup"] .row {
320
+ border-color: transparent;
321
+ border-radius: var(--r-lg);
322
+ background: var(--bg-elevated-2);
323
+ }
324
+ :root[data-look="tactile"] [data-tsu="RadioGroup"] .row.selected {
325
+ border-color: transparent;
326
+ background: color-mix(in oklab, var(--accent) 12%, var(--bg-elevated));
327
+ }
328
+
329
+ /* ---------- Switch ---------- */
330
+
331
+ :root[data-look="tactile"] .switch {
332
+ --sw-h: 1.625rem;
333
+ --sw-w: 2.875rem;
334
+ border-color: transparent;
335
+ background: var(--look-well);
336
+ box-shadow: var(--look-well-shadow), inset 0 0 0 1px color-mix(in oklab, var(--border-strong) 45%, transparent);
337
+ transition:
338
+ background-color var(--dur-spring) var(--ease),
339
+ box-shadow var(--dur-spring) var(--ease);
340
+ }
341
+ :root[data-look="tactile"] .switch.on {
342
+ background: var(--accent);
343
+ box-shadow: inset 0 2px 4px color-mix(in oklab, var(--accent) 55%, var(--look-ink));
344
+ }
345
+ :root[data-look="tactile"] .switch .knob,
346
+ :root[data-look="tactile"] .switch.on .knob {
347
+ background: var(--look-knob);
348
+ box-shadow: var(--look-knob-shadow);
349
+ transition:
350
+ translate var(--dur-spring) var(--ease-spring-bounce),
351
+ scale var(--dur-fast) var(--ease-spring-bounce);
352
+ }
353
+ :root[data-look="tactile"] .switch:active:not(:disabled) .knob {
354
+ scale: 1.18 0.92;
355
+ transition-duration: var(--dur-press);
356
+ }
357
+
358
+ /* ---------- Slider ---------- */
359
+
360
+ :root[data-look="tactile"] .slider {
361
+ --thumb: 1.5rem;
362
+ --track: 0.5rem;
363
+ --halo: 0 0 0 6px color-mix(in oklab, var(--slider-accent, var(--accent)) 22%, transparent);
364
+ }
365
+ :root[data-look="tactile"] .slider input[type="range"] {
366
+ height: 1.75rem;
367
+ }
368
+ :root[data-look="tactile"] .slider input[type="range"]::-webkit-slider-runnable-track {
369
+ background: linear-gradient(to right, var(--slider-accent, var(--accent)) var(--pct), var(--look-well) var(--pct));
370
+ box-shadow: var(--look-track-shadow);
371
+ }
372
+ :root[data-look="tactile"] .slider input[type="range"]::-moz-range-track {
373
+ background: var(--look-well);
374
+ }
375
+ :root[data-look="tactile"] .slider input[type="range"]::-webkit-slider-thumb {
376
+ border: 0;
377
+ background: var(--look-knob);
378
+ box-shadow: var(--look-knob-shadow);
379
+ transition:
380
+ scale var(--dur-fast) var(--ease-spring-bounce),
381
+ box-shadow var(--dur-fast) var(--ease);
382
+ }
383
+ :root[data-look="tactile"] .slider input[type="range"]::-moz-range-thumb {
384
+ border: 0;
385
+ background: var(--look-knob);
386
+ box-shadow: var(--look-knob-shadow);
387
+ }
388
+ :root[data-look="tactile"] .slider input[type="range"]:not(:disabled):active::-webkit-slider-thumb {
389
+ scale: 1.1;
390
+ box-shadow: var(--look-knob-shadow), var(--halo);
391
+ }
392
+
393
+ /* ---------- Segmented control ---------- */
394
+
395
+ :root[data-look="tactile"] .seg {
396
+ border-color: transparent;
397
+ background: var(--look-well);
398
+ box-shadow: var(--look-well-shadow), var(--look-field-ring);
399
+ }
400
+ :root[data-look="tactile"] .seg-thumb,
401
+ :root[data-look="tactile"] .seg-item.selected {
402
+ background: linear-gradient(to bottom, color-mix(in oklab, var(--surface) 92%, var(--look-tint)), var(--surface));
403
+ box-shadow:
404
+ inset 0 1px 0 var(--look-hi),
405
+ 0 2px 0 color-mix(in oklab, var(--surface) var(--look-lip-pct), var(--look-lip-ink)),
406
+ 0 3px 6px -2px var(--look-drop);
407
+ }
408
+ :root[data-look="tactile"] .seg-thumb {
409
+ transition:
410
+ translate var(--dur-spring) var(--ease-spring-bounce),
411
+ scale var(--dur-spring) var(--ease-spring-bounce);
412
+ }
413
+ :root[data-look="tactile"] .seg.placed .seg-item.selected {
414
+ background: transparent;
415
+ box-shadow: none;
416
+ }
417
+
418
+ /* ---------- Tabs ---------- */
419
+
420
+ :root[data-look="tactile"] .tablist,
421
+ :root[data-look="tactile"] .strip .actions {
422
+ border-bottom: 0;
423
+ }
424
+ :root[data-look="tactile"] .tablist {
425
+ gap: var(--sp-1);
426
+ padding-bottom: var(--sp-1);
427
+ }
428
+ :root[data-look="tactile"] .tab {
429
+ border-bottom: 0;
430
+ margin-bottom: 0;
431
+ border-radius: var(--r-pill);
432
+ transition:
433
+ color var(--dur-fast) var(--ease),
434
+ background-color var(--dur-fast) var(--ease),
435
+ scale var(--dur-fast) var(--ease-spring-bounce);
436
+ }
437
+ :root[data-look="tactile"] .tab.selected {
438
+ color: var(--text);
439
+ background: color-mix(in oklab, var(--accent) 14%, transparent);
440
+ }
441
+ :root[data-look="tactile"] .indicator {
442
+ height: 3px;
443
+ border-radius: var(--r-pill);
444
+ }
445
+ :root[data-look="tactile"] .tab:active:not(:disabled, .disabled) {
446
+ scale: var(--press-scale);
447
+ transition-duration: var(--dur-press);
448
+ }
449
+
450
+ /* ---------- Badges, dots, kbd ---------- */
451
+
452
+ :root[data-look="tactile"] .badge:not(.text) {
453
+ border-color: transparent;
454
+ background: var(--badge-bg, color-mix(in oklab, var(--text) 8%, transparent));
455
+ font-weight: var(--badge-fw, var(--fw-semibold));
456
+ }
457
+ :root[data-look="tactile"] .tab .badge:not(.text) {
458
+ font-weight: var(--badge-fw, var(--fw-medium));
459
+ }
460
+ :root[data-look="tactile"] .badge:not(.text, .role-pill) {
461
+ color: var(--badge-fg, color-mix(in oklab, var(--text-muted) 60%, var(--text)));
462
+ }
463
+ :root[data-look="tactile"] .bubble .role-pill {
464
+ color: color-mix(in oklab, var(--role) 70%, var(--text));
465
+ }
466
+ :root[data-look="tactile"] .badge.toned:not(.text, .active) {
467
+ background: var(--badge-bg, color-mix(in oklab, var(--badge-tone) var(--look-pastel), transparent));
468
+ color: var(--badge-fg, color-mix(in oklab, var(--badge-tone) 70%, var(--text)));
469
+ }
470
+ :root[data-look="tactile"] .badge.active,
471
+ :root[data-look="tactile"] .tab.selected .badge.toned:not(.text) {
472
+ background: var(--badge-tone, var(--accent));
473
+ color: var(--text-on-accent);
474
+ }
475
+
476
+ :root[data-look="tactile"] .dot.glow {
477
+ box-shadow: 0 0 0 3px color-mix(in oklab, var(--dot-color) 25%, transparent);
478
+ }
479
+
480
+ :root[data-look="tactile"] .kbd {
481
+ border: 0;
482
+ border-radius: 6px;
483
+ padding: 0 0.4em;
484
+ color: var(--text);
485
+ background: linear-gradient(to bottom, color-mix(in oklab, var(--surface) 90%, var(--look-tint)), var(--surface));
486
+ box-shadow:
487
+ inset 0 0 0 1px color-mix(in oklab, var(--border) 60%, transparent),
488
+ inset 0 1px 0 var(--look-hi),
489
+ 0 2px 0 color-mix(in oklab, var(--surface) var(--look-lip-pct), var(--look-lip-ink));
490
+ }
491
+
492
+ /* ---------- Cards & surfaces ---------- */
493
+
494
+ :root[data-look="tactile"] .card {
495
+ --look-card-bg: var(--bg-elevated);
496
+ border-color: transparent;
497
+ border-radius: var(--r-lg);
498
+ background: var(--look-card-bg);
499
+ box-shadow: var(--look-elev-1);
500
+ }
501
+ :root[data-look="tactile"] .card.surface-raised {
502
+ --look-card-bg: var(--surface);
503
+ box-shadow: var(--look-elev-2);
504
+ }
505
+ :root[data-look="tactile"] .card.surface-sunken {
506
+ --look-card-bg: var(--look-well);
507
+ box-shadow: var(--look-well-shadow);
508
+ }
509
+ :root[data-look="tactile"] .card:is(.card-ok, .card-warn, .card-danger, .card-info, .card-accent) {
510
+ --look-card-bg: color-mix(in oklab, var(--card-tone) 10%, var(--bg-elevated));
511
+ --text-faint: color-mix(in oklab, var(--c-text-faint) 75%, var(--text));
512
+ border-color: transparent;
513
+ }
514
+ :root[data-look="tactile"] :is(.card:is(.card-ok, .card-warn, .card-danger, .card-info, .card-accent), .bubble) .tone-muted {
515
+ color: color-mix(in oklab, var(--text-muted) 55%, var(--text));
516
+ }
517
+ :root[data-look="tactile"] .card.card-attention {
518
+ --look-card-bg: var(--attention-bg);
519
+ }
520
+ :root[data-look="tactile"] .card.border-dashed {
521
+ border: 2px dashed color-mix(in oklab, var(--border-strong) 70%, transparent);
522
+ background: transparent;
523
+ box-shadow: none;
524
+ }
525
+ :root[data-look="tactile"] .card-head {
526
+ border-bottom: 0;
527
+ padding-bottom: 0;
528
+ }
529
+ :root[data-look="tactile"] .card-foot {
530
+ border-top: 0;
531
+ background: color-mix(in oklab, var(--text) 3.5%, transparent);
532
+ border-radius: 0 0 var(--r-lg) var(--r-lg);
533
+ }
534
+ :root[data-look="tactile"] .card-stacked::before,
535
+ :root[data-look="tactile"] .card-stacked::after {
536
+ border: 0;
537
+ box-shadow: var(--look-elev-1);
538
+ }
539
+ :root[data-look="tactile"] .card-stacked::before {
540
+ background: color-mix(in oklab, var(--bg-elevated) 55%, var(--bg-elevated-2));
541
+ }
542
+ :root[data-look="tactile"] .card-stacked::after {
543
+ background: var(--bg-elevated-2);
544
+ }
545
+
546
+ :root[data-look="tactile"] .card-tap {
547
+ transition:
548
+ background-color var(--dur-fast) var(--ease),
549
+ box-shadow var(--dur-fast) var(--ease),
550
+ translate var(--dur-fast) var(--ease-spring-bounce),
551
+ scale var(--dur-fast) var(--ease-spring-bounce);
552
+ }
553
+ :root[data-look="tactile"] .card-tap:active {
554
+ background: var(--look-card-bg);
555
+ scale: var(--press-scale-lg);
556
+ translate: 0 1px;
557
+ box-shadow: inset 0 1px 0 var(--look-hi), 0 1px 2px var(--look-drop);
558
+ transition-duration: var(--dur-press);
559
+ transition-timing-function: var(--ease-out);
560
+ }
561
+
562
+ :root[data-look="tactile"] .metric-chip {
563
+ border: 0;
564
+ border-radius: var(--r-pill);
565
+ width: 2rem;
566
+ height: 2rem;
567
+ background: color-mix(in oklab, var(--metric-tone) 20%, transparent);
568
+ }
569
+
570
+ /* ---------- Callouts ---------- */
571
+
572
+ :root[data-look="tactile"] .card.callout {
573
+ --look-card-bg: color-mix(in oklab, var(--card-tone, var(--text-muted)) 14%, var(--bg-elevated));
574
+ box-shadow: none;
575
+ padding: var(--sp-3) var(--sp-4);
576
+ }
577
+ :root[data-look="tactile"] .card.callout:not(.callout-ok, .callout-warn, .callout-danger, .callout-info, .callout-accent) {
578
+ --look-card-bg: var(--bg-elevated-2);
579
+ }
580
+ :root[data-look="tactile"] .callout-icon {
581
+ justify-content: center;
582
+ width: 1.75rem;
583
+ height: 1.75rem;
584
+ min-height: 0;
585
+ border-radius: var(--r-pill);
586
+ font-size: var(--fs-md);
587
+ color: var(--card-tone, var(--text-muted));
588
+ background: color-mix(in oklab, var(--card-tone, var(--text-muted)) 22%, transparent);
589
+ }
590
+
591
+ /* ---------- Table ---------- */
592
+
593
+ :root[data-look="tactile"] .dt-scroll {
594
+ border: 0;
595
+ border-radius: var(--r-lg);
596
+ background: var(--bg-elevated);
597
+ box-shadow: var(--look-elev-1);
598
+ }
599
+ :root[data-look="tactile"] .dt {
600
+ background: transparent;
601
+ }
602
+ :root[data-look="tactile"] .dt :is(th, td) {
603
+ border-bottom: 1px solid var(--look-hairline);
604
+ }
605
+ :root[data-look="tactile"] .dt tbody tr:last-child td {
606
+ border-bottom: 0;
607
+ }
608
+ :root[data-look="tactile"] .dt th {
609
+ background: color-mix(in oklab, var(--text) 4%, transparent);
610
+ border-bottom: 0;
611
+ }
612
+ :root[data-look="tactile"] .dt tr.clickable {
613
+ transition: background-color var(--dur-fast) var(--ease);
614
+ }
615
+ :root[data-look="tactile"] [data-stacked] :is(tbody, tfoot) tr {
616
+ border-bottom: 1px solid var(--look-hairline);
617
+ }
618
+
619
+ /* ---------- Accordion ---------- */
620
+
621
+ :root[data-look="tactile"] .accordion:not(.accordion--plain) {
622
+ display: grid;
623
+ gap: var(--sp-2);
624
+ border: 0;
625
+ border-radius: 0;
626
+ overflow: visible;
627
+ }
628
+ :root[data-look="tactile"] .accordion:not(.accordion--plain) > .acc-item {
629
+ border: 0;
630
+ border-radius: var(--r-lg);
631
+ background: var(--bg-elevated);
632
+ box-shadow: var(--look-elev-1);
633
+ overflow: hidden;
634
+ }
635
+ :root[data-look="tactile"] .disclosure__button {
636
+ border-radius: inherit;
637
+ }
638
+ :root[data-look="tactile"] .disclosure__chevron {
639
+ display: inline-flex;
640
+ align-items: center;
641
+ justify-content: center;
642
+ width: 1.5rem;
643
+ height: 1.5rem;
644
+ border-radius: var(--r-pill);
645
+ background: color-mix(in oklab, var(--text) 7%, transparent);
646
+ }
647
+
648
+ /* ---------- Progress, gauge ---------- */
649
+
650
+ :root[data-look="tactile"] .progress {
651
+ height: 0.625rem;
652
+ background: var(--look-well);
653
+ box-shadow: var(--look-track-shadow);
654
+ }
655
+ :root[data-look="tactile"] .progress.size-sm {
656
+ height: 0.375rem;
657
+ }
658
+ :root[data-look="tactile"] .progress .bar {
659
+ box-shadow:
660
+ inset 0 1px 0 color-mix(in oklab, var(--look-tint) 30%, transparent),
661
+ inset 0 -1px 0 color-mix(in oklab, var(--look-ink) 15%, transparent);
662
+ }
663
+ :root[data-look="tactile"] .gauge[data-tsu="Gauge"] {
664
+ border: 0;
665
+ background: var(--look-well);
666
+ box-shadow: var(--look-track-shadow);
667
+ }
668
+
669
+ /* ---------- Menus, popovers, rich select ---------- */
670
+
671
+ :root[data-look="tactile"] .pop-panel {
672
+ border: 0;
673
+ border-radius: 18px;
674
+ background: var(--surface);
675
+ box-shadow: var(--raised-shadow);
676
+ padding: var(--sp-1);
677
+ }
678
+ :root[data-look="tactile"] .menu-item,
679
+ :root[data-look="tactile"] .rs-row,
680
+ :root[data-look="tactile"] .rs-option {
681
+ border-radius: var(--r-md);
682
+ }
683
+ :root[data-look="tactile"] .menu-item {
684
+ transition:
685
+ background-color var(--dur-fast) var(--ease),
686
+ translate var(--dur-fast) var(--ease-spring-bounce);
687
+ }
688
+ :root[data-look="tactile"] .rs-footer {
689
+ border-top: 0;
690
+ }
691
+ :root[data-look="tactile"] .fake-menu {
692
+ border-radius: 18px;
693
+ }
694
+
695
+ /* ---------- Modal & toast ---------- */
696
+
697
+ :root[data-look="tactile"] .sheet {
698
+ border: 0;
699
+ border-radius: 28px 28px 0 0;
700
+ box-shadow: var(--overlay-shadow);
701
+ }
702
+ :root[data-look="tactile"] :is(.sheet-head, .sheet-foot) {
703
+ border: 0;
704
+ }
705
+ :root[data-look="tactile"] .sheet-foot {
706
+ background: color-mix(in oklab, var(--text) 3.5%, transparent);
707
+ }
708
+ :root[data-look="tactile"] .sheet-toned {
709
+ border-top: 0;
710
+ box-shadow: inset 0 4px 0 var(--modal-tone), var(--shadow-lg);
711
+ }
712
+ @media (min-width: 40rem) {
713
+ :root[data-look="tactile"] .sheet {
714
+ border-radius: 28px;
715
+ }
716
+ }
717
+ :root[data-look="tactile"] .toaster .card.toast {
718
+ --look-card-bg: var(--surface);
719
+ border-radius: var(--r-pill);
720
+ padding-inline: var(--sp-5);
721
+ box-shadow: var(--overlay-shadow);
722
+ }
723
+
724
+ /* ---------- Section headers ---------- */
725
+
726
+ :root[data-look="tactile"] .sh-divider > .sh-row {
727
+ border-bottom: 0;
728
+ }
729
+ :root[data-look="tactile"] .sh-rule {
730
+ background: transparent;
731
+ }
732
+
733
+ /* ---------- Chat ---------- */
734
+
735
+ :root[data-look="tactile"] .bubble {
736
+ border: 0;
737
+ border-radius: 20px;
738
+ background: color-mix(in oklab, var(--role) 8%, var(--bg-elevated));
739
+ box-shadow: var(--look-elev-1);
740
+ }
741
+ :root[data-look="tactile"] .bubble.align-end {
742
+ border-end-end-radius: 6px;
743
+ }
744
+ :root[data-look="tactile"] .bubble.align-start {
745
+ border-end-start-radius: 6px;
746
+ }
747
+ :root[data-look="tactile"] .composer .textarea {
748
+ border-radius: 22px;
749
+ }
750
+ :root[data-look="tactile"] .composer .ig {
751
+ --ig-radius: 22px;
752
+ }
753
+
754
+ /* ---------- Hover micro-interactions (fine pointers only) ---------- */
755
+
756
+ @media (hover: hover) and (pointer: fine) {
757
+ :root[data-look="tactile"] :is(.btn:not(.btn-link, .btn-icon-inline, .btn-ghost), .pop-trigger.canonical:not(.trigger-ghost), .pop-trigger.trigger-primary):hover:not(:disabled, [aria-disabled="true"], .loading, .is-disabled, :active) {
758
+ translate: 0 calc(-1 * var(--hover-lift));
759
+ background: var(--btn-bg, var(--pop-trigger-bg, linear-gradient(to bottom, color-mix(in oklab, var(--look-face) 86%, var(--look-tint)), color-mix(in oklab, var(--look-face) 94%, var(--look-tint)))));
760
+ box-shadow:
761
+ inset 0 1px 0 var(--look-hi),
762
+ 0 calc(var(--look-lip) + 1px) 0 var(--look-lip-c),
763
+ 0 calc(var(--look-lip) + 5px) 12px -4px var(--look-drop);
764
+ }
765
+ :root[data-look="tactile"] :is(.btn-ghost, .pop-trigger.trigger-ghost):hover:not(:disabled, [aria-disabled="true"]) {
766
+ background: color-mix(in oklab, var(--text) 8%, transparent);
767
+ }
768
+ :root[data-look="tactile"] .btn .icon,
769
+ :root[data-look="tactile"] .pop-trigger .icon {
770
+ transition:
771
+ translate var(--dur-fast) var(--ease-spring-bounce),
772
+ rotate var(--dur-fast) var(--ease-spring-bounce);
773
+ }
774
+ :root[data-look="tactile"] .btn:hover:not(:disabled, .loading) > .icon:first-child,
775
+ :root[data-look="tactile"] .pop-trigger:hover > .icon:first-child {
776
+ translate: 0 -1px;
777
+ rotate: -8deg;
778
+ }
779
+ :root[data-look="tactile"] .pop-trigger:hover .caret-glyph .icon {
780
+ translate: 0 2px;
781
+ }
782
+
783
+ /* Pointer spotlight: --pointer-x/--pointer-y come from trackPointer(); without it the spot rests above the card. */
784
+ :root[data-look="tactile"] .card-tap:hover,
785
+ :root[data-look="tactile"] .card.metric:hover {
786
+ background:
787
+ radial-gradient(circle 14rem at var(--pointer-x, 50%) var(--pointer-y, -40%), var(--look-spot), transparent 70%),
788
+ var(--look-card-bg);
789
+ }
790
+ :root[data-look="tactile"] .card-tap:hover:not(:active) {
791
+ translate: 0 -2px;
792
+ box-shadow: var(--look-elev-2);
793
+ }
794
+
795
+ :root[data-look="tactile"] .tab:hover:not(:disabled, .disabled, .selected) {
796
+ background: color-mix(in oklab, var(--text) 7%, transparent);
797
+ }
798
+ :root[data-look="tactile"] .badge.interactive:hover:not(.active) {
799
+ color: var(--text);
800
+ }
801
+ :root[data-look="tactile"] .seg-item:hover:not(:disabled):not(.selected) {
802
+ background: color-mix(in oklab, var(--text) 6%, transparent);
803
+ }
804
+ :root[data-look="tactile"] .menu-item:hover:not([inert]) {
805
+ background: color-mix(in oklab, var(--accent) 14%, transparent);
806
+ translate: 2px 0;
807
+ }
808
+ :root[data-look="tactile"] .rs-row[data-active] {
809
+ background: color-mix(in oklab, var(--accent) 12%, transparent);
810
+ }
811
+ :root[data-look="tactile"] .disclosure__button:hover {
812
+ background: color-mix(in oklab, var(--text) 4%, transparent);
813
+ }
814
+ :root[data-look="tactile"] .disclosure__chevron {
815
+ transition:
816
+ rotate var(--dur-base) var(--ease-spring-bounce),
817
+ background-color var(--dur-fast) var(--ease);
818
+ }
819
+ :root[data-look="tactile"] .disclosure__button:hover .disclosure__chevron {
820
+ background: color-mix(in oklab, var(--accent) 18%, transparent);
821
+ color: var(--accent);
822
+ }
823
+ :root[data-look="tactile"] :is(.input, .select:not(.ghost, .embedded), .textarea):hover:not(:disabled, :focus, [aria-invalid="true"]) {
824
+ border-color: transparent;
825
+ background: color-mix(in oklab, var(--text) 3%, var(--look-well));
826
+ }
827
+ :root[data-look="tactile"] .checkbox:hover .box,
828
+ :root[data-look="tactile"] .radio:hover:not(.disabled) .dot-ctl {
829
+ translate: 0 -1px;
830
+ }
831
+ :root[data-look="tactile"] .switch:hover:not(:disabled) .knob {
832
+ scale: 1.06;
833
+ }
834
+ :root[data-look="tactile"] .slider input[type="range"]:not(:disabled):hover::-webkit-slider-thumb {
835
+ box-shadow: var(--look-knob-shadow), var(--halo);
836
+ }
837
+ :root[data-look="tactile"] .dt tr.clickable:hover td {
838
+ background: color-mix(in oklab, var(--accent) 6%, transparent);
839
+ }
840
+ }
841
+
842
+ /* ---------- Focus bloom ---------- */
843
+
844
+ :root[data-look="tactile"] :is(.btn, .pop-trigger, .tab, .seg-item, .switch, .card-tap):focus-visible {
845
+ animation: tsu-tactile-bloom var(--dur-fast) var(--ease-out);
846
+ }
847
+ @keyframes tsu-tactile-bloom {
848
+ from {
849
+ outline-offset: 7px;
850
+ outline-color: transparent;
851
+ }
852
+ }
853
+
854
+ /* ---------- Reduced motion ---------- */
855
+
856
+ @media (prefers-reduced-motion: reduce) {
857
+ :root[data-look="tactile"] :is(.btn, .pop-trigger, .card-tap, .tab, .menu-item, .checkbox .box, .dot-ctl, .icon) {
858
+ translate: none !important;
859
+ scale: none !important;
860
+ rotate: none !important;
861
+ }
862
+ :root[data-look="tactile"] .knob {
863
+ scale: none !important;
864
+ }
865
+ :root[data-look="tactile"] :is(.knob, .seg-thumb) {
866
+ transition-property: background-color, box-shadow;
867
+ }
868
+ :root[data-look="tactile"] :focus-visible {
869
+ animation: none;
870
+ }
871
+ }