@motion-proto/live-tokens 0.67.1 → 0.69.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 (138) hide show
  1. package/.claude/skills/live-tokens-build-page/SKILL.md +16 -5
  2. package/.claude/skills/live-tokens-create-component/SKILL.md +43 -8
  3. package/.claude/skills/live-tokens-create-component/references/token-naming.md +30 -1
  4. package/.claude/skills/live-tokens-fix-findings/SKILL.md +131 -0
  5. package/.claude/skills/live-tokens-pick-component/SKILL.md +2 -1
  6. package/CHANGELOG.md +239 -0
  7. package/README.md +11 -4
  8. package/bin/check-component.mjs +367 -63
  9. package/bin/check-page.mjs +409 -0
  10. package/bin/cli.mjs +57 -8
  11. package/bin/generate-theme.mjs +5 -4
  12. package/bin/lib/cssValues.mjs +50 -0
  13. package/bin/lib/findings.mjs +106 -0
  14. package/bin/lib/tokenVocabulary.mjs +213 -0
  15. package/dist-plugin/adjust/index.cjs +174 -23
  16. package/dist-plugin/adjust/index.d.cts +1 -1
  17. package/dist-plugin/adjust/index.d.ts +1 -1
  18. package/dist-plugin/adjust/index.js +68 -23
  19. package/dist-plugin/{chunk-J2JT4UEA.js → chunk-2YNERPXY.js} +26 -26
  20. package/dist-plugin/{chunk-NE6N66EE.js → chunk-GPIBU44G.js} +107 -1
  21. package/dist-plugin/{chunk-ZHPX7ZYQ.js → chunk-RFVYPNRO.js} +39 -1
  22. package/dist-plugin/{dataPaths-DZUzVv8H.d.ts → dataPaths-bJTCEO4H.d.cts} +1 -1
  23. package/dist-plugin/{dataPaths-DZUzVv8H.d.cts → dataPaths-bJTCEO4H.d.ts} +1 -1
  24. package/dist-plugin/fontPairing/index.d.cts +1 -1
  25. package/dist-plugin/fontPairing/index.d.ts +1 -1
  26. package/dist-plugin/generateColorsAndType/index.cjs +107 -1
  27. package/dist-plugin/generateColorsAndType/index.d.cts +1 -1
  28. package/dist-plugin/generateColorsAndType/index.d.ts +1 -1
  29. package/dist-plugin/generateColorsAndType/index.js +1 -1
  30. package/dist-plugin/index.cjs +173 -29
  31. package/dist-plugin/index.d.cts +1 -1
  32. package/dist-plugin/index.d.ts +1 -1
  33. package/dist-plugin/index.js +7 -7
  34. package/dist-plugin/migrateData/index.cjs +132 -26
  35. package/dist-plugin/migrateData/index.d.cts +1 -1
  36. package/dist-plugin/migrateData/index.d.ts +1 -1
  37. package/dist-plugin/migrateData/index.js +2 -2
  38. package/dist-plugin/tokensCssMigrations/index.cjs +39 -1
  39. package/dist-plugin/tokensCssMigrations/index.d.cts +1 -1
  40. package/dist-plugin/tokensCssMigrations/index.d.ts +1 -1
  41. package/dist-plugin/tokensCssMigrations/index.js +1 -1
  42. package/package.json +6 -5
  43. package/src/app/site.css +4 -4
  44. package/src/editor/bootstrap.ts +6 -6
  45. package/src/editor/component-editor/ButtonEditor.svelte +71 -4
  46. package/src/editor/component-editor/CardEditor.svelte +6 -6
  47. package/src/editor/component-editor/DialogEditor.svelte +3 -3
  48. package/src/editor/component-editor/IconButtonEditor.svelte +68 -3
  49. package/src/editor/component-editor/ImageEditor.svelte +8 -8
  50. package/src/editor/component-editor/ImageLightboxEditor.svelte +13 -2
  51. package/src/editor/component-editor/MenuSelectEditor.svelte +63 -3
  52. package/src/editor/component-editor/SegmentedControlEditor.svelte +63 -3
  53. package/src/editor/component-editor/SideNavigationEditor.svelte +67 -3
  54. package/src/editor/component-editor/SliderEditor.svelte +186 -0
  55. package/src/editor/component-editor/TabBarEditor.svelte +63 -3
  56. package/src/editor/component-editor/registry.ts +10 -0
  57. package/src/editor/component-editor/scaffolding/ComponentFileManager.svelte +4 -4
  58. package/src/editor/core/components/aliasKinds.ts +51 -28
  59. package/src/editor/core/fonts/fontLoader.ts +2 -2
  60. package/src/editor/core/preview/{lookPreview.ts → themePreview.ts} +27 -27
  61. package/src/editor/core/productionPulse.ts +3 -3
  62. package/src/editor/core/sketch/index.ts +52 -44
  63. package/src/editor/core/sketch/maskField.ts +9 -9
  64. package/src/editor/core/sketch/sketchLayer.ts +25 -9
  65. package/src/editor/core/sketch/sketchRegistry.ts +34 -34
  66. package/src/editor/core/sketch/sketchStore.ts +98 -83
  67. package/src/editor/core/sketch/sketchStyleService.ts +4 -4
  68. package/src/editor/core/sketch/sketchStyles.ts +28 -28
  69. package/src/editor/core/store/editorPersistence.ts +44 -1
  70. package/src/editor/core/store/editorRenderer.ts +2 -2
  71. package/src/editor/core/store/editorStore.ts +18 -18
  72. package/src/editor/core/store/editorTypes.ts +7 -6
  73. package/src/editor/core/themes/colorsAndTypeService.ts +1 -1
  74. package/src/editor/core/themes/loadRows.ts +8 -8
  75. package/src/editor/core/themes/migrations/2026-09-01-gate-suffix-enabled.ts +31 -0
  76. package/src/editor/core/themes/migrations/2026-09-01-scrim-rename.ts +52 -0
  77. package/src/editor/core/themes/migrations/2026-09-01-tabbar-active-tint.ts +27 -0
  78. package/src/editor/core/themes/migrations/2026-09-01-tint-rename.ts +42 -0
  79. package/src/editor/core/themes/migrations/index.ts +16 -0
  80. package/src/editor/core/themes/slices/domainVars.ts +2 -2
  81. package/src/editor/core/themes/slices/washes.ts +107 -0
  82. package/src/editor/core/themes/themeDocumentSync.ts +2 -2
  83. package/src/editor/core/themes/themeInit.ts +2 -2
  84. package/src/editor/core/themes/themeService.ts +17 -17
  85. package/src/editor/core/themes/{lookSummary.ts → themeSummary.ts} +9 -9
  86. package/src/editor/core/themes/themeTypes.ts +10 -6
  87. package/src/editor/docs/content/editing-tokens.md +5 -3
  88. package/src/editor/docs/content/getting-started.md +1 -1
  89. package/src/editor/docs/content/sketch-mode.md +22 -17
  90. package/src/editor/docs/content/themes-workflow.md +11 -11
  91. package/src/editor/docs/content/where-themes-live.md +6 -6
  92. package/src/editor/docs/content.generated.ts +5 -5
  93. package/src/editor/index.ts +2 -2
  94. package/src/editor/pages/EditorShell.svelte +1 -1
  95. package/src/editor/ui/SurfacesTab.svelte +3 -3
  96. package/src/editor/ui/ThemePanel.svelte +52 -52
  97. package/src/editor/ui/UITokenSelector.svelte +1 -0
  98. package/src/editor/ui/VariablesTab.svelte +2 -2
  99. package/src/editor/ui/sections/{OverlaysSection.svelte → WashesSection.svelte} +44 -43
  100. package/src/editor/ui/sketch/SketchPreview.svelte +2 -2
  101. package/src/editor/ui/sketch/SketchTab.svelte +64 -38
  102. package/src/live-tokens/data/colors-and-type/autumn.json +6 -6
  103. package/src/live-tokens/data/colors-and-type/default.json +6 -6
  104. package/src/live-tokens/data/colors-and-type/halloween.json +6 -6
  105. package/src/live-tokens/data/colors-and-type/midnight-study.json +6 -6
  106. package/src/live-tokens/data/colors-and-type/ocean.json +6 -6
  107. package/src/live-tokens/data/colors-and-type/royal-velvet.json +6 -6
  108. package/src/live-tokens/data/colors-and-type/sketchy.json +6 -6
  109. package/src/live-tokens/data/colors-and-type/spring-meadow.json +6 -6
  110. package/src/live-tokens/data/colors-and-type/sunset.json +6 -6
  111. package/src/live-tokens/data/sketch-styles/dry.json +5 -5
  112. package/src/live-tokens/data/sketch-styles/hatched.json +9 -9
  113. package/src/live-tokens/data/themes/autumn.json +82 -14
  114. package/src/live-tokens/data/themes/halloween.json +82 -14
  115. package/src/live-tokens/data/themes/midnight-study.json +82 -14
  116. package/src/live-tokens/data/themes/ocean.json +82 -14
  117. package/src/live-tokens/data/themes/royal-velvet.json +82 -14
  118. package/src/live-tokens/data/themes/sketchy.json +82 -14
  119. package/src/live-tokens/data/themes/spring-meadow.json +82 -14
  120. package/src/live-tokens/data/themes/sunset.json +82 -14
  121. package/src/live-tokens/data/tokens.generated.css +6 -6
  122. package/src/system/backdrop/backdrop.ts +1 -1
  123. package/src/system/components/Button.svelte +28 -10
  124. package/src/system/components/Card.svelte +6 -6
  125. package/src/system/components/Dialog.svelte +3 -3
  126. package/src/system/components/IconButton.svelte +23 -7
  127. package/src/system/components/Image.svelte +6 -6
  128. package/src/system/components/MenuSelect.svelte +17 -1
  129. package/src/system/components/SectionDivider.svelte +1 -1
  130. package/src/system/components/SegmentedControl.svelte +20 -2
  131. package/src/system/components/SideNavigation.svelte +22 -2
  132. package/src/system/components/Slider.svelte +348 -0
  133. package/src/system/components/TabBar.svelte +20 -2
  134. package/src/system/styles/CONVENTIONS.md +2 -2
  135. package/src/system/styles/tokens.css +12 -4
  136. package/template/package.json +3 -2
  137. package/template/src/pages/Home.svelte +1 -1
  138. package/src/editor/core/themes/slices/overlays.ts +0 -101
