@motion-proto/live-tokens 0.47.0 → 0.48.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 (124) hide show
  1. package/.claude/skills/live-tokens-adjust-shape-space/SKILL.md +68 -0
  2. package/.claude/skills/live-tokens-create-component/SKILL.md +2 -2
  3. package/.claude/skills/live-tokens-generate-theme/SKILL.md +152 -0
  4. package/CHANGELOG.md +292 -0
  5. package/README.md +37 -26
  6. package/bin/adjust.mjs +254 -0
  7. package/bin/cli.mjs +94 -7
  8. package/bin/generate-theme.mjs +251 -0
  9. package/bin/migrate.mjs +95 -6
  10. package/dist-plugin/adjust/index.cjs +259 -0
  11. package/dist-plugin/adjust/index.d.cts +45 -0
  12. package/dist-plugin/adjust/index.d.ts +45 -0
  13. package/dist-plugin/adjust/index.js +176 -0
  14. package/dist-plugin/{chunk-H4TRUINI.js → chunk-44RSTAII.js} +0 -48
  15. package/dist-plugin/chunk-6OZFXIQI.js +316 -0
  16. package/dist-plugin/chunk-76TFDTJO.js +556 -0
  17. package/dist-plugin/chunk-D3ZVKOR4.js +52 -0
  18. package/dist-plugin/dataPaths-DBN0RPuT.d.cts +54 -0
  19. package/dist-plugin/dataPaths-DBN0RPuT.d.ts +54 -0
  20. package/dist-plugin/generateColorsAndType/index.cjs +1781 -0
  21. package/dist-plugin/generateColorsAndType/index.d.cts +81 -0
  22. package/dist-plugin/generateColorsAndType/index.d.ts +81 -0
  23. package/dist-plugin/generateColorsAndType/index.js +1210 -0
  24. package/dist-plugin/index.cjs +901 -533
  25. package/dist-plugin/index.d.cts +3 -2
  26. package/dist-plugin/index.d.ts +3 -2
  27. package/dist-plugin/index.js +658 -1082
  28. package/dist-plugin/migrateData/index.cjs +728 -0
  29. package/dist-plugin/migrateData/index.d.cts +60 -0
  30. package/dist-plugin/migrateData/index.d.ts +60 -0
  31. package/dist-plugin/migrateData/index.js +348 -0
  32. package/dist-plugin/themeTypes-DMHZOnUn.d.cts +211 -0
  33. package/dist-plugin/themeTypes-DMHZOnUn.d.ts +211 -0
  34. package/dist-plugin/tokensCssMigrations/index.cjs +2 -1
  35. package/dist-plugin/tokensCssMigrations/index.d.cts +3 -15
  36. package/dist-plugin/tokensCssMigrations/index.d.ts +3 -15
  37. package/dist-plugin/tokensCssMigrations/index.js +4 -2
  38. package/package.json +18 -4
  39. package/src/editor/component-editor/scaffolding/ComponentFileManager.svelte +183 -158
  40. package/src/editor/component-editor/scaffolding/ComponentFileMenu.svelte +0 -4
  41. package/src/editor/component-editor/scaffolding/SaveAsDialog.svelte +4 -4
  42. package/src/editor/component-editor/scaffolding/TokenLayout.svelte +2 -59
  43. package/src/editor/component-editor/scaffolding/VariantGroup.svelte +1 -1
  44. package/src/editor/core/components/adjustAliases.ts +180 -0
  45. package/src/editor/core/components/aliasKinds.ts +73 -0
  46. package/src/editor/core/components/componentConfigService.ts +26 -38
  47. package/src/editor/core/flashStatus.ts +1 -1
  48. package/src/editor/core/fonts/fontMigration.ts +13 -13
  49. package/src/editor/core/fonts/fontPairing.ts +35 -0
  50. package/src/editor/core/palettes/paletteDerivation.ts +128 -16
  51. package/src/editor/core/preview/lookPreview.ts +141 -0
  52. package/src/editor/core/productionPulse.ts +34 -21
  53. package/src/editor/core/storage/files/versionedFileResourceClient.ts +18 -45
  54. package/src/editor/core/store/editorConfigStore.ts +2 -2
  55. package/src/editor/core/store/editorPersistence.ts +0 -1
  56. package/src/editor/core/store/editorStore.ts +114 -51
  57. package/src/editor/core/store/editorTypes.ts +0 -1
  58. package/src/editor/core/store/gradientSource.ts +2 -2
  59. package/src/editor/core/themes/colorsAndTypeService.ts +95 -0
  60. package/src/editor/core/themes/generateColorsAndType.ts +433 -0
  61. package/src/editor/core/themes/loadRows.ts +64 -0
  62. package/src/editor/core/themes/lookSummary.ts +75 -0
  63. package/src/editor/core/themes/migrations/2026-04-24-legacy-keys-and-bg-to-canvas.ts +3 -3
  64. package/src/editor/core/themes/migrations/2026-05-13-primary-to-brand.ts +2 -2
  65. package/src/editor/core/themes/migrations/2026-05-26-drop-overlay-extra-stops.ts +3 -3
  66. package/src/editor/core/themes/migrations/2026-08-13-drop-legacy-shape-space-keys.ts +38 -0
  67. package/src/editor/core/themes/migrations/2026-08-15-line-height-scale-rename.ts +57 -0
  68. package/src/editor/core/themes/migrations/index.ts +19 -11
  69. package/src/editor/core/themes/slices/components.ts +4 -4
  70. package/src/editor/core/themes/slices/fonts.ts +1 -1
  71. package/src/editor/core/themes/slices/gradients.ts +22 -0
  72. package/src/editor/core/themes/slices/palettes.ts +2 -2
  73. package/src/editor/core/themes/themeInit.ts +21 -29
  74. package/src/editor/core/themes/themeService.ts +218 -78
  75. package/src/editor/core/themes/themeTypes.ts +94 -51
  76. package/src/editor/docs/Docs.svelte +1 -0
  77. package/src/editor/docs/chapters.ts +1 -0
  78. package/src/editor/docs/content/01-overview.md +1 -1
  79. package/src/editor/docs/content/editing-tokens.md +6 -6
  80. package/src/editor/docs/content/getting-started.md +9 -7
  81. package/src/editor/docs/content/themes-workflow.md +74 -34
  82. package/src/editor/docs/content/where-themes-live.md +61 -0
  83. package/src/editor/docs/content.generated.ts +5 -4
  84. package/src/editor/index.ts +27 -27
  85. package/src/editor/pages/ComponentEditorPage.svelte +2 -2
  86. package/src/editor/pages/EditorShell.svelte +4 -30
  87. package/src/editor/ui/BezierCurveEditor.svelte +2 -2
  88. package/src/editor/ui/ColorEditPanel.svelte +1 -1
  89. package/src/editor/ui/FileLoadList.svelte +67 -7
  90. package/src/editor/ui/GradientEditor.svelte +3 -3
  91. package/src/editor/ui/PaletteEditor.svelte +26 -12
  92. package/src/editor/ui/ThemePanel.svelte +1067 -0
  93. package/src/editor/ui/UIDialog.svelte +11 -9
  94. package/src/editor/ui/UIPillButton.svelte +7 -2
  95. package/src/editor/ui/colors/ColorWheel.svelte +34 -1
  96. package/src/editor/ui/curveEngine.ts +48 -0
  97. package/src/editor/ui/index.ts +4 -2
  98. package/src/editor/ui/palette/PaletteBase.svelte +75 -51
  99. package/src/editor/ui/palette/PaletteJumpButton.svelte +3 -8
  100. package/src/live-tokens/data/colors-and-type/autumn.json +2490 -0
  101. package/src/live-tokens/data/{themes → colors-and-type}/default.json +816 -293
  102. package/src/live-tokens/data/colors-and-type/halloween.json +2529 -0
  103. package/src/live-tokens/data/colors-and-type/midnight-study.json +2536 -0
  104. package/src/live-tokens/data/colors-and-type/ocean.json +2489 -0
  105. package/src/live-tokens/data/colors-and-type/royal-velvet.json +2520 -0
  106. package/src/live-tokens/data/colors-and-type/spring-meadow.json +2476 -0
  107. package/src/live-tokens/data/colors-and-type/sunset.json +2528 -0
  108. package/src/live-tokens/data/themes/autumn.json +3918 -0
  109. package/src/live-tokens/data/themes/halloween.json +3992 -0
  110. package/src/live-tokens/data/themes/midnight-study.json +3932 -0
  111. package/src/live-tokens/data/themes/ocean.json +3917 -0
  112. package/src/live-tokens/data/themes/royal-velvet.json +3983 -0
  113. package/src/live-tokens/data/themes/spring-meadow.json +3904 -0
  114. package/src/live-tokens/data/themes/sunset.json +3931 -0
  115. package/src/live-tokens/data/tokens.generated.css +106 -117
  116. package/src/system/styles/CONVENTIONS.md +1 -1
  117. package/src/system/styles/fonts.css +1 -1
  118. package/template/README.md +7 -5
  119. package/template/_gitignore +0 -6
  120. package/src/editor/core/components/componentPersist.ts +0 -62
  121. package/src/editor/core/manifests/manifestService.ts +0 -172
  122. package/src/editor/ui/ManifestFileManager.svelte +0 -446
  123. package/src/editor/ui/ThemeFileManager.svelte +0 -785
  124. package/src/live-tokens/data/manifests/default.json +0 -35
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import { run, self } from 'svelte/legacy';
2
+ import { self } from 'svelte/legacy';
3
3
 
