@motion-proto/live-tokens 0.6.2 → 0.8.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 (232) hide show
  1. package/README.md +14 -13
  2. package/dist-plugin/index.cjs +854 -226
  3. package/dist-plugin/index.d.cts +2 -1
  4. package/dist-plugin/index.d.ts +2 -1
  5. package/dist-plugin/index.js +852 -225
  6. package/package.json +26 -40
  7. package/src/{styles → app}/site.css +1 -1
  8. package/src/{component-editor → editor/component-editor}/BadgeEditor.svelte +8 -82
  9. package/src/{component-editor → editor/component-editor}/CalloutEditor.svelte +4 -4
  10. package/src/{component-editor → editor/component-editor}/CardEditor.svelte +28 -76
  11. package/src/{component-editor → editor/component-editor}/CollapsibleSectionEditor.svelte +37 -30
  12. package/src/{component-editor → editor/component-editor}/CornerBadgeEditor.svelte +31 -93
  13. package/src/{component-editor → editor/component-editor}/DialogEditor.svelte +60 -57
  14. package/src/editor/component-editor/ImageEditor.svelte +30 -0
  15. package/src/{component-editor → editor/component-editor}/InlineEditActionsEditor.svelte +6 -4
  16. package/src/editor/component-editor/MenuSelectEditor.svelte +160 -0
  17. package/src/{component-editor → editor/component-editor}/NotificationEditor.svelte +67 -38
  18. package/src/{component-editor → editor/component-editor}/ProgressBarEditor.svelte +5 -4
  19. package/src/{component-editor → editor/component-editor}/RadioButtonEditor.svelte +3 -3
  20. package/src/editor/component-editor/SectionDividerEditor.svelte +565 -0
  21. package/src/{component-editor → editor/component-editor}/SegmentedControlEditor.svelte +2 -2
  22. package/src/{component-editor → editor/component-editor}/StandardButtonsEditor.svelte +29 -21
  23. package/src/{component-editor → editor/component-editor}/TabBarEditor.svelte +9 -14
  24. package/src/{component-editor → editor/component-editor}/TableEditor.svelte +9 -18
  25. package/src/{component-editor → editor/component-editor}/TooltipEditor.svelte +11 -47
  26. package/src/editor/component-editor/editors.d.ts +10 -0
  27. package/src/{component-editor → editor/component-editor}/registry.ts +28 -18
  28. package/src/{component-editor → editor/component-editor}/scaffolding/AngleDial.svelte +54 -15
  29. package/src/{component-editor → editor/component-editor}/scaffolding/ComponentEditorBase.svelte +3 -51
  30. package/src/{component-editor → editor/component-editor}/scaffolding/ComponentFileManager.svelte +151 -424
  31. package/src/{component-editor → editor/component-editor}/scaffolding/ComponentFileMenu.svelte +18 -170
  32. package/src/{component-editor → editor/component-editor}/scaffolding/ComponentsTab.svelte +2 -2
  33. package/src/{component-editor → editor/component-editor}/scaffolding/CopyFromMenu.svelte +44 -4
  34. package/src/{component-editor → editor/component-editor}/scaffolding/FieldsetWrapper.svelte +1 -1
  35. package/src/{component-editor → editor/component-editor}/scaffolding/LinkageChart.svelte +6 -6
  36. package/src/{component-editor → editor/component-editor}/scaffolding/LinkedBlock.svelte +6 -12
  37. package/src/editor/component-editor/scaffolding/NonStylableConfig.svelte +38 -0
  38. package/src/editor/component-editor/scaffolding/RadialShapePad.svelte +483 -0
  39. package/src/{component-editor → editor/component-editor}/scaffolding/SaveAsDialog.svelte +66 -12
  40. package/src/editor/component-editor/scaffolding/ShadowBackdrop.svelte +85 -0
  41. package/src/editor/component-editor/scaffolding/ShadowBackdropControls.svelte +132 -0
  42. package/src/editor/component-editor/scaffolding/StateBlock.svelte +345 -0
  43. package/src/{component-editor → editor/component-editor}/scaffolding/TokenLayout.svelte +17 -12
  44. package/src/{component-editor → editor/component-editor}/scaffolding/TypeEditor.svelte +13 -1
  45. package/src/editor/component-editor/scaffolding/VariantGroup.svelte +858 -0
  46. package/src/{component-editor → editor/component-editor}/scaffolding/buildTypeGroupTokens.ts +1 -0
  47. package/src/{component-editor → editor/component-editor}/scaffolding/editorContext.ts +19 -9
  48. package/src/{component-editor → editor/component-editor}/scaffolding/linkedBlock.ts +2 -2
  49. package/src/{component-editor → editor/component-editor}/scaffolding/types.ts +25 -0
  50. package/src/{lib → editor/core/components}/componentConfigKeys.ts +8 -0
  51. package/src/{lib → editor/core/components}/componentConfigService.ts +3 -3
  52. package/src/{lib → editor/core/components}/componentPersist.ts +11 -9
  53. package/src/editor/core/flashStatus.ts +30 -0
  54. package/src/{lib → editor/core/fonts}/fontLoader.ts +2 -2
  55. package/src/{lib → editor/core/fonts}/fontMigration.ts +4 -4
  56. package/src/{lib → editor/core/fonts}/fontParse.ts +1 -1
  57. package/src/editor/core/manifests/manifestService.ts +171 -0
  58. package/src/editor/core/palettes/familySwap.ts +99 -0
  59. package/src/{lib → editor/core/palettes}/paletteDerivation.ts +71 -2
  60. package/src/{lib → editor/core/palettes}/tokenRegistry.ts +9 -6
  61. package/src/editor/core/productionPulse.ts +37 -0
  62. package/src/{lib → editor/core/routing}/router.ts +1 -1
  63. package/src/{lib/files/versionedFileResource.ts → editor/core/storage/files/versionedFileResourceClient.ts} +8 -1
  64. package/src/{lib → editor/core/store}/editorCore.ts +24 -8
  65. package/src/{lib → editor/core/store}/editorPersistence.ts +3 -3
  66. package/src/{lib → editor/core/store}/editorRenderer.ts +2 -2
  67. package/src/{lib → editor/core/store}/editorStore.ts +222 -28
  68. package/src/{lib → editor/core/store}/editorTypes.ts +56 -13
  69. package/src/editor/core/store/gradientSource.ts +192 -0
  70. package/src/editor/core/themes/migrations/2026-05-19-collapsiblesection-drop-frame-surface.ts +28 -0
  71. package/src/editor/core/themes/migrations/2026-05-19-sectiondivider-rich-gradient.ts +35 -0
  72. package/src/editor/core/themes/migrations/2026-05-20-sectiondivider-slim-variants.ts +82 -0
  73. package/src/editor/core/themes/migrations/2026-05-21-sectiondivider-spacing-to-padding.ts +24 -0
  74. package/src/editor/core/themes/migrations/2026-05-22-sectiondivider-intrinsics-to-css.ts +81 -0
  75. package/src/{lib → editor/core/themes}/migrations/index.ts +10 -0
  76. package/src/{lib → editor/core/themes}/slices/columns.ts +2 -2
  77. package/src/{lib → editor/core/themes}/slices/components.ts +20 -6
  78. package/src/{lib → editor/core/themes}/slices/fonts.ts +1 -1
  79. package/src/{lib → editor/core/themes}/slices/gradients.ts +89 -14
  80. package/src/{lib → editor/core/themes}/slices/overlays.ts +1 -1
  81. package/src/{lib → editor/core/themes}/slices/palettes.ts +1 -1
  82. package/src/{lib → editor/core/themes}/slices/shadows.ts +3 -3
  83. package/src/{lib → editor/core/themes}/themeInit.ts +8 -8
  84. package/src/{lib → editor/core/themes}/themeService.ts +6 -6
  85. package/src/{lib → editor/core/themes}/themeTypes.ts +67 -8
  86. package/src/editor/index.ts +69 -0
  87. package/src/{lib → editor/overlay}/ColumnsOverlay.svelte +0 -1
  88. package/src/{lib → editor/overlay}/LiveEditorOverlay.svelte +80 -129
  89. package/src/{lib → editor/overlay}/columnsOverlay.ts +2 -2
  90. package/src/{pages → editor/pages}/ComponentEditorPage.svelte +12 -12
  91. package/src/{pages → editor/pages}/Editor.svelte +4 -4
  92. package/src/{pages → editor/pages}/EditorShell.svelte +18 -36
  93. package/src/{styles → editor/styles}/ui-editor.css +43 -22
  94. package/src/{styles → editor/styles}/ui-form-controls.css +23 -24
  95. package/src/{ui → editor/ui}/BezierCurveEditor.svelte +119 -68
  96. package/src/{ui → editor/ui}/ColorEditPanel.svelte +13 -13
  97. package/src/{ui → editor/ui}/EditorViewSwitcher.svelte +7 -6
  98. package/src/editor/ui/FileLoadList.svelte +367 -0
  99. package/src/editor/ui/FilePill.svelte +80 -0
  100. package/src/editor/ui/FontStackEditor.svelte +499 -0
  101. package/src/editor/ui/GradientEditor.svelte +690 -0
  102. package/src/{ui → editor/ui}/GradientStopPicker.svelte +12 -4
  103. package/src/editor/ui/ManifestFileManager.svelte +438 -0
  104. package/src/{ui → editor/ui}/PaletteEditor.svelte +180 -673
  105. package/src/editor/ui/ProjectFontsSection.svelte +638 -0
  106. package/src/{ui → editor/ui}/SurfacesTab.svelte +3 -3
  107. package/src/{ui → editor/ui}/TextTab.svelte +3 -3
  108. package/src/editor/ui/ThemeFileManager.svelte +783 -0
  109. package/src/{ui → editor/ui}/UICopyPopover.svelte +4 -4
  110. package/src/{ui → editor/ui}/UIFontFamilySelector.svelte +6 -7
  111. package/src/{ui → editor/ui}/UIFontSizeSelector.svelte +4 -1
  112. package/src/editor/ui/UIInfoPopover.svelte +243 -0
  113. package/src/editor/ui/UILetterSpacingSelector.svelte +65 -0
  114. package/src/{ui → editor/ui}/UILineHeightSelector.svelte +5 -5
  115. package/src/{ui → editor/ui}/UILinkToggle.svelte +2 -2
  116. package/src/{ui → editor/ui}/UIPaddingSelector.svelte +6 -6
  117. package/src/{ui → editor/ui}/UIPaletteSelector.svelte +57 -30
  118. package/src/editor/ui/UIPillButton.svelte +168 -0
  119. package/src/{ui → editor/ui}/UIRadio.svelte +2 -2
  120. package/src/{ui → editor/ui}/UIRelinkConfirmPopover.svelte +4 -4
  121. package/src/editor/ui/UISegmentedControl.svelte +114 -0
  122. package/src/editor/ui/UISquareButton.svelte +172 -0
  123. package/src/{ui → editor/ui}/UITokenSelector.svelte +14 -11
  124. package/src/{ui → editor/ui}/UIVariantSelector.svelte +1 -1
  125. package/src/{ui → editor/ui}/VariablesTab.svelte +46 -17
  126. package/src/{ui → editor/ui}/palette/GradientStopEditor.svelte +13 -13
  127. package/src/{ui → editor/ui}/palette/OverridesPanel.svelte +24 -47
  128. package/src/{ui → editor/ui}/palette/PaletteBase.svelte +11 -8
  129. package/src/{ui → editor/ui}/palette/paletteEditorState.ts +1 -1
  130. package/src/editor/ui/palette/paletteMath.ts +275 -0
  131. package/src/{ui → editor/ui}/sections/ColumnsSection.svelte +137 -18
  132. package/src/{ui → editor/ui}/sections/GradientsSection.svelte +8 -8
  133. package/src/{ui → editor/ui}/sections/OverlaysSection.svelte +18 -18
  134. package/src/{ui → editor/ui}/sections/ShadowsSection.svelte +23 -23
  135. package/src/{ui → editor/ui}/sections/TokenScaleTable.svelte +3 -3
  136. package/src/{components → system/components}/Badge.svelte +0 -36
  137. package/src/{components → system/components}/Button.svelte +2 -2
  138. package/src/{components → system/components}/Card.svelte +34 -60
  139. package/src/{components → system/components}/CollapsibleSection.svelte +25 -2
  140. package/src/{components → system/components}/CornerBadge.svelte +8 -24
  141. package/src/{components → system/components}/Dialog.svelte +1 -1
  142. package/src/system/components/FloatingTokenTags.css +275 -0
  143. package/src/system/components/FloatingTokenTags.svelte +543 -0
  144. package/src/{components → system/components}/InlineEditActions.svelte +6 -4
  145. package/src/system/components/MenuSelect.svelte +229 -0
  146. package/src/{components → system/components}/Notification.svelte +8 -1
  147. package/src/{components → system/components}/ProgressBar.svelte +29 -11
  148. package/src/system/components/SectionDivider.svelte +560 -0
  149. package/src/{components → system/components}/SegmentedControl.svelte +49 -43
  150. package/src/{components → system/components}/TabBar.svelte +81 -65
  151. package/src/{components → system/components}/Table.svelte +17 -3
  152. package/src/{components → system/components}/Tooltip.svelte +6 -4
  153. package/src/system/styles/CONVENTIONS.md +178 -0
  154. package/src/system/styles/fonts.css +20 -0
  155. package/src/system/styles/tokens.css +601 -0
  156. package/src/system/styles/tokens.generated.css +544 -0
  157. package/src/component-editor/ImageEditor.svelte +0 -74
  158. package/src/component-editor/SectionDividerEditor.svelte +0 -265
  159. package/src/component-editor/scaffolding/DividerEditor.svelte +0 -94
  160. package/src/component-editor/scaffolding/GradientCard.svelte +0 -296
  161. package/src/component-editor/scaffolding/NonStylableConfig.svelte +0 -62
  162. package/src/component-editor/scaffolding/ShadowBackdrop.svelte +0 -37
  163. package/src/component-editor/scaffolding/ShadowBackdropControls.svelte +0 -61
  164. package/src/component-editor/scaffolding/StateBlock.svelte +0 -132
  165. package/src/component-editor/scaffolding/VariantGroup.svelte +0 -310
  166. package/src/components/SectionDivider.svelte +0 -483
  167. package/src/data/google-fonts.json +0 -75
  168. package/src/lib/index.ts +0 -68
  169. package/src/lib/presetService.ts +0 -214
  170. package/src/lib/productionPulse.ts +0 -32
  171. package/src/styles/fonts.css +0 -30
  172. package/src/styles/tokens.css +0 -1324
  173. package/src/ui/FontStackEditor.svelte +0 -361
  174. package/src/ui/GradientEditor.svelte +0 -470
  175. package/src/ui/PresetFileManager.svelte +0 -1116
  176. package/src/ui/ProjectFontsSection.svelte +0 -645
  177. package/src/ui/ThemeFileManager.svelte +0 -1020
  178. package/src/ui/UnsavedComponentsDialog.svelte +0 -315
  179. /package/src/{component-editor → editor/component-editor}/index.ts +0 -0
  180. /package/src/{component-editor → editor/component-editor}/scaffolding/DemoHeader.svelte +0 -0
  181. /package/src/{component-editor → editor/component-editor}/scaffolding/componentSectionType.ts +0 -0
  182. /package/src/{component-editor → editor/component-editor}/scaffolding/componentSources.ts +0 -0
  183. /package/src/{component-editor → editor/component-editor}/scaffolding/defaultSections.ts +0 -0
  184. /package/src/{component-editor → editor/component-editor}/scaffolding/siblings.ts +0 -0
  185. /package/src/{lib → editor/core}/cssVarSync.ts +0 -0
  186. /package/src/{lib → editor/core/palettes}/oklch.ts +0 -0
  187. /package/src/{lib → editor/core/routing}/navLinkTypes.ts +0 -0
  188. /package/src/{lib → editor/core/routing}/parentRouteStore.ts +0 -0
  189. /package/src/{lib → editor/core/storage}/storage.ts +0 -0
  190. /package/src/{lib → editor/core/store}/editorConfig.ts +0 -0
  191. /package/src/{lib → editor/core/store}/editorConfigStore.ts +0 -0
  192. /package/src/{lib → editor/core/store}/editorKeybindings.ts +0 -0
  193. /package/src/{lib → editor/core/store}/editorViewStore.ts +0 -0
  194. /package/src/{lib → editor/core/themes}/migrations/2026-04-24-component-prefix-and-suffix-renames.ts +0 -0
  195. /package/src/{lib → editor/core/themes}/migrations/2026-04-24-legacy-keys-and-bg-to-canvas.ts +0 -0
  196. /package/src/{lib → editor/core/themes}/migrations/2026-04-27-segmentedcontrol-disabled-flatten.ts +0 -0
  197. /package/src/{lib → editor/core/themes}/migrations/2026-05-08-collapsiblesection-frame-and-cleanup.ts +0 -0
  198. /package/src/{lib → editor/core/themes}/migrations/2026-05-08-collapsiblesection-variant-namespace.ts +0 -0
  199. /package/src/{lib → editor/core/themes}/migrations/2026-05-10-sectiondivider-gradient-stops.ts +0 -0
  200. /package/src/{lib → editor/core/themes}/migrations/2026-05-13-primary-to-brand.ts +0 -0
  201. /package/src/{lib → editor/core/themes}/parsers/globalRootBlock.ts +0 -0
  202. /package/src/{lib → editor/core/themes}/slices/domainVars.ts +0 -0
  203. /package/src/{lib → editor/overlay}/overlayState.ts +0 -0
  204. /package/src/{pages → editor/pages}/ComponentEditorPage.svelte.d.ts +0 -0
  205. /package/src/{pages → editor/pages}/Editor.svelte.d.ts +0 -0
  206. /package/src/{ui → editor/ui}/Toggle.svelte +0 -0
  207. /package/src/{ui → editor/ui}/UIDialog.svelte +0 -0
  208. /package/src/{ui → editor/ui}/UIFontWeightSelector.svelte +0 -0
  209. /package/src/{ui → editor/ui}/UIOptionItem.svelte +0 -0
  210. /package/src/{ui → editor/ui}/UIOptionList.svelte +0 -0
  211. /package/src/{ui → editor/ui}/UIRadioGroup.svelte +0 -0
  212. /package/src/{lib → editor/ui}/copyPopover.ts +0 -0
  213. /package/src/{ui → editor/ui}/curveEngine.ts +0 -0
  214. /package/src/{ui → editor/ui}/index.ts +0 -0
  215. /package/src/{ui → editor/ui}/keepInViewport.ts +0 -0
  216. /package/src/{ui → editor/ui}/palette/ScaleCurveEditor.svelte +0 -0
  217. /package/src/{lib → editor/ui}/scrollSection.ts +0 -0
  218. /package/src/{ui → editor/ui}/sections/tokenScales.ts +0 -0
  219. /package/src/{ui → editor/ui}/variantScales.ts +0 -0
  220. /package/src/{assets → system/assets}/newspaper.webp +0 -0
  221. /package/src/{assets → system/assets}/offering.webp +0 -0
  222. /package/src/{components → system/components}/Callout.svelte +0 -0
  223. /package/src/{components → system/components}/Image.svelte +0 -0
  224. /package/src/{components → system/components}/RadioButton.svelte +0 -0
  225. /package/src/{components → system/components}/types.ts +0 -0
  226. /package/src/{styles → system/styles}/_padding.scss +0 -0
  227. /package/src/{styles → system/styles}/fonts/Fraunces/Fraunces-italic-latin-ext.woff2 +0 -0
  228. /package/src/{styles → system/styles}/fonts/Fraunces/Fraunces-italic-latin.woff2 +0 -0
  229. /package/src/{styles → system/styles}/fonts/Fraunces/Fraunces-roman-latin-ext.woff2 +0 -0
  230. /package/src/{styles → system/styles}/fonts/Fraunces/Fraunces-roman-latin.woff2 +0 -0
  231. /package/src/{styles → system/styles}/fonts/Manrope/Manrope-latin-ext.woff2 +0 -0
  232. /package/src/{styles → system/styles}/fonts/Manrope/Manrope-latin.woff2 +0 -0