@@ -1,5 +1,8 @@
1
1
  <script lang="ts">
2
2
  interface Props {
3
+ /** Wash the hovered surface with the theme's tint. `undefined` inherits the
4
+ global default; `true`/`false` force this instance on/off. */
5
+ hoverTint?: boolean | undefined;
3
6
  disabled?: boolean;
4
7
  type?: 'button' | 'submit' | 'reset';
5
8
  variant?: 'primary' | 'secondary' | 'outline' | 'success' | 'danger' | 'warning';
@@ -14,6 +17,7 @@
14
17
  }
15
18
 
16
19
  let {
20
+ hoverTint = undefined,
17
21
  disabled = false,
18
22
  type = 'button',
19
23
  variant = 'primary',
@@ -26,12 +30,18 @@
26
30
  onclick
27
31
  }: Props = $props();
28
32
 
33
+ // Per-instance override of the global hover-tint intrinsic; undefined leaves :root in charge.
34
+ let hoverTintValue = $derived(
35
+ hoverTint === undefined ? undefined : hoverTint ? 'var(--iconbutton-hover-tint)' : 'var(--color-transparent)',
36
+ );
37
+
29
38
  function handleClick(event: MouseEvent) {
30
39
  if (!disabled) onclick?.(event);
31
40
  }
