@nextclaw/ui 0.14.2 → 0.14.3

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 (129) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/assets/{api-a14tR_z1.js → api-BP_8IaxB.js} +3 -3
  3. package/dist/assets/{channels-list-page-CFGkm4DT.js → channels-list-page-DEh5Jjqx.js} +1 -1
  4. package/dist/assets/chat-page-BRB0N5WW.js +105 -0
  5. package/dist/assets/config-split-page-CRhlZ_pH.js +1 -0
  6. package/dist/assets/{confirm-dialog-ClH_Ec7n.js → confirm-dialog-DsivFJ4r.js} +2 -2
  7. package/dist/assets/{desktop-update-config-DPNDnVpk.js → desktop-update-config-B0w9p2ep.js} +1 -1
  8. package/dist/assets/{dist-BtCS2Ucq.js → dist-CikkhOlq.js} +1 -1
  9. package/dist/assets/{dist-CLGGLm8b.js → dist-PVA_xL1D.js} +1 -1
  10. package/dist/assets/doc-browser-BoNJ7-tE.js +1 -0
  11. package/dist/assets/doc-browser-CdJ_d4ik.js +1 -0
  12. package/dist/assets/{doc-browser-context-D4JwMMxK.js → doc-browser-context-MTw4EvKd.js} +1 -1
  13. package/dist/assets/{ellipsis-CtJXjIol.js → ellipsis-y6vDtq4M.js} +1 -1
  14. package/dist/assets/{external-link-CdJiG13p.js → external-link-DVJIQf_G.js} +1 -1
  15. package/dist/assets/index-BiE-K8-q.css +1 -0
  16. package/dist/assets/index-D9BAE_L_.js +105 -0
  17. package/dist/assets/{mcp-marketplace-page-BU0kIjhR.js → mcp-marketplace-page-B1SZNY5m.js} +1 -1
  18. package/dist/assets/mcp-marketplace-page-Cq_Tw42T.js +1 -0
  19. package/dist/assets/{model-config-page-D6hYXROd.js → model-config-page-DotaTUHb.js} +1 -1
  20. package/dist/assets/plus-BbZqquJe.js +1 -0
  21. package/dist/assets/{provider-scoped-model-input-DAX2HgmR.js → provider-scoped-model-input-DsFRuWJH.js} +1 -1
  22. package/dist/assets/providers-config-page-DW4tQSLN.js +1 -0
  23. package/dist/assets/{react-C6cZgP44.js → react-VNqT5Zp7.js} +1 -1
  24. package/dist/assets/remote-B8TiUfwW.js +1 -0
  25. package/dist/assets/rotate-cw-DjHDTkCv.js +1 -0
  26. package/dist/assets/{runtime-config-page-C5xKaV3i.js → runtime-config-page-S6ErRHR8.js} +1 -1
  27. package/dist/assets/{save-DKA0x4zk.js → save-BOJ477H-.js} +1 -1
  28. package/dist/assets/{search-BNlcoj5c.js → search-BEti5beA.js} +1 -1
  29. package/dist/assets/{search-config-page-Cq9uJ-N8.js → search-config-page-DGj5am03.js} +1 -1
  30. package/dist/assets/{secrets-config-page-CxSbZLBo.js → secrets-config-page--IzrIOid.js} +1 -1
  31. package/dist/assets/{select-CvTlDZTQ.js → select-hoj8dK4K.js} +2 -2
  32. package/dist/assets/{tag-chip-8ffF2y2C.js → tag-chip-T8-h-die.js} +1 -1
  33. package/dist/assets/{use-config-DmT0o1gv.js → use-config-CjRV2hwL.js} +1 -1
  34. package/dist/assets/x-D9PXs_xP.js +1 -0
  35. package/dist/index.html +69 -19
  36. package/index.html +55 -5
  37. package/package.json +7 -7
  38. package/src/app/components/layout/__tests__/sidebar.layout.test.tsx +3 -3
  39. package/src/app/components/layout/header.tsx +3 -3
  40. package/src/app/components/layout/page-layout.tsx +2 -2
  41. package/src/app/components/layout/runtime-status-entry.tsx +7 -7
  42. package/src/app/components/layout/sidebar-items.tsx +10 -10
  43. package/src/app/components/layout/sidebar-rail.styles.ts +2 -2
  44. package/src/app/components/layout/sidebar.tsx +6 -6
  45. package/src/app/styles/design-system.css +388 -26
  46. package/src/app/test/vitest-setup.ts +31 -0
  47. package/src/features/chat/components/chat-sidebar-list-mode-switch.tsx +3 -3
  48. package/src/features/chat/components/conversation/__tests__/chat-conversation-header.test.tsx +4 -2
  49. package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +1 -1
  50. package/src/features/chat/components/conversation/chat-conversation-header.tsx +7 -6
  51. package/src/features/chat/components/conversation/chat-conversation-panel.tsx +1 -1
  52. package/src/features/chat/components/conversation/chat-conversation-skeleton.tsx +13 -13
  53. package/src/features/chat/components/layout/__tests__/chat-sidebar.test.tsx +2 -2
  54. package/src/features/chat/components/layout/chat-page-shell.tsx +1 -1
  55. package/src/features/chat/components/layout/chat-sidebar-desktop-layout.tsx +3 -3
  56. package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +14 -14
  57. package/src/features/chat/components/layout/chat-sidebar-utility-menu.tsx +15 -15
  58. package/src/features/chat/components/layout/chat-sidebar.tsx +3 -3
  59. package/src/features/chat/features/conversation/components/__tests__/session-conversation-area.test.tsx +225 -0
  60. package/src/features/chat/features/conversation/components/__tests__/session-conversation-input.streaming.test.tsx +199 -0
  61. package/src/features/chat/features/conversation/components/session-conversation-area.tsx +28 -9
  62. package/src/features/chat/features/conversation/components/session-conversation-input.tsx +18 -6
  63. package/src/features/chat/features/conversation/hooks/use-session-conversation-controller.ts +3 -13
  64. package/src/features/chat/features/conversation/hooks/use-session-conversation-input-query.ts +19 -3
  65. package/src/features/chat/features/message/components/chat-inline-panel-app-card.tsx +7 -7
  66. package/src/features/chat/features/message/components/chat-message-list.container.tsx +6 -6
  67. package/src/features/chat/features/session/components/chat-sidebar-project-groups.tsx +5 -5
  68. package/src/features/chat/features/session/components/chat-sidebar-session-list.tsx +4 -4
  69. package/src/features/chat/features/session/components/session-context-icon.tsx +2 -2
  70. package/src/features/chat/features/session/components/session-header/__tests__/chat-session-project-badge.test.tsx +2 -2
  71. package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx +1 -1
  72. package/src/features/chat/features/session/components/session-header/chat-session-header-menu-item.tsx +1 -1
  73. package/src/features/chat/features/session/components/session-header/chat-session-metadata-dialog.tsx +1 -1
  74. package/src/features/chat/features/session/components/session-header/chat-session-project-badge.tsx +3 -3
  75. package/src/features/chat/features/session/components/session-run-badge.tsx +1 -1
  76. package/src/features/chat/features/session-type/hooks/use-chat-session-type-state.ts +10 -2
  77. package/src/features/chat/features/welcome/components/__tests__/chat-welcome.test.tsx +0 -7
  78. package/src/features/chat/features/welcome/components/chat-welcome-agent-picker.tsx +3 -3
  79. package/src/features/chat/features/welcome/components/chat-welcome-capability-grid.tsx +4 -4
  80. package/src/features/chat/features/welcome/components/chat-welcome-project-picker.tsx +14 -19
  81. package/src/features/chat/features/welcome/components/chat-welcome-session-type-picker.tsx +3 -3
  82. package/src/features/chat/features/welcome/components/chat-welcome.tsx +4 -4
  83. package/src/features/chat/features/welcome/utils/__tests__/chat-welcome-project-options.utils.test.ts +6 -8
  84. package/src/features/chat/features/welcome/utils/chat-welcome-project-options.utils.ts +1 -16
  85. package/src/features/panel-apps/components/panel-app-list-item.tsx +8 -8
  86. package/src/features/panel-apps/components/panel-app-toolbar.tsx +4 -4
  87. package/src/features/panel-apps/components/panel-apps-list.tsx +20 -20
  88. package/src/features/pwa/managers/__tests__/pwa-shell-theme.manager.test.ts +70 -6
  89. package/src/features/pwa/managers/pwa-shell-theme.manager.ts +10 -5
  90. package/src/features/service-apps/components/service-action-authorization-dialog.tsx +8 -8
  91. package/src/features/service-apps/components/service-apps-panel.tsx +24 -24
  92. package/src/features/settings/components/config/provider-advanced-settings-section.tsx +5 -5
  93. package/src/features/settings/components/config/provider-auth-section.tsx +7 -7
  94. package/src/features/settings/components/config/provider-form.tsx +10 -10
  95. package/src/features/settings/components/config/provider-models-section.tsx +16 -16
  96. package/src/features/settings/components/config/provider-pill-selector.tsx +1 -1
  97. package/src/features/settings/pages/providers-config-page.tsx +17 -17
  98. package/src/shared/components/config-split-page.tsx +11 -11
  99. package/src/shared/components/doc-browser/doc-browser-home-page.tsx +2 -2
  100. package/src/shared/components/doc-browser/doc-browser-panel-parts.tsx +4 -4
  101. package/src/shared/components/doc-browser/doc-browser-tab-strip.tsx +4 -4
  102. package/src/shared/components/doc-browser/doc-browser.tsx +3 -3
  103. package/src/shared/components/resizable-right-panel/resizable-right-panel.tsx +1 -1
  104. package/src/shared/components/ui/actions/icon-action-button.tsx +1 -1
  105. package/src/shared/components/ui/button.tsx +4 -4
  106. package/src/shared/components/ui/card.tsx +4 -4
  107. package/src/shared/components/ui/dialog.tsx +5 -5
  108. package/src/shared/components/ui/input.tsx +1 -1
  109. package/src/shared/components/ui/label.tsx +1 -1
  110. package/src/shared/components/ui/popover.tsx +1 -1
  111. package/src/shared/components/ui/select.tsx +3 -3
  112. package/src/shared/components/ui/switch.tsx +3 -3
  113. package/src/shared/components/ui/tabs.tsx +4 -4
  114. package/src/shared/components/ui/textarea.tsx +1 -1
  115. package/src/shared/lib/i18n/locales/en-US/core.json +7 -2
  116. package/src/shared/lib/i18n/locales/zh-CN/core.json +7 -2
  117. package/src/shared/lib/theme/index.ts +94 -52
  118. package/dist/assets/chat-page-CEdavJXc.js +0 -105
  119. package/dist/assets/config-split-page-B5b9B0uE.js +0 -1
  120. package/dist/assets/doc-browser-5nMWYKBD.js +0 -1
  121. package/dist/assets/doc-browser-BJRLhztv.js +0 -1
  122. package/dist/assets/index-BDN1zzMQ.js +0 -105
  123. package/dist/assets/index-g3uSZXoc.css +0 -1
  124. package/dist/assets/mcp-marketplace-page-sMNFSq_T.js +0 -1
  125. package/dist/assets/plus-DPjb0piO.js +0 -1
  126. package/dist/assets/providers-config-page-BzAeaACA.js +0 -1
  127. package/dist/assets/remote-B0G80uPr.js +0 -1
  128. package/dist/assets/rotate-cw-DnEB1Rju.js +0 -1
  129. package/dist/assets/x-BiSSpgqB.js +0 -1
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * NextClaw Design System
3
- * Warm minimalist palette inspired by YouWare + YouMind
4
- * Warm amber brand, warm neutral grays, refined details
3
+ * Quiet workbench palettes.
4
+ * Neutral surfaces carry the UI; accent colors only mark actions and focus.
5
5
  */