@@ -126,7 +126,22 @@
126
126
  border-radius: var(--segmentedcontrol-bar-radius);
127
127
  }
128
128
 
129
+ /* Font + color properties are declared once on `.segment` and rebound per
130
+ state via the `--_*` custom properties below. State classes only change
131
+ the bindings; the actual `font-*` declarations never move. When two
132
+ states resolve to the same final value the computed font is identical
133
+ and the browser has no reason to re-shape — which is what kept the
134
+ selected segment shifting by a whole pixel even after the border was
135
+ swapped for an outline. */
129
136
  .segment {
137
+ --_text-color: var(--segmentedcontrol-option-text);
138
+ --_text-family: var(--segmentedcontrol-option-text-font-family);
139
+ --_text-size: var(--segmentedcontrol-option-text-font-size);
140
+ --_text-weight: var(--segmentedcontrol-option-text-font-weight);
141
+ --_text-line-height: var(--segmentedcontrol-option-text-line-height);
142
+ --_icon-color: var(--segmentedcontrol-option-icon);
143
+ --_icon-size: var(--segmentedcontrol-option-icon-size);
144
+
130
145
  display: inline-flex;
131
146
  align-items: center;
132
147
  gap: var(--space-8);
@@ -134,19 +149,19 @@
134
149
  background: transparent;
135
150
  border: 0;
136
151
  border-radius: var(--segmentedcontrol-selected-radius);
137
- color: var(--segmentedcontrol-option-text);
138
- font-family: var(--segmentedcontrol-option-text-font-family);
139
- font-size: var(--segmentedcontrol-option-text-font-size);
140
- font-weight: var(--segmentedcontrol-option-text-font-weight);
141
- line-height: var(--segmentedcontrol-option-text-line-height);
152
+ color: var(--_text-color);
153
+ font-family: var(--_text-family);
154
+ font-size: var(--_text-size);
155
+ font-weight: var(--_text-weight);
156
+ line-height: var(--_text-line-height);
142
157
  cursor: pointer;
143
158
  transition: background var(--duration-150), color var(--duration-150);
144
159
  position: relative;
145
160
  }