32
41
  </script>
33
42
 
34
43
  <button
44
+ style:--iconbutton-hover-tint-enabled={hoverTintValue}
35
45
  bind:this={buttonRef}
36
46
  {type}
37
47
  class="icon-button {variant} {className}"
@@ -48,6 +58,11 @@
48
58
  @use '../styles/padding' as *;
49
59
 
50
60
  :global(:root) {
61
+ /* Hover tint: an optional wash over the hovered surface, one stop for the
62
+ whole component. Off by default; the gate holds the tint when enabled. */
63
+ --iconbutton-hover-tint: var(--tint);
64
+ --iconbutton-hover-tint-enabled: var(--color-transparent);
65
+
51
66
  /* Primary */
52
67
  --iconbutton-primary-surface: var(--surface-brand);
53
68
  --iconbutton-primary-icon: var(--text-primary);
@@ -89,7 +104,7 @@
89
104
  --iconbutton-outline-hover-surface: var(--surface-neutral-lower);
90
105
  --iconbutton-outline-hover-icon: var(--text-primary);
91
106
  --iconbutton-outline-hover-border: var(--border-neutral-strong);
92
- --iconbutton-outline-active-surface: var(--hover);
107
+ --iconbutton-outline-active-surface: var(--surface-neutral-low);
93
108
  --iconbutton-outline-disabled-surface: var(--color-transparent);
94
109
  --iconbutton-outline-disabled-icon: var(--text-tertiary);
95
110
  --iconbutton-outline-disabled-border: var(--border-neutral-faint);
@@ -154,6 +169,7 @@
154
169
 
155
170
  &:hover:not(:disabled),
156
171
  &.force-hover:not(:disabled) {
172
+ background-image: linear-gradient(var(--iconbutton-hover-tint-enabled), var(--iconbutton-hover-tint-enabled));
157
173
  transform: translateY(-0.0625rem);
158
174
  box-shadow: var(--shadow-md);
159
175
  }
@@ -176,7 +192,7 @@
176
192
 
177
193
  &:hover:not(:disabled),
178
194
  &.force-hover:not(:disabled) {
179
- background: var(--iconbutton-primary-hover-surface);
195
+ background-color: var(--iconbutton-primary-hover-surface);
180
196
  border-color: var(--iconbutton-primary-hover-border);
181
197
  color: var(--iconbutton-primary-hover-icon);
182
198
  }
@@ -202,7 +218,7 @@
202
218
 
203
219
  &:hover:not(:disabled),
204
220
  &.force-hover:not(:disabled) {
205
- background: var(--iconbutton-secondary-hover-surface);
221
+ background-color: var(--iconbutton-secondary-hover-surface);
206
222
  border-color: var(--iconbutton-secondary-hover-border);
207
223
  color: var(--iconbutton-secondary-hover-icon);
208
224
  }
@@ -224,7 +240,7 @@
224
240
 
225
241
  &:hover:not(:disabled),
226
242
  &.force-hover:not(:disabled) {
227
- background: var(--iconbutton-outline-hover-surface);
243
+ background-color: var(--iconbutton-outline-hover-surface);
228
244
  border-color: var(--iconbutton-outline-hover-border);
229
245
  color: var(--iconbutton-outline-hover-icon);
230
246
  }
@@ -251,7 +267,7 @@
251
267
 
252
268
  &:hover:not(:disabled),
253
269
  &.force-hover:not(:disabled) {
254
- background: var(--iconbutton-success-hover-surface);
270
+ background-color: var(--iconbutton-success-hover-surface);
255
271
  border-color: var(--iconbutton-success-hover-border);
256
272
  color: var(--iconbutton-success-hover-icon);
257
273
  }
@@ -273,7 +289,7 @@
273
289
 
274
290
  &:hover:not(:disabled),
275
291
  &.force-hover:not(:disabled) {
276
- background: var(--iconbutton-danger-hover-surface);
292
+ background-color: var(--iconbutton-danger-hover-surface);
277
293
  border-color: var(--iconbutton-danger-hover-border);
278
294
  color: var(--iconbutton-danger-hover-icon);
279
295
  }
@@ -295,7 +311,7 @@
295
311
 
296
312
  &:hover:not(:disabled),
297
313
  &.force-hover:not(:disabled) {
298
- background: var(--iconbutton-warning-hover-surface);
314
+ background-color: var(--iconbutton-warning-hover-surface);
299
315
  border-color: var(--iconbutton-warning-hover-border);
300
316
  color: var(--iconbutton-warning-hover-icon);
301
317
  }
@@ -65,8 +65,8 @@
65
65
  class="image"
66
66
  class:force-hover={forceHover}
67
67
  style:height={resolvedHeight}
68
- style:--image-zoom-hover={contentHover}
69
- style:--image-grow-hover={frameHover}
68
+ style:--image-zoom-enabled={contentHover}
69
+ style:--image-grow-enabled={frameHover}
70
70
  >
71
71
  <img {src} {alt} {srcset} {sizes} {loading} {decoding} />
72
72
  </div>
@@ -81,8 +81,8 @@
81
81
  /* Hover-scale targets. Contained mode (`overflowScaling`) scales the content within the
82
82
  masked frame; grow mode scales the whole frame so it grows past its box. Each is `none`
83
83
  (off) or `scale(var(--image-zoom-scale))` (on); only one is ever on at a time. */
84
- --image-zoom-hover: none;
85
- --image-grow-hover: none;
84
+ --image-zoom-enabled: none;
85
+ --image-grow-enabled: none;
86
86
  }
