@ds-mo/ui 13.10.0 → 13.11.1

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 (185) hide show
  1. package/dist/.package-ready.json +1 -1
  2. package/dist/agent-patterns.json +9 -6
  3. package/dist/agent.json +34 -14
  4. package/dist/angular/ds-mobile-bar-nav.d.ts +1 -1
  5. package/dist/angular/ds-mobile-bar-nav.js +3 -3
  6. package/dist/angular/ds-shell-page.d.ts +1 -1
  7. package/dist/angular/ds-shell-page.js +3 -3
  8. package/dist/components/ds-agent-activity.js +1 -1
  9. package/dist/components/ds-agent-response.js +1 -1
  10. package/dist/components/ds-agent-source-list.js +1 -1
  11. package/dist/components/ds-agent-tool-call.js +1 -1
  12. package/dist/components/ds-attachment-list.js +1 -1
  13. package/dist/components/ds-avatar.js +1 -1
  14. package/dist/components/ds-banner.js +1 -1
  15. package/dist/components/ds-bar-nav.js +1 -1
  16. package/dist/components/ds-bar-title.js +1 -1
  17. package/dist/components/ds-bar-workflow.js +1 -1
  18. package/dist/components/ds-button-filled.js +1 -1
  19. package/dist/components/ds-button-unfilled.js +1 -1
  20. package/dist/components/ds-card-chart.js +1 -1
  21. package/dist/components/ds-card-overview.js +1 -1
  22. package/dist/components/ds-card-overview.js.map +1 -1
  23. package/dist/components/ds-card-setting.js +1 -1
  24. package/dist/components/ds-chip.js +1 -1
  25. package/dist/components/ds-code-block.js +1 -1
  26. package/dist/components/ds-empty-state.js +1 -1
  27. package/dist/components/ds-icon.js +1 -1
  28. package/dist/components/ds-input.js +1 -1
  29. package/dist/components/ds-markdown.js +1 -1
  30. package/dist/components/ds-message-actions.js +1 -1
  31. package/dist/components/ds-message-composer.js +1 -1
  32. package/dist/components/ds-message-scroller.js +1 -1
  33. package/dist/components/ds-mobile-bar-nav.js +1 -1
  34. package/dist/components/ds-mobile-sheet-nav.js +1 -1
  35. package/dist/components/ds-modal.js +1 -1
  36. package/dist/components/ds-panel-nav.js +1 -1
  37. package/dist/components/ds-panel-tool-header.js +1 -1
  38. package/dist/components/ds-panel-tool-search.js +1 -1
  39. package/dist/components/ds-panel-tools.js +1 -1
  40. package/dist/components/ds-select.js +1 -1
  41. package/dist/components/ds-shell-app.js +1 -1
  42. package/dist/components/ds-shell-app.js.map +1 -1
  43. package/dist/components/ds-shell-page.js +1 -1
  44. package/dist/components/ds-shell-tools.js +1 -1
  45. package/dist/components/ds-tab-group.js +1 -1
  46. package/dist/components/ds-tag.js +1 -1
  47. package/dist/components/ds-toast.js +1 -1
  48. package/dist/components/p-BHb3Ws8e.js +2 -0
  49. package/dist/components/p-BHb3Ws8e.js.map +1 -0
  50. package/dist/components/{p-BtS5na9O.js → p-BRajO-Za.js} +2 -2
  51. package/dist/components/{p-BQDi0v_h.js → p-BX57q1Lo.js} +2 -2
  52. package/dist/components/{p-Dv8_hmUZ.js → p-C5gZHZHU.js} +2 -2
  53. package/dist/components/p-CE82aQZr.js +2 -0
  54. package/dist/components/p-CE82aQZr.js.map +1 -0
  55. package/dist/components/{p-HIg1XX62.js → p-CIlO_j3q.js} +2 -2
  56. package/dist/components/p-CIlO_j3q.js.map +1 -0
  57. package/dist/components/{p-CnbrksLl.js → p-CVmtbj-6.js} +2 -2
  58. package/dist/components/{p-BjoyHNaM.js → p-CdFnvBem.js} +2 -2
  59. package/dist/components/{p-BP-EtYbR.js → p-DAbaMtEX.js} +2 -2
  60. package/dist/components/{p-KFHFBznh.js → p-DBJJiSP0.js} +2 -2
  61. package/dist/components/{p-D8qgVmHn.js → p-DBchq8Zw.js} +2 -2
  62. package/dist/components/{p-BYB0f1_F.js → p-DCN04sgt.js} +2 -2
  63. package/dist/components/{p-D2dQyoyK.js → p-DGkWMhHO.js} +2 -2
  64. package/dist/components/{p-2inC7Jm-.js → p-DJGdoPMG.js} +2 -2
  65. package/dist/components/p-DNpE0RBz.js +2 -0
  66. package/dist/components/p-DNpE0RBz.js.map +1 -0
  67. package/dist/components/{p-BjIYFiuQ.js → p-DcmqsAMP.js} +2 -2
  68. package/dist/components/p-DkhE3BsH.js +2 -0
  69. package/dist/components/p-DkhE3BsH.js.map +1 -0
  70. package/dist/components/{p-B4VlfBNc.js → p-Doz2uwRv.js} +2 -2
  71. package/dist/components/p-DumWT7NN.js +2 -0
  72. package/dist/components/p-DumWT7NN.js.map +1 -0
  73. package/dist/components/{p-Cog5NTLa.js → p-Xftomzsv.js} +2 -2
  74. package/dist/components/{p-DJ0XMH9E.js → p-c1pY-Mqq.js} +2 -2
  75. package/dist/docs/components.json +121 -9
  76. package/dist/lib/components/PanelTools/panel-tools-types.d.ts +3 -3
  77. package/dist/lib/components/ShellApp/shell-app-types.d.ts +4 -1
  78. package/dist/lib/components/ShellPage/shell-page-types.d.ts +5 -0
  79. package/dist/lib/shell/index.d.ts +1 -0
  80. package/dist/lib/shell/index.js +12 -11
  81. package/dist/lib/shell/index.js.map +2 -2
  82. package/dist/lib/shell/shell-responsive.d.ts +1 -1
  83. package/dist/mcp-data/registry/agent-activity.json +1 -1
  84. package/dist/mcp-data/registry/agent-response.json +1 -1
  85. package/dist/mcp-data/registry/agent-source-list.json +1 -1
  86. package/dist/mcp-data/registry/agent-tool-call.json +1 -1
  87. package/dist/mcp-data/registry/attachment-list.json +1 -1
  88. package/dist/mcp-data/registry/avatar.json +1 -1
  89. package/dist/mcp-data/registry/badge.json +1 -1
  90. package/dist/mcp-data/registry/banner.json +1 -1
  91. package/dist/mcp-data/registry/bar-nav.json +1 -1
  92. package/dist/mcp-data/registry/bar-title.json +3 -2
  93. package/dist/mcp-data/registry/bar-workflow.json +1 -1
  94. package/dist/mcp-data/registry/breadcrumb.json +1 -1
  95. package/dist/mcp-data/registry/button-filled.json +1 -1
  96. package/dist/mcp-data/registry/button-unfilled.json +1 -1
  97. package/dist/mcp-data/registry/card-chart.json +1 -1
  98. package/dist/mcp-data/registry/card-overview.json +5 -5
  99. package/dist/mcp-data/registry/card-setting.json +1 -1
  100. package/dist/mcp-data/registry/chart-legend.json +1 -1
  101. package/dist/mcp-data/registry/chart.json +1 -1
  102. package/dist/mcp-data/registry/checkbox.json +1 -1
  103. package/dist/mcp-data/registry/chip.json +1 -1
  104. package/dist/mcp-data/registry/code-block.json +1 -1
  105. package/dist/mcp-data/registry/conversation-list-item.json +1 -1
  106. package/dist/mcp-data/registry/conversation-list-section.json +1 -1
  107. package/dist/mcp-data/registry/conversation-list.json +1 -1
  108. package/dist/mcp-data/registry/divider.json +1 -1
  109. package/dist/mcp-data/registry/empty-state.json +1 -1
  110. package/dist/mcp-data/registry/field.json +1 -1
  111. package/dist/mcp-data/registry/icon.json +2 -2
  112. package/dist/mcp-data/registry/input.json +1 -1
  113. package/dist/mcp-data/registry/loader.json +1 -1
  114. package/dist/mcp-data/registry/markdown.json +1 -1
  115. package/dist/mcp-data/registry/menu.json +1 -1
  116. package/dist/mcp-data/registry/message-actions.json +1 -1
  117. package/dist/mcp-data/registry/message-bubble.json +1 -1
  118. package/dist/mcp-data/registry/message-composer.json +1 -1
  119. package/dist/mcp-data/registry/message-scroller.json +1 -1
  120. package/dist/mcp-data/registry/message.json +1 -1
  121. package/dist/mcp-data/registry/mobile-bar-nav.json +39 -7
  122. package/dist/mcp-data/registry/mobile-header.json +1 -1
  123. package/dist/mcp-data/registry/mobile-section-switcher.json +1 -1
  124. package/dist/mcp-data/registry/mobile-sheet-nav.json +1 -1
  125. package/dist/mcp-data/registry/modal.json +1 -1
  126. package/dist/mcp-data/registry/panel-nav.json +1 -1
  127. package/dist/mcp-data/registry/panel-sub-nav.json +1 -1
  128. package/dist/mcp-data/registry/panel-tool-header.json +1 -1
  129. package/dist/mcp-data/registry/panel-tool-search.json +1 -1
  130. package/dist/mcp-data/registry/panel-tools.json +3 -3
  131. package/dist/mcp-data/registry/radio.json +1 -1
  132. package/dist/mcp-data/registry/registry.json +34 -14
  133. package/dist/mcp-data/registry/scroll-overlay.json +1 -1
  134. package/dist/mcp-data/registry/select.json +1 -1
  135. package/dist/mcp-data/registry/shell-app.json +6 -5
  136. package/dist/mcp-data/registry/shell-page.json +33 -9
  137. package/dist/mcp-data/registry/shell-tools.json +4 -4
  138. package/dist/mcp-data/registry/skeleton.json +1 -1
  139. package/dist/mcp-data/registry/slider.json +1 -1
  140. package/dist/mcp-data/registry/swatch-picker.json +1 -1
  141. package/dist/mcp-data/registry/switch.json +1 -1
  142. package/dist/mcp-data/registry/tab-group.json +1 -1
  143. package/dist/mcp-data/registry/tag.json +1 -1
  144. package/dist/mcp-data/registry/text.json +1 -1
  145. package/dist/mcp-data/registry/toast.json +1 -1
  146. package/dist/mcp-data/registry/tooltip-chart.json +1 -1
  147. package/dist/mcp-data/registry/tooltip.json +1 -1
  148. package/dist/mcp-data/registry/typing-indicator.json +1 -1
  149. package/dist/types/components/CardOverview/card-overview-types.d.ts +0 -2
  150. package/dist/types/components/MobileBarNav/MobileBarNav.d.ts +4 -2
  151. package/dist/types/components/PanelTools/panel-tools-types.d.ts +3 -3
  152. package/dist/types/components/ShellApp/shell-app-types.d.ts +4 -1
  153. package/dist/types/components/ShellPage/ShellPage.d.ts +3 -1
  154. package/dist/types/components/ShellPage/index.d.ts +1 -1
  155. package/dist/types/components/ShellPage/shell-page-types.d.ts +1 -0
  156. package/dist/types/components.d.ts +33 -4
  157. package/dist/types/shell/index.d.ts +1 -0
  158. package/dist/types/shell/shell-responsive.d.ts +1 -1
  159. package/package.json +4 -4
  160. package/dist/components/p-B16OuqyJ.js +0 -2
  161. package/dist/components/p-B16OuqyJ.js.map +0 -1
  162. package/dist/components/p-BAfG3M8z.js +0 -2
  163. package/dist/components/p-BAfG3M8z.js.map +0 -1
  164. package/dist/components/p-BkWhTEqe.js +0 -2
  165. package/dist/components/p-BkWhTEqe.js.map +0 -1
  166. package/dist/components/p-BnQXAbif.js +0 -2
  167. package/dist/components/p-BnQXAbif.js.map +0 -1
  168. package/dist/components/p-HIg1XX62.js.map +0 -1
  169. package/dist/components/p-iyiOFsws.js +0 -2
  170. package/dist/components/p-iyiOFsws.js.map +0 -1
  171. /package/dist/components/{p-BtS5na9O.js.map → p-BRajO-Za.js.map} +0 -0
  172. /package/dist/components/{p-BQDi0v_h.js.map → p-BX57q1Lo.js.map} +0 -0
  173. /package/dist/components/{p-Dv8_hmUZ.js.map → p-C5gZHZHU.js.map} +0 -0
  174. /package/dist/components/{p-CnbrksLl.js.map → p-CVmtbj-6.js.map} +0 -0
  175. /package/dist/components/{p-BjoyHNaM.js.map → p-CdFnvBem.js.map} +0 -0
  176. /package/dist/components/{p-BP-EtYbR.js.map → p-DAbaMtEX.js.map} +0 -0
  177. /package/dist/components/{p-KFHFBznh.js.map → p-DBJJiSP0.js.map} +0 -0
  178. /package/dist/components/{p-D8qgVmHn.js.map → p-DBchq8Zw.js.map} +0 -0
  179. /package/dist/components/{p-BYB0f1_F.js.map → p-DCN04sgt.js.map} +0 -0
  180. /package/dist/components/{p-D2dQyoyK.js.map → p-DGkWMhHO.js.map} +0 -0
  181. /package/dist/components/{p-2inC7Jm-.js.map → p-DJGdoPMG.js.map} +0 -0
  182. /package/dist/components/{p-BjIYFiuQ.js.map → p-DcmqsAMP.js.map} +0 -0
  183. /package/dist/components/{p-B4VlfBNc.js.map → p-Doz2uwRv.js.map} +0 -0
  184. /package/dist/components/{p-Cog5NTLa.js.map → p-Xftomzsv.js.map} +0 -0
  185. /package/dist/components/{p-DJ0XMH9E.js.map → p-c1pY-Mqq.js.map} +0 -0
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/wc/components/PanelTools/panel-tools-types.ts", "../../../src/wc/shell/nav-chrome.ts", "../../../src/wc/components/Menu/menu-placement.ts", "../../../src/wc/shell/shell-gradient-presets.ts", "../../../src/wc/shell/shell-responsive.ts"],
4
- "sourcesContent": ["/** Application-owned tool id for the shell rail and responsive tool views. */\nexport type PanelToolsToolId = string;\n\n/** Canonical Motive shell recipe used when item metadata is omitted. */\nexport type CanonicalPanelToolsToolId =\n | 'search'\n | 'agents'\n | 'messages'\n | 'stacks'\n | 'activity'\n | 'help';\n\nexport const PANEL_TOOLS_TOOL_IDS: CanonicalPanelToolsToolId[] = [\n 'search',\n 'agents',\n 'messages',\n 'stacks',\n 'activity',\n 'help',\n];\n\n/** Rail header slot \u2014 mirrors panel-nav M logo row. */\nexport const PANEL_TOOLS_PRIMARY_TOOL_ID: CanonicalPanelToolsToolId = 'search';\n\n/** Rail footer slot \u2014 flush to the bottom of the tools column. */\nexport const PANEL_TOOLS_FOOTER_TOOL_ID: CanonicalPanelToolsToolId = 'help';\n\nexport const PANEL_TOOLS_LABELS: Record<CanonicalPanelToolsToolId, string> = {\n search: 'Search',\n messages: 'Messages',\n stacks: 'Stacks',\n activity: 'Activity',\n agents: 'Agents',\n help: 'Help & Support',\n};\n\nexport const PANEL_TOOLS_SHORTCUTS: Partial<Record<CanonicalPanelToolsToolId, string>> = {\n search: 'K',\n agents: 'A',\n messages: 'M',\n stacks: 'S',\n activity: 'N',\n help: '/',\n};\n\nexport interface PanelToolsItem {\n id: PanelToolsToolId;\n /** Icon name for <ds-icon>. */\n icon: string;\n /** Visible and accessible fallback label for custom tool ids. */\n label?: string;\n /** Explicit rail region; canonical Search/Help placement is the fallback. */\n railPlacement?: 'header' | 'body' | 'footer';\n /** Stable ordering within the selected rail region. */\n order?: number;\n /** Optional shortcut label displayed by the tooltip. */\n shortcutKey?: string;\n /** Mobile destination recipe; canonical ids retain their existing defaults. */\n mobileDestination?: 'search' | 'agents' | 'inbox' | 'help';\n /** Whether this rail button is currently pressed/active. */\n selected?: boolean;\n /** Show a notification dot. */\n dot?: boolean;\n isInactive?: boolean;\n ariaLabel?: string;\n}\n\n/** Canonical shell recipe used by Lab and by managed ShellApp examples. */\nexport const PANEL_TOOLS_DEFAULT_ITEMS: PanelToolsItem[] = [\n {\n id: 'search',\n icon: 'MagnifyingGlass',\n label: PANEL_TOOLS_LABELS.search,\n railPlacement: 'header',\n order: 0,\n shortcutKey: PANEL_TOOLS_SHORTCUTS.search,\n mobileDestination: 'search',\n },\n {\n id: 'agents',\n icon: 'AI',\n label: PANEL_TOOLS_LABELS.agents,\n order: 1,\n shortcutKey: PANEL_TOOLS_SHORTCUTS.agents,\n mobileDestination: 'agents',\n },\n {\n id: 'messages',\n icon: 'MessageBubbleStack',\n label: PANEL_TOOLS_LABELS.messages,\n order: 2,\n shortcutKey: PANEL_TOOLS_SHORTCUTS.messages,\n mobileDestination: 'inbox',\n },\n {\n id: 'stacks',\n icon: 'ViewMenu',\n label: PANEL_TOOLS_LABELS.stacks,\n order: 3,\n shortcutKey: PANEL_TOOLS_SHORTCUTS.stacks,\n mobileDestination: 'inbox',\n },\n {\n id: 'activity',\n icon: 'Bell',\n label: PANEL_TOOLS_LABELS.activity,\n order: 4,\n shortcutKey: PANEL_TOOLS_SHORTCUTS.activity,\n mobileDestination: 'inbox',\n },\n {\n id: 'help',\n icon: 'CircleQuestion',\n label: PANEL_TOOLS_LABELS.help,\n railPlacement: 'footer',\n order: 5,\n shortcutKey: PANEL_TOOLS_SHORTCUTS.help,\n mobileDestination: 'help',\n },\n];\n\nexport interface PanelToolsHeaderAction {\n id: string;\n icon: string;\n ariaLabel: string;\n triggerId?: string;\n controls?: string;\n expanded?: boolean;\n haspopup?: 'menu' | 'dialog' | 'listbox' | 'tree' | 'grid';\n pressed?: boolean;\n isInactive?: boolean;\n}\n\nexport interface PanelToolsHeaderConfig {\n title?: string;\n showBack?: boolean;\n backIcon?: string;\n backAriaLabel?: string;\n actions?: PanelToolsHeaderAction[];\n}\n\n/** Per-tool header state. The application replaces the object when a tool changes depth or actions. */\nexport type PanelToolsHeaders = Partial<Record<PanelToolsToolId, PanelToolsHeaderConfig>>;\n", "/** Nav chrome style slot \u2014 dashboard vs settings. Colors unified for now; texture hooks use the class. */\nexport type NavChromeStyle = 'dashboard' | 'settings';\n\n/** Document hint for first paint before framework props land. */\nexport const NAV_STYLE_HINT_ATTR = 'data-nav-style';\n\nexport function readNavStyleAttr(attr: string | null): NavChromeStyle | undefined {\n if (attr === 'dashboard' || attr === 'settings') return attr;\n return undefined;\n}\n\nexport function setNavStyleHint(style: NavChromeStyle): void {\n if (typeof document === 'undefined') return;\n document.documentElement.setAttribute(NAV_STYLE_HINT_ATTR, style);\n}\n\nexport function clearNavStyleHint(): void {\n if (typeof document === 'undefined') return;\n document.documentElement.removeAttribute(NAV_STYLE_HINT_ATTR);\n}\n\nexport function resolveNavChromeStyle(\n styleProp: NavChromeStyle,\n hostAttr: string | null,\n docHint?: string | null,\n): NavChromeStyle {\n const fromHost = readNavStyleAttr(hostAttr);\n if (fromHost) return fromHost;\n\n const hint =\n docHint !== undefined\n ? docHint\n : typeof document !== 'undefined'\n ? document.documentElement.getAttribute(NAV_STYLE_HINT_ATTR)\n : null;\n const fromHint = readNavStyleAttr(hint);\n if (fromHint) return fromHint;\n\n return styleProp;\n}\n\nexport function shouldResyncNavChromeStyle(\n renderedStyle: NavChromeStyle,\n style: NavChromeStyle,\n): boolean {\n return renderedStyle !== style;\n}\n", "import type { ChoicePopupAnchorAlignment } from '../../utils/choice-popup-alignment';\nimport type { MenuAlign, MenuSide } from './menu-position';\n\n/** Placement props bindable on `ds-menu` (side, align, offsets). */\nexport interface MenuPlacement {\n side: MenuSide;\n align: MenuAlign;\n anchorAlignment: ChoicePopupAnchorAlignment;\n sideOffset: number | string;\n alignOffset: number | string;\n}\n\n/**\n * Canonical `ds-menu` placement for the **panel-nav footer user menu**.\n * Anchor from `dsNavUserAction` detail `{ anchor }` (id `ds-panel-nav-user-menu-anchor`).\n *\n * Not for BarNav overflow menus \u2014 those use `side=\"bottom\"` / `align=\"end\"` internally.\n * `align: 'end'` bottom-aligns the last choice cell on the anchor; the side offset nudges into the content area:\n * - `sideOffset` space-100 + space-050 (12px): 4px past the panel-nav outer edge (anchor is ~8px inset).\n * - `anchorAlignment: 'choice-cell'`: the shared section inset puts the last row edge on the footer user row.\n */\nexport const PANEL_NAV_USER_MENU_PLACEMENT = {\n side: 'right',\n align: 'end',\n anchorAlignment: 'choice-cell',\n sideOffset: 'calc(var(--dimension-space-100) + var(--dimension-space-050))',\n alignOffset: 0,\n} as const satisfies MenuPlacement;\n\n/**\n * Canonical placement for a menu opened by a PanelTools header action.\n * Matches BarNav overflow: the 32px trigger is 8px inside the 48px header, so\n * a 12px side offset places the popup 4px below the header edge. Choice-cell\n * alignment keeps the final menu item edge aligned with the trigger.\n */\nexport const PANEL_TOOLS_HEADER_MENU_PLACEMENT = {\n side: 'bottom',\n align: 'end',\n anchorAlignment: 'choice-cell',\n sideOffset: 'calc(var(--dimension-space-100) + var(--dimension-space-050))',\n alignOffset: 0,\n} as const satisfies MenuPlacement;\n", "/** Built-in shell chrome wash presets. */\nexport type ShellGradientPreset = 'none' | 'cool' | 'neutral' | 'warm' | 'fresh';\n\nexport const SHELL_GRADIENT_PRESETS: ShellGradientPreset[] = [\n 'none',\n 'cool',\n 'neutral',\n 'warm',\n 'fresh',\n];\n\n/** Wash presets shown after the `none` option in pickers. */\nexport const SHELL_GRADIENT_WASH_PRESETS: Exclude<ShellGradientPreset, 'none'>[] = [\n 'cool',\n 'neutral',\n 'warm',\n 'fresh',\n];\n\n/** Default wash when `gradient-preset` is omitted. */\nexport const DEFAULT_SHELL_GRADIENT_PRESET: ShellGradientPreset = 'neutral';\n\nexport const SHELL_GRADIENT_PRESET_LABELS: Record<ShellGradientPreset, string> = {\n none: 'None',\n cool: 'Cool',\n neutral: 'Neutral',\n warm: 'Warm',\n fresh: 'Fresh',\n};\n\nexport interface ShellGradientStop {\n color: string;\n position: number;\n}\n\nexport interface ShellGradientRecipe {\n opacity: number;\n stops: readonly ShellGradientStop[];\n}\n\nexport interface ShellGradientPickerPreview {\n backgroundColor: string;\n backgroundImage?: string;\n opacity?: number;\n}\n\nexport interface ShellGradientPickerOption {\n value: ShellGradientPreset;\n label: string;\n preview: ShellGradientPickerPreview;\n}\n\nexport interface ShellGradientPickerSection {\n options: ShellGradientPickerOption[];\n}\n\nconst SHELL_GRADIENT_RECIPES: Record<Exclude<ShellGradientPreset, 'none'>, ShellGradientRecipe> = {\n cool: {\n opacity: 0.1,\n stops: [\n { color: 'var(--color-background-transparent)', position: 0 },\n { color: 'var(--color-color-intent-blue-strong-background)', position: 100 },\n ],\n },\n neutral: {\n opacity: 0.1,\n stops: [\n { color: 'var(--color-background-transparent)', position: 0 },\n { color: 'var(--color-color-intent-grey-strong-background)', position: 100 },\n ],\n },\n warm: {\n opacity: 0.1,\n stops: [\n { color: 'var(--color-background-transparent)', position: 0 },\n { color: 'var(--color-color-intent-yellow-strong-background)', position: 100 },\n ],\n },\n fresh: {\n opacity: 0.4,\n stops: [\n { color: 'var(--color-color-intent-cyan-faint-background)', position: 0 },\n { color: 'var(--color-background-transparent)', position: 47 },\n { color: 'var(--color-background-transparent)', position: 58 },\n { color: 'var(--color-color-intent-red-faint-background)', position: 83 },\n { color: 'var(--color-color-intent-pink-faint-background)', position: 100 },\n ],\n },\n};\n\nconst GRADIENT_GEOMETRY = '100% 100% at 0% 0%';\n\nexport function shellGradientPresetStopToken(preset: ShellGradientPreset): string | null {\n if (preset === 'none') return null;\n const stops = SHELL_GRADIENT_RECIPES[preset].stops;\n return stops[stops.length - 1]?.color ?? null;\n}\n\nexport function shellGradientPresetRecipe(preset: ShellGradientPreset): ShellGradientRecipe | null {\n const normalized = normalizeShellGradientPreset(preset);\n return normalized === 'none' ? null : SHELL_GRADIENT_RECIPES[normalized];\n}\n\nexport function shellGradientPresetOpacity(preset: ShellGradientPreset): string {\n return String(shellGradientPresetRecipe(preset)?.opacity ?? 0);\n}\n\nexport function isShellGradientPreset(value: string): value is ShellGradientPreset {\n return (SHELL_GRADIENT_PRESETS as string[]).includes(value);\n}\n\n/**\n * Coerce unknown/absent presets to the default. Runtime values escape the\n * type: removing the reflected `gradient-preset` attribute (e.g. an Angular\n * `[attr.gradient-preset]=\"null\"` binding) drives the prop to null past its\n * field default \u2014 without normalization the stop lookup interpolates the\n * literal string \"undefined\" into CSS and the wash silently disappears.\n */\nexport function normalizeShellGradientPreset(\n value: string | null | undefined,\n): ShellGradientPreset {\n return value != null && isShellGradientPreset(value) ? value : DEFAULT_SHELL_GRADIENT_PRESET;\n}\n\n/** Radial wash for a preset \u2014 transparent at top-left into the intent stop. `none` returns no image. */\nexport function buildShellRadialGradientForPreset(preset: ShellGradientPreset): string {\n const normalized = normalizeShellGradientPreset(preset);\n if (normalized === 'none') return 'none';\n\n return buildShellRadialGradientFromStops(SHELL_GRADIENT_RECIPES[normalized].stops);\n}\n\n/** Build the production shell geometry from an ordered set of design-time stops. */\nexport function buildShellRadialGradientFromStops(stops: readonly ShellGradientStop[]): string {\n const serialized = stops.map(stop => `${stop.color} ${stop.position}%`).join(', ');\n return `radial-gradient(${GRADIENT_GEOMETRY}, ${serialized})`;\n}\n\n/** Generic SwatchPicker sections for the fixed shell appearance presets. */\nexport function shellGradientPickerSections(): ShellGradientPickerSection[] {\n return [\n {\n options: [{\n value: 'none',\n label: SHELL_GRADIENT_PRESET_LABELS.none,\n preview: {\n backgroundColor: 'var(--color-background-secondary)',\n },\n }],\n },\n {\n options: SHELL_GRADIENT_WASH_PRESETS.map(preset => ({\n value: preset,\n label: SHELL_GRADIENT_PRESET_LABELS[preset],\n preview: {\n backgroundColor: 'var(--color-background-secondary)',\n backgroundImage: buildShellRadialGradientForPreset(preset),\n opacity: Number(shellGradientPresetOpacity(preset)),\n },\n })),\n },\n ];\n}\n", "import type { PanelToolsToolId } from '../components/PanelTools/panel-tools-types';\n\nexport type ShellResponsiveMode = 'desktop' | 'tablet' | 'mobile';\nexport type MobileDestination = 'area' | 'search' | 'agents' | 'inbox' | 'help';\nexport type ShellInboxToolId = PanelToolsToolId;\n\nexport const SHELL_DESKTOP_BREAKPOINT = 1200;\nexport const SHELL_MOBILE_BREAKPOINT = 768;\nexport const SHELL_DEFAULT_INBOX_TOOL: ShellInboxToolId = 'messages';\n\nexport function resolveShellResponsiveMode(width: number): ShellResponsiveMode {\n if (width >= SHELL_DESKTOP_BREAKPOINT) return 'desktop';\n if (width >= SHELL_MOBILE_BREAKPOINT) return 'tablet';\n return 'mobile';\n}\n\nexport function resolveManagedShellPageCapacity(\n mode: ShellResponsiveMode,\n toolsOpen: boolean\n): 'roomy' | 'compact' | 'constrained' {\n if (mode === 'desktop') return toolsOpen ? 'compact' : 'roomy';\n return toolsOpen ? 'constrained' : 'compact';\n}\n\nexport function shellMobileDestinationForTool(\n open: boolean,\n tool: PanelToolsToolId | ''\n): MobileDestination {\n if (!open || !tool) return 'area';\n if (tool === 'help') return 'help';\n if (tool === 'search') return 'search';\n if (tool === 'agents') return 'agents';\n return 'inbox';\n}\n\nexport function isShellInboxTool(tool: string): tool is ShellInboxToolId {\n return tool === 'messages' || tool === 'stacks' || tool === 'activity';\n}\n\nexport function resolveAvailableInboxTool(\n preferred: string,\n available: readonly PanelToolsToolId[]\n): ShellInboxToolId | '' {\n const inbox = available.filter(isShellInboxTool);\n if (isShellInboxTool(preferred) && inbox.includes(preferred)) return preferred;\n if (inbox.includes(SHELL_DEFAULT_INBOX_TOOL)) return SHELL_DEFAULT_INBOX_TOOL;\n return inbox[0] ?? '';\n}\n\n/** Active-destination reselects are inert unless they also dismiss the Menu pane. */\nexport function shouldEmitMobileDestinationChange(\n active: MobileDestination,\n next: MobileDestination,\n navigationOpen: boolean\n): boolean {\n return navigationOpen || active !== next;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/** Application-owned tool id for the shell rail and responsive tool views. */\nexport type PanelToolsToolId = string;\n\n/** Canonical Motive shell recipe used when item metadata is omitted. */\nexport type CanonicalPanelToolsToolId =\n | 'search'\n | 'messages'\n | 'agents'\n | 'stacks'\n | 'activity'\n | 'help';\n\nexport const PANEL_TOOLS_TOOL_IDS: CanonicalPanelToolsToolId[] = [\n 'search',\n 'messages',\n 'agents',\n 'stacks',\n 'activity',\n 'help',\n];\n\n/** Rail header slot \u2014 mirrors panel-nav M logo row. */\nexport const PANEL_TOOLS_PRIMARY_TOOL_ID: CanonicalPanelToolsToolId = 'search';\n\n/** Rail footer slot \u2014 flush to the bottom of the tools column. */\nexport const PANEL_TOOLS_FOOTER_TOOL_ID: CanonicalPanelToolsToolId = 'help';\n\nexport const PANEL_TOOLS_LABELS: Record<CanonicalPanelToolsToolId, string> = {\n search: 'Search',\n messages: 'Messages',\n stacks: 'Stacks',\n activity: 'Activity',\n agents: 'Agents',\n help: 'Help & Support',\n};\n\nexport const PANEL_TOOLS_SHORTCUTS: Partial<Record<CanonicalPanelToolsToolId, string>> = {\n search: 'K',\n agents: 'A',\n messages: 'M',\n stacks: 'S',\n activity: 'N',\n help: '/',\n};\n\nexport interface PanelToolsItem {\n id: PanelToolsToolId;\n /** Icon name for <ds-icon>. */\n icon: string;\n /** Visible and accessible fallback label for custom tool ids. */\n label?: string;\n /** Explicit rail region; canonical Search/Help placement is the fallback. */\n railPlacement?: 'header' | 'body' | 'footer';\n /** Stable ordering within the selected rail region. */\n order?: number;\n /** Optional shortcut label displayed by the tooltip. */\n shortcutKey?: string;\n /** Mobile destination recipe; canonical ids retain their explicit defaults. */\n mobileDestination?: 'search' | 'inbox' | 'messages' | 'agents' | 'help';\n /** Whether this rail button is currently pressed/active. */\n selected?: boolean;\n /** Show a notification dot. */\n dot?: boolean;\n isInactive?: boolean;\n ariaLabel?: string;\n}\n\n/** Canonical shell recipe used by Lab and by managed ShellApp examples. */\nexport const PANEL_TOOLS_DEFAULT_ITEMS: PanelToolsItem[] = [\n {\n id: 'search',\n icon: 'MagnifyingGlass',\n label: PANEL_TOOLS_LABELS.search,\n railPlacement: 'header',\n order: 0,\n shortcutKey: PANEL_TOOLS_SHORTCUTS.search,\n mobileDestination: 'search',\n },\n {\n id: 'messages',\n icon: 'MessageBubbleStack',\n label: PANEL_TOOLS_LABELS.messages,\n order: 1,\n shortcutKey: PANEL_TOOLS_SHORTCUTS.messages,\n mobileDestination: 'messages',\n },\n {\n id: 'agents',\n icon: 'AI',\n label: PANEL_TOOLS_LABELS.agents,\n order: 2,\n shortcutKey: PANEL_TOOLS_SHORTCUTS.agents,\n mobileDestination: 'agents',\n },\n {\n id: 'stacks',\n icon: 'ViewMenu',\n label: PANEL_TOOLS_LABELS.stacks,\n order: 3,\n shortcutKey: PANEL_TOOLS_SHORTCUTS.stacks,\n mobileDestination: 'inbox',\n },\n {\n id: 'activity',\n icon: 'Bell',\n label: PANEL_TOOLS_LABELS.activity,\n order: 4,\n shortcutKey: PANEL_TOOLS_SHORTCUTS.activity,\n mobileDestination: 'inbox',\n },\n {\n id: 'help',\n icon: 'CircleQuestion',\n label: PANEL_TOOLS_LABELS.help,\n railPlacement: 'footer',\n order: 5,\n shortcutKey: PANEL_TOOLS_SHORTCUTS.help,\n mobileDestination: 'help',\n },\n];\n\nexport interface PanelToolsHeaderAction {\n id: string;\n icon: string;\n ariaLabel: string;\n triggerId?: string;\n controls?: string;\n expanded?: boolean;\n haspopup?: 'menu' | 'dialog' | 'listbox' | 'tree' | 'grid';\n pressed?: boolean;\n isInactive?: boolean;\n}\n\nexport interface PanelToolsHeaderConfig {\n title?: string;\n showBack?: boolean;\n backIcon?: string;\n backAriaLabel?: string;\n actions?: PanelToolsHeaderAction[];\n}\n\n/** Per-tool header state. The application replaces the object when a tool changes depth or actions. */\nexport type PanelToolsHeaders = Partial<Record<PanelToolsToolId, PanelToolsHeaderConfig>>;\n", "/** Nav chrome style slot \u2014 dashboard vs settings. Colors unified for now; texture hooks use the class. */\nexport type NavChromeStyle = 'dashboard' | 'settings';\n\n/** Document hint for first paint before framework props land. */\nexport const NAV_STYLE_HINT_ATTR = 'data-nav-style';\n\nexport function readNavStyleAttr(attr: string | null): NavChromeStyle | undefined {\n if (attr === 'dashboard' || attr === 'settings') return attr;\n return undefined;\n}\n\nexport function setNavStyleHint(style: NavChromeStyle): void {\n if (typeof document === 'undefined') return;\n document.documentElement.setAttribute(NAV_STYLE_HINT_ATTR, style);\n}\n\nexport function clearNavStyleHint(): void {\n if (typeof document === 'undefined') return;\n document.documentElement.removeAttribute(NAV_STYLE_HINT_ATTR);\n}\n\nexport function resolveNavChromeStyle(\n styleProp: NavChromeStyle,\n hostAttr: string | null,\n docHint?: string | null,\n): NavChromeStyle {\n const fromHost = readNavStyleAttr(hostAttr);\n if (fromHost) return fromHost;\n\n const hint =\n docHint !== undefined\n ? docHint\n : typeof document !== 'undefined'\n ? document.documentElement.getAttribute(NAV_STYLE_HINT_ATTR)\n : null;\n const fromHint = readNavStyleAttr(hint);\n if (fromHint) return fromHint;\n\n return styleProp;\n}\n\nexport function shouldResyncNavChromeStyle(\n renderedStyle: NavChromeStyle,\n style: NavChromeStyle,\n): boolean {\n return renderedStyle !== style;\n}\n", "import type { ChoicePopupAnchorAlignment } from '../../utils/choice-popup-alignment';\nimport type { MenuAlign, MenuSide } from './menu-position';\n\n/** Placement props bindable on `ds-menu` (side, align, offsets). */\nexport interface MenuPlacement {\n side: MenuSide;\n align: MenuAlign;\n anchorAlignment: ChoicePopupAnchorAlignment;\n sideOffset: number | string;\n alignOffset: number | string;\n}\n\n/**\n * Canonical `ds-menu` placement for the **panel-nav footer user menu**.\n * Anchor from `dsNavUserAction` detail `{ anchor }` (id `ds-panel-nav-user-menu-anchor`).\n *\n * Not for BarNav overflow menus \u2014 those use `side=\"bottom\"` / `align=\"end\"` internally.\n * `align: 'end'` bottom-aligns the last choice cell on the anchor; the side offset nudges into the content area:\n * - `sideOffset` space-100 + space-050 (12px): 4px past the panel-nav outer edge (anchor is ~8px inset).\n * - `anchorAlignment: 'choice-cell'`: the shared section inset puts the last row edge on the footer user row.\n */\nexport const PANEL_NAV_USER_MENU_PLACEMENT = {\n side: 'right',\n align: 'end',\n anchorAlignment: 'choice-cell',\n sideOffset: 'calc(var(--dimension-space-100) + var(--dimension-space-050))',\n alignOffset: 0,\n} as const satisfies MenuPlacement;\n\n/**\n * Canonical placement for a menu opened by a PanelTools header action.\n * Matches BarNav overflow: the 32px trigger is 8px inside the 48px header, so\n * a 12px side offset places the popup 4px below the header edge. Choice-cell\n * alignment keeps the final menu item edge aligned with the trigger.\n */\nexport const PANEL_TOOLS_HEADER_MENU_PLACEMENT = {\n side: 'bottom',\n align: 'end',\n anchorAlignment: 'choice-cell',\n sideOffset: 'calc(var(--dimension-space-100) + var(--dimension-space-050))',\n alignOffset: 0,\n} as const satisfies MenuPlacement;\n", "/** Built-in shell chrome wash presets. */\nexport type ShellGradientPreset = 'none' | 'cool' | 'neutral' | 'warm' | 'fresh';\n\nexport const SHELL_GRADIENT_PRESETS: ShellGradientPreset[] = [\n 'none',\n 'cool',\n 'neutral',\n 'warm',\n 'fresh',\n];\n\n/** Wash presets shown after the `none` option in pickers. */\nexport const SHELL_GRADIENT_WASH_PRESETS: Exclude<ShellGradientPreset, 'none'>[] = [\n 'cool',\n 'neutral',\n 'warm',\n 'fresh',\n];\n\n/** Default wash when `gradient-preset` is omitted. */\nexport const DEFAULT_SHELL_GRADIENT_PRESET: ShellGradientPreset = 'neutral';\n\nexport const SHELL_GRADIENT_PRESET_LABELS: Record<ShellGradientPreset, string> = {\n none: 'None',\n cool: 'Cool',\n neutral: 'Neutral',\n warm: 'Warm',\n fresh: 'Fresh',\n};\n\nexport interface ShellGradientStop {\n color: string;\n position: number;\n}\n\nexport interface ShellGradientRecipe {\n opacity: number;\n stops: readonly ShellGradientStop[];\n}\n\nexport interface ShellGradientPickerPreview {\n backgroundColor: string;\n backgroundImage?: string;\n opacity?: number;\n}\n\nexport interface ShellGradientPickerOption {\n value: ShellGradientPreset;\n label: string;\n preview: ShellGradientPickerPreview;\n}\n\nexport interface ShellGradientPickerSection {\n options: ShellGradientPickerOption[];\n}\n\nconst SHELL_GRADIENT_RECIPES: Record<Exclude<ShellGradientPreset, 'none'>, ShellGradientRecipe> = {\n cool: {\n opacity: 0.1,\n stops: [\n { color: 'var(--color-background-transparent)', position: 0 },\n { color: 'var(--color-color-intent-blue-strong-background)', position: 100 },\n ],\n },\n neutral: {\n opacity: 0.1,\n stops: [\n { color: 'var(--color-background-transparent)', position: 0 },\n { color: 'var(--color-color-intent-grey-strong-background)', position: 100 },\n ],\n },\n warm: {\n opacity: 0.1,\n stops: [\n { color: 'var(--color-background-transparent)', position: 0 },\n { color: 'var(--color-color-intent-yellow-strong-background)', position: 100 },\n ],\n },\n fresh: {\n opacity: 0.4,\n stops: [\n { color: 'var(--color-color-intent-cyan-faint-background)', position: 0 },\n { color: 'var(--color-background-transparent)', position: 47 },\n { color: 'var(--color-background-transparent)', position: 58 },\n { color: 'var(--color-color-intent-red-faint-background)', position: 83 },\n { color: 'var(--color-color-intent-pink-faint-background)', position: 100 },\n ],\n },\n};\n\nconst GRADIENT_GEOMETRY = '100% 100% at 0% 0%';\n\nexport function shellGradientPresetStopToken(preset: ShellGradientPreset): string | null {\n if (preset === 'none') return null;\n const stops = SHELL_GRADIENT_RECIPES[preset].stops;\n return stops[stops.length - 1]?.color ?? null;\n}\n\nexport function shellGradientPresetRecipe(preset: ShellGradientPreset): ShellGradientRecipe | null {\n const normalized = normalizeShellGradientPreset(preset);\n return normalized === 'none' ? null : SHELL_GRADIENT_RECIPES[normalized];\n}\n\nexport function shellGradientPresetOpacity(preset: ShellGradientPreset): string {\n return String(shellGradientPresetRecipe(preset)?.opacity ?? 0);\n}\n\nexport function isShellGradientPreset(value: string): value is ShellGradientPreset {\n return (SHELL_GRADIENT_PRESETS as string[]).includes(value);\n}\n\n/**\n * Coerce unknown/absent presets to the default. Runtime values escape the\n * type: removing the reflected `gradient-preset` attribute (e.g. an Angular\n * `[attr.gradient-preset]=\"null\"` binding) drives the prop to null past its\n * field default \u2014 without normalization the stop lookup interpolates the\n * literal string \"undefined\" into CSS and the wash silently disappears.\n */\nexport function normalizeShellGradientPreset(\n value: string | null | undefined,\n): ShellGradientPreset {\n return value != null && isShellGradientPreset(value) ? value : DEFAULT_SHELL_GRADIENT_PRESET;\n}\n\n/** Radial wash for a preset \u2014 transparent at top-left into the intent stop. `none` returns no image. */\nexport function buildShellRadialGradientForPreset(preset: ShellGradientPreset): string {\n const normalized = normalizeShellGradientPreset(preset);\n if (normalized === 'none') return 'none';\n\n return buildShellRadialGradientFromStops(SHELL_GRADIENT_RECIPES[normalized].stops);\n}\n\n/** Build the production shell geometry from an ordered set of design-time stops. */\nexport function buildShellRadialGradientFromStops(stops: readonly ShellGradientStop[]): string {\n const serialized = stops.map(stop => `${stop.color} ${stop.position}%`).join(', ');\n return `radial-gradient(${GRADIENT_GEOMETRY}, ${serialized})`;\n}\n\n/** Generic SwatchPicker sections for the fixed shell appearance presets. */\nexport function shellGradientPickerSections(): ShellGradientPickerSection[] {\n return [\n {\n options: [{\n value: 'none',\n label: SHELL_GRADIENT_PRESET_LABELS.none,\n preview: {\n backgroundColor: 'var(--color-background-secondary)',\n },\n }],\n },\n {\n options: SHELL_GRADIENT_WASH_PRESETS.map(preset => ({\n value: preset,\n label: SHELL_GRADIENT_PRESET_LABELS[preset],\n preview: {\n backgroundColor: 'var(--color-background-secondary)',\n backgroundImage: buildShellRadialGradientForPreset(preset),\n opacity: Number(shellGradientPresetOpacity(preset)),\n },\n })),\n },\n ];\n}\n", "import type { PanelToolsToolId } from '../components/PanelTools/panel-tools-types';\n\nexport type ShellResponsiveMode = 'desktop' | 'tablet' | 'mobile';\nexport type MobileDestination = 'area' | 'search' | 'inbox' | 'messages' | 'agents' | 'help';\nexport type ShellInboxToolId = PanelToolsToolId;\n\nexport const SHELL_DESKTOP_BREAKPOINT = 1200;\nexport const SHELL_MOBILE_BREAKPOINT = 768;\nexport const SHELL_DEFAULT_INBOX_TOOL: ShellInboxToolId = 'activity';\n\nexport function resolveShellResponsiveMode(width: number): ShellResponsiveMode {\n if (width >= SHELL_DESKTOP_BREAKPOINT) return 'desktop';\n if (width >= SHELL_MOBILE_BREAKPOINT) return 'tablet';\n return 'mobile';\n}\n\nexport function resolveManagedShellPageCapacity(\n mode: ShellResponsiveMode,\n toolsOpen: boolean\n): 'roomy' | 'compact' | 'constrained' {\n if (mode === 'desktop') return toolsOpen ? 'compact' : 'roomy';\n return toolsOpen ? 'constrained' : 'compact';\n}\n\nexport function shellMobileDestinationForTool(\n open: boolean,\n tool: PanelToolsToolId | ''\n): MobileDestination {\n if (!open || !tool) return 'area';\n if (tool === 'help') return 'help';\n if (tool === 'search') return 'search';\n if (tool === 'messages') return 'messages';\n if (tool === 'agents') return 'agents';\n return 'inbox';\n}\n\nexport function isShellInboxTool(tool: string): tool is ShellInboxToolId {\n return tool === 'stacks' || tool === 'activity';\n}\n\nexport function resolveAvailableInboxTool(\n preferred: string,\n available: readonly PanelToolsToolId[]\n): ShellInboxToolId | '' {\n const inbox = available.filter(isShellInboxTool);\n if (isShellInboxTool(preferred) && inbox.includes(preferred)) return preferred;\n if (inbox.includes(SHELL_DEFAULT_INBOX_TOOL)) return SHELL_DEFAULT_INBOX_TOOL;\n return inbox[0] ?? '';\n}\n\n/** Active-destination reselects are inert unless they also dismiss the Menu pane. */\nexport function shouldEmitMobileDestinationChange(\n active: MobileDestination,\n next: MobileDestination,\n navigationOpen: boolean\n): boolean {\n return navigationOpen || active !== next;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,6 @@
1
1
  import type { PanelToolsToolId } from '../components/PanelTools/panel-tools-types';
2
2
  export type ShellResponsiveMode = 'desktop' | 'tablet' | 'mobile';
3
- export type MobileDestination = 'area' | 'search' | 'agents' | 'inbox' | 'help';
3
+ export type MobileDestination = 'area' | 'search' | 'inbox' | 'messages' | 'agents' | 'help';
4
4
  export type ShellInboxToolId = PanelToolsToolId;
5
5
  export declare const SHELL_DESKTOP_BREAKPOINT = 1200;
6
6
  export declare const SHELL_MOBILE_BREAKPOINT = 768;
@@ -127,7 +127,7 @@
127
127
  "peerDependencies": {
128
128
  "required": [
129
129
  "@ds-mo/tokens ^6.0.0",
130
- "@ds-mo/icons ^6.4.0"
130
+ "@ds-mo/icons ^6.5.0"
131
131
  ],
132
132
  "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
133
133
  }
@@ -204,7 +204,7 @@
204
204
  "peerDependencies": {
205
205
  "required": [
206
206
  "@ds-mo/tokens ^6.0.0",
207
- "@ds-mo/icons ^6.4.0"
207
+ "@ds-mo/icons ^6.5.0"
208
208
  ],
209
209
  "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
210
210
  }
@@ -123,7 +123,7 @@
123
123
  "peerDependencies": {
124
124
  "required": [
125
125
  "@ds-mo/tokens ^6.0.0",
126
- "@ds-mo/icons ^6.4.0"
126
+ "@ds-mo/icons ^6.5.0"
127
127
  ],
128
128
  "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
129
129
  }
@@ -182,7 +182,7 @@
182
182
  "peerDependencies": {
183
183
  "required": [
184
184
  "@ds-mo/tokens ^6.0.0",
185
- "@ds-mo/icons ^6.4.0"
185
+ "@ds-mo/icons ^6.5.0"
186
186
  ],
187
187
  "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
188
188
  }
@@ -107,7 +107,7 @@
107
107
  "peerDependencies": {
108
108
  "required": [
109
109
  "@ds-mo/tokens ^6.0.0",
110
- "@ds-mo/icons ^6.4.0"
110
+ "@ds-mo/icons ^6.5.0"
111
111
  ],
112
112
  "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
113
113
  }
@@ -144,7 +144,7 @@
144
144
  "peerDependencies": {
145
145
  "required": [
146
146
  "@ds-mo/tokens ^6.0.0",
147
- "@ds-mo/icons ^6.4.0"
147
+ "@ds-mo/icons ^6.5.0"
148
148
  ],
149
149
  "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
150
150
  }
@@ -261,7 +261,7 @@
261
261
  "peerDependencies": {
262
262
  "required": [
263
263
  "@ds-mo/tokens ^6.0.0",
264
- "@ds-mo/icons ^6.4.0"
264
+ "@ds-mo/icons ^6.5.0"
265
265
  ],
266
266
  "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
267
267
  }
@@ -303,7 +303,7 @@
303
303
  "peerDependencies": {
304
304
  "required": [
305
305
  "@ds-mo/tokens ^6.0.0",
306
- "@ds-mo/icons ^6.4.0"
306
+ "@ds-mo/icons ^6.5.0"
307
307
  ],
308
308
  "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
309
309
  }
@@ -277,7 +277,7 @@
277
277
  "peerDependencies": {
278
278
  "required": [
279
279
  "@ds-mo/tokens ^6.0.0",
280
- "@ds-mo/icons ^6.4.0"
280
+ "@ds-mo/icons ^6.5.0"
281
281
  ],
282
282
  "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
283
283
  }
@@ -74,6 +74,7 @@
74
74
  "responsiveBehavior": [
75
75
  "BarTitle does not observe viewport, shell, scroll, or container state. Its owner selects an explicit variant.",
76
76
  "ShellPage is the standard owner for automatic expanded, compact, and constrained selection.",
77
+ "When ShellPage owns BarTitle on a secondary desktop or tablet page, its expanded, compact, and constrained presentations all match that canvas; the separate MobileHeader component remains primary.",
77
78
  "Compact titles use the shared compact-header geometry and md control inset so top-level headings align with BarNav and inline Back geometry aligns with PanelToolHeader. Long headings and section labels truncate independently while Back and action controls retain complete hit targets and accessible names.",
78
79
  "A never-collapse primary action remains visible in constrained mode; the title and section label yield space first."
79
80
  ],
@@ -450,7 +451,7 @@
450
451
  "peerDependencies": {
451
452
  "required": [
452
453
  "@ds-mo/tokens ^6.0.0",
453
- "@ds-mo/icons ^6.4.0"
454
+ "@ds-mo/icons ^6.5.0"
454
455
  ],
455
456
  "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
456
457
  }
@@ -473,7 +474,7 @@
473
474
  "files": [
474
475
  {
475
476
  "path": "src/wc/components/BarTitle/BarTitle.css",
476
- "content": "@import '../../utils/control-density.css';\n@import '../../utils/chrome-header.css';\n@import '../../utils/focus-ring.css';\n@import '../../utils/interaction-fill.css';\n\n:host {\n display: block;\n min-width: 0;\n box-sizing: border-box;\n background: var(--color-background-primary);\n}\n\n:host([data-shell-page-syncing]) {\n visibility: hidden;\n}\n\n.bar-title {\n position: relative;\n min-width: 0;\n box-sizing: border-box;\n background: var(--color-background-primary);\n}\n\n.bar-title::after {\n content: '';\n position: absolute;\n inset: auto var(--ds-bar-title-divider-inset, var(--dimension-space-400)) 0;\n height: var(--dimension-stroke-width-012);\n background: var(--color-border-tertiary);\n pointer-events: none;\n}\n\n.bar-title__inner {\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: var(--dimension-space-100);\n padding: var(--dimension-space-400);\n box-sizing: border-box;\n}\n\n.bar-title__row {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: var(--dimension-space-100);\n min-height: var(--dimension-size-400);\n min-width: 0;\n}\n\n:host(.bar-title-host--expanded) .bar-title__row {\n gap: var(--dimension-space-400);\n}\n\n.bar-title__leading {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n gap: var(--dimension-space-100);\n min-width: 0;\n}\n\n.bar-title__title-row {\n display: flex;\n align-items: center;\n gap: var(--dimension-space-100);\n min-width: 0;\n min-height: var(--dimension-size-400);\n}\n\n.bar-title__identity {\n display: flex;\n flex: 0 1 auto;\n align-items: center;\n gap: var(--dimension-space-050);\n min-width: 0;\n}\n\n.bar-title__back,\n.bar-title__section-chevron {\n flex: 0 0 auto;\n}\n\n.bar-title__breadcrumb {\n display: block;\n width: 100%;\n min-width: 0;\n}\n\n.bar-title__heading {\n display: block;\n width: auto;\n min-width: 0;\n user-select: none;\n}\n\n.bar-title__divider {\n width: var(--dimension-stroke-width-012);\n height: var(--dimension-size-250);\n margin-inline-start: var(--dimension-space-100);\n flex: 0 0 var(--dimension-stroke-width-012);\n background: var(--color-border-tertiary);\n}\n\n.bar-title__section-selector {\n display: flex;\n flex: 0 1 auto;\n min-width: 0;\n max-width: var(--dimension-panel-width-sm);\n}\n\n.bar-title__section-trigger {\n --ds-control-radius: var(--dimension-radius-half);\n\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--ds-control-gap);\n height: var(--ds-control-height);\n min-width: 0;\n max-width: 100%;\n padding-inline: var(--ds-control-padding-inline);\n border: none;\n border-radius: var(--ds-control-radius);\n box-sizing: border-box;\n background: transparent;\n color: var(--color-foreground-secondary);\n cursor: default;\n font-family: inherit;\n user-select: none;\n}\n\n.bar-title__section-trigger--expanded {\n color: var(--color-foreground-primary);\n}\n\n.bar-title__section-trigger--expanded::after,\n.bar-title__section-trigger--expanded:hover::after {\n background: var(--ds-interaction-pressed);\n}\n\n.bar-title__section-label {\n min-width: 0;\n padding-inline: var(--ds-control-label-inset);\n}\n\n.bar-title__actions {\n display: flex;\n align-items: center;\n gap: var(--dimension-space-100);\n flex: 0 0 auto;\n}\n\n.bar-title__description {\n display: block;\n min-width: 0;\n max-width: 100%;\n}\n\n:host(.bar-title-host--compact) .bar-title {\n height: var(--dimension-size-600);\n}\n\n:host(.bar-title-host--compact) .bar-title::after {\n inset-inline: 0;\n}\n\n:host(.bar-title-host--compact) .bar-title__inner {\n flex: 1 1 auto;\n height: 100%;\n min-width: 0;\n padding: 0;\n gap: 0;\n}\n\n:host(.bar-title-host--compact) .bar-title__row {\n height: 100%;\n align-items: center;\n}\n\n:host(.bar-title-host--compact) .bar-title__identity {\n height: var(--dimension-size-400);\n}\n\n:host(.bar-title-host--compact) .bar-title__divider {\n margin-inline-start: 0;\n}\n\n:host(.bar-title-host--compact) .bar-title__heading {\n display: inline-flex;\n flex: 1 1 auto;\n align-items: center;\n height: var(--dimension-size-400);\n padding-inline: calc(var(--ds-control-padding-inline) + var(--ds-control-label-inset));\n box-sizing: border-box;\n}\n",
477
+ "content": "@import '../../utils/control-density.css';\n@import '../../utils/chrome-header.css';\n@import '../../utils/focus-ring.css';\n@import '../../utils/interaction-fill.css';\n\n:host {\n display: block;\n min-width: 0;\n box-sizing: border-box;\n background: var(--_shell-page-header-background, var(--color-background-primary));\n}\n\n:host([data-shell-page-syncing]) {\n visibility: hidden;\n}\n\n.bar-title {\n position: relative;\n min-width: 0;\n box-sizing: border-box;\n background: var(--_shell-page-header-background, var(--color-background-primary));\n}\n\n.bar-title::after {\n content: '';\n position: absolute;\n inset: auto var(--ds-bar-title-divider-inset, var(--dimension-space-400)) 0;\n height: var(--dimension-stroke-width-012);\n background: var(--color-border-tertiary);\n pointer-events: none;\n}\n\n.bar-title__inner {\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: var(--dimension-space-100);\n padding: var(--dimension-space-400);\n box-sizing: border-box;\n}\n\n.bar-title__row {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: var(--dimension-space-100);\n min-height: var(--dimension-size-400);\n min-width: 0;\n}\n\n:host(.bar-title-host--expanded) .bar-title__row {\n gap: var(--dimension-space-400);\n}\n\n.bar-title__leading {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n gap: var(--dimension-space-100);\n min-width: 0;\n}\n\n.bar-title__title-row {\n display: flex;\n align-items: center;\n gap: var(--dimension-space-100);\n min-width: 0;\n min-height: var(--dimension-size-400);\n}\n\n.bar-title__identity {\n display: flex;\n flex: 0 1 auto;\n align-items: center;\n gap: var(--dimension-space-050);\n min-width: 0;\n}\n\n.bar-title__back,\n.bar-title__section-chevron {\n flex: 0 0 auto;\n}\n\n.bar-title__breadcrumb {\n display: block;\n width: 100%;\n min-width: 0;\n}\n\n.bar-title__heading {\n display: block;\n width: auto;\n min-width: 0;\n user-select: none;\n}\n\n.bar-title__divider {\n width: var(--dimension-stroke-width-012);\n height: var(--dimension-size-250);\n margin-inline-start: var(--dimension-space-100);\n flex: 0 0 var(--dimension-stroke-width-012);\n background: var(--color-border-tertiary);\n}\n\n.bar-title__section-selector {\n display: flex;\n flex: 0 1 auto;\n min-width: 0;\n max-width: var(--dimension-panel-width-sm);\n}\n\n.bar-title__section-trigger {\n --ds-control-radius: var(--dimension-radius-half);\n\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--ds-control-gap);\n height: var(--ds-control-height);\n min-width: 0;\n max-width: 100%;\n padding-inline: var(--ds-control-padding-inline);\n border: none;\n border-radius: var(--ds-control-radius);\n box-sizing: border-box;\n background: transparent;\n color: var(--color-foreground-secondary);\n cursor: default;\n font-family: inherit;\n user-select: none;\n}\n\n.bar-title__section-trigger--expanded {\n color: var(--color-foreground-primary);\n}\n\n.bar-title__section-trigger--expanded::after,\n.bar-title__section-trigger--expanded:hover::after {\n background: var(--ds-interaction-pressed);\n}\n\n.bar-title__section-label {\n min-width: 0;\n padding-inline: var(--ds-control-label-inset);\n}\n\n.bar-title__actions {\n display: flex;\n align-items: center;\n gap: var(--dimension-space-100);\n flex: 0 0 auto;\n}\n\n.bar-title__description {\n display: block;\n min-width: 0;\n max-width: 100%;\n}\n\n:host(.bar-title-host--compact) .bar-title {\n height: var(--dimension-size-600);\n}\n\n:host(.bar-title-host--compact) .bar-title::after {\n inset-inline: 0;\n}\n\n:host(.bar-title-host--compact) .bar-title__inner {\n flex: 1 1 auto;\n height: 100%;\n min-width: 0;\n padding: 0;\n gap: 0;\n}\n\n:host(.bar-title-host--compact) .bar-title__row {\n height: 100%;\n align-items: center;\n}\n\n:host(.bar-title-host--compact) .bar-title__identity {\n height: var(--dimension-size-400);\n}\n\n:host(.bar-title-host--compact) .bar-title__divider {\n margin-inline-start: 0;\n}\n\n:host(.bar-title-host--compact) .bar-title__heading {\n display: inline-flex;\n flex: 1 1 auto;\n align-items: center;\n height: var(--dimension-size-400);\n padding-inline: calc(var(--ds-control-padding-inline) + var(--ds-control-label-inset));\n box-sizing: border-box;\n}\n",
477
478
  "type": "registry:ui"
478
479
  },
479
480
  {
@@ -352,7 +352,7 @@
352
352
  "peerDependencies": {
353
353
  "required": [
354
354
  "@ds-mo/tokens ^6.0.0",
355
- "@ds-mo/icons ^6.4.0"
355
+ "@ds-mo/icons ^6.5.0"
356
356
  ],
357
357
  "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
358
358
  }
@@ -172,7 +172,7 @@
172
172
  "peerDependencies": {
173
173
  "required": [
174
174
  "@ds-mo/tokens ^6.0.0",
175
- "@ds-mo/icons ^6.4.0"
175
+ "@ds-mo/icons ^6.5.0"
176
176
  ],
177
177
  "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
178
178
  }
@@ -492,7 +492,7 @@
492
492
  "peerDependencies": {
493
493
  "required": [
494
494
  "@ds-mo/tokens ^6.0.0",
495
- "@ds-mo/icons ^6.4.0"
495
+ "@ds-mo/icons ^6.5.0"
496
496
  ],
497
497
  "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
498
498
  }
@@ -553,7 +553,7 @@
553
553
  "peerDependencies": {
554
554
  "required": [
555
555
  "@ds-mo/tokens ^6.0.0",
556
- "@ds-mo/icons ^6.4.0"
556
+ "@ds-mo/icons ^6.5.0"
557
557
  ],
558
558
  "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
559
559
  }
@@ -209,7 +209,7 @@
209
209
  "peerDependencies": {
210
210
  "required": [
211
211
  "@ds-mo/tokens ^6.0.0",
212
- "@ds-mo/icons ^6.4.0"
212
+ "@ds-mo/icons ^6.5.0"
213
213
  ],
214
214
  "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
215
215
  }
@@ -57,7 +57,7 @@
57
57
  "Omit score to render a centered Score unavailable cell with a tertiary border and no score fill. Set scoreErrorMessage to replace that copy while the measures remain readable.",
58
58
  "Loading replaces the score and measures with skeletons and does not alter the slotted period control. When measures are already supplied, their count preserves the resolved grid shape; otherwise five measure placeholders join the score in the standard six-cell grid.",
59
59
  "At most seven measures are shown. Keep larger collections outside the summary bar rather than turning it into a dense dashboard.",
60
- "The period and filter controls are slotted rather than owned. Use the period slot when the current range is selectable; otherwise periodLabel supplies fixed current copy in the same md control-frame and label-inset anatomy. Use the filter slot for the application-owned comparison-window control. Slotted Selects use hasBorder false so the 48px bar owns their surrounding boundary.",
60
+ "The period and filter controls are slotted rather than owned. Use the period slot when the current range is selectable; otherwise periodLabel supplies fixed current copy in the same md control-frame and label-inset anatomy. Use the filter slot for the application-owned comparison-window control. Slotted Selects use hasBorder false so the 48px bar owns their surrounding boundary and allowClear false because both controls always require one selected reporting period.",
61
61
  "A numeric safety score infers fair from 0–50, good from 51–80, and excellent from 81–100. The level can be supplied explicitly when the displayed value is not numeric. The deprecated band field is ignored.",
62
62
  "The safety score is the first grid cell and uses the same track, 8px outer inset, 6px inner padding, dividers, and responsive behavior as metric cells. The display value removes 8px from both block edges of its line box so it does not increase the shared row height. Score remains nonselectable and excluded from metric roving focus.",
63
63
  "During page-controlled scroll collapse, the component preserves its expanded flow height and stationary reporting bar while the metric grid moves and clips beneath it. Elevation remains fitted to the visible surface.",
@@ -346,7 +346,7 @@
346
346
  "peerDependencies": {
347
347
  "required": [
348
348
  "@ds-mo/tokens ^6.0.0",
349
- "@ds-mo/icons ^6.4.0"
349
+ "@ds-mo/icons ^6.5.0"
350
350
  ],
351
351
  "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
352
352
  }
@@ -364,12 +364,12 @@
364
364
  "files": [
365
365
  {
366
366
  "path": "src/wc/components/CardOverview/CardOverview.css",
367
- "content": "@import '../../utils/interaction-fill.css';\n@import '../../utils/focus-ring.css';\n@import '../../utils/control-density.css';\n@import '../../utils/control-parts.css';\n@import '../../styles/control-elevation.css';\n\n:host {\n display: block;\n box-sizing: border-box;\n container-type: inline-size;\n -webkit-user-select: none;\n user-select: none;\n --ds-card-overview-metric-min: calc(var(--dimension-size-400) * 5);\n --ds-card-overview-divider-width: var(--dimension-stroke-width-012);\n --ds-card-overview-divider-color: var(--color-always-dark-border-tertiary);\n color: var(--color-always-dark-foreground-primary);\n}\n\n.card-overview__surface {\n width: 100%;\n min-width: 0;\n box-sizing: border-box;\n border-radius: var(--dimension-radius-125);\n background: var(--color-always-dark-background);\n color: var(--color-always-dark-foreground-primary);\n overflow-anchor: none;\n}\n\n.card-overview__clip {\n height: 100%;\n min-width: 0;\n border-radius: inherit;\n background: inherit;\n overflow: hidden;\n}\n\n:host(.card-overview--scroll-collapsing) {\n height: var(--ds-card-overview-expanded-height);\n pointer-events: none;\n}\n\n:host(.card-overview--scroll-collapsing) .card-overview__surface {\n height: var(--ds-card-overview-visible-height);\n pointer-events: auto;\n will-change: height;\n}\n\n:host(.card-overview--scroll-collapsing) .card-overview__body {\n transform: translateY(calc(-1 * var(--ds-card-overview-content-offset)));\n will-change: transform;\n}\n\n.card-overview__layout {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n.card-overview__summary {\n position: relative;\n z-index: 1;\n flex: 0 0 auto;\n min-width: 0;\n background: var(--color-always-dark-background);\n}\n\n.card-overview__header {\n display: flex;\n position: relative;\n align-items: center;\n gap: 0;\n width: 100%;\n height: var(--dimension-size-600);\n min-width: 0;\n padding: var(--dimension-space-100);\n box-sizing: border-box;\n}\n\n.card-overview__header::after {\n content: '';\n position: absolute;\n inset-inline: 0;\n inset-block-end: 0;\n height: var(--ds-card-overview-divider-width);\n background: var(--ds-card-overview-divider-color);\n pointer-events: none;\n}\n\n.card-overview__period {\n display: flex;\n flex: 0 1 auto;\n align-items: center;\n gap: 0;\n min-width: 0;\n min-height: var(--ds-control-height);\n overflow: hidden;\n white-space: nowrap;\n}\n\n.card-overview__period-current,\n.card-overview__period-comparison {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.card-overview__period-current {\n display: flex;\n flex: 0 1 auto;\n align-items: center;\n}\n\n.card-overview__period-fixed {\n flex: 0 1 auto;\n min-width: 0;\n}\n\n.card-overview__period-comparison {\n flex: 0 0 auto;\n}\n\n.card-overview__filter {\n display: flex;\n flex: 0 1 auto;\n align-items: center;\n min-width: 0;\n}\n\n.card-overview__body {\n display: flex;\n position: relative;\n z-index: 0;\n flex-direction: column;\n min-width: 0;\n transform: translateY(0);\n}\n\n.card-overview__metrics {\n display: grid;\n flex: 1 1 auto;\n grid-template-columns: repeat(\n var(--ds-card-overview-grid-columns, auto-fit),\n minmax(min(100%, var(--ds-card-overview-metric-min)), 1fr)\n );\n align-content: stretch;\n min-width: 0;\n overflow: clip;\n}\n\n.card-overview__score,\n.card-overview__metric {\n display: flex;\n min-width: 0;\n padding: var(--dimension-space-100);\n box-shadow:\n var(--ds-card-overview-divider-width) 0 0 0 var(--ds-card-overview-divider-color),\n 0 var(--ds-card-overview-divider-width) 0 0 var(--ds-card-overview-divider-color);\n box-sizing: border-box;\n}\n\n.card-overview__score-content,\n.card-overview__metric-action {\n display: flex;\n flex: 1 1 auto;\n min-width: 0;\n padding: var(--dimension-space-075);\n border-radius: var(--dimension-radius-025);\n box-sizing: border-box;\n}\n\n.card-overview__score-content {\n align-items: center;\n justify-content: flex-start;\n /*\n * Sits the fill 16px from the cell's left edge, on top of the 8px cell padding.\n * Metric cells keep the shared inner inset because their content is text; the\n * fill is a filled box and needs more room around it to read as inset.\n */\n padding-inline-start: var(--dimension-space-100);\n gap: var(--dimension-space-100);\n}\n\n/*\n * The level fill wraps the score figure alone. Label and trend sit outside it so\n * they keep the same colors and baselines as every other metric cell, and are\n * never held to the fill's contrast.\n */\n.card-overview__score-badge {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n justify-content: center;\n /*\n * The padding gives the fill its own breathing room around the figure, and the\n * matching negative margin keeps that padding out of layout so the cell still\n * measures the same as a metric cell.\n */\n margin-block: calc(-1 * var(--dimension-space-050));\n padding: var(--dimension-space-050);\n border-radius: var(--dimension-radius-025);\n background: var(--color-always-dark-interaction-active);\n color: var(--color-always-dark-foreground-primary);\n}\n\n.card-overview__score-badge--fair {\n background: var(--color-safety-score-background-fair);\n color: var(--color-safety-score-foreground-on-fair);\n}\n\n.card-overview__score-badge--good {\n background: var(--color-safety-score-background-good);\n color: var(--color-safety-score-foreground-on-good);\n}\n\n.card-overview__score-badge--excellent {\n background: var(--color-safety-score-background-excellent);\n color: var(--color-safety-score-foreground-on-excellent);\n}\n\n/* Mirrors .card-overview__metric-content so labels and trends line up across cells. */\n.card-overview__score-copy {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n justify-content: center;\n align-items: flex-start;\n gap: var(--dimension-space-050);\n min-width: 0;\n}\n\n/*\n * The display line box is taller than the figure needs, so it is cropped to keep\n * the fill from driving the cell taller than a metric cell's label-plus-figure\n * column.\n */\n.card-overview__score-value,\n.card-overview__score-badge ds-skeleton {\n flex: 0 0 auto;\n margin-block: calc(-1 * var(--dimension-space-100));\n}\n\n.card-overview__score-content--error {\n align-items: center;\n justify-content: center;\n /* No fill to align, so this box keeps the metric cells' inner inset. */\n padding-inline-start: var(--dimension-space-075);\n border: var(--ds-card-overview-divider-width) solid\n var(--color-always-dark-border-tertiary);\n background: transparent;\n color: var(--color-always-dark-foreground-negative);\n text-align: center;\n}\n\n.card-overview__metric-action {\n flex-direction: column;\n justify-content: center;\n gap: var(--dimension-space-050);\n}\n\n.card-overview__metric-action[role='button'] {\n cursor: default;\n}\n\n.card-overview__metric-content {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n justify-content: center;\n gap: var(--dimension-space-050);\n min-width: 0;\n}\n\n.card-overview__metric-label {\n min-width: 0;\n}\n\n.card-overview__metric-figure {\n display: flex;\n align-items: baseline;\n gap: var(--dimension-space-100);\n min-width: 0;\n}\n\n.card-overview__trend {\n flex: 0 0 auto;\n white-space: nowrap;\n}\n\n:host(.card-overview--stacked) .card-overview__metrics {\n grid-template-columns: minmax(0, 1fr);\n}\n\n:host(.card-overview--compact) {\n height: var(--dimension-size-600);\n min-height: var(--dimension-size-600);\n}\n\n:host(.card-overview--compact) .card-overview__surface,\n:host(.card-overview--compact) .card-overview__clip,\n:host(.card-overview--compact) .card-overview__layout,\n:host(.card-overview--compact) .card-overview__summary {\n width: 100%;\n height: 100%;\n}\n\n:host(.card-overview--compact) .card-overview__header::after {\n display: none;\n}\n\n@media (forced-colors: active) {\n .card-overview__header::after {\n background: var(--ds-forced-color-content);\n }\n\n .card-overview__score-badge,\n .card-overview__score-content--error {\n border: var(--dimension-stroke-width-012) solid var(--ds-forced-color-content);\n background: var(--ds-forced-color-surface);\n color: var(--ds-forced-color-content);\n }\n}\n",
367
+ "content": "@import '../../utils/interaction-fill.css';\n@import '../../utils/focus-ring.css';\n@import '../../utils/control-density.css';\n@import '../../utils/control-parts.css';\n@import '../../styles/control-elevation.css';\n\n:host {\n display: block;\n box-sizing: border-box;\n container-type: inline-size;\n -webkit-user-select: none;\n user-select: none;\n --ds-card-overview-metric-min: calc(var(--dimension-size-400) * 5);\n --ds-card-overview-divider-width: var(--dimension-stroke-width-012);\n --ds-card-overview-divider-color: var(--color-always-dark-border-tertiary);\n color: var(--color-always-dark-foreground-primary);\n}\n\n.card-overview__surface {\n width: 100%;\n min-width: 0;\n box-sizing: border-box;\n border-radius: var(--dimension-radius-125);\n background: var(--color-always-dark-background);\n color: var(--color-always-dark-foreground-primary);\n overflow-anchor: none;\n}\n\n.card-overview__clip {\n height: 100%;\n min-width: 0;\n border-radius: inherit;\n background: inherit;\n overflow: hidden;\n}\n\n:host(.card-overview--scroll-collapsing) {\n height: var(--ds-card-overview-expanded-height);\n pointer-events: none;\n}\n\n:host(.card-overview--scroll-collapsing) .card-overview__surface {\n height: var(--ds-card-overview-visible-height);\n pointer-events: auto;\n will-change: height;\n}\n\n:host(.card-overview--scroll-collapsing) .card-overview__body {\n transform: translateY(calc(-1 * var(--ds-card-overview-content-offset)));\n will-change: transform;\n}\n\n.card-overview__layout {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n.card-overview__summary {\n position: relative;\n z-index: 1;\n flex: 0 0 auto;\n min-width: 0;\n background: var(--color-always-dark-background);\n}\n\n.card-overview__header {\n display: flex;\n position: relative;\n align-items: center;\n gap: 0;\n width: 100%;\n height: var(--dimension-size-600);\n min-width: 0;\n padding: var(--dimension-space-100);\n box-sizing: border-box;\n}\n\n.card-overview__header::after {\n content: '';\n position: absolute;\n inset-inline: 0;\n inset-block-end: 0;\n height: var(--ds-card-overview-divider-width);\n background: var(--ds-card-overview-divider-color);\n pointer-events: none;\n}\n\n.card-overview__period {\n display: flex;\n flex: 0 1 auto;\n align-items: center;\n gap: 0;\n min-width: 0;\n min-height: var(--ds-control-height);\n overflow: hidden;\n white-space: nowrap;\n}\n\n.card-overview__period-current,\n.card-overview__period-comparison {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.card-overview__period-current {\n display: flex;\n flex: 0 1 auto;\n align-items: center;\n}\n\n.card-overview__period-fixed {\n flex: 0 1 auto;\n min-width: 0;\n}\n\n.card-overview__period-comparison {\n flex: 0 0 auto;\n}\n\n.card-overview__filter {\n display: flex;\n flex: 0 1 auto;\n align-items: center;\n min-width: 0;\n}\n\n.card-overview__body {\n display: flex;\n position: relative;\n z-index: 0;\n flex-direction: column;\n min-width: 0;\n transform: translateY(0);\n}\n\n.card-overview__metrics {\n display: grid;\n flex: 1 1 auto;\n grid-template-columns: repeat(\n var(--ds-card-overview-grid-columns, auto-fit),\n minmax(min(100%, var(--ds-card-overview-metric-min)), 1fr)\n );\n align-content: stretch;\n min-width: 0;\n overflow: clip;\n}\n\n.card-overview__score,\n.card-overview__metric {\n display: flex;\n min-width: 0;\n padding: var(--dimension-space-100);\n box-shadow:\n var(--ds-card-overview-divider-width) 0 0 0 var(--ds-card-overview-divider-color),\n 0 var(--ds-card-overview-divider-width) 0 0 var(--ds-card-overview-divider-color);\n box-sizing: border-box;\n}\n\n.card-overview__score-content,\n.card-overview__metric-action {\n display: flex;\n flex: 1 1 auto;\n min-width: 0;\n padding: var(--dimension-space-075);\n border-radius: var(--dimension-radius-025);\n box-sizing: border-box;\n}\n\n.card-overview__score-content {\n align-items: center;\n justify-content: flex-start;\n /*\n * Sits the fill 16px from the cell's left edge, on top of the 8px cell padding.\n * Metric cells keep the shared inner inset because their content is text; the\n * fill is a filled box and needs more room around it to read as inset.\n */\n padding-inline-start: var(--dimension-space-100);\n gap: var(--dimension-space-100);\n}\n\n/*\n * The level fill wraps the score figure alone. The trend sits outside it so it\n * keeps the same color and baseline as every other metric cell, and is never\n * held to the fill's contrast.\n */\n.card-overview__score-badge {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n justify-content: center;\n /*\n * The padding gives the fill its own breathing room around the figure, and the\n * matching negative margin keeps that padding out of layout so the cell still\n * measures the same as a metric cell.\n */\n margin-block: calc(-1 * var(--dimension-space-050));\n padding: var(--dimension-space-050);\n border-radius: var(--dimension-radius-025);\n background: var(--color-always-dark-interaction-active);\n color: var(--color-always-dark-foreground-primary);\n}\n\n.card-overview__score-badge--fair {\n background: var(--color-safety-score-background-fair);\n color: var(--color-safety-score-foreground-on-fair);\n}\n\n.card-overview__score-badge--good {\n background: var(--color-safety-score-background-good);\n color: var(--color-safety-score-foreground-on-good);\n}\n\n.card-overview__score-badge--excellent {\n background: var(--color-safety-score-background-excellent);\n color: var(--color-safety-score-foreground-on-excellent);\n}\n\n/* Mirrors .card-overview__metric-content so labels and trends line up across cells. */\n.card-overview__score-copy {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n justify-content: center;\n align-items: flex-start;\n gap: var(--dimension-space-050);\n min-width: 0;\n}\n\n.card-overview__score-label-spacer {\n visibility: hidden;\n}\n\n/*\n * The display line box is taller than the figure needs, so it is cropped to keep\n * the fill from driving the cell taller than a metric cell's label-plus-figure\n * column.\n */\n.card-overview__score-value,\n.card-overview__score-badge ds-skeleton {\n flex: 0 0 auto;\n margin-block: calc(-1 * var(--dimension-space-100));\n}\n\n.card-overview__score-content--error {\n align-items: center;\n justify-content: center;\n /* No fill to align, so this box keeps the metric cells' inner inset. */\n padding-inline-start: var(--dimension-space-075);\n border: var(--ds-card-overview-divider-width) solid\n var(--color-always-dark-border-tertiary);\n background: transparent;\n color: var(--color-always-dark-foreground-negative);\n text-align: center;\n}\n\n.card-overview__metric-action {\n flex-direction: column;\n justify-content: center;\n gap: var(--dimension-space-050);\n}\n\n.card-overview__metric-action[role='button'] {\n cursor: default;\n}\n\n.card-overview__metric-content {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n justify-content: center;\n gap: var(--dimension-space-050);\n min-width: 0;\n}\n\n.card-overview__metric-label {\n min-width: 0;\n}\n\n.card-overview__metric-figure {\n display: flex;\n align-items: baseline;\n gap: var(--dimension-space-050);\n min-width: 0;\n}\n\n.card-overview__trend {\n flex: 0 0 auto;\n white-space: nowrap;\n}\n\n:host(.card-overview--stacked) .card-overview__metrics {\n grid-template-columns: minmax(0, 1fr);\n}\n\n:host(.card-overview--compact) {\n height: var(--dimension-size-600);\n min-height: var(--dimension-size-600);\n}\n\n:host(.card-overview--compact) .card-overview__surface,\n:host(.card-overview--compact) .card-overview__clip,\n:host(.card-overview--compact) .card-overview__layout,\n:host(.card-overview--compact) .card-overview__summary {\n width: 100%;\n height: 100%;\n}\n\n:host(.card-overview--compact) .card-overview__header::after {\n display: none;\n}\n\n@media (forced-colors: active) {\n .card-overview__header::after {\n background: var(--ds-forced-color-content);\n }\n\n .card-overview__score-badge,\n .card-overview__score-content--error {\n border: var(--dimension-stroke-width-012) solid var(--ds-forced-color-content);\n background: var(--ds-forced-color-surface);\n color: var(--ds-forced-color-content);\n }\n}\n",
368
368
  "type": "registry:ui"
369
369
  },
370
370
  {
371
371
  "path": "src/wc/components/CardOverview/CardOverview.tsx",
372
- "content": "import {\n Component,\n Element,\n Event,\n EventEmitter,\n forceUpdate,\n h,\n Host,\n Prop,\n State,\n} from '@stencil/core';\nimport { resolveCssLengthPx, TOKEN_DEFAULTS } from '../../utils';\nimport type { TextColor, TextVariant } from '../Text/text-types';\nimport type { MetricTrend } from '../../utils/metric-change';\nimport type {\n CardOverviewLayout,\n CardOverviewVariant,\n OverviewMetric,\n OverviewScore,\n} from './card-overview-types';\nimport {\n findNextOverviewMetricIndex,\n resolveCardOverviewCollapseGeometry,\n resolveOverviewGridColumns,\n resolveOverviewRovingIndex,\n resolveSafetyScoreLevel,\n} from './card-overview-controller';\n\n/**\n * Metric cells below this width drop a grid column rather than compress further.\n *\n * A literal rather than a token: this is a layout threshold for a grid cell, and\n * the dimension scale has no token for that. The 200px tokens it could borrow\n * (`menu-width-xs`, `form-width-xs`, `panel-width-2xs`) all name other\n * components, so binding to one would couple this grid to an unrelated contract.\n * Consumers override with the `metricMinWidth` prop.\n */\nconst DEFAULT_METRIC_MIN_WIDTH = '200px';\n\n/** Skeleton cells rendered while loading with no metrics supplied yet. */\nconst DEFAULT_LOADING_METRIC_COUNT = 5;\n\n/** Maximum number of comparable measures the summary bar presents at once. */\nconst MAX_METRIC_COUNT = 7;\n\nconst TREND_COLORS: Record<MetricTrend['tone'], TextColor> = {\n positive: 'var(--color-always-dark-foreground-positive)',\n negative: 'var(--color-always-dark-foreground-negative)',\n neutral: 'var(--color-always-dark-foreground-secondary)',\n};\n\nconst ALWAYS_DARK_PRIMARY: TextColor = 'var(--color-always-dark-foreground-primary)';\nconst ALWAYS_DARK_SECONDARY: TextColor = 'var(--color-always-dark-foreground-secondary)';\n\n@Component({\n tag: 'ds-card-overview',\n styleUrl: 'CardOverview.css',\n scoped: true,\n})\nexport class CardOverview {\n @Element() el!: HTMLElement;\n\n /** Full summary card, or the condensed 48px summary bar. */\n @Prop() variant: CardOverviewVariant = 'default';\n\n /** Intrinsic responsive layout, or a page-owned single-column stack. */\n @Prop() layout: CardOverviewLayout = 'auto';\n\n /** Optional nonselectable safety score rendered as the first grid cell. */\n @Prop() score: OverviewScore | undefined;\n\n /** Fixed current date or range. Replaced by content in the `period` slot. */\n @Prop() periodLabel: string = '';\n\n /** Copy between the current period and comparison control, usually `vs.`. */\n @Prop() comparisonLabel: string = '';\n\n /** Measures rendered in the responsive grid. Only the first seven are shown. */\n @Prop() metrics: OverviewMetric[] = [];\n\n /**\n * Width a metric cell may shrink to before the grid drops a column. The grid\n * uses this threshold while choosing an evenly distributed column count.\n */\n @Prop() metricMinWidth: string = DEFAULT_METRIC_MIN_WIDTH;\n\n /** Replace the score and metrics with skeletons while data resolves. */\n @Prop() isLoading: boolean = false;\n\n /** Message shown in place of the score when its figure cannot be resolved. */\n @Prop() scoreErrorMessage: string | undefined;\n\n /** Accessible name for the region. */\n @Prop() overviewLabel: string = 'Overview';\n\n /**\n * Page-controlled visual collapse from the full card (`0`) toward its 48px\n * compact handoff height (`1`). The component preserves its expanded flow\n * height, keeps the period bar stationary, and moves/clips the grid beneath\n * it. The page still owns sticky positioning and the final compact handoff.\n */\n @Prop() scrollCollapseProgress: number = 0;\n\n /** Emitted when a metric that is not inactive is activated. */\n @Event() dsMetricSelect!: EventEmitter<OverviewMetric>;\n\n /** Roving tab stop across selectable metrics. */\n @State() private focusedMetricIndex: number = 0;\n @State() private expandedHeight: number = 0;\n @State() private gridColumns: number | undefined;\n\n private layoutEl?: HTMLElement;\n private layoutResizeObserver: ResizeObserver | null = null;\n /** The node the observer is bound to, which a later render can replace. */\n private observedLayoutEl?: HTMLElement;\n\n componentDidLoad() {\n this.observeLayout();\n }\n\n componentDidRender() {\n // Re-bind after HMR when DidLoad's observer was dropped, and whenever a\n // render swapped the layout node out from under the observer: the ref points\n // at the new node while the observer still watches the detached one, which\n // never resizes again. The grid would then keep its first measured column\n // count for the life of the component.\n if (!this.layoutResizeObserver || this.observedLayoutEl !== this.layoutEl) {\n this.observeLayout();\n } else {\n this.updateLayoutGeometry();\n }\n }\n\n disconnectedCallback() {\n this.layoutResizeObserver?.disconnect();\n this.layoutResizeObserver = null;\n this.observedLayoutEl = undefined;\n }\n\n private get visibleMetrics(): OverviewMetric[] {\n return this.metrics.slice(0, MAX_METRIC_COUNT);\n }\n\n private get visibleCellCount(): number {\n const metricCount = this.isLoading ? this.loadingMetricCount : this.visibleMetrics.length;\n return 1 + metricCount;\n }\n\n /** Preserve an authored data shape while loading, or use the standard six-cell grid. */\n private get loadingMetricCount(): number {\n return this.visibleMetrics.length || DEFAULT_LOADING_METRIC_COUNT;\n }\n\n private get resolvedScrollCollapseProgress(): number {\n if (this.variant === 'compact' || !Number.isFinite(this.scrollCollapseProgress)) return 0;\n return Math.min(1, Math.max(0, this.scrollCollapseProgress));\n }\n\n private get scrollCollapseGeometry() {\n const compactHeight = resolveCssLengthPx(TOKEN_DEFAULTS.size600, 48);\n return resolveCardOverviewCollapseGeometry({\n variant: this.variant,\n progress: this.resolvedScrollCollapseProgress,\n expandedHeight: this.expandedHeight,\n compactHeight,\n });\n }\n\n private observeLayout() {\n const layout = this.layoutEl;\n if (!layout) return;\n\n const bounds = layout.getBoundingClientRect();\n this.updateLayoutGeometry(bounds.width, bounds.height);\n if (typeof ResizeObserver === 'undefined') return;\n\n this.layoutResizeObserver?.disconnect();\n this.layoutResizeObserver = new ResizeObserver(entries => {\n const rect = entries[0]?.contentRect;\n if (rect) this.updateLayoutGeometry(rect.width, rect.height);\n });\n this.layoutResizeObserver.observe(layout);\n this.observedLayoutEl = layout;\n }\n\n private updateLayoutGeometry(width?: number, height?: number) {\n const layout = this.layoutEl;\n if (!layout) return;\n\n const bounds = width === undefined || height === undefined ? layout.getBoundingClientRect() : null;\n const resolvedWidth = width ?? bounds?.width ?? 0;\n const resolvedHeight = height ?? bounds?.height ?? 0;\n\n let changed = false;\n\n if (resolvedHeight > 0 && Math.abs(resolvedHeight - this.expandedHeight) >= 0.5) {\n this.expandedHeight = resolvedHeight;\n changed = true;\n }\n\n const columns = resolveOverviewGridColumns({\n cellCount: this.visibleCellCount,\n availableWidth: resolvedWidth,\n minCellWidth: resolveCssLengthPx(this.metricMinWidth, DEFAULT_METRIC_MIN_WIDTH),\n });\n if (columns !== this.gridColumns) {\n this.gridColumns = columns;\n changed = true;\n }\n\n // The column count is written straight to the host rather than through the\n // rendered style object. Measurement happens in `componentDidLoad` and in the\n // ResizeObserver callback, both outside a render cycle, and the host's style\n // is not patched again after the first render — so a rendered value would stay\n // pinned to whatever the first paint produced, before any width was known.\n if (this.gridColumns) {\n this.el.style.setProperty('--ds-card-overview-grid-columns', String(this.gridColumns));\n } else {\n this.el.style.removeProperty('--ds-card-overview-grid-columns');\n }\n\n if (changed) forceUpdate(this);\n }\n\n /** Index of the roving tab stop, skipping inactive metrics. */\n private get rovingIndex(): number {\n return resolveOverviewRovingIndex(this.visibleMetrics, this.focusedMetricIndex);\n }\n\n private selectMetric(metric: OverviewMetric, index: number) {\n if (metric.isInactive) return;\n this.focusedMetricIndex = index;\n this.dsMetricSelect.emit(metric);\n }\n\n /** Move the roving tab stop, wrapping and skipping inactive metrics. */\n private moveFocus(from: number, step: number) {\n const metrics = this.visibleMetrics;\n const next = findNextOverviewMetricIndex(metrics, from, step < 0 ? -1 : 1);\n if (next < 0) return;\n\n this.focusedMetricIndex = next;\n const cells = this.el.querySelectorAll<HTMLElement>('.card-overview__metric-action');\n cells[next]?.focus();\n }\n\n private handleMetricKeyDown = (event: KeyboardEvent, index: number) => {\n switch (event.key) {\n case 'ArrowRight':\n case 'ArrowDown':\n event.preventDefault();\n this.moveFocus(index, 1);\n break;\n case 'ArrowLeft':\n case 'ArrowUp':\n event.preventDefault();\n this.moveFocus(index, -1);\n break;\n default:\n break;\n }\n };\n\n /**\n * A skeleton bar matching the type metrics of the text it stands in for, so the\n * loading state holds the same shape and rhythm as the resolved content.\n *\n * `background` is always passed so the base and shimmer follow the card's\n * permanently dark surface in both themes.\n */\n private bar(textVariant: TextVariant, width: string, className?: string) {\n return (\n <ds-skeleton\n class={className}\n variant=\"text\"\n textVariant={textVariant}\n width={width}\n background=\"always-dark\"\n />\n );\n }\n\n /**\n * Arrow and change in one text node.\n *\n * The arrow is a typeface glyph rather than an icon so it inherits the exact\n * size, weight, and baseline of the value beside it; an icon would need its\n * own size scale and would drift whenever the type scale changed.\n *\n * Tone is supplied by the caller and never inferred here.\n */\n private renderTrend(trend: MetricTrend | undefined, variant: TextVariant) {\n if (!trend) return null;\n return (\n <ds-text\n as=\"span\"\n class={{\n 'card-overview__trend': true,\n 'ds-control-label-box': true,\n [`card-overview__trend--${trend.tone}`]: true,\n }}\n variant={variant}\n color={TREND_COLORS[trend.tone]}\n fontFeature=\"tabular-nums\"\n >\n {trend.direction === 'up' ? '↑' : '↓'} {trend.value}\n </ds-text>\n );\n }\n\n private renderScore() {\n if (this.isLoading) {\n return (\n <div class=\"card-overview__score\" part=\"score\">\n <div class=\"card-overview__score-content\">\n <div class=\"card-overview__score-badge\">\n {this.bar('text-display-small', '40px')}\n </div>\n <div class=\"card-overview__score-copy\">\n {this.bar('text-body-small', '64px', 'card-overview__score-label')}\n {this.bar('text-body-medium', '28px')}\n </div>\n </div>\n </div>\n );\n }\n\n const unavailableMessage =\n this.scoreErrorMessage || (!this.score ? 'Score unavailable' : undefined);\n if (unavailableMessage) {\n return (\n /* eslint-disable-next-line local/prefer-direct-ds-text -- The score track owns the grid divider and 8px outer inset. */\n <div class=\"card-overview__score\" part=\"score\">\n <ds-text\n as=\"span\"\n class=\"card-overview__score-content card-overview__score-content--error\"\n variant=\"text-body-medium\"\n color=\"inherit\"\n role=\"alert\"\n >\n {unavailableMessage}\n </ds-text>\n </div>\n );\n }\n\n const score = this.score;\n if (!score) return null;\n const level = score.level ?? resolveSafetyScoreLevel(score.value);\n\n return (\n <div class=\"card-overview__score\" part=\"score\">\n <div class=\"card-overview__score-content\">\n {/* eslint-disable-next-line local/prefer-direct-ds-text -- The fill owns its own box: it pads out to 52px and crops the display line box, which the text element cannot do to itself. */}\n <div\n class={{\n 'card-overview__score-badge': true,\n [`card-overview__score-badge--${level}`]: Boolean(level),\n }}\n >\n <ds-text\n as=\"span\"\n class=\"card-overview__score-value ds-control-label-box\"\n variant=\"text-display-small\"\n emphasis\n color=\"inherit\"\n fontFeature=\"tabular-nums\"\n >\n {score.value}\n </ds-text>\n </div>\n <div class=\"card-overview__score-copy\">\n <ds-text\n as=\"span\"\n class=\"card-overview__score-label ds-control-label-box\"\n variant=\"text-body-small\"\n color={ALWAYS_DARK_SECONDARY}\n >\n {score.label}\n </ds-text>\n {this.renderTrend(score.trend, 'text-body-medium')}\n </div>\n </div>\n </div>\n );\n }\n\n private renderMetric(metric: OverviewMetric, index: number) {\n const selectable = !metric.isInactive;\n const label = (\n <ds-text\n as=\"span\"\n class=\"card-overview__metric-label ds-control-label-box\"\n variant=\"text-body-small\"\n color={ALWAYS_DARK_SECONDARY}\n >\n {metric.label}\n </ds-text>\n );\n\n return (\n <div class=\"card-overview__metric\" part=\"metric\">\n <div\n class={{\n 'card-overview__metric-action': true,\n 'card-overview__metric-action--inactive': !selectable,\n // Selection targets get the shared wash; press scaling is not used here\n // so the grid keeps its columns aligned. See docs/control-press-policy.md.\n 'ds-interaction-fill': selectable,\n 'ds-interaction-fill--on-always-dark': selectable,\n 'ds-focus-ring-inset': selectable,\n }}\n role={selectable ? 'button' : undefined}\n tabIndex={selectable && index === this.rovingIndex ? 0 : -1}\n onClick={() => this.selectMetric(metric, index)}\n onKeyDown={event => this.handleMetricKeyDown(event, index)}\n onFocusin={() => {\n if (selectable) this.focusedMetricIndex = index;\n }}\n >\n <div class=\"ds-interaction-fill__content card-overview__metric-content\">\n {metric.labelTooltip ? (\n <ds-tooltip label={metric.labelTooltip} side=\"top\" size=\"sm\">\n {label}\n </ds-tooltip>\n ) : (\n label\n )}\n <div class=\"card-overview__metric-figure\">\n <ds-text\n as=\"span\"\n class=\"card-overview__metric-value ds-control-label-box\"\n variant=\"text-body-medium\"\n color={ALWAYS_DARK_PRIMARY}\n fontFeature=\"tabular-nums\"\n >\n {metric.value}\n </ds-text>\n {this.renderTrend(metric.trend, 'text-body-medium')}\n </div>\n </div>\n </div>\n </div>\n );\n }\n\n private renderMetrics() {\n if (this.isLoading) {\n return [\n this.renderScore(),\n ...Array.from({ length: this.loadingMetricCount }, (_, index) => (\n <div class=\"card-overview__metric\" key={`loading-${index}`}>\n <div class=\"card-overview__metric-action card-overview__metric-action--inactive\">\n <div class=\"card-overview__metric-content\">\n {this.bar('text-body-small', '35%', 'card-overview__metric-label')}\n <div class=\"card-overview__metric-figure\">\n {this.bar('text-body-medium', '40px')}\n {/* Match renderTrend's type canvas and the score trend's 28px width. */}\n {this.bar('text-body-medium', '28px')}\n </div>\n </div>\n </div>\n </div>\n )),\n ];\n }\n\n return [\n this.renderScore(),\n ...this.visibleMetrics.map((metric, index) => this.renderMetric(metric, index)),\n ];\n }\n\n render() {\n const compact = this.variant === 'compact';\n const collapse = this.scrollCollapseGeometry;\n\n // Omit absent custom properties rather than handing them an undefined value.\n // Stencil serialises undefined to the string \"undefined\", which is invalid in\n // `repeat()` and voids the whole grid-template-columns declaration — the grid\n // then collapses to one implicit column instead of using the `auto-fit`\n // fallback baked into the stylesheet.\n const customProperties: Record<string, string> = {\n '--ds-card-overview-metric-min': this.metricMinWidth,\n };\n if (this.gridColumns) {\n customProperties['--ds-card-overview-grid-columns'] = String(this.gridColumns);\n }\n if (collapse.active) {\n customProperties['--ds-card-overview-expanded-height'] = `${collapse.expandedHeight}px`;\n customProperties['--ds-card-overview-visible-height'] = `${collapse.visibleHeight}px`;\n customProperties['--ds-card-overview-content-offset'] = `${collapse.offset}px`;\n }\n\n return (\n <Host\n class={{\n 'card-overview': true,\n 'card-overview--compact': compact,\n 'card-overview--stacked': !compact && this.layout === 'stacked',\n 'card-overview--scroll-collapsing': collapse.active,\n }}\n role=\"region\"\n aria-label={this.overviewLabel}\n aria-busy={this.isLoading ? 'true' : undefined}\n style={customProperties}\n >\n <div\n class={{\n 'card-overview__surface': true,\n // Split shadow and inset highlight, so the opaque surface cannot cover\n // the highlight the way a combined elevation shadow would.\n 'ds-control-elevation': true,\n 'ds-control-elevation--sm': !compact,\n 'ds-control-elevation--floating': compact,\n }}\n >\n <div class=\"card-overview__clip\">\n <div\n ref={element => {\n this.layoutEl = (element as HTMLElement) ?? undefined;\n }}\n class={{\n 'card-overview__layout': true,\n }}\n >\n <div class=\"card-overview__summary\">\n <div class=\"card-overview__header ds-control--md\">\n <div class=\"card-overview__period\">\n <div class=\"card-overview__period-current\">\n <slot name=\"period\">\n {this.periodLabel && (\n /* eslint-disable-next-line local/prefer-direct-ds-text -- Fixed copy uses the same structural frame and label inset as a slotted Select. */\n <div class=\"card-overview__period-fixed ds-control-frame\">\n <ds-text\n as=\"span\"\n class=\"ds-control-label-box\"\n variant=\"text-body-medium\"\n emphasis\n color={ALWAYS_DARK_PRIMARY}\n >\n {this.periodLabel}\n </ds-text>\n </div>\n )}\n </slot>\n </div>\n {this.comparisonLabel && (\n <ds-text\n as=\"span\"\n class=\"card-overview__period-comparison ds-control-label-box\"\n variant=\"text-body-medium\"\n color={ALWAYS_DARK_SECONDARY}\n >\n {this.comparisonLabel}\n </ds-text>\n )}\n </div>\n <div class=\"card-overview__filter\">\n <slot name=\"filter\" />\n </div>\n </div>\n </div>\n\n {!compact && (\n <div class=\"card-overview__body\">\n <div class=\"card-overview__metrics\" part=\"metrics\">\n {this.renderMetrics()}\n </div>\n\n <slot name=\"footer\" />\n </div>\n )}\n </div>\n </div>\n </div>\n </Host>\n );\n }\n}\n",
372
+ "content": "import {\n Component,\n Element,\n Event,\n EventEmitter,\n forceUpdate,\n h,\n Host,\n Prop,\n State,\n} from '@stencil/core';\nimport { resolveCssLengthPx, TOKEN_DEFAULTS } from '../../utils';\nimport type { TextColor, TextVariant } from '../Text/text-types';\nimport type { MetricTrend } from '../../utils/metric-change';\nimport type {\n CardOverviewLayout,\n CardOverviewVariant,\n OverviewMetric,\n OverviewScore,\n} from './card-overview-types';\nimport {\n findNextOverviewMetricIndex,\n resolveCardOverviewCollapseGeometry,\n resolveOverviewGridColumns,\n resolveOverviewRovingIndex,\n resolveSafetyScoreLevel,\n} from './card-overview-controller';\n\n/**\n * Metric cells below this width drop a grid column rather than compress further.\n *\n * A literal rather than a token: this is a layout threshold for a grid cell, and\n * the dimension scale has no token for that. The 200px tokens it could borrow\n * (`menu-width-xs`, `form-width-xs`, `panel-width-2xs`) all name other\n * components, so binding to one would couple this grid to an unrelated contract.\n * Consumers override with the `metricMinWidth` prop.\n */\nconst DEFAULT_METRIC_MIN_WIDTH = '200px';\n\n/** Skeleton cells rendered while loading with no metrics supplied yet. */\nconst DEFAULT_LOADING_METRIC_COUNT = 5;\n\n/** Maximum number of comparable measures the summary bar presents at once. */\nconst MAX_METRIC_COUNT = 7;\n\nconst TREND_COLORS: Record<MetricTrend['tone'], TextColor> = {\n positive: 'var(--color-always-dark-foreground-positive)',\n negative: 'var(--color-always-dark-foreground-negative)',\n neutral: 'var(--color-always-dark-foreground-secondary)',\n};\n\nconst ALWAYS_DARK_PRIMARY: TextColor = 'var(--color-always-dark-foreground-primary)';\nconst ALWAYS_DARK_SECONDARY: TextColor = 'var(--color-always-dark-foreground-secondary)';\n\n@Component({\n tag: 'ds-card-overview',\n styleUrl: 'CardOverview.css',\n scoped: true,\n})\nexport class CardOverview {\n @Element() el!: HTMLElement;\n\n /** Full summary card, or the condensed 48px summary bar. */\n @Prop() variant: CardOverviewVariant = 'default';\n\n /** Intrinsic responsive layout, or a page-owned single-column stack. */\n @Prop() layout: CardOverviewLayout = 'auto';\n\n /** Optional nonselectable safety score rendered as the first grid cell. */\n @Prop() score: OverviewScore | undefined;\n\n /** Fixed current date or range. Replaced by content in the `period` slot. */\n @Prop() periodLabel: string = '';\n\n /** Copy between the current period and comparison control, usually `vs.`. */\n @Prop() comparisonLabel: string = '';\n\n /** Measures rendered in the responsive grid. Only the first seven are shown. */\n @Prop() metrics: OverviewMetric[] = [];\n\n /**\n * Width a metric cell may shrink to before the grid drops a column. The grid\n * uses this threshold while choosing an evenly distributed column count.\n */\n @Prop() metricMinWidth: string = DEFAULT_METRIC_MIN_WIDTH;\n\n /** Replace the score and metrics with skeletons while data resolves. */\n @Prop() isLoading: boolean = false;\n\n /** Message shown in place of the score when its figure cannot be resolved. */\n @Prop() scoreErrorMessage: string | undefined;\n\n /** Accessible name for the region. */\n @Prop() overviewLabel: string = 'Overview';\n\n /**\n * Page-controlled visual collapse from the full card (`0`) toward its 48px\n * compact handoff height (`1`). The component preserves its expanded flow\n * height, keeps the period bar stationary, and moves/clips the grid beneath\n * it. The page still owns sticky positioning and the final compact handoff.\n */\n @Prop() scrollCollapseProgress: number = 0;\n\n /** Emitted when a metric that is not inactive is activated. */\n @Event() dsMetricSelect!: EventEmitter<OverviewMetric>;\n\n /** Roving tab stop across selectable metrics. */\n @State() private focusedMetricIndex: number = 0;\n @State() private expandedHeight: number = 0;\n @State() private gridColumns: number | undefined;\n\n private layoutEl?: HTMLElement;\n private layoutResizeObserver: ResizeObserver | null = null;\n /** The node the observer is bound to, which a later render can replace. */\n private observedLayoutEl?: HTMLElement;\n\n componentDidLoad() {\n this.observeLayout();\n }\n\n componentDidRender() {\n // Re-bind after HMR when DidLoad's observer was dropped, and whenever a\n // render swapped the layout node out from under the observer: the ref points\n // at the new node while the observer still watches the detached one, which\n // never resizes again. The grid would then keep its first measured column\n // count for the life of the component.\n if (!this.layoutResizeObserver || this.observedLayoutEl !== this.layoutEl) {\n this.observeLayout();\n } else {\n this.updateLayoutGeometry();\n }\n }\n\n disconnectedCallback() {\n this.layoutResizeObserver?.disconnect();\n this.layoutResizeObserver = null;\n this.observedLayoutEl = undefined;\n }\n\n private get visibleMetrics(): OverviewMetric[] {\n return this.metrics.slice(0, MAX_METRIC_COUNT);\n }\n\n private get visibleCellCount(): number {\n const metricCount = this.isLoading ? this.loadingMetricCount : this.visibleMetrics.length;\n return 1 + metricCount;\n }\n\n /** Preserve an authored data shape while loading, or use the standard six-cell grid. */\n private get loadingMetricCount(): number {\n return this.visibleMetrics.length || DEFAULT_LOADING_METRIC_COUNT;\n }\n\n private get resolvedScrollCollapseProgress(): number {\n if (this.variant === 'compact' || !Number.isFinite(this.scrollCollapseProgress)) return 0;\n return Math.min(1, Math.max(0, this.scrollCollapseProgress));\n }\n\n private get scrollCollapseGeometry() {\n const compactHeight = resolveCssLengthPx(TOKEN_DEFAULTS.size600, 48);\n return resolveCardOverviewCollapseGeometry({\n variant: this.variant,\n progress: this.resolvedScrollCollapseProgress,\n expandedHeight: this.expandedHeight,\n compactHeight,\n });\n }\n\n private observeLayout() {\n const layout = this.layoutEl;\n if (!layout) return;\n\n const bounds = layout.getBoundingClientRect();\n this.updateLayoutGeometry(bounds.width, bounds.height);\n if (typeof ResizeObserver === 'undefined') return;\n\n this.layoutResizeObserver?.disconnect();\n this.layoutResizeObserver = new ResizeObserver(entries => {\n const rect = entries[0]?.contentRect;\n if (rect) this.updateLayoutGeometry(rect.width, rect.height);\n });\n this.layoutResizeObserver.observe(layout);\n this.observedLayoutEl = layout;\n }\n\n private updateLayoutGeometry(width?: number, height?: number) {\n const layout = this.layoutEl;\n if (!layout) return;\n\n const bounds = width === undefined || height === undefined ? layout.getBoundingClientRect() : null;\n const resolvedWidth = width ?? bounds?.width ?? 0;\n const resolvedHeight = height ?? bounds?.height ?? 0;\n\n let changed = false;\n\n if (resolvedHeight > 0 && Math.abs(resolvedHeight - this.expandedHeight) >= 0.5) {\n this.expandedHeight = resolvedHeight;\n changed = true;\n }\n\n const columns = resolveOverviewGridColumns({\n cellCount: this.visibleCellCount,\n availableWidth: resolvedWidth,\n minCellWidth: resolveCssLengthPx(this.metricMinWidth, DEFAULT_METRIC_MIN_WIDTH),\n });\n if (columns !== this.gridColumns) {\n this.gridColumns = columns;\n changed = true;\n }\n\n // The column count is written straight to the host rather than through the\n // rendered style object. Measurement happens in `componentDidLoad` and in the\n // ResizeObserver callback, both outside a render cycle, and the host's style\n // is not patched again after the first render — so a rendered value would stay\n // pinned to whatever the first paint produced, before any width was known.\n if (this.gridColumns) {\n this.el.style.setProperty('--ds-card-overview-grid-columns', String(this.gridColumns));\n } else {\n this.el.style.removeProperty('--ds-card-overview-grid-columns');\n }\n\n if (changed) forceUpdate(this);\n }\n\n /** Index of the roving tab stop, skipping inactive metrics. */\n private get rovingIndex(): number {\n return resolveOverviewRovingIndex(this.visibleMetrics, this.focusedMetricIndex);\n }\n\n private selectMetric(metric: OverviewMetric, index: number) {\n if (metric.isInactive) return;\n this.focusedMetricIndex = index;\n this.dsMetricSelect.emit(metric);\n }\n\n /** Move the roving tab stop, wrapping and skipping inactive metrics. */\n private moveFocus(from: number, step: number) {\n const metrics = this.visibleMetrics;\n const next = findNextOverviewMetricIndex(metrics, from, step < 0 ? -1 : 1);\n if (next < 0) return;\n\n this.focusedMetricIndex = next;\n const cells = this.el.querySelectorAll<HTMLElement>('.card-overview__metric-action');\n cells[next]?.focus();\n }\n\n private handleMetricKeyDown = (event: KeyboardEvent, index: number) => {\n switch (event.key) {\n case 'ArrowRight':\n case 'ArrowDown':\n event.preventDefault();\n this.moveFocus(index, 1);\n break;\n case 'ArrowLeft':\n case 'ArrowUp':\n event.preventDefault();\n this.moveFocus(index, -1);\n break;\n default:\n break;\n }\n };\n\n /**\n * A skeleton bar matching the type metrics of the text it stands in for, so the\n * loading state holds the same shape and rhythm as the resolved content.\n *\n * `background` is always passed so the base and shimmer follow the card's\n * permanently dark surface in both themes.\n */\n private bar(textVariant: TextVariant, width: string, className?: string) {\n return (\n <ds-skeleton\n class={className}\n variant=\"text\"\n textVariant={textVariant}\n width={width}\n background=\"always-dark\"\n />\n );\n }\n\n /**\n * Arrow and change in one text node.\n *\n * The arrow is a typeface glyph rather than an icon so it inherits the exact\n * size, weight, and baseline of the value beside it; an icon would need its\n * own size scale and would drift whenever the type scale changed.\n *\n * Tone is supplied by the caller and never inferred here.\n */\n private renderTrend(trend: MetricTrend | undefined, variant: TextVariant) {\n if (!trend) return null;\n return (\n <ds-text\n as=\"span\"\n class={{\n 'card-overview__trend': true,\n 'ds-control-label-box': true,\n [`card-overview__trend--${trend.tone}`]: true,\n }}\n variant={variant}\n color={TREND_COLORS[trend.tone]}\n fontFeature=\"tabular-nums\"\n >\n {trend.direction === 'up' ? '↑' : '↓'} {trend.value}\n </ds-text>\n );\n }\n\n private renderScore() {\n if (this.isLoading) {\n return (\n <div class=\"card-overview__score\" part=\"score\">\n <div class=\"card-overview__score-content\">\n <div class=\"card-overview__score-badge\">\n {this.bar('text-display-small', '40px')}\n </div>\n <div class=\"card-overview__score-copy\">\n {this.bar('text-body-small', '64px', 'card-overview__score-label-spacer')}\n {this.bar('text-body-medium', '28px')}\n </div>\n </div>\n </div>\n );\n }\n\n const unavailableMessage =\n this.scoreErrorMessage || (!this.score ? 'Score unavailable' : undefined);\n if (unavailableMessage) {\n return (\n /* eslint-disable-next-line local/prefer-direct-ds-text -- The score track owns the grid divider and 8px outer inset. */\n <div class=\"card-overview__score\" part=\"score\">\n <ds-text\n as=\"span\"\n class=\"card-overview__score-content card-overview__score-content--error\"\n variant=\"text-body-medium\"\n color=\"inherit\"\n role=\"alert\"\n >\n {unavailableMessage}\n </ds-text>\n </div>\n );\n }\n\n const score = this.score;\n if (!score) return null;\n const level = score.level ?? resolveSafetyScoreLevel(score.value);\n\n return (\n <div class=\"card-overview__score\" part=\"score\">\n <div class=\"card-overview__score-content\">\n {/* eslint-disable-next-line local/prefer-direct-ds-text -- The fill owns its own box: it pads out to 52px and crops the display line box, which the text element cannot do to itself. */}\n <div\n class={{\n 'card-overview__score-badge': true,\n [`card-overview__score-badge--${level}`]: Boolean(level),\n }}\n >\n <ds-text\n as=\"span\"\n class=\"card-overview__score-value ds-control-label-box\"\n variant=\"text-display-small\"\n emphasis\n color=\"inherit\"\n fontFeature=\"tabular-nums\"\n >\n {score.value}\n </ds-text>\n </div>\n <div class=\"card-overview__score-copy\">\n <ds-text\n as=\"span\"\n class=\"card-overview__score-label-spacer ds-control-label-box\"\n variant=\"text-body-small\"\n color={ALWAYS_DARK_SECONDARY}\n aria-hidden=\"true\"\n >\n &nbsp;\n </ds-text>\n {this.renderTrend(score.trend, 'text-body-medium')}\n </div>\n </div>\n </div>\n );\n }\n\n private renderMetric(metric: OverviewMetric, index: number) {\n const selectable = !metric.isInactive;\n const label = (\n <ds-text\n as=\"span\"\n class=\"card-overview__metric-label ds-control-label-box\"\n variant=\"text-body-small\"\n color={ALWAYS_DARK_SECONDARY}\n >\n {metric.label}\n </ds-text>\n );\n\n return (\n <div class=\"card-overview__metric\" part=\"metric\">\n <div\n class={{\n 'card-overview__metric-action': true,\n 'card-overview__metric-action--inactive': !selectable,\n // Selection targets get the shared wash; press scaling is not used here\n // so the grid keeps its columns aligned. See docs/control-press-policy.md.\n 'ds-interaction-fill': selectable,\n 'ds-interaction-fill--on-always-dark': selectable,\n 'ds-focus-ring-inset': selectable,\n }}\n role={selectable ? 'button' : undefined}\n tabIndex={selectable && index === this.rovingIndex ? 0 : -1}\n onClick={() => this.selectMetric(metric, index)}\n onKeyDown={event => this.handleMetricKeyDown(event, index)}\n onFocusin={() => {\n if (selectable) this.focusedMetricIndex = index;\n }}\n >\n <div class=\"ds-interaction-fill__content card-overview__metric-content\">\n {metric.labelTooltip ? (\n <ds-tooltip label={metric.labelTooltip} side=\"top\" size=\"sm\">\n {label}\n </ds-tooltip>\n ) : (\n label\n )}\n <div class=\"card-overview__metric-figure\">\n <ds-text\n as=\"span\"\n class=\"card-overview__metric-value ds-control-label-box\"\n variant=\"text-body-medium\"\n color={ALWAYS_DARK_PRIMARY}\n fontFeature=\"tabular-nums\"\n >\n {metric.value}\n </ds-text>\n {this.renderTrend(metric.trend, 'text-body-medium')}\n </div>\n </div>\n </div>\n </div>\n );\n }\n\n private renderMetrics() {\n if (this.isLoading) {\n return [\n this.renderScore(),\n ...Array.from({ length: this.loadingMetricCount }, (_, index) => (\n <div class=\"card-overview__metric\" key={`loading-${index}`}>\n <div class=\"card-overview__metric-action card-overview__metric-action--inactive\">\n <div class=\"card-overview__metric-content\">\n {this.bar('text-body-small', '35%', 'card-overview__metric-label')}\n <div class=\"card-overview__metric-figure\">\n {this.bar('text-body-medium', '40px')}\n {/* Match renderTrend's type canvas and the score trend's 28px width. */}\n {this.bar('text-body-medium', '28px')}\n </div>\n </div>\n </div>\n </div>\n )),\n ];\n }\n\n return [\n this.renderScore(),\n ...this.visibleMetrics.map((metric, index) => this.renderMetric(metric, index)),\n ];\n }\n\n render() {\n const compact = this.variant === 'compact';\n const collapse = this.scrollCollapseGeometry;\n\n // Omit absent custom properties rather than handing them an undefined value.\n // Stencil serialises undefined to the string \"undefined\", which is invalid in\n // `repeat()` and voids the whole grid-template-columns declaration — the grid\n // then collapses to one implicit column instead of using the `auto-fit`\n // fallback baked into the stylesheet.\n const customProperties: Record<string, string> = {\n '--ds-card-overview-metric-min': this.metricMinWidth,\n };\n if (this.gridColumns) {\n customProperties['--ds-card-overview-grid-columns'] = String(this.gridColumns);\n }\n if (collapse.active) {\n customProperties['--ds-card-overview-expanded-height'] = `${collapse.expandedHeight}px`;\n customProperties['--ds-card-overview-visible-height'] = `${collapse.visibleHeight}px`;\n customProperties['--ds-card-overview-content-offset'] = `${collapse.offset}px`;\n }\n\n return (\n <Host\n class={{\n 'card-overview': true,\n 'card-overview--compact': compact,\n 'card-overview--stacked': !compact && this.layout === 'stacked',\n 'card-overview--scroll-collapsing': collapse.active,\n }}\n role=\"region\"\n aria-label={this.overviewLabel}\n aria-busy={this.isLoading ? 'true' : undefined}\n style={customProperties}\n >\n <div\n class={{\n 'card-overview__surface': true,\n // Split shadow and inset highlight, so the opaque surface cannot cover\n // the highlight the way a combined elevation shadow would.\n 'ds-control-elevation': true,\n 'ds-control-elevation--sm': !compact,\n 'ds-control-elevation--floating': compact,\n }}\n >\n <div class=\"card-overview__clip\">\n <div\n ref={element => {\n this.layoutEl = (element as HTMLElement) ?? undefined;\n }}\n class={{\n 'card-overview__layout': true,\n }}\n >\n <div class=\"card-overview__summary\">\n <div class=\"card-overview__header ds-control--md\">\n <div class=\"card-overview__period\">\n <div class=\"card-overview__period-current\">\n <slot name=\"period\">\n {this.periodLabel && (\n /* eslint-disable-next-line local/prefer-direct-ds-text -- Fixed copy uses the same structural frame and label inset as a slotted Select. */\n <div class=\"card-overview__period-fixed ds-control-frame\">\n <ds-text\n as=\"span\"\n class=\"ds-control-label-box\"\n variant=\"text-body-medium\"\n emphasis\n color={ALWAYS_DARK_PRIMARY}\n >\n {this.periodLabel}\n </ds-text>\n </div>\n )}\n </slot>\n </div>\n {this.comparisonLabel && (\n <ds-text\n as=\"span\"\n class=\"card-overview__period-comparison ds-control-label-box\"\n variant=\"text-body-medium\"\n color={ALWAYS_DARK_SECONDARY}\n >\n {this.comparisonLabel}\n </ds-text>\n )}\n </div>\n <div class=\"card-overview__filter\">\n <slot name=\"filter\" />\n </div>\n </div>\n </div>\n\n {!compact && (\n <div class=\"card-overview__body\">\n <div class=\"card-overview__metrics\" part=\"metrics\">\n {this.renderMetrics()}\n </div>\n\n <slot name=\"footer\" />\n </div>\n )}\n </div>\n </div>\n </div>\n </Host>\n );\n }\n}\n",
373
373
  "type": "registry:ui"
374
374
  },
375
375
  {
@@ -379,7 +379,7 @@
379
379
  },
380
380
  {
381
381
  "path": "src/wc/components/CardOverview/card-overview-types.ts",
382
- "content": "import type { MetricTrend } from '../../utils/metric-change';\n\nexport type CardOverviewVariant = 'default' | 'compact';\nexport type CardOverviewLayout = 'auto' | 'stacked';\nexport type SafetyScoreLevel = 'fair' | 'good' | 'excellent';\n\n/**\n * Leading summary block — the headline figure the rest of the bar contextualises.\n *\n * Derive `trend` with `resolveMetricTrend` so whether a rise reads well stays a\n * product decision rather than a design-system one.\n */\nexport interface OverviewScore {\n /** Category before the trend and figure, for example `Safety score`. */\n label: string;\n /** Display-ready headline figure. */\n value: string | number;\n /** Change against the comparison period. Omit when there is nothing to report. */\n trend?: MetricTrend;\n /**\n * Safety score color level. Numeric values from 0–100 infer fair (0–50),\n * good (51–80), or excellent (81–100) when this is omitted.\n */\n level?: SafetyScoreLevel;\n /** @deprecated Ignored. The redesigned score cell no longer renders a band. */\n band?: string;\n}\n\n/** One measure in the overview grid. */\nexport interface OverviewMetric {\n /** Stable identity for keyed rendering and selection events. */\n id: string;\n label: string;\n /** Display-ready value; format compactly before passing it in. */\n value: string | number;\n /** Change against the comparison period. Omit when there is nothing to report. */\n trend?: MetricTrend;\n /** Present the measure without making it selectable. */\n isInactive?: boolean;\n /** Supplementary explanation for the label. */\n labelTooltip?: string;\n}\n",
382
+ "content": "import type { MetricTrend } from '../../utils/metric-change';\n\nexport type CardOverviewVariant = 'default' | 'compact';\nexport type CardOverviewLayout = 'auto' | 'stacked';\nexport type SafetyScoreLevel = 'fair' | 'good' | 'excellent';\n\n/**\n * Leading summary block — the headline figure the rest of the bar contextualises.\n *\n * Derive `trend` with `resolveMetricTrend` so whether a rise reads well stays a\n * product decision rather than a design-system one.\n */\nexport interface OverviewScore {\n /** Display-ready headline figure. */\n value: string | number;\n /** Change against the comparison period. Omit when there is nothing to report. */\n trend?: MetricTrend;\n /**\n * Safety score color level. Numeric values from 0–100 infer fair (0–50),\n * good (51–80), or excellent (81–100) when this is omitted.\n */\n level?: SafetyScoreLevel;\n /** @deprecated Ignored. The redesigned score cell no longer renders a band. */\n band?: string;\n}\n\n/** One measure in the overview grid. */\nexport interface OverviewMetric {\n /** Stable identity for keyed rendering and selection events. */\n id: string;\n label: string;\n /** Display-ready value; format compactly before passing it in. */\n value: string | number;\n /** Change against the comparison period. Omit when there is nothing to report. */\n trend?: MetricTrend;\n /** Present the measure without making it selectable. */\n isInactive?: boolean;\n /** Supplementary explanation for the label. */\n labelTooltip?: string;\n}\n",
383
383
  "type": "registry:ui"
384
384
  }
385
385
  ]
@@ -250,7 +250,7 @@
250
250
  "peerDependencies": {
251
251
  "required": [
252
252
  "@ds-mo/tokens ^6.0.0",
253
- "@ds-mo/icons ^6.4.0"
253
+ "@ds-mo/icons ^6.5.0"
254
254
  ],
255
255
  "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
256
256
  }
@@ -268,7 +268,7 @@
268
268
  "peerDependencies": {
269
269
  "required": [
270
270
  "@ds-mo/tokens ^6.0.0",
271
- "@ds-mo/icons ^6.4.0"
271
+ "@ds-mo/icons ^6.5.0"
272
272
  ],
273
273
  "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
274
274
  }
@@ -230,7 +230,7 @@
230
230
  "peerDependencies": {
231
231
  "required": [
232
232
  "@ds-mo/tokens ^6.0.0",
233
- "@ds-mo/icons ^6.4.0"
233
+ "@ds-mo/icons ^6.5.0"
234
234
  ],
235
235
  "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
236
236
  }
@@ -333,7 +333,7 @@
333
333
  "peerDependencies": {
334
334
  "required": [
335
335
  "@ds-mo/tokens ^6.0.0",
336
- "@ds-mo/icons ^6.4.0"
336
+ "@ds-mo/icons ^6.5.0"
337
337
  ],
338
338
  "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
339
339
  }
@@ -246,7 +246,7 @@
246
246
  "peerDependencies": {
247
247
  "required": [
248
248
  "@ds-mo/tokens ^6.0.0",
249
- "@ds-mo/icons ^6.4.0"
249
+ "@ds-mo/icons ^6.5.0"
250
250
  ],
251
251
  "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
252
252
  }
@@ -121,7 +121,7 @@
121
121
  "peerDependencies": {
122
122
  "required": [
123
123
  "@ds-mo/tokens ^6.0.0",
124
- "@ds-mo/icons ^6.4.0"
124
+ "@ds-mo/icons ^6.5.0"
125
125
  ],
126
126
  "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
127
127
  }
@@ -254,7 +254,7 @@
254
254
  "peerDependencies": {
255
255
  "required": [
256
256
  "@ds-mo/tokens ^6.0.0",
257
- "@ds-mo/icons ^6.4.0"
257
+ "@ds-mo/icons ^6.5.0"
258
258
  ],
259
259
  "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
260
260
  }
@@ -111,7 +111,7 @@
111
111
  "peerDependencies": {
112
112
  "required": [
113
113
  "@ds-mo/tokens ^6.0.0",
114
- "@ds-mo/icons ^6.4.0"
114
+ "@ds-mo/icons ^6.5.0"
115
115
  ],
116
116
  "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
117
117
  }
@@ -103,7 +103,7 @@
103
103
  "peerDependencies": {
104
104
  "required": [
105
105
  "@ds-mo/tokens ^6.0.0",
106
- "@ds-mo/icons ^6.4.0"
106
+ "@ds-mo/icons ^6.5.0"
107
107
  ],
108
108
  "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
109
109
  }
@@ -199,7 +199,7 @@
199
199
  "peerDependencies": {
200
200
  "required": [
201
201
  "@ds-mo/tokens ^6.0.0",
202
- "@ds-mo/icons ^6.4.0"
202
+ "@ds-mo/icons ^6.5.0"
203
203
  ],
204
204
  "frameworks": "Custom Elements; React 18/19 wrappers; Angular 19-22 standalone adapters."
205
205
  }