146
161
 
147
162
  .segment i {
148
- font-size: var(--segmentedcontrol-option-icon-size);
149
- color: var(--segmentedcontrol-option-icon);
163
+ font-size: var(--_icon-size);
164
+ color: var(--_icon-color);
150
165
  transition: color var(--duration-150);
151
166
  }
152
167
 
@@ -166,52 +181,43 @@
166
181
 
167
182
  .segment:hover:not(:disabled):not(.selected),
168
183
  .segment.force-hover:not(:disabled):not(.selected) {
184
+ --_text-color: var(--segmentedcontrol-option-hover-text);
185
+ --_text-family: var(--segmentedcontrol-option-hover-text-font-family);
186
+ --_text-size: var(--segmentedcontrol-option-hover-text-font-size);
187
+ --_text-weight: var(--segmentedcontrol-option-hover-text-font-weight);
188
+ --_text-line-height: var(--segmentedcontrol-option-hover-text-line-height);
189
+ --_icon-color: var(--segmentedcontrol-option-hover-icon);
190
+ --_icon-size: var(--segmentedcontrol-option-hover-icon-size);
169
191
  background: var(--segmentedcontrol-option-hover-surface);
170
- color: var(--segmentedcontrol-option-hover-text);
171
- font-family: var(--segmentedcontrol-option-hover-text-font-family);
172
- font-size: var(--segmentedcontrol-option-hover-text-font-size);
173
- font-weight: var(--segmentedcontrol-option-hover-text-font-weight);
174
- line-height: var(--segmentedcontrol-option-hover-text-line-height);
175
- }
176
-
177
- .segment:hover:not(:disabled):not(.selected) i,
178
- .segment.force-hover:not(:disabled):not(.selected) i {
179
- color: var(--segmentedcontrol-option-hover-icon);
180
- font-size: var(--segmentedcontrol-option-hover-icon-size);
181
192
  }