87
87
 
88
88
  .image {
@@ -106,11 +106,11 @@
106
106
 
107
107
  .image:hover,
108
108
  .image.force-hover {
109
- transform: var(--image-grow-hover);
109
+ transform: var(--image-grow-enabled);
110
110
  }
111
111
 
112
112
  .image:hover img,
113
113
  .image.force-hover img {
114
- transform: var(--image-zoom-hover);
114
+ transform: var(--image-zoom-enabled);
115
115
  }
116
116
  </style>
@@ -9,6 +9,9 @@
9
9
  };
10
10
 
11
11
  interface Props {
12
+ /** Wash the hovered surface with the theme's tint. `undefined` inherits the
13
+ global default; `true`/`false` force this instance on/off. */
14
+ hoverTint?: boolean | undefined;
12
15
  items?: Item[];
13
16
  value?: string;
14
17
  /** Editor preview: force-hover one item by value. */
@@ -22,6 +25,7 @@
22
25
  }
23
26
 
24
27
  let {
28
+ hoverTint = undefined,
25
29
  items = [],
26
30
  value = $bindable(''),
27
31
  forceHoverValue = null,
@@ -30,6 +34,11 @@
30
34
  onchange,
31
35
  }: Props = $props();
32
36
 
37
+ // Per-instance override of the global hover-tint intrinsic; undefined leaves :root in charge.
38
+ let hoverTintValue = $derived(
39
+ hoverTint === undefined ? undefined : hoverTint ? 'var(--menuselect-hover-tint)' : 'var(--color-transparent)',
40
+ );
41
+
33
42
  // Dual-fire bridge — see Button.svelte for the deprecation timeline.