4
4
  import { tick } from 'svelte';
5
5
 
@@ -31,14 +31,16 @@
31
31
  let cancelButtonRef: HTMLButtonElement | undefined = $state();
32
32
  let confirmButtonRef: HTMLButtonElement | undefined = $state();
33
33
 
34
- run(() => {
35
- if (show) {
36
- tick().then(() => {
37
- if (confirmLabel && confirmButtonRef) confirmButtonRef.focus();
38
- else if (showCancel && cancelButtonRef) cancelButtonRef.focus();
39
- else if (closeButtonRef) closeButtonRef.focus();
40
- });
41
- }
34
+ // Depends on `show` alone: the footer can gain or lose its confirm button
35
+ // while the dialog is open (theme preview), and pulling focus out of the
36
+ // body each time that happens would fight whatever the user is doing.
37
+ $effect(() => {
38
+ if (!show) return;
39
+ tick().then(() => {
40
+ if (confirmLabel && confirmButtonRef) confirmButtonRef.focus();
41
+ else if (showCancel && cancelButtonRef) cancelButtonRef.focus();
42
+ else if (closeButtonRef) closeButtonRef.focus();
43
+ });
42
44
  });
43
45
 
44
46
  function handleClose() {
@@ -60,6 +60,7 @@
60
60
 
61
61
  <style>
62
62
  .ui-pill {
63
+ box-sizing: border-box;
63
64
  display: inline-flex;
64
65
  align-items: center;
65
66
  gap: var(--ui-space-6, 6px);
@@ -175,9 +176,13 @@
175
176
  border-color: rgba(255, 255, 255, 0.18);
176
177
  }
177
178
 
178
- /* Size: compact — for header bars / chrome rails */
179
+ /* Size: compact — for header bars / chrome rails. The min-height, not the
180
+ padding, sets the height: a pill carrying an icon has a taller line box than
181
+ one with only a label, and equal padding would leave them different heights
182
+ in the same row. The slack also clears glyphs that draw past their em box. */
179
183
  .ui-pill-compact {
180
184
  font-size: var(--ui-font-size-sm, 14px);
181
- padding: var(--ui-space-2, 2px) var(--ui-space-12, 12px);
185
+ padding: var(--ui-space-4, 4px) var(--ui-space-12, 12px);
186
+ min-height: 1.75rem;
182
187
  }
183
188
  </style>
@@ -62,6 +62,8 @@
62
62
  const EXT_OFFSET = 20; // external handle radius beyond the disc rim (room for the dotted tether)
63
63
  const NUM_OFFSET = 24; // numeral radius beyond the external handles
64
64
  const FREE_NUM_OFFSET = 15; // free-dot numeral, diagonal clearance past the enlarged dot
65
+ const NUM_PERP = 20; // sideways clearance for a numeral moved beside its own marker
66
+ const NUM_STACK = 20; // radial gap between the numerals of co-hued unbound axes
65
67
  const MIN_SIZE = 240;
66
68
  const MAX_SIZE = 560;
67
69
 
@@ -128,6 +130,7 @@
128
130
  return {
129
131
  ...t,
130
132
  hue,
133
+ dotR,
131
134
  selected: t.bound && selected === t.family,
132
135
  dot: { x: center + dotR * Math.cos(rad(hue)), y: center - dotR * Math.sin(rad(hue)) },
133
136
  ext: { x: center + extRadius * Math.cos(rad(hue)), y: center - extRadius * Math.sin(rad(hue)) },
@@ -141,7 +144,37 @@
141
144
  }),
142
145
  );
143
146
 
144
- let visibleRender = $derived(axisRender.filter(isVisible));
147
+ // Monochromatic stacks every axis on one hue (custom does too, once the hues
148
+ // are dragged together), so the outer numeral slot is the same point for all
149
+ // of them. Each numeral then moves beside the marker it names — its own dot,
150
+ // or the external handle when the axis carries no color — which is the only
151
+ // thing that still tells the axes apart on a shared rail.
152
+ let visibleRender = $derived.by(() => {
153
+ const vis = axisRender.filter(isVisible);
154
+ const hueKey = (hue: number) => Math.round(normDeg(hue)) % 360;
155
+ const byHue = new Map<number, typeof vis>();
156
+ for (const t of vis) {
157
+ const group = byHue.get(hueKey(t.hue));
158
+ if (group) group.push(t);
159
+ else byHue.set(hueKey(t.hue), [t]);
160
+ }
161
+ return vis.map((t) => {
162
+ const group = byHue.get(hueKey(t.hue))!;
163
+ if (group.length < 2) return t;
164
+ // Bound axes separate by chroma radius on their own; unbound ones share the
165
+ // handle track, so they step outward past it instead.
166
+ const unboundBefore = group.slice(0, group.indexOf(t)).filter((g) => !g.bound).length;
167
+ const r = t.bound ? t.dotR : extRadius + unboundBefore * NUM_STACK;
168
+ const a = rad(t.hue);
169
+ return {
170
+ ...t,
171
+ num: {
172
+ x: center + r * Math.cos(a) - NUM_PERP * Math.sin(a),
173
+ y: center - r * Math.sin(a) - NUM_PERP * Math.cos(a),
174
+ },
175
+ };
176
+ });
177
+ });
145
178
 
146
179
  // Free dot for a selected family on no ACTIVE axis (Neutral, Alternate, …,
147
180
  // plus families whose axis the applied geometry deals no distinct slot): a 2D
@@ -97,6 +97,54 @@ export function makeAnchor(x: number, y: number, tangentLen = 15): CurveAnchor {
97
97
  return { x, y, inDx: -tangentLen, inDy: 0, outDx: tangentLen, outDy: 0 };
98
98
  }
99
99
 
100
+ /** Share of a segment's x-span a tangent handle reaches across. At a third the
101
+ * cubic is the exact Hermite form of the slope, so the handle length carries no
102
+ * shape of its own, and the two facing handles can never cross. */
103
+ const HANDLE_SPAN = 1 / 3;
104
+
105
+ /**
106
+ * Slope to carry through (x, y), given whichever neighbours it has.
107
+ *
108
+ * The weighted harmonic mean of the two secants (Fritsch–Carlson): it always
109
+ * lands between them, so the segment cannot overshoot its own endpoints. The
110
+ * plain average (Catmull-Rom) can overshoot when the gaps differ, and on a
111
+ * lightness ramp an overshoot puts a step out of order with its neighbours,
112
+ * which is the one thing a ramp must not do.
113
+ */
114
+ function tangentSlope(
115
+ prev: CurveAnchor | null,
116
+ x: number,
117
+ y: number,
118
+ next: CurveAnchor | null,
119
+ ): number {
120
+ const hPrev = prev ? x - prev.x : 0;
121
+ const hNext = next ? next.x - x : 0;
122
+ const dPrev = hPrev > 0 ? (y - prev!.y) / hPrev : null;
123
+ const dNext = hNext > 0 ? (next!.y - y) / hNext : null;
124
+ if (dPrev === null) return dNext ?? 0;
125
+ if (dNext === null) return dPrev;
126
+ // Secants disagreeing in sign make this a turning point, where flat is the
127
+ // true slope rather than a failure to find one.
128
+ if (dPrev * dNext <= 0) return 0;
129
+ const wPrev = 2 * hNext + hPrev;
130
+ const wNext = hNext + 2 * hPrev;
131
+ return (wPrev + wNext) / (wPrev / dPrev + wNext / dNext);
132
+ }
133
+
134
+ /** An anchor at (x, y) whose handles lie along the local slope, so dropping it
135
+ * onto a run bends the line rather than flattening it. */
136
+ export function tangentAnchor(
137
+ x: number,
138
+ y: number,
139
+ prev: CurveAnchor | null,
140
+ next: CurveAnchor | null,
141
+ ): CurveAnchor {
142
+ const m = tangentSlope(prev, x, y, next);
143
+ const inDx = prev ? -(x - prev.x) * HANDLE_SPAN : 0;
144
+ const outDx = next ? (next.x - x) * HANDLE_SPAN : 0;
145
+ return { x, y, inDx, inDy: m * inDx, outDx, outDy: m * outDx };
146
+ }
147
+
100
148
  export function isCornerAnchor(a: CurveAnchor): boolean {
101
149
  return a.inDx === 0 && a.inDy === 0 && a.outDx === 0 && a.outDy === 0;
102
150
  }
@@ -26,5 +26,7 @@ export { default as BezierCurveEditor } from './BezierCurveEditor.svelte';
26
26
  export { default as FontStackEditor } from './FontStackEditor.svelte';
27
27
  export { default as ProjectFontsSection } from './ProjectFontsSection.svelte';
28
28
 
29
- // Theme persistence UI
30
- export { default as ThemeFileManager } from './ThemeFileManager.svelte';
29
+ // Theme persistence UI. `ThemeFileManager` was the layer manager; the panel is
30
+ // what carries that role now, and the alias keeps the public import working.
31
+ export { default as ThemePanel } from './ThemePanel.svelte';
32
+ export { default as ThemeFileManager } from './ThemePanel.svelte';
@@ -1,7 +1,6 @@
1
1
  <script lang="ts">
2
2
  import ColorEditPanel from '../ColorEditPanel.svelte';
3
3
  import Toggle from '../Toggle.svelte';
4
- import PaletteJumpButton from './PaletteJumpButton.svelte';
5
4
  import { beginSliderGesture } from '../../core/store/editorStore';
6
5
  import { oklchToHexClamped, type Oklch } from '../../core/palettes/oklch';
7
6
 
@@ -85,46 +84,58 @@
85
84
  onkeydown={(e) => e.key === 'Enter' && onStartEdit()}
86
85
  ></div>
87
86
  <div class="primary-info">
88
- <div class="label-row">
89
- <span class="editor-label">{displayLabel ?? label}</span>
90
- <PaletteJumpButton family={label} {displayLabel} target="wheel" />
91
- </div>
87
+ <span class="editor-label">{displayLabel ?? label}</span>
92
88
  <button
93
- class="base-hex clickable-hex"
89
+ class="base-hex"
90
+ class:copied={copiedKey === '__base__'}
94
91
  type="button"
92
+ title="Copy {baseHex}"
95
93
  onclick={(e) => onCopyBaseHex('__base__', baseHex, e)}
96
- >{copiedKey === '__base__' ? 'copied!' : baseHex}</button>
94
+ >
95
+ <span class="hex-value">{baseHex}</span>
96
+ <i
97
+ class="fas"
98
+ class:fa-copy={copiedKey !== '__base__'}
99
+ class:fa-check={copiedKey === '__base__'}
100
+ aria-hidden="true"
101
+ ></i>
102
+ </button>
97
103
  </div>
98
104
  </div>
99
- </div>
100
105
 
101
- {#if pinnedOpen || (isEditingBase && panelOpen && editingColor)}
102
- <ColorEditPanel
103
- title={isEditingBase ? editPanelTitle : 'Base Color'}
104
- showRemoveOverride={false}
105
- hideActions={!isEditingBase}
106
- hue={baseOklch.h}
107
- chroma={baseOklch.c}
108
- lightness={baseOklch.l * 100}
109
- chromaMax={CHROMA_MAX}
110
- chromaHint={pickerChromaHint}
111
- onHueChromaChange={onBaseChange}
112
- onConfirm={onConfirm}
113
- onCancel={onCancel}
114
- onRemoveOverride={() => {}}
115
- onSliderStart={() => beginSliderGesture(`edit ${label} base`)}
116
- >
117
- {#snippet actions()}
118
- <Toggle
119
- checked={anchorToBase}
120
- onchange={(v) => onAnchorToBaseChange(v ?? !anchorToBase)}
121
- label={anchorStepLabel ? `Base color placed at ${anchorStepLabel}` : 'Place base color in palette'}
122
- />
123
- {/snippet}
124
- </ColorEditPanel>
125
- {/if}
106
+ {#if pinnedOpen || (isEditingBase && panelOpen && editingColor)}
107
+ <div class="editor-controls">
108
+ <ColorEditPanel
109
+ title={isEditingBase ? editPanelTitle : 'Base Color'}
110
+ showRemoveOverride={false}
111
+ hideActions={!isEditingBase}
112
+ hidePreview
113
+ hue={baseOklch.h}
114
+ chroma={baseOklch.c}
115
+ lightness={baseOklch.l * 100}
116
+ chromaMax={CHROMA_MAX}
117
+ chromaHint={pickerChromaHint}
118
+ onHueChromaChange={onBaseChange}
119
+ onConfirm={onConfirm}
120
+ onCancel={onCancel}
121
+ onRemoveOverride={() => {}}
122
+ onSliderStart={() => beginSliderGesture(`edit ${label} base`)}
123
+ >
124
+ {#snippet actions()}
125
+ <Toggle
126
+ checked={anchorToBase}
127
+ onchange={(v) => onAnchorToBaseChange(v ?? !anchorToBase)}
128
+ label={anchorStepLabel ? `Base color placed at ${anchorStepLabel}` : 'Place base color in palette'}
129
+ />
130
+ {/snippet}
131
+ </ColorEditPanel>
132
+ </div>
133
+ {/if}
134
+ </div>
126
135
 
127
136
  <style>
137
+ /* Identity and controls read as one band: the sliders sit beside the swatch
138
+ rather than under it, which is what leaves the palette below its height. */
128
139
  .editor-top {
129
140
  display: flex;
130
141
  align-items: flex-start;
@@ -134,7 +145,7 @@
134
145
 
135
146
  .editor-primary {
136
147
  display: flex;
137
- align-items: center;
148
+ align-items: stretch;
138
149
  gap: var(--ui-space-12);
139
150
  flex-shrink: 0;
140
151
  }
@@ -142,19 +153,20 @@
142
153
  .primary-info {
143
154
  display: flex;
144
155
  flex-direction: column;
156
+ align-items: flex-start;
145
157
  gap: var(--ui-space-2);
146
158
  }
147
159
 
148
- .label-row {
149
- display: flex;
150
- align-items: center;
151
- gap: var(--ui-space-10);
160
+ /* Basis, not width: the panel takes the rest of the row and drops below only
161
+ when it can't hold that much. */
162
+ .editor-controls {
163
+ flex: 1 1 26rem;
164
+ min-width: 0;
152
165
  }
153
166
 
154
-
155
167
  .header-swatch {
156
- width: 4rem;
157
- height: 4rem;
168
+ width: 4.5rem;
169
+ min-height: 4.5rem;
158
170
  border-radius: var(--ui-radius-md);
159
171
  border: 2px solid var(--ui-border);
160
172
  flex-shrink: 0;
@@ -178,13 +190,9 @@
178
190
  }
179
191
 
180
192
  .base-hex {
181
- font-size: var(--ui-font-size-md);
182
- color: var(--ui-text-secondary);
183
- font-family: var(--ui-font-mono);
184
- }
185
-
186
- .clickable-hex {
187
- align-self: flex-start;
193
+ display: inline-flex;
194
+ align-items: center;
195
+ gap: var(--ui-space-6);
188
196
  background: none;
189
197
  border: none;
190
198
  cursor: pointer;
@@ -197,15 +205,31 @@
197
205
  text-align: left;
198
206
  }
199
207
 
200
- .clickable-hex:hover {
208
+ /* The glyph only announces itself on approach; the hex is the content. */
209
+ .base-hex i {
210
+ font-size: var(--ui-font-size-xs);
211
+ color: var(--ui-text-muted);
212
+ transition: color var(--ui-transition-fast);
213
+ }
214
+
215
+ .base-hex:hover {
201
216
  background: var(--ui-surface-highest);
202
217
  color: var(--ui-text-primary);
203
218
  }
204
219
 
220
+ .base-hex:hover i {
221
+ color: var(--ui-text-secondary);
222
+ }
223
+
224
+ .base-hex.copied,
225
+ .base-hex.copied i {
226
+ color: var(--ui-text-accent);
227
+ }
228
+
205
229
  @media (max-width: 1280px) {
206
230
  .header-swatch {
207
- width: 3rem;
208
- height: 3rem;
231
+ width: 3.5rem;
232
+ min-height: 3.5rem;
209
233
  }
210
234
  }
211
235
  </style>
@@ -35,15 +35,10 @@
35
35
  display: inline-flex;
36
36
  }
37
37
 
38
- /* fa-palette loses its bowl at the pill's default icon size. The compact
39
- pill's line box is shorter than the glyph draws, so the padding grows with
40
- it rather than letting it cross the border. */
41
- .palette-jump :global(.ui-pill) {
42
- padding-block: var(--ui-space-6);
43
- }
44
-
38
+ /* fa-palette loses its bowl at the pill's default icon size; the compact
39
+ pill's min-height carries the taller glyph without changing the pill's
40
+ height, so it still lines up with the plain pills beside it. */
45
41
  .palette-jump :global(.ui-pill i) {
46
42
  font-size: var(--ui-font-size-md);
47
- line-height: 1.2;
48
43
  }
49
44
  </style>