182
193
 
194
+ /* Outline (not border) so the selection ring sits outside the box model.
195
+ A real border would force a padding compensation calc, and the resulting
196
+ sub-pixel flex layout would shift the selected segment by a whole pixel
197
+ against its neighbors. Outline is paint-only and leaves geometry alone. */
183
198
  .segment.selected {
199
+ --_text-color: var(--segmentedcontrol-selected-text);
200
+ --_text-family: var(--segmentedcontrol-selected-text-font-family);
201
+ --_text-size: var(--segmentedcontrol-selected-text-font-size);
202
+ --_text-weight: var(--segmentedcontrol-selected-text-font-weight);
203
+ --_text-line-height: var(--segmentedcontrol-selected-text-line-height);
204
+ --_icon-color: var(--segmentedcontrol-selected-icon);
205
+ --_icon-size: var(--segmentedcontrol-selected-icon-size);
184
206
  background: var(--segmentedcontrol-selected-surface);
185
- border: var(--segmentedcontrol-selected-border-width) solid var(--segmentedcontrol-selected-border);
186
- border-radius: var(--segmentedcontrol-selected-radius);
187
- color: var(--segmentedcontrol-selected-text);
188
- font-family: var(--segmentedcontrol-selected-text-font-family);
189
- font-size: var(--segmentedcontrol-selected-text-font-size);
190
- font-weight: var(--segmentedcontrol-selected-text-font-weight);
191
- line-height: var(--segmentedcontrol-selected-text-line-height);
192
- /* Account for border so the pill doesn't shift adjacent segments */
193
- padding: calc(var(--space-6) - var(--segmentedcontrol-selected-border-width))
194
- calc(var(--space-16) - var(--segmentedcontrol-selected-border-width));
195
- }
196
-
197
- .segment.selected i {
198
- color: var(--segmentedcontrol-selected-icon);
199
- font-size: var(--segmentedcontrol-selected-icon-size);
207
+ outline: var(--segmentedcontrol-selected-border-width) solid var(--segmentedcontrol-selected-border);
208
+ outline-offset: calc(var(--segmentedcontrol-selected-border-width) * -1);
200
209
  }
201
210
 
202
211
  .segment:disabled {
212
+ --_text-color: var(--segmentedcontrol-disabled-text);
213
+ --_text-family: var(--segmentedcontrol-disabled-text-font-family);
214
+ --_text-size: var(--segmentedcontrol-disabled-text-font-size);
215
+ --_text-weight: var(--segmentedcontrol-disabled-text-font-weight);
216
+ --_text-line-height: var(--segmentedcontrol-disabled-text-line-height);
217
+ --_icon-color: var(--segmentedcontrol-disabled-icon);
218
+ --_icon-size: var(--segmentedcontrol-disabled-icon-size);
203
219
  background: var(--segmentedcontrol-disabled-surface);
204
- color: var(--segmentedcontrol-disabled-text);
205
- font-family: var(--segmentedcontrol-disabled-text-font-family);
206
- font-size: var(--segmentedcontrol-disabled-text-font-size);
207
- font-weight: var(--segmentedcontrol-disabled-text-font-weight);
208
- line-height: var(--segmentedcontrol-disabled-text-line-height);
209
220
  opacity: 0.4;
210
221
  cursor: not-allowed;
211
222
  }
212
-
213
- .segment:disabled i {
214
- color: var(--segmentedcontrol-disabled-icon);
215
- font-size: var(--segmentedcontrol-disabled-icon-size);
216
- }
217
223
  </style>
@@ -140,91 +140,107 @@
140
140
  margin-bottom: var(--tabbar-bar-bottom-margin);
141
141
  }
142
142
 