6
6
 
7
7
  @layer base {
8
8
  :root {
9
9
  /* ========================================
10
- BRAND COLORS (Olive Green)
10
+ BRAND COLORS (Natural Olive)
11
11
  ======================================== */
12
12
  --brand-50: 94 20% 95%;
13
13
  --brand-100: 94 20% 90%;
@@ -140,7 +140,7 @@
140
140
  --radius-full: 9999px;
141
141
 
142
142
  /* ========================================
143
- SHADOWS (Warmer tint)
143
+ SHADOWS (Natural warm tint)
144
144
  ======================================== */
145
145
  --shadow-xs: 0 1px 2px 0 rgb(30 20 10 / 0.04);
146
146
  --shadow-sm: 0 1px 3px 0 rgb(30 20 10 / 0.06), 0 1px 2px -1px rgb(30 20 10 / 0.04);
@@ -207,29 +207,175 @@
207
207
  }
208
208
  }
209
209
 
210
+ @layer base {
211
+ :root[data-theme="minimal"] {
212
+ /* ========================================
213
+ BRAND COLORS (Minimal Ink)
214
+ ======================================== */
215
+ --brand-50: 0 0% 98%;
216
+ --brand-100: 0 0% 96%;
217
+ --brand-200: 0 0% 90%;
218
+ --brand-300: 0 0% 80%;
219
+ --brand-400: 0 0% 64%;
220
+ --brand-500: 0 0% 9%;
221
+ --brand-600: 0 0% 5%;
222
+ --brand-700: 0 0% 0%;
223
+ --brand-800: 0 0% 4%;
224
+ --brand-900: 0 0% 2%;
225
+
226
+ /* ========================================
227
+ NEUTRAL COLORS (Clean Gray / Ink scale)
228
+ ======================================== */
229
+ --gray-50: 0 0% 100%;
230
+ --gray-100: 0 0% 98%;
231
+ --gray-200: 0 0% 96%;
232
+ --gray-300: 0 0% 90%;
233
+ --gray-400: 0 0% 74%;
234
+ --gray-500: 0 0% 45%;
235
+ --gray-600: 0 0% 32%;
236
+ --gray-700: 0 0% 20%;
237
+ --gray-800: 0 0% 9%;
238
+ --gray-900: 0 0% 4%;
239
+
240
+ /* Semantic Colors */
241
+ --background: var(--gray-50);
242
+ --background-secondary: var(--gray-100);
243
+ --background-tertiary: var(--gray-200);
244
+ --foreground: var(--gray-800);
245
+ --foreground-secondary: var(--gray-700);
246
+ --foreground-tertiary: var(--gray-500);
247
+ --foreground-muted: var(--gray-400);
248
+ --primary: var(--brand-500);
249
+ --primary-hover: var(--brand-600);
250
+ --primary-active: var(--brand-700);
251
+ --secondary: var(--gray-100);
252
+ --secondary-hover: var(--gray-200);
253
+ --secondary-foreground: var(--gray-800);
254
+ --accent: 0 0% 96%;
255
+ --accent-foreground: var(--brand-700);
256
+ --muted: var(--gray-100);
257
+ --muted-foreground: var(--gray-500);
258
+ --card: 0 0% 100%;
259
+ --card-foreground: var(--gray-800);
260
+ --card-border: 0 0% 90%;
261
+ --popover: 0 0% 100%;
262
+ --popover-foreground: var(--gray-800);
263
+ --border: 0 0% 90%;
264
+ --border-hover: 0 0% 81%;
265
+ --border-active: var(--brand-500);
266
+ --input: 0 0% 100%;
267
+ --input-border: 0 0% 90%;
268
+ --input-focus: var(--brand-500);
269
+ --ring: var(--brand-500);
270
+ --ring-offset: var(--gray-50);
271
+
272
+ /* Shadows (minimal neutral tint) */
273
+ --shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.03);
274
+ --shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.05), 0 1px 2px -1px rgb(0 0 0 / 0.04);
275
+ --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.05), 0 2px 4px -2px rgb(0 0 0 / 0.04);
276
+ --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.06), 0 4px 6px -4px rgb(0 0 0 / 0.04);
277
+ --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.08), 0 8px 10px -6px rgb(0 0 0 / 0.04);
278
+ --shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.14);
279
+ --shadow-card: 0 0 8px 0 rgba(0, 0, 0, 0.04);
280
+ --shadow-card-hover: 0 0 16px 0 rgba(0, 0, 0, 0.06);
281
+ }
282
+ }
283
+
284
+ @layer base {
285
+ :root[data-theme="warm"] {
286
+ /* ========================================
287
+ BRAND COLORS (Paper Taupe)
288
+ ======================================== */
289
+ --brand-50: 36 35% 94%;
290
+ --brand-100: 35 32% 90%;
291
+ --brand-200: 34 26% 82%;
292
+ --brand-300: 32 20% 70%;
293
+ --brand-400: 30 16% 56%;
294
+ --brand-500: 28 15% 42%;
295
+ --brand-600: 27 16% 34%;
296
+ --brand-700: 25 18% 28%;
297
+ --brand-800: 24 20% 20%;
298
+ --brand-900: 23 24% 13%;
299
+
300
+ /* ========================================
301
+ NEUTRAL COLORS (Warm Paper / Ink scale)
302
+ ======================================== */
303
+ --gray-50: 40 38% 97%;
304
+ --gray-100: 39 30% 94%;
305
+ --gray-200: 36 24% 87%;
306
+ --gray-300: 34 18% 78%;
307
+ --gray-400: 32 10% 60%;
308
+ --gray-500: 30 9% 46%;
309
+ --gray-600: 28 10% 36%;
310
+ --gray-700: 26 14% 27%;
311
+ --gray-800: 24 18% 18%;
312
+ --gray-900: 22 24% 11%;
313
+
314
+ /* Semantic Colors */
315
+ --background: var(--gray-50);
316
+ --background-secondary: var(--gray-100);
317
+ --background-tertiary: var(--gray-200);
318
+ --foreground: var(--gray-800);
319
+ --foreground-secondary: var(--gray-700);
320
+ --foreground-tertiary: var(--gray-500);
321
+ --foreground-muted: var(--gray-400);
322
+ --primary: var(--brand-500);
323
+ --primary-hover: var(--brand-600);
324
+ --primary-active: var(--brand-700);
325
+ --secondary: var(--gray-100);
326
+ --secondary-hover: var(--gray-200);
327
+ --secondary-foreground: var(--gray-800);
328
+ --accent: 38 30% 91%;
329
+ --accent-foreground: var(--brand-700);
330
+ --muted: var(--gray-100);
331
+ --muted-foreground: var(--gray-500);
332
+ --card: 40 48% 98%;
333
+ --card-foreground: var(--gray-800);
334
+ --card-border: 34 22% 84%;
335
+ --popover: 40 48% 98%;
336
+ --popover-foreground: var(--gray-800);
337
+ --border: 34 22% 84%;
338
+ --border-hover: 32 20% 73%;
339
+ --border-active: var(--brand-500);
340
+ --input: 40 48% 98%;
341
+ --input-border: 34 22% 84%;
342
+ --input-focus: var(--brand-500);
343
+ --ring: var(--brand-500);
344
+ --ring-offset: var(--gray-50);
345
+
346
+ /* Shadows (warmer tint) */
347
+ --shadow-xs: 0 1px 2px 0 rgb(30 20 10 / 0.04);
348
+ --shadow-sm: 0 1px 3px 0 rgb(30 20 10 / 0.06), 0 1px 2px -1px rgb(30 20 10 / 0.04);
349
+ --shadow-md: 0 4px 6px -1px rgb(30 20 10 / 0.06), 0 2px 4px -2px rgb(30 20 10 / 0.04);
350
+ --shadow-lg: 0 10px 15px -3px rgb(30 20 10 / 0.06), 0 4px 6px -4px rgb(30 20 10 / 0.04);
351
+ --shadow-xl: 0 20px 25px -5px rgb(30 20 10 / 0.08), 0 8px 10px -6px rgb(30 20 10 / 0.04);
352
+ --shadow-2xl: 0 25px 50px -12px rgb(30 20 10 / 0.15);
353
+ }
354
+ }
355
+
210
356
  @layer base {
211
357
  :root[data-theme="cool"] {
212
358
  /* ========================================
213
- BRAND COLORS (Cool Blue)
359
+ BRAND COLORS (Mist Blue)
214
360
  ======================================== */
215
- --brand-50: 214 100% 97%;
216
- --brand-100: 214 95% 93%;
217
- --brand-200: 213 97% 87%;
218
- --brand-300: 212 96% 78%;
219
- --brand-400: 213 94% 68%;
220
- --brand-500: 217 91% 60%;
221
- --brand-600: 221 83% 53%;
222
- --brand-700: 224 76% 48%;
223
- --brand-800: 226 71% 40%;
224
- --brand-900: 224 64% 33%;
361
+ --brand-50: 210 48% 96%;
362
+ --brand-100: 211 42% 92%;
363
+ --brand-200: 212 36% 84%;
364
+ --brand-300: 212 32% 72%;
365
+ --brand-400: 213 30% 60%;
366
+ --brand-500: 214 35% 48%;
367
+ --brand-600: 214 36% 42%;
368
+ --brand-700: 215 38% 34%;
369
+ --brand-800: 216 40% 26%;
370
+ --brand-900: 218 42% 18%;
225
371
 
226
372
  /* ========================================
227
373
  NEUTRAL COLORS (Cool Slate)
228
374
  ======================================== */
229
- --gray-50: 210 20% 98%;
230
- --gray-100: 220 14% 96%;
231
- --gray-200: 220 13% 91%;
232
- --gray-300: 216 12% 84%;
375
+ --gray-50: 210 32% 98%;
376
+ --gray-100: 210 24% 96%;
377
+ --gray-200: 214 18% 90%;
378
+ --gray-300: 216 14% 82%;
233
379
  --gray-400: 218 11% 65%;
234
380
  --gray-500: 220 9% 46%;
235
381
  --gray-600: 215 14% 34%;
@@ -255,16 +401,16 @@
255
401
  --accent-foreground: var(--brand-700);
256
402
  --muted: var(--gray-100);
257
403
  --muted-foreground: var(--gray-500);
258
- --card: 0 0% 100%;
404
+ --card: 210 36% 99%;
259
405
  --card-foreground: var(--gray-800);
260
- --card-border: var(--gray-200);
261
- --popover: 0 0% 100%;
406
+ --card-border: 214 22% 87%;
407
+ --popover: 210 36% 99%;
262
408
  --popover-foreground: var(--gray-800);
263
- --border: var(--gray-200);
264
- --border-hover: var(--gray-300);
409
+ --border: 214 22% 87%;
410
+ --border-hover: 215 17% 76%;
265
411
  --border-active: var(--brand-500);
266
- --input: 0 0% 100%;
267
- --input-border: var(--gray-200);
412
+ --input: 210 36% 99%;
413
+ --input-border: 214 22% 87%;
268
414
  --input-focus: var(--brand-500);
269
415
  --ring: var(--brand-500);
270
416
  --ring-offset: var(--gray-50);
@@ -279,6 +425,222 @@
279
425
  }
280
426
  }
