@nextclaw/ui 0.26.3 → 0.26.5

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 (191) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/.vite/manifest.json +362 -362
  3. package/dist/assets/{account-panel-DIdHjKG-.js → account-panel-BAH7FW6z.js} +1 -1
  4. package/dist/assets/{api-DkLJrSCd.js → api-DjiZvIa0.js} +2 -2
  5. package/dist/assets/app-presenter-provider-CCRFsFYr.js +232 -0
  6. package/dist/assets/{appearance-settings-page-DI8aDY2G.js → appearance-settings-page-CdP86QJ7.js} +1 -1
  7. package/dist/assets/{book-open-BPMkKSci.js → book-open-Bcnn2_uV.js} +1 -1
  8. package/dist/assets/card-Cqs73hGI.js +1 -0
  9. package/dist/assets/{channels-list-page-CCIaTQu7.js → channels-list-page-5qGagKuE.js} +2 -2
  10. package/dist/assets/{circle-dashed-B48a0t6p.js → circle-dashed-EY1ScSMe.js} +1 -1
  11. package/dist/assets/{client-imrVphQb.js → client-CH7w6yRV.js} +1 -1
  12. package/dist/assets/config-split-page-CuEGQL8Z.js +1 -0
  13. package/dist/assets/{confirm-dialog-10Qb3dpZ.js → confirm-dialog-CxfecBzO.js} +1 -1
  14. package/dist/assets/{context-menu-CRqH2SEk.js → context-menu-BsCj2fRs.js} +1 -1
  15. package/dist/assets/{createLucideIcon-B4xj2I2g.js → createLucideIcon-Cfo2ySi5.js} +1 -1
  16. package/dist/assets/{desktop-capabilities-page-CFcT2g8-.js → desktop-capabilities-page-BDYITStl.js} +1 -1
  17. package/dist/assets/{desktop-update-config-CRJd_An1.js → desktop-update-config-e-zhkJuS.js} +1 -1
  18. package/dist/assets/{dialog-BgL3vKJQ.js → dialog-QjQoKbIV.js} +1 -1
  19. package/dist/assets/doc-browser-CLEdkH9z.js +1 -0
  20. package/dist/assets/{doc-browser-context-DH4aWvkS.js → doc-browser-context-DwgG6wrz.js} +1 -1
  21. package/dist/assets/{download-Cr337h4W.js → download-BoaKzDJk.js} +1 -1
  22. package/dist/assets/{es2015-D-CRf3_Z.js → es2015-Bp6cuSGh.js} +1 -1
  23. package/dist/assets/{extensions-CsmJPz7g.js → extensions-CgShSIkd.js} +1 -1
  24. package/dist/assets/{eye-DrQRSAfJ.js → eye-kisejBFH.js} +1 -1
  25. package/dist/assets/{form-actions-BEeWTGUZ.js → form-actions-D9JWSFQu.js} +1 -1
  26. package/dist/assets/{i18n-OGmF0Ws_.js → i18n-Bm3Ov7Fy.js} +2 -2
  27. package/dist/assets/{keyboard-shortcuts-settings-page-DQU56SrW.js → keyboard-shortcuts-settings-page-DZ8A1iLg.js} +1 -1
  28. package/dist/assets/loader-circle-Bd1fTm-x.js +1 -0
  29. package/dist/assets/{login-page-sgivRYG1.js → login-page-C-DvcG3L.js} +1 -1
  30. package/dist/assets/login-page-D99JjH9F.js +1 -0
  31. package/dist/assets/{main-B-oxUq-o.js → main-Bt5r6b21.js} +2 -2
  32. package/dist/assets/main-DXd_aKJV.css +1 -0
  33. package/dist/assets/main-i18n-catalog.config-D0Ll36J_.js +1 -0
  34. package/dist/assets/mcp-marketplace-page-DUoGfSmY.js +1 -0
  35. package/dist/assets/{model-config-page-CDQBhmVr.js → model-config-page-9NNf-mzK.js} +1 -1
  36. package/dist/assets/{navigation-link-D3pzNHeA.js → navigation-link-CjxNC8aT.js} +1 -1
  37. package/dist/assets/panel-app-i18n-catalog.config-Ddf2Kv8A.js +1 -0
  38. package/dist/assets/panelStandalone-BRg7B1EI.css +1 -0
  39. package/dist/assets/{panelStandalone-CGkYeMK5.js → panelStandalone-BaUzY8Wy.js} +2 -2
  40. package/dist/assets/{privacy-settings-page-CjoAkoDt.js → privacy-settings-page-CVMBFuak.js} +1 -1
  41. package/dist/assets/projects-BEsU3box.js +1 -0
  42. package/dist/assets/provider-models-Dm-pmWAA.js +1 -0
  43. package/dist/assets/provider-scoped-model-input-CzrXg4cX.js +1 -0
  44. package/dist/assets/providers-config-page-839uUADZ.js +1 -0
  45. package/dist/assets/{puzzle--RLCeYML.js → puzzle-BGvD2DPZ.js} +1 -1
  46. package/dist/assets/{pwa-DcizGowz.js → pwa-DNNK_8E9.js} +1 -1
  47. package/dist/assets/{refresh-cw-syCVj_nw.js → refresh-cw-BlXDrVP0.js} +1 -1
  48. package/dist/assets/remote-B5qIuUbT.js +1 -0
  49. package/dist/assets/{rotate-cw-BlH9El3x.js → rotate-cw-ei6rPD6z.js} +1 -1
  50. package/dist/assets/{runtime-config-page-Cco9dS73.js → runtime-config-page-Bf-4JYxQ.js} +1 -1
  51. package/dist/assets/{save-BWynuRQ2.js → save-DdF-bXgC.js} +1 -1
  52. package/dist/assets/{search-config-page-Cc74_SAU.js → search-config-page-C0qA3j-T.js} +1 -1
  53. package/dist/assets/{secrets-config-page-raYDzlFC.js → secrets-config-page-DxfZWpnk.js} +1 -1
  54. package/dist/assets/security-config-CItfIQZ4.js +1 -0
  55. package/dist/assets/{select-6Uq4chZW.js → select-CWyjnar7.js} +1 -1
  56. package/dist/assets/service-apps-panel-D3SOkRVv.js +1 -0
  57. package/dist/assets/{settings-2-COvVf1XX.js → settings-2-CrNhfInU.js} +1 -1
  58. package/dist/assets/{status-dot-DZlxa5zW.js → status-dot-C3SRFEta.js} +1 -1
  59. package/dist/assets/{tag-chip-DXHtZ8AS.js → tag-chip-BIuavK2K.js} +1 -1
  60. package/dist/assets/{theme-provider-C5PCDBPB.js → theme-provider-CWUz4yO9.js} +1 -1
  61. package/dist/assets/{trash-2-DazgBvmJ.js → trash-2-hAbJh9VZ.js} +1 -1
  62. package/dist/assets/{use-config-DRRGF9Zb.js → use-config-evzage09.js} +1 -1
  63. package/dist/assets/{use-desktop-capabilities-CdfOUjdE.js → use-desktop-capabilities-BYDjFlpt.js} +1 -1
  64. package/dist/assets/{use-viewport-layout-DdxVnCYc.js → use-viewport-layout-D_9XWGDV.js} +1 -1
  65. package/dist/assets/x-ChPbNv39.js +1 -0
  66. package/dist/index.html +34 -34
  67. package/dist/panel-standalone.html +11 -11
  68. package/package.json +3 -3
  69. package/src/app/components/layout/__tests__/sidebar.layout.test.tsx +2 -2
  70. package/src/app/components/layout/sidebar-rail.styles.ts +3 -3
  71. package/src/app/configs/__tests__/app-navigation.config.test.ts +4 -2
  72. package/src/app/configs/app-navigation.config.ts +7 -2
  73. package/src/app/styles/charcoal-theme.css +0 -3
  74. package/src/app/styles/design-system.css +12 -6
  75. package/src/app/styles/island-theme.css +2 -15
  76. package/src/features/app-data/components/app-data-removal-choice.tsx +1 -1
  77. package/src/features/channels/pages/channels-list-page.tsx +1 -1
  78. package/src/features/chat/components/chat-sidebar-list-mode-switch.tsx +1 -1
  79. package/src/features/chat/components/conversation/__tests__/chat-conversation-header-section.test.tsx +28 -16
  80. package/src/features/chat/components/conversation/chat-conversation-content.tsx +8 -2
  81. package/src/features/chat/components/layout/__tests__/chat-sidebar-session-area.test.tsx +6 -4
  82. package/src/features/chat/components/layout/__tests__/chat-sidebar-toolbar.test.tsx +22 -1
  83. package/src/features/chat/components/layout/chat-sidebar-desktop-layout.tsx +10 -14
  84. package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +38 -7
  85. package/src/features/chat/components/layout/chat-sidebar-utility-menu.tsx +4 -4
  86. package/src/features/chat/components/layout/chat-sidebar.tsx +2 -2
  87. package/src/features/chat/features/conversation/components/session-queued-input-rows.tsx +1 -1
  88. package/src/features/chat/features/message/components/chat-message-list.container.tsx +12 -3
  89. package/src/features/chat/features/message/components/chat-tool-call-stress-harness.tsx +32 -2
  90. package/src/features/chat/features/message/hooks/__tests__/use-chat-message-virtualizer.test.tsx +7 -5
  91. package/src/features/chat/features/message/hooks/use-chat-message-virtualizer.ts +7 -3
  92. package/src/features/chat/features/message/utils/__tests__/chat-message-process-summary.utils.test.ts +4 -6
  93. package/src/features/chat/features/message/utils/chat-message-process-summary.utils.ts +2 -10
  94. package/src/features/chat/features/message/utils/chat-message-texts.utils.ts +1 -0
  95. package/src/features/chat/features/session/components/__tests__/chat-sidebar-project-groups.test.tsx +1 -1
  96. package/src/features/chat/features/session/components/chat-mobile-session-row.tsx +1 -1
  97. package/src/features/chat/features/session/components/chat-sidebar-context-card.tsx +1 -1
  98. package/src/features/chat/features/session/components/chat-sidebar-project-groups.tsx +2 -1
  99. package/src/features/chat/features/session/components/chat-sidebar-session-item.tsx +7 -5
  100. package/src/features/chat/features/session/components/chat-sidebar-session-list.tsx +45 -10
  101. package/src/features/chat/features/session/components/session-header/chat-session-more-actions-menu.tsx +3 -0
  102. package/src/features/chat/features/session/components/session-header/chat-session-switcher-groups.tsx +6 -6
  103. package/src/features/chat/features/session/components/session-header/chat-session-title-switcher.tsx +5 -4
  104. package/src/features/chat/features/session-type/components/chat-session-type-option-item.tsx +1 -1
  105. package/src/features/chat/features/welcome/components/chat-welcome-agent-picker.tsx +0 -1
  106. package/src/features/chat/features/welcome/components/chat-welcome-project-picker.tsx +1 -1
  107. package/src/features/chat/features/welcome/components/chat-welcome-prompt-suggestions.tsx +1 -1
  108. package/src/features/chat/features/welcome/components/chat-welcome-session-type-picker.tsx +1 -1
  109. package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumb-browser.tsx +2 -2
  110. package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumbs.tsx +5 -5
  111. package/src/features/chat/features/workspace/components/chat-session-workspace-file-preview.tsx +1 -0
  112. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +1 -1
  113. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-nav.tsx +1 -1
  114. package/src/features/chat/features/workspace/components/child-sessions/chat-session-child-sessions.tsx +2 -2
  115. package/src/features/chat/features/workspace/components/file-content-preview/workspace-spreadsheet-preview.tsx +2 -2
  116. package/src/features/chat/features/workspace/components/overview/chat-session-continuous-attention.tsx +3 -3
  117. package/src/features/chat/features/workspace/components/overview/chat-session-token-usage.tsx +1 -1
  118. package/src/features/chat/features/workspace/components/project-files/workspace-directory-tree.tsx +4 -3
  119. package/src/features/chat/features/workspace/components/project-files/workspace-new-folder-tree-item.tsx +2 -1
  120. package/src/features/chat/features/workspace/components/session-cron-job-content.tsx +3 -3
  121. package/src/features/chat/features/workspace/components/workspace-file-content-preview.tsx +2 -2
  122. package/src/features/chat/features/workspace/components/workspace-markdown-outline.tsx +1 -1
  123. package/src/features/cron/components/cron-config.tsx +2 -2
  124. package/src/features/cron/components/cron-job-detail-dialog.tsx +1 -1
  125. package/src/features/cron/components/cron-job-row.tsx +3 -3
  126. package/src/features/cron/components/cron-task-discovery.tsx +1 -1
  127. package/src/features/inbox/pages/inbox-page.test.ts +12 -3
  128. package/src/features/inbox/pages/inbox-page.tsx +32 -25
  129. package/src/features/marketplace/components/curated-shelves/marketplace-curated-shelves.tsx +2 -2
  130. package/src/features/marketplace/components/curated-shelves/marketplace-shelf-card.tsx +2 -2
  131. package/src/features/marketplace/components/marketplace-list-card.tsx +4 -4
  132. package/src/features/marketplace/components/marketplace-page.tsx +2 -2
  133. package/src/features/marketplace/components/mcp/mcp-marketplace-card.tsx +2 -2
  134. package/src/features/marketplace/components/mcp/mcp-marketplace-page.tsx +3 -3
  135. package/src/features/panel-apps/components/panel-app-list-item.tsx +3 -3
  136. package/src/features/projects/pages/project-home-page.tsx +4 -2
  137. package/src/features/pwa/components/pwa-install-entry.tsx +1 -1
  138. package/src/features/right-panel-resources/components/__tests__/page-resource-sidebar-nav.test.tsx +9 -1
  139. package/src/features/right-panel-resources/components/page-resource-sidebar-nav.tsx +1 -1
  140. package/src/features/right-panel-resources/components/right-panel-resource-home-page.tsx +1 -1
  141. package/src/features/service-apps/components/service-action-row.tsx +3 -3
  142. package/src/features/service-apps/components/service-app-list-item.tsx +4 -4
  143. package/src/features/service-apps/components/service-apps-panel.tsx +1 -1
  144. package/src/features/settings/components/config/provider-model-list.tsx +5 -5
  145. package/src/features/settings/components/config/provider-model-suggestions-panel.tsx +4 -4
  146. package/src/features/settings/components/config/provider-pill-selector.tsx +1 -1
  147. package/src/features/settings/pages/appearance-settings-page.tsx +2 -2
  148. package/src/features/settings/pages/providers-config-page.tsx +6 -6
  149. package/src/features/side-dock/components/side-dock.tsx +4 -4
  150. package/src/index.css +4 -0
  151. package/src/platforms/desktop/components/desktop-window-chrome.tsx +1 -1
  152. package/src/platforms/mobile/components/__tests__/mobile-app-shell.test.tsx +9 -0
  153. package/src/platforms/mobile/components/mobile-app-shell.tsx +4 -2
  154. package/src/platforms/mobile/components/mobile-bottom-nav.tsx +3 -3
  155. package/src/platforms/mobile/components/mobile-topbar.tsx +2 -2
  156. package/src/shared/components/common/brand-header.tsx +1 -1
  157. package/src/shared/components/common/searchable-model-input.tsx +2 -2
  158. package/src/shared/components/config-split-page.tsx +3 -3
  159. package/src/shared/components/doc-browser/doc-browser-tab-strip.tsx +2 -2
  160. package/src/shared/components/path-picker/server-path-picker-locations.tsx +1 -1
  161. package/src/shared/components/ui/button.tsx +2 -2
  162. package/src/shared/components/ui/card.tsx +1 -1
  163. package/src/shared/components/ui/context-menu/context-menu-items.tsx +3 -3
  164. package/src/shared/components/ui/input.tsx +7 -3
  165. package/src/shared/components/ui/overlays/sheet.tsx +1 -1
  166. package/src/shared/components/ui/popover.tsx +1 -1
  167. package/src/shared/components/ui/select.tsx +2 -2
  168. package/src/shared/components/ui/tab-strip/compact-tab-strip.tsx +4 -4
  169. package/src/shared/components/ui/tabs.tsx +1 -1
  170. package/src/shared/components/workbench/workbench-surface.tsx +1 -1
  171. package/src/shared/lib/i18n/locales/en-US/chat.json +1 -2
  172. package/src/shared/lib/i18n/locales/zh-CN/chat.json +1 -2
  173. package/dist/assets/app-presenter-provider-Co8uKOyW.js +0 -124
  174. package/dist/assets/card-Bqu8zWLq.js +0 -1
  175. package/dist/assets/config-split-page-Bd-bGKsw.js +0 -1
  176. package/dist/assets/doc-browser-52t2_rSF.js +0 -1
  177. package/dist/assets/loader-circle-DbOQWT9C.js +0 -1
  178. package/dist/assets/login-page-DW1AZXqX.js +0 -1
  179. package/dist/assets/main-BpL6OjwM.css +0 -1
  180. package/dist/assets/main-i18n-catalog.config-Bpu5GcwF.js +0 -1
  181. package/dist/assets/mcp-marketplace-page-DSLRpJEB.js +0 -1
  182. package/dist/assets/panel-app-i18n-catalog.config-D44qmtfk.js +0 -1
  183. package/dist/assets/panelStandalone-D-mhAGNa.css +0 -1
  184. package/dist/assets/projects-C7Zxpcoi.js +0 -1
  185. package/dist/assets/provider-models-YW7rIeOD.js +0 -1
  186. package/dist/assets/provider-scoped-model-input-axJ-pTEu.js +0 -1
  187. package/dist/assets/providers-config-page-_QhBXQ4M.js +0 -1
  188. package/dist/assets/remote-BLQU7aY5.js +0 -1
  189. package/dist/assets/security-config-aE_jOwy-.js +0 -1
  190. package/dist/assets/service-apps-panel-jBWAa4qZ.js +0 -1
  191. package/dist/assets/x-CQIp_nJT.js +0 -1