34
43
  const dispatch = createEventDispatcher<{ change: string }>();
35
44
 
@@ -41,6 +50,7 @@
41
50
  </script>
42
51
 
43
52
  <ul
53
+ style:--menuselect-hover-tint-enabled={hoverTintValue}
44
54
  class="menuselect"
45
55
  {role}
46
56
  style:min-width={minWidth}
@@ -71,6 +81,11 @@
71
81
  @use '../styles/padding' as *;
72
82
 
73
83
  :global(:root) {
84
+ /* Hover tint: an optional wash over the hovered surface, one stop for the
85
+ whole component. Off by default; the gate holds the tint when enabled. */
86
+ --menuselect-hover-tint: var(--tint);
87
+ --menuselect-hover-tint-enabled: var(--color-transparent);
88
+
74
89
  /* Menu panel */
75
90
  --menuselect-menu-surface: color-mix(in srgb, var(--surface-neutral-lower) 95%, transparent);
76
91
  --menuselect-menu-border: var(--border-neutral-medium);
@@ -183,7 +198,8 @@
183
198
 
184
199
  .menuselect-item:hover:not(:disabled):not(.selected),
185
200
  .menuselect-item.force-hover:not(:disabled):not(.selected) {
186
- background: var(--menuselect-hover-surface);
201
+ background-color: var(--menuselect-hover-surface);
202
+ background-image: linear-gradient(var(--menuselect-hover-tint-enabled), var(--menuselect-hover-tint-enabled));
187
203
  color: var(--menuselect-hover-text);
188
204
  font-family: var(--menuselect-hover-text-font-family);
189
205
  font-size: var(--menuselect-hover-text-font-size);
@@ -3,7 +3,7 @@
3
3
 
4
4
  import { onMount, tick } from 'svelte';
5
5
 
6
- /** Size variant. Each variant owns everything that defines its look:
6
+ /** Size variant. Each variant owns everything that defines its style:
7
7
  * typography, geometry, colors AND the intrinsic display properties
8
8
  * (alignment, eyebrow visibility, description visibility, hairline
9
9
  * position). Every intrinsic flows through `:root` CSS vars so a designer
@@ -9,6 +9,9 @@
9
9
  };
10
10
 
11
11
  interface Props {
12
+ /** Wash the hovered surface with the theme's tint. `undefined` inherits the
13
+ global default; `true`/`false` force this instance on/off. */
14
+ hoverTint?: boolean | undefined;
12
15
  segments?: Segment[];
13
16
  value?: string;
14
17
  disabled?: boolean;
@@ -21,6 +24,7 @@
21
24
  }
22
25
 
23
26
  let {
27
+ hoverTint = undefined,
24
28
  segments = [],
25
29
  value = $bindable(''),
26
30
  disabled = false,
@@ -29,6 +33,11 @@
29
33
  onchange
30
34
  }: Props = $props();
31
35
 
36
+ // Per-instance override of the global hover-tint intrinsic; undefined leaves :root in charge.
37
+ let hoverTintValue = $derived(
38
+ hoverTint === undefined ? undefined : hoverTint ? 'var(--segmentedcontrol-hover-tint)' : 'var(--color-transparent)',
39
+ );
40
+
32
41
  // Dual-fire bridge — see Button.svelte for the deprecation timeline.
33
42
  const dispatch = createEventDispatcher<{ change: string }>();
34
43
 
@@ -39,7 +48,10 @@
39
48
  }