281
427
 
428
+ @layer base {
429
+ :root[data-theme="dawn"] {
430
+ /* ========================================
431
+ BRAND COLORS (Dawn Clay)
432
+ ======================================== */
433
+ --brand-50: 352 34% 96%;
434
+ --brand-100: 352 30% 92%;
435
+ --brand-200: 352 25% 84%;
436
+ --brand-300: 352 22% 72%;
437
+ --brand-400: 351 22% 58%;
438
+ --brand-500: 350 24% 46%;
439
+ --brand-600: 350 25% 39%;
440
+ --brand-700: 349 26% 32%;
441
+ --brand-800: 348 28% 24%;
442
+ --brand-900: 347 30% 16%;
443
+
444
+ /* ========================================
445
+ NEUTRAL COLORS (Blush Paper)
446
+ ======================================== */
447
+ --gray-50: 24 38% 97%;
448
+ --gray-100: 20 30% 94%;
449
+ --gray-200: 18 22% 87%;
450
+ --gray-300: 17 18% 78%;
451
+ --gray-400: 16 10% 60%;
452
+ --gray-500: 15 9% 46%;
453
+ --gray-600: 12 10% 36%;
454
+ --gray-700: 10 13% 27%;
455
+ --gray-800: 8 16% 18%;
456
+ --gray-900: 6 20% 11%;
457
+
458
+ /* Semantic Colors */
459
+ --background: var(--gray-50);
460
+ --background-secondary: var(--gray-100);
461
+ --background-tertiary: var(--gray-200);
462
+ --foreground: var(--gray-800);
463
+ --foreground-secondary: var(--gray-700);
464
+ --foreground-tertiary: var(--gray-500);
465
+ --foreground-muted: var(--gray-400);
466
+ --primary: var(--brand-500);
467
+ --primary-hover: var(--brand-600);
468
+ --primary-active: var(--brand-700);
469
+ --secondary: var(--gray-100);
470
+ --secondary-hover: var(--gray-200);
471
+ --secondary-foreground: var(--gray-800);
472
+ --accent: 352 34% 94%;
473
+ --accent-foreground: var(--brand-700);
474
+ --muted: var(--gray-100);
475
+ --muted-foreground: var(--gray-500);
476
+ --card: 24 48% 98%;
477
+ --card-foreground: var(--gray-800);
478
+ --card-border: 18 22% 84%;
479
+ --popover: 24 48% 98%;
480
+ --popover-foreground: var(--gray-800);
481
+ --border: 18 22% 84%;
482
+ --border-hover: 16 20% 74%;
483
+ --border-active: var(--brand-500);
484
+ --input: 24 48% 98%;
485
+ --input-border: 18 22% 84%;
486
+ --input-focus: var(--brand-500);
487
+ --ring: var(--brand-500);
488
+ --ring-offset: var(--gray-50);
489
+
490
+ /* Shadows (clay tint) */
491
+ --shadow-xs: 0 1px 2px 0 rgb(64 40 36 / 0.04);
492
+ --shadow-sm: 0 1px 3px 0 rgb(64 40 36 / 0.06), 0 1px 2px -1px rgb(64 40 36 / 0.04);
493
+ --shadow-md: 0 4px 6px -1px rgb(64 40 36 / 0.06), 0 2px 4px -2px rgb(64 40 36 / 0.04);
494
+ --shadow-lg: 0 10px 15px -3px rgb(64 40 36 / 0.06), 0 4px 6px -4px rgb(64 40 36 / 0.04);
495
+ --shadow-xl: 0 20px 25px -5px rgb(64 40 36 / 0.08), 0 8px 10px -6px rgb(64 40 36 / 0.04);
496
+ --shadow-2xl: 0 25px 50px -12px rgb(64 40 36 / 0.14);
497
+ }
498
+ }
499
+
500
+ @layer base {
501
+ :root[data-theme="graphite"] {
502
+ /* ========================================
503
+ BRAND COLORS (Quiet Graphite)
504
+ ======================================== */
505
+ --brand-50: 220 12% 95%;
506
+ --brand-100: 220 10% 91%;
507
+ --brand-200: 220 9% 84%;
508
+ --brand-300: 220 8% 72%;
509
+ --brand-400: 220 7% 58%;
510
+ --brand-500: 220 9% 39%;
511
+ --brand-600: 220 10% 32%;
512
+ --brand-700: 220 12% 25%;
513
+ --brand-800: 220 14% 18%;
514
+ --brand-900: 220 18% 11%;
515
+
516
+ /* ========================================
517
+ NEUTRAL COLORS (Soft Monochrome)
518
+ ======================================== */
519
+ --gray-50: 48 10% 97%;
520
+ --gray-100: 45 8% 94%;
521
+ --gray-200: 42 7% 87%;
522
+ --gray-300: 38 6% 78%;
523
+ --gray-400: 34 5% 60%;
524
+ --gray-500: 30 4% 46%;
525
+ --gray-600: 28 5% 36%;
526
+ --gray-700: 25 7% 27%;
527
+ --gray-800: 220 11% 18%;
528
+ --gray-900: 220 18% 11%;
529
+
530
+ /* Semantic Colors */
531
+ --background: var(--gray-50);
532
+ --background-secondary: var(--gray-100);
533
+ --background-tertiary: var(--gray-200);
534
+ --foreground: var(--gray-800);
535
+ --foreground-secondary: var(--gray-700);
536
+ --foreground-tertiary: var(--gray-500);
537
+ --foreground-muted: var(--gray-400);
538
+ --primary: var(--brand-500);
539
+ --primary-hover: var(--brand-600);
540
+ --primary-active: var(--brand-700);
541
+ --secondary: var(--gray-100);
542
+ --secondary-hover: var(--gray-200);
543
+ --secondary-foreground: var(--gray-800);
544
+ --accent: 220 12% 92%;
545
+ --accent-foreground: var(--brand-700);
546
+ --muted: var(--gray-100);
547
+ --muted-foreground: var(--gray-500);
548
+ --card: 48 13% 99%;
549
+ --card-foreground: var(--gray-800);
550
+ --card-border: 42 7% 84%;
551
+ --popover: 48 13% 99%;
552
+ --popover-foreground: var(--gray-800);
553
+ --border: 42 7% 84%;
554
+ --border-hover: 38 6% 74%;
555
+ --border-active: var(--brand-500);
556
+ --input: 48 13% 99%;
557
+ --input-border: 42 7% 84%;
558
+ --input-focus: var(--brand-500);
559
+ --ring: var(--brand-500);
560
+ --ring-offset: var(--gray-50);
561
+
562
+ /* Shadows (neutral tint) */
563
+ --shadow-xs: 0 1px 2px 0 rgb(24 26 31 / 0.04);
564
+ --shadow-sm: 0 1px 3px 0 rgb(24 26 31 / 0.06), 0 1px 2px -1px rgb(24 26 31 / 0.04);
565
+ --shadow-md: 0 4px 6px -1px rgb(24 26 31 / 0.06), 0 2px 4px -2px rgb(24 26 31 / 0.04);
566
+ --shadow-lg: 0 10px 15px -3px rgb(24 26 31 / 0.06), 0 4px 6px -4px rgb(24 26 31 / 0.04);
567
+ --shadow-xl: 0 20px 25px -5px rgb(24 26 31 / 0.08), 0 8px 10px -6px rgb(24 26 31 / 0.04);
568
+ --shadow-2xl: 0 25px 50px -12px rgb(24 26 31 / 0.14);
569
+ }
570
+ }
571
+
572
+ @layer base {
573
+ :root[data-theme="probe"] {
574
+ /* ========================================
575
+ BRAND COLORS (Reference Ink)
576
+ ======================================== */
577
+ --brand-50: 210 16% 95%;
578
+ --brand-100: 210 14% 90%;
579
+ --brand-200: 210 12% 82%;
580
+ --brand-300: 210 11% 70%;
581
+ --brand-400: 210 12% 52%;
582
+ --brand-500: 210 14% 22%;
583
+ --brand-600: 210 16% 18%;
584
+ --brand-700: 210 18% 15%;
585
+ --brand-800: 210 20% 12%;
586
+ --brand-900: 210 24% 9%;
587
+
588
+ /* ========================================
589
+ NEUTRAL COLORS (Cream Paper / Ink)
590
+ ======================================== */
591
+ --gray-50: 42 83% 98%;
592
+ --gray-100: 41 80% 96%;
593
+ --gray-200: 38 48% 92%;
594
+ --gray-300: 38 24% 78%;
595
+ --gray-400: 180 2% 52%;
596
+ --gray-500: 213 6% 45%;
597
+ --gray-600: 213 6% 36%;
598
+ --gray-700: 213 6% 30%;
599
+ --gray-800: 207 28% 19%;
600
+ --gray-900: 210 30% 12%;
601
+
602
+ /* Semantic Colors */
603
+ --background: var(--gray-50);
604
+ --background-secondary: var(--gray-100);
605
+ --background-tertiary: var(--gray-200);
606
+ --foreground: var(--gray-800);
607
+ --foreground-secondary: var(--gray-700);
608
+ --foreground-tertiary: var(--gray-500);
609
+ --foreground-muted: var(--gray-400);
610
+ --primary: var(--brand-500);
611
+ --primary-hover: var(--brand-600);
612
+ --primary-active: var(--brand-700);
613
+ --secondary: var(--gray-100);
614
+ --secondary-hover: var(--gray-200);
615
+ --secondary-foreground: var(--gray-800);
616
+ --accent: 210 16% 92%;
617
+ --accent-foreground: var(--brand-700);
618
+ --muted: var(--gray-100);
619
+ --muted-foreground: var(--gray-500);
620
+ --card: 41 80% 96%;
621
+ --card-foreground: var(--gray-800);
622
+ --card-border: 38 26% 82%;
623
+ --popover: 42 83% 98%;
624
+ --popover-foreground: var(--gray-800);
625
+ --border: 38 26% 82%;
626
+ --border-hover: 210 14% 72%;
627
+ --border-active: var(--brand-500);
628
+ --input: 42 83% 98%;
629
+ --input-border: 38 26% 82%;
630
+ --input-focus: var(--brand-500);
631
+ --ring: var(--brand-500);
632
+ --ring-offset: var(--gray-50);
633
+
634
+ /* Shadows (ink / paper tint) */
635
+ --shadow-xs: 0 1px 2px 0 rgb(34 49 61 / 0.04);
636
+ --shadow-sm: 0 1px 3px 0 rgb(34 49 61 / 0.06), 0 1px 2px -1px rgb(34 49 61 / 0.04);
637
+ --shadow-md: 0 4px 6px -1px rgb(34 49 61 / 0.06), 0 2px 4px -2px rgb(34 49 61 / 0.04);
638
+ --shadow-lg: 0 10px 15px -3px rgb(34 49 61 / 0.06), 0 4px 6px -4px rgb(34 49 61 / 0.04);
639
+ --shadow-xl: 0 20px 25px -5px rgb(34 49 61 / 0.08), 0 8px 10px -6px rgb(34 49 61 / 0.04);
640
+ --shadow-2xl: 0 25px 50px -12px rgb(34 49 61 / 0.14);
641
+ }
642
+ }
643
+
282
644
  @layer utilities {
283
645
  /* ========================================
284
646
  UTILITY CLASSES
@@ -14,3 +14,34 @@ class MockResizeObserver {
14
14
  }
15
15
 
16
16
  vi.stubGlobal('ResizeObserver', MockResizeObserver);
17
+
18
+ class MemoryStorage implements Storage {
19
+ private readonly values = new Map<string, string>();
20
+
21
+ get length() {
22
+ return this.values.size;
23
+ }
24
+
25
+ clear = () => {
26
+ this.values.clear();
27
+ };
28
+
29
+ getItem = (key: string) => this.values.get(key) ?? null;
30
+
31
+ key = (index: number) => Array.from(this.values.keys())[index] ?? null;
32
+
33
+ removeItem = (key: string) => {
34
+ this.values.delete(key);
35
+ };
36
+
37
+ setItem = (key: string, value: string) => {
38
+ this.values.set(key, value);
39
+ };
40
+ }
41
+
42
+ if (typeof window !== 'undefined' && typeof window.localStorage?.getItem !== 'function') {
43
+ Object.defineProperty(window, 'localStorage', {
44
+ configurable: true,
45
+ value: new MemoryStorage()
46
+ });
47
+ }
@@ -10,16 +10,16 @@ export function ChatSidebarListModeSwitch({ isProjectFirstView, onSelectMode }:
10
10
  type="button"
11
11
  aria-pressed={!isProjectFirstView}
12
12
  onClick={() => onSelectMode('time-first')}
13
- className={cn('transition-colors', isProjectFirstView ? 'text-gray-400 hover:text-gray-600' : 'font-medium text-gray-600')}
13
+ className={cn('transition-colors', isProjectFirstView ? 'text-muted-foreground/65 hover:text-muted-foreground' : 'font-medium text-foreground')}
14
14
  >
15
15
  {t('chatSidebarViewTime')}
16
16
  </button>
17
- <span className="text-gray-300">/</span>
17
+ <span className="text-muted-foreground/35">/</span>
18
18
  <button
19
19
  type="button"
20
20
  aria-pressed={isProjectFirstView}
21
21
  onClick={() => onSelectMode('project-first')}
22
- className={cn('transition-colors', isProjectFirstView ? 'font-medium text-gray-600' : 'text-gray-400 hover:text-gray-600')}
22
+ className={cn('transition-colors', isProjectFirstView ? 'font-medium text-foreground' : 'text-muted-foreground/65 hover:text-muted-foreground')}
23
23
  >
24
24
  {t('chatSidebarViewProject')}
25
25
  </button>
@@ -36,9 +36,10 @@ describe("ChatConversationHeader", () => {
36
36
  it("uses a stable desktop height before and after session materialization", () => {
37
37
  renderHeader();
38
38
 
39
- const header = screen.getByText("New Task").closest(".border-b");
39
+ const header = screen.getByTestId("chat-conversation-header");
40
40
 
41
41
  expect(header?.className).toContain("h-[52px]");
42
+ expect(header?.className).not.toContain("border-b");
42
43
  expect(header?.className).not.toContain("transition-all");
43
44
  });
44
45
 
@@ -58,9 +59,10 @@ describe("ChatConversationHeader", () => {
58
59
  });
59
60
 
60
61
  const moreActions = screen.getByRole("button", { name: "More actions" });
61
- const header = screen.getByText("First message").closest(".border-b");
62
+ const header = screen.getByTestId("chat-conversation-header");
62
63
 
63
64
  expect(header?.className).toContain("h-[52px]");
65
+ expect(header?.className).not.toContain("border-b");
64
66
  expect(moreActions.className).toContain("h-7");
65
67
  expect(moreActions.className).toContain("w-7");
66
68
  });
@@ -103,7 +103,7 @@ export function ChatConversationHeaderSection({
103
103
  }
104
104
  sessionTypeBadge={
105
105
  sessionTypeLabel ? (
106
- <span className="inline-flex shrink-0 items-center gap-1.5 rounded-full border border-gray-200 bg-gray-100 px-2 py-0.5 text-[11px] font-medium text-gray-600">
106
+ <span className="inline-flex shrink-0 items-center gap-1.5 rounded-full border border-border bg-muted px-2 py-0.5 text-[11px] font-medium text-muted-foreground">
107
107
  {sessionTypeOption?.icon?.src ? (
108
108
  <span className="inline-flex h-[1.125rem] w-[1.125rem] items-center justify-center">
109
109
  <SessionContextIconNode
@@ -16,11 +16,11 @@ export function ChatParentSessionBanner({
16
16
  }
17
17
  const trimmedLabel = parentSessionLabel.trim();
18
18
  return (
19
- <div className="border-b border-gray-200/60 bg-white/75 px-4 py-2 backdrop-blur-sm sm:px-5">
19
+ <div className="bg-background/75 px-4 py-2 backdrop-blur-sm sm:px-5">
20
20
  <button
21
21
  type="button"
22
22
  onClick={onGoToParentSession}
23
- className="inline-flex items-center gap-2 text-xs font-medium text-gray-600 transition-colors hover:text-gray-900"
23
+ className="inline-flex items-center gap-2 text-xs font-medium text-muted-foreground transition-colors hover:text-foreground"
24
24
  >
25
25
  <ArrowLeft className="h-3.5 w-3.5" />
26
26
  <span>
@@ -55,10 +55,11 @@ export function ChatConversationHeader({
55
55
 
56
56
  return (
57
57
  <div
58
+ data-testid="chat-conversation-header"
58
59
  className={cn(
59
- "border-b border-gray-200/60 bg-white/80 backdrop-blur-sm flex items-center justify-between shrink-0 overflow-hidden transition-colors duration-200",
60
+ "bg-background/80 backdrop-blur-sm flex items-center justify-between shrink-0 overflow-hidden transition-colors duration-200",
60
61
  isMobileLayout ? "px-3 sm:px-3" : "px-4 sm:px-5",
61
- shouldShow ? "opacity-100" : "h-0 py-0 opacity-0 border-b-0",
62
+ shouldShow ? "opacity-100" : "h-0 py-0 opacity-0",
62
63
  shouldShow && (isMobileLayout ? "min-h-12 pb-2 pt-2" : "h-[52px]"),
63
64
  )}
64
65
  style={
@@ -73,11 +74,11 @@ export function ChatConversationHeader({
73
74
  icon={<ArrowLeft className="h-4 w-4" />}
74
75
  label={t("chat")}
75
76
  onClick={onBackToList}
76
- className="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-gray-600 transition-colors hover:bg-gray-100 hover:text-gray-900"
77
+ className="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground"
77
78
  />
78
79
  ) : null}
79
80
  {leading}
80
- <span className="text-sm font-medium text-gray-700 truncate">
81
+ <span className="text-sm font-medium text-foreground truncate">
81
82
  {title}
82
83
  </span>
83
84
  {sessionTypeBadge}
@@ -34,7 +34,7 @@ export function ChatConversationPanel({
34
34
  }
35
35
 
36
36
  return (
37
- <section className="flex-1 min-h-0 flex overflow-hidden bg-gradient-to-b from-gray-50/60 to-white">
37
+ <section className="flex-1 min-h-0 flex overflow-hidden bg-background">
38
38
  <div className="flex min-h-0 flex-1 flex-col overflow-hidden">
39
39
  <ChatConversationParentBanner />
40
40
  <ChatConversationHeaderSection
@@ -28,13 +28,13 @@ export function ChatConversationSkeleton() {
28
28
  return (
29
29
  <section
30
30
  data-testid="chat-conversation-skeleton"
31
- className="flex-1 min-h-0 flex flex-col overflow-hidden bg-gradient-to-b from-gray-50/60 to-white"
31
+ className="flex-1 min-h-0 flex flex-col overflow-hidden bg-background"
32
32
  >
33
33
  <div className="flex-1 min-h-0 overflow-y-auto custom-scrollbar">
34
34
  <div className="mx-auto flex min-h-full w-full max-w-[min(1120px,100%)] flex-col px-6 py-5">
35
35
  <div className="flex flex-1 flex-col gap-8">
36
36
  <div className="space-y-6">
37
- <Skeleton className="h-6 w-52 rounded-lg bg-gray-200/90" />
37
+ <Skeleton className="h-6 w-52 rounded-lg bg-muted" />
38
38
  <div className="space-y-5">
39
39
  {CHAT_CONVERSATION_SKELETON_BUBBLES.map((bubble) => (
40
40
  <div
@@ -44,7 +44,7 @@ export function ChatConversationSkeleton() {
44
44
  <Skeleton
45
45
  data-testid="chat-conversation-skeleton-bubble"
46
46
  className={cn(
47
- "w-full bg-gray-200/80",
47
+ "w-full bg-muted",
48
48
  bubble.bubbleClassName,
49
49
  )}
50
50
  />
@@ -54,29 +54,29 @@ export function ChatConversationSkeleton() {
54
54
  </div>
55
55
  <div className="mt-auto grid gap-4 pb-2 sm:grid-cols-[minmax(0,1fr)_minmax(180px,240px)] sm:items-end">
56
56
  <div className="space-y-3">
57
- <Skeleton className="h-4 w-40 rounded-full bg-gray-200/70" />
58
- <Skeleton className="h-[112px] w-full rounded-[30px] bg-gray-200/70" />
57
+ <Skeleton className="h-4 w-40 rounded-full bg-muted" />
58
+ <Skeleton className="h-[112px] w-full rounded-[30px] bg-muted" />
59
59
  </div>
60
60
  <div className="hidden justify-end sm:flex">
61
- <Skeleton className="h-10 w-36 rounded-full bg-gray-200/75" />
61
+ <Skeleton className="h-10 w-36 rounded-full bg-muted" />
62
62
  </div>
63
63
  </div>
64
64
  </div>
65
65
  </div>
66
66
  </div>
67
- <div className="border-t border-gray-200/80 bg-white p-4">
67
+ <div className="bg-background p-4">
68
68
  <div className="mx-auto w-full max-w-[min(1120px,100%)]">
69
- <div className="overflow-hidden rounded-2xl border border-gray-200 bg-white shadow-card">
69
+ <div className="overflow-hidden rounded-2xl border border-border bg-card shadow-card">
70
70
  <div className="px-4 py-2.5">
71
- <Skeleton className="h-[84px] w-full rounded-[28px] bg-gray-200/80" />
71
+ <Skeleton className="h-[84px] w-full rounded-[28px] bg-muted" />
72
72
  </div>
73
73
  <div className="flex items-center justify-between gap-3 px-3 pb-3">
74
74
  <div className="flex items-center gap-2">
75
- <Skeleton className="h-8 w-20 rounded-full bg-gray-200/75" />
76
- <Skeleton className="h-8 w-28 rounded-full bg-gray-200/75" />
77
- <Skeleton className="hidden h-8 w-24 rounded-full bg-gray-200/70 sm:block" />
75
+ <Skeleton className="h-8 w-20 rounded-full bg-muted" />
76
+ <Skeleton className="h-8 w-28 rounded-full bg-muted" />
77
+ <Skeleton className="hidden h-8 w-24 rounded-full bg-muted sm:block" />
78
78
  </div>
79
- <Skeleton className="h-8 w-8 rounded-full bg-gray-200/85" />
79
+ <Skeleton className="h-8 w-8 rounded-full bg-muted" />
80
80
  </div>
81
81
  </div>
82
82
  </div>