@happyvertical/smrt-svelte 0.55.16 → 0.55.18

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 (153) hide show
  1. package/README.md +5 -3
  2. package/agents/cookbook-shell.md +7 -1
  3. package/agents/overview-surfaces.md +5 -0
  4. package/agents/workspace.md +155 -11
  5. package/dist/browser-ai/svelte/components/DownloadProgress.svelte +22 -19
  6. package/dist/browser-ai/svelte/components/ModelStatusControl.svelte +16 -13
  7. package/dist/browser-ai/svelte/components/STTTest.svelte +41 -38
  8. package/dist/browser-ai/svelte/components/VoiceInput.svelte +17 -14
  9. package/dist/components/activity/ActivityList.svelte +1 -1
  10. package/dist/components/app/AppShell.svelte +279 -14
  11. package/dist/components/app/AppShell.svelte.d.ts +63 -2
  12. package/dist/components/app/AppShell.svelte.d.ts.map +1 -1
  13. package/dist/components/app/DockToggles.svelte +53 -11
  14. package/dist/components/app/DockToggles.svelte.d.ts.map +1 -1
  15. package/dist/components/app/OwnerSetupForm.svelte +98 -34
  16. package/dist/components/app/OwnerSetupForm.svelte.d.ts +4 -0
  17. package/dist/components/app/OwnerSetupForm.svelte.d.ts.map +1 -1
  18. package/dist/components/app/PhoneTabBar.svelte +136 -0
  19. package/dist/components/app/PhoneTabBar.svelte.d.ts +22 -0
  20. package/dist/components/app/PhoneTabBar.svelte.d.ts.map +1 -0
  21. package/dist/components/app/ShellSettingsPage.svelte +17 -2
  22. package/dist/components/app/ShellSettingsPage.svelte.d.ts +11 -16
  23. package/dist/components/app/ShellSettingsPage.svelte.d.ts.map +1 -1
  24. package/dist/components/app/dock-toggle.d.ts +3 -2
  25. package/dist/components/app/dock-toggle.d.ts.map +1 -1
  26. package/dist/components/app/index.d.ts +2 -1
  27. package/dist/components/app/index.d.ts.map +1 -1
  28. package/dist/components/app/index.js +1 -0
  29. package/dist/components/app/owner-setup-types.d.ts +5 -0
  30. package/dist/components/app/owner-setup-types.d.ts.map +1 -1
  31. package/dist/components/app/phone-tabs.d.ts +41 -0
  32. package/dist/components/app/phone-tabs.d.ts.map +1 -0
  33. package/dist/components/app/phone-tabs.js +66 -0
  34. package/dist/components/app/slot-item.d.ts +16 -0
  35. package/dist/components/app/slot-item.d.ts.map +1 -1
  36. package/dist/components/app/view-transition.d.ts +43 -0
  37. package/dist/components/app/view-transition.d.ts.map +1 -0
  38. package/dist/components/app/view-transition.js +76 -0
  39. package/dist/components/audit/AuditList.svelte +4 -1
  40. package/dist/components/audit/RecordHistory.svelte +4 -1
  41. package/dist/components/board/Board.svelte +4 -1
  42. package/dist/components/command-palette/CommandPalette.svelte +4 -1
  43. package/dist/components/command-palette/CommandPalette.svelte.d.ts +2 -0
  44. package/dist/components/command-palette/CommandPalette.svelte.d.ts.map +1 -1
  45. package/dist/components/command-palette/CommandPaletteDialog.svelte +3 -0
  46. package/dist/components/command-palette/CommandPaletteTrigger.svelte +3 -0
  47. package/dist/components/cookbook/CookbookApp.svelte +2 -1
  48. package/dist/components/cookbook/CookbookApp.svelte.d.ts.map +1 -1
  49. package/dist/components/cookbook/CookbookSectionPage.svelte +4 -1
  50. package/dist/components/cookbook/brand-theme.d.ts.map +1 -1
  51. package/dist/components/cookbook/brand-theme.js +21 -2
  52. package/dist/components/cookbook/build.js +1 -1
  53. package/dist/components/cookbook/theme.d.ts.map +1 -1
  54. package/dist/components/cookbook/theme.js +9 -5
  55. package/dist/components/cookbook/types.d.ts +5 -1
  56. package/dist/components/cookbook/types.d.ts.map +1 -1
  57. package/dist/components/forms/AddressInput.svelte +25 -22
  58. package/dist/components/forms/CheckboxInput.svelte +8 -5
  59. package/dist/components/forms/DateRangeInput.svelte +41 -38
  60. package/dist/components/forms/DateTimeInput.svelte +29 -26
  61. package/dist/components/forms/FileUpload.svelte +24 -21
  62. package/dist/components/forms/Form.svelte +34 -31
  63. package/dist/components/forms/FormMicButton.svelte +10 -7
  64. package/dist/components/forms/FormScope.svelte +4 -1
  65. package/dist/components/forms/MeasurementInput.svelte +26 -23
  66. package/dist/components/forms/MoneyInput.svelte +18 -15
  67. package/dist/components/forms/NumberInput.svelte +17 -14
  68. package/dist/components/forms/PhoneInput.svelte +37 -34
  69. package/dist/components/forms/SearchInput.svelte +16 -13
  70. package/dist/components/forms/SelectInput.svelte +17 -14
  71. package/dist/components/forms/TextInput.svelte +19 -16
  72. package/dist/components/forms/TextareaInput.svelte +21 -18
  73. package/dist/components/import-export/ImportExport.svelte +4 -1
  74. package/dist/components/module/ModulePanel.svelte +14 -11
  75. package/dist/components/notifications/NotificationBell.svelte +4 -1
  76. package/dist/components/overview/OverviewAssistantUndo.svelte +4 -1
  77. package/dist/components/overview/OverviewGrid.svelte +11 -6
  78. package/dist/components/overview/OverviewGrid.svelte.d.ts.map +1 -1
  79. package/dist/components/overview/WidgetOptionsForm.svelte +3 -0
  80. package/dist/components/overview/widgets/ChartWidget.svelte +7 -4
  81. package/dist/components/overview/widgets/MetricWidget.svelte +5 -2
  82. package/dist/components/overview/widgets/NoteWidget.svelte +5 -2
  83. package/dist/components/overview/widgets/RecordListWidget.svelte +6 -3
  84. package/dist/components/overview/widgets/ShortcutsWidget.svelte +12 -6
  85. package/dist/components/overview/widgets/ShortcutsWidget.svelte.d.ts.map +1 -1
  86. package/dist/components/screens/DetailScreen.svelte +6 -3
  87. package/dist/components/screens/EditForm.svelte +6 -3
  88. package/dist/components/screens/ListScreen.svelte +4 -1
  89. package/dist/components/screens/RecipeScreens.svelte +1 -1
  90. package/dist/components/settings/SettingsCatalog.svelte +4 -1
  91. package/dist/components/sortable/Sortable.svelte +11 -5
  92. package/dist/components/sortable/Sortable.svelte.d.ts.map +1 -1
  93. package/dist/components/workspace/Breadcrumbs.svelte +4 -1
  94. package/dist/components/workspace/NavTree.svelte +4 -1
  95. package/dist/components/workspace/RoleShell.svelte +4 -1
  96. package/dist/components/workspace/WorkspaceShell.svelte +43 -40
  97. package/dist/components/workspace/admin-shell/ActivityItem.svelte +4 -1
  98. package/dist/components/workspace/admin-shell/ActivityList.svelte +5 -2
  99. package/dist/components/workspace/admin-shell/ActivityTicker.svelte +6 -3
  100. package/dist/components/workspace/admin-shell/ActivityToasts.svelte +9 -4
  101. package/dist/components/workspace/admin-shell/AdminShell.svelte +642 -126
  102. package/dist/components/workspace/admin-shell/AdminShell.svelte.d.ts +7 -1
  103. package/dist/components/workspace/admin-shell/AdminShell.svelte.d.ts.map +1 -1
  104. package/dist/components/workspace/admin-shell/AppScopePanel.svelte +4 -1
  105. package/dist/components/workspace/admin-shell/HotkeyInput.svelte +4 -1
  106. package/dist/components/workspace/admin-shell/PhoneBottomBar.svelte +58 -14
  107. package/dist/components/workspace/admin-shell/PhoneBottomBar.svelte.d.ts +9 -2
  108. package/dist/components/workspace/admin-shell/PhoneBottomBar.svelte.d.ts.map +1 -1
  109. package/dist/components/workspace/admin-shell/PhoneTopBar.svelte +15 -6
  110. package/dist/components/workspace/admin-shell/ShellBrand.svelte +3 -0
  111. package/dist/components/workspace/admin-shell/ShellCorner.svelte +4 -1
  112. package/dist/components/workspace/admin-shell/ShellIconButton.svelte +11 -7
  113. package/dist/components/workspace/admin-shell/ShellLayoutEditor.svelte +6 -3
  114. package/dist/components/workspace/admin-shell/ShellNavEditor.svelte +19 -13
  115. package/dist/components/workspace/admin-shell/ShellNavEditor.svelte.d.ts +1 -1
  116. package/dist/components/workspace/admin-shell/ShellNavEditor.svelte.d.ts.map +1 -1
  117. package/dist/components/workspace/admin-shell/ShellNavToggle.svelte +8 -5
  118. package/dist/components/workspace/admin-shell/ShellSectionIcon.svelte +4 -1
  119. package/dist/components/workspace/admin-shell/ShellSectionMenu.svelte +24 -17
  120. package/dist/components/workspace/admin-shell/ShellSectionMenu.svelte.d.ts.map +1 -1
  121. package/dist/components/workspace/admin-shell/ShellSettingsPanel.svelte +236 -48
  122. package/dist/components/workspace/admin-shell/ShellSettingsPanel.svelte.d.ts +11 -1
  123. package/dist/components/workspace/admin-shell/ShellSettingsPanel.svelte.d.ts.map +1 -1
  124. package/dist/components/workspace/admin-shell/ShellTitle.svelte +4 -1
  125. package/dist/components/workspace/admin-shell/ShortcutsOverlay.svelte +4 -1
  126. package/dist/components/workspace/admin-shell/SystemScopePanel.svelte +4 -1
  127. package/dist/components/workspace/admin-shell/SystemStatusChips.svelte +5 -2
  128. package/dist/components/workspace/admin-shell/TenantNav.svelte +112 -43
  129. package/dist/components/workspace/admin-shell/TenantNav.svelte.d.ts +4 -3
  130. package/dist/components/workspace/admin-shell/TenantNav.svelte.d.ts.map +1 -1
  131. package/dist/components/workspace/admin-shell/WorkspaceAccountMenu.svelte +322 -55
  132. package/dist/components/workspace/admin-shell/WorkspaceAccountMenu.svelte.d.ts +15 -2
  133. package/dist/components/workspace/admin-shell/WorkspaceAccountMenu.svelte.d.ts.map +1 -1
  134. package/dist/components/workspace/admin-shell/motion.d.ts +19 -0
  135. package/dist/components/workspace/admin-shell/motion.d.ts.map +1 -0
  136. package/dist/components/workspace/admin-shell/motion.js +44 -0
  137. package/dist/components/workspace/admin-shell/settings.d.ts +1 -0
  138. package/dist/components/workspace/admin-shell/settings.d.ts.map +1 -1
  139. package/dist/components/workspace/admin-shell/settings.js +1 -1
  140. package/dist/components/workspace/admin-shell/shell-icons.d.ts +8 -0
  141. package/dist/components/workspace/admin-shell/shell-icons.d.ts.map +1 -1
  142. package/dist/components/workspace/admin-shell/shell-icons.js +8 -0
  143. package/dist/components/workspace/admin-shell/state.svelte.d.ts +6 -0
  144. package/dist/components/workspace/admin-shell/state.svelte.d.ts.map +1 -1
  145. package/dist/components/workspace/admin-shell/state.svelte.js +15 -0
  146. package/dist/components/workspace/admin-shell/types.d.ts +13 -3
  147. package/dist/components/workspace/admin-shell/types.d.ts.map +1 -1
  148. package/dist/components/workspace/tools-dock/ToolsDock.svelte +41 -38
  149. package/dist/i18n/strings.workspace.d.ts +37 -0
  150. package/dist/i18n/strings.workspace.d.ts.map +1 -1
  151. package/dist/i18n/strings.workspace.js +42 -2
  152. package/dist/mcp-apps/McpAppsBridge.svelte +4 -1
  153. package/package.json +14 -14
