@motion-proto/live-tokens 0.7.1 → 0.9.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 (96) hide show
  1. package/.claude/skills/live-tokens-add-component/SKILL.md +488 -0
  2. package/README.md +34 -0
  3. package/dist-plugin/index.cjs +707 -90
  4. package/dist-plugin/index.d.cts +1 -0
  5. package/dist-plugin/index.d.ts +1 -0
  6. package/dist-plugin/index.js +707 -90
  7. package/package.json +6 -2
  8. package/src/app/site.css +1 -1
  9. package/src/editor/component-editor/CollapsibleSectionEditor.svelte +34 -27
  10. package/src/editor/component-editor/DialogEditor.svelte +4 -4
  11. package/src/editor/component-editor/NotificationEditor.svelte +3 -1
  12. package/src/editor/component-editor/SectionDividerEditor.svelte +439 -112
  13. package/src/editor/component-editor/StandardButtonsEditor.svelte +13 -1
  14. package/src/editor/component-editor/editors.d.ts +10 -0
  15. package/src/editor/component-editor/index.ts +16 -1
  16. package/src/editor/component-editor/registry.ts +103 -26
  17. package/src/editor/component-editor/scaffolding/AngleDial.svelte +52 -13
  18. package/src/editor/component-editor/scaffolding/ComponentFileManager.svelte +10 -11
  19. package/src/editor/component-editor/scaffolding/ComponentsTab.svelte +2 -2
  20. package/src/editor/component-editor/scaffolding/LinkedBlock.svelte +0 -1
  21. package/src/editor/component-editor/scaffolding/RadialShapePad.svelte +483 -0
  22. package/src/editor/component-editor/scaffolding/ShadowBackdrop.svelte +15 -2
  23. package/src/editor/component-editor/scaffolding/StateBlock.svelte +103 -15
  24. package/src/editor/component-editor/scaffolding/TokenLayout.svelte +9 -6
  25. package/src/editor/component-editor/scaffolding/TypeEditor.svelte +13 -1
  26. package/src/editor/component-editor/scaffolding/VariantGroup.svelte +239 -25
  27. package/src/editor/component-editor/scaffolding/buildTypeGroupTokens.ts +1 -0
  28. package/src/editor/component-editor/scaffolding/componentSources.ts +3 -3
  29. package/src/editor/component-editor/scaffolding/defaultSections.ts +15 -10
  30. package/src/editor/component-editor/scaffolding/types.ts +11 -0
  31. package/src/editor/core/components/componentConfigKeys.ts +22 -3
  32. package/src/editor/core/components/componentConfigService.ts +2 -2
  33. package/src/editor/core/components/componentPersist.ts +7 -5
  34. package/src/editor/core/manifests/manifestService.ts +58 -3
  35. package/src/editor/core/palettes/familySwap.ts +99 -0
  36. package/src/editor/core/palettes/paletteDerivation.ts +69 -0
  37. package/src/editor/core/palettes/tokenRegistry.ts +4 -1
  38. package/src/editor/core/store/editorStore.ts +206 -12
  39. package/src/editor/core/store/editorTypes.ts +55 -12
  40. package/src/editor/core/store/gradientSource.ts +192 -0
  41. package/src/editor/core/themes/migrations/2026-05-19-collapsiblesection-drop-frame-surface.ts +28 -0
  42. package/src/editor/core/themes/migrations/2026-05-19-sectiondivider-rich-gradient.ts +35 -0
  43. package/src/editor/core/themes/migrations/2026-05-20-sectiondivider-slim-variants.ts +82 -0
  44. package/src/editor/core/themes/migrations/2026-05-21-sectiondivider-spacing-to-padding.ts +24 -0
  45. package/src/editor/core/themes/migrations/2026-05-22-sectiondivider-intrinsics-to-css.ts +81 -0
  46. package/src/editor/core/themes/migrations/index.ts +10 -0
  47. package/src/editor/core/themes/slices/components.ts +27 -4
  48. package/src/editor/core/themes/slices/gradients.ts +88 -13
  49. package/src/editor/core/themes/themeInit.ts +2 -2
  50. package/src/editor/core/themes/themeTypes.ts +56 -1
  51. package/src/editor/index.ts +10 -1
  52. package/src/editor/overlay/ColumnsOverlay.svelte +0 -1
  53. package/src/editor/overlay/LiveEditorOverlay.svelte +1 -4
  54. package/src/editor/pages/ComponentEditorPage.svelte +53 -3
  55. package/src/editor/pages/EditorShell.svelte +53 -3
  56. package/src/editor/styles/ui-editor.css +1 -0
  57. package/src/editor/styles/ui-form-controls.css +19 -20
  58. package/src/editor/ui/BezierCurveEditor.svelte +114 -63
  59. package/src/editor/ui/EditorViewSwitcher.svelte +0 -1
  60. package/src/editor/ui/FileLoadList.svelte +22 -5
  61. package/src/editor/ui/FontStackEditor.svelte +214 -76
  62. package/src/editor/ui/GradientEditor.svelte +435 -215
  63. package/src/editor/ui/GradientStopPicker.svelte +11 -3
  64. package/src/editor/ui/ManifestFileManager.svelte +71 -4
  65. package/src/editor/ui/PaletteEditor.svelte +52 -79
  66. package/src/editor/ui/ProjectFontsSection.svelte +328 -293
  67. package/src/editor/ui/ThemeFileManager.svelte +0 -4
  68. package/src/editor/ui/UIFontFamilySelector.svelte +0 -1
  69. package/src/editor/ui/UIFontSizeSelector.svelte +3 -0
  70. package/src/editor/ui/UIInfoPopover.svelte +0 -1
  71. package/src/editor/ui/UILetterSpacingSelector.svelte +65 -0
  72. package/src/editor/ui/UIPaletteSelector.svelte +31 -4
  73. package/src/editor/ui/UIPillButton.svelte +33 -3
  74. package/src/editor/ui/UISegmentedControl.svelte +114 -0
  75. package/src/editor/ui/UITokenSelector.svelte +4 -1
  76. package/src/editor/ui/VariablesTab.svelte +41 -35
  77. package/src/editor/ui/palette/OverridesPanel.svelte +14 -37
  78. package/src/editor/ui/palette/PaletteBase.svelte +3 -3
  79. package/src/editor/ui/sections/ColumnsSection.svelte +1 -2
  80. package/src/editor/ui/sections/GradientsSection.svelte +1 -1
  81. package/src/editor/ui/sections/OverlaysSection.svelte +1 -1
  82. package/src/editor/ui/sections/ShadowsSection.svelte +1 -1
  83. package/src/system/components/Button.svelte +2 -2
  84. package/src/system/components/Card.svelte +29 -1
  85. package/src/system/components/CollapsibleSection.svelte +25 -2
  86. package/src/system/components/Dialog.svelte +24 -4
  87. package/src/system/components/FloatingTokenTags.css +43 -24
  88. package/src/system/components/FloatingTokenTags.svelte +88 -137
  89. package/src/system/components/Notification.svelte +8 -1
  90. package/src/system/components/SectionDivider.svelte +532 -381
  91. package/src/system/styles/CONVENTIONS.md +1 -1
  92. package/src/system/styles/fonts.css +3 -16
  93. package/src/system/styles/tokens.css +356 -1199
  94. package/src/system/styles/tokens.generated.css +544 -0
  95. package/src/editor/component-editor/scaffolding/DividerEditor.svelte +0 -94
  96. package/src/editor/component-editor/scaffolding/GradientCard.svelte +0 -296
@@ -12,10 +12,13 @@
12
12
  stopId: string; // unique key (e.g. gradient-var + stop index)
13
13
  color: string; // token name like '--color-brand-500'
14
14
  opacity?: number; // 0–100
15
+ /** Forwarded to UIPaletteSelector to scope picks to a color family.
16
+ * See UIPaletteSelector's `familyFilter` for accepted values. */
17
+ familyFilter?: string | null;
15
18
  onchange?: (payload: { color: string; opacity: number }) => void;
16
19
  }
17
20
 
18
- let { stopId, color, opacity = 100, onchange }: Props = $props();
21
+ let { stopId, color, opacity = 100, familyFilter = null, onchange }: Props = $props();
19
22
 
20
23
  /** Scratch var the embedded picker reads/writes; isolated per stop. */
21
24
  let scratchVar = $derived(`--__grad-stop-${stopId}`);
@@ -26,10 +29,15 @@
26
29
  return `color-mix(in srgb, ${base} ${Math.round(o)}%, transparent)`;
27
30
  }
28
31
 
29
- /** Parse a scratch var write back into structured stop fields. */
32
+ /** Parse a scratch var write back into structured stop fields. UIPaletteSelector's
33
+ * "None" choice writes the literal `transparent`; we round-trip it as a stop
34
+ * whose color is the keyword itself — `formatGradientStopColor` already passes
35
+ * non-`--` colors through verbatim, so the gradient (or solid first-stop) ends
36
+ * up painting `transparent`. */
30
37
  function parseScratch(raw: string): { color: string; opacity: number } | null {
31
38
  const trimmed = raw.trim();
32
39
  if (!trimmed) return null;
40
+ if (trimmed === 'transparent') return { color: 'transparent', opacity: 100 };
33
41
  const mixMatch = trimmed.match(/^color-mix\(in srgb,\s*var\((--[a-z0-9-]+)\)\s+(\d+(?:\.\d+)?)%,\s*transparent\)$/i);
34
42
  if (mixMatch) {
35
43
  return { color: mixMatch[1], opacity: parseFloat(mixMatch[2]) };
@@ -60,4 +68,4 @@
60
68
  }
61
69
  </script>
62
70
 
63
- <UIPaletteSelector variable={scratchVar} onchange={handleChange} />
71
+ <UIPaletteSelector variable={scratchVar} {familyFilter} onchange={handleChange} />
@@ -8,6 +8,8 @@
8
8
  applyManifest,
9
9
  saveAsManifest,
10
10
  saveActiveManifest,
11
+ exportManifest,
12
+ importManifest,
11
13
  } from '../core/manifests/manifestService';
12
14
  import { dirty, componentDirty } from '../core/store/editorStore';
13
15
  import { productionRevision, activeManifest } from '../core/productionPulse';
@@ -118,14 +120,62 @@
118
120
  showFileList = false;
119
121
  try {
120
122
  await applyManifest(file.fileName);
121
- // applyManifest atomically flips active pointers; reload to rehydrate
122
- // the editor from the now-active theme + component configs.
123
+ // applyManifest atomically flips active + production pointers and
124
+ // syncs tokens.css; reload to rehydrate the editor from the
125
+ // now-active theme + component configs.
123
126
  window.location.reload();
124
127
  } catch (err) {
125
128
  window.alert(`Failed to apply manifest: ${(err as Error).message}`);
126
129
  }
127
130
  }
128
131
 
132
+ async function handleExport(file: ManifestMeta) {
133
+ try {
134
+ await exportManifest(file.fileName);
135
+ } catch (err) {
136
+ window.alert(`Failed to export: ${(err as Error).message}`);
137
+ }
138
+ }
139
+
140
+ let importInput: HTMLInputElement | null = $state(null);
141
+
142
+ function openImport() {
143
+ importInput?.click();
144
+ }
145
+
146
+ async function handleImportFile(event: Event) {
147
+ const input = event.target as HTMLInputElement;
148
+ const file = input.files?.[0];
149
+ input.value = ''; // allow re-picking the same file later
150
+ if (!file) return;
151
+ let bundle: any;
152
+ try {
153
+ bundle = JSON.parse(await file.text());
154
+ } catch {
155
+ window.alert('Selected file is not valid JSON.');
156
+ return;
157
+ }
158
+ if (bundle?.kind !== 'manifest-bundle') {
159
+ window.alert('Not a manifest bundle (missing kind discriminator).');
160
+ return;
161
+ }
162
+ try {
163
+ const result = await importManifest(bundle);
164
+ await refreshFiles();
165
+ const renameCount = Object.keys(result.renames).length;
166
+ if (renameCount > 0) {
167
+ const summary = Object.entries(result.renames)
168
+ .map(([k, v]) => `${k} → ${v}`)
169
+ .join('\n');
170
+ window.alert(
171
+ `Imported as "${result.manifest}". ${renameCount} file(s) renamed to avoid collisions:\n\n${summary}`,
172
+ );
173
+ }
174
+ } catch (err) {
175
+ window.alert(`Failed to import: ${(err as Error).message}`);
176
+ }
177
+ }
178
+
129
179
  async function handleDelete(file: ManifestMeta) {
130
180
  if (file.isProtected) return;
131
181
  if (file.fileName === activeFileName) {
@@ -218,10 +268,27 @@
218
268
  <i class="fas fa-folder-open"></i>
219
269
  <span>Load…</span>
220
270
  </button>
271
+ <button
272
+ class="mfm-btn mfm-btn-row"
273
+ onclick={openImport}
274
+ title="Import a shared manifest bundle"
275
+ >
276
+ <i class="fas fa-file-import"></i>
277
+ <span>Import…</span>
278
+ </button>
221
279
  </div>
222
280
  </div>
223
281
  </div>
224
282
 
283
+ <!-- Hidden file input for Import; clicked via openImport(). -->
284
+ <input
285
+ bind:this={importInput}
286
+ type="file"
287
+ accept=".json,application/json"
288
+ onchange={handleImportFile}
289
+ style="display: none;"
290
+ />
291
+
225
292
  <FileLoadList
226
293
  bind:show={showFileList}
227
294
  title="Load Manifest"
@@ -229,6 +296,8 @@
229
296
  {activeFileName}
230
297
  onload={handleApply}
231
298
  ondelete={handleDelete}
299
+ onexport={handleExport}
300
+ exportTitle={(f) => `Export "${f.name}" as a shareable bundle`}
232
301
  />
233
302
 
234
303
  <SaveAsDialog
@@ -265,7 +334,6 @@
265
334
  font-size: var(--ui-font-size-xs);
266
335
  color: var(--ui-text-secondary);
267
336
  text-transform: uppercase;
268
- letter-spacing: 0.05em;
269
337
  }
270
338
 
271
339
  .mfm-card {
@@ -304,7 +372,6 @@
304
372
  .mfm-card-label {
305
373
  font-size: 10px;
306
374
  font-weight: var(--ui-font-weight-semibold);
307
- letter-spacing: 0.08em;
308
375
  text-transform: uppercase;
309
376
  color: var(--ui-text-tertiary);
310
377
  }
@@ -1,12 +1,13 @@
1
1
  <script lang="ts">
2
- import { run, stopPropagation, createBubbler } from 'svelte/legacy';
2
+ import { stopPropagation, createBubbler } from 'svelte/legacy';
3
3
 
4
4
  const bubble = createBubbler();
5
- import { onMount, onDestroy, tick } from 'svelte';
5
+ import { onMount, onDestroy, tick, untrack } from 'svelte';
6
6
  import { hexToOklch } from '../core/palettes/oklch';
7
7
  import { type CurveAnchor, lightnessCurveConfig, saturationCurveConfig } from './curveEngine';
8
8
  import ColorEditPanel from './ColorEditPanel.svelte';
9
9
  import OverridesPanel from './palette/OverridesPanel.svelte';
10
+ import UIPillButton from './UIPillButton.svelte';
10
11
  import GradientStopEditor from './palette/GradientStopEditor.svelte';
11
12
  import ScaleCurveEditor from './palette/ScaleCurveEditor.svelte';
12
13
  import PaletteBase from './palette/PaletteBase.svelte';
@@ -79,8 +80,18 @@
79
80
  });
80
81
  }
81
82
 
82
- let lockedLightnessIdx: number | null = $state(null);
83
- let lockedSaturationIdx: number | null = $state(null);
83
+ let lockedLightnessIdx: number | null = $derived.by(() => {
84
+ if (!anchorToBase) return null;
85
+ const x500 = stepIndexToX(4);
86
+ const idx = lightnessCurve.findIndex(a => Math.abs(a.x - x500) < 0.5);
87
+ return idx >= 0 ? idx : null;
88
+ });
89
+ let lockedSaturationIdx: number | null = $derived.by(() => {
90
+ if (!anchorToBase) return null;
91
+ const x500 = stepIndexToX(4);
92
+ const idx = saturationCurve.findIndex(a => Math.abs(a.x - x500) < 0.5);
93
+ return idx >= 0 ? idx : null;
94
+ });
84
95
 
85
96
  // Held at component scope so inline header-swatch handlers and the function
86
97
  // handlers share one handle for commit/cancel.
@@ -95,10 +106,6 @@
95
106
  return ps ? ps.effective : '#000000';
96
107
  }
97
108
 
98
- let gradientColorStops = $state('');
99
- let gradientCssValue = $state('');
100
- let gradientBarPreview = $state('');
101
-
102
109
  function onEmptyModeChange(e: Event) {
103
110
  edit('emptyMode', (e.currentTarget as HTMLInputElement).checked ? 'gradient' : 'solid');
104
111
  }
@@ -464,28 +471,21 @@
464
471
  let gray500Hex = $derived(mode === 'gray'
465
472
  ? (grayComputed.find(g => g.step.label === '500')?.hex ?? GRAY_FALLBACK)
466
473
  : baseColor);
467
- run(() => {
468
- if (anchorToBase) {
469
- const x500 = stepIndexToX(4);
470
- const lIdx = lightnessCurve.findIndex(a => Math.abs(a.x - x500) < 0.5);
471
- lockedLightnessIdx = lIdx >= 0 ? lIdx : null;
472
- const sIdx = saturationCurve.findIndex(a => Math.abs(a.x - x500) < 0.5);
473
- lockedSaturationIdx = sIdx >= 0 ? sIdx : null;
474
- } else {
475
- lockedLightnessIdx = null;
476
- lockedSaturationIdx = null;
477
- }
478
- });
479
474
  // Keep the locked lightness anchor y in sync with baseColor. Idempotent.
480
- // During a baseColor drag the curve edit merges into the same history entry;
481
- // on undo/redo the curve already has the correct y, so this is a no-op.
482
- run(() => {
483
- if (anchorToBase && lockedLightnessIdx !== null && baseColor) {
484
- const targetY = hexToOklch(baseColor).l * 100;
485
- if (lightnessCurve[lockedLightnessIdx] && Math.abs(lightnessCurve[lockedLightnessIdx].y - targetY) > 0.01) {
486
- edit('lightnessCurve', lightnessCurve.map((a, i) => i === lockedLightnessIdx ? { ...a, y: targetY } : a));
475
+ // `lightnessCurve` is read via `untrack` so writing it back via `edit` does
476
+ // not retrigger this effect (Svelte 5 flags the read+write pattern as
477
+ // recursive).
478
+ $effect(() => {
479
+ if (!anchorToBase || lockedLightnessIdx === null || !baseColor) return;
480
+ const targetY = hexToOklch(baseColor).l * 100;
481
+ untrack(() => {
482
+ const idx = lockedLightnessIdx;
483
+ if (idx === null) return;
484
+ const curve = lightnessCurve;
485
+ if (curve[idx] && Math.abs(curve[idx].y - targetY) > 0.01) {
486
+ edit('lightnessCurve', curve.map((a, i) => i === idx ? { ...a, y: targetY } : a));
487
487
  }
488
- }
488
+ });
489
489
  });
490
490
  let paletteComputed = $derived((() => {
491
491
  const _bc = baseColor, _lc = lightnessCurve, _sc = saturationCurve, _co = curveOffset, _ed = editingDraft, _ek = editingKey, _ov = overrides, _ab = anchorToBase;
@@ -503,21 +503,11 @@
503
503
  };
504
504
  });
505
505
  })());
506
- // Gradient reactives must follow paletteComputed
507
- run(() => {
506
+ let gradientBarPreview = $derived.by(() => {
508
507
  const pc = paletteComputed;
509
508
  const sorted = [...gradientStops].sort((a, b) => gradientReverse ? b.position - a.position : a.position - b.position);
510
- gradientColorStops = sorted.map(s => `${stopColor(s, pc)} ${s.position}%`).join(', ');
511
- gradientBarPreview = `linear-gradient(to right, ${gradientColorStops})`;
512
- if (emptySelector && emptyMode === 'gradient') {
513
- switch (gradientStyle) {
514
- case 'radial': gradientCssValue = `radial-gradient(circle, ${gradientColorStops})`; break;
515
- case 'conic': gradientCssValue = `conic-gradient(from ${gradientAngle}deg, ${gradientColorStops})`; break;
516
- default: gradientCssValue = `linear-gradient(${gradientAngle}deg, ${gradientColorStops})`;
517
- }
518
- } else {
519
- gradientCssValue = '';
520
- }
509
+ const stops = sorted.map(s => `${stopColor(s, pc)} ${s.position}%`).join(', ');
510
+ return `linear-gradient(to right, ${stops})`;
521
511
  });
522
512
  let grayScales = $derived(mode === 'gray' ? scales : []);
523
513
  let curveVersion = $derived(JSON.stringify(scaleCurves) + JSON.stringify(curveOffset) + gray500Hex);
@@ -606,12 +596,10 @@
606
596
  <span>Gradient</span>
607
597
  </label>
608
598
  {/if}
609
- <button class="edit-toggle" type="button" onclick={clearPaletteOverrides}>Clear Overrides</button>
610
- <button
611
- class="edit-toggle"
612
- type="button"
613
- onclick={() => paletteEditorOpen = !paletteEditorOpen}
614
- >{paletteEditorOpen ? 'Close' : 'Edit'}</button>
599
+ <UIPillButton size="compact" variant="outline" onclick={clearPaletteOverrides}>Clear Overrides</UIPillButton>
600
+ <UIPillButton size="compact" variant="outline" onclick={() => paletteEditorOpen = !paletteEditorOpen}>
601
+ {paletteEditorOpen ? 'Close' : 'Edit'}
602
+ </UIPillButton>
615
603
  </div>
616
604
  <div class="swatch-grid" style="--swatch-cols: {paletteStepLightness.length + 2}">
617
605
  <div class="step-column">
@@ -718,12 +706,10 @@
718
706
  <div class="scale-section">
719
707
  <div class="scale-header">
720
708
  <h4 class="scale-title">{displayLabel ?? label}</h4>
721
- <button class="edit-toggle" type="button" onclick={clearPaletteOverrides}>Clear Overrides</button>
722
- <button
723
- class="edit-toggle"
724
- type="button"
725
- onclick={() => grayEditorOpen = !grayEditorOpen}
726
- >{grayEditorOpen ? 'Close' : 'Edit'}</button>
709
+ <UIPillButton size="compact" variant="outline" onclick={clearPaletteOverrides}>Clear Overrides</UIPillButton>
710
+ <UIPillButton size="compact" variant="outline" onclick={() => grayEditorOpen = !grayEditorOpen}>
711
+ {grayEditorOpen ? 'Close' : 'Edit'}
712
+ </UIPillButton>
727
713
  </div>
728
714
  <div class="swatch-grid" style="--swatch-cols: {graySteps.length + 2}">
729
715
  <div class="step-column">
@@ -891,21 +877,7 @@
891
877
  display: flex;
892
878
  align-items: center;
893
879
  gap: var(--ui-space-8);
894
- }
895
-
896
- .edit-toggle {
897
- font-size: var(--ui-font-size-md);
898
- color: var(--ui-text-tertiary);
899
- background: none;
900
- border: 1px solid var(--ui-border-low);
901
- border-radius: var(--ui-radius-sm);
902
- padding: var(--ui-space-2) var(--ui-space-6);
903
- cursor: pointer;
904
- }
905
-
906
- .edit-toggle:hover {
907
- color: var(--ui-text-primary);
908
- border-color: var(--ui-border-high);
880
+ padding-bottom: 0.5rem;
909
881
  }
910
882
 
911
883
  .derived-toggle {
@@ -915,17 +887,15 @@
915
887
  padding: var(--ui-space-6) var(--ui-space-4);
916
888
  background: none;
917
889
  border: none;
918
- color: var(--ui-text-tertiary);
919
- font-size: var(--ui-font-size-sm);
920
- font-weight: var(--ui-font-weight-semibold);
890
+ color: var(--ui-text-secondary);
891
+ font-size: var(--ui-font-size-lg);
892
+ font-weight: var(--ui-font-weight-light);
921
893
  cursor: pointer;
922
894
  transition: color var(--ui-transition-fast);
923
- text-transform: uppercase;
924
- letter-spacing: 0.04em;
925
895
  }
926
896
 
927
897
  .derived-toggle:hover {
928
- color: var(--ui-text-secondary);
898
+ color: var(--ui-text-primary);
929
899
  }
930
900
 
931
901
  .derived-toggle i {
@@ -952,12 +922,11 @@
952
922
  }
953
923
 
954
924
  .scale-title {
955
- font-size: var(--ui-font-size-md);
956
- font-weight: var(--ui-font-weight-semibold);
957
- color: var(--ui-text-tertiary);
925
+ font-size: var(--ui-font-size-lg);
926
+ font-weight: var(--ui-font-weight-bold);
927
+ color: var(--ui-text-primary);
958
928
  margin: 0;
959
- text-transform: uppercase;
960
- letter-spacing: 0.05em;
929
+ padding-right: 1rem;
961
930
  }
962
931
 
963
932
  /* Step columns */
@@ -1024,7 +993,11 @@
1024
993
  background: none;
1025
994
  border: none;
1026
995
  text-align: center;
996
+ display: block;
997
+ width: 100%;
998
+ box-sizing: border-box;
1027
999
  min-width: 0;
1000
+ margin-top: var(--ui-space-2);
1028
1001
  overflow: hidden;
1029
1002
  text-overflow: ellipsis;
1030
1003
  }