@motion-proto/live-tokens 0.71.0 → 0.72.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.
- package/.claude/skills/live-tokens-check-compliance/SKILL.md +7 -1
- package/.claude/skills/live-tokens-create-component/SKILL.md +2 -2
- package/.claude/skills/live-tokens-create-component/references/contract-tests.md +99 -0
- package/.claude/skills/live-tokens-create-component/references/sketch-mode.md +1 -2
- package/.claude/skills/live-tokens-create-component/references/token-naming.md +6 -0
- package/CHANGELOG.md +77 -0
- package/README.md +1 -1
- package/bin/check-component.mjs +2 -11
- package/bin/check-page.mjs +3 -2
- package/bin/cli.mjs +2 -1
- package/bin/lib/catalogue.mjs +6 -2
- package/bin/lib/findings.mjs +17 -0
- package/bin/lib/report.mjs +1 -1
- package/bin/lib/tokenVocabulary.mjs +20 -0
- package/dist-plugin/adjust/index.cjs +33 -6
- package/dist-plugin/adjust/index.d.cts +2 -2
- package/dist-plugin/adjust/index.d.ts +2 -2
- package/dist-plugin/adjust/index.js +7 -6
- package/dist-plugin/{chunk-2YNERPXY.js → chunk-RIXO2E55.js} +1 -1
- package/dist-plugin/{chunk-RVE3MNKM.js → chunk-W6Y4BWFB.js} +3 -1
- package/dist-plugin/{chunk-GPIBU44G.js → chunk-YLCOIGQC.js} +25 -1
- package/dist-plugin/{dataPaths-bJTCEO4H.d.ts → dataPaths-BhWzd5cL.d.cts} +4 -0
- package/dist-plugin/{dataPaths-bJTCEO4H.d.cts → dataPaths-BhWzd5cL.d.ts} +4 -0
- package/dist-plugin/fontPairing/index.cjs +3 -1
- package/dist-plugin/fontPairing/index.d.cts +1 -1
- package/dist-plugin/fontPairing/index.d.ts +1 -1
- package/dist-plugin/fontPairing/index.js +1 -1
- package/dist-plugin/generateColorsAndType/index.cjs +28 -2
- package/dist-plugin/generateColorsAndType/index.d.cts +1 -1
- package/dist-plugin/generateColorsAndType/index.d.ts +1 -1
- package/dist-plugin/generateColorsAndType/index.js +2 -2
- package/dist-plugin/index.cjs +28 -2
- package/dist-plugin/index.d.cts +1 -1
- package/dist-plugin/index.d.ts +1 -1
- package/dist-plugin/index.js +3 -3
- package/dist-plugin/migrateData/index.cjs +28 -2
- package/dist-plugin/migrateData/index.d.cts +1 -1
- package/dist-plugin/migrateData/index.d.ts +1 -1
- package/dist-plugin/migrateData/index.js +3 -3
- package/dist-plugin/tokensCssMigrations/index.cjs +3 -1
- package/dist-plugin/tokensCssMigrations/index.d.cts +1 -1
- package/dist-plugin/tokensCssMigrations/index.d.ts +1 -1
- package/dist-plugin/tokensCssMigrations/index.js +1 -1
- package/package.json +5 -1
- package/src/editor/component-editor/SectionDividerEditor.svelte +1 -11
- package/src/editor/component-editor/contract.ts +175 -0
- package/src/editor/component-editor/scaffolding/StateBlock.svelte +0 -8
- package/src/editor/component-editor/scaffolding/TokenLayout.svelte +5 -0
- package/src/editor/component-editor/scaffolding/TypeEditor.svelte +0 -21
- package/src/editor/component-editor/scaffolding/VariantGroup.svelte +2 -2
- package/src/editor/component-editor/scaffolding/types.ts +1 -7
- package/src/editor/core/components/aliasKinds.ts +6 -2
- package/src/editor/core/themes/migrations/2026-09-02-sectiondivider-drop-title-outline.ts +39 -0
- package/src/editor/core/themes/migrations/index.ts +2 -0
- package/src/live-tokens/data/themes/autumn.json +1 -7
- package/src/live-tokens/data/themes/halloween.json +1 -7
- package/src/live-tokens/data/themes/midnight-study.json +1 -7
- package/src/live-tokens/data/themes/ocean.json +1 -7
- package/src/live-tokens/data/themes/royal-velvet.json +1 -7
- package/src/live-tokens/data/themes/sketchy.json +1 -7
- package/src/live-tokens/data/themes/spring-meadow.json +1 -7
- package/src/live-tokens/data/themes/sunset.json +1 -7
- package/src/system/components/SectionDivider.svelte +3 -143
- package/src/system/components/FloatingTokenTags.css +0 -284
- package/src/system/components/FloatingTokenTags.svelte +0 -570
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { run } from 'svelte/legacy';
|
|
3
|
-
|
|
4
|
-
import { onMount, tick } from 'svelte';
|
|
5
|
-
|
|
6
2
|
/** Size variant. Each variant owns everything that defines its style:
|
|
7
3
|
* typography, geometry, colors AND the intrinsic display properties
|
|
8
4
|
* (alignment, eyebrow visibility, description visibility, hairline
|
|
@@ -23,69 +19,6 @@
|
|
|
23
19
|
eyebrow = undefined,
|
|
24
20
|
variant = 'md',
|
|
25
21
|
}: Props = $props();
|
|
26
|
-
|
|
27
|
-
let svgEl: SVGSVGElement | undefined = $state();
|
|
28
|
-
let svgTextEl: SVGTextElement | undefined = $state();
|
|
29
|
-
let svgW = $state(0);
|
|
30
|
-
let svgH = $state(0);
|
|
31
|
-
let svgX = $state(0);
|
|
32
|
-
let svgY = $state(0);
|
|
33
|
-
|
|
34
|
-
// feMorphology radius and feFlood flood-color are non-presentation attributes
|
|
35
|
-
// and can't read CSS vars. Read resolved values off the SVG element and push
|
|
36
|
-
// them onto the filter primitives, refreshing on doc-level inline-var changes.
|
|
37
|
-
let outlineRadius = $state('0');
|
|
38
|
-
let outlineColor = $state('#000');
|
|
39
|
-
const filterId = `sd-outline-${Math.random().toString(36).slice(2, 10)}`;
|
|
40
|
-
|
|
41
|
-
function syncFilter(): void {
|
|
42
|
-
if (!svgEl) return;
|
|
43
|
-
const cs = getComputedStyle(svgEl);
|
|
44
|
-
const wPx = parseFloat(cs.getPropertyValue('--_divider-title-outline-width'));
|
|
45
|
-
outlineRadius = String(Number.isFinite(wPx) ? wPx / 2 : 0);
|
|
46
|
-
const c = cs.getPropertyValue('--_divider-title-outline-color').trim();
|
|
47
|
-
outlineColor = c || '#000';
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function measure(): void {
|
|
51
|
-
if (!svgTextEl) return;
|
|
52
|
-
const bb = svgTextEl.getBBox();
|
|
53
|
-
svgX = bb.x;
|
|
54
|
-
svgY = bb.y;
|
|
55
|
-
svgW = Math.ceil(bb.width);
|
|
56
|
-
svgH = Math.ceil(bb.height);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
run(() => {
|
|
60
|
-
if (title) {
|
|
61
|
-
tick().then(() => { measure(); syncFilter(); });
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
onMount(() => {
|
|
66
|
-
let mounted = true;
|
|
67
|
-
const sync = () => { measure(); syncFilter(); };
|
|
68
|
-
measure();
|
|
69
|
-
syncFilter();
|
|
70
|
-
const obs = new MutationObserver(sync);
|
|
71
|
-
obs.observe(document.documentElement, { attributes: true, attributeFilter: ['style'] });
|
|
72
|
-
|
|
73
|
-
// A font-family variable changes before its webfont necessarily finishes
|
|
74
|
-
// loading. Re-run getBBox when the real face becomes available so the SVG
|
|
75
|
-
// viewBox and outline do not stay sized for the fallback font.
|
|
76
|
-
const fonts = document.fonts;
|
|
77
|
-
const onFontsLoaded = () => {
|
|
78
|
-
if (mounted) sync();
|
|
79
|
-
};
|
|
80
|
-
fonts?.addEventListener('loadingdone', onFontsLoaded);
|
|
81
|
-
void fonts?.ready.then(onFontsLoaded);
|
|
82
|
-
|
|
83
|
-
return () => {
|
|
84
|
-
mounted = false;
|
|
85
|
-
obs.disconnect();
|
|
86
|
-
fonts?.removeEventListener('loadingdone', onFontsLoaded);
|
|
87
|
-
};
|
|
88
|
-
});
|
|
89
22
|
</script>
|
|
90
23
|
|
|
91
24
|
<!-- In dev, render every variant-controlled block so the editor can flip
|
|
@@ -101,31 +34,7 @@
|
|
|
101
34
|
<div class="title-row">
|
|
102
35
|
<span class="sd-hairline sd-hairline--side sd-hairline-through-label" aria-hidden="true"></span>
|
|
103
36
|
<span class="title-inline">
|
|
104
|
-
<
|
|
105
|
-
bind:this={svgEl}
|
|
106
|
-
class="divider-label"
|
|
107
|
-
width={svgW || undefined}
|
|
108
|
-
height={svgH || undefined}
|
|
109
|
-
viewBox={svgW && svgH ? `${svgX} ${svgY} ${svgW} ${svgH}` : undefined}
|
|
110
|
-
aria-label={title}
|
|
111
|
-
role="img"
|
|
112
|
-
>
|
|
113
|
-
<defs>
|
|
114
|
-
<filter id={filterId} x="-50%" y="-50%" width="200%" height="200%">
|
|
115
|
-
<feMorphology in="SourceAlpha" operator="dilate" radius={outlineRadius} result="dilated" />
|
|
116
|
-
<feFlood flood-color={outlineColor} result="color" />
|
|
117
|
-
<feComposite in="color" in2="dilated" operator="in" result="outline" />
|
|
118
|
-
<feComposite in="SourceGraphic" in2="outline" operator="over" />
|
|
119
|
-
</filter>
|
|
120
|
-
</defs>
|
|
121
|
-
<text
|
|
122
|
-
bind:this={svgTextEl}
|
|
123
|
-
x="0"
|
|
124
|
-
y="0"
|
|
125
|
-
dominant-baseline="hanging"
|
|
126
|
-
filter="url(#{filterId})"
|
|
127
|
-
>{title}</text>
|
|
128
|
-
</svg>
|
|
37
|
+
<span class="divider-label">{title}</span>
|
|
129
38
|
</span>
|
|
130
39
|
<span class="sd-hairline sd-hairline--side sd-hairline-through-label" aria-hidden="true"></span>
|
|
131
40
|
</div>
|
|
@@ -153,31 +62,7 @@
|
|
|
153
62
|
<span class="sd-hairline sd-hairline--side sd-hairline-through-label" aria-hidden="true"></span>
|
|
154
63
|
<!--END_PRUNE-->
|
|
155
64
|
<span class="title-inline">
|
|
156
|
-
<
|
|
157
|
-
bind:this={svgEl}
|
|
158
|
-
class="divider-label"
|
|
159
|
-
width={svgW || undefined}
|
|
160
|
-
height={svgH || undefined}
|
|
161
|
-
viewBox={svgW && svgH ? `${svgX} ${svgY} ${svgW} ${svgH}` : undefined}
|
|
162
|
-
aria-label={title}
|
|
163
|
-
role="img"
|
|
164
|
-
>
|
|
165
|
-
<defs>
|
|
166
|
-
<filter id={filterId} x="-50%" y="-50%" width="200%" height="200%">
|
|
167
|
-
<feMorphology in="SourceAlpha" operator="dilate" radius={outlineRadius} result="dilated" />
|
|
168
|
-
<feFlood flood-color={outlineColor} result="color" />
|
|
169
|
-
<feComposite in="color" in2="dilated" operator="in" result="outline" />
|
|
170
|
-
<feComposite in="SourceGraphic" in2="outline" operator="over" />
|
|
171
|
-
</filter>
|
|
172
|
-
</defs>
|
|
173
|
-
<text
|
|
174
|
-
bind:this={svgTextEl}
|
|
175
|
-
x="0"
|
|
176
|
-
y="0"
|
|
177
|
-
dominant-baseline="hanging"
|
|
178
|
-
filter="url(#{filterId})"
|
|
179
|
-
>{title}</text>
|
|
180
|
-
</svg>
|
|
65
|
+
<span class="divider-label">{title}</span>
|
|
181
66
|
</span>
|
|
182
67
|
<!--PRUNE_FOR sectiondivider hairline == through-label default=none-->
|
|
183
68
|
<span class="sd-hairline sd-hairline--side sd-hairline-through-label" aria-hidden="true"></span>
|
|
@@ -221,7 +106,6 @@
|
|
|
221
106
|
--sectiondivider-lg-title-font-size: var(--font-size-5xl);
|
|
222
107
|
--sectiondivider-lg-title-line-height: var(--line-height-normal);
|
|
223
108
|
--sectiondivider-lg-title-letter-spacing: var(--letter-spacing-normal);
|
|
224
|
-
--sectiondivider-lg-title-outline-width: var(--border-width-4);
|
|
225
109
|
--sectiondivider-lg-description-font-family: var(--font-sans);
|
|
226
110
|
--sectiondivider-lg-description-font-weight: var(--font-weight-medium);
|
|
227
111
|
--sectiondivider-lg-description-font-size: var(--font-size-lg);
|
|
@@ -243,7 +127,6 @@
|
|
|
243
127
|
--sectiondivider-lg-description: var(--text-alternate);
|
|
244
128
|
--sectiondivider-lg-eyebrow: var(--text-brand);
|
|
245
129
|
--sectiondivider-lg-border: var(--color-transparent);
|
|
246
|
-
--sectiondivider-lg-title-outline-color: var(--color-transparent);
|
|
247
130
|
--sectiondivider-lg-hairline-color: var(--border-brand-medium);
|
|
248
131
|
|
|
249
132
|
/* Medium */
|
|
@@ -252,7 +135,6 @@
|
|
|
252
135
|
--sectiondivider-md-title-font-size: var(--font-size-4xl);
|
|
253
136
|
--sectiondivider-md-title-line-height: var(--line-height-normal);
|
|
254
137
|
--sectiondivider-md-title-letter-spacing: var(--letter-spacing-normal);
|
|
255
|
-
--sectiondivider-md-title-outline-width: var(--border-width-4);
|
|
256
138
|
--sectiondivider-md-description-font-family: var(--font-sans);
|
|
257
139
|
--sectiondivider-md-description-font-weight: var(--font-weight-medium);
|
|
258
140
|
--sectiondivider-md-description-font-size: var(--font-size-lg);
|
|
@@ -274,7 +156,6 @@
|
|
|
274
156
|
--sectiondivider-md-description: var(--text-secondary);
|
|
275
157
|
--sectiondivider-md-eyebrow: var(--text-tertiary);
|
|
276
158
|
--sectiondivider-md-border: var(--color-transparent);
|
|
277
|
-
--sectiondivider-md-title-outline-color: var(--color-transparent);
|
|
278
159
|
--sectiondivider-md-hairline-color: var(--border-brand-medium);
|
|
279
160
|
|
|
280
161
|
/* Small */
|
|
@@ -283,7 +164,6 @@
|
|
|
283
164
|
--sectiondivider-sm-title-font-size: var(--font-size-3xl);
|
|
284
165
|
--sectiondivider-sm-title-line-height: var(--line-height-normal);
|
|
285
166
|
--sectiondivider-sm-title-letter-spacing: var(--letter-spacing-normal);
|
|
286
|
-
--sectiondivider-sm-title-outline-width: var(--border-width-4);
|
|
287
167
|
--sectiondivider-sm-description-font-family: var(--font-sans);
|
|
288
168
|
--sectiondivider-sm-description-font-weight: var(--font-weight-medium);
|
|
289
169
|
--sectiondivider-sm-description-font-size: var(--font-size-5xl);
|
|
@@ -305,7 +185,6 @@
|
|
|
305
185
|
--sectiondivider-sm-description: var(--text-secondary);
|
|
306
186
|
--sectiondivider-sm-eyebrow: var(--text-tertiary);
|
|
307
187
|
--sectiondivider-sm-border: var(--color-transparent);
|
|
308
|
-
--sectiondivider-sm-title-outline-color: var(--color-transparent);
|
|
309
188
|
--sectiondivider-sm-hairline-color: color-mix(in srgb, var(--border-brand-medium) 50%, transparent);
|
|
310
189
|
|
|
311
190
|
/* Intrinsic defaults. These keys cascade to `:root` via the editor's
|
|
@@ -361,7 +240,6 @@
|
|
|
361
240
|
--_divider-title-font-size: var(--sectiondivider-lg-title-font-size);
|
|
362
241
|
--_divider-title-line-height: var(--sectiondivider-lg-title-line-height);
|
|
363
242
|
--_divider-title-letter-spacing: var(--sectiondivider-lg-title-letter-spacing);
|
|
364
|
-
--_divider-title-outline-width: var(--sectiondivider-lg-title-outline-width);
|
|
365
243
|
--_divider-description-font-family: var(--sectiondivider-lg-description-font-family);
|
|
366
244
|
--_divider-description-font-weight: var(--sectiondivider-lg-description-font-weight);
|
|
367
245
|
--_divider-description-font-size: var(--sectiondivider-lg-description-font-size);
|
|
@@ -383,7 +261,6 @@
|
|
|
383
261
|
--_divider-description: var(--sectiondivider-lg-description);
|
|
384
262
|
--_divider-eyebrow: var(--sectiondivider-lg-eyebrow);
|
|
385
263
|
--_divider-border: var(--sectiondivider-lg-border);
|
|
386
|
-
--_divider-title-outline-color: var(--sectiondivider-lg-title-outline-color);
|
|
387
264
|
--_divider-hairline-color: var(--sectiondivider-lg-hairline-color);
|
|
388
265
|
--_divider-align: var(--sectiondivider-lg-align);
|
|
389
266
|
--_divider-eyebrow-display: var(--sectiondivider-lg-eyebrow-display);
|
|
@@ -398,7 +275,6 @@
|
|
|
398
275
|
--_divider-title-font-size: var(--sectiondivider-md-title-font-size);
|
|
399
276
|
--_divider-title-line-height: var(--sectiondivider-md-title-line-height);
|
|
400
277
|
--_divider-title-letter-spacing: var(--sectiondivider-md-title-letter-spacing);
|
|
401
|
-
--_divider-title-outline-width: var(--sectiondivider-md-title-outline-width);
|
|
402
278
|
--_divider-description-font-family: var(--sectiondivider-md-description-font-family);
|
|
403
279
|
--_divider-description-font-weight: var(--sectiondivider-md-description-font-weight);
|
|
404
280
|
--_divider-description-font-size: var(--sectiondivider-md-description-font-size);
|
|
@@ -420,7 +296,6 @@
|
|
|
420
296
|
--_divider-description: var(--sectiondivider-md-description);
|
|
421
297
|
--_divider-eyebrow: var(--sectiondivider-md-eyebrow);
|
|
422
298
|
--_divider-border: var(--sectiondivider-md-border);
|
|
423
|
-
--_divider-title-outline-color: var(--sectiondivider-md-title-outline-color);
|
|
424
299
|
--_divider-hairline-color: var(--sectiondivider-md-hairline-color);
|
|
425
300
|
--_divider-align: var(--sectiondivider-md-align);
|
|
426
301
|
--_divider-eyebrow-display: var(--sectiondivider-md-eyebrow-display);
|
|
@@ -435,7 +310,6 @@
|
|
|
435
310
|
--_divider-title-font-size: var(--sectiondivider-sm-title-font-size);
|
|
436
311
|
--_divider-title-line-height: var(--sectiondivider-sm-title-line-height);
|
|
437
312
|
--_divider-title-letter-spacing: var(--sectiondivider-sm-title-letter-spacing);
|
|
438
|
-
--_divider-title-outline-width: var(--sectiondivider-sm-title-outline-width);
|
|
439
313
|
--_divider-description-font-family: var(--sectiondivider-sm-description-font-family);
|
|
440
314
|
--_divider-description-font-weight: var(--sectiondivider-sm-description-font-weight);
|
|
441
315
|
--_divider-description-font-size: var(--sectiondivider-sm-description-font-size);
|
|
@@ -457,7 +331,6 @@
|
|
|
457
331
|
--_divider-description: var(--sectiondivider-sm-description);
|
|
458
332
|
--_divider-eyebrow: var(--sectiondivider-sm-eyebrow);
|
|
459
333
|
--_divider-border: var(--sectiondivider-sm-border);
|
|
460
|
-
--_divider-title-outline-color: var(--sectiondivider-sm-title-outline-color);
|
|
461
334
|
--_divider-hairline-color: var(--sectiondivider-sm-hairline-color);
|
|
462
335
|
--_divider-align: var(--sectiondivider-sm-align);
|
|
463
336
|
--_divider-eyebrow-display: var(--sectiondivider-sm-eyebrow-display);
|
|
@@ -535,27 +408,14 @@
|
|
|
535
408
|
var(--sectiondivider-sm-eyebrow-padding-left, var(--sectiondivider-sm-eyebrow-padding, 0));
|
|
536
409
|
}
|
|
537
410
|
|
|
538
|
-
|
|
539
|
-
composite filter. Dilating the alpha treats all glyphs as one combined
|
|
540
|
-
shape, so neighbor-glyph overlaps (CQ, AC etc.) merge into a single
|
|
541
|
-
outline instead of double-stacking. */
|
|
542
|
-
svg.divider-label {
|
|
411
|
+
.divider-label {
|
|
543
412
|
display: block;
|
|
544
|
-
overflow: visible;
|
|
545
413
|
color: var(--_divider-title);
|
|
546
|
-
/* The title is type that happens to be drawn as an SVG, so Sketch mode
|
|
547
|
-
reads it as one glyph and pushes it as far as it pushes a 16px icon.
|
|
548
|
-
At heading size any travel pulls the letters apart, so it stays crisp.
|
|
549
|
-
`none` drops the ink mask along with the displacement. */
|
|
550
|
-
--sketch-icon-off: none;
|
|
551
|
-
}
|
|
552
|
-
svg.divider-label text {
|
|
553
414
|
font-family: var(--_divider-title-font-family);
|
|
554
415
|
font-weight: var(--_divider-title-font-weight);
|
|
555
416
|
font-size: var(--_divider-title-font-size);
|
|
556
417
|
line-height: var(--_divider-title-line-height);
|
|
557
418
|
letter-spacing: var(--_divider-title-letter-spacing);
|
|
558
|
-
fill: currentColor;
|
|
559
419
|
}
|
|
560
420
|
|
|
561
421
|
.title-row {
|
|
@@ -1,284 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Decoupled from the design system: pills, knots, strings, balls, and
|
|
3
|
-
* animations are hardcoded so token edits don't repaint our chrome. The
|
|
4
|
-
* exceptions are intentional and ARE the demo: the central box's
|
|
5
|
-
* surface/radius/border (set inline), the dropdown (rendered through
|
|
6
|
-
* <MenuSelect>), elevation, which reads from the --shadow-* scale, and the
|
|
7
|
-
* zap colour, which tracks --text-accent so the beam stays on-theme.
|
|
8
|
-
* File is global; keep selectors `ftt-` prefixed.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
.ftt-stage {
|
|
12
|
-
--ftt-contrast-color: var(--color-white);
|
|
13
|
-
--ftt-zap-color: var(--text-accent);
|
|
14
|
-
--ftt-string-opacity: 0.5;
|
|
15
|
-
position: relative;
|
|
16
|
-
width: 100%;
|
|
17
|
-
height: 100%;
|
|
18
|
-
/* No overflow clipping: the bottom tag's dropdown must extend past the
|
|
19
|
-
stage edge. */
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/* --- Central box ---------------------------------------------------------- */
|
|
23
|
-
.ftt-box {
|
|
24
|
-
--ftt-box-contrast-color: var(--color-white);
|
|
25
|
-
position: absolute;
|
|
26
|
-
left: 50%;
|
|
27
|
-
top: 50%;
|
|
28
|
-
translate: -50% -50%;
|
|
29
|
-
box-sizing: border-box;
|
|
30
|
-
padding: 0.75rem 1.5rem;
|
|
31
|
-
display: inline-flex;
|
|
32
|
-
width: 12rem;
|
|
33
|
-
align-items: center;
|
|
34
|
-
justify-content: center;
|
|
35
|
-
/* Defaults; overridden inline from the active token bindings. */
|
|
36
|
-
background: color-mix(in srgb, #264542 50%, transparent);
|
|
37
|
-
border-style: solid;
|
|
38
|
-
border-color: #52726e;
|
|
39
|
-
border-width: 2px;
|
|
40
|
-
border-radius: 0.25rem;
|
|
41
|
-
box-shadow: var(--shadow-md);
|
|
42
|
-
transition:
|
|
43
|
-
background 300ms ease,
|
|
44
|
-
border-color 300ms ease,
|
|
45
|
-
border-width 300ms ease,
|
|
46
|
-
border-radius 300ms ease;
|
|
47
|
-
z-index: 1;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
.ftt-box-label {
|
|
51
|
-
font-family: Manrope, system-ui, -apple-system, sans-serif;
|
|
52
|
-
font-size: 1.25rem;
|
|
53
|
-
font-weight: 700;
|
|
54
|
-
color: var(--ftt-box-contrast-color);
|
|
55
|
-
white-space: nowrap;
|
|
56
|
-
user-select: none;
|
|
57
|
-
pointer-events: none;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
.ftt-box.ftt-bloop {
|
|
61
|
-
animation: ftt-bloop 480ms ease-out;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
@keyframes ftt-bloop {
|
|
65
|
-
0% { scale: 1; filter: brightness(1); }
|
|
66
|
-
30% { scale: 1.08; filter: brightness(1.8) saturate(1.4); }
|
|
67
|
-
100% { scale: 1; filter: brightness(1); }
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/* --- Kite strings --------------------------------------------------------- */
|
|
71
|
-
.ftt-strings {
|
|
72
|
-
position: absolute;
|
|
73
|
-
inset: 0;
|
|
74
|
-
width: 100%;
|
|
75
|
-
height: 100%;
|
|
76
|
-
pointer-events: none;
|
|
77
|
-
z-index: 2;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
.ftt-string {
|
|
81
|
-
stroke: var(--ftt-contrast-color);
|
|
82
|
-
stroke-width: 2;
|
|
83
|
-
stroke-linecap: round;
|
|
84
|
-
vector-effect: non-scaling-stroke;
|
|
85
|
-
opacity: var(--ftt-string-opacity);
|
|
86
|
-
transition: opacity 150ms ease, stroke 150ms ease;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
.ftt-string.ftt-live {
|
|
90
|
-
stroke: var(--ftt-zap-color);
|
|
91
|
-
opacity: 1;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/* --- Anchor knots --------------------------------------------------------- */
|
|
95
|
-
.ftt-knot {
|
|
96
|
-
position: absolute;
|
|
97
|
-
width: 0.625rem;
|
|
98
|
-
height: 0.625rem;
|
|
99
|
-
translate: -50% -50%;
|
|
100
|
-
border-radius: 9999px;
|
|
101
|
-
background: #c4bcb6;
|
|
102
|
-
border: 1px solid #f0eae4;
|
|
103
|
-
pointer-events: none;
|
|
104
|
-
z-index: 3;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/* --- Energy ball ---------------------------------------------------------- */
|
|
108
|
-
/* Shares --ftt-zap-color with `.ftt-string.ftt-live` so the beam reads as a
|
|
109
|
-
continuous trail, not a colour-shifting projectile. */
|
|
110
|
-
.ftt-energy-ball {
|
|
111
|
-
position: absolute;
|
|
112
|
-
width: 0.875rem;
|
|
113
|
-
height: 0.875rem;
|
|
114
|
-
translate: -50% -50%;
|
|
115
|
-
border-radius: 9999px;
|
|
116
|
-
background: var(--ftt-zap-color);
|
|
117
|
-
box-shadow:
|
|
118
|
-
0 0 8px 2px var(--ftt-zap-color),
|
|
119
|
-
0 0 18px 4px var(--ftt-zap-color);
|
|
120
|
-
pointer-events: none;
|
|
121
|
-
opacity: 0;
|
|
122
|
-
z-index: 6;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/* --- Floating tag wrapper ------------------------------------------------- */
|
|
126
|
-
.ftt-float {
|
|
127
|
-
position: absolute;
|
|
128
|
-
translate: -50% -50%;
|
|
129
|
-
rotate: var(--ftt-rot, 0deg);
|
|
130
|
-
animation: ftt-bob var(--ftt-bob-duration, 7s) ease-in-out infinite;
|
|
131
|
-
z-index: 4;
|
|
132
|
-
pointer-events: none;
|
|
133
|
-
display: flex;
|
|
134
|
-
flex-direction: column;
|
|
135
|
-
align-items: center;
|
|
136
|
-
gap: 0.25rem;
|
|
137
|
-
width: 14rem;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/* Lift open tag so its dropdown paints over sibling tags. */
|
|
141
|
-
.ftt-float.ftt-open {
|
|
142
|
-
z-index: 20;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/* Bottom-placement chips mirror the top arc: chip first, eyebrow on the
|
|
146
|
-
outer (lower) side. Dropdown opens upward toward the box so the menu
|
|
147
|
-
doesn't fall off the stage. */
|
|
148
|
-
.ftt-float[data-placement="bottom"] {
|
|
149
|
-
flex-direction: column-reverse;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/* Pivot the tilt around the chip's right semicircular cap. The chip is
|
|
153
|
-
~1.84rem tall so the cap center sits ~0.9rem from the chip's right edge
|
|
154
|
-
and ~0.9rem above its bottom — which (since the chip is the widest, last
|
|
155
|
-
in-flow element of the wrapper) coincides with `calc(100% - 0.9rem)` on
|
|
156
|
-
both axes of the wrapper. */
|
|
157
|
-
.ftt-float[data-pivot="right-cap"] {
|
|
158
|
-
transform-origin: calc(100% - 0.9rem) calc(100% - 0.9rem);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
@keyframes ftt-bob {
|
|
162
|
-
0%, 100% { translate: -50% -50%; }
|
|
163
|
-
50% { translate: -50% calc(-50% + var(--ftt-bob-distance, -8px)); }
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/* --- Property label paired with each tag ---------------------------------- */
|
|
167
|
-
/* Sits on the outer side of the chip: above for top-placement chips, below
|
|
168
|
-
for bottom-placement chips (see `.ftt-float[data-placement="bottom"]`). */
|
|
169
|
-
.ftt-float-property {
|
|
170
|
-
font-family: Manrope, system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
|
|
171
|
-
font-size: 0.875rem;
|
|
172
|
-
font-weight: 700;
|
|
173
|
-
color: var(--text-secondary);
|
|
174
|
-
white-space: nowrap;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/* --- Tag pill ------------------------------------------------------------- */
|
|
178
|
-
/* Hardcoded (not the Badge component) so badge-* token edits don't repaint. */
|
|
179
|
-
.ftt-tag {
|
|
180
|
-
display: inline-flex;
|
|
181
|
-
align-items: center;
|
|
182
|
-
gap: 0.25rem;
|
|
183
|
-
padding: 0.375rem 0.75rem;
|
|
184
|
-
/* Polished chrome, not brushed steel: the bands keep their spacing but sit
|
|
185
|
-
high in the scale, so the pill stays bright against a cream page. Keep
|
|
186
|
-
the darkest stop ≥ #8f9090 or the black label loses AA. */
|
|
187
|
-
background: linear-gradient(
|
|
188
|
-
135deg,
|
|
189
|
-
#fbfbfb 0%,
|
|
190
|
-
#c9cbcb 38%,
|
|
191
|
-
#eff0f0 62%,
|
|
192
|
-
#b6b8b8 100%
|
|
193
|
-
);
|
|
194
|
-
color: #000;
|
|
195
|
-
border: 1px solid rgba(86, 96, 104, 0.45);
|
|
196
|
-
border-radius: 9999px;
|
|
197
|
-
box-shadow: var(--shadow-md);
|
|
198
|
-
font-family: Manrope, system-ui, -apple-system, sans-serif;
|
|
199
|
-
font-size: 0.875rem;
|
|
200
|
-
font-weight: 600;
|
|
201
|
-
line-height: 1.1;
|
|
202
|
-
white-space: nowrap;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
.ftt-tag-icon {
|
|
206
|
-
display: inline-flex;
|
|
207
|
-
align-items: center;
|
|
208
|
-
font-size: 0.875em;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
.ftt-tag-label {
|
|
212
|
-
display: inline-block;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/* --- Tag trigger (draggable button wrapping the pill) --------------------- */
|
|
216
|
-
.ftt-tag-trigger {
|
|
217
|
-
pointer-events: auto;
|
|
218
|
-
background: transparent;
|
|
219
|
-
border: none;
|
|
220
|
-
padding: 0;
|
|
221
|
-
margin: 0;
|
|
222
|
-
cursor: grab;
|
|
223
|
-
touch-action: none;
|
|
224
|
-
transition: filter 150ms ease, scale 150ms ease;
|
|
225
|
-
}
|
|
226
|
-
.ftt-tag-trigger:hover {
|
|
227
|
-
filter: brightness(1.2);
|
|
228
|
-
scale: 1.04;
|
|
229
|
-
}
|
|
230
|
-
.ftt-float.ftt-dragging .ftt-tag-trigger {
|
|
231
|
-
cursor: grabbing;
|
|
232
|
-
}
|
|
233
|
-
.ftt-float.ftt-dragging {
|
|
234
|
-
animation: none; /* pause bob while dragging */
|
|
235
|
-
z-index: 30;
|
|
236
|
-
}
|
|
237
|
-
.ftt-tag-trigger:focus-visible {
|
|
238
|
-
outline: 2px solid var(--ftt-zap-color);
|
|
239
|
-
outline-offset: 3px;
|
|
240
|
-
border-radius: 9999px;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
.ftt-float.ftt-flash .ftt-tag-trigger {
|
|
244
|
-
animation: ftt-tag-flash 500ms ease-out;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
@keyframes ftt-tag-flash {
|
|
248
|
-
0% { scale: 1; filter: brightness(1) drop-shadow(0 0 0 transparent); }
|
|
249
|
-
25% { scale: 1.14; filter: brightness(1.8) drop-shadow(0 0 14px #fff5f0); }
|
|
250
|
-
100% { scale: 1; filter: brightness(1) drop-shadow(0 0 0 transparent); }
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
/* --- Chip host ------------------------------------------------------------ */
|
|
254
|
-
/* Wraps the chip-trigger and (when open) the dropdown so the dropdown can
|
|
255
|
-
anchor directly to the chip's edges, not the float wrapper's. Without
|
|
256
|
-
this, `top: 100%` lands at the wrapper bottom — which is the eyebrow for
|
|
257
|
-
`data-placement="bottom"` — and the menu drifts off the chip. */
|
|
258
|
-
.ftt-chip-host {
|
|
259
|
-
position: relative;
|
|
260
|
-
display: inline-flex;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/* --- Dropdown menu -------------------------------------------------------- */
|
|
264
|
-
/* The wrap handles position/stacking only; the surface lives on
|
|
265
|
-
<MenuSelect> so menuselect-* token edits reshape the in-flight UI. */
|
|
266
|
-
.ftt-dropdown-wrap {
|
|
267
|
-
position: absolute;
|
|
268
|
-
top: calc(100% + 0.25rem);
|
|
269
|
-
left: 50%;
|
|
270
|
-
translate: -50% 0;
|
|
271
|
-
pointer-events: auto;
|
|
272
|
-
z-index: 10;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/* --- Reduced motion ------------------------------------------------------- */
|
|
276
|
-
@media (prefers-reduced-motion: reduce) {
|
|
277
|
-
.ftt-float {
|
|
278
|
-
animation: none;
|
|
279
|
-
}
|
|
280
|
-
.ftt-box.ftt-bloop,
|
|
281
|
-
.ftt-float.ftt-flash .ftt-tag-trigger {
|
|
282
|
-
animation: none;
|
|
283
|
-
}
|
|
284
|
-
}
|