@@ -51,6 +51,7 @@ function buildLayoutStyle(shell: ModuleShellState): string {
51
51
  import { M } from '../../../i18n/strings.workspace.js';
52
52
  import ActivityBadge from './ActivityBadge.svelte';
53
53
  import ShellBrand from './ShellBrand.svelte';
54
+ import { SHELL_DEFAULT_TOOL_ICON, SHELL_ICON_PATHS } from './shell-icons.js';
54
55
  import { setAdminShell } from './context.js';
55
56
  import {
56
57
  formatHotkeyBinding,
@@ -64,7 +65,12 @@ function buildLayoutStyle(shell: ModuleShellState): string {
64
65
  installShellViewport,
65
66
  watchFormActionBar,
66
67
  } from './mobile-shell-dom.js';
67
- import { clampPanelSize, resolveHotkey } from './settings.js';
68
+ import { tokenDuration } from './motion.js';
69
+ import {
70
+ clampPanelSize,
71
+ DEFAULT_PANEL_CONFIG,
72
+ resolveHotkey,
73
+ } from './settings.js';
68
74
  import { createShellState, type ShellState } from './state.svelte.js';
69
75
  import {
70
76
  resolveSlot,
@@ -168,8 +174,14 @@ function buildLayoutStyle(shell: ModuleShellState): string {
168
174
  * children receive them.
169
175
  */
170
176
  overlays?: Snippet<[{ viewport: ShellViewport; bottomBar: BottomBarMode }]>;
171
- /** Phone behavior switches (scrim, swipe to close, hide on scroll). */
177
+ /** Phone behavior switches (scrim and swipe to close default on; hide on scroll). */
172
178
  phone?: AdminShellPhoneOptions;
179
+ /**
180
+ * Show the built-in "Tools" opener on phones while the right edge has
181
+ * focus tools (default true). `AppShell` turns it off when dock toggles
182
+ * already open the dock from the header.
183
+ */
184
+ phoneDockOpener?: boolean;
173
185
  /** Keep the phone top bar shown (e.g. while a banner is visible). */
174
186
  pinChrome?: boolean;
175
187
  /**
@@ -221,6 +233,7 @@ function buildLayoutStyle(shell: ModuleShellState): string {
221
233
  phoneBottomBar,
222
234
  overlays,
223
235
  phone,
236
+ phoneDockOpener = true,
224
237
  pinChrome = false,
225
238
  path,
226
239
  children,
@@ -257,6 +270,8 @@ function buildLayoutStyle(shell: ModuleShellState): string {
257
270
  let formActions = $state(false);
258
271
  let chromeHidden = $state(false);
259
272
  let resizing = $state<SideEdge | null>(null);
273
+ /** Set after hydration and two frames, so first paint never animates. */
274
+ let motionReady = $state(false);
260
275
  const sideElements = $state<Partial<Record<SideEdge, HTMLElement>>>({});
261
276
  let scrollChrome: ReturnType<typeof installScrollChrome> | null = null;
262
277
 
@@ -280,16 +295,20 @@ function buildLayoutStyle(shell: ModuleShellState): string {
280
295
  });
281
296
  return () => { cancelled = true; queueMicrotask(() => { if (opener?.isConnected) opener.focus(); }); };
282
297
  });
283
- const showDefaultPhoneTenantOpener = $derived(
298
+ const phoneScrim = $derived(phone?.scrim !== false);
299
+ const phoneSwipeToClose = $derived(phone?.swipeToClose !== false);
300
+ /** The right edge has tools a phone user must be able to open. */
301
+ const rightOpenerShown = $derived(
302
+ isPhone &&
303
+ phoneDockOpener &&
304
+ shell.isEdgeShown('right') &&
305
+ (shell.focusTools.length > 0 || Boolean(focusRail)),
306
+ );
307
+ const leftOpenerShown = $derived(
284
308
  isPhone &&
285
- !phoneTopBar &&
286
- panelState('top') === 'hidden' &&
287
309
  shell.isEdgeShown('left') &&
288
310
  shell.phonePresentation('left') !== 'hidden',
289
311
  );
290
- const showPhoneTop = $derived(
291
- isPhone && (Boolean(phoneTopBar) || showDefaultPhoneTenantOpener),
292
- );
293
312
  const showHeader = $derived(
294
313
  Boolean(header) && !(isPhone && Boolean(phoneTopBar)),
295
314
  );
@@ -304,6 +323,18 @@ function buildLayoutStyle(shell: ModuleShellState): string {
304
323
  (edge) => panelState(edge) === 'expanded' && shell.isEdgeShown(edge),
305
324
  ),
306
325
  );
326
+ // Starting to edit the layout on a phone puts any open drawer or sheet away,
327
+ // so the editor and a drawer never overlap.
328
+ let wasEditingLayout = false;
329
+ $effect(() => {
330
+ const now = Boolean(layoutEdit?.active);
331
+ untrack(() => {
332
+ if (now && !wasEditingLayout && shell.viewport === 'phone') {
333
+ collapsePhoneSurfaces();
334
+ }
335
+ wasEditingLayout = now;
336
+ });
337
+ });
307
338
  const reserveStyle = $derived(
308
339
  [
309
340
  `--smrt-shell-floating-reserve-inline: ${floatingReserve?.inline ?? '0px'}`,
@@ -472,7 +503,45 @@ function buildLayoutStyle(shell: ModuleShellState): string {
472
503
  onMount(() => {
473
504
  const offViewport = installShellViewport(shell);
474
505
  const offOverlayMedia = installShellOverlayMedia(shell);
475
- void shell.hydrate().then(() => shell.closeOverlaidEdges());
506
+ const hydrated = shell
507
+ .hydrate()
508
+ .then(() => shell.closeOverlaidEdges());
509
+ let disposed = false;
510
+ let frame = 0;
511
+ let themeObserver: MutationObserver | null = null;
512
+ let themeTimer: ReturnType<typeof setTimeout> | null = null;
513
+ // Colour-scheme crossfade: flag the root for one transition when the
514
+ // theme root's scheme changes. The flag is set from the observer
515
+ // microtask, i.e. before the style recalc that applies the new tokens.
516
+ function watchColorScheme(): void {
517
+ const root = rootElement;
518
+ if (!root || typeof MutationObserver === 'undefined') return;
519
+ const host =
520
+ root.closest<HTMLElement>('[data-color-scheme]') ??
521
+ document.documentElement;
522
+ themeObserver = new MutationObserver(() => {
523
+ if (prefersReducedMotion()) return;
524
+ root.setAttribute('data-smrt-theme-changing', '');
525
+ if (themeTimer) clearTimeout(themeTimer);
526
+ themeTimer = setTimeout(
527
+ () => root.removeAttribute('data-smrt-theme-changing'),
528
+ tokenDuration('--smrt-duration-medium1', root) + 100,
529
+ );
530
+ });
531
+ themeObserver.observe(host, {
532
+ attributes: true,
533
+ attributeFilter: ['data-color-scheme', 'class'],
534
+ });
535
+ }
536
+ void hydrated.then(() => {
537
+ frame = requestAnimationFrame(() => {
538
+ frame = requestAnimationFrame(() => {
539
+ if (disposed) return;
540
+ motionReady = true;
541
+ watchColorScheme();
542
+ });
543
+ });
544
+ });
476
545
  const offKeyboard = phoneBottomBar
477
546
  ? installKeyboardWatcher((open) => (keyboardOpen = open))
478
547
  : () => {};
@@ -523,6 +592,10 @@ function buildLayoutStyle(shell: ModuleShellState): string {
523
592
  window.addEventListener('keydown', handleKeydown);
524
593
  return () => {
525
594
  window.removeEventListener('keydown', handleKeydown);
595
+ disposed = true;
596
+ cancelAnimationFrame(frame);
597
+ themeObserver?.disconnect();
598
+ if (themeTimer) clearTimeout(themeTimer);
526
599
  offViewport();
527
600
  offOverlayMedia();
528
601
  if (closingTimer) clearTimeout(closingTimer);
@@ -709,9 +782,69 @@ function buildLayoutStyle(shell: ModuleShellState): string {
709
782
  const stripRegions = $derived(
710
783
  layoutEdit?.active && layoutEdit.strip ? (layoutEdit.hiddenRegions ?? []) : [],
711
784
  );
785
+ function slotHas(...names: ShellSlot[]): boolean {
786
+ return names.some((name) => (slotContent[name]?.length ?? 0) > 0);
787
+ }
788
+ const layoutEditing = $derived(Boolean(layoutEdit?.active));
789
+ const menuOpenerCounts = $derived(
790
+ !(layoutEditing && !isPhone) &&
791
+ shell.config.panels.left.initial !== 'hidden' &&
792
+ shell.layoutPanels.left?.visible !== false &&
793
+ (!isPhone || shell.phonePresentation('left') !== 'hidden') &&
794
+ (isPhone || panelState('left') === 'hidden'),
795
+ );
796
+ // A band or edge with nothing to show is not rendered and its grid track
797
+ // collapses to 0 (the five-row grid itself never changes).
798
+ const topRendered = $derived(
799
+ panelState('top') !== 'hidden' &&
800
+ (layoutEditing ||
801
+ Boolean(appBar) ||
802
+ !brandInSlot ||
803
+ showToggle('top') ||
804
+ menuOpenerCounts ||
805
+ rightOpenerShown ||
806
+ Boolean(account) ||
807
+ footerInHeader ||
808
+ Boolean(topLeftCorner) ||
809
+ Boolean(topRightCorner) ||
810
+ slotHas('header.start', 'header.center', 'header.end') ||
811
+ panelMounted('top')),
812
+ );
813
+ const bottomRendered = $derived(
814
+ panelState('bottom') !== 'hidden' &&
815
+ (layoutEditing ||
816
+ Boolean(systemBar) ||
817
+ Boolean(bottomLeftCorner) ||
818
+ Boolean(bottomRightCorner) ||
819
+ (showToggle('bottom') && Boolean(systemPanel || !systemBar)) ||
820
+ slotHas('footer.start', 'footer.center', 'footer.end') ||
821
+ panelMounted('bottom')),
822
+ );
823
+ const rightRendered = $derived(
824
+ shell.isEdgeShown('right') &&
825
+ (layoutEditing ||
826
+ shell.focusTools.length > 0 ||
827
+ Boolean(focusRail) ||
828
+ Boolean(focusPanel) ||
829
+ showToggle('right') ||
830
+ slotHas('rightSidebar.header', 'rightSidebar.footer') ||
831
+ panelMounted('right')),
832
+ );
833
+ const showDefaultPhoneTenantOpener = $derived(
834
+ isPhone &&
835
+ !phoneTopBar &&
836
+ !topRendered &&
837
+ (leftOpenerShown || rightOpenerShown),
838
+ );
839
+ const showPhoneTop = $derived(
840
+ isPhone && (Boolean(phoneTopBar) || showDefaultPhoneTenantOpener),
841
+ );
712
842
  const layoutStyle = $derived(
713
843
  [
714
844
  buildLayoutStyle(shell),
845
+ ...(topRendered ? [] : ['--smrt-admin-shell-top-track: 0rem']),
846
+ ...(bottomRendered ? [] : ['--smrt-admin-shell-bottom-track: 0rem']),
847
+ ...(rightRendered ? [] : ['--smrt-admin-shell-right-track: 0rem']),
715
848
  ...stripRegions.map(
716
849
  (region) => `--smrt-admin-shell-${REGION_TRACK[region]}-track: ${STRIP_TRACK}`,
717
850
  ),
@@ -788,6 +921,39 @@ function buildLayoutStyle(shell: ModuleShellState): string {
788
921
  return shell.config.panels[edge].label;
789
922
  }
790
923
 
924
+ /**
925
+ * Accessible name of the left chevron. A host-configured panel label
926
+ * ("Packages") names the panel; the default region name ("Left sidebar")
927
+ * is a developer term, so the name is then just "Collapse sidebar".
928
+ */
929
+ function leftEdgeToggleName(): string {
930
+ const label = labelFor('left');
931
+ const expanded = edgeExpanded('left');
932
+ if (label && label !== DEFAULT_PANEL_CONFIG.left.label) {
933
+ return t(
934
+ M[expanded ? 'ui.admin_shell.collapse_panel' : 'ui.admin_shell.expand_panel'],
935
+ { panel: label },
936
+ );
937
+ }
938
+ return t(
939
+ M[expanded ? 'ui.admin_shell.collapse_sidebar' : 'ui.admin_shell.expand_sidebar'],
940
+ );
941
+ }
942
+
943
+ function toggleMenu(): void {
944
+ shell.setPanelState('left', edgeExpanded('left') ? 'collapsed' : 'expanded');
945
+ }
946
+
947
+ function toggleTools(): void {
948
+ if (edgeExpanded('right')) {
949
+ shell.collapsePanel('right');
950
+ return;
951
+ }
952
+ const tool = resolveActiveFocusTool();
953
+ if (tool) shell.openFocusTool(tool.id);
954
+ else shell.expandPanel('right');
955
+ }
956
+
791
957
  function hotkeyFor(edge: PanelEdge): string {
792
958
  return formatHotkeyBinding(
793
959
  resolveHotkey(edge, shell.config.panels[edge], shell.settings),
@@ -840,6 +1006,12 @@ function buildLayoutStyle(shell: ModuleShellState): string {
840
1006
  return toggleOn(edge) || showToggle(edge);
841
1007
  }
842
1008
 
1009
+ $effect(() => {
1010
+ shell.hotkeysAvailable = (['top', 'left', 'right', 'bottom'] as const).some(
1011
+ hotkeyActive,
1012
+ );
1013
+ });
1014
+
843
1015
  function showsHotkeyFor(edge: PanelEdge): boolean {
844
1016
  return (
845
1017
  hotkeyActive(edge) &&
@@ -894,21 +1066,80 @@ function buildLayoutStyle(shell: ModuleShellState): string {
894
1066
  </script>
895
1067
 
896
1068
  {#snippet edgeToggle(edge: PanelEdge)}
897
- <Button
898
- variant="ghost"
899
- size="sm"
900
- class="smrt-admin-shell__edge-toggle"
901
- aria-label={edge === 'left' ? t(M[edgeExpanded(edge) ? 'ui.admin_shell.collapse_panel' : 'ui.admin_shell.expand_panel'], { panel: labelFor(edge) }) : undefined}
902
- aria-expanded={edgeExpanded(edge)}
903
- aria-controls={`smrt-admin-shell-${edge}-panel`}
904
- onclick={() => shell.togglePanel(edge)}
1069
+ {#if edge === 'left'}
1070
+ <!-- The left toggle is an icon-only chevron: it points the way the panel
1071
+ will move (left to collapse, right to expand). Its accessible name
1072
+ carries the action and the hotkey rides in the tooltip. -->
1073
+ {@const name = leftEdgeToggleName()}
1074
+ <Button
1075
+ variant="ghost"
1076
+ size="sm"
1077
+ class="smrt-admin-shell__edge-toggle smrt-admin-shell__edge-toggle--left"
1078
+ aria-label={name}
1079
+ title={showsHotkeyFor('left') ? `${name} (${hotkeyFor('left')})` : name}
1080
+ aria-expanded={edgeExpanded('left')}
1081
+ aria-controls="smrt-admin-shell-left-panel"
1082
+ onclick={() => shell.togglePanel('left')}
1083
+ >
1084
+ <svg
1085
+ class="smrt-admin-shell__edge-toggle-chevron"
1086
+ viewBox="0 0 24 24"
1087
+ width="18"
1088
+ height="18"
1089
+ fill="currentColor"
1090
+ aria-hidden="true"
1091
+ focusable="false"
1092
+ ><path d={SHELL_ICON_PATHS.chevronRight} /></svg>
1093
+ <ActivityBadge edge="left" />
1094
+ </Button>
1095
+ {:else}
1096
+ <Button
1097
+ variant="ghost"
1098
+ size="sm"
1099
+ class="smrt-admin-shell__edge-toggle"
1100
+ aria-expanded={edgeExpanded(edge)}
1101
+ aria-controls={`smrt-admin-shell-${edge}-panel`}
1102
+ onclick={() => shell.togglePanel(edge)}
1103
+ >
1104
+ <span>{labelFor(edge)}</span>
1105
+ {#if showsHotkeyFor(edge)}
1106
+ <kbd class="smrt-admin-shell__edge-toggle-kbd">{hotkeyFor(edge)}</kbd>
1107
+ {/if}
1108
+ <ActivityBadge {edge} />
1109
+ </Button>
1110
+ {/if}
1111
+ {/snippet}
1112
+
1113
+ {#snippet menuOpener()}
1114
+ <!-- raw-primitive-allow: shell chrome control, not a content button -->
1115
+ <button
1116
+ type="button"
1117
+ class="smrt-admin-shell__chrome-button"
1118
+ data-smrt-part="trigger"
1119
+ aria-label={t(M['ui.admin_shell.menu'])}
1120
+ title={t(M['ui.admin_shell.menu'])}
1121
+ aria-expanded={edgeExpanded('left')}
1122
+ aria-controls="smrt-admin-shell-left-panel"
1123
+ onclick={toggleMenu}
905
1124
  >
906
- {#if edge === 'left' && !edgeExpanded(edge)}<span aria-hidden="true">›</span>{:else}<span>{labelFor(edge)}</span>{/if}
907
- {#if showsHotkeyFor(edge) && (edge !== 'left' || edgeExpanded(edge))}
908
- <kbd class="smrt-admin-shell__edge-toggle-kbd">{hotkeyFor(edge)}</kbd>
909
- {/if}
910
- <ActivityBadge {edge} />
911
- </Button>
1125
+ <svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor" aria-hidden="true" focusable="false"><path d={SHELL_ICON_PATHS.menu} /></svg>
1126
+ </button>
1127
+ {/snippet}
1128
+
1129
+ {#snippet toolsOpener()}
1130
+ <!-- raw-primitive-allow: shell chrome control, not a content button -->
1131
+ <button
1132
+ type="button"
1133
+ class="smrt-admin-shell__chrome-button smrt-admin-shell__tools-opener"
1134
+ data-smrt-part="trigger"
1135
+ aria-label={t(M['ui.admin_shell.tools'])}
1136
+ title={t(M['ui.admin_shell.tools'])}
1137
+ aria-expanded={edgeExpanded('right')}
1138
+ aria-controls="smrt-admin-shell-right-panel"
1139
+ onclick={toggleTools}
1140
+ >
1141
+ <svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor" aria-hidden="true" focusable="false"><path d={SHELL_ICON_PATHS[SHELL_DEFAULT_TOOL_ICON]} /></svg>
1142
+ </button>
912
1143
  {/snippet}
913
1144
 
914
1145
  {#snippet resizer(edge: SideEdge)}
@@ -1007,7 +1238,8 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1007
1238
  data-phone-top={showPhoneTop ? '' : undefined}
1008
1239
  data-chrome-hidden={chromeHidden ? '' : undefined}
1009
1240
  data-resizing={resizing ?? undefined}
1010
- style={`${layoutStyle}; ${chromeStyle}; ${reserveStyle}`}
1241
+ data-motion={motionReady ? '' : undefined}
1242
+ style={`${layoutStyle}; ${chromeStyle}; ${reserveStyle}`} data-smrt-component="AdminShell"
1011
1243
  >
1012
1244
  {#if showHeader}
1013
1245
  <div
@@ -1020,13 +1252,13 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1020
1252
  {/if}
1021
1253
 
1022
1254
  {@render regionStrip('header')}
1023
- {#if panelState('top') !== 'hidden'}
1255
+ {#if topRendered}
1024
1256
  <header
1025
1257
  id="smrt-admin-shell-top-panel"
1026
1258
  class="smrt-admin-shell__edge smrt-admin-shell__edge--top"
1027
1259
  data-state={panelState('top')}
1028
1260
  data-presentation={shell.config.panels.top.presentation}
1029
- style:--edge-columns={topEdgeColumns}
1261
+ style:--smrt-admin-shell-edge-columns={topEdgeColumns}
1030
1262
  >
1031
1263
  {#if topLeftCorner}
1032
1264
  <div class="smrt-admin-shell__corner smrt-admin-shell__corner--top-left">
@@ -1035,7 +1267,7 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1035
1267
  {/if}
1036
1268
  <div
1037
1269
  class="smrt-admin-shell__band smrt-admin-shell__band--top"
1038
- style:--band-column={2}
1270
+ style:--smrt-admin-shell-band-column={2}
1039
1271
  >
1040
1272
  {#if appBar}
1041
1273
  {@render appBar()}
@@ -1045,7 +1277,7 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1045
1277
  {/if}
1046
1278
  {#if !(layoutEdit?.active && !isPhone) && shell.config.panels.left.initial !== 'hidden' && shell.layoutPanels.left?.visible !== false && (!isPhone || shell.phonePresentation('left') !== 'hidden')}
1047
1279
  <div class="smrt-admin-shell__tenant-opener" class:restore-hidden={panelState('left') === 'hidden'}>
1048
- <Button variant="ghost" size="sm" aria-label={t(M['ui.admin_shell.menu'])} aria-expanded={edgeExpanded('left')} aria-controls="smrt-admin-shell-left-panel" onclick={() => shell.setPanelState('left', edgeExpanded('left') ? 'collapsed' : 'expanded')}>{t(M['ui.admin_shell.menu'])}</Button>
1280
+ {@render menuOpener()}
1049
1281
  </div>
1050
1282
  {/if}
1051
1283
  {@render slotGroup('header.start')}
@@ -1056,6 +1288,7 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1056
1288
  </div>
1057
1289
  {/if}
1058
1290
  {@render slotGroup('header.end')}
1291
+ {#if rightOpenerShown}{@render toolsOpener()}{/if}
1059
1292
  {@render regionEdit('header')}
1060
1293
  </div>
1061
1294
  {#if topRightCorner}
@@ -1101,14 +1334,29 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1101
1334
  use:swipeDismiss={{
1102
1335
  direction: 'left',
1103
1336
  onDismiss: () => shell.collapsePanel('left'),
1104
- enabled: isPhone && Boolean(phone?.swipeToClose) && edgeExpanded('left'),
1337
+ enabled: isPhone && phoneSwipeToClose && edgeExpanded('left'),
1105
1338
  }}
1106
1339
  >
1107
1340
  {@render resizer('left')}
1108
1341
  <div class="smrt-admin-shell__rail">
1109
1342
  {@render regionEdit('leftSidebar')}
1110
- {#if (panelState('top') === 'hidden' || !edgeExpanded('left')) && (homeHref || logoSrc || brand)}{@render shellBrand(!edgeExpanded('left'))}{/if}
1111
- {#if showToggle('left') || isPhone}{@render edgeToggle('left')}{/if}
1343
+ {#if isPhone}
1344
+ <!-- Phone drawer: the app title and an icon-only close control. -->
1345
+ <div class="smrt-admin-shell__drawer-head" data-smrt-part="header">
1346
+ <div class="smrt-admin-shell__drawer-title">{@render shellBrand()}</div>
1347
+ <!-- raw-primitive-allow: shell chrome control, not a content button -->
1348
+ <button
1349
+ type="button"
1350
+ class="smrt-admin-shell__chrome-button"
1351
+ data-smrt-part="close"
1352
+ aria-label={t(M['ui.admin_shell.close_menu'])}
1353
+ title={t(M['ui.admin_shell.close_menu'])}
1354
+ onclick={() => shell.collapsePanel('left')}
1355
+ >
1356
+ <svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor" aria-hidden="true" focusable="false"><path d={SHELL_ICON_PATHS.close} /></svg>
1357
+ </button>
1358
+ </div>
1359
+ {:else if !topRendered && (homeHref || logoSrc || brand)}{@render shellBrand(!edgeExpanded('left'))}{/if}
1112
1360
  {#if shownOpen('left') || (tenantPanel && keepsContent('left'))}
1113
1361
  <div
1114
1362
  class="smrt-admin-shell__tenant-stack"
@@ -1122,6 +1370,7 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1122
1370
  {@render tenantRail()}
1123
1371
  {/if}
1124
1372
  </div>
1373
+ {#if showToggle('left') && !isPhone && shownOpen('left')}{@render edgeToggle('left')}{/if}
1125
1374
  {#if tenantFooter && !footerInHeader}
1126
1375
  <div class="smrt-admin-shell__tenant-footer">
1127
1376
  {@render tenantFooter()}
@@ -1132,11 +1381,10 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1132
1381
  {/if}
1133
1382
  {#if !shownOpen('left') && (tenantRail || tenantRailFooter)}
1134
1383
  <div class="smrt-admin-shell__tenant-rail-stack">
1135
- {#if tenantRail}
1136
- <div class="smrt-admin-shell__tenant-rail-content">
1137
- {@render tenantRail()}
1138
- </div>
1139
- {/if}
1384
+ <div class="smrt-admin-shell__tenant-rail-content">
1385
+ {#if tenantRail}{@render tenantRail()}{/if}
1386
+ </div>
1387
+ {#if showToggle('left') && !isPhone}{@render edgeToggle('left')}{/if}
1140
1388
  {#if tenantRailFooter}
1141
1389
  <div class="smrt-admin-shell__tenant-rail-footer">
1142
1390
  {@render tenantRailFooter()}
@@ -1144,6 +1392,10 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1144
1392
  {/if}
1145
1393
  </div>
1146
1394
  {/if}
1395
+ <!-- The chevron closes the nav region, above the footer slot: inside
1396
+ the expanded stack or the collapsed rail stack. Only when neither
1397
+ is rendered does it stand alone at the bottom of the rail. -->
1398
+ {#if showToggle('left') && !isPhone && !shownOpen('left') && !(tenantRail || tenantRailFooter)}{@render edgeToggle('left')}{/if}
1147
1399
  </div>
1148
1400
  </aside>
1149
1401
  {/if}
@@ -1163,32 +1415,28 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1163
1415
  {@render phoneTopBar({ hidden: chromeHidden })}
1164
1416
  {:else if showDefaultPhoneTenantOpener}
1165
1417
  <div class="smrt-admin-shell__phone-default-top">
1166
- <Button
1167
- variant="ghost"
1168
- size="sm"
1169
- aria-label={t(M['ui.admin_shell.menu'])}
1170
- aria-expanded={edgeExpanded('left')}
1171
- aria-controls="smrt-admin-shell-left-panel"
1172
- onclick={() =>
1173
- shell.setPanelState(
1174
- 'left',
1175
- edgeExpanded('left') ? 'collapsed' : 'expanded',
1176
- )}
1177
- >{t(M['ui.admin_shell.menu'])}</Button>
1418
+ {#if leftOpenerShown}{@render menuOpener()}{/if}
1419
+ {#if rightOpenerShown}
1420
+ <span class="smrt-admin-shell__phone-default-end">{@render toolsOpener()}</span>
1421
+ {/if}
1178
1422
  </div>
1179
1423
  {/if}
1180
1424
  </div>
1181
1425
  {/if}
1182
1426
 
1183
- {#if isPhone && phone?.scrim && phoneSurfaceOpen}
1427
+ {#if isPhone && phoneScrim && phoneSurfaceOpen}
1184
1428
  <!-- raw-primitive-allow: click-catching backdrop behind a phone drawer -->
1185
1429
  <button
1186
1430
  type="button"
1187
1431
  class="smrt-admin-shell__scrim"
1188
1432
  tabindex="-1"
1189
- aria-label={t(M['ui.admin_shell.close_panel'], {
1190
- label: labelFor(edgeExpanded('left') && shell.isEdgeShown('left') ? 'left' : 'right'),
1191
- })}
1433
+ aria-label={t(
1434
+ M[
1435
+ edgeExpanded('left') && shell.isEdgeShown('left')
1436
+ ? 'ui.admin_shell.close_menu'
1437
+ : 'ui.admin_shell.close_tools'
1438
+ ],
1439
+ )}
1192
1440
  data-testid="admin-shell-scrim"
1193
1441
  onclick={collapsePhoneSurfaces}
1194
1442
  ></button>
@@ -1201,7 +1449,13 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1201
1449
  type="button"
1202
1450
  class="smrt-admin-shell__overlay-scrim"
1203
1451
  tabindex="-1"
1204
- aria-label={t(M['ui.admin_shell.close_panel'], { label: labelFor(scrimEdge) })}
1452
+ aria-label={t(
1453
+ M[
1454
+ scrimEdge === 'left'
1455
+ ? 'ui.admin_shell.close_sidebar'
1456
+ : 'ui.admin_shell.close_tools'
1457
+ ],
1458
+ )}
1205
1459
  data-testid="admin-shell-overlay-scrim"
1206
1460
  data-closing={overlayEdge ? undefined : ''}
1207
1461
  onclick={() => {
@@ -1211,7 +1465,7 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1211
1465
  {/if}
1212
1466
 
1213
1467
  {@render regionStrip('rightSidebar')}
1214
- {#if shell.isEdgeShown('right')}
1468
+ {#if rightRendered}
1215
1469
  {@const rightPhone = isPhone ? shell.phonePresentation('right') : undefined}
1216
1470
  <!-- tabindex -1 only while overlaid, so the panel can take focus on open -->
1217
1471
  <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
@@ -1234,7 +1488,7 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1234
1488
  onDismiss: () => shell.collapsePanel('right'),
1235
1489
  enabled:
1236
1490
  rightPhone === 'drawer' &&
1237
- Boolean(phone?.swipeToClose) &&
1491
+ phoneSwipeToClose &&
1238
1492
  edgeExpanded('right'),
1239
1493
  }}
1240
1494
  >
@@ -1254,6 +1508,19 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1254
1508
  {/if}
1255
1509
  <div class="smrt-admin-shell__rail">
1256
1510
  {@render regionEdit('rightSidebar')}
1511
+ {#if rightPhone === 'drawer'}
1512
+ <!-- raw-primitive-allow: shell chrome control, not a content button -->
1513
+ <button
1514
+ type="button"
1515
+ class="smrt-admin-shell__chrome-button smrt-admin-shell__rail-close"
1516
+ data-smrt-part="close"
1517
+ aria-label={t(M['ui.admin_shell.close_tools'])}
1518
+ title={t(M['ui.admin_shell.close_tools'])}
1519
+ onclick={() => shell.collapsePanel('right')}
1520
+ >
1521
+ <svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor" aria-hidden="true" focusable="false"><path d={SHELL_ICON_PATHS.close} /></svg>
1522
+ </button>
1523
+ {/if}
1257
1524
  {#if shell.config.panels.right.rail === false}
1258
1525
  <!-- Railless: no tool buttons; the host's toggle opens and closes it. -->
1259
1526
  {:else if focusRail}
@@ -1276,7 +1543,7 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1276
1543
  {#if tool.icon}
1277
1544
  <tool.icon />
1278
1545
  {:else}
1279
- <span aria-hidden="true">{tool.label.charAt(0)}</span>
1546
+ <svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor" aria-hidden="true" focusable="false"><path d={SHELL_ICON_PATHS[SHELL_DEFAULT_TOOL_ICON]} /></svg>
1280
1547
  {/if}
1281
1548
  {#if tool.badge != null}
1282
1549
  <span class="smrt-admin-shell__focus-tool-badge">
@@ -1330,13 +1597,13 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1330
1597
  {/if}
1331
1598
 
1332
1599
  {@render regionStrip('footer')}
1333
- {#if panelState('bottom') !== 'hidden'}
1600
+ {#if bottomRendered}
1334
1601
  <footer
1335
1602
  id="smrt-admin-shell-bottom-panel"
1336
1603
  class="smrt-admin-shell__edge smrt-admin-shell__edge--bottom"
1337
1604
  data-state={panelState('bottom')}
1338
1605
  data-presentation={shell.config.panels.bottom.presentation}
1339
- style:--edge-columns={bottomEdgeColumns}
1606
+ style:--smrt-admin-shell-edge-columns={bottomEdgeColumns}
1340
1607
  >
1341
1608
  {#if bottomLeftCorner}
1342
1609
  <div class="smrt-admin-shell__corner smrt-admin-shell__corner--bottom-left">
@@ -1345,7 +1612,7 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1345
1612
  {/if}
1346
1613
  <div
1347
1614
  class="smrt-admin-shell__band smrt-admin-shell__band--bottom"
1348
- style:--band-column={2}
1615
+ style:--smrt-admin-shell-band-column={2}
1349
1616
  >
1350
1617
  {@render slotGroup('footer.start')}
1351
1618
  {@render slotGroup('footer.center')}
@@ -1432,6 +1699,8 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1432
1699
  </div>
1433
1700
 
1434
1701
  <style>
1702
+ @layer smrt.reset, smrt.structure, smrt.theme;
1703
+ @layer smrt.theme {
1435
1704
  .smrt-admin-shell {
1436
1705
  --smrt-shell-floating-reserve-inline: 0px;
1437
1706
  --smrt-shell-floating-reserve-block: 0px;
@@ -1466,7 +1735,7 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1466
1735
  block-size: 100svh;
1467
1736
  /* Themeable: an app sets --smrt-admin-shell-background on the shell or an
1468
1737
  ancestor (a tinted page behind cards, for instance). */
1469
- background: var(--smrt-admin-shell-background, var(--smrt-color-surface));
1738
+ background: var(--smrt-admin-shell-background, var(--smrt-surface-ground));
1470
1739
  color: var(--smrt-color-on-surface);
1471
1740
  /* `clip`, not `hidden`: a hidden box is still programmatically scrollable
1472
1741
  (focus / scrollIntoView on a grid-track child shifts the whole shell
@@ -1476,8 +1745,8 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1476
1745
  overflow: clip;
1477
1746
  /* Themed, thin scrollbars for every scroller inside the shell. Override
1478
1747
  --smrt-admin-shell-scrollbar-track / -thumb / -thumb-hover to retint. */
1479
- scrollbar-color: var(--smrt-admin-shell-scrollbar-thumb, color-mix(in srgb, var(--smrt-color-on-surface) 26%, transparent))
1480
- var(--smrt-admin-shell-scrollbar-track, color-mix(in srgb, var(--smrt-color-surface-container-low) 88%, transparent));
1748
+ scrollbar-color: var(--smrt-admin-shell-scrollbar-thumb, var(--smrt-scrollbar-thumb))
1749
+ var(--smrt-admin-shell-scrollbar-track, var(--smrt-scrollbar-track));
1481
1750
  }
1482
1751
 
1483
1752
  .smrt-admin-shell :global(*) {
@@ -1490,14 +1759,14 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1490
1759
  }
1491
1760
 
1492
1761
  .smrt-admin-shell :global(*)::-webkit-scrollbar-track {
1493
- background: var(--smrt-admin-shell-scrollbar-track, color-mix(in srgb, var(--smrt-color-surface-container-low) 88%, transparent));
1762
+ background: var(--smrt-admin-shell-scrollbar-track, var(--smrt-scrollbar-track));
1494
1763
  }
1495
1764
 
1496
1765
  .smrt-admin-shell :global(*)::-webkit-scrollbar-thumb {
1497
- background-color: var(--smrt-admin-shell-scrollbar-thumb, color-mix(in srgb, var(--smrt-color-on-surface) 26%, transparent));
1766
+ background-color: var(--smrt-admin-shell-scrollbar-thumb, var(--smrt-scrollbar-thumb));
1498
1767
  background-clip: padding-box;
1499
1768
  border: 2px solid transparent;
1500
- border-radius: var(--smrt-radius-full, 999px);
1769
+ border-radius: var(--smrt-radius-full);
1501
1770
  }
1502
1771
 
1503
1772
  .smrt-admin-shell :global(*)::-webkit-scrollbar-thumb:hover {
@@ -1511,9 +1780,9 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1511
1780
  .smrt-admin-shell__edge {
1512
1781
  min-width: 0;
1513
1782
  min-height: 0;
1514
- background: var(--smrt-color-surface-container-low);
1783
+ background: var(--smrt-surface-panel);
1515
1784
  color: var(--smrt-color-on-surface);
1516
- border-color: var(--smrt-color-outline-variant);
1785
+ border-color: var(--smrt-hairline-color);
1517
1786
  }
1518
1787
 
1519
1788
  .smrt-admin-shell__header {
@@ -1531,8 +1800,12 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1531
1800
  to drop below it. `clip` (unlike `hidden`) allows a visible block axis. */
1532
1801
  overflow-x: clip;
1533
1802
  overflow-y: visible;
1534
- border-block-end: 1px solid var(--smrt-color-outline-variant);
1535
- background: var(--smrt-color-surface-container-low);
1803
+ border-block-end: var(--smrt-hairline);
1804
+ /* Glass chrome: translucent with blur in the Glass preset, the opaque
1805
+ panel surface (blur 0) everywhere else. */
1806
+ background: var(--smrt-glass-surface);
1807
+ -webkit-backdrop-filter: blur(var(--smrt-glass-blur)) saturate(var(--smrt-glass-saturation));
1808
+ backdrop-filter: blur(var(--smrt-glass-blur)) saturate(var(--smrt-glass-saturation));
1536
1809
  color: var(--smrt-color-on-surface);
1537
1810
  z-index: 30;
1538
1811
  }
@@ -1542,11 +1815,11 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1542
1815
  grid-row: 2;
1543
1816
  display: grid;
1544
1817
  grid-template-columns: var(
1545
- --edge-columns,
1818
+ --smrt-admin-shell-edge-columns,
1546
1819
  var(--smrt-admin-shell-left-collapsed) minmax(0, 1fr)
1547
1820
  var(--smrt-admin-shell-right-collapsed)
1548
1821
  );
1549
- border-block-end: 1px solid var(--smrt-color-outline-variant);
1822
+ border-block-end: var(--smrt-hairline);
1550
1823
  z-index: 30;
1551
1824
  }
1552
1825
 
@@ -1554,7 +1827,7 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1554
1827
  position: relative;
1555
1828
  grid-column: 1;
1556
1829
  grid-row: 3;
1557
- border-inline-end: 1px solid var(--smrt-color-outline-variant);
1830
+ border-inline-end: var(--smrt-hairline);
1558
1831
  z-index: 20;
1559
1832
  }
1560
1833
 
@@ -1562,8 +1835,13 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1562
1835
  position: relative;
1563
1836
  grid-column: 3;
1564
1837
  grid-row: 3;
1565
- border-inline-start: 1px solid var(--smrt-color-outline-variant);
1838
+ border-inline-start: var(--smrt-hairline);
1566
1839
  z-index: 20;
1840
+ /* The dock is the raised glass region of the shell. */
1841
+ background: var(--smrt-glass-surface-strong);
1842
+ -webkit-backdrop-filter: blur(var(--smrt-glass-blur)) saturate(var(--smrt-glass-saturation));
1843
+ backdrop-filter: blur(var(--smrt-glass-blur)) saturate(var(--smrt-glass-saturation));
1844
+ box-shadow: var(--smrt-elevation-3), var(--smrt-inset-highlight);
1567
1845
  }
1568
1846
 
1569
1847
  .smrt-admin-shell__edge--right[data-state='expanded'] {
@@ -1578,11 +1856,11 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1578
1856
  grid-row: 4;
1579
1857
  display: grid;
1580
1858
  grid-template-columns: var(
1581
- --edge-columns,
1859
+ --smrt-admin-shell-edge-columns,
1582
1860
  var(--smrt-admin-shell-left-collapsed) minmax(0, 1fr)
1583
1861
  var(--smrt-admin-shell-right-collapsed)
1584
1862
  );
1585
- border-block-start: 1px solid var(--smrt-color-outline-variant);
1863
+ border-block-start: var(--smrt-hairline);
1586
1864
  z-index: 30;
1587
1865
  }
1588
1866
 
@@ -1593,7 +1871,7 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1593
1871
  min-height: 0;
1594
1872
  overflow: auto;
1595
1873
  padding-block-start: var(--smrt-shell-floating-reserve-main);
1596
- background: var(--smrt-color-surface);
1874
+ background: var(--smrt-surface-ground);
1597
1875
  }
1598
1876
 
1599
1877
  .smrt-admin-shell__band {
@@ -1608,7 +1886,7 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1608
1886
 
1609
1887
  .smrt-admin-shell__band--top,
1610
1888
  .smrt-admin-shell__band--bottom {
1611
- grid-column: var(--band-column, 2);
1889
+ grid-column: var(--smrt-admin-shell-band-column, 2);
1612
1890
  }
1613
1891
 
1614
1892
  /* The header's slots can render in the top band too: keep the floating
@@ -1652,21 +1930,59 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1652
1930
  position: relative;
1653
1931
  display: grid;
1654
1932
  place-items: center;
1655
- width: 2.35rem;
1656
- height: 2.35rem;
1933
+ width: var(--smrt-control-height-small);
1934
+ height: var(--smrt-control-height-small);
1657
1935
  border: 1px solid transparent;
1658
- border-radius: var(--smrt-radius-md, 8px);
1936
+ border-radius: var(--smrt-control-radius);
1659
1937
  background: transparent;
1660
1938
  color: var(--smrt-color-on-surface-variant);
1661
1939
  cursor: pointer;
1662
1940
  font: inherit;
1663
1941
  }
1664
1942
 
1665
- .smrt-admin-shell__focus-tool:hover,
1943
+ /* One state layer per control: a currentColor veil whose opacity is the
1944
+ theme's hover / pressed / selected token. */
1945
+ .smrt-admin-shell__focus-tool::after,
1946
+ .smrt-admin-shell__edit-indicator::after {
1947
+ content: '';
1948
+ position: absolute;
1949
+ inset: 0;
1950
+ border-radius: inherit;
1951
+ background: currentColor;
1952
+ opacity: 0;
1953
+ pointer-events: none;
1954
+ }
1955
+
1956
+ .smrt-admin-shell__focus-tool:hover::after,
1957
+ .smrt-admin-shell__edit-indicator:hover::after {
1958
+ opacity: var(--smrt-state-hover);
1959
+ }
1960
+
1961
+ .smrt-admin-shell__focus-tool:hover {
1962
+ color: var(--smrt-color-on-surface);
1963
+ }
1964
+
1666
1965
  .smrt-admin-shell__focus-tool.active {
1667
1966
  color: var(--smrt-color-primary);
1668
- border-color: var(--smrt-color-primary);
1669
- background: var(--smrt-color-surface-container-high);
1967
+ }
1968
+
1969
+ .smrt-admin-shell__focus-tool.active::after {
1970
+ opacity: var(--smrt-state-selected);
1971
+ }
1972
+
1973
+ .smrt-admin-shell__focus-tool:active::after,
1974
+ .smrt-admin-shell__edit-indicator:active::after {
1975
+ opacity: var(--smrt-state-pressed);
1976
+ }
1977
+
1978
+ .smrt-admin-shell__focus-tool:focus-visible {
1979
+ outline: var(--smrt-focus-ring-width) solid var(--smrt-focus-ring-color);
1980
+ outline-offset: var(--smrt-focus-ring-offset);
1981
+ }
1982
+
1983
+ .smrt-admin-shell__focus-tool:disabled {
1984
+ opacity: var(--smrt-state-disabled);
1985
+ cursor: default;
1670
1986
  }
1671
1987
 
1672
1988
  /* Edit-mode tab for a closed railless right edge: pinned to the shell's
@@ -1680,12 +1996,14 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1680
1996
  display: inline-flex;
1681
1997
  align-items: center;
1682
1998
  gap: var(--smrt-spacing-1, 0.25rem);
1999
+ position: relative;
1683
2000
  padding: var(--smrt-spacing-2, 0.5rem) var(--smrt-spacing-2, 0.5rem);
1684
- border: 1px solid var(--smrt-color-outline-variant);
2001
+ border: var(--smrt-hairline);
1685
2002
  border-inline-end: 0;
1686
- border-start-start-radius: var(--smrt-radius-md, 8px);
1687
- border-end-start-radius: var(--smrt-radius-md, 8px);
1688
- background: var(--smrt-color-surface-container-high);
2003
+ border-start-start-radius: var(--smrt-control-radius);
2004
+ border-end-start-radius: var(--smrt-control-radius);
2005
+ background: var(--smrt-surface-raised);
2006
+ box-shadow: var(--smrt-elevation-2), var(--smrt-inset-highlight);
1689
2007
  color: var(--smrt-color-on-surface-variant);
1690
2008
  font: inherit;
1691
2009
  font-size: var(--smrt-typography-label-small-size, 0.75rem);
@@ -1694,7 +2012,11 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1694
2012
 
1695
2013
  .smrt-admin-shell__edit-indicator:hover {
1696
2014
  color: var(--smrt-color-primary);
1697
- border-color: var(--smrt-color-primary);
2015
+ }
2016
+
2017
+ .smrt-admin-shell__edit-indicator:focus-visible {
2018
+ outline: var(--smrt-focus-ring-width) solid var(--smrt-focus-ring-color);
2019
+ outline-offset: var(--smrt-focus-ring-offset);
1698
2020
  }
1699
2021
 
1700
2022
  .smrt-admin-shell__edit-indicator :global(svg) {
@@ -1707,7 +2029,7 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1707
2029
  inset-block-start: -0.25rem;
1708
2030
  inset-inline-end: -0.25rem;
1709
2031
  min-width: 1rem;
1710
- border-radius: var(--smrt-radius-full, 9999px);
2032
+ border-radius: var(--smrt-radius-full);
1711
2033
  background: var(--smrt-color-error);
1712
2034
  color: var(--smrt-color-on-error);
1713
2035
  font-size: var(--smrt-typography-label-small-size, 0.625rem);
@@ -1725,12 +2047,56 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1725
2047
  max-inline-size: min(20rem, 45vw);
1726
2048
  flex: 1 1 12rem;
1727
2049
  }
1728
- .smrt-admin-shell__account :global(.smrt-workspace-account-menu .dropdown__menu) {
2050
+ .smrt-admin-shell__account :global(.smrt-workspace-account-menu__popover) {
1729
2051
  top: 100%; bottom: auto; right: 0; left: auto;
1730
2052
  inline-size: max-content;
1731
2053
  max-inline-size: calc(100vw - 2 * var(--smrt-spacing-4));
1732
2054
  }
1733
2055
 
2056
+ .smrt-admin-shell__chrome-button {
2057
+ flex: 0 0 auto;
2058
+ display: inline-grid;
2059
+ place-items: center;
2060
+ box-sizing: border-box;
2061
+ inline-size: var(--smrt-control-height);
2062
+ block-size: var(--smrt-control-height);
2063
+ padding: 0;
2064
+ border: 0;
2065
+ border-radius: var(--smrt-control-radius);
2066
+ background: transparent;
2067
+ color: var(--smrt-color-on-surface-variant);
2068
+ cursor: pointer;
2069
+ }
2070
+ .smrt-admin-shell__chrome-button:hover {
2071
+ background: color-mix(in srgb, currentColor calc(var(--smrt-state-hover) * 100%), transparent);
2072
+ color: var(--smrt-color-on-surface);
2073
+ }
2074
+ .smrt-admin-shell__chrome-button:active {
2075
+ background: color-mix(in srgb, currentColor calc(var(--smrt-state-pressed) * 100%), transparent);
2076
+ }
2077
+ .smrt-admin-shell__chrome-button:focus-visible {
2078
+ outline: var(--smrt-focus-ring-width) solid var(--smrt-focus-ring-color);
2079
+ outline-offset: var(--smrt-focus-ring-offset);
2080
+ }
2081
+ .smrt-admin-shell__chrome-button:disabled {
2082
+ opacity: var(--smrt-state-disabled);
2083
+ cursor: default;
2084
+ }
2085
+
2086
+ .smrt-admin-shell__drawer-head {
2087
+ display: flex;
2088
+ align-items: center;
2089
+ justify-content: space-between;
2090
+ gap: var(--smrt-spacing-2);
2091
+ min-inline-size: 0;
2092
+ }
2093
+ .smrt-admin-shell__drawer-title {
2094
+ min-inline-size: 0;
2095
+ overflow: hidden;
2096
+ text-overflow: ellipsis;
2097
+ }
2098
+ .smrt-admin-shell__rail-close { justify-self: center; }
2099
+
1734
2100
  .smrt-admin-shell__tenant-opener { display: none; flex-shrink: 0; }
1735
2101
  .smrt-admin-shell__tenant-opener.restore-hidden { display: block; }
1736
2102
  .smrt-admin-shell__edge--left[data-state='collapsed'] .smrt-admin-shell__rail { padding-inline: var(--smrt-spacing-2); }
@@ -1748,7 +2114,7 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1748
2114
  .smrt-admin-shell__tenant-stack[hidden],
1749
2115
  .smrt-admin-shell__panel[hidden],
1750
2116
  .smrt-admin-shell__drawer[hidden] {
1751
- display: none !important;
2117
+ display: none;
1752
2118
  }
1753
2119
 
1754
2120
  .smrt-admin-shell__tenant-stack {
@@ -1802,25 +2168,25 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1802
2168
  .smrt-admin-shell__slot--leftSidebar-header,
1803
2169
  .smrt-admin-shell__slot--rightSidebar-header {
1804
2170
  padding-block-end: var(--smrt-spacing-3);
1805
- border-block-end: 1px solid var(--smrt-color-outline-variant);
2171
+ border-block-end: var(--smrt-hairline);
1806
2172
  }
1807
2173
 
1808
2174
  .smrt-admin-shell__slot--leftSidebar-footer,
1809
2175
  .smrt-admin-shell__slot--rightSidebar-footer {
1810
2176
  padding-block-start: var(--smrt-spacing-3);
1811
- border-block-start: 1px solid var(--smrt-color-outline-variant);
2177
+ border-block-start: var(--smrt-hairline);
1812
2178
  }
1813
2179
 
1814
2180
  .smrt-admin-shell__slot--rightSidebar-header {
1815
2181
  position: sticky;
1816
2182
  inset-block-start: 0;
1817
- background: var(--smrt-color-surface);
2183
+ background: var(--smrt-surface-raised);
1818
2184
  }
1819
2185
 
1820
2186
  .smrt-admin-shell__slot--rightSidebar-footer {
1821
2187
  position: sticky;
1822
2188
  inset-block-end: 0;
1823
- background: var(--smrt-color-surface);
2189
+ background: var(--smrt-surface-raised);
1824
2190
  }
1825
2191
 
1826
2192
  /* Layout editing: slots as dashed drop zones, hidden regions as strips. */
@@ -1830,14 +2196,15 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1830
2196
  min-inline-size: 4rem;
1831
2197
  min-block-size: 2.25rem;
1832
2198
  padding: var(--smrt-spacing-1);
1833
- border: 1px dashed var(--smrt-color-outline);
1834
- border-radius: var(--smrt-radius-medium, 0.5rem);
1835
- background: color-mix(in srgb, var(--smrt-color-primary) 4%, transparent);
2199
+ border: var(--smrt-hairline);
2200
+ border-style: dashed;
2201
+ border-radius: var(--smrt-control-radius);
2202
+ background: color-mix(in srgb, var(--smrt-color-primary) calc(var(--smrt-state-hover) * 50%), transparent);
1836
2203
  }
1837
2204
  .smrt-admin-shell__slot--editing[data-drop-target] {
1838
2205
  border-style: solid;
1839
2206
  border-color: var(--smrt-color-primary);
1840
- background: color-mix(in srgb, var(--smrt-color-primary) 14%, transparent);
2207
+ background: color-mix(in srgb, var(--smrt-color-primary) calc(var(--smrt-state-dragged) * 100%), transparent);
1841
2208
  }
1842
2209
  .smrt-admin-shell__slot--editing.smrt-admin-shell__slot--header-center,
1843
2210
  .smrt-admin-shell__slot--editing.smrt-admin-shell__slot--footer-center {
@@ -1852,8 +2219,9 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1852
2219
  min-inline-size: 0;
1853
2220
  min-block-size: 0;
1854
2221
  overflow: hidden;
1855
- border: 1px dashed var(--smrt-color-outline);
1856
- background: var(--smrt-color-surface-container-low);
2222
+ border: var(--smrt-hairline);
2223
+ border-style: dashed;
2224
+ background: var(--smrt-surface-sunken);
1857
2225
  color: var(--smrt-color-on-surface-variant);
1858
2226
  font: var(--smrt-typography-label-small-font);
1859
2227
  z-index: 25;
@@ -1868,12 +2236,12 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1868
2236
  .smrt-admin-shell__tenant-footer {
1869
2237
  min-width: 0;
1870
2238
  padding-block-start: var(--smrt-spacing-3);
1871
- border-block-start: 1px solid var(--smrt-color-outline-variant);
2239
+ border-block-start: var(--smrt-hairline);
1872
2240
  }
1873
2241
 
1874
2242
  .smrt-admin-shell__tenant-rail-stack {
1875
2243
  display: grid;
1876
- grid-template-rows: minmax(0, 1fr) auto;
2244
+ grid-template-rows: minmax(0, 1fr) auto auto;
1877
2245
  flex: 1;
1878
2246
  min-width: 0;
1879
2247
  min-height: 0;
@@ -1888,17 +2256,17 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1888
2256
  .smrt-admin-shell__tenant-rail-footer {
1889
2257
  position: relative;
1890
2258
  z-index: 1;
1891
- grid-row: 2;
2259
+ grid-row: 3;
1892
2260
  min-width: 0;
1893
2261
  padding-block-start: var(--smrt-spacing-2);
1894
- border-block-start: 1px solid var(--smrt-color-outline-variant);
2262
+ border-block-start: var(--smrt-hairline);
1895
2263
  overflow: visible;
1896
2264
  }
1897
2265
 
1898
2266
  .smrt-admin-shell__edge--right[data-state='expanded']
1899
2267
  .smrt-admin-shell__rail {
1900
2268
  grid-column: 2;
1901
- border-inline-start: 1px solid var(--smrt-color-outline-variant);
2269
+ border-inline-start: var(--smrt-hairline);
1902
2270
  }
1903
2271
 
1904
2272
  .smrt-admin-shell__panel {
@@ -1916,22 +2284,71 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1916
2284
  padding-block-start: var(--smrt-shell-floating-reserve-block);
1917
2285
  }
1918
2286
 
2287
+ /* The left chevron closes the navigation region: after the navigation and
2288
+ above the sidebar footer slot (the account menu), never below it.
2289
+ `margin-block-start: auto` pins it to the end of the nav region even when
2290
+ nothing above it grows. Expanded it hugs the inner edge and points left;
2291
+ collapsed it is centred in the narrow rail and points right. */
2292
+ .smrt-admin-shell__edge--left :global(.smrt-admin-shell__edge-toggle--left) {
2293
+ flex: 0 0 auto;
2294
+ margin-block-start: auto;
2295
+ align-self: flex-end;
2296
+ inline-size: max(2rem, var(--smrt-control-target-min, 0px));
2297
+ block-size: max(2rem, var(--smrt-control-target-min, 0px));
2298
+ padding: 0;
2299
+ border-radius: var(--smrt-control-radius);
2300
+ color: var(--smrt-color-on-surface-variant);
2301
+ }
2302
+ .smrt-admin-shell__edge--left[data-state='collapsed'] :global(.smrt-admin-shell__edge-toggle--left) {
2303
+ align-self: center;
2304
+ justify-self: center;
2305
+ }
2306
+ .smrt-admin-shell__tenant-rail-stack > :global(.smrt-admin-shell__edge-toggle--left) {
2307
+ grid-row: 2;
2308
+ }
2309
+ .smrt-admin-shell__edge--left[data-state='expanded'] :global(.smrt-admin-shell__edge-toggle-chevron) {
2310
+ transform: scaleX(-1);
2311
+ }
1919
2312
  .smrt-admin-shell__edge-toggle-kbd {
1920
2313
  padding: 0 var(--smrt-spacing-1);
1921
2314
  border-radius: var(--smrt-radius-small);
1922
- background: var(--smrt-color-surface-container-high);
2315
+ background: var(--smrt-surface-sunken);
1923
2316
  color: var(--smrt-color-on-surface-variant);
1924
2317
  font-size: var(--smrt-typography-body-small-size);
1925
2318
  }
1926
2319
 
2320
+ :global(.smrt-admin-shell__edge-toggle--left.button.ghost) {
2321
+ flex: 0 0 auto;
2322
+ inline-size: max(2.75rem, var(--smrt-control-target-min, 0px));
2323
+ block-size: max(2.75rem, var(--smrt-control-target-min, 0px));
2324
+ padding: 0;
2325
+ color: var(--smrt-color-on-surface-variant);
2326
+ }
2327
+
2328
+ :global(.smrt-admin-shell__edge-toggle--left.button.ghost) {
2329
+ border-radius: var(--smrt-control-radius);
2330
+ }
2331
+
2332
+ :global(.smrt-admin-shell__edge-toggle--left.button.ghost:hover) {
2333
+ background: color-mix(in srgb, currentColor calc(var(--smrt-state-hover) * 100%), transparent);
2334
+ color: var(--smrt-color-on-surface);
2335
+ }
2336
+
2337
+ :global(.smrt-admin-shell__edge-toggle--left.button.ghost:active) {
2338
+ background: color-mix(in srgb, currentColor calc(var(--smrt-state-pressed) * 100%), transparent);
2339
+ }
2340
+
1927
2341
  .smrt-admin-shell__drawer {
1928
2342
  position: absolute;
1929
2343
  z-index: 40;
1930
2344
  overflow: auto;
1931
2345
  padding: var(--smrt-spacing-5);
1932
- background: var(--smrt-color-surface-container);
2346
+ border: var(--smrt-hairline);
2347
+ background: var(--smrt-glass-surface-strong);
2348
+ -webkit-backdrop-filter: blur(var(--smrt-glass-blur)) saturate(var(--smrt-glass-saturation));
2349
+ backdrop-filter: blur(var(--smrt-glass-blur)) saturate(var(--smrt-glass-saturation));
1933
2350
  color: var(--smrt-color-on-surface);
1934
- box-shadow: var(--smrt-elevation-3);
2351
+ box-shadow: var(--smrt-elevation-4), var(--smrt-inset-highlight);
1935
2352
  }
1936
2353
 
1937
2354
  .smrt-admin-shell__drawer--top {
@@ -1967,7 +2384,7 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1967
2384
  align-items: center;
1968
2385
  min-width: 0;
1969
2386
  padding: 0 var(--smrt-spacing-3);
1970
- background: var(--smrt-color-surface-container-low);
2387
+ background: var(--smrt-surface-panel);
1971
2388
  }
1972
2389
 
1973
2390
  .smrt-admin-shell__corner--top-left,
@@ -1987,17 +2404,20 @@ function buildLayoutStyle(shell: ModuleShellState): string {
1987
2404
  display: grid;
1988
2405
  place-items: center;
1989
2406
  padding: var(--smrt-spacing-5);
1990
- background: var(--smrt-color-scrim);
2407
+ background: var(--smrt-surface-overlay);
1991
2408
  }
1992
2409
 
1993
2410
  .smrt-admin-shell__shortcuts-panel {
1994
2411
  inline-size: min(32rem, 100%);
1995
2412
  max-block-size: min(36rem, 100%);
1996
2413
  overflow: auto;
2414
+ border: var(--smrt-hairline);
1997
2415
  border-radius: var(--smrt-radius-large);
1998
- background: var(--smrt-color-surface-container);
2416
+ background: var(--smrt-glass-surface-strong);
2417
+ -webkit-backdrop-filter: blur(var(--smrt-glass-blur)) saturate(var(--smrt-glass-saturation));
2418
+ backdrop-filter: blur(var(--smrt-glass-blur)) saturate(var(--smrt-glass-saturation));
1999
2419
  padding: var(--smrt-spacing-5);
2000
- box-shadow: var(--smrt-elevation-4);
2420
+ box-shadow: var(--smrt-elevation-4), var(--smrt-inset-highlight);
2001
2421
  }
2002
2422
 
2003
2423
  .smrt-admin-shell__shortcuts-panel header,
@@ -2078,11 +2498,13 @@ function buildLayoutStyle(shell: ModuleShellState): string {
2078
2498
  align-self: start;
2079
2499
  z-index: 10;
2080
2500
  min-inline-size: 0;
2081
- background: var(--smrt-color-surface);
2501
+ background: var(--smrt-surface-ground);
2082
2502
  transition: transform var(--smrt-admin-shell-chrome-duration)
2083
2503
  var(--smrt-easing-standard, ease);
2084
2504
  }
2085
2505
 
2506
+ .smrt-admin-shell__phone-default-end { margin-inline-start: auto; }
2507
+
2086
2508
  .smrt-admin-shell__phone-default-top {
2087
2509
  display: flex;
2088
2510
  align-items: center;
@@ -2127,7 +2549,7 @@ function buildLayoutStyle(shell: ModuleShellState): string {
2127
2549
  margin: 0;
2128
2550
  padding: 0;
2129
2551
  border: 0;
2130
- background: var(--smrt-color-scrim);
2552
+ background: var(--smrt-surface-overlay);
2131
2553
  opacity: 0.36;
2132
2554
  cursor: pointer;
2133
2555
  }
@@ -2138,10 +2560,10 @@ function buildLayoutStyle(shell: ModuleShellState): string {
2138
2560
  .smrt-admin-shell__edge--right[data-presentation='overlay'][data-state='expanded'] {
2139
2561
  grid-column: 1 / -1;
2140
2562
  z-index: 25;
2141
- box-shadow: var(
2142
- --smrt-elevation-3,
2143
- 0 0.5rem 1.5rem color-mix(in srgb, var(--smrt-color-shadow, #000) 24%, transparent)
2144
- );
2563
+ background: var(--smrt-glass-surface-strong);
2564
+ -webkit-backdrop-filter: blur(var(--smrt-glass-blur)) saturate(var(--smrt-glass-saturation));
2565
+ backdrop-filter: blur(var(--smrt-glass-blur)) saturate(var(--smrt-glass-saturation));
2566
+ box-shadow: var(--smrt-elevation-4), var(--smrt-inset-highlight);
2145
2567
  outline: none;
2146
2568
  }
2147
2569
 
@@ -2166,7 +2588,7 @@ function buildLayoutStyle(shell: ModuleShellState): string {
2166
2588
  margin: 0;
2167
2589
  padding: 0;
2168
2590
  border: 0;
2169
- background: var(--smrt-color-scrim);
2591
+ background: var(--smrt-surface-overlay);
2170
2592
  opacity: 0.24;
2171
2593
  cursor: pointer;
2172
2594
  animation: smrt-admin-shell-scrim-in var(--smrt-admin-shell-chrome-duration)
@@ -2245,7 +2667,7 @@ function buildLayoutStyle(shell: ModuleShellState): string {
2245
2667
  inline-size: 2.5rem;
2246
2668
  block-size: 0.25rem;
2247
2669
  border-radius: var(--smrt-radius-full);
2248
- background: var(--smrt-color-outline-variant);
2670
+ background: var(--smrt-hairline-strong-color);
2249
2671
  }
2250
2672
 
2251
2673
  /* Phone page contracts: breadcrumbs give way to the top bar, and so does
@@ -2286,7 +2708,7 @@ function buildLayoutStyle(shell: ModuleShellState): string {
2286
2708
  position: sticky;
2287
2709
  inset-block-start: var(--smrt-admin-shell-phone-top-size);
2288
2710
  z-index: 6;
2289
- background: var(--smrt-color-surface);
2711
+ background: var(--smrt-surface-ground);
2290
2712
  transition: transform var(--smrt-admin-shell-chrome-duration)
2291
2713
  var(--smrt-easing-standard, ease);
2292
2714
  }
@@ -2309,8 +2731,10 @@ function buildLayoutStyle(shell: ModuleShellState): string {
2309
2731
  margin: 0;
2310
2732
  padding: var(--smrt-spacing-2) var(--smrt-spacing-4)
2311
2733
  calc(var(--smrt-spacing-2) + env(safe-area-inset-bottom));
2312
- border-block-start: 1px solid var(--smrt-color-outline-variant);
2313
- background: var(--smrt-color-surface);
2734
+ border-block-start: var(--smrt-hairline);
2735
+ background: var(--smrt-glass-surface);
2736
+ -webkit-backdrop-filter: blur(var(--smrt-glass-blur)) saturate(var(--smrt-glass-saturation));
2737
+ backdrop-filter: blur(var(--smrt-glass-blur)) saturate(var(--smrt-glass-saturation));
2314
2738
  }
2315
2739
 
2316
2740
  .smrt-admin-shell[data-viewport='phone'] :global([data-form-action-bar] > *) {
@@ -2351,6 +2775,13 @@ function buildLayoutStyle(shell: ModuleShellState): string {
2351
2775
  }
2352
2776
 
2353
2777
  .smrt-admin-shell__tenant-opener { display: block; }
2778
+
2779
+ /* Touch rows: every phone chrome control meets the touch target. */
2780
+ .smrt-admin-shell__chrome-button,
2781
+ .smrt-admin-shell__focus-tool {
2782
+ min-inline-size: var(--smrt-touch-target-min);
2783
+ min-block-size: var(--smrt-touch-target-min);
2784
+ }
2354
2785
  .smrt-admin-shell__edge--left:not([data-state='expanded']),
2355
2786
  .smrt-admin-shell__edge--right:not([data-state='expanded']) { visibility: hidden; }
2356
2787
  .smrt-admin-shell__edge--left,
@@ -2366,6 +2797,10 @@ function buildLayoutStyle(shell: ModuleShellState): string {
2366
2797
  var(--smrt-admin-shell-phone-bar-track)
2367
2798
  );
2368
2799
  inline-size: min(22rem, 86vw);
2800
+ background: var(--smrt-glass-surface-strong);
2801
+ -webkit-backdrop-filter: blur(var(--smrt-glass-blur)) saturate(var(--smrt-glass-saturation));
2802
+ backdrop-filter: blur(var(--smrt-glass-blur)) saturate(var(--smrt-glass-saturation));
2803
+ box-shadow: var(--smrt-elevation-4), var(--smrt-inset-highlight);
2369
2804
  transform: translateX(-100%);
2370
2805
  transition: transform var(--smrt-duration-short2)
2371
2806
  var(--smrt-easing-standard);
@@ -2399,8 +2834,11 @@ function buildLayoutStyle(shell: ModuleShellState): string {
2399
2834
  border-inline-start: 0;
2400
2835
  border-start-start-radius: var(--smrt-radius-lg);
2401
2836
  border-start-end-radius: var(--smrt-radius-lg);
2402
- background: var(--smrt-color-surface);
2403
- box-shadow: var(--smrt-elevation-3);
2837
+ border-block-start: var(--smrt-hairline);
2838
+ background: var(--smrt-glass-surface-strong);
2839
+ -webkit-backdrop-filter: blur(var(--smrt-glass-blur)) saturate(var(--smrt-glass-saturation));
2840
+ backdrop-filter: blur(var(--smrt-glass-blur)) saturate(var(--smrt-glass-saturation));
2841
+ box-shadow: var(--smrt-elevation-4), var(--smrt-inset-highlight);
2404
2842
  transform: translateY(100%);
2405
2843
  visibility: hidden;
2406
2844
  transition:
@@ -2459,9 +2897,86 @@ function buildLayoutStyle(shell: ModuleShellState): string {
2459
2897
  }
2460
2898
  }
2461
2899
 
2900
+ /* ---- Motion --------------------------------------------------------- */
2901
+ /* `data-motion` is set after hydration and two frames, so first paint,
2902
+ SSR and a persisted layout restoring never animate. The pointer-drag
2903
+ resize stays immediate (`data-resizing`). Phone drawers keep their own
2904
+ animation handshake (onEdgeAnimationEnd / waitForPanelAnimations).
2905
+ Every rule below sits in `no-preference`, so reduced motion is off by
2906
+ construction, matching the reduced-motion block at the end. */
2907
+
2908
+ @media (prefers-reduced-motion: no-preference) {
2909
+ .smrt-admin-shell[data-motion]:not([data-viewport='phone']) {
2910
+ transition: grid-template-columns var(--smrt-duration-short4)
2911
+ var(--smrt-easing-emphasized);
2912
+ }
2913
+
2914
+ .smrt-admin-shell[data-motion][data-resizing]:not([data-viewport='phone']) {
2915
+ transition: none;
2916
+ }
2917
+
2918
+ /* One colour-scheme crossfade, flagged by the scheme observer. */
2919
+ .smrt-admin-shell[data-smrt-theme-changing]:not([data-viewport='phone']) {
2920
+ transition:
2921
+ grid-template-columns var(--smrt-duration-short4)
2922
+ var(--smrt-easing-emphasized),
2923
+ background-color var(--smrt-duration-medium1) var(--smrt-easing-standard),
2924
+ color var(--smrt-duration-medium1) var(--smrt-easing-standard);
2925
+ }
2926
+
2927
+ .smrt-admin-shell[data-smrt-theme-changing]:not([data-viewport='phone']) .smrt-admin-shell__edge,
2928
+ .smrt-admin-shell[data-smrt-theme-changing]:not([data-viewport='phone']) .smrt-admin-shell__header,
2929
+ .smrt-admin-shell[data-smrt-theme-changing]:not([data-viewport='phone']) .smrt-admin-shell__main {
2930
+ transition:
2931
+ background-color var(--smrt-duration-medium1) var(--smrt-easing-standard),
2932
+ border-color var(--smrt-duration-medium1) var(--smrt-easing-standard),
2933
+ color var(--smrt-duration-medium1) var(--smrt-easing-standard);
2934
+ }
2935
+
2936
+ /* Newly revealed sidebar / dock content fades in. */
2937
+ .smrt-admin-shell[data-motion]:not([data-viewport='phone']) .smrt-admin-shell__edge[data-presentation='push'] .smrt-admin-shell__tenant-stack:not([hidden]),
2938
+ .smrt-admin-shell[data-motion]:not([data-viewport='phone']) .smrt-admin-shell__edge[data-presentation='push'] .smrt-admin-shell__panel--right:not([hidden]) {
2939
+ animation: smrt-admin-shell-content-in var(--smrt-duration-short2)
2940
+ var(--smrt-easing-standard) backwards;
2941
+ }
2942
+
2943
+ /* Layout edit mode: zones, strips and region controls fade / scale in. */
2944
+ .smrt-admin-shell__slot--editing,
2945
+ .smrt-admin-shell__strip,
2946
+ .smrt-admin-shell__region-edit {
2947
+ animation: smrt-admin-shell-edit-in var(--smrt-duration-short2)
2948
+ var(--smrt-easing-standard) backwards;
2949
+ }
2950
+ }
2951
+
2952
+ @keyframes smrt-admin-shell-content-in {
2953
+ from { opacity: 0; }
2954
+ }
2955
+
2956
+ @keyframes smrt-admin-shell-edit-in {
2957
+ from { opacity: 0; transform: scale(0.96); }
2958
+ }
2959
+
2960
+ /* View transitions: the names exist only while runViewTransition runs
2961
+ (html[data-smrt-view-transition]); they must be unique per document, so
2962
+ hosts must not reuse them. */
2963
+ :global([data-smrt-view-transition]) .smrt-admin-shell:not([data-viewport='phone']) :global(.smrt-admin-shell__brand) {
2964
+ view-transition-name: smrt-shell-brand;
2965
+ }
2966
+
2967
+ :global([data-smrt-view-transition]) .smrt-admin-shell:not([data-viewport='phone']) .smrt-admin-shell__tenant-content,
2968
+ :global([data-smrt-view-transition]) .smrt-admin-shell:not([data-viewport='phone']) .smrt-admin-shell__tenant-rail-content {
2969
+ view-transition-name: smrt-shell-nav;
2970
+ }
2971
+
2972
+ :global([data-smrt-view-transition]) .smrt-admin-shell:not([data-viewport='phone']) .smrt-admin-shell__edge--right {
2973
+ view-transition-name: smrt-shell-dock;
2974
+ }
2975
+
2462
2976
  @media (prefers-reduced-motion: reduce) {
2463
2977
  .smrt-admin-shell {
2464
2978
  --smrt-admin-shell-chrome-duration: 0ms;
2979
+
2465
2980
  }
2466
2981
 
2467
2982
  .smrt-admin-shell__edge--left,
@@ -2475,4 +2990,5 @@ function buildLayoutStyle(shell: ModuleShellState): string {
2475
2990
  animation: none;
2476
2991
  }
2477
2992
  }
2993
+ }
2478
2994
  </style>