143
+ /* Per-state tokens are bound to `--_*` custom properties below. The actual
144
+ layout-affecting declarations (padding, border, border-radius, font-*)
145
+ are written exactly once on `.tab`, so a hover/active state change can
146
+ only repaint, not relayout. When two states resolve to the same value,
147
+ the computed property is identical and no reshape is triggered. The
148
+ `transition: all` of the old rule has also been narrowed to paint-only
149
+ properties — otherwise it would try to animate layout changes between
150
+ states that happen to differ in tokens. */
143
151
  .tab {
152
+ --_text-color: var(--tabbar-default-text);
153
+ --_text-family: var(--tabbar-default-text-font-family);
154
+ --_text-size: var(--tabbar-default-text-font-size);
155
+ --_text-weight: var(--tabbar-default-text-font-weight);
156
+ --_text-line-height: var(--tabbar-default-text-line-height);
157
+ --_icon-size: var(--tabbar-default-icon-size);
158
+ --_surface: var(--tabbar-default-surface);
159
+ --_indicator-color: var(--tabbar-default-border);
160
+ --_padding: var(--tabbar-default-padding);
161
+ --_border-color: var(--tabbar-default-tab-border-color);
162
+ --_border-width: var(--tabbar-default-tab-border-width);
163
+ --_top-radius: var(--tabbar-default-tab-top-radius);
164
+ --_bottom-radius: var(--tabbar-default-tab-bottom-radius);
165
+
144
166
  display: inline-flex;
145
167
  align-items: center;
146
168
  gap: var(--space-6);
147
- @include themed-padding(--tabbar-default-padding, $h: 2);
148
- background: var(--tabbar-default-surface);
149
- border: var(--tabbar-default-tab-border-width) solid var(--tabbar-default-tab-border-color);
150
- /* indicator accent owns the bottom edge */
151
- border-bottom: var(--tabbar-bar-indicator-thickness) solid var(--tabbar-default-border);
152
- border-radius: var(--tabbar-default-tab-top-radius) var(--tabbar-default-tab-top-radius) var(--tabbar-default-tab-bottom-radius) var(--tabbar-default-tab-bottom-radius);
153
- color: var(--tabbar-default-text);
154
- font-family: var(--tabbar-default-text-font-family);
155
- font-size: var(--tabbar-default-text-font-size);
156
- font-weight: var(--tabbar-default-text-font-weight);
157
- line-height: var(--tabbar-default-text-line-height);
169
+ padding: var(--_padding) calc(var(--_padding) * 2);
170
+ background: var(--_surface);
171
+ border: var(--_border-width) solid var(--_border-color);
172
+ /* Indicator accent owns the bottom edge. Thickness is constant across
173
+ states (--tabbar-bar-indicator-thickness), only color rebinds. */
174
+ border-bottom: var(--tabbar-bar-indicator-thickness) solid var(--_indicator-color);
175
+ border-radius: var(--_top-radius) var(--_top-radius) var(--_bottom-radius) var(--_bottom-radius);
176
+ color: var(--_text-color);
177
+ font-family: var(--_text-family);
178
+ font-size: var(--_text-size);
179
+ font-weight: var(--_text-weight);
180
+ line-height: var(--_text-line-height);
158
181
  cursor: pointer;
159
- transition: all var(--duration-150);
182
+ transition:
183
+ background var(--duration-150),
184
+ color var(--duration-150),
185
+ border-color var(--duration-150);
160
186
  position: relative;
161
187
  }
162
188
 
189
+ .tab i {
190
+ font-size: var(--_icon-size);
191
+ }
192
+
163
193
  .tab:hover:not(:disabled):not(.active),
164
194
  .tab-bar.force-hover .tab:not(:disabled):not(.active) {
165
- color: var(--tabbar-hover-text);
166
- background: var(--tabbar-hover-surface);
167
- border-color: var(--tabbar-hover-tab-border-color);
168
- border-width: var(--tabbar-hover-tab-border-width);
169
- /* indicator accent owns the bottom edge */
170
- border-bottom: var(--tabbar-bar-indicator-thickness) solid var(--tabbar-hover-border);
171
- border-radius: var(--tabbar-hover-tab-top-radius) var(--tabbar-hover-tab-top-radius) var(--tabbar-hover-tab-bottom-radius) var(--tabbar-hover-tab-bottom-radius);
172
- font-family: var(--tabbar-hover-text-font-family);
173
- font-size: var(--tabbar-hover-text-font-size);
174
- font-weight: var(--tabbar-hover-text-font-weight);
175
- line-height: var(--tabbar-hover-text-line-height);
176
- @include themed-padding(--tabbar-hover-padding, $h: 2);
195
+ --_text-color: var(--tabbar-hover-text);
196
+ --_text-family: var(--tabbar-hover-text-font-family);
197
+ --_text-size: var(--tabbar-hover-text-font-size);
198
+ --_text-weight: var(--tabbar-hover-text-font-weight);
199
+ --_text-line-height: var(--tabbar-hover-text-line-height);
200
+ --_icon-size: var(--tabbar-hover-icon-size);
201
+ --_surface: var(--tabbar-hover-surface);
202
+ --_indicator-color: var(--tabbar-hover-border);
203
+ --_padding: var(--tabbar-hover-padding);
204
+ --_border-color: var(--tabbar-hover-tab-border-color);
205
+ --_border-width: var(--tabbar-hover-tab-border-width);
206
+ --_top-radius: var(--tabbar-hover-tab-top-radius);
207
+ --_bottom-radius: var(--tabbar-hover-tab-bottom-radius);
177
208
  }
178
209
 
179
210
  .tab.active {
180
- color: var(--tabbar-active-text);
181
- background: var(--tabbar-active-surface);
182
- border-color: var(--tabbar-active-tab-border-color);
183
- border-width: var(--tabbar-active-tab-border-width);
184
- /* indicator accent owns the bottom edge */
185
- border-bottom: var(--tabbar-bar-indicator-thickness) solid var(--tabbar-active-border);
186
- border-radius: var(--tabbar-active-tab-top-radius) var(--tabbar-active-tab-top-radius) var(--tabbar-active-tab-bottom-radius) var(--tabbar-active-tab-bottom-radius);
187
- font-family: var(--tabbar-active-text-font-family);
188
- font-size: var(--tabbar-active-text-font-size);
189
- font-weight: var(--tabbar-active-text-font-weight);
190
- line-height: var(--tabbar-active-text-line-height);
191
- @include themed-padding(--tabbar-active-padding, $h: 2);
211
+ --_text-color: var(--tabbar-active-text);
212
+ --_text-family: var(--tabbar-active-text-font-family);
213
+ --_text-size: var(--tabbar-active-text-font-size);
214
+ --_text-weight: var(--tabbar-active-text-font-weight);
215
+ --_text-line-height: var(--tabbar-active-text-line-height);
216
+ --_icon-size: var(--tabbar-active-icon-size);
217
+ --_surface: var(--tabbar-active-surface);
218
+ --_indicator-color: var(--tabbar-active-border);
219
+ --_padding: var(--tabbar-active-padding);
220
+ --_border-color: var(--tabbar-active-tab-border-color);
221
+ --_border-width: var(--tabbar-active-tab-border-width);
222
+ --_top-radius: var(--tabbar-active-tab-top-radius);
223
+ --_bottom-radius: var(--tabbar-active-tab-bottom-radius);
192
224
  }
193
225
 
194
226
  .tab:disabled {
195
- color: var(--tabbar-disabled-text);
196
- background: var(--tabbar-disabled-surface);
197
- border-color: var(--tabbar-disabled-tab-border-color);
198
- border-width: var(--tabbar-disabled-tab-border-width);
199
- /* indicator accent owns the bottom edge */
200
- border-bottom: var(--tabbar-bar-indicator-thickness) solid var(--tabbar-disabled-border);
201
- border-radius: var(--tabbar-disabled-tab-top-radius) var(--tabbar-disabled-tab-top-radius) var(--tabbar-disabled-tab-bottom-radius) var(--tabbar-disabled-tab-bottom-radius);
202
- font-family: var(--tabbar-disabled-text-font-family);
203
- font-size: var(--tabbar-disabled-text-font-size);
204
- font-weight: var(--tabbar-disabled-text-font-weight);
205
- line-height: var(--tabbar-disabled-text-line-height);
206
- @include themed-padding(--tabbar-disabled-padding, $h: 2);
227
+ --_text-color: var(--tabbar-disabled-text);
228
+ --_text-family: var(--tabbar-disabled-text-font-family);
229
+ --_text-size: var(--tabbar-disabled-text-font-size);
230
+ --_text-weight: var(--tabbar-disabled-text-font-weight);
231
+ --_text-line-height: var(--tabbar-disabled-text-line-height);
232
+ --_icon-size: var(--tabbar-disabled-icon-size);
233
+ --_surface: var(--tabbar-disabled-surface);
234
+ --_indicator-color: var(--tabbar-disabled-border);
235
+ --_padding: var(--tabbar-disabled-padding);
236
+ --_border-color: var(--tabbar-disabled-tab-border-color);
237
+ --_border-width: var(--tabbar-disabled-tab-border-width);
238
+ --_top-radius: var(--tabbar-disabled-tab-top-radius);
239
+ --_bottom-radius: var(--tabbar-disabled-tab-bottom-radius);
207
240
  cursor: not-allowed;
208
241
  }