40
49
  </script>
41
50
 
42
- <div class="segmented-control" class:is-disabled={disabled} class:small={size === 'small'} role="radiogroup">
51
+ <div
52
+ class="segmented-control" class:is-disabled={disabled} class:small={size === 'small'} role="radiogroup"
53
+ style:--segmentedcontrol-hover-tint-enabled={hoverTintValue}
54
+ >
43
55
  {#each segments as seg, i (seg.value)}
44
56
  {#if i > 0}
45
57
  <span class="segment-divider" aria-hidden="true"></span>
@@ -64,6 +76,11 @@
64
76
  @use '../styles/padding' as *;
65
77
 
66
78
  :global(:root) {
79
+ /* Hover tint: an optional wash over the hovered surface, one stop for the
80
+ whole component. Off by default; the gate holds the tint when enabled. */
81
+ --segmentedcontrol-hover-tint: var(--tint);
82
+ --segmentedcontrol-hover-tint-enabled: var(--color-transparent);
83
+
67
84
  /* Bar (outer wrapper) */
68
85
  --segmentedcontrol-bar-surface: color-mix(in srgb, var(--surface-neutral-lowest) 75%, transparent);
69
86
  --segmentedcontrol-bar-border: var(--border-neutral);
@@ -252,13 +269,14 @@
252
269
 
253
270
  .segment:hover:not(:disabled):not(.selected),
254
271
  .segment.force-hover:not(:disabled):not(.selected) {
272
+ background-image: linear-gradient(var(--segmentedcontrol-hover-tint-enabled), var(--segmentedcontrol-hover-tint-enabled));
255
273
  --_text-color: var(--segmentedcontrol-option-hover-text);
256
274
  --_text-family: var(--segmentedcontrol-option-hover-text-font-family);
257
275
  --_text-size: var(--segmentedcontrol-option-hover-text-font-size);
258
276
  --_text-weight: var(--segmentedcontrol-option-hover-text-font-weight);
259
277
  --_text-line-height: var(--segmentedcontrol-option-hover-text-line-height);
260
278
  --_icon-color: var(--segmentedcontrol-option-hover-icon);
261
- background: var(--segmentedcontrol-option-hover-surface);
279
+ background-color: var(--segmentedcontrol-option-hover-surface);
262
280
  }
263
281
 
264
282
  /* Outline (not border) so the selection ring sits outside the box model.
@@ -26,6 +26,9 @@
26
26
  };
27
27
 
28
28
  interface Props {
29
+ /** Wash the hovered surface with the theme's tint. `undefined` inherits the
30
+ global default; `true`/`false` force this instance on/off. */
31
+ hoverTint?: boolean | undefined;
29
32
  sections?: SideNavSection[];
30
33
  footer?: SideNavFooter | undefined;
31
34
  titleLabel?: string;
@@ -51,6 +54,7 @@
51
54
  }
52
55
 
53
56
  let {
57
+ hoverTint = undefined,
54
58
  sections = [],
55
59
  footer = undefined,
56
60
  titleLabel = '',
@@ -66,6 +70,11 @@
66
70
  actions,
67
71
  }: Props = $props();
68
72
 
73
+ // Per-instance override of the global hover-tint intrinsic; undefined leaves :root in charge.
74
+ let hoverTintValue = $derived(
75
+ hoverTint === undefined ? undefined : hoverTint ? 'var(--sidenavigation-hover-tint)' : 'var(--color-transparent)',
76
+ );
77
+
69
78
  // Dual-fire bridge — see Button.svelte for the deprecation timeline.
70
79
  const dispatch = createEventDispatcher<{ toggle: void }>();
71
80
 
@@ -154,6 +163,7 @@
154
163
  </script>
155
164
 
156
165
  <aside
166
+ style:--sidenavigation-hover-tint-enabled={hoverTintValue}
157
167
  class="sidenavigation {className}"
158
168
  class:collapsed={!open}
159
169
  class:force-title-hover={forceHoverPart === 'title'}
@@ -241,6 +251,11 @@
241
251
  @use '../styles/padding' as *;
242
252
 
243
253
  :global(:root) {
254
+ /* Hover tint: an optional wash over the hovered surface, one stop for the
255
+ whole component. Off by default; the gate holds the tint when enabled. */
256
+ --sidenavigation-hover-tint: var(--tint);
257
+ --sidenavigation-hover-tint-enabled: var(--color-transparent);
258
+
244
259
  /* Panel — outer chrome + layout. No states. */
245
260
  --sidenavigation-panel-surface: var(--surface-canvas-lower);
246
261
  --sidenavigation-panel-border: var(--border-canvas-faint);
@@ -249,8 +264,8 @@
249
264
  --sidenavigation-panel-section-gap: var(--space-4);
250
265
  --sidenavigation-panel-item-padding: var(--space-32);
251
266
  --sidenavigation-panel-footer-gap: var(--space-16);
252
- --sidenavigation-panel-open-width: 16rem;
253
- --sidenavigation-panel-closed-width: 3rem;
267
+ --sidenavigation-panel-open-width: calc(var(--space-64) * 4);
268
+ --sidenavigation-panel-closed-width: calc(var(--space-64) * 0.75);
254
269
  --sidenavigation-open-duration: var(--duration-200);
255
270
  --sidenavigation-open-easing: var(--ease-out-quart);
256
271
  --sidenavigation-close-duration: var(--duration-150);
@@ -501,6 +516,7 @@
501
516
 
502
517
  .sn-title:hover:not(.active),
503
518
  .sidenavigation.force-title-hover .sn-title:not(.active) {
519
+ background-image: linear-gradient(var(--sidenavigation-hover-tint-enabled), var(--sidenavigation-hover-tint-enabled));
504
520
  --_surface: var(--sidenavigation-title-hover-surface);
505
521
  --_border: var(--sidenavigation-title-hover-border);
506
522
  --_border-width: var(--sidenavigation-title-hover-border-width);
@@ -603,6 +619,7 @@
603
619
 
604
620
  .sn-toggle:hover,
605
621
  .sidenavigation.force-toggle-hover .sn-toggle {
622
+ background-image: linear-gradient(var(--sidenavigation-hover-tint-enabled), var(--sidenavigation-hover-tint-enabled));
606
623
  --_surface: var(--sidenavigation-toggle-hover-surface);
607
624
  --_border: var(--sidenavigation-toggle-hover-border);
608
625
  --_border-width: var(--sidenavigation-toggle-hover-border-width);
@@ -658,6 +675,7 @@
658
675
  }
659
676
  .sn-section-header:hover:not(.active),
660
677
  .sn-section-header.force-hover:not(.active) {
678
+ background-image: linear-gradient(var(--sidenavigation-hover-tint-enabled), var(--sidenavigation-hover-tint-enabled));
661
679
  --_surface: var(--sidenavigation-section-hover-surface);
662
680
  --_indicator: var(--sidenavigation-section-hover-accent);
663
681
  --_indicator-width: var(--sidenavigation-section-hover-accent-width);
@@ -720,6 +738,7 @@
720
738
 
721
739
  .sn-item:hover:not(.active),
722
740
  .sn-item.force-hover:not(.active) {
741
+ background-image: linear-gradient(var(--sidenavigation-hover-tint-enabled), var(--sidenavigation-hover-tint-enabled));
723
742
  --_surface: var(--sidenavigation-item-hover-surface);
724
743
  --_padding: var(--sidenavigation-item-hover-padding);
725
744
  --_indicator: var(--sidenavigation-item-hover-accent);
@@ -781,6 +800,7 @@
781
800
 
782
801
  .sn-footer:hover:not(.active),
783
802
  .sidenavigation.force-footer-hover .sn-footer:not(.active) {
803
+ background-image: linear-gradient(var(--sidenavigation-hover-tint-enabled), var(--sidenavigation-hover-tint-enabled));
784
804
  --_surface: var(--sidenavigation-footer-hover-surface);
785
805
  --_padding: var(--sidenavigation-footer-hover-padding);
786
806
  --_gap: var(--sidenavigation-footer-hover-gap);