@@ -22,6 +22,7 @@ type ChatSessionMoreActionsMenuProps = {
22
22
  disabled?: boolean;
23
23
  triggerSize?: IconActionButtonSize;
24
24
  triggerTone?: IconActionButtonTone;
25
+ triggerTooltipSide?: 'top' | 'bottom';
25
26
  className?: string;
26
27
  };
27
28
 
@@ -39,6 +40,7 @@ export function ChatSessionMoreActionsMenu({
39
40
  disabled = false,
40
41
  triggerSize = 'md',
41
42
  triggerTone = 'default',
43
+ triggerTooltipSide = 'bottom',
42
44
  className,
43
45
  }: ChatSessionMoreActionsMenuProps) {
44
46
  const [isOpen, setIsOpen] = useState(false);
@@ -59,6 +61,7 @@ export function ChatSessionMoreActionsMenu({
59
61
  label={t('chatSessionMoreActions')}
60
62
  size={triggerSize}
61
63
  tone={triggerTone}
64
+ tooltipSide={triggerTooltipSide}
62
65
  className={className}
63
66
  disabled={disabled}
64
67
  onClick={(event) => event.stopPropagation()}
@@ -66,9 +66,9 @@ function ChatSessionSwitchItem({
66
66
  type="button"
67
67
  aria-current={active ? "page" : undefined}
68
68
  className={cn(
69
- "flex w-full min-w-0 items-start gap-2 rounded-lg px-2.5 py-2 text-left transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border",
69
+ "flex w-full min-w-0 items-start gap-2 rounded-lg px-2.5 py-1.5 text-left transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border",
70
70
  active
71
- ? "bg-accent text-accent-foreground"
71
+ ? "bg-accent/60 text-accent-foreground"
72
72
  : "text-foreground hover:bg-[var(--interaction-hover)] hover:text-accent-foreground",
73
73
  )}
74
74
  onClick={() => onSelect(session.key)}
@@ -101,7 +101,7 @@ function ChatSessionSwitchItem({
101
101
  </span>
102
102
  ) : null}
103
103
  </span>
104
- <span className="mt-0.5 flex min-w-0 items-center gap-2 text-[11px] text-muted-foreground">
104
+ <span className="mt-0.5 flex min-w-0 items-center gap-2 text-[11px] text-muted-foreground/75">
105
105
  <span className="min-w-0 truncate">{previewText}</span>
106
106
  <span className="shrink-0">{trailingText}</span>
107
107
  </span>
@@ -177,12 +177,12 @@ function ChatSessionSwitchProjectGroup({
177
177
  aria-controls={contentId}
178
178
  aria-expanded={!isCollapsed}
179
179
  aria-label={actionLabel}
180
- className="group flex h-10 w-full min-w-0 items-center gap-1.5 rounded-lg px-2 text-left text-muted-foreground transition-colors hover:bg-gray-200/60 hover:text-gray-900 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
180
+ className="group flex h-8 w-full min-w-0 items-center gap-1.5 rounded-lg px-2 text-left text-muted-foreground transition-colors hover:bg-[var(--interaction-hover)] hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
181
181
  onClick={() => onToggleCollapsed(group.projectRoot)}
182
182
  >
183
183
  <Folder className="h-3.5 w-3.5 shrink-0" aria-hidden="true" />
184
184
  <span
185
- className="min-w-0 flex-1 truncate text-[11px] font-medium uppercase tracking-wider"
185
+ className="min-w-0 flex-1 truncate text-[13px] font-medium"
186
186
  title={group.projectRoot}
187
187
  >
188
188
  {group.projectName}
@@ -222,7 +222,7 @@ export function ChatSessionSwitcherGroups({
222
222
  projectGroups: ChatSidebarProjectGroup[];
223
223
  }) {
224
224
  return (
225
- <div className="space-y-3">
225
+ <div className="space-y-0.5">
226
226
  {isProjectFirstView
227
227
  ? projectGroups.map((group) => (
228
228
  <ChatSessionSwitchProjectGroup
@@ -165,9 +165,9 @@ function ChatSessionTitleSwitcherPopover({
165
165
  </PopoverTrigger>
166
166
  <ChatPopoverContent
167
167
  align="start"
168
- className="w-[22rem] max-w-[calc(100vw-2rem)] p-0"
168
+ className="flex w-[22rem] max-w-[calc(100vw-2rem)] flex-col overflow-hidden p-0"
169
169
  >
170
- <div className="space-y-2 border-b border-border px-3 py-2">
170
+ <div className="shrink-0 space-y-2 border-b border-border/40 px-3 py-2">
171
171
  <div className="flex items-center justify-between gap-3">
172
172
  <div className="text-[11px] font-medium uppercase tracking-wider text-muted-foreground/75">
173
173
  {t("chatSessionSwitcherTitle")}
@@ -180,16 +180,17 @@ function ChatSessionTitleSwitcherPopover({
180
180
  <div className="relative">
181
181
  <Search className="pointer-events-none absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground/65" />
182
182
  <Input
183
+ density="compact"
183
184
  value={searchQuery}
184
185
  onChange={(event) => setSearchQuery(event.target.value)}
185
186
  placeholder={t("chatSearchSessionPlaceholder")}
186
187
  aria-label={t("chatSearchSessionPlaceholder")}
187
- className="h-8 rounded-lg bg-background pl-8 pr-2 text-xs"
188
+ className="h-8 rounded-lg border-0 bg-muted/50 pl-8 pr-2"
188
189
  autoFocus
189
190
  />
190
191
  </div>
191
192
  </div>
192
- <div className="max-h-80 overflow-y-auto p-1.5">
193
+ <div className="min-h-0 max-h-80 overflow-y-auto overscroll-contain p-1.5">
193
194
  {isLoading ? (
194
195
  <ChatSessionTitleSwitcherLoadingState />
195
196
  ) : hasVisibleGroups ? (
@@ -27,7 +27,7 @@ export function ChatSessionTypeOptionItem(props: {
27
27
  onClick={onSelect}
28
28
  className={cn(
29
29
  "w-full rounded-2xl px-3 py-2.5 text-left transition-colors",
30
- selected ? "bg-gray-50" : "hover:bg-gray-50",
30
+ selected ? "bg-[var(--interaction-selection)]" : "hover:bg-[var(--interaction-hover)]",
31
31
  disabled ? "cursor-not-allowed opacity-70" : null,
32
32
  )}
33
33
  >
@@ -48,7 +48,6 @@ export function ChatWelcomeAgentPicker({
48
48
  </div>
49
49
  </SelectTrigger>
50
50
  <SelectContent
51
- className="rounded-xl border-border shadow-lg"
52
51
  style={{ maxHeight: AGENT_PICKER_MAX_HEIGHT }}
53
52
  >
54
53
  {agents.map((agent) => (
@@ -55,7 +55,7 @@ export function ChatWelcomeProjectPicker({
55
55
  </PopoverTrigger>
56
56
  <ChatPopoverContent
57
57
  align="start"
58
- className="flex w-[min(20rem,calc(100vw-1rem))] flex-col overflow-hidden rounded-2xl border border-border bg-popover p-0 text-popover-foreground shadow-[0_24px_60px_-28px_rgba(15,23,42,0.38)]"
58
+ className="flex w-[min(20rem,calc(100vw-1rem))] flex-col overflow-hidden p-0"
59
59
  style={{ maxHeight: PROJECT_PICKER_MAX_HEIGHT }}
60
60
  >
61
61
  <div className="shrink-0 px-3 pb-2 pt-3 text-[10px] font-semibold uppercase tracking-[0.18em] text-muted-foreground">
@@ -27,7 +27,7 @@ export function ChatWelcomePromptSuggestions({
27
27
  key={suggestion.labelKey}
28
28
  type="button"
29
29
  onClick={() => onSelectPrompt(t(suggestion.promptKey))}
30
- className="rounded-full bg-muted/55 px-3.5 py-2 text-xs font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
30
+ className="rounded-full bg-muted/55 px-3.5 py-2 text-xs font-medium text-muted-foreground transition-colors hover:bg-[var(--interaction-hover)] hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
31
31
  >
32
32
  {t(suggestion.labelKey)}
33
33
  </button>
@@ -61,7 +61,7 @@ export function ChatWelcomeSessionTypePicker({
61
61
  </PopoverTrigger>
62
62
  <ChatPopoverContent
63
63
  align="start"
64
- className="flex w-[min(16rem,calc(100vw-1rem))] flex-col overflow-hidden rounded-2xl border border-border bg-popover p-1.5 text-popover-foreground shadow-[0_24px_60px_-28px_rgba(15,23,42,0.38)]"
64
+ className="flex w-[min(16rem,calc(100vw-1rem))] flex-col overflow-hidden p-1.5"
65
65
  style={{ maxHeight: SESSION_TYPE_PICKER_MAX_HEIGHT }}
66
66
  >
67
67
  <div className="min-h-0 flex-1 overflow-y-auto">
@@ -70,7 +70,7 @@ export function WorkspaceBreadcrumbBrowser({
70
70
  <Fragment key={breadcrumb.path}>
71
71
  <button
72
72
  type="button"
73
- className="h-5 rounded-sm px-1 text-left hover:bg-gray-100 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
73
+ className="h-5 rounded-sm px-1 text-left hover:bg-[var(--interaction-hover)] focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
74
74
  onClick={() => onBrowsePathChange(breadcrumb.path)}
75
75
  >
76
76
  {breadcrumb.label}
@@ -100,7 +100,7 @@ export function WorkspaceBreadcrumbBrowser({
100
100
  key={entry.path}
101
101
  type="button"
102
102
  className={cn(
103
- "flex h-6 w-full items-center gap-1.5 rounded-sm px-1.5 text-left text-[11px] text-gray-700 transition-colors hover:bg-gray-100 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border",
103
+ "flex h-6 w-full items-center gap-1.5 rounded-sm px-1.5 text-left text-[11px] text-gray-700 transition-colors hover:bg-[var(--interaction-hover)] focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border",
104
104
  entry.hidden ? "opacity-65" : null,
105
105
  )}
106
106
  onClick={() => openEntry(entry)}
@@ -43,9 +43,9 @@ function WorkspaceBreadcrumbSegmentButton({
43
43
  type="button"
44
44
  aria-current={segment.isCurrent ? 'page' : undefined}
45
45
  className={cn(
46
- 'inline-flex h-5 shrink-0 items-center gap-1 whitespace-nowrap rounded-sm px-1 text-[11px] leading-none transition-colors hover:bg-gray-200/80 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border',
46
+ 'inline-flex h-5 shrink-0 items-center gap-1 whitespace-nowrap rounded-sm px-1 text-[11px] leading-none transition-colors hover:bg-[var(--interaction-hover)] focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border',
47
47
  segment.kind === 'workspace'
48
- ? 'bg-primary/8 text-primary hover:bg-primary/12'
48
+ ? 'bg-[var(--interaction-selection)] text-foreground hover:bg-[var(--interaction-selection)]'
49
49
  : segment.isCurrent
50
50
  ? 'bg-gray-200/70 text-gray-900'
51
51
  : 'text-gray-500',
@@ -115,13 +115,13 @@ export function ChatSessionWorkspaceFileBreadcrumbs({
115
115
  <div
116
116
  data-testid="workspace-file-breadcrumbs"
117
117
  title={breadcrumb.fullPath}
118
- className="flex min-w-0 items-center border-b border-gray-200/80 bg-gray-50/55"
118
+ className="flex h-8 min-w-0 shrink-0 items-center border-b border-gray-200/80 bg-gray-50/55"
119
119
  >
120
120
  {leading ? <div className="flex h-full shrink-0 items-center pl-1 pr-0.5">{leading}</div> : null}
121
121
  <div
122
122
  ref={scrollRef}
123
123
  data-testid="workspace-file-breadcrumb-scroll"
124
- className="workspace-horizontal-scrollbar flex min-w-0 flex-1 items-center gap-2.5 overflow-x-auto overflow-y-hidden px-3 py-1.5"
124
+ className="workspace-horizontal-scrollbar flex h-full min-w-0 flex-1 items-center gap-1 overflow-x-auto overflow-y-hidden px-1.5"
125
125
  >
126
126
  <div className="flex min-w-0 flex-1 items-center gap-1 pr-1">
127
127
  {breadcrumb.segments.map((segment, index) => (
@@ -140,7 +140,7 @@ export function ChatSessionWorkspaceFileBreadcrumbs({
140
140
  </div>
141
141
  ) : null}
142
142
  </div>
143
- {trailing ? <div className="flex shrink-0 items-center py-1.5 pr-2 pl-0.5">{trailing}</div> : null}
143
+ {trailing ? <div className="flex h-full shrink-0 items-center pr-1 pl-0.5">{trailing}</div> : null}
144
144
  </div>
145
145
  );
146
146
  }
@@ -268,6 +268,7 @@ function WorkspacePreviewBody({
268
268
  texts={{
269
269
  copyCodeLabel: t('chatCodeCopy'),
270
270
  copiedCodeLabel: t('chatCodeCopied'),
271
+ frontmatterLabel: t('chatMarkdownFrontmatter'),
271
272
  }}
272
273
  onFileOpen={onFileOpen}
273
274
  resolveFileContentUrl={(action) => buildServerPathContentUrl(action.path, fileBasePath)}
@@ -66,7 +66,7 @@ function WorkspaceOverviewEntry({
66
66
  return (
67
67
  <button
68
68
  type="button"
69
- className="group flex w-full items-center gap-3 rounded-lg border border-gray-200/80 bg-white px-3 py-3 text-left transition-colors hover:border-gray-300 hover:bg-gray-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/25"
69
+ className="group flex w-full items-center gap-3 rounded-lg border border-gray-200/80 bg-white px-3 py-3 text-left transition-colors hover:border-gray-300 hover:bg-[var(--interaction-hover)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/25"
70
70
  onClick={onClick}
71
71
  >
72
72
  <span className="inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-gray-100 text-gray-600">
@@ -218,7 +218,7 @@ export function WorkspaceTabsBar({
218
218
 
219
219
  return (
220
220
  <CompactTabStrip
221
- className="h-10 min-w-0 flex-1 border-0 bg-transparent px-0"
221
+ className="h-8 min-w-0 flex-1 border-0 bg-transparent px-0"
222
222
  testId="workspace-tabs-bar"
223
223
  scrollTestId="workspace-tabs-scroll"
224
224
  tabs={compactTabs}
@@ -27,7 +27,7 @@ export function ChatSessionChildSessions({
27
27
  </div>
28
28
  <button
29
29
  type="button"
30
- className="inline-flex shrink-0 items-center gap-1.5 rounded-md bg-primary px-2.5 py-1.5 text-xs font-semibold text-primary-foreground transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/25 disabled:cursor-not-allowed disabled:opacity-50"
30
+ className="inline-flex shrink-0 items-center gap-1.5 rounded-md bg-primary px-2.5 py-1.5 text-xs font-semibold text-primary-foreground transition-colors hover:bg-[hsl(var(--primary-hover))] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/25 disabled:cursor-not-allowed disabled:opacity-50"
31
31
  disabled={!sessionKey}
32
32
  onClick={() => presenter.chatThreadManager.openSideChatDraft(sessionKey)}
33
33
  >
@@ -42,7 +42,7 @@ export function ChatSessionChildSessions({
42
42
  {childSessionTabs.map((tab) => (
43
43
  <div
44
44
  key={tab.sessionKey}
45
- className="group relative flex w-full items-center rounded-lg border border-gray-200/80 bg-white transition-colors hover:border-gray-300 hover:bg-gray-50"
45
+ className="group relative flex w-full items-center rounded-lg border border-gray-200/80 bg-white transition-colors hover:border-gray-300 hover:bg-[var(--interaction-hover)]"
46
46
  >
47
47
  <button
48
48
  type="button"
@@ -121,8 +121,8 @@ export function WorkspaceSpreadsheetPreview({
121
121
  className={cn(
122
122
  "h-7 shrink-0 rounded-md px-2.5 text-xs transition-colors",
123
123
  sheet.name === activeSheet?.name
124
- ? "bg-accent font-medium text-accent-foreground"
125
- : "text-muted-foreground hover:bg-muted hover:text-foreground",
124
+ ? "bg-[var(--interaction-selection)] font-medium text-foreground"
125
+ : "text-muted-foreground hover:bg-[var(--interaction-hover)] hover:text-foreground",
126
126
  )}
127
127
  onClick={() => setSelectedSheetName(sheet.name)}
128
128
  >
@@ -96,7 +96,7 @@ function ObservationRow({
96
96
  type="button"
97
97
  data-testid={`observation-${item.id}-${toggleAction}`}
98
98
  disabled={isPending}
99
- className="inline-flex items-center gap-1.5 rounded-md border border-gray-200 px-2.5 py-1.5 text-xs font-medium text-gray-700 transition-colors hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-50"
99
+ className="inline-flex items-center gap-1.5 rounded-md border border-gray-200 px-2.5 py-1.5 text-xs font-medium text-gray-700 transition-colors hover:bg-[var(--interaction-hover)] disabled:cursor-not-allowed disabled:opacity-50"
100
100
  onClick={() => onAction(toggleAction)}
101
101
  >
102
102
  {toggleAction === 'pause' ? <Pause className="h-3.5 w-3.5" /> : <Play className="h-3.5 w-3.5" />}
@@ -107,7 +107,7 @@ function ObservationRow({
107
107
  type="button"
108
108
  data-testid={`observation-${item.id}-remove`}
109
109
  disabled={isPending}
110
- className="inline-flex items-center gap-1.5 rounded-md border border-rose-200 px-2.5 py-1.5 text-xs font-medium text-rose-700 transition-colors hover:bg-rose-50 disabled:cursor-not-allowed disabled:opacity-50"
110
+ className="inline-flex items-center gap-1.5 rounded-md border border-rose-200 px-2.5 py-1.5 text-xs font-medium text-rose-700 transition-colors hover:bg-destructive/10 disabled:cursor-not-allowed disabled:opacity-50"
111
111
  onClick={() => onAction('remove')}
112
112
  >
113
113
  <Trash2 className="h-3.5 w-3.5" />
@@ -179,7 +179,7 @@ export function ChatSessionContinuousAttention({ sessionKey }: { sessionKey: str
179
179
  type="button"
180
180
  role="tab"
181
181
  aria-selected={activeGroup === group}
182
- className={cn('flex-1 rounded-md px-3 py-2 text-xs font-medium transition-colors', activeGroup === group ? 'bg-gray-100 text-gray-900' : 'text-gray-500 hover:text-gray-700')}
182
+ className={cn('flex-1 rounded-md px-3 py-2 text-xs font-medium transition-colors', activeGroup === group ? 'bg-[var(--interaction-selection)] text-foreground' : 'text-muted-foreground hover:bg-[var(--interaction-hover)] hover:text-foreground')}
183
183
  onClick={() => setActiveGroup(group)}
184
184
  >
185
185
  {getGroupLabel(group)} <span className="ml-1 tabular-nums text-gray-400">{count}</span>
@@ -90,7 +90,7 @@ export function ChatSessionTokenUsage({ sessionKey }: { sessionKey: string | nul
90
90
  <span>{t('chatWorkspaceTokenUsageLoadFailed')}</span>
91
91
  <button
92
92
  type="button"
93
- className="shrink-0 rounded px-1.5 py-1 font-semibold text-gray-700 hover:bg-gray-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/25"
93
+ className="shrink-0 rounded px-1.5 py-1 font-semibold text-gray-700 hover:bg-[var(--interaction-hover)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/25"
94
94
  onClick={() => void usageQuery.refetch()}
95
95
  >
96
96
  {t('chatWorkspaceTokenUsageRetry')}
@@ -355,8 +355,8 @@ export function WorkspaceDirectoryTreeEntry({
355
355
  ref={rowRef}
356
356
  data-workspace-tree-entry=""
357
357
  className={cn(
358
- 'group flex h-[26px] w-full min-w-0 items-center text-gray-700 transition-colors hover:bg-gray-100 focus-within:bg-gray-100',
359
- selected ? 'bg-primary/10' : null,
358
+ 'group flex h-[26px] w-full min-w-0 items-center text-gray-700 transition-colors hover:bg-[var(--interaction-hover)] focus-within:bg-[var(--interaction-hover)]',
359
+ selected ? 'bg-[var(--interaction-selection)] hover:bg-[var(--interaction-selection)] focus-within:bg-[var(--interaction-selection)]' : null,
360
360
  entry.hidden ? 'opacity-65' : null,
361
361
  )}
362
362
  style={{ paddingLeft: `${6 + level * 12}px` }}
@@ -371,9 +371,10 @@ export function WorkspaceDirectoryTreeEntry({
371
371
  }}
372
372
  >
373
373
  <Input
374
+ density="compact"
374
375
  autoFocus
375
376
  aria-label={t('chatWorkspaceRenameName')}
376
- className="h-6 min-w-0 flex-1 px-1.5 text-xs"
377
+ className="h-6 min-w-0 flex-1 px-1.5"
377
378
  value={rename.name}
378
379
  onChange={(event) => rename.updateName(event.target.value)}
379
380
  onKeyDown={(event) => {
@@ -67,9 +67,10 @@ export function WorkspaceNewFolderTreeItem({
67
67
  <Folder className="h-4 w-4 shrink-0 text-amber-500" />
68
68
  )}
69
69
  <Input
70
+ density="compact"
70
71
  ref={inputRef}
71
72
  aria-label={t(kind === 'file' ? 'chatWorkspaceFileName' : 'chatWorkspaceFolderName')}
72
- className="h-7 min-w-0 flex-1 rounded-md px-2 text-xs"
73
+ className="h-7 min-w-0 flex-1 rounded-md px-2"
73
74
  disabled={isCreating}
74
75
  placeholder={t(kind === 'file' ? 'chatWorkspaceFileNamePlaceholder' : 'chatWorkspaceFolderNamePlaceholder')}
75
76
  value={name}
@@ -83,7 +83,7 @@ function SessionCronJobCard({
83
83
  const jobLabel = job.name || job.id;
84
84
 
85
85
  return (
86
- <article className="rounded-2xl border border-border/60 bg-background px-3.5 py-3 shadow-sm transition-colors hover:bg-muted/20 focus-within:bg-muted/20">
86
+ <article className="rounded-2xl border border-border/60 bg-background px-3.5 py-3 shadow-sm transition-colors hover:bg-[var(--interaction-hover)] focus-within:bg-[var(--interaction-hover)]">
87
87
  <div className="flex items-start gap-3">
88
88
  <span
89
89
  className={cn(
@@ -189,7 +189,7 @@ function SessionCronJobCard({
189
189
  setMenuOpen(false);
190
190
  void cronActions.runJob(job);
191
191
  }}
192
- className="flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm text-foreground transition-colors hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50"
192
+ className="flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm text-foreground transition-colors hover:bg-[var(--interaction-hover)] disabled:cursor-not-allowed disabled:opacity-50"
193
193
  >
194
194
  <Play className="h-3.5 w-3.5 text-muted-foreground" />
195
195
  {t("cronRunNow")}
@@ -201,7 +201,7 @@ function SessionCronJobCard({
201
201
  setMenuOpen(false);
202
202
  void cronActions.deleteJob(job);
203
203
  }}
204
- className="flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm text-red-600 transition-colors hover:bg-red-50 disabled:cursor-not-allowed disabled:opacity-50"
204
+ className="flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm text-red-600 transition-colors hover:bg-destructive/10 disabled:cursor-not-allowed disabled:opacity-50"
205
205
  >
206
206
  {t("delete")}
207
207
  </button>
@@ -105,7 +105,7 @@ function WorkspaceUnsupportedContent({
105
105
  <a
106
106
  href={contentUrl}
107
107
  download={label}
108
- className="inline-flex h-8 items-center rounded-lg border border-border bg-card px-3 text-xs font-medium text-foreground transition-colors hover:bg-muted"
108
+ className="inline-flex h-8 items-center rounded-lg border border-border bg-card px-3 text-xs font-medium text-foreground transition-colors hover:bg-[var(--interaction-hover)]"
109
109
  >
110
110
  {t("chatWorkspacePreviewDownload")}
111
111
  </a>
@@ -113,7 +113,7 @@ function WorkspaceUnsupportedContent({
113
113
  href={contentUrl}
114
114
  target="_blank"
115
115
  rel="noreferrer"
116
- className="inline-flex h-8 items-center rounded-lg bg-primary px-3 text-xs font-medium text-primary-foreground transition-colors hover:bg-primary/90"
116
+ className="inline-flex h-8 items-center rounded-lg bg-primary px-3 text-xs font-medium text-primary-foreground transition-colors hover:bg-[hsl(var(--primary-hover))]"
117
117
  >
118
118
  {t("chatWorkspacePreviewOpenExternally")}
119
119
  </a>
@@ -137,7 +137,7 @@ export function WorkspaceMarkdownOutline({
137
137
  <li key={item.index}>
138
138
  <button
139
139
  type="button"
140
- className="block w-full truncate rounded-md py-1.5 pr-2 text-left text-xs leading-4 text-gray-600 transition-colors hover:bg-gray-100 hover:text-gray-950 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-border active:bg-gray-200"
140
+ className="block w-full truncate rounded-md py-1.5 pr-2 text-left text-xs leading-4 text-gray-600 transition-colors hover:bg-[var(--interaction-hover)] hover:text-gray-950 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-border active:bg-[var(--interaction-hover)]"
141
141
  style={{
142
142
  paddingInlineStart: `${0.5 + item.depth * 0.75}rem`,
143
143
  }}
@@ -308,8 +308,8 @@ export function CronConfig() {
308
308
  handlePageChange(0);
309
309
  }}
310
310
  className={cn(
311
- "rounded-lg px-2.5 py-2 text-[11px] font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
312
- status === value && "bg-muted text-foreground",
311
+ "rounded-lg px-2.5 py-2 text-[11px] font-medium text-muted-foreground transition-colors hover:bg-[var(--interaction-hover)] hover:text-foreground",
312
+ status === value && "bg-[var(--interaction-selection)] hover:bg-[var(--interaction-selection)] text-foreground",
313
313
  )}
314
314
  >
315
315
  {t(label)}
@@ -206,7 +206,7 @@ export function CronJobDetailDialog({
206
206
  <SheetFooter className="shrink-0 border-t border-border/60 bg-background px-5 py-4 sm:px-7">
207
207
  <Button
208
208
  variant="ghost"
209
- className="text-red-600 hover:bg-red-50 hover:text-red-700"
209
+ className="text-red-600 hover:bg-destructive/10 hover:text-red-700"
210
210
  onClick={() => onDelete(job)}
211
211
  >
212
212
  <Trash2 className="mr-2 h-4 w-4" />
@@ -105,7 +105,7 @@ export function CronJobRow({
105
105
  return (
106
106
  <div
107
107
  className={cn(
108
- "group relative rounded-xl border-b border-border/55 transition-colors duration-150 last:border-b-0 hover:bg-muted/35 focus-within:bg-muted/35",
108
+ "group relative rounded-xl border-b border-border/55 transition-colors duration-150 last:border-b-0 hover:bg-[var(--interaction-hover)] focus-within:bg-[var(--interaction-hover)]",
109
109
  expanded && "bg-muted/35",
110
110
  )}
111
111
  >
@@ -206,7 +206,7 @@ export function CronJobRow({
206
206
  setMenuOpen(false);
207
207
  onRun(job);
208
208
  }}
209
- className="flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm text-foreground transition-colors hover:bg-muted"
209
+ className="flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm text-foreground transition-colors hover:bg-[var(--interaction-hover)]"
210
210
  >
211
211
  <Play className="h-3.5 w-3.5 text-muted-foreground" />
212
212
  {t("cronRunNow")}
@@ -217,7 +217,7 @@ export function CronJobRow({
217
217
  setMenuOpen(false);
218
218
  onDelete(job);
219
219
  }}
220
- className="flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm text-red-600 transition-colors hover:bg-red-50"
220
+ className="flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm text-red-600 transition-colors hover:bg-destructive/10"
221
221
  >
222
222
  <Trash2 className="h-3.5 w-3.5" />
223
223
  {t("delete")}
@@ -133,7 +133,7 @@ export function CronTemplateGallery({
133
133
  onClick={() => onSelect(t(template.promptKey))}
134
134
  className="group grid min-h-24 grid-cols-[38px_minmax(0,1fr)] items-center gap-3 rounded-2xl border border-border/60 bg-card px-4 py-4 text-left transition-all hover:-translate-y-0.5 hover:border-primary/20 hover:shadow-[0_12px_30px_rgba(30,45,52,0.08)] focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
135
135
  >
136
- <span className="flex h-9 w-9 shrink-0 items-center justify-center rounded-xl bg-muted text-muted-foreground transition-colors group-hover:bg-primary/10 group-hover:text-primary">
136
+ <span className="flex h-9 w-9 shrink-0 items-center justify-center rounded-xl bg-muted text-muted-foreground transition-colors group-hover:bg-[var(--interaction-hover)] group-hover:text-primary">
137
137
  <Icon className="h-4 w-4" aria-hidden="true" />
138
138
  </span>
139
139
  <span className="min-w-0">
@@ -7,6 +7,7 @@ import { InboxPage, resolveInboxFilter } from "@/features/inbox/pages/inbox-page
7
7
  import { t } from "@/shared/lib/i18n";
8
8
 
9
9
  const mocks = vi.hoisted(() => ({
10
+ isMobile: false,
10
11
  prepareChatReference: vi.fn(),
11
12
  requestSystemObjectReference: vi.fn(),
12
13
  }));
@@ -28,7 +29,7 @@ vi.mock("@/app/components/app-presenter-provider", () => ({
28
29
  }));
29
30
 
30
31
  vi.mock("@/app/hooks/use-viewport-layout", () => ({
31
- useViewportLayout: () => ({ isMobile: false }),
32
+ useViewportLayout: () => ({ isMobile: mocks.isMobile }),
32
33
  }));
33
34
 
34
35
  vi.mock("@/features/inbox/hooks/use-inbox-deliveries", () => ({
@@ -101,6 +102,7 @@ describe("resolveInboxFilter", () => {
101
102
  describe("InboxPage", () => {
102
103
  beforeEach(() => {
103
104
  vi.clearAllMocks();
105
+ mocks.isMobile = false;
104
106
  mocks.prepareChatReference.mockResolvedValue({
105
107
  reference: {
106
108
  uri: "nextclaw://objects/inbox-delivery/delivery-1",
@@ -109,7 +111,8 @@ describe("InboxPage", () => {
109
111
  });
110
112
  });
111
113
 
112
- it("opens a draft with the same visible system object intent as the reader dialog", async () => {
114
+ it.each([false, true])("opens a draft with the same system object intent (mobile=%s)", async (isMobile) => {
115
+ mocks.isMobile = isMobile;
113
116
  render(
114
117
  createElement(
115
118
  MemoryRouter,
@@ -134,7 +137,13 @@ describe("InboxPage", () => {
134
137
  ),
135
138
  );
136
139
 
137
- fireEvent.click(screen.getByRole("button", { name: t("inboxContinueChat") }));
140
+ const continueButton = screen.getByRole("button", { name: t("inboxContinueChat") });
141
+ if (isMobile) {
142
+ const moreButton = screen.getByRole("button", { name: t("more") });
143
+ expect(continueButton.compareDocumentPosition(moreButton) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy();
144
+ expect(screen.getByRole("button", { name: t("inboxTitle") })).toBeTruthy();
145
+ }
146
+ fireEvent.click(continueButton);
138
147
 
139
148
  await waitFor(() => {
140
149
  expect(screen.getByTestId("current-path").textContent).toBe(CHAT_DRAFT_SESSION_PATH);