209
242
 
210
243
  .tab.icon-only {
211
244
  padding: var(--space-8) var(--space-12);
212
245
  }
213
-
214
- .tab:hover:not(:disabled):not(.active) i,
215
- .tab-bar.force-hover .tab:not(:disabled):not(.active) i {
216
- font-size: var(--tabbar-hover-icon-size);
217
- }
218
-
219
- .tab.active i {
220
- font-size: var(--tabbar-active-icon-size);
221
- }
222
-
223
- .tab:disabled i {
224
- font-size: var(--tabbar-disabled-icon-size);
225
- }
226
-
227
- .tab i {
228
- font-size: var(--tabbar-default-icon-size);
229
- }
230
246
  </style>
@@ -11,9 +11,12 @@
11
11
  </div>
12
12
 
13
13
  <style lang="scss">
14
+ @use '../styles/padding' as *;
15
+
14
16
  :global(:root) {
15
17
  /* Wrapper */
16
18
  --table-default-radius: var(--radius-md);
19
+ --table-default-surface: var(--color-transparent);
17
20
  --table-default-border: var(--border-canvas-subtle);
18
21
  --table-default-border-width: var(--border-width-1);
19
22
  --table-default-shadow: var(--shadow-md);
@@ -38,9 +41,10 @@
38
41
  --table-default-cell-padding: var(--space-8);
39
42
 
40
43
  /* Row */
44
+ --table-default-row-surface: var(--color-transparent);
41
45
  --table-default-row-divider: var(--border-canvas-faint);
42
46
  --table-default-row-divider-width: var(--border-width-1);
43
- --table-default-row-stripe-surface: var(--surface-canvas-lower);
47
+ --table-default-row-stripe-surface: var(--color-transparent);
44
48
 
45
49
  /* Column */
46
50
  --table-default-column-divider: var(--border-canvas-faint);
@@ -51,6 +55,7 @@
51
55
  overflow-x: auto;
52
56
  margin: var(--space-12) 0;
53
57
  -webkit-overflow-scrolling: touch;
58
+ background: var(--table-default-surface);
54
59
  border: var(--table-default-border-width) solid var(--table-default-border);
55
60
  border-radius: var(--table-default-radius);
56
61
  box-shadow: var(--table-default-shadow);
@@ -70,7 +75,7 @@
70
75
  font-size: var(--table-default-header-font-size);
71
76
  font-weight: var(--table-default-header-font-weight);
72
77
  line-height: var(--table-default-header-line-height);
73
- padding: var(--table-default-header-padding);
78
+ @include themed-padding(--table-default-header-padding);
74
79
  text-align: left;
75
80
  border-bottom: var(--table-default-header-border-width) solid var(--table-default-header-border);
76
81
  border-right: var(--table-default-column-divider-width) solid var(--table-default-column-divider);
@@ -78,6 +83,7 @@
78
83
  }
79
84
 
80
85
  .table-wrapper :global(td) {
86
+ background: var(--table-default-row-surface);
81
87
  color: var(--table-default-cell-text);
82
88
  font-family: var(--table-default-cell-font-family);
83
89
  font-size: var(--table-default-cell-font-size);
@@ -97,8 +103,16 @@
97
103
  border-right: none;
98
104
  }
99
105
 
106
+ /* Stripe is layered over the base row surface as a background-image, so a
107
+ translucent stripe color blends with the base instead of replacing it.
108
+ An opaque stripe still covers the base (visually identical to the old
109
+ replacement behavior); a fully transparent stripe leaves the base
110
+ untouched, which is the default out of the box. */
100
111
  .table-wrapper :global(tr:nth-child(even) td) {
101
- background: var(--table-default-row-stripe-surface);
112
+ background-image: linear-gradient(
113
+ var(--table-default-row-stripe-surface),
114
+ var(--table-default-row-stripe-surface)
115
+ );
102
116
  }
103
117
 
104
118
  .table-wrapper :global(tr:last-child td) {
@@ -23,7 +23,9 @@
23
23
  {/if}
24
24
  </div>
25
25
 
26
- <style>
26
+ <style lang="scss">
27
+ @use '../styles/padding' as *;
28
+
27
29
  :global(:root) {
28
30
  --tooltip-surface: var(--surface-neutral-highest);
29
31
  --tooltip-text: var(--text-primary);
@@ -50,7 +52,7 @@
50
52
  transform: translateX(-50%);
51
53
  background: var(--tooltip-surface);
52
54
  color: var(--tooltip-text);
53
- padding: var(--tooltip-padding) calc(var(--tooltip-padding) * 2);
55
+ @include themed-padding(--tooltip-padding, $h: 2);
54
56
  border: var(--tooltip-border-width) solid var(--tooltip-border);
55
57
  border-radius: var(--tooltip-radius);
56
58
  font-family: var(--tooltip-text-font-family);
@@ -68,7 +70,7 @@
68
70
  .tooltip::after {
69
71
  content: '';
70
72
  position: absolute;
71
- bottom: calc(-4px - var(--tooltip-border-width) * 1px);
73
+ bottom: calc(-4px - var(--tooltip-border-width));
72
74
  left: 50%;
73
75
  width: 8px;
74
76
  height: 8px;
@@ -86,7 +88,7 @@
86
88
 
87
89
  .tooltip.bottom::after {
88
90
  bottom: auto;
89
- top: calc(-4px - var(--tooltip-border-width) * 1px);
91
+ top: calc(-4px - var(--tooltip-border-width));
90
92
  border-right: none;
91
93
  border-bottom: none;
92
94
  border-left: var(--tooltip-border-width) solid var(--tooltip-border);
@@ -0,0 +1,178 @@
1
+ # Token naming conventions
2
+
3
+ This project uses a **two-layer token system**. Read this before adding or renaming a CSS custom property.
4
+
5
+ ## Files in this directory
6
+
7
+ Each file plays a distinct role. Don't merge them without understanding why they were split.
8
+
9
+ | File | Scope | Tokens used | Loaded by | Notes |
10
+ |---|---|---|---|---|
11
+ | `tokens.css` | Themed pages | Defines `--color-*`, `--surface-*`, `--text-*`, `--space-*`, … | `main.ts` | **Runtime-edited.** The token editor rewrites this file via the `themeFileApi` Vite plugin. Starter content; consumers replace at will. |
12
+ | `ui-editor.css` | Editor chrome only | Defines `--ui-*` (opaque grayscale, system fonts) | JS-imported by `Editor.svelte` and `ComponentEditorPage.svelte` | Deliberately isolated from the theme system so editor surfaces stay neutral while live theme edits flow through the components being edited. Never load globally. |
13
+ | `ui-form-controls.css` | Editor chrome only | Consumes `--ui-*` only | JS-imported by `Editor.svelte` and `ComponentEditorPage.svelte` | `.ui-form-select` / `.ui-form-input` / `.ui-form-field-*` classes. Used by `ProjectFontsSection`, `FontStackEditor`, `DialogEditor`, `NotificationEditor`. Theme-immune — must not reference `--font-*`, `--surface-*`, etc. |
14
+ | `site.css` | Themed pages | Consumes theme tokens | Page-imported by `Home.svelte` | Consumer-facing starter typography for the landing page (unscoped `h1`, `p`, `a`, …). Never load on editor pages. Replaceable starter content — users edit or replace this file to style their own site. Components that take slot content (Card body, CollapsibleSection content) defend their typography aliases against these global rules via `:global(p) { font: inherit; color: inherit; }`. The demo page no longer imports it; the demo uses scoped classes and component-owned slot typography instead. |
15
+ | `fonts.css` + `fonts/` | Themed pages only | n/a (`@font-face` only) | `main.ts` | Build-special-cased: copied directly to `dist/` without processing so Vite doesn't inline woff2 files as base64. Starter content; editor's font invariant means these never affect chrome. |
16
+
17
+ ### Publishing layout
18
+
19
+ The library publishes a small set of subpaths:
20
+
21
+ - `./styles/ui-editor.css` — read-only window onto the editor's `--ui-*` token contract (for theming inspection or debugging). Consumers don't *need* to import this; the editor pages auto-load it.
22
+ - `./starter/tokens.css`, `./starter/site.css`, `./starter/fonts.css` — replaceable starter content. Consumers can import as-is for a working default, or copy + edit.
23
+
24
+ `ui-form-controls.css` is editor-internal and not exported — the editor pages script-import it themselves.
25
+
26
+ ### Editor font invariant
27
+
28
+ Editor chrome uses **only** the `--ui-*` font namespace (`--ui-font-sans`, `--ui-font-mono`, `--ui-font-size-*`, etc.), which `ui-editor.css` defines as a pure system stack. No editor-namespace rule may reference `var(--font-sans)`, `var(--font-serif)`, `var(--font-display)`, or `var(--font-mono)` — those are the consumer's theme fonts and must not bleed into chrome. This invariant is what closes the "editor adopts consumer brand fonts" leak.
29
+
30
+ ### When to put a rule where
31
+
32
+ - It defines a `--color-*` / `--surface-*` / `--space-*` / etc. → `tokens.css`.
33
+ - It defines a `--ui-*` token → `ui-editor.css`.
34
+ - It styles a bare element selector (`h1`, `p`, `blockquote`) on themed pages → `site.css`.
35
+ - It styles editor chrome → put it in the component's own `<style>` block using `--ui-*` tokens; don't add a new global file.
36
+ - It declares an `@font-face` → `fonts.css` (and add the woff2 to `fonts/`).
37
+
38
+ ## Layer 1 — theme tokens (`tokens.css`)
39
+
40
+ Theme tokens are the design system's vocabulary. They describe colors, sizes, spacing, shadows, and motion: the things a designer reasons about independent of any one component. Components consume them, and themes in `themes/*.json` recolor or re-scale them.
41
+
42
+ ### Category-first naming
43
+
44
+ Every theme token starts with a **category prefix**. The category tells you what *kind* of value lives at that key:
45
+
46
+ | Category | What it holds |
47
+ |----------------|-----------------------------------------------------------------|
48
+ | `--color-*` | Primitive color palette (e.g. `--color-accent-500`) |
49
+ | `--surface-*` | Fill/background colors, with elevation tiers |
50
+ | `--border-*` | Border colors, with emphasis tiers |
51
+ | `--text-*` | Text colors, with hierarchy tiers |
52
+ | `--font-*` | Font families and weights |
53
+ | `--font-size-*`| Font sizes (explicit subcategory to avoid colliding with families) |
54
+ | `--space-*` | Spacing scale, values encoded in the name (`--space-8` = 8px) |
55
+ | `--radius-*` | Border radii (t-shirt scale) |
56
+ | `--shadow-*` | Elevation shadows |
57
+ | `--ring-*` | Focus rings (separate namespace from shadows) |
58
+ | `--border-width-*` | Stroke widths |
59
+ | `--transition-*`, `--opacity-*`, `--z-*` | Animation, opacity, z-index scales |
60
+ | `--overlay-*`, `--hover-*` | Semantic overlay tints |
61
+ | `--gradient-*` | Named gradients |
62
+ | `--columns-*`, `--page-*` | Page-level layout primitives |
63
+
64
+ **Rule: a bare one-word token belongs to *some* category.** If you find yourself writing `--overlay` or `--border`, make sure the category is obvious and it's the canonical default. Otherwise pick a longer name that slots it into its family (e.g. `--border-neutral`).
65
+
66
+ ### Families within a category
67
+
68
+ Color categories (`--surface-*`, `--border-*`, `--text-*`) partition into **families**: `neutral`, `canvas`, `primary` (*→ brand, rename pending*), `accent`, `success`, `warning`, `danger`, `info`, `special`, `alternate`. Each family carries its own emphasis/elevation scale suited to its role: 7-step elevation for surfaces, 4-step emphasis for borders, 5-step hierarchy for text. They differ on purpose.
69
+
70
+ ### Scales
71
+
72
+ Two shapes appear:
73
+
74
+ - **T-shirt scale** (`-xs / -sm / -md / -lg / -xl / -2xl …`). Used for `--radius-*`, `--font-size-*`, `--shadow-*`, `--ring-focus-*`.
75
+ - **Numeric scale.** `--color-*-100` through `--color-*-950` for palettes; `--space-4 / -8 / -16 / …` (value encoded in the name).
76
+
77
+ Don't invent a third scale shape for a new category.
78
+
79
+ ## Layer 2 — component tokens (`component-configs/*/default.json` + component Svelte files)
80
+
81
+ Component tokens *reference* theme tokens. They're how a component names its own slots: "my bar's surface color", "my selected option's border width". The config file records which theme alias is currently assigned to each slot.
82
+
83
+ ### The naming scheme
84
+
85
+ ```
86
+ --<componentId>-<part>[-<state>][-<element>]-<property>
87
+ ```
88
+
89
+ - **`componentId`.** The literal component ID. No abbreviations. The ID itself has no dashes (it's the file-system-safe form: `segmentedcontrol`, not `segmented-control`).
90
+ - **`part`.** Which part of the component this slot belongs to: `bar`, `divider`, `option`, `selected`, `track`, `save`, `cancel`, etc.
91
+ - **`state`.** Optional. The interaction state if more than default: `hover`, `disabled`, `active`, `focus`. States come **before** the property, never after.
92
+ - **`element`.** Optional. A sub-element within the part: `dot`, `icon`, `label`, `text`.
93
+ - **`property`.** Always last. Either a **theme role** (`surface`, `border`, `text`, `icon`, `label`, `fill`) or a **CSS property name** (`radius`, `border-width`, `font-weight`, `font-family`, `font-size`).
94
+
95
+ ### No abbreviations
96
+
97
+ - `bg` → `surface` (matches the theme role name and the theme layer's full-word vocabulary).
98
+ - `fg` → `text`.
99
+ - Component IDs are never abbreviated. Use `--segmentedcontrol-*`, not `--segment-*` or `--sc-*`.
100
+
101
+ ### Property suffix vocabulary
102
+
103
+ | Suffix | Meaning |
104
+ |----------------|--------------------------------------------------------------|
105
+ | `-surface` | Fill/background color |
106
+ | `-border` | Border color |
107
+ | `-text` | Text color |
108
+ | `-icon` | Icon color |
109
+ | `-label` | Label text color |
110
+ | `-fill` | Inner fill (distinct from outer surface) |
111
+ | `-radius` | Corner radius |
112
+ | `-border-width`| Stroke thickness |
113
+ | `-font-family` | Font family reference |
114
+ | `-font-weight` | Font weight reference |
115
+ | `-font-size` | Font size reference |
116
+ | `-thickness` | Alternative stroke dimension (used where `-width` would alias another token under name-based fallback grouping) |
117
+ | `-height` | Explicit height when `-width`'s sibling would collide under name-based fallback grouping |
118
+ | `-color` | Generic color when none of the role words fits (rare) |
119
+
120
+ **Why `thickness` and `height` sometimes stand in for `width`:** when an editor declares no explicit `groupKey` for a token, sibling grouping falls back to matching the final `-<property>` segment. If two unrelated slots both end in `-width` and neither has a `groupKey`, they get auto-linked. Either declare a `groupKey` per token in the editor (preferred) or use an alternative property word. The divider in SegmentedControl uses `--segmentedcontrol-divider-thickness` for legacy parity with the fallback rule, but it now also has `groupKey: 'divider-thickness'` declared in the editor. The `groupKey` is the source of truth.
121
+
122
+ ### State order matters
123
+
124
+ State comes **before** the property, not after:
125
+
126
+ ```
127
+ --inlineeditactions-save-hover-surface ✓ state before property; siblings on `-surface`
128
+ --inlineeditactions-save-surface-hover ✗ breaks sibling matching and reads oddly
129
+ ```
130
+
131
+ ### Linked siblings (the link toggle)
132
+
133
+ Tokens that share a `groupKey` form a **sibling set**. A property declared `canBeLinked: true` in the editor shows a link toggle that lets the user broadcast one value across every sibling. So in SegmentedControl:
134
+
135
+ - `--segmentedcontrol-bar-border-width` and `--segmentedcontrol-selected-border-width` share `groupKey: 'border-width'`.
136
+ - `--segmentedcontrol-option-text-font-weight`, `--segmentedcontrol-option-disabled-text-font-weight`, and `--segmentedcontrol-selected-text-font-weight` share `groupKey: 'font-weight'`.
137
+
138
+ Editor authors declare `groupKey` per token in the editor's token list (and call `registerComponentSchema(component, tokens)` once at module load). The store consults the schema first; for unmigrated editors with no schema entry, it falls back to matching the last `-<property>` segment. Tokens with neither a `groupKey` nor a colliding name suffix are solo.
139
+
140
+ Linkage is **dev-declared** — the editor schema is the source of truth for which variables share a `groupKey`. Users only choose whether to opt out of an existing link (per-property), never to add or reshape one.
141
+
142
+ The `unlinked` array on a `ComponentSlice` stores the variable names the user has explicitly detached. The remaining declared siblings stay linked to each other; an unlinked variable rejoins via `setComponentAliasLinked` or `relinkComponentProperty`.
143
+
144
+ ### Typography slot scoping
145
+
146
+ When a component declares more than one typography slot — e.g. a notification with separate `title` and `text` slots — every typography `groupKey` (`font-family`, `font-size`, `font-weight`, `line-height`) **must** include the slot name as a prefix:
147
+
148
+ ```
149
+ groupKey: 'title-font-family', 'text-font-family' ✓ one link tree per slot
150
+ groupKey: 'font-family' ✗ silently links title and text together
151
+ ```
152
+
153
+ A bare typography `groupKey` like `'font-family'` is fine when the component has only one typography slot (Button has only `text`; RadioButton only `label`; CollapsibleSection only `label`). Add a slot prefix the moment the component grows a second slot.
154
+
155
+ `registerComponentSchema` emits a console warning at runtime if a single `groupKey` covers variables whose name-derived slots differ. Treat that warning as a build-time error.
156
+
157
+ ### When the last-dash fallback surprises you
158
+
159
+ For tokens without an explicit `groupKey`, the store derives one by splitting on the last dash:
160
+
161
+ - `--segmentedcontrol-option-text-font-weight` → fallback groupKey `weight`.
162
+
163
+ So the fallback property is always the literal last segment. If you don't want a token to participate in the fallback grouping, declare an explicit `groupKey` (or omit `canBeLinked`).
164
+
165
+ ## Checklist for adding a new component token
166
+
167
+ 1. Does the value belong at the **theme layer**? (It's a color or scale that multiple components could reuse.) → Add it to `tokens.css` under the correct category, not here.
168
+ 2. Pick a **componentId** matching the one used in `component-configs/` and the editor's `const component = '...'` literal.
169
+ 3. Build the name as `--<componentId>-<part>[-<state>]-<property>`.
170
+ 4. Use **full words**: no `bg`, no shortened component IDs.
171
+ 5. Declare the slot in both the component's Svelte `<style>` (`--tok: var(--theme-alias);`) and the config JSON (`"--tok": "--theme-alias"`).
172
+ 6. If the slot should link across variants, add `canBeLinked: true` and `groupKey: '<your-key>'` in the editor's token list. Siblings are tokens that share the same `groupKey`. Pick a `groupKey` that names the kind of property (`radius`, `border-width`, `font-weight`, `font-family`, etc.); a unique key isolates a token from any other. For typography on multi-slot components, prefix the slot name (see "Typography slot scoping").
173
+ 7. Make sure the editor calls `registerComponentSchema(component, tokens)` once at module load so the store sees the explicit groupKeys.
174
+
175
+ ## What's still pending
176
+
177
+ - **`primary` → `brand` rename.** Disambiguates the emphasis-tier, color-family, and component-variant uses of "primary." Tracked in `temp/primary-to-brand-rename.md`.
178
+ - **Theme-layer cleanups** tracked in `temp/theme-token-improvements.md`: font-weight scale normalization, bare-word orphan audit, full `bg` → `canvas` sweep.
@@ -0,0 +1,20 @@
1
+ /* Generated from the production theme by syncFontsToCss. Do not edit. */
2
+ /* Both fonts.css and fonts/ are in dist/, so relative paths work at runtime. */
3
+
4
+ /* Adobe Typekit — fira-code */
5
+ @import url('https://use.typekit.net/jes8oow.css');
6
+
7
+ /* Google Fonts — Arvo */
8
+ @import url('https://fonts.googleapis.com/css2?family=Arvo:ital,wght@0,400;0,700;1,400;1,700&display=swap');
9
+
10
+ /* Google Fonts — GFS Didot */
11
+ @import url('https://fonts.googleapis.com/css2?family=GFS+Didot&display=swap');
12
+
13
+ /* Local — Manrope */
14
+ @font-face {
15
+ font-family: "Manrope";
16
+ src: url('/src/system/styles/fonts/Manrope/Manrope-latin.woff2') format('woff2');
17
+ font-weight: 200 800;
18
+ font-style: normal;
19
+ font-display: swap;
20
+ }