@xenide-io/the-old-ui-theme 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/README.md +9 -10
  2. package/dist/{Chip-Cq3AiAji.d.mts → Chip-BzuNgJIa.d.mts} +81 -23
  3. package/dist/{Chip-Cq3AiAji.d.ts → Chip-BzuNgJIa.d.ts} +81 -23
  4. package/dist/{ai-message-blocknote-WABTHFY7.mjs → ai-message-blocknote-D4Z6DUCJ.mjs} +9 -3
  5. package/dist/chunk-2EO5VCXP.mjs +3912 -0
  6. package/dist/chunk-APKRZQRO.mjs +251 -0
  7. package/dist/chunk-BS7BZI5W.mjs +19 -0
  8. package/dist/chunk-IULORI3A.mjs +8 -0
  9. package/dist/index.d.mts +3 -3
  10. package/dist/index.d.ts +3 -3
  11. package/dist/index.js +997 -576
  12. package/dist/index.mjs +49 -45
  13. package/dist/suite.d.mts +157 -55
  14. package/dist/suite.d.ts +157 -55
  15. package/dist/suite.js +4249 -801
  16. package/dist/suite.mjs +2578 -594
  17. package/dist/theme-boot-P-oqKVZF.d.mts +74 -0
  18. package/dist/theme-boot-P-oqKVZF.d.ts +74 -0
  19. package/dist/theme-boot.d.mts +2 -0
  20. package/dist/theme-boot.d.ts +2 -0
  21. package/dist/theme-boot.js +44 -0
  22. package/dist/theme-boot.mjs +8 -0
  23. package/dist/ui.d.mts +5 -29
  24. package/dist/ui.d.ts +5 -29
  25. package/dist/ui.js +647 -352
  26. package/dist/ui.mjs +10 -12
  27. package/docs/README.md +34 -0
  28. package/docs/ai-quick-reference.md +56 -0
  29. package/docs/component-library-improvement-plan.md +751 -0
  30. package/docs/component-reference.md +81 -0
  31. package/docs/components.md +48 -0
  32. package/docs/demos.md +19 -0
  33. package/docs/installation.md +117 -0
  34. package/docs/suite-audit.md +34 -0
  35. package/docs/theme-token-reference.md +67 -0
  36. package/docs/themes.md +164 -0
  37. package/package.json +22 -21
  38. package/public/fonts/OpenRunde-Bold.woff2 +0 -0
  39. package/public/fonts/OpenRunde-Medium.woff2 +0 -0
  40. package/public/fonts/OpenRunde-Regular.woff2 +0 -0
  41. package/public/fonts/OpenRunde-Semibold.woff2 +0 -0
  42. package/scripts/package-smoke.mjs +43 -0
  43. package/src/app/globals.css +2 -1
  44. package/src/components/ui/Accordion.tsx +20 -6
  45. package/src/components/ui/Avatar.tsx +5 -3
  46. package/src/components/ui/Calendar.tsx +187 -63
  47. package/src/components/ui/Card.test.tsx +38 -0
  48. package/src/components/ui/Card.tsx +77 -14
  49. package/src/components/ui/CollapsibleSection.tsx +12 -4
  50. package/src/components/ui/CommandPalette.test.tsx +91 -4
  51. package/src/components/ui/CommandPalette.tsx +138 -128
  52. package/src/components/ui/EmptyState.tsx +2 -2
  53. package/src/components/ui/FormField.tsx +1 -1
  54. package/src/components/ui/Input.tsx +42 -18
  55. package/src/components/ui/Kbd.tsx +18 -3
  56. package/src/components/ui/Modal.tsx +3 -1
  57. package/src/components/ui/Progress.tsx +14 -5
  58. package/src/components/ui/SegmentedControl.tsx +2 -2
  59. package/src/components/ui/SettingsLayout.tsx +1 -1
  60. package/src/components/ui/Stat.tsx +3 -2
  61. package/src/components/ui/Table.tsx +8 -3
  62. package/src/components/ui/Tooltip.test.tsx +70 -1
  63. package/src/components/ui/Tooltip.tsx +53 -29
  64. package/src/components/ui/Typography.tsx +103 -49
  65. package/src/components/ui/avatar-stat.test.tsx +23 -0
  66. package/src/components/ui/calendar.test.tsx +88 -0
  67. package/src/components/ui/disclosure.test.tsx +39 -0
  68. package/src/components/ui/index.ts +44 -6
  69. package/src/components/ui/progress.test.tsx +15 -0
  70. package/src/components/ui/typography.test.tsx +26 -1
  71. package/src/styles/suite-skin.css +8 -2
  72. package/src/styles/themes.css +184 -68
  73. package/src/suite/components/ai-message-blocknote.tsx +13 -2
  74. package/src/suite/components/ai-panel.tsx +41 -10
  75. package/src/suite/components/app-switcher.test.tsx +21 -6
  76. package/src/suite/components/app-switcher.tsx +7 -11
  77. package/src/suite/components/suite-app-layout.tsx +12 -3
  78. package/src/suite/components/suite-bottom-nav.tsx +0 -1
  79. package/src/suite/components/suite-clients-projects-directory.test.tsx +71 -0
  80. package/src/suite/components/suite-clients-projects-directory.tsx +943 -0
  81. package/src/suite/components/suite-integration-picker.test.tsx +224 -0
  82. package/src/suite/components/suite-integration-picker.tsx +939 -0
  83. package/src/suite/components/suite-integration-rules.test.tsx +157 -0
  84. package/src/suite/components/suite-integration-rules.tsx +471 -0
  85. package/src/suite/components/suite-mobile-drawer.test.tsx +18 -2
  86. package/src/suite/components/suite-mobile-drawer.tsx +65 -98
  87. package/src/suite/components/suite-notification-bell.tsx +29 -4
  88. package/src/suite/components/suite-sidebar.tsx +25 -25
  89. package/src/suite/components/suite-skeleton.tsx +2 -2
  90. package/src/suite/components/suite-user-menu.tsx +9 -8
  91. package/src/suite/components/theme-provider.test.tsx +87 -3
  92. package/src/suite/components/theme-provider.tsx +144 -23
  93. package/src/suite/components/today-ui.tsx +79 -68
  94. package/src/suite/components/workspace-switcher.test.tsx +56 -0
  95. package/src/suite/components/workspace-switcher.tsx +3 -3
  96. package/src/suite/icons/app-accents.ts +12 -12
  97. package/src/suite/icons/glyphs.ts +6 -12
  98. package/src/suite/index.ts +27 -0
  99. package/src/suite/lib/apps.test.ts +9 -1
  100. package/src/suite/lib/apps.ts +14 -8
  101. package/src/suite/lib/cookies.ts +53 -0
  102. package/src/suite/lib/theme-boot.ts +32 -0
  103. package/src/suite/lib/theme-cookie.ts +7 -0
  104. package/src/suite/lib/use-sidebar-width.ts +5 -51
  105. package/dist/chunk-KDR6HI6F.mjs +0 -1075
  106. package/dist/chunk-NOI42JNZ.mjs +0 -151
  107. package/dist/chunk-VXISSXTB.mjs +0 -2564
  108. package/src/suite/lib/use-lock-mobile-page-zoom.test.tsx +0 -65
  109. package/src/suite/lib/use-lock-mobile-page-zoom.ts +0 -51
package/dist/suite.mjs CHANGED
@@ -1,12 +1,31 @@
1
1
  import {
2
+ Alert,
3
+ Badge,
4
+ Button,
5
+ Card,
2
6
  DropdownItem,
3
7
  DropdownMenu,
4
- Tooltip
5
- } from "./chunk-KDR6HI6F.mjs";
8
+ FileUpload,
9
+ Input,
10
+ Modal,
11
+ Select,
12
+ Toggle,
13
+ Tooltip,
14
+ cn
15
+ } from "./chunk-2EO5VCXP.mjs";
16
+ import {
17
+ suiteThemeBootScript
18
+ } from "./chunk-BS7BZI5W.mjs";
6
19
  import {
7
20
  SuiteThemeProvider,
8
- useSuiteTheme
9
- } from "./chunk-NOI42JNZ.mjs";
21
+ clearCookie,
22
+ readCookie,
23
+ useSuiteTheme,
24
+ writeCookie
25
+ } from "./chunk-APKRZQRO.mjs";
26
+ import {
27
+ SUITE_THEME_COOKIE
28
+ } from "./chunk-IULORI3A.mjs";
10
29
  import {
11
30
  __spreadProps,
12
31
  __spreadValues
@@ -56,7 +75,7 @@ import { Refresh as RefreshCw } from "iconoir-react";
56
75
  // src/suite/lib/cn.ts
57
76
  import { clsx } from "clsx";
58
77
  import { twMerge } from "tailwind-merge";
59
- function cn(...inputs) {
78
+ function cn2(...inputs) {
60
79
  return twMerge(clsx(inputs));
61
80
  }
62
81
 
@@ -85,10 +104,10 @@ var APP_ACCENTS = {
85
104
  },
86
105
  shellstack: {
87
106
  label: "ShellStack",
88
- accent: "#5e5893",
89
- tile: "#5e5893",
90
- onTile: "#ffffff",
91
- onTileAccent: "#c4a7e7"
107
+ accent: "#0078D4",
108
+ tile: "#FFFFFF",
109
+ onTile: "#111114",
110
+ onTileAccent: "#0078D4"
92
111
  },
93
112
  crew: {
94
113
  label: "Crew",
@@ -97,12 +116,12 @@ var APP_ACCENTS = {
97
116
  onTile: "#ffffff",
98
117
  onTileAccent: "#a5f3fc"
99
118
  },
100
- nakama: {
101
- label: "Nakama",
102
- accent: "#b8eb44",
103
- tile: "#17101f",
104
- onTile: "#fff2e2",
105
- onTileAccent: "#f54b87"
119
+ shelly: {
120
+ label: "Shelly",
121
+ accent: "#0078D4",
122
+ tile: "#1B1B1F",
123
+ onTile: "#ECECF1",
124
+ onTileAccent: "#00BCF2"
106
125
  }
107
126
  };
108
127
  var APP_GLYPHS = {
@@ -111,7 +130,7 @@ var APP_GLYPHS = {
111
130
  kraken: "squid-doc",
112
131
  shellstack: "stack-hex",
113
132
  crew: "crew-bot",
114
- nakama: "nakama-fist"
133
+ shelly: "shelly-snail"
115
134
  };
116
135
 
117
136
  // src/suite/icons/glyph-parts.tsx
@@ -234,22 +253,15 @@ var SUITE_GLYPHS = {
234
253
  { kind: "path", d: "M9.6 14.6q2.4 1.7 4.8 0", accent: true }
235
254
  ]
236
255
  },
237
- "nakama-fist": {
238
- description: "Nakama \u2014 raised fist with neon crew signal lines",
256
+ "shelly-snail": {
257
+ description: "Shelly \u2014 smiling snail with spiral shell and ball-tipped antennae",
239
258
  elements: [
240
259
  {
241
260
  kind: "path",
242
- d: "M192 0c17.7 0 32 14.3 32 32v112h-64V32c0-17.7 14.3-32 32-32zM64 64c0-17.7-32-32 32-32s32 14.3 32 32v80H64V64zm192 0c0-17.7 14.3-32 32-32s32 14.3 32 32v96c0 17.7-14.3 32-32 32s-32-14.3-32-32V64zm96 64c0-17.7 14.3-32 32-32s32 14.3 32 32v64c0 17.7-14.3 32-32 32s-32-14.3-32-32v-64zm-96 88v-.6c9.4 5.4 20.3 8.6 32 8.6 13.2 0 25.4-4 35.6-10.8 8.7 24.9 32.5 42.8 60.4 42.8 11.7 0 22.6-3.1 32-8.6v8.6c0 52.3-25.1 98.8-64 128v96c0 17.7-14.3 32-32 32H160c-17.7 0-32-14.3-32-32v-78.4c-17.3-7.9-33.2-18.8-46.9-32.5L69.5 357.5C45.5 333.5 32 300.9 32 267v-27c0-35.3 28.7-64 64-64h88c22.1 0 40 17.9 40 40s-17.9 40-40 40h-56c-8.8 0-16 7.2-16 16s7.2 16 16 16h56c39.8 0 72-32.2 72-72z",
261
+ d: "M2931 37263 c-1542 -737 -1730 -2870 -339 -3838 427 -297 339 1 1730 -5802 102 -425 101 -430 -391 -950 -1003 -1062 -1175 -1507 -1834 -4748 -1525 -7505 -1398 -10142 668 -13875 2061 -3724 4835 -5715 9185 -6592 2869 -579 4928 -582 8750 -15 1293 192 3408 506 4700 697 6839 1012 8768 1422 9385 1993 1103 1021 425 2357 -1733 3414 l-944 462 916 620 c5469 3705 5358 13657 -209 18536 -2592 2272 -5133 3185 -8865 3185 -3361 0 -5965 -948 -8226 -2994 -501 -453 -824 -546 -824 -235 0 70 301 1416 668 2991 668 2863 668 2863 1053 3101 1156 713 1317 2506 305 3395 -1583 1390 -3787 234 -3592 -1885 61 -673 61 -673 -1165 -3013 l-1227 -2340 -1303 -10 -1303 -10 -1267 2463 c-1202 2337 -1261 2480 -1155 2784 610 1750 -1309 3465 -2983 2666z m1743 -1216 c309 -354 379 -713 232 -1191 -205 -669 -183 -731 1300 -3583 1821 -3503 1488 -3127 2631 -2970 816 112 1053 109 1729 -25 587 -117 813 -127 901 -42 64 63 778 1394 1586 2958 1470 2844 1470 2844 1345 3365 -208 868 106 1458 852 1598 1380 258 1829 -1605 545 -2260 -501 -255 -427 -36 -1292 -3813 l-725 -3166 513 -617 c1210 -1453 1328 -2014 1709 -8068 224 -3562 368 -4603 790 -5688 820 -2113 2775 -3739 5643 -4695 2847 -948 5589 -1186 7567 -654 l850 228 1070 -471 c2352 -1034 2946 -1824 1719 -2288 -1707 -647 -14950 -2665 -17489 -2665 -5500 0 -9506 1872 -11922 5573 -2564 3926 -2753 6473 -1075 14490 542 2586 754 3104 1682 4102 778 837 757 677 322 2415 -188 754 -529 2180 -757 3170 -228 990 -436 1878 -463 1973 -27 95 -246 260 -486 366 -685 303 -961 1115 -610 1795 335 647 1332 736 1833 163z m21523 -6801 c6385 -1036 10732 -7090 9753 -13583 -628 -4167 -2948 -6812 -6688 -7626 -6108 -1329 -10963 4878 -8256 10556 1608 3373 6202 4320 8566 1766 2055 -2219 1699 -6037 -662 -7096 -2082 -935 -4058 98 -4184 2187 -93 1553 1143 2685 2287 2093 607 -313 709 -1340 148 -1481 -564 -142 -462 -962 120 -962 1033 2 1610 1420 1015 2496 -814 1471 -2971 1452 -3972 -37 -1601 -2380 159 -5650 3046 -5658 2778 -8 4680 2269 4503 5390 -265 4668 -5206 7028 -9332 4457 -3911 -2438 -4439 -8515 -1057 -12167 l561 -607 -647 327 c-2556 1290 -3718 2796 -4088 5301 -61 411 -201 2166 -311 3898 -312 4898 -436 5802 -952 6962 l-261 588 532 493 c1419 1314 3729 2427 5782 2786 639 112 3218 59 4097 -83z M5574 23846 c-476 -475 -431 -1229 97 -1644 835 -658 1687 739 970 1590 -326 388 -715 407 -1067 54z M12075 23992 c-669 -390 -584 -1598 134 -1896 608 -252 1135 289 1057 1085 -72 728 -654 1124 -1191 811z M7801 22451 c-626 -754 1585 -1648 2460 -995 485 362 676 688 546 932 -155 288 -335 267 -719 -84 -549 -502 -1237 -469 -1728 82 -224 251 -389 271 -559 65z",
243
262
  filled: true,
244
- transform: "translate(2.5 1.75) scale(.0425 .0375)"
245
- },
246
- { kind: "path", d: "M7 18h3.5M12.2 18h3M8.5 19.5h6", accent: true },
247
- {
248
- kind: "path",
249
- d: "M4.8 5.8h2.7M4.8 7.4h1.4M18.5 17.1h1.7",
250
- accent: true
251
- },
252
- { kind: "circle", cx: 18.5, cy: 4.5, r: 0.8, accent: true, filled: true }
263
+ transform: "translate(0.88 22.8) scale(0.0005714 -0.0005714)"
264
+ }
253
265
  ]
254
266
  },
255
267
  workspace: {
@@ -363,7 +375,7 @@ function SuiteAppIcon({
363
375
  width: px,
364
376
  height: px,
365
377
  viewBox: "0 0 24 24",
366
- className: cn("shrink-0", className),
378
+ className: cn2("shrink-0", className),
367
379
  style,
368
380
  role: label ? "img" : void 0,
369
381
  "aria-label": label,
@@ -391,104 +403,55 @@ function SuiteAppIcon({
391
403
  );
392
404
  }
393
405
 
394
- // src/suite/icons/suite-icon.tsx
395
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
396
- var TODAY_SUN_STYLE = `
397
- @media (prefers-reduced-motion: no-preference) {
398
- .suite-icon-today-sun-rays {
399
- animation: suite-icon-today-sun-spin 18s linear infinite;
400
- transform-box: fill-box;
401
- transform-origin: center;
402
- }
403
- }
404
- @keyframes suite-icon-today-sun-spin {
405
- to { transform: rotate(360deg); }
406
- }
407
- `;
408
- function SuiteIcon({
409
- name,
410
- size = 24,
411
- accent,
412
- strokeWidth = 2,
413
- animated = true,
414
- label,
415
- className,
416
- style
417
- }) {
418
- const glyph = SUITE_GLYPHS[name];
419
- const accentHex = accent ? APP_ACCENTS[accent].accent : void 0;
420
- const mergedStyle = accentHex ? __spreadProps(__spreadValues({}, style), { "--suite-icon-accent": accentHex }) : style;
421
- return /* @__PURE__ */ jsxs4(
422
- "svg",
423
- {
424
- width: size,
425
- height: size,
426
- viewBox: "0 0 24 24",
427
- fill: "none",
428
- stroke: "currentColor",
429
- strokeWidth,
430
- strokeLinecap: "round",
431
- strokeLinejoin: "round",
432
- className: cn("shrink-0", className),
433
- style: mergedStyle,
434
- role: label ? "img" : void 0,
435
- "aria-label": label,
436
- "aria-hidden": label ? void 0 : true,
437
- children: [
438
- glyph.animatedAccent && animated ? /* @__PURE__ */ jsx4("style", { children: TODAY_SUN_STYLE }) : null,
439
- /* @__PURE__ */ jsx4(
440
- GlyphParts,
441
- {
442
- elements: glyph.elements,
443
- accentClassName: glyph.animatedAccent && animated ? "suite-icon-today-sun-rays" : void 0
444
- }
445
- )
446
- ]
447
- }
448
- );
449
- }
450
-
451
406
  // src/suite/components/today-ui.tsx
452
- import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
407
+ import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
453
408
  var APP_META = {
454
409
  shellstack: { name: "ShellStack" },
455
410
  tides: { name: "Tides" },
456
411
  turtletime: { name: "TurtleTime" },
457
- kraken: { name: "Kraken" }
412
+ kraken: { name: "Kraken" },
413
+ shelly: { name: "Shelly" }
458
414
  };
459
415
  var SUITE_APPS = [
460
416
  "shellstack",
461
417
  "tides",
462
418
  "turtletime",
463
- "kraken"
419
+ "kraken",
420
+ "shelly"
464
421
  ];
465
422
  function sourceToSuiteApp(source) {
466
- if (source === "tides" || source === "turtletime" || source === "kraken") {
467
- return source;
423
+ const normalised = source.trim().toLowerCase();
424
+ if (normalised === "tides" || normalised === "turtletime" || normalised === "kraken" || normalised === "shelly") {
425
+ return normalised;
468
426
  }
469
427
  return "shellstack";
470
428
  }
471
429
  function suiteAppLabel(source) {
472
430
  return APP_META[sourceToSuiteApp(source)].name;
473
431
  }
474
- var SOURCE_APP_GLYPH = {
475
- shellstack: "stack-hex",
476
- tides: "kanban-wave",
477
- turtletime: "timer-shell",
478
- kraken: "squid-doc"
432
+ var SOURCE_APP_LOGOS = {
433
+ shellstack: "/icon-shellstack.svg",
434
+ tides: "/tides-icon.svg",
435
+ turtletime: "/turtletime-icon.svg",
436
+ kraken: "/kraken-icon.svg",
437
+ shelly: "/shelly-icon.svg"
479
438
  };
480
439
  function SourceAppGlyph({
481
440
  source,
482
441
  className
483
442
  }) {
484
443
  const app = sourceToSuiteApp(source);
485
- return /* @__PURE__ */ jsx5(
486
- SuiteIcon,
487
- {
488
- name: SOURCE_APP_GLYPH[app],
489
- accent: app,
490
- className: cn("h-4 w-4 shrink-0 text-ph-subtle", className)
491
- }
444
+ return (
445
+ // These assets are copied into each product's public directory.
446
+ // eslint-disable-next-line @next/next/no-img-element
447
+ /* @__PURE__ */ jsx4(
448
+ "img",
449
+ {
450
+ src: SOURCE_APP_LOGOS[app],
451
+ alt: "",
452
+ className: cn2("h-7 w-7 shrink-0 rounded-lg object-contain", className)
453
+ }
454
+ )
492
455
  );
493
456
  }
494
457
  function formatLongDate(date = /* @__PURE__ */ new Date()) {
@@ -501,23 +464,23 @@ function SuiteAppStrip({
501
464
  className,
502
465
  icons
503
466
  }) {
504
- return /* @__PURE__ */ jsx5(
467
+ return /* @__PURE__ */ jsx4(
505
468
  "div",
506
469
  {
507
- className: cn(
470
+ className: cn2(
508
471
  "flex flex-wrap items-center justify-center gap-2.5",
509
472
  className
510
473
  ),
511
474
  "aria-label": "ShellStack suite apps",
512
475
  children: SUITE_APPS.map((app) => {
513
476
  var _a;
514
- return /* @__PURE__ */ jsxs5(
477
+ return /* @__PURE__ */ jsxs4(
515
478
  "div",
516
479
  {
517
480
  className: "flex items-center gap-2 rounded-full border border-ph-border bg-ph-surface px-2.5 py-1.5 shadow-sm",
518
481
  children: [
519
- (_a = icons == null ? void 0 : icons[app]) != null ? _a : /* @__PURE__ */ jsx5(SuiteAppIcon, { app, size: "sm" }),
520
- /* @__PURE__ */ jsx5("span", { className: "text-xs font-medium text-ph-subtle", children: APP_META[app].name })
482
+ (_a = icons == null ? void 0 : icons[app]) != null ? _a : /* @__PURE__ */ jsx4(SuiteAppIcon, { app, size: "sm" }),
483
+ /* @__PURE__ */ jsx4("span", { className: "text-xs font-medium text-ph-subtle", children: APP_META[app].name })
521
484
  ]
522
485
  },
523
486
  app
@@ -527,7 +490,7 @@ function SuiteAppStrip({
527
490
  );
528
491
  }
529
492
  function AnimatedSun({ className }) {
530
- return /* @__PURE__ */ jsxs5(
493
+ return /* @__PURE__ */ jsxs4(
531
494
  "svg",
532
495
  {
533
496
  width: "40",
@@ -535,14 +498,14 @@ function AnimatedSun({ className }) {
535
498
  viewBox: "0 0 40 40",
536
499
  fill: "none",
537
500
  xmlns: "http://www.w3.org/2000/svg",
538
- className: cn(className),
501
+ className: cn2(className),
539
502
  "aria-hidden": "true",
540
503
  children: [
541
- /* @__PURE__ */ jsx5("defs", { children: /* @__PURE__ */ jsxs5("linearGradient", { id: "animatedSunCenter", x1: "0", y1: "0", x2: "40", y2: "40", children: [
542
- /* @__PURE__ */ jsx5("stop", { stopColor: "#f59e0b" }),
543
- /* @__PURE__ */ jsx5("stop", { offset: "1", stopColor: "#fb923c" })
504
+ /* @__PURE__ */ jsx4("defs", { children: /* @__PURE__ */ jsxs4("linearGradient", { id: "animatedSunCenter", x1: "0", y1: "0", x2: "40", y2: "40", children: [
505
+ /* @__PURE__ */ jsx4("stop", { stopColor: "#f59e0b" }),
506
+ /* @__PURE__ */ jsx4("stop", { offset: "1", stopColor: "#fb923c" })
544
507
  ] }) }),
545
- /* @__PURE__ */ jsx5("g", { className: "origin-center opacity-80 motion-safe:animate-[pulse_8s_ease-in-out_infinite] motion-reduce:animate-none", children: [0, 45, 90, 135, 180, 225, 270, 315].map((angle) => /* @__PURE__ */ jsx5(
508
+ /* @__PURE__ */ jsx4("g", { className: "origin-center opacity-80 motion-safe:animate-[pulse_8s_ease-in-out_infinite] motion-reduce:animate-none", children: [0, 45, 90, 135, 180, 225, 270, 315].map((angle) => /* @__PURE__ */ jsx4(
546
509
  "line",
547
510
  {
548
511
  x1: "20",
@@ -556,13 +519,13 @@ function AnimatedSun({ className }) {
556
519
  },
557
520
  angle
558
521
  )) }),
559
- /* @__PURE__ */ jsx5("circle", { cx: "20", cy: "20", r: "9", fill: "url(#animatedSunCenter)" })
522
+ /* @__PURE__ */ jsx4("circle", { cx: "20", cy: "20", r: "9", fill: "url(#animatedSunCenter)" })
560
523
  ]
561
524
  }
562
525
  );
563
526
  }
564
527
  function AnimatedMoon({ className }) {
565
- return /* @__PURE__ */ jsxs5(
528
+ return /* @__PURE__ */ jsxs4(
566
529
  "svg",
567
530
  {
568
531
  width: "40",
@@ -570,23 +533,23 @@ function AnimatedMoon({ className }) {
570
533
  viewBox: "0 0 40 40",
571
534
  fill: "none",
572
535
  xmlns: "http://www.w3.org/2000/svg",
573
- className: cn(className),
536
+ className: cn2(className),
574
537
  "aria-hidden": "true",
575
538
  children: [
576
- /* @__PURE__ */ jsx5("defs", { children: /* @__PURE__ */ jsxs5("linearGradient", { id: "animatedMoonBody", x1: "0", y1: "0", x2: "40", y2: "40", children: [
577
- /* @__PURE__ */ jsx5("stop", { stopColor: "#a5b4fc" }),
578
- /* @__PURE__ */ jsx5("stop", { offset: "1", stopColor: "#818cf8" })
539
+ /* @__PURE__ */ jsx4("defs", { children: /* @__PURE__ */ jsxs4("linearGradient", { id: "animatedMoonBody", x1: "0", y1: "0", x2: "40", y2: "40", children: [
540
+ /* @__PURE__ */ jsx4("stop", { stopColor: "#a5b4fc" }),
541
+ /* @__PURE__ */ jsx4("stop", { offset: "1", stopColor: "#818cf8" })
579
542
  ] }) }),
580
- /* @__PURE__ */ jsx5(
543
+ /* @__PURE__ */ jsx4(
581
544
  "path",
582
545
  {
583
546
  d: "M27.5 25.5A11 11 0 1 1 14.5 9.6a9 9 0 1 0 13 15.9Z",
584
547
  fill: "url(#animatedMoonBody)"
585
548
  }
586
549
  ),
587
- /* @__PURE__ */ jsxs5("g", { className: "opacity-70 motion-safe:animate-[pulse_10s_ease-in-out_infinite] motion-reduce:animate-none", children: [
588
- /* @__PURE__ */ jsx5("circle", { cx: "29", cy: "10", r: "1.2", fill: "#c7d2fe" }),
589
- /* @__PURE__ */ jsx5("circle", { cx: "34", cy: "16", r: "0.9", fill: "#c7d2fe" })
550
+ /* @__PURE__ */ jsxs4("g", { className: "opacity-70 motion-safe:animate-[pulse_10s_ease-in-out_infinite] motion-reduce:animate-none", children: [
551
+ /* @__PURE__ */ jsx4("circle", { cx: "29", cy: "10", r: "1.2", fill: "#c7d2fe" }),
552
+ /* @__PURE__ */ jsx4("circle", { cx: "34", cy: "16", r: "0.9", fill: "#c7d2fe" })
590
553
  ] })
591
554
  ]
592
555
  }
@@ -595,7 +558,7 @@ function AnimatedMoon({ className }) {
595
558
  function TodayTimeIcon({ className }) {
596
559
  const hour = (/* @__PURE__ */ new Date()).getHours();
597
560
  const isNight = hour >= 18 || hour < 6;
598
- return isNight ? /* @__PURE__ */ jsx5(AnimatedMoon, { className }) : /* @__PURE__ */ jsx5(AnimatedSun, { className });
561
+ return isNight ? /* @__PURE__ */ jsx4(AnimatedMoon, { className }) : /* @__PURE__ */ jsx4(AnimatedSun, { className });
599
562
  }
600
563
  function TodayTopBar({
601
564
  refreshing,
@@ -604,17 +567,17 @@ function TodayTopBar({
604
567
  appIcon,
605
568
  appName
606
569
  }) {
607
- const icon = appIcon != null ? appIcon : /* @__PURE__ */ jsx5(TodayTimeIcon, { className: "h-6 w-6 sm:h-7 sm:w-7 text-amber-500" });
608
- return /* @__PURE__ */ jsxs5("header", { className: "flex items-center justify-between gap-4", children: [
609
- /* @__PURE__ */ jsxs5("div", { className: "flex min-w-0 items-center gap-3", children: [
610
- /* @__PURE__ */ jsx5("div", { className: "hidden shrink-0 sm:block", "aria-hidden": "true", children: icon }),
611
- /* @__PURE__ */ jsxs5("div", { className: "flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1", children: [
612
- /* @__PURE__ */ jsx5("h1", { className: "font-display text-[1.625rem] font-bold leading-tight tracking-tight text-ph-ink sm:text-[2.25rem]", children: "Today" }),
613
- appName ? /* @__PURE__ */ jsx5("span", { className: "rounded-md bg-ph-muted px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wide text-ph-subtle", children: appName }) : null,
614
- /* @__PURE__ */ jsx5("span", { className: "text-sm text-ph-subtle", children: formatLongDate() })
570
+ const icon = appIcon != null ? appIcon : /* @__PURE__ */ jsx4(TodayTimeIcon, { className: "h-6 w-6 sm:h-7 sm:w-7 text-amber-500" });
571
+ return /* @__PURE__ */ jsxs4("header", { className: "flex items-center justify-between gap-4", children: [
572
+ /* @__PURE__ */ jsxs4("div", { className: "flex min-w-0 items-center gap-3", children: [
573
+ /* @__PURE__ */ jsx4("div", { className: "hidden shrink-0 sm:block", "aria-hidden": "true", children: icon }),
574
+ /* @__PURE__ */ jsxs4("div", { className: "flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1", children: [
575
+ /* @__PURE__ */ jsx4("h1", { className: "font-display text-[1.625rem] font-bold leading-tight tracking-tight text-ph-ink sm:text-[2.25rem]", children: "Today" }),
576
+ appName ? /* @__PURE__ */ jsx4("span", { className: "rounded-md bg-ph-muted px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wide text-ph-subtle", children: appName }) : null,
577
+ /* @__PURE__ */ jsx4("span", { className: "text-sm text-ph-subtle", children: formatLongDate() })
615
578
  ] })
616
579
  ] }),
617
- /* @__PURE__ */ jsx5("div", { className: "flex shrink-0 items-center", children: /* @__PURE__ */ jsx5(
580
+ /* @__PURE__ */ jsx4("div", { className: "flex shrink-0 items-center", children: /* @__PURE__ */ jsx4(
618
581
  "button",
619
582
  {
620
583
  type: "button",
@@ -623,10 +586,10 @@ function TodayTopBar({
623
586
  className: "press-subtle inline-flex h-10 w-10 items-center justify-center rounded-lg text-ph-subtle transition hover:bg-ph-surface hover:text-ph-ink disabled:opacity-50",
624
587
  "data-test": "today-refresh",
625
588
  "aria-label": "Refresh today",
626
- children: /* @__PURE__ */ jsx5(
589
+ children: /* @__PURE__ */ jsx4(
627
590
  RefreshCw,
628
591
  {
629
- className: cn("h-4 w-4", refreshing && "animate-spin"),
592
+ className: cn2("h-4 w-4", refreshing && "animate-spin"),
630
593
  "aria-hidden": true
631
594
  }
632
595
  )
@@ -666,8 +629,8 @@ function TodayHero({
666
629
  brief,
667
630
  briefMeta
668
631
  }) {
669
- return /* @__PURE__ */ jsxs5("div", { className: "mt-4 sm:mt-6", children: [
670
- /* @__PURE__ */ jsx5(
632
+ return /* @__PURE__ */ jsxs4("div", { className: "mt-4 sm:mt-6", children: [
633
+ /* @__PURE__ */ jsx4(
671
634
  "p",
672
635
  {
673
636
  className: "today-hero max-w-2xl font-display text-lg font-semibold tracking-tight text-ph-ink sm:text-xl sm:leading-snug",
@@ -675,9 +638,9 @@ function TodayHero({
675
638
  },
676
639
  typeof message === "string" ? message : "hero"
677
640
  ),
678
- brief ? /* @__PURE__ */ jsxs5("div", { className: "mt-4 max-w-2xl", "data-test": "today-focus-brief", children: [
679
- /* @__PURE__ */ jsx5("p", { className: "text-[15px] leading-[1.65] text-ph-ink", children: brief }),
680
- briefMeta ? /* @__PURE__ */ jsx5("p", { className: "mt-1.5 text-xs text-ph-mutedtext", children: briefMeta }) : null
641
+ brief ? /* @__PURE__ */ jsxs4("div", { className: "mt-4 max-w-2xl", "data-test": "today-focus-brief", children: [
642
+ /* @__PURE__ */ jsx4("p", { className: "text-[15px] leading-[1.65] text-ph-ink", children: brief }),
643
+ briefMeta ? /* @__PURE__ */ jsx4("p", { className: "mt-1.5 text-xs text-ph-mutedtext", children: briefMeta }) : null
681
644
  ] }) : null
682
645
  ] });
683
646
  }
@@ -693,20 +656,20 @@ function TodayPrimaryAction({
693
656
  className,
694
657
  dataTest = "today-primary-action"
695
658
  }) {
696
- const classes = cn(
659
+ const classes = cn2(
697
660
  "today-primary-action group relative flex w-full max-w-md items-center gap-3 overflow-hidden rounded-xl px-3.5 py-2.5 text-left transition sm:px-4 sm:py-3",
698
661
  `today-primary-action--${accent}`,
699
662
  active && "today-primary-action--active",
700
663
  loading && "pointer-events-none opacity-70",
701
664
  className
702
665
  );
703
- const body = /* @__PURE__ */ jsxs5(Fragment2, { children: [
704
- /* @__PURE__ */ jsx5("span", { className: "today-primary-action__icon inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-lg sm:h-10 sm:w-10", children: icon }),
705
- /* @__PURE__ */ jsxs5("span", { className: "min-w-0 flex-1", children: [
706
- /* @__PURE__ */ jsx5("span", { className: "block text-sm font-semibold tracking-tight sm:text-base", children: label }),
707
- description ? /* @__PURE__ */ jsx5("span", { className: "mt-0.5 block text-xs opacity-80 sm:text-sm", children: description }) : null
666
+ const body = /* @__PURE__ */ jsxs4(Fragment2, { children: [
667
+ /* @__PURE__ */ jsx4("span", { className: "today-primary-action__icon inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-lg sm:h-10 sm:w-10", children: icon }),
668
+ /* @__PURE__ */ jsxs4("span", { className: "min-w-0 flex-1", children: [
669
+ /* @__PURE__ */ jsx4("span", { className: "block text-sm font-semibold tracking-tight sm:text-base", children: label }),
670
+ description ? /* @__PURE__ */ jsx4("span", { className: "mt-0.5 block text-xs opacity-80 sm:text-sm", children: description }) : null
708
671
  ] }),
709
- /* @__PURE__ */ jsx5(
672
+ /* @__PURE__ */ jsx4(
710
673
  "span",
711
674
  {
712
675
  className: "today-primary-action__chevron shrink-0 text-base opacity-60 transition group-hover:translate-x-0.5 group-hover:opacity-100",
@@ -716,7 +679,7 @@ function TodayPrimaryAction({
716
679
  )
717
680
  ] });
718
681
  if (href && !onClick) {
719
- return /* @__PURE__ */ jsx5(
682
+ return /* @__PURE__ */ jsx4(
720
683
  "a",
721
684
  {
722
685
  href,
@@ -727,7 +690,7 @@ function TodayPrimaryAction({
727
690
  }
728
691
  );
729
692
  }
730
- return /* @__PURE__ */ jsx5(
693
+ return /* @__PURE__ */ jsx4(
731
694
  "button",
732
695
  {
733
696
  type: "button",
@@ -743,33 +706,33 @@ function TodayPrimaryAction({
743
706
  function TodayEmptyAction({
744
707
  title,
745
708
  description,
746
- actionLabel,
709
+ actionLabel: actionLabel2,
747
710
  href,
748
711
  onClick,
749
712
  dataTest
750
713
  }) {
751
- return /* @__PURE__ */ jsxs5(
714
+ return /* @__PURE__ */ jsxs4(
752
715
  "div",
753
716
  {
754
717
  className: "rounded-lg border border-dashed border-ph-border/80 bg-ph-muted/30 px-4 py-4 text-center",
755
718
  "data-test": dataTest,
756
719
  children: [
757
- /* @__PURE__ */ jsx5("p", { className: "text-sm font-semibold text-ph-ink", children: title }),
758
- description ? /* @__PURE__ */ jsx5("p", { className: "mx-auto mt-1 max-w-sm text-xs leading-relaxed text-ph-subtle sm:text-sm", children: description }) : null,
759
- actionLabel && (href || onClick) ? href ? /* @__PURE__ */ jsx5(
720
+ /* @__PURE__ */ jsx4("p", { className: "text-sm font-semibold text-ph-ink", children: title }),
721
+ description ? /* @__PURE__ */ jsx4("p", { className: "mx-auto mt-1 max-w-sm text-xs leading-relaxed text-ph-subtle sm:text-sm", children: description }) : null,
722
+ actionLabel2 && (href || onClick) ? href ? /* @__PURE__ */ jsx4(
760
723
  "a",
761
724
  {
762
725
  href,
763
726
  className: "mt-2.5 inline-flex text-sm font-semibold text-ph-brand hover:underline",
764
- children: actionLabel
727
+ children: actionLabel2
765
728
  }
766
- ) : /* @__PURE__ */ jsx5(
729
+ ) : /* @__PURE__ */ jsx4(
767
730
  "button",
768
731
  {
769
732
  type: "button",
770
733
  onClick,
771
734
  className: "mt-2.5 inline-flex text-sm font-semibold text-ph-brand hover:underline",
772
- children: actionLabel
735
+ children: actionLabel2
773
736
  }
774
737
  ) : null
775
738
  ]
@@ -782,16 +745,16 @@ function TodayLayout({
782
745
  aside,
783
746
  className
784
747
  }) {
785
- return /* @__PURE__ */ jsxs5(
748
+ return /* @__PURE__ */ jsxs4(
786
749
  "div",
787
750
  {
788
- className: cn("mt-5 space-y-6 sm:mt-6", className),
751
+ className: cn2("mt-5 space-y-6 sm:mt-6", className),
789
752
  "data-test": "today-layout",
790
753
  children: [
791
- primary ? /* @__PURE__ */ jsx5("div", { className: "max-w-md", children: primary }) : null,
792
- /* @__PURE__ */ jsxs5("div", { className: "grid gap-6 lg:grid-cols-[minmax(0,1fr)_minmax(16rem,20rem)] lg:items-start lg:gap-8", children: [
793
- /* @__PURE__ */ jsx5("div", { className: "min-w-0 space-y-8", children: main }),
794
- aside ? /* @__PURE__ */ jsx5("aside", { className: "space-y-3 lg:sticky lg:top-6 lg:self-start", children: aside }) : null
754
+ primary ? /* @__PURE__ */ jsx4("div", { className: "max-w-md", children: primary }) : null,
755
+ /* @__PURE__ */ jsxs4("div", { className: "grid gap-6 lg:grid-cols-[minmax(0,1fr)_minmax(16rem,20rem)] lg:items-start lg:gap-8", children: [
756
+ /* @__PURE__ */ jsx4("div", { className: "min-w-0 space-y-8", children: main }),
757
+ aside ? /* @__PURE__ */ jsx4("aside", { className: "space-y-3 lg:sticky lg:top-6 lg:self-start", children: aside }) : null
795
758
  ] })
796
759
  ]
797
760
  }
@@ -805,22 +768,30 @@ function TodayAskAiCard({
805
768
  onClick,
806
769
  href
807
770
  }) {
808
- const classes = cn(
771
+ const classes = cn2(
809
772
  "group flex w-full items-start gap-3.5 rounded-2xl border border-ph-border/70 bg-ph-surface px-4 py-3.5 text-left shadow-[0_1px_12px_-8px_rgba(15,23,42,0.1)] transition hover:border-ph-brand/35 hover:bg-[color-mix(in_oklab,var(--ph-accent)_6%,var(--ph-surface))] sm:px-5",
810
773
  className
811
774
  );
812
- const body = /* @__PURE__ */ jsxs5(Fragment2, { children: [
813
- /* @__PURE__ */ jsx5("span", { className: "inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-2xl bg-ph-brand/15 text-ph-brand shadow-sm ring-1 ring-black/[0.06]", children: /* @__PURE__ */ jsx5(SuiteIcon, { name: "stack-hex", accent: "shellstack", className: "h-5 w-5" }) }),
814
- /* @__PURE__ */ jsxs5("span", { className: "min-w-0 flex-1", children: [
815
- /* @__PURE__ */ jsxs5("span", { className: "flex flex-wrap items-baseline justify-between gap-x-3 gap-y-1", children: [
816
- /* @__PURE__ */ jsx5("span", { className: "font-display text-sm font-bold tracking-tight text-ph-ink", children: title }),
817
- /* @__PURE__ */ jsx5("span", { className: "text-sm font-medium text-ph-brand transition group-hover:underline", children: cta })
775
+ const body = /* @__PURE__ */ jsxs4(Fragment2, { children: [
776
+ /* @__PURE__ */ jsx4(
777
+ "img",
778
+ {
779
+ src: "/shelly-icon.svg",
780
+ alt: "",
781
+ "aria-hidden": true,
782
+ className: "h-5 w-5 shrink-0 object-contain"
783
+ }
784
+ ),
785
+ /* @__PURE__ */ jsxs4("span", { className: "min-w-0 flex-1", children: [
786
+ /* @__PURE__ */ jsxs4("span", { className: "flex flex-wrap items-baseline justify-between gap-x-3 gap-y-1", children: [
787
+ /* @__PURE__ */ jsx4("span", { className: "font-display text-sm font-bold tracking-tight text-ph-ink", children: title }),
788
+ /* @__PURE__ */ jsx4("span", { className: "text-sm font-medium text-ph-brand transition group-hover:underline", children: cta })
818
789
  ] }),
819
- /* @__PURE__ */ jsx5("span", { className: "mt-1 block text-sm leading-relaxed text-ph-subtle", children: description })
790
+ /* @__PURE__ */ jsx4("span", { className: "mt-1 block text-sm leading-relaxed text-ph-subtle", children: description })
820
791
  ] })
821
792
  ] });
822
793
  if (onClick) {
823
- return /* @__PURE__ */ jsx5(
794
+ return /* @__PURE__ */ jsx4(
824
795
  "button",
825
796
  {
826
797
  type: "button",
@@ -832,9 +803,9 @@ function TodayAskAiCard({
832
803
  );
833
804
  }
834
805
  if (href) {
835
- return /* @__PURE__ */ jsx5("a", { href, className: classes, "data-test": "today-ask-ai", children: body });
806
+ return /* @__PURE__ */ jsx4("a", { href, className: classes, "data-test": "today-ask-ai", children: body });
836
807
  }
837
- return /* @__PURE__ */ jsx5("div", { className: classes, "data-test": "today-ask-ai", children: body });
808
+ return /* @__PURE__ */ jsx4("div", { className: classes, "data-test": "today-ask-ai", children: body });
838
809
  }
839
810
  function TodaySection({
840
811
  icon: Icon,
@@ -845,22 +816,22 @@ function TodaySection({
845
816
  testId,
846
817
  children
847
818
  }) {
848
- return /* @__PURE__ */ jsxs5("section", { "data-test": testId, className: "space-y-5", children: [
849
- /* @__PURE__ */ jsxs5("div", { className: "flex items-start justify-between gap-4", children: [
850
- /* @__PURE__ */ jsxs5("div", { className: "flex min-w-0 items-start gap-3.5", children: [
851
- /* @__PURE__ */ jsx5(
819
+ return /* @__PURE__ */ jsxs4("section", { "data-test": testId, className: "space-y-5", children: [
820
+ /* @__PURE__ */ jsxs4("div", { className: "flex items-start justify-between gap-4", children: [
821
+ /* @__PURE__ */ jsxs4("div", { className: "flex min-w-0 items-start gap-3.5", children: [
822
+ /* @__PURE__ */ jsx4(
852
823
  "span",
853
824
  {
854
- className: cn(
825
+ className: cn2(
855
826
  "inline-flex h-10 w-10 sm:h-11 sm:w-11 shrink-0 items-center justify-center rounded-2xl shadow-sm ring-1 ring-black/[0.06]",
856
827
  iconClassName != null ? iconClassName : "bg-ph-muted text-ph-ink"
857
828
  ),
858
- children: /* @__PURE__ */ jsx5(Icon, { className: "h-5 w-5", "aria-hidden": true })
829
+ children: /* @__PURE__ */ jsx4(Icon, { className: "h-5 w-5", "aria-hidden": true })
859
830
  }
860
831
  ),
861
- /* @__PURE__ */ jsxs5("div", { className: "min-w-0 pt-0.5", children: [
862
- /* @__PURE__ */ jsx5("h2", { className: "font-display text-lg font-bold tracking-tight text-ph-ink", children: title }),
863
- description ? /* @__PURE__ */ jsx5("p", { className: "mt-1 max-w-xl text-sm leading-relaxed text-ph-subtle", children: description }) : null
832
+ /* @__PURE__ */ jsxs4("div", { className: "min-w-0 pt-0.5", children: [
833
+ /* @__PURE__ */ jsx4("h2", { className: "font-display text-lg font-bold tracking-tight text-ph-ink", children: title }),
834
+ description ? /* @__PURE__ */ jsx4("p", { className: "mt-1 max-w-xl text-sm leading-relaxed text-ph-subtle", children: description }) : null
864
835
  ] })
865
836
  ] }),
866
837
  action
@@ -872,10 +843,10 @@ function TodayPanel({
872
843
  children,
873
844
  className
874
845
  }) {
875
- return /* @__PURE__ */ jsx5(
846
+ return /* @__PURE__ */ jsx4(
876
847
  "div",
877
848
  {
878
- className: cn(
849
+ className: cn2(
879
850
  "border-ph-border/70 rounded-2xl border bg-ph-surface p-5 shadow-[0_1px_16px_-8px_rgba(15,23,42,0.12)] sm:p-5",
880
851
  className
881
852
  ),
@@ -887,41 +858,38 @@ function TodayEmptyState({
887
858
  title,
888
859
  description
889
860
  }) {
890
- return /* @__PURE__ */ jsxs5("div", { className: "border-ph-border/80 rounded-xl border border-dashed px-5 py-8 text-center", children: [
891
- /* @__PURE__ */ jsx5("p", { className: "text-sm font-semibold text-ph-ink", children: title }),
892
- description ? /* @__PURE__ */ jsx5("p", { className: "mt-1.5 text-sm leading-relaxed text-ph-subtle", children: description }) : null
861
+ return /* @__PURE__ */ jsxs4("div", { className: "border-ph-border/80 rounded-xl border border-dashed px-5 py-8 text-center", children: [
862
+ /* @__PURE__ */ jsx4("p", { className: "text-sm font-semibold text-ph-ink", children: title }),
863
+ description ? /* @__PURE__ */ jsx4("p", { className: "mt-1.5 text-sm leading-relaxed text-ph-subtle", children: description }) : null
893
864
  ] });
894
865
  }
895
866
 
896
867
  // src/suite/components/app-switcher.tsx
897
868
  import Image from "next/image";
898
869
  import { useState } from "react";
899
- import {
900
- NavArrowDown as ChevronDown,
901
- OpenNewWindow
902
- } from "iconoir-react";
903
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
870
+ import { NavArrowDown as ChevronDown, OpenNewWindow } from "iconoir-react";
871
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
904
872
  function appSwitcherTriggerClass(open, collapsed = false) {
905
- return cn(
873
+ return cn2(
906
874
  "group flex min-w-0 items-center gap-2 rounded-lg border px-2 py-1.5 text-left transition-all duration-200",
907
875
  collapsed ? "h-11 w-11 justify-center px-0 py-0" : "w-full",
908
876
  open ? "border-ph-brand/30 bg-ph-muted shadow-[0_1px_2px_rgba(0,0,0,0.06)] ring-1 ring-ph-brand/15" : "border-transparent hover:border-ph-border hover:bg-ph-muted/80 hover:shadow-sm"
909
877
  );
910
878
  }
911
879
  function appSwitcherMarkClass() {
912
- return "h-8 w-8 shrink-0 rounded-lg shadow-[0_1px_2px_rgba(0,0,0,0.1),0_4px_12px_rgba(0,0,0,0.08)] ring-1 ring-black/[0.06]";
880
+ return "h-8 w-8 shrink-0 rounded-lg";
913
881
  }
914
882
  function appSwitcherMenuItemClass() {
915
- return "rounded-lg px-2 py-2 data-[highlighted]:bg-transparent hover:bg-ph-muted/80";
883
+ return "rounded-lg px-2 py-2 data-[highlighted]:bg-transparent hover:bg-ph-muted/80 focus-visible:shadow-none";
916
884
  }
917
885
  function AppSwitcherMark({
918
886
  children,
919
887
  collapsed
920
888
  }) {
921
- return /* @__PURE__ */ jsx6(
889
+ return /* @__PURE__ */ jsx5(
922
890
  "span",
923
891
  {
924
- className: cn(
892
+ className: cn2(
925
893
  "relative shrink-0",
926
894
  collapsed && "group-hover:scale-[1.02]"
927
895
  ),
@@ -934,18 +902,18 @@ function AppSwitcherChevron({
934
902
  collapsed = false
935
903
  }) {
936
904
  if (collapsed) {
937
- return /* @__PURE__ */ jsx6(
905
+ return /* @__PURE__ */ jsx5(
938
906
  "span",
939
907
  {
940
- className: cn(
908
+ className: cn2(
941
909
  "absolute bottom-0 right-0 flex h-3 w-3 items-center justify-center rounded-full border border-ph-border bg-ph-surface shadow-sm transition-colors",
942
910
  open && "border-ph-brand/40 bg-ph-brand/10"
943
911
  ),
944
912
  "aria-hidden": true,
945
- children: /* @__PURE__ */ jsx6(
913
+ children: /* @__PURE__ */ jsx5(
946
914
  ChevronDown,
947
915
  {
948
- className: cn(
916
+ className: cn2(
949
917
  "h-2 w-2 text-ph-mutedtext transition-transform duration-200",
950
918
  open && "rotate-180 text-ph-brand"
951
919
  )
@@ -954,18 +922,18 @@ function AppSwitcherChevron({
954
922
  }
955
923
  );
956
924
  }
957
- return /* @__PURE__ */ jsx6(
925
+ return /* @__PURE__ */ jsx5(
958
926
  "span",
959
927
  {
960
- className: cn(
928
+ className: cn2(
961
929
  "border-ph-border/80 flex h-5 w-5 shrink-0 items-center justify-center rounded-lg border bg-ph-canvas shadow-sm transition-all duration-200",
962
930
  open ? "border-ph-brand/35 bg-ph-brand/10 text-ph-brand" : "text-ph-mutedtext group-hover:border-ph-border group-hover:bg-ph-surface"
963
931
  ),
964
932
  "aria-hidden": true,
965
- children: /* @__PURE__ */ jsx6(
933
+ children: /* @__PURE__ */ jsx5(
966
934
  ChevronDown,
967
935
  {
968
- className: cn(
936
+ className: cn2(
969
937
  "h-3 w-3 transition-transform duration-200",
970
938
  open && "rotate-180"
971
939
  )
@@ -987,7 +955,7 @@ function AppSwitcher({
987
955
  triggerDataTest
988
956
  }) {
989
957
  const [open, setOpen] = useState(false);
990
- return /* @__PURE__ */ jsx6(
958
+ return /* @__PURE__ */ jsx5(
991
959
  DropdownMenu2,
992
960
  {
993
961
  "aria-label": "Switch application",
@@ -998,26 +966,25 @@ function AppSwitcher({
998
966
  align: "start",
999
967
  open,
1000
968
  onOpenChange: setOpen,
1001
- trigger: /* @__PURE__ */ jsxs6(
969
+ trigger: /* @__PURE__ */ jsxs5(
1002
970
  "span",
1003
971
  {
1004
972
  className: appSwitcherTriggerClass(open, collapsed),
1005
973
  "data-test": "app-switcher-trigger",
1006
- "aria-expanded": open,
1007
974
  children: [
1008
- /* @__PURE__ */ jsxs6(AppSwitcherMark, { collapsed, children: [
975
+ /* @__PURE__ */ jsxs5(AppSwitcherMark, { collapsed, children: [
1009
976
  mark,
1010
- collapsed ? /* @__PURE__ */ jsx6(AppSwitcherChevron, { open, collapsed: true }) : null
977
+ collapsed ? /* @__PURE__ */ jsx5(AppSwitcherChevron, { open, collapsed: true }) : null
1011
978
  ] }),
1012
979
  !collapsed ? title : null,
1013
- !collapsed ? /* @__PURE__ */ jsx6(AppSwitcherChevron, { open }) : null
980
+ !collapsed ? /* @__PURE__ */ jsx5(AppSwitcherChevron, { open }) : null
1014
981
  ]
1015
982
  }
1016
983
  ),
1017
- children: /* @__PURE__ */ jsxs6("div", { id: "app-switcher-menu", className: "p-1", "data-test": "app-switcher-menu", children: [
1018
- /* @__PURE__ */ jsx6("p", { className: "px-3 py-2 text-[10px] font-semibold uppercase tracking-[0.14em] text-ph-mutedtext", children: "Switch application" }),
1019
- apps.filter((app) => app.slug !== currentApp).map((app) => /* @__PURE__ */ jsxs6("div", { className: "relative", children: [
1020
- /* @__PURE__ */ jsx6(
984
+ children: /* @__PURE__ */ jsxs5("div", { id: "app-switcher-menu", className: "p-1", "data-test": "app-switcher-menu", children: [
985
+ /* @__PURE__ */ jsx5("p", { className: "px-3 py-2 text-[10px] font-semibold uppercase tracking-[0.14em] text-ph-mutedtext", children: "Switch application" }),
986
+ apps.filter((app) => app.slug !== currentApp).map((app) => /* @__PURE__ */ jsxs5("div", { className: "relative", children: [
987
+ /* @__PURE__ */ jsx5(
1021
988
  DropdownItem2,
1022
989
  {
1023
990
  id: `switch-app-${app.slug}`,
@@ -1027,9 +994,9 @@ function AppSwitcher({
1027
994
  setOpen(false);
1028
995
  onSelect(app);
1029
996
  },
1030
- className: cn(appSwitcherMenuItemClass(), "pr-11"),
1031
- children: /* @__PURE__ */ jsxs6("span", { className: "flex min-w-0 items-center gap-3", children: [
1032
- /* @__PURE__ */ jsx6(
997
+ className: cn2(appSwitcherMenuItemClass(), "pr-11"),
998
+ children: /* @__PURE__ */ jsxs5("span", { className: "flex min-w-0 items-center gap-3", children: [
999
+ /* @__PURE__ */ jsx5(
1033
1000
  Image,
1034
1001
  {
1035
1002
  src: app.icon,
@@ -1039,17 +1006,16 @@ function AppSwitcher({
1039
1006
  className: "h-7 w-7 shrink-0 rounded-md object-contain"
1040
1007
  }
1041
1008
  ),
1042
- /* @__PURE__ */ jsxs6("span", { className: "min-w-0 flex-1", children: [
1043
- /* @__PURE__ */ jsx6("span", { className: "block truncate text-sm font-medium text-ph-ink", children: app.name }),
1044
- /* @__PURE__ */ jsx6("span", { className: "block truncate text-xs text-ph-mutedtext", children: app.description })
1009
+ /* @__PURE__ */ jsxs5("span", { className: "min-w-0 flex-1", children: [
1010
+ /* @__PURE__ */ jsx5("span", { className: "block truncate text-sm font-medium text-ph-ink", children: app.name }),
1011
+ /* @__PURE__ */ jsx5("span", { className: "block truncate text-xs text-ph-mutedtext", children: app.description })
1045
1012
  ] })
1046
1013
  ] })
1047
1014
  }
1048
1015
  ),
1049
- /* @__PURE__ */ jsx6(
1050
- "button",
1016
+ /* @__PURE__ */ jsx5(
1017
+ DropdownItem2,
1051
1018
  {
1052
- type: "button",
1053
1019
  id: `switch-app-${app.slug}-new-tab`,
1054
1020
  "data-test": `switch-app-${app.slug}-new-tab`,
1055
1021
  "aria-label": `Open ${app.name} in a new tab`,
@@ -1058,8 +1024,9 @@ function AppSwitcher({
1058
1024
  setOpen(false);
1059
1025
  onSelect(app, { newTab: true });
1060
1026
  },
1061
- className: "absolute right-1.5 top-1/2 z-[1] flex h-8 w-8 -translate-y-1/2 items-center justify-center rounded-md text-ph-mutedtext transition-colors hover:bg-ph-muted hover:text-ph-ink focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-ph-brand/35",
1062
- children: /* @__PURE__ */ jsx6(OpenNewWindow, { className: "h-4 w-4", "aria-hidden": "true" })
1027
+ className: "absolute right-1.5 top-1/2 z-[1] flex h-8 -translate-y-1/2 justify-center rounded-md p-0 text-ph-mutedtext transition-colors hover:bg-ph-muted hover:text-ph-ink focus-visible:shadow-none focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-ph-brand/35",
1028
+ style: { width: "2rem" },
1029
+ children: /* @__PURE__ */ jsx5(OpenNewWindow, { className: "h-4 w-4", "aria-hidden": "true" })
1063
1030
  }
1064
1031
  )
1065
1032
  ] }, app.slug))
@@ -1081,7 +1048,7 @@ var SUITE_APPS2 = [
1081
1048
  description: "Organisation and billing",
1082
1049
  icon: "/icon-shellstack.svg",
1083
1050
  landing: "/home",
1084
- baseUrlEnv: "NEXT_PUBLIC_SHELLSTACK_URL",
1051
+ baseUrlEnv: "NEXT_PUBLIC_PORTAL_URL",
1085
1052
  baseUrlFallback: "http://localhost:3002"
1086
1053
  },
1087
1054
  {
@@ -1112,12 +1079,12 @@ var SUITE_APPS2 = [
1112
1079
  baseUrlFallback: "http://localhost:3003"
1113
1080
  },
1114
1081
  {
1115
- slug: "nakama",
1116
- name: "Nakama",
1082
+ slug: "shelly",
1083
+ name: "Shelly",
1117
1084
  description: "AI teammates",
1118
- icon: "/nakama-icon.svg",
1085
+ icon: "/shelly-icon.svg",
1119
1086
  landing: "/today",
1120
- baseUrlEnv: "NEXT_PUBLIC_NAKAMA_URL",
1087
+ baseUrlEnv: "NEXT_PUBLIC_SHELLY_URL",
1121
1088
  baseUrlFallback: "http://localhost:3004"
1122
1089
  }
1123
1090
  ];
@@ -1131,16 +1098,20 @@ var SOURCE_APP_SLUG = {
1131
1098
  turtletime: "turtletime",
1132
1099
  tides: "tides",
1133
1100
  kraken: "kraken",
1134
- nakama: "nakama",
1101
+ shelly: "shelly",
1135
1102
  portal: "shellstack",
1136
1103
  shellstack: "shellstack"
1137
1104
  };
1105
+ function suiteAppSlugForNotificationSource(sourceApp) {
1106
+ var _a;
1107
+ return (_a = SOURCE_APP_SLUG[(sourceApp || "").toLowerCase()]) != null ? _a : null;
1108
+ }
1138
1109
  function resolveSuiteNotificationHref(href, sourceApp) {
1139
1110
  const value = (href || "").trim();
1140
1111
  if (!value) return "";
1141
1112
  if (/^(https?:|mailto:|\/\/)/i.test(value)) return value;
1142
1113
  const path = value.startsWith("/") ? value : `/${value}`;
1143
- const slug = SOURCE_APP_SLUG[(sourceApp || "").toLowerCase()];
1114
+ const slug = suiteAppSlugForNotificationSource(sourceApp);
1144
1115
  if (!slug) return path;
1145
1116
  return `${suiteAppBaseUrl(slug)}${path}`;
1146
1117
  }
@@ -1171,7 +1142,7 @@ function classifySuiteHref(href, bases, currentOrigin = "") {
1171
1142
  }
1172
1143
 
1173
1144
  // src/suite/components/suite-notification-bell.tsx
1174
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1145
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1175
1146
  var POLL_MS = 6e4;
1176
1147
  function timeAgo(iso) {
1177
1148
  const then = new Date(iso).getTime();
@@ -1267,6 +1238,28 @@ function SuiteNotificationBell({
1267
1238
  const target = resolveSuiteNotificationHref(n.href, n.source_app);
1268
1239
  if (!target) return;
1269
1240
  if (/^https?:\/\//i.test(target)) {
1241
+ try {
1242
+ const url = new URL(target);
1243
+ const sourceApp = suiteAppSlugForNotificationSource(n.source_app);
1244
+ const path = `${url.pathname}${url.search}${url.hash}`;
1245
+ if (url.origin === window.location.origin) {
1246
+ router.push(path);
1247
+ return;
1248
+ }
1249
+ if (sourceApp && sourceApp !== "shellstack") {
1250
+ const sourceOrigin = new URL(suiteAppBaseUrl(sourceApp)).origin;
1251
+ if (url.origin === sourceOrigin) {
1252
+ const launchUrl = new URL(
1253
+ `/launch/${sourceApp}`,
1254
+ suiteAppBaseUrl("shellstack")
1255
+ );
1256
+ launchUrl.searchParams.set("next", path);
1257
+ window.location.assign(launchUrl.toString());
1258
+ return;
1259
+ }
1260
+ }
1261
+ } catch (e) {
1262
+ }
1270
1263
  window.location.assign(target);
1271
1264
  return;
1272
1265
  }
@@ -1289,7 +1282,7 @@ function SuiteNotificationBell({
1289
1282
  } catch (e) {
1290
1283
  }
1291
1284
  }, [markAllRead]);
1292
- return /* @__PURE__ */ jsxs7(
1285
+ return /* @__PURE__ */ jsxs6(
1293
1286
  DropdownMenu2,
1294
1287
  {
1295
1288
  "aria-label": unread > 0 ? `Notifications, ${unread} unread` : "Notifications",
@@ -1299,14 +1292,14 @@ function SuiteNotificationBell({
1299
1292
  panelClassName: "w-80 overflow-hidden p-0",
1300
1293
  open,
1301
1294
  onOpenChange,
1302
- trigger: /* @__PURE__ */ jsx7("span", { className: "relative inline-flex h-11 w-11 items-center justify-center overflow-visible rounded-full text-ph-mutedtext transition hover:bg-ph-muted hover:text-ph-ink", children: /* @__PURE__ */ jsxs7("span", { className: "relative inline-flex h-5 w-5", children: [
1303
- /* @__PURE__ */ jsx7(Bell, { className: "h-5 w-5", strokeWidth: 1.75, "aria-hidden": true }),
1304
- unread > 0 ? /* @__PURE__ */ jsx7("span", { className: "pointer-events-none absolute -right-2 -top-2 z-[1] flex h-4 min-w-4 items-center justify-center rounded-full bg-ph-brand px-1 text-[9px] font-semibold leading-none text-white ring-2 ring-ph-surface", children: unread > 9 ? "9+" : unread }) : null
1295
+ trigger: /* @__PURE__ */ jsx6("span", { className: "relative inline-flex h-11 w-11 items-center justify-center overflow-visible rounded-full text-ph-mutedtext transition hover:bg-ph-muted hover:text-ph-ink", children: /* @__PURE__ */ jsxs6("span", { className: "relative inline-flex h-5 w-5", children: [
1296
+ /* @__PURE__ */ jsx6(Bell, { className: "h-5 w-5", strokeWidth: 1.75, "aria-hidden": true }),
1297
+ unread > 0 ? /* @__PURE__ */ jsx6("span", { className: "pointer-events-none absolute -right-2 -top-2 z-[1] flex h-4 min-w-4 items-center justify-center rounded-full bg-ph-brand px-1 text-[9px] font-semibold leading-none text-[var(--ph-on-accent)] ring-2 ring-ph-surface", children: unread > 9 ? "9+" : unread }) : null
1305
1298
  ] }) }),
1306
1299
  children: [
1307
- /* @__PURE__ */ jsxs7("div", { className: "flex items-center justify-between border-b border-ph-border px-3 py-2", children: [
1308
- /* @__PURE__ */ jsx7("span", { className: "text-sm font-semibold text-ph-ink", children: "Notifications" }),
1309
- unread > 0 ? /* @__PURE__ */ jsx7(
1300
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between border-b border-ph-border px-3 py-2", children: [
1301
+ /* @__PURE__ */ jsx6("span", { className: "text-sm font-semibold text-ph-ink", children: "Notifications" }),
1302
+ unread > 0 ? /* @__PURE__ */ jsx6(
1310
1303
  "button",
1311
1304
  {
1312
1305
  type: "button",
@@ -1318,27 +1311,26 @@ function SuiteNotificationBell({
1318
1311
  }
1319
1312
  ) : null
1320
1313
  ] }),
1321
- /* @__PURE__ */ jsx7("div", { className: "max-h-80 overflow-y-auto py-1", children: items.length === 0 ? /* @__PURE__ */ jsx7("p", { className: "px-3 py-6 text-center text-sm text-ph-mutedtext", children: "You're all caught up." }) : items.map((n) => /* @__PURE__ */ jsxs7(
1314
+ /* @__PURE__ */ jsx6("div", { className: "max-h-80 overflow-y-auto py-1", children: items.length === 0 ? /* @__PURE__ */ jsx6("p", { className: "px-3 py-6 text-center text-sm text-ph-mutedtext", children: "You're all caught up." }) : items.map((n) => /* @__PURE__ */ jsxs6(
1322
1315
  "button",
1323
1316
  {
1324
- type: "button",
1325
1317
  id: `${dataTest}-item-${n.id}`,
1326
1318
  "data-test": `${dataTest}-item-${n.id}`,
1327
1319
  onClick: () => void openItem(n),
1328
1320
  className: "flex w-full flex-col gap-0.5 px-3 py-2 text-left transition hover:bg-ph-muted",
1329
1321
  children: [
1330
- /* @__PURE__ */ jsxs7("span", { className: "flex items-center gap-2", children: [
1331
- !n.read_at ? /* @__PURE__ */ jsx7(
1322
+ /* @__PURE__ */ jsxs6("span", { className: "flex items-center gap-2", children: [
1323
+ !n.read_at ? /* @__PURE__ */ jsx6(
1332
1324
  "span",
1333
1325
  {
1334
1326
  className: "h-1.5 w-1.5 shrink-0 rounded-full bg-ph-brand",
1335
1327
  "aria-hidden": true
1336
1328
  }
1337
1329
  ) : null,
1338
- /* @__PURE__ */ jsx7("span", { className: "truncate text-sm font-medium text-ph-ink", children: n.title })
1330
+ /* @__PURE__ */ jsx6("span", { className: "truncate text-sm font-medium text-ph-ink", children: n.title })
1339
1331
  ] }),
1340
- n.body ? /* @__PURE__ */ jsx7("span", { className: "line-clamp-2 text-xs text-ph-mutedtext", children: n.body }) : null,
1341
- /* @__PURE__ */ jsxs7("span", { className: "text-[11px] uppercase tracking-wide text-ph-subtle", children: [
1332
+ n.body ? /* @__PURE__ */ jsx6("span", { className: "line-clamp-2 text-xs text-ph-mutedtext", children: n.body }) : null,
1333
+ /* @__PURE__ */ jsxs6("span", { className: "text-[11px] uppercase tracking-wide text-ph-subtle", children: [
1342
1334
  n.source_app,
1343
1335
  " \xB7 ",
1344
1336
  timeAgo(n.created_at)
@@ -1354,7 +1346,7 @@ function SuiteNotificationBell({
1354
1346
 
1355
1347
  // src/suite/components/command-palette-host.tsx
1356
1348
  import { useEffect as useEffect2, useState as useState3 } from "react";
1357
- import { jsx as jsx8 } from "react/jsx-runtime";
1349
+ import { jsx as jsx7 } from "react/jsx-runtime";
1358
1350
  function isEditableTarget() {
1359
1351
  if (typeof document === "undefined") return false;
1360
1352
  const el = document.activeElement;
@@ -1386,7 +1378,7 @@ function CommandPaletteHost({
1386
1378
  return () => window.removeEventListener("keydown", onKey);
1387
1379
  }, [open]);
1388
1380
  if (!isAuthenticated) return null;
1389
- return /* @__PURE__ */ jsx8(
1381
+ return /* @__PURE__ */ jsx7(
1390
1382
  CommandPalette,
1391
1383
  {
1392
1384
  items,
@@ -1420,17 +1412,18 @@ function useIdleMount(timeoutMs = 1200) {
1420
1412
  }
1421
1413
 
1422
1414
  // src/suite/components/deferred-chrome.tsx
1423
- import { Fragment as Fragment3, jsx as jsx9 } from "react/jsx-runtime";
1415
+ import { Fragment as Fragment3, jsx as jsx8 } from "react/jsx-runtime";
1424
1416
  function DeferredChrome({ children }) {
1425
1417
  const ready = useIdleMount();
1426
1418
  if (!ready) return null;
1427
- return /* @__PURE__ */ jsx9(Fragment3, { children });
1419
+ return /* @__PURE__ */ jsx8(Fragment3, { children });
1428
1420
  }
1429
1421
 
1430
1422
  // src/suite/components/suite-mobile-drawer.tsx
1431
- import { useEffect as useEffect4, useRef, useState as useState5 } from "react";
1423
+ import * as Dialog from "@radix-ui/react-dialog";
1424
+ import { useEffect as useEffect4, useState as useState5 } from "react";
1432
1425
  import { Xmark as X } from "iconoir-react";
1433
- import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
1426
+ import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
1434
1427
  function SuiteMobileDrawer({
1435
1428
  open,
1436
1429
  onClose,
@@ -1452,11 +1445,6 @@ function SuiteMobileDrawer({
1452
1445
  }) {
1453
1446
  const [rendered, setRendered] = useState5(open);
1454
1447
  const [shown, setShown] = useState5(open);
1455
- const panelRef = useRef(null);
1456
- const onCloseRef = useRef(onClose);
1457
- useEffect4(() => {
1458
- onCloseRef.current = onClose;
1459
- }, [onClose]);
1460
1448
  useEffect4(() => {
1461
1449
  if (open) {
1462
1450
  queueMicrotask(() => setRendered(true));
@@ -1473,86 +1461,61 @@ function SuiteMobileDrawer({
1473
1461
  const timeout = window.setTimeout(() => setRendered(false), durationMs);
1474
1462
  return () => window.clearTimeout(timeout);
1475
1463
  }, [open, durationMs]);
1476
- useEffect4(() => {
1477
- if (!open) return;
1478
- const onKeyDown = (event) => {
1479
- if (event.key === "Escape") onCloseRef.current();
1480
- };
1481
- window.addEventListener("keydown", onKeyDown);
1482
- const previousOverflow = document.body.style.overflow;
1483
- document.body.style.overflow = "hidden";
1484
- const previouslyFocused = document.activeElement instanceof HTMLElement ? document.activeElement : null;
1485
- const frame = requestAnimationFrame(() => {
1486
- var _a;
1487
- return (_a = panelRef.current) == null ? void 0 : _a.focus();
1488
- });
1489
- return () => {
1490
- window.removeEventListener("keydown", onKeyDown);
1491
- document.body.style.overflow = previousOverflow;
1492
- cancelAnimationFrame(frame);
1493
- if (previouslyFocused == null ? void 0 : previouslyFocused.isConnected) previouslyFocused.focus();
1494
- };
1495
- }, [open]);
1496
1464
  if (!rendered) return null;
1497
- return /* @__PURE__ */ jsxs8("div", { "data-test": dataTest, className: "no-print fixed inset-0 z-50 lg:hidden", children: [
1498
- /* @__PURE__ */ jsx10(
1499
- "button",
1465
+ return /* @__PURE__ */ jsx9(Dialog.Root, { open, onOpenChange: (nextOpen) => !nextOpen && onClose(), children: /* @__PURE__ */ jsxs7(Dialog.Portal, { forceMount: true, children: [
1466
+ /* @__PURE__ */ jsx9(
1467
+ Dialog.Overlay,
1500
1468
  {
1501
- type: "button",
1469
+ forceMount: true,
1502
1470
  id: backdropId,
1503
- "data-test": backdropDataTest,
1504
- tabIndex: -1,
1505
- className: cn(
1506
- "absolute inset-0 bg-black/25 backdrop-blur-sm motion-safe:transition-opacity motion-safe:ease-spring-subtle",
1471
+ "data-test": backdropDataTest != null ? backdropDataTest : dataTest,
1472
+ "aria-label": backdropLabel,
1473
+ className: cn2(
1474
+ "no-print fixed inset-0 z-50 bg-black/25 backdrop-blur-sm motion-safe:transition-opacity motion-safe:ease-spring-subtle lg:hidden",
1507
1475
  shown ? "opacity-100" : "opacity-0"
1508
1476
  ),
1509
- style: { transitionDuration: `${durationMs}ms` },
1510
- onClick: onClose,
1511
- "aria-label": backdropLabel
1477
+ style: { transitionDuration: `${durationMs}ms` }
1512
1478
  }
1513
1479
  ),
1514
- /* @__PURE__ */ jsxs8(
1480
+ /* @__PURE__ */ jsx9(Dialog.Content, { forceMount: true, asChild: true, children: /* @__PURE__ */ jsxs7(
1515
1481
  "aside",
1516
1482
  {
1517
- ref: panelRef,
1518
1483
  role: "dialog",
1519
- "aria-modal": "true",
1520
- "aria-label": dialogLabel,
1521
- tabIndex: -1,
1522
1484
  "data-test": panelDataTest,
1523
- className: cn(
1524
- "relative flex h-dvh max-h-dvh w-[86%] max-w-72 flex-col overflow-hidden bg-ph-surface shadow-xl outline-none motion-safe:transition-transform motion-safe:ease-spring-fast",
1525
- side === "right" && "ml-auto",
1485
+ "aria-modal": "true",
1486
+ className: cn2(
1487
+ "fixed inset-y-0 left-0 z-50 flex h-dvh max-h-dvh w-[86%] max-w-72 flex-col overflow-hidden bg-ph-surface shadow-xl outline-none motion-safe:transition-transform motion-safe:ease-spring-fast lg:hidden",
1488
+ side === "right" && "left-auto right-0",
1526
1489
  shown ? "translate-x-0" : side === "right" ? "translate-x-full" : "-translate-x-full",
1527
1490
  panelClassName
1528
1491
  ),
1529
1492
  style: { transitionDuration: `${durationMs}ms` },
1530
1493
  children: [
1531
- showCloseButton ? /* @__PURE__ */ jsxs8(
1494
+ /* @__PURE__ */ jsx9(Dialog.Title, { className: "sr-only", children: dialogLabel }),
1495
+ showCloseButton ? /* @__PURE__ */ jsxs7(
1532
1496
  "div",
1533
1497
  {
1534
- className: cn(
1498
+ className: cn2(
1535
1499
  "flex h-14 shrink-0 items-center border-b border-ph-border px-3",
1536
1500
  title ? "justify-between" : "justify-end"
1537
1501
  ),
1538
1502
  children: [
1539
- title ? /* @__PURE__ */ jsx10("span", { className: "truncate text-sm font-semibold text-ph-ink", children: title }) : null,
1540
- /* @__PURE__ */ jsx10(
1503
+ title ? /* @__PURE__ */ jsx9("span", { className: "truncate text-sm font-semibold text-ph-ink", children: title }) : null,
1504
+ /* @__PURE__ */ jsx9(Dialog.Close, { asChild: true, children: /* @__PURE__ */ jsx9(
1541
1505
  "button",
1542
1506
  {
1543
1507
  type: "button",
1544
1508
  id: closeButtonId,
1545
1509
  "data-test": closeButtonDataTest,
1546
- onClick: onClose,
1547
1510
  className: "-mr-1.5 inline-flex h-11 w-11 items-center justify-center rounded-lg text-ph-mutedtext transition-colors hover:bg-ph-muted hover:text-ph-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-brand",
1548
1511
  "aria-label": closeLabel,
1549
- children: /* @__PURE__ */ jsx10(X, { className: "h-4 w-4", "aria-hidden": true })
1512
+ children: /* @__PURE__ */ jsx9(X, { className: "h-4 w-4", "aria-hidden": true })
1550
1513
  }
1551
- )
1514
+ ) })
1552
1515
  ]
1553
1516
  }
1554
1517
  ) : null,
1555
- /* @__PURE__ */ jsx10(
1518
+ /* @__PURE__ */ jsx9(
1556
1519
  "div",
1557
1520
  {
1558
1521
  "data-test": "suite-mobile-drawer-body",
@@ -1562,13 +1525,13 @@ function SuiteMobileDrawer({
1562
1525
  )
1563
1526
  ]
1564
1527
  }
1565
- )
1566
- ] });
1528
+ ) })
1529
+ ] }) });
1567
1530
  }
1568
1531
 
1569
1532
  // src/suite/components/suite-mobile-header.tsx
1570
1533
  import { Menu } from "iconoir-react";
1571
- import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
1534
+ import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
1572
1535
  function SuiteMobileHeader({
1573
1536
  onMenuClick,
1574
1537
  menuIcon: MenuIcon = Menu,
@@ -1580,16 +1543,16 @@ function SuiteMobileHeader({
1580
1543
  dataTest,
1581
1544
  className
1582
1545
  }) {
1583
- return /* @__PURE__ */ jsxs9(
1546
+ return /* @__PURE__ */ jsxs8(
1584
1547
  "header",
1585
1548
  {
1586
1549
  "data-test": dataTest,
1587
- className: cn(
1550
+ className: cn2(
1588
1551
  "suite-app-bar no-print sticky top-0 z-30 flex min-h-[56px] shrink-0 items-center gap-1 border-b border-ph-border px-2 lg:hidden",
1589
1552
  className
1590
1553
  ),
1591
1554
  children: [
1592
- onMenuClick ? /* @__PURE__ */ jsx11(
1555
+ onMenuClick ? /* @__PURE__ */ jsx10(
1593
1556
  "button",
1594
1557
  {
1595
1558
  type: "button",
@@ -1598,20 +1561,20 @@ function SuiteMobileHeader({
1598
1561
  className: "suite-press inline-flex h-11 w-11 shrink-0 items-center justify-center rounded-xl text-ph-ink transition-colors hover:bg-ph-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-brand",
1599
1562
  onClick: onMenuClick,
1600
1563
  "aria-label": menuLabel,
1601
- children: /* @__PURE__ */ jsx11(MenuIcon, { className: "h-5 w-5", "aria-hidden": true })
1564
+ children: /* @__PURE__ */ jsx10(MenuIcon, { className: "h-5 w-5", "aria-hidden": true })
1602
1565
  }
1603
1566
  ) : null,
1604
- /* @__PURE__ */ jsx11(
1567
+ /* @__PURE__ */ jsx10(
1605
1568
  "div",
1606
1569
  {
1607
- className: cn(
1570
+ className: cn2(
1608
1571
  "flex min-w-0 flex-1 items-center",
1609
1572
  !onMenuClick && "pl-2"
1610
1573
  ),
1611
1574
  children: title
1612
1575
  }
1613
1576
  ),
1614
- actions ? /* @__PURE__ */ jsx11("div", { className: "flex shrink-0 items-center gap-1", children: actions }) : null
1577
+ actions ? /* @__PURE__ */ jsx10("div", { className: "flex shrink-0 items-center gap-1", children: actions }) : null
1615
1578
  ]
1616
1579
  }
1617
1580
  );
@@ -1620,26 +1583,26 @@ function SuiteMobileHeader({
1620
1583
  // src/suite/components/suite-layout.tsx
1621
1584
  import {
1622
1585
  useEffect as useEffect5,
1623
- useRef as useRef2,
1586
+ useRef,
1624
1587
  useState as useState6
1625
1588
  } from "react";
1626
- import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
1589
+ import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
1627
1590
  function SuiteBreadcrumbs({ items, className }) {
1628
- return /* @__PURE__ */ jsx12("nav", { "aria-label": "Breadcrumb", className, children: /* @__PURE__ */ jsx12("ol", { className: "flex min-w-0 items-center gap-1.5", children: items.map((item, index) => {
1591
+ return /* @__PURE__ */ jsx11("nav", { "aria-label": "Breadcrumb", className, children: /* @__PURE__ */ jsx11("ol", { className: "flex min-w-0 items-center gap-1.5", children: items.map((item, index) => {
1629
1592
  const isLast = index === items.length - 1;
1630
- return /* @__PURE__ */ jsxs10("li", { className: "flex min-w-0 items-center gap-1.5", children: [
1631
- index > 0 ? /* @__PURE__ */ jsx12("span", { className: "select-none text-ph-border", "aria-hidden": "true", children: "/" }) : null,
1632
- item.href && !isLast ? /* @__PURE__ */ jsx12(
1593
+ return /* @__PURE__ */ jsxs9("li", { className: "flex min-w-0 items-center gap-1.5", children: [
1594
+ index > 0 ? /* @__PURE__ */ jsx11("span", { className: "select-none text-ph-border", "aria-hidden": "true", children: "/" }) : null,
1595
+ item.href && !isLast ? /* @__PURE__ */ jsx11(
1633
1596
  "a",
1634
1597
  {
1635
1598
  href: item.href,
1636
1599
  className: "truncate transition hover:text-ph-ink",
1637
1600
  children: item.label
1638
1601
  }
1639
- ) : /* @__PURE__ */ jsx12(
1602
+ ) : /* @__PURE__ */ jsx11(
1640
1603
  "span",
1641
1604
  {
1642
- className: cn(
1605
+ className: cn2(
1643
1606
  "truncate",
1644
1607
  isLast ? "font-medium text-ph-ink" : "text-ph-subtle"
1645
1608
  ),
@@ -1661,7 +1624,7 @@ function SuitePage({
1661
1624
  role,
1662
1625
  "aria-live": ariaLive
1663
1626
  }) {
1664
- return /* @__PURE__ */ jsx12(
1627
+ return /* @__PURE__ */ jsx11(
1665
1628
  Component,
1666
1629
  {
1667
1630
  id,
@@ -1669,7 +1632,7 @@ function SuitePage({
1669
1632
  "data-width": width,
1670
1633
  role,
1671
1634
  "aria-live": ariaLive,
1672
- className: cn(
1635
+ className: cn2(
1673
1636
  "suite-page-stage relative flex w-full min-w-0 flex-col",
1674
1637
  inset && "suite-page-inset",
1675
1638
  className
@@ -1701,7 +1664,7 @@ function SuitePageHeader({
1701
1664
  */
1702
1665
  sticky = true
1703
1666
  }) {
1704
- const headerRef = useRef2(null);
1667
+ const headerRef = useRef(null);
1705
1668
  const [stuck, setStuck] = useState6(false);
1706
1669
  useEffect5(() => {
1707
1670
  if (!sticky) return;
@@ -1729,33 +1692,33 @@ function SuitePageHeader({
1729
1692
  sentinel.remove();
1730
1693
  };
1731
1694
  }, [sticky]);
1732
- const resolvedIcon = todayIcon ? /* @__PURE__ */ jsx12(
1695
+ const resolvedIcon = todayIcon ? /* @__PURE__ */ jsx11(
1733
1696
  TodayTimeIcon,
1734
1697
  {
1735
- className: cn(
1698
+ className: cn2(
1736
1699
  "h-6 w-6 text-amber-500",
1737
1700
  todayIconClassName
1738
1701
  )
1739
1702
  }
1740
1703
  ) : icon;
1741
- return /* @__PURE__ */ jsxs10(
1704
+ return /* @__PURE__ */ jsxs9(
1742
1705
  "header",
1743
1706
  {
1744
1707
  ref: headerRef,
1745
1708
  "data-test": dataTest,
1746
1709
  "data-stuck": sticky ? stuck ? "true" : "false" : void 0,
1747
- className: cn(
1710
+ className: cn2(
1748
1711
  "flex min-w-0 shrink-0 flex-col items-start gap-3 pb-2 sm:flex-row sm:justify-between sm:gap-4 sm:pb-3",
1749
1712
  // No extra pt here — page inset sets the shared title baseline.
1750
1713
  sticky && "suite-page-header-sticky",
1751
1714
  className
1752
1715
  ),
1753
1716
  children: [
1754
- /* @__PURE__ */ jsxs10("div", { className: "min-w-0 flex-1", children: [
1755
- eyebrow ? /* @__PURE__ */ jsx12("div", { className: "mb-0.5 flex min-w-0 items-center gap-1.5 text-xs text-ph-subtle", children: eyebrow }) : null,
1756
- breadcrumb ? /* @__PURE__ */ jsx12("div", { className: "mb-0.5 flex min-w-0 items-center gap-1.5 text-xs text-ph-subtle", children: breadcrumb }) : null,
1757
- /* @__PURE__ */ jsxs10("div", { className: "flex min-w-0 items-center gap-3", children: [
1758
- resolvedIcon ? /* @__PURE__ */ jsx12(
1717
+ /* @__PURE__ */ jsxs9("div", { className: "min-w-0 flex-1", children: [
1718
+ eyebrow ? /* @__PURE__ */ jsx11("div", { className: "mb-0.5 flex min-w-0 items-center gap-1.5 text-xs text-ph-subtle", children: eyebrow }) : null,
1719
+ breadcrumb ? /* @__PURE__ */ jsx11("div", { className: "mb-0.5 flex min-w-0 items-center gap-1.5 text-xs text-ph-subtle", children: breadcrumb }) : null,
1720
+ /* @__PURE__ */ jsxs9("div", { className: "flex min-w-0 items-center gap-3", children: [
1721
+ resolvedIcon ? /* @__PURE__ */ jsx11(
1759
1722
  "div",
1760
1723
  {
1761
1724
  className: "hidden shrink-0 sm:flex sm:items-center [&_svg]:h-6 [&_svg]:w-6",
@@ -1763,24 +1726,24 @@ function SuitePageHeader({
1763
1726
  children: resolvedIcon
1764
1727
  }
1765
1728
  ) : null,
1766
- /* @__PURE__ */ jsxs10("div", { className: "flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1", children: [
1767
- /* @__PURE__ */ jsx12(
1729
+ /* @__PURE__ */ jsxs9("div", { className: "flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1", children: [
1730
+ /* @__PURE__ */ jsx11(
1768
1731
  "h1",
1769
1732
  {
1770
- className: cn(
1733
+ className: cn2(
1771
1734
  "min-w-0 break-words font-display text-[1.375rem] font-semibold leading-tight tracking-tight text-ph-ink text-balance sm:text-2xl",
1772
1735
  titleClassName
1773
1736
  ),
1774
1737
  children: title
1775
1738
  }
1776
1739
  ),
1777
- badge ? /* @__PURE__ */ jsx12("span", { className: "rounded-md bg-ph-muted px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wide text-ph-subtle", children: badge }) : null
1740
+ badge ? /* @__PURE__ */ jsx11("span", { className: "rounded-md bg-ph-muted px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wide text-ph-subtle", children: badge }) : null
1778
1741
  ] })
1779
1742
  ] }),
1780
- description ? /* @__PURE__ */ jsx12(
1743
+ description ? /* @__PURE__ */ jsx11(
1781
1744
  "div",
1782
1745
  {
1783
- className: cn(
1746
+ className: cn2(
1784
1747
  "mt-1.5 max-w-2xl text-pretty text-sm leading-5 text-ph-subtle",
1785
1748
  resolvedIcon && "sm:pl-9"
1786
1749
  ),
@@ -1788,7 +1751,7 @@ function SuitePageHeader({
1788
1751
  }
1789
1752
  ) : null
1790
1753
  ] }),
1791
- actions ? /* @__PURE__ */ jsx12("div", { className: "flex max-w-full items-center gap-2 self-stretch overflow-x-auto pb-1 sm:shrink-0 sm:self-center sm:overflow-visible sm:pb-0", children: actions }) : null
1754
+ actions ? /* @__PURE__ */ jsx11("div", { className: "flex max-w-full items-center gap-2 self-stretch overflow-x-auto pb-1 sm:shrink-0 sm:self-center sm:overflow-visible sm:pb-0", children: actions }) : null
1792
1755
  ]
1793
1756
  }
1794
1757
  );
@@ -1799,13 +1762,13 @@ function SuiteToolbar({
1799
1762
  label = "Page tools",
1800
1763
  dataTest
1801
1764
  }) {
1802
- return /* @__PURE__ */ jsx12(
1765
+ return /* @__PURE__ */ jsx11(
1803
1766
  "div",
1804
1767
  {
1805
1768
  role: "toolbar",
1806
1769
  "aria-label": label,
1807
1770
  "data-test": dataTest,
1808
- className: cn("flex min-w-0 flex-wrap items-center gap-2", className),
1771
+ className: cn2("flex min-w-0 flex-wrap items-center gap-2", className),
1809
1772
  children
1810
1773
  }
1811
1774
  );
@@ -1816,12 +1779,12 @@ function SuiteTabList({
1816
1779
  label,
1817
1780
  dataTest
1818
1781
  }) {
1819
- return /* @__PURE__ */ jsx12(
1782
+ return /* @__PURE__ */ jsx11(
1820
1783
  "nav",
1821
1784
  {
1822
1785
  "aria-label": label,
1823
1786
  "data-test": dataTest,
1824
- className: cn(
1787
+ className: cn2(
1825
1788
  "flex min-w-0 flex-wrap gap-2 [&_a]:min-h-[48px] [&_button]:min-h-[48px] sm:[&_a]:min-h-[44px] sm:[&_button]:min-h-[44px]",
1826
1789
  className
1827
1790
  ),
@@ -1835,26 +1798,26 @@ function SuiteSectionHeader({
1835
1798
  action,
1836
1799
  className
1837
1800
  }) {
1838
- return /* @__PURE__ */ jsxs10(
1801
+ return /* @__PURE__ */ jsxs9(
1839
1802
  "div",
1840
1803
  {
1841
- className: cn(
1804
+ className: cn2(
1842
1805
  "flex min-w-0 flex-col gap-4 sm:flex-row sm:items-end sm:justify-between",
1843
1806
  className
1844
1807
  ),
1845
1808
  children: [
1846
- /* @__PURE__ */ jsxs10("div", { className: "min-w-0", children: [
1847
- /* @__PURE__ */ jsx12("h2", { className: "font-display text-balance text-lg font-semibold tracking-tight text-ph-ink sm:text-xl", children: title }),
1848
- description ? /* @__PURE__ */ jsx12("div", { className: "mt-1 max-w-2xl text-pretty text-sm leading-5 text-ph-subtle", children: description }) : null
1809
+ /* @__PURE__ */ jsxs9("div", { className: "min-w-0", children: [
1810
+ /* @__PURE__ */ jsx11("h2", { className: "font-display text-balance text-lg font-semibold tracking-tight text-ph-ink sm:text-xl", children: title }),
1811
+ description ? /* @__PURE__ */ jsx11("div", { className: "mt-1 max-w-2xl text-pretty text-sm leading-5 text-ph-subtle", children: description }) : null
1849
1812
  ] }),
1850
- action ? /* @__PURE__ */ jsx12("div", { className: "flex min-h-[44px] shrink-0 items-center", children: action }) : null
1813
+ action ? /* @__PURE__ */ jsx11("div", { className: "flex min-h-[44px] shrink-0 items-center", children: action }) : null
1851
1814
  ]
1852
1815
  }
1853
1816
  );
1854
1817
  }
1855
1818
 
1856
1819
  // src/suite/components/suite-settings-layout.tsx
1857
- import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
1820
+ import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
1858
1821
  function SuiteSettingsLayout({
1859
1822
  children,
1860
1823
  sidebar,
@@ -1868,13 +1831,13 @@ function SuiteSettingsLayout({
1868
1831
  className,
1869
1832
  contentClassName
1870
1833
  }) {
1871
- return /* @__PURE__ */ jsxs11(
1834
+ return /* @__PURE__ */ jsxs10(
1872
1835
  SuitePage,
1873
1836
  {
1874
1837
  dataTest,
1875
- className: cn("flex h-full flex-col overflow-hidden", className),
1838
+ className: cn2("flex h-full flex-col overflow-hidden", className),
1876
1839
  children: [
1877
- header != null ? header : /* @__PURE__ */ jsx13(
1840
+ header != null ? header : /* @__PURE__ */ jsx12(
1878
1841
  SuitePageHeader,
1879
1842
  {
1880
1843
  sticky: true,
@@ -1883,10 +1846,10 @@ function SuiteSettingsLayout({
1883
1846
  description
1884
1847
  }
1885
1848
  ),
1886
- loading != null ? loading : /* @__PURE__ */ jsxs11("div", { className: "suite-page-body mt-6 flex min-h-0 flex-1 flex-col", children: [
1887
- mobileNav ? /* @__PURE__ */ jsx13("div", { className: "sticky top-0 z-20 mb-2 shrink-0 bg-ph-canvas/95 backdrop-blur lg:hidden", children: mobileNav }) : null,
1888
- /* @__PURE__ */ jsxs11("div", { className: "flex min-h-0 flex-1 flex-col gap-6 lg:flex-row lg:gap-8", children: [
1889
- /* @__PURE__ */ jsx13(
1849
+ loading != null ? loading : /* @__PURE__ */ jsxs10("div", { className: "suite-page-body mt-6 flex min-h-0 flex-1 flex-col", children: [
1850
+ mobileNav ? /* @__PURE__ */ jsx12("div", { className: "sticky top-0 z-20 mb-2 shrink-0 bg-ph-canvas/95 backdrop-blur lg:hidden", children: mobileNav }) : null,
1851
+ /* @__PURE__ */ jsxs10("div", { className: "flex min-h-0 flex-1 flex-col gap-6 lg:flex-row lg:gap-8", children: [
1852
+ /* @__PURE__ */ jsx12(
1890
1853
  "aside",
1891
1854
  {
1892
1855
  "aria-label": "Settings",
@@ -1894,10 +1857,10 @@ function SuiteSettingsLayout({
1894
1857
  children: sidebar
1895
1858
  }
1896
1859
  ),
1897
- /* @__PURE__ */ jsx13(
1860
+ /* @__PURE__ */ jsx12(
1898
1861
  "div",
1899
1862
  {
1900
- className: cn(
1863
+ className: cn2(
1901
1864
  "min-h-0 min-w-0 flex-1 overflow-y-auto overscroll-contain pb-6",
1902
1865
  contentClassName
1903
1866
  ),
@@ -1915,24 +1878,25 @@ function SuiteSettingsLayout({
1915
1878
  import Image2 from "next/image";
1916
1879
  import { useRouter as useRouter2 } from "next/navigation";
1917
1880
  import { LogOut, Settings } from "iconoir-react";
1918
- import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
1881
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
1919
1882
  function computeInitials(name, email) {
1920
1883
  const source = (name || email || "?").trim();
1921
1884
  return source.split(/[\s@]+/).filter(Boolean).slice(0, 2).map((part) => part[0]).join("").toUpperCase();
1922
1885
  }
1923
1886
  var AVATAR_TOKENS = [
1924
- "bg-ph-brand",
1925
- "bg-ph-violet",
1926
- "bg-ph-info",
1927
- "bg-ph-success",
1928
- "bg-ph-danger"
1887
+ ["bg-ph-brand", "text-[var(--ph-on-accent)]"],
1888
+ ["bg-ph-violet", "text-[var(--ph-on-violet)]"],
1889
+ ["bg-ph-info", "text-[var(--ph-on-info)]"],
1890
+ ["bg-ph-success", "text-[var(--ph-on-success)]"],
1891
+ ["bg-ph-danger", "text-[var(--ph-on-danger)]"]
1929
1892
  ];
1930
1893
  function avatarColorClass(seed) {
1931
1894
  let hash = 0;
1932
1895
  for (let i = 0; i < seed.length; i += 1) {
1933
1896
  hash = seed.charCodeAt(i) + ((hash << 5) - hash);
1934
1897
  }
1935
- return AVATAR_TOKENS[Math.abs(hash) % AVATAR_TOKENS.length];
1898
+ const [bg, ink] = AVATAR_TOKENS[Math.abs(hash) % AVATAR_TOKENS.length];
1899
+ return `${bg} ${ink}`;
1936
1900
  }
1937
1901
  function SuiteUserMenu({
1938
1902
  name,
@@ -1950,7 +1914,7 @@ function SuiteUserMenu({
1950
1914
  const router = useRouter2();
1951
1915
  const initials = fallbackInitials != null ? fallbackInitials : computeInitials(name, email);
1952
1916
  const fallbackColor = avatarColorClass(email || name || "?");
1953
- const avatar = /* @__PURE__ */ jsx14("span", { className: "inline-flex h-10 w-10 items-center justify-center overflow-hidden rounded-full border border-ph-border", children: image ? /* @__PURE__ */ jsx14(
1917
+ const avatar = /* @__PURE__ */ jsx13("span", { className: "inline-flex h-10 w-10 items-center justify-center overflow-hidden rounded-full border border-ph-border", children: image ? /* @__PURE__ */ jsx13(
1954
1918
  Image2,
1955
1919
  {
1956
1920
  src: image,
@@ -1960,17 +1924,17 @@ function SuiteUserMenu({
1960
1924
  className: "h-full w-full object-cover",
1961
1925
  unoptimized: true
1962
1926
  }
1963
- ) : /* @__PURE__ */ jsx14(
1927
+ ) : /* @__PURE__ */ jsx13(
1964
1928
  "span",
1965
1929
  {
1966
- className: cn(
1967
- "flex h-full w-full items-center justify-center text-sm font-semibold text-white",
1930
+ className: cn2(
1931
+ "flex h-full w-full items-center justify-center text-sm font-semibold",
1968
1932
  fallbackColor
1969
1933
  ),
1970
1934
  children: initials
1971
1935
  }
1972
1936
  ) });
1973
- const accountMenu = /* @__PURE__ */ jsxs12(
1937
+ const accountMenu = /* @__PURE__ */ jsxs11(
1974
1938
  DropdownMenu,
1975
1939
  {
1976
1940
  trigger: avatar,
@@ -1982,30 +1946,30 @@ function SuiteUserMenu({
1982
1946
  sideOffset: 6,
1983
1947
  collisionPadding: 16,
1984
1948
  modal: false,
1985
- className: cn(
1949
+ className: cn2(
1986
1950
  "[&_.ph-dropdown-trigger]:rounded-full",
1987
1951
  showSignOutAction ? void 0 : className
1988
1952
  ),
1989
1953
  "data-test": dataTest,
1990
1954
  children: [
1991
- /* @__PURE__ */ jsxs12("div", { className: "px-2 py-1.5", children: [
1992
- /* @__PURE__ */ jsx14("p", { className: "truncate text-sm font-medium text-ph-ink", children: name || email || "Account" }),
1993
- email ? /* @__PURE__ */ jsx14("p", { className: "truncate text-xs text-ph-mutedtext", children: email }) : null
1955
+ /* @__PURE__ */ jsxs11("div", { className: "px-2 py-1.5", children: [
1956
+ /* @__PURE__ */ jsx13("p", { className: "truncate text-sm font-medium text-ph-ink", children: name || email || "Account" }),
1957
+ email ? /* @__PURE__ */ jsx13("p", { className: "truncate text-xs text-ph-mutedtext", children: email }) : null
1994
1958
  ] }),
1995
- /* @__PURE__ */ jsx14("div", { className: "my-1 border-t border-ph-border" }),
1996
- /* @__PURE__ */ jsxs12(
1959
+ /* @__PURE__ */ jsx13("div", { className: "my-1 border-t border-ph-border" }),
1960
+ /* @__PURE__ */ jsxs11(
1997
1961
  DropdownItem,
1998
1962
  {
1999
1963
  "data-test": `${dataTest}-settings`,
2000
1964
  onClick: () => router.push(settingsHref),
2001
1965
  children: [
2002
- /* @__PURE__ */ jsx14(Settings, { className: "h-4 w-4 text-ph-mutedtext", "aria-hidden": true }),
1966
+ /* @__PURE__ */ jsx13(Settings, { className: "h-4 w-4 text-ph-mutedtext", "aria-hidden": true }),
2003
1967
  "Profile settings"
2004
1968
  ]
2005
1969
  }
2006
1970
  ),
2007
- /* @__PURE__ */ jsxs12(DropdownItem, { "data-test": `${dataTest}-sign-out`, onClick: onSignOut, children: [
2008
- /* @__PURE__ */ jsx14(LogOut, { className: "h-4 w-4 text-ph-mutedtext", "aria-hidden": true }),
1971
+ /* @__PURE__ */ jsxs11(DropdownItem, { "data-test": `${dataTest}-sign-out`, onClick: onSignOut, children: [
1972
+ /* @__PURE__ */ jsx13(LogOut, { className: "h-4 w-4 text-ph-mutedtext", "aria-hidden": true }),
2009
1973
  "Sign out"
2010
1974
  ] })
2011
1975
  ]
@@ -2014,16 +1978,16 @@ function SuiteUserMenu({
2014
1978
  if (!showSignOutAction) {
2015
1979
  return accountMenu;
2016
1980
  }
2017
- return /* @__PURE__ */ jsxs12(
1981
+ return /* @__PURE__ */ jsxs11(
2018
1982
  "div",
2019
1983
  {
2020
- className: cn(
1984
+ className: cn2(
2021
1985
  "flex w-full min-w-0 flex-1 items-center justify-between gap-2",
2022
1986
  className
2023
1987
  ),
2024
1988
  children: [
2025
- /* @__PURE__ */ jsx14("div", { className: "shrink-0", children: accountMenu }),
2026
- /* @__PURE__ */ jsx14(
1989
+ /* @__PURE__ */ jsx13("div", { className: "shrink-0", children: accountMenu }),
1990
+ /* @__PURE__ */ jsx13(
2027
1991
  "button",
2028
1992
  {
2029
1993
  type: "button",
@@ -2032,7 +1996,7 @@ function SuiteUserMenu({
2032
1996
  "aria-label": "Sign out",
2033
1997
  className: "inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-lg text-ph-mutedtext transition-colors hover:bg-ph-muted hover:text-ph-ink focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ph-focus-ring",
2034
1998
  onClick: onSignOut,
2035
- children: /* @__PURE__ */ jsx14(LogOut, { className: "h-4 w-4", "aria-hidden": true })
1999
+ children: /* @__PURE__ */ jsx13(LogOut, { className: "h-4 w-4", "aria-hidden": true })
2036
2000
  }
2037
2001
  )
2038
2002
  ]
@@ -2042,7 +2006,7 @@ function SuiteUserMenu({
2042
2006
 
2043
2007
  // src/suite/components/suite-bottom-nav.tsx
2044
2008
  import Link from "next/link";
2045
- import { Fragment as Fragment4, jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
2009
+ import { Fragment as Fragment4, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
2046
2010
  function SuiteBottomNav({
2047
2011
  items,
2048
2012
  ariaLabel = "Primary navigation",
@@ -2055,8 +2019,8 @@ function SuiteBottomNav({
2055
2019
  );
2056
2020
  }
2057
2021
  const activeIndex = items.findIndex((item) => item.active);
2058
- return /* @__PURE__ */ jsxs13(Fragment4, { children: [
2059
- /* @__PURE__ */ jsx15(
2022
+ return /* @__PURE__ */ jsxs12(Fragment4, { children: [
2023
+ /* @__PURE__ */ jsx14(
2060
2024
  "div",
2061
2025
  {
2062
2026
  "aria-hidden": true,
@@ -2064,12 +2028,12 @@ function SuiteBottomNav({
2064
2028
  style: { height: "calc(60px + env(safe-area-inset-bottom))" }
2065
2029
  }
2066
2030
  ),
2067
- /* @__PURE__ */ jsxs13(
2031
+ /* @__PURE__ */ jsxs12(
2068
2032
  "nav",
2069
2033
  {
2070
2034
  "aria-label": ariaLabel,
2071
2035
  "data-test": dataTest,
2072
- className: cn(
2036
+ className: cn2(
2073
2037
  "suite-bottom-nav no-print z-40 grid auto-cols-fr grid-flow-col lg:hidden",
2074
2038
  className
2075
2039
  ),
@@ -2079,31 +2043,31 @@ function SuiteBottomNav({
2079
2043
  "--suite-nav-active": activeIndex >= 0 ? activeIndex : 0
2080
2044
  },
2081
2045
  children: [
2082
- activeIndex >= 0 ? /* @__PURE__ */ jsx15("span", { "aria-hidden": true, className: "suite-bottom-nav__indicator" }) : null,
2046
+ activeIndex >= 0 ? /* @__PURE__ */ jsx14("span", { "aria-hidden": true, className: "suite-bottom-nav__indicator" }) : null,
2083
2047
  items.map((item) => {
2084
2048
  var _a;
2085
2049
  const Icon = item.icon;
2086
2050
  const active = Boolean(item.active);
2087
- return /* @__PURE__ */ jsxs13(
2051
+ return /* @__PURE__ */ jsxs12(
2088
2052
  Link,
2089
2053
  {
2090
2054
  href: item.href,
2091
2055
  id: item.id,
2092
2056
  "data-test": (_a = item.dataTest) != null ? _a : `suite-nav-${item.label.toLowerCase().replace(/\s+/g, "-")}`,
2093
2057
  "aria-current": active ? "page" : void 0,
2094
- className: cn(
2058
+ className: cn2(
2095
2059
  "suite-bottom-nav__item relative flex min-h-[60px] min-w-0 flex-col items-center justify-center gap-1 px-1 pb-1.5 pt-2 text-[10px] font-medium leading-none text-ph-mutedtext transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ph-brand motion-reduce:transition-none",
2096
2060
  active && "font-semibold text-ph-brand"
2097
2061
  ),
2098
2062
  children: [
2099
- /* @__PURE__ */ jsx15(
2063
+ /* @__PURE__ */ jsx14(
2100
2064
  "span",
2101
2065
  {
2102
- className: cn(
2066
+ className: cn2(
2103
2067
  "suite-bottom-nav__icon relative z-10 inline-flex items-center justify-center",
2104
2068
  active && "suite-bottom-nav__icon--active"
2105
2069
  ),
2106
- children: /* @__PURE__ */ jsx15(
2070
+ children: /* @__PURE__ */ jsx14(
2107
2071
  Icon,
2108
2072
  {
2109
2073
  className: "h-6 w-6",
@@ -2113,7 +2077,7 @@ function SuiteBottomNav({
2113
2077
  )
2114
2078
  }
2115
2079
  ),
2116
- /* @__PURE__ */ jsx15("span", { className: "relative z-10 max-w-full truncate", children: item.label })
2080
+ /* @__PURE__ */ jsx14("span", { className: "relative z-10 max-w-full truncate", children: item.label })
2117
2081
  ]
2118
2082
  },
2119
2083
  item.href
@@ -2127,7 +2091,7 @@ function SuiteBottomNav({
2127
2091
 
2128
2092
  // src/suite/components/today-calibrating.tsx
2129
2093
  import { Refresh as RefreshCw2, SunLight as Sun } from "iconoir-react";
2130
- import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
2094
+ import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
2131
2095
  function TodayCalibrating({
2132
2096
  onRetry,
2133
2097
  retrying = false,
@@ -2137,27 +2101,27 @@ function TodayCalibrating({
2137
2101
  retrySpinnerClassName = "text-ph-brand"
2138
2102
  }) {
2139
2103
  void _variant;
2140
- return /* @__PURE__ */ jsxs14(
2104
+ return /* @__PURE__ */ jsxs13(
2141
2105
  "div",
2142
2106
  {
2143
- className: cn(
2107
+ className: cn2(
2144
2108
  "suite-auth-handoff relative flex min-h-[14rem] flex-col items-center justify-center overflow-hidden rounded-2xl border border-ph-border bg-ph-surface px-5 py-8 text-center shadow-sm",
2145
2109
  className
2146
2110
  ),
2147
2111
  "data-test": "today-calibrating",
2148
2112
  children: [
2149
- /* @__PURE__ */ jsx16(
2113
+ /* @__PURE__ */ jsx15(
2150
2114
  "div",
2151
2115
  {
2152
2116
  className: "pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_50%_35%,rgba(251,191,36,0.1),transparent_55%)]",
2153
2117
  "aria-hidden": true
2154
2118
  }
2155
2119
  ),
2156
- /* @__PURE__ */ jsx16("div", { className: "relative mb-5 flex h-14 w-14 items-center justify-center rounded-2xl border border-ph-border bg-ph-surface text-ph-ink shadow-sm", children: /* @__PURE__ */ jsx16(Sun, { className: "h-8 w-8", strokeWidth: 2, "aria-hidden": true }) }),
2157
- /* @__PURE__ */ jsx16("h2", { className: "relative text-base font-semibold tracking-tight text-ph-ink sm:text-lg md:text-xl", children: "Calibrating your day" }),
2158
- /* @__PURE__ */ jsx16("p", { className: "relative mt-1.5 max-w-sm text-sm sm:text-[15px] leading-relaxed text-ph-subtle", children: "Pulling together tasks, time and updates from your workspace\u2026" }),
2159
- /* @__PURE__ */ jsx16("div", { className: "relative mt-5 flex justify-center", children: /* @__PURE__ */ jsx16(Spinner, { size: "sm", className: "opacity-70", label: "Loading today" }) }),
2160
- onRetry ? /* @__PURE__ */ jsxs14(
2120
+ /* @__PURE__ */ jsx15("div", { className: "relative mb-5 flex h-14 w-14 items-center justify-center rounded-2xl border border-ph-border bg-ph-surface text-ph-ink shadow-sm", children: /* @__PURE__ */ jsx15(Sun, { className: "h-8 w-8", strokeWidth: 2, "aria-hidden": true }) }),
2121
+ /* @__PURE__ */ jsx15("h2", { className: "relative text-base font-semibold tracking-tight text-ph-ink sm:text-lg md:text-xl", children: "Calibrating your day" }),
2122
+ /* @__PURE__ */ jsx15("p", { className: "relative mt-1.5 max-w-sm text-sm sm:text-[15px] leading-relaxed text-ph-subtle", children: "Pulling together tasks, time and updates from your workspace\u2026" }),
2123
+ /* @__PURE__ */ jsx15("div", { className: "relative mt-5 flex justify-center", children: /* @__PURE__ */ jsx15(Spinner, { size: "sm", className: "opacity-70", label: "Loading today" }) }),
2124
+ onRetry ? /* @__PURE__ */ jsxs13(
2161
2125
  "button",
2162
2126
  {
2163
2127
  type: "button",
@@ -2165,7 +2129,7 @@ function TodayCalibrating({
2165
2129
  disabled: retrying,
2166
2130
  className: "relative mt-6 inline-flex items-center gap-2 rounded-xl border border-ph-border bg-ph-canvas px-4 py-2 text-sm font-medium text-ph-ink transition hover:bg-ph-muted disabled:opacity-60",
2167
2131
  children: [
2168
- retrying ? /* @__PURE__ */ jsx16(Spinner, { size: "sm", className: retrySpinnerClassName }) : /* @__PURE__ */ jsx16(RefreshCw2, { className: "h-4 w-4", "aria-hidden": true }),
2132
+ retrying ? /* @__PURE__ */ jsx15(Spinner, { size: "sm", className: retrySpinnerClassName }) : /* @__PURE__ */ jsx15(RefreshCw2, { className: "h-4 w-4", "aria-hidden": true }),
2169
2133
  "Try again"
2170
2134
  ]
2171
2135
  }
@@ -2183,7 +2147,7 @@ import {
2183
2147
  useEffect as useEffect6,
2184
2148
  useId,
2185
2149
  useLayoutEffect,
2186
- useRef as useRef3,
2150
+ useRef as useRef2,
2187
2151
  useState as useState7
2188
2152
  } from "react";
2189
2153
  import {
@@ -2194,8 +2158,8 @@ import {
2194
2158
  Square,
2195
2159
  WarningTriangle
2196
2160
  } from "iconoir-react";
2197
- import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
2198
- var SuiteAiBlockNoteMessage = lazy(() => import("./ai-message-blocknote-WABTHFY7.mjs"));
2161
+ import { Fragment as Fragment5, jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
2162
+ var SuiteAiBlockNoteMessage = lazy(() => import("./ai-message-blocknote-D4Z6DUCJ.mjs"));
2199
2163
  var SUITE_OPEN_ASK_AI_EVENT = "shellstack:open-ask-ai";
2200
2164
  var SUITE_ASK_AI_OPEN_KEY = "shellstack:shelly-open";
2201
2165
  var SUITE_ASK_AI_OPEN_QUERY = "shelly";
@@ -2277,7 +2241,8 @@ function SuiteAiPanel({
2277
2241
  suiteAppBases,
2278
2242
  onSwitchApp,
2279
2243
  onSameAppNavigate,
2280
- resolveAction
2244
+ resolveAction,
2245
+ isWaitingForReply = false
2281
2246
  }) {
2282
2247
  const inputId = useId();
2283
2248
  const [uncontrolledOpen, setUncontrolledOpen] = useState7(false);
@@ -2297,10 +2262,11 @@ function SuiteAiPanel({
2297
2262
  const [hydrating, setHydrating] = useState7(false);
2298
2263
  const [error, setError] = useState7("");
2299
2264
  const [atBottom, setAtBottom] = useState7(true);
2300
- const scrollerRef = useRef3(null);
2301
- const textareaRef = useRef3(null);
2302
- const abortRef = useRef3(null);
2303
- const pendingPromptRef = useRef3(null);
2265
+ const scrollerRef = useRef2(null);
2266
+ const textareaRef = useRef2(null);
2267
+ const abortRef = useRef2(null);
2268
+ const pendingPromptRef = useRef2(null);
2269
+ const waiting = loading || isWaitingForReply;
2304
2270
  useEffect6(() => {
2305
2271
  function onOpen(event) {
2306
2272
  var _a;
@@ -2328,7 +2294,7 @@ function SuiteAiPanel({
2328
2294
  setAtBottom(distance < 64);
2329
2295
  }, []);
2330
2296
  const hydrate = useCallback2(async () => {
2331
- var _a;
2297
+ var _a, _b, _c;
2332
2298
  setHydrating(true);
2333
2299
  setError("");
2334
2300
  try {
@@ -2336,6 +2302,11 @@ function SuiteAiPanel({
2336
2302
  setMessages((_a = data.messages) != null ? _a : []);
2337
2303
  if (!data.configured) {
2338
2304
  setError("ShellStack AI is not configured for this workspace yet.");
2305
+ } else {
2306
+ const latestJob = (_b = data.jobs) == null ? void 0 : _b[0];
2307
+ if ((latestJob == null ? void 0 : latestJob.status) === "failed" && latestJob.error && latestJob.error !== "Chat cleared." && ((_c = data.messages.at(-1)) == null ? void 0 : _c.role) !== "assistant") {
2308
+ setError(latestJob.error);
2309
+ }
2339
2310
  }
2340
2311
  } catch (err) {
2341
2312
  setError(
@@ -2358,7 +2329,7 @@ function SuiteAiPanel({
2358
2329
  }, [open, hydrate]);
2359
2330
  useEffect6(() => {
2360
2331
  if (open && atBottom) scrollToBottom();
2361
- }, [messages, loading, open, atBottom, scrollToBottom]);
2332
+ }, [messages, waiting, open, atBottom, scrollToBottom]);
2362
2333
  useEffect6(() => {
2363
2334
  var _a;
2364
2335
  if (open && !hydrating) (_a = textareaRef.current) == null ? void 0 : _a.focus();
@@ -2372,7 +2343,7 @@ function SuiteAiPanel({
2372
2343
  async function ask(text) {
2373
2344
  var _a;
2374
2345
  const trimmed = text.trim();
2375
- if (!trimmed || loading) return;
2346
+ if (!trimmed || waiting) return;
2376
2347
  const controller = new AbortController();
2377
2348
  abortRef.current = controller;
2378
2349
  setLoading(true);
@@ -2488,32 +2459,32 @@ function SuiteAiPanel({
2488
2459
  }
2489
2460
  if (!open) return null;
2490
2461
  const Icon = BrandIcon != null ? BrandIcon : Sparks;
2491
- return /* @__PURE__ */ jsxs15(
2462
+ return /* @__PURE__ */ jsxs14(
2492
2463
  "aside",
2493
2464
  {
2494
2465
  className: "flex h-full min-h-0 flex-col bg-ph-canvas",
2495
2466
  "data-test": "suite-ask-ai-panel",
2496
2467
  "aria-label": title,
2497
2468
  children: [
2498
- /* @__PURE__ */ jsxs15("header", { className: "flex items-center gap-2 px-2 pb-2", children: [
2499
- /* @__PURE__ */ jsx17("h2", { className: "sr-only", children: title }),
2500
- messages.length > 0 ? /* @__PURE__ */ jsxs15(
2469
+ /* @__PURE__ */ jsxs14("header", { className: "flex items-center gap-2 px-2 pb-2", children: [
2470
+ /* @__PURE__ */ jsx16("h2", { className: "sr-only", children: title }),
2471
+ messages.length > 0 ? /* @__PURE__ */ jsxs14(
2501
2472
  "button",
2502
2473
  {
2503
2474
  type: "button",
2504
2475
  onClick: () => void handleClear(),
2505
- disabled: loading,
2476
+ disabled: waiting,
2506
2477
  className: "ml-auto inline-flex h-9 items-center gap-1.5 rounded-lg px-2 text-xs font-medium text-ph-subtle transition-colors hover:bg-ph-muted hover:text-ph-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-focus disabled:opacity-40",
2507
2478
  "data-test": "ask-ai-clear",
2508
2479
  children: [
2509
- /* @__PURE__ */ jsx17(Erase, { className: "h-3.5 w-3.5" }),
2480
+ /* @__PURE__ */ jsx16(Erase, { className: "h-3.5 w-3.5" }),
2510
2481
  "Clear"
2511
2482
  ]
2512
2483
  }
2513
2484
  ) : null
2514
2485
  ] }),
2515
- /* @__PURE__ */ jsxs15("div", { className: "relative min-h-0 flex-1", children: [
2516
- /* @__PURE__ */ jsxs15(
2486
+ /* @__PURE__ */ jsxs14("div", { className: "relative min-h-0 flex-1", children: [
2487
+ /* @__PURE__ */ jsxs14(
2517
2488
  "div",
2518
2489
  {
2519
2490
  ref: scrollerRef,
@@ -2524,25 +2495,25 @@ function SuiteAiPanel({
2524
2495
  "aria-label": "Conversation",
2525
2496
  className: "suite-scroll-lock h-full space-y-5 overflow-y-auto px-2 py-3",
2526
2497
  children: [
2527
- hydrating && messages.length === 0 ? /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2 text-sm text-ph-subtle", children: [
2528
- /* @__PURE__ */ jsx17(Spinner, { className: "h-4 w-4 animate-spin" }),
2498
+ hydrating && messages.length === 0 ? /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-2 text-sm text-ph-subtle", children: [
2499
+ /* @__PURE__ */ jsx16(Spinner, { className: "h-4 w-4 animate-spin" }),
2529
2500
  "Loading your chat\u2026"
2530
2501
  ] }) : null,
2531
- !hydrating && messages.length === 0 && !error ? /* @__PURE__ */ jsxs15("div", { className: "mx-auto mt-4 flex max-w-sm flex-col items-center px-1 text-center", children: [
2532
- /* @__PURE__ */ jsx17("span", { className: "flex h-10 w-10 items-center justify-center rounded-2xl bg-ph-brand/10 text-ph-brand", children: /* @__PURE__ */ jsx17(Icon, { className: "h-5 w-5" }) }),
2533
- /* @__PURE__ */ jsx17("p", { className: "mt-3 font-display text-base font-semibold text-ph-ink", children: "How can I help?" }),
2534
- /* @__PURE__ */ jsx17("p", { className: "mt-1 text-sm leading-relaxed text-ph-subtle", children: emptyState }),
2535
- presets.length > 0 ? /* @__PURE__ */ jsx17("div", { className: "mt-4 flex w-full flex-col gap-2", children: presets.map((preset) => /* @__PURE__ */ jsxs15(
2502
+ !hydrating && messages.length === 0 && !error ? /* @__PURE__ */ jsxs14("div", { className: "mx-auto mt-4 flex max-w-sm flex-col items-center px-1 text-center", children: [
2503
+ /* @__PURE__ */ jsx16("span", { className: "flex h-10 w-10 items-center justify-center rounded-2xl bg-ph-brand/10 text-ph-brand", children: /* @__PURE__ */ jsx16(Icon, { className: "h-5 w-5" }) }),
2504
+ /* @__PURE__ */ jsx16("p", { className: "mt-3 font-display text-base font-semibold text-ph-ink", children: "How can I help?" }),
2505
+ /* @__PURE__ */ jsx16("p", { className: "mt-1 text-sm leading-relaxed text-ph-subtle", children: emptyState }),
2506
+ presets.length > 0 ? /* @__PURE__ */ jsx16("div", { className: "mt-4 flex w-full flex-col gap-2", children: presets.map((preset) => /* @__PURE__ */ jsxs14(
2536
2507
  "button",
2537
2508
  {
2538
2509
  type: "button",
2539
2510
  onClick: () => void ask(preset.prompt),
2540
- disabled: loading || hydrating,
2511
+ disabled: waiting || hydrating,
2541
2512
  className: "group flex w-full items-center gap-2 rounded-xl border border-ph-border bg-ph-surface px-3 py-2 text-left text-sm text-ph-ink transition-colors hover:border-ph-brand/40 hover:bg-ph-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-focus disabled:opacity-40",
2542
2513
  children: [
2543
- /* @__PURE__ */ jsx17(Sparks, { className: "h-4 w-4 shrink-0 text-ph-brand" }),
2544
- /* @__PURE__ */ jsx17("span", { className: "min-w-0 flex-1 truncate", children: preset.label }),
2545
- /* @__PURE__ */ jsx17(ArrowUp, { className: "h-3.5 w-3.5 shrink-0 rotate-45 text-ph-mutedtext transition-transform group-hover:translate-x-0.5" })
2514
+ /* @__PURE__ */ jsx16(Sparks, { className: "h-4 w-4 shrink-0 text-ph-brand" }),
2515
+ /* @__PURE__ */ jsx16("span", { className: "min-w-0 flex-1 truncate", children: preset.label }),
2516
+ /* @__PURE__ */ jsx16(ArrowUp, { className: "h-3.5 w-3.5 shrink-0 rotate-45 text-ph-mutedtext transition-transform group-hover:translate-x-0.5" })
2546
2517
  ]
2547
2518
  },
2548
2519
  preset.label
@@ -2552,48 +2523,61 @@ function SuiteAiPanel({
2552
2523
  var _a;
2553
2524
  const isUser = message.role === "user";
2554
2525
  if (isUser) {
2555
- return /* @__PURE__ */ jsx17(
2526
+ return /* @__PURE__ */ jsx16(
2556
2527
  "div",
2557
2528
  {
2558
2529
  className: "flex justify-end",
2559
2530
  "data-test": "ask-ai-user",
2560
- children: /* @__PURE__ */ jsx17("div", { className: "w-fit max-w-[85%] whitespace-pre-wrap break-words rounded-2xl rounded-br-md bg-ph-brand px-3 py-2 text-sm leading-relaxed text-[var(--ph-on-accent)] [overflow-wrap:anywhere]", children: message.content })
2531
+ children: /* @__PURE__ */ jsx16("div", { className: "w-fit max-w-[85%] whitespace-pre-wrap break-words rounded-2xl rounded-br-md bg-ph-brand px-3 py-2 text-sm leading-relaxed text-[var(--ph-on-accent)] [overflow-wrap:anywhere]", children: message.content })
2561
2532
  },
2562
2533
  `user-${index}`
2563
2534
  );
2564
2535
  }
2565
- return /* @__PURE__ */ jsxs15(
2536
+ return /* @__PURE__ */ jsxs14(
2566
2537
  "div",
2567
2538
  {
2568
2539
  className: "flex items-end gap-2",
2569
2540
  "data-test": "ask-ai-assistant",
2570
2541
  children: [
2571
- /* @__PURE__ */ jsx17(
2542
+ /* @__PURE__ */ jsx16(
2572
2543
  "span",
2573
2544
  {
2574
2545
  className: "mb-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-ph-brand/10 text-ph-brand",
2575
2546
  "aria-hidden": true,
2576
- children: /* @__PURE__ */ jsx17(Icon, { className: "h-3.5 w-3.5" })
2547
+ children: /* @__PURE__ */ jsx16(Icon, { className: "h-3.5 w-3.5" })
2577
2548
  }
2578
2549
  ),
2579
- /* @__PURE__ */ jsxs15("div", { className: "min-w-0 max-w-[85%] space-y-2", children: [
2580
- /* @__PURE__ */ jsx17("div", { className: "rounded-2xl rounded-bl-md bg-ph-muted px-3 py-2 text-sm leading-relaxed text-ph-ink", children: /* @__PURE__ */ jsx17(
2550
+ /* @__PURE__ */ jsxs14("div", { className: "min-w-0 max-w-[85%] space-y-2", children: [
2551
+ /* @__PURE__ */ jsx16("div", { className: "rounded-2xl rounded-bl-md bg-ph-muted px-3 py-2 text-sm leading-relaxed text-ph-ink", children: /* @__PURE__ */ jsx16(
2581
2552
  Suspense,
2582
2553
  {
2583
- fallback: /* @__PURE__ */ jsx17("p", { className: "whitespace-pre-wrap break-words", children: message.content }),
2584
- children: /* @__PURE__ */ jsx17(SuiteAiBlockNoteMessage, { markdown: message.content })
2554
+ fallback: /* @__PURE__ */ jsxs14(
2555
+ "div",
2556
+ {
2557
+ className: "space-y-2 py-0.5",
2558
+ role: "status",
2559
+ "aria-label": "Rendering response",
2560
+ children: [
2561
+ /* @__PURE__ */ jsx16("span", { className: "sr-only", children: "Rendering response\u2026" }),
2562
+ /* @__PURE__ */ jsx16("div", { className: "h-3 w-11/12 rounded bg-ph-mutedtext/20 motion-safe:animate-pulse" }),
2563
+ /* @__PURE__ */ jsx16("div", { className: "h-3 w-full rounded bg-ph-mutedtext/20 motion-safe:animate-pulse" }),
2564
+ /* @__PURE__ */ jsx16("div", { className: "h-3 w-3/5 rounded bg-ph-mutedtext/20 motion-safe:animate-pulse" })
2565
+ ]
2566
+ }
2567
+ ),
2568
+ children: /* @__PURE__ */ jsx16(SuiteAiBlockNoteMessage, { markdown: message.content })
2585
2569
  }
2586
2570
  ) }),
2587
- ((_a = message.actions) != null ? _a : []).map((action) => /* @__PURE__ */ jsxs15(
2571
+ ((_a = message.actions) != null ? _a : []).map((action) => /* @__PURE__ */ jsxs14(
2588
2572
  "div",
2589
2573
  {
2590
2574
  "data-test": "ask-ai-action",
2591
2575
  "data-status": action.status,
2592
2576
  className: "rounded-xl border border-ph-border bg-ph-surface px-3 py-2 text-sm text-ph-ink",
2593
2577
  children: [
2594
- /* @__PURE__ */ jsx17("p", { className: "font-medium", children: action.summary }),
2595
- action.status === "proposed" ? /* @__PURE__ */ jsxs15("div", { className: "mt-2 flex flex-wrap gap-2", children: [
2596
- /* @__PURE__ */ jsx17(
2578
+ /* @__PURE__ */ jsx16("p", { className: "font-medium", children: action.summary }),
2579
+ action.status === "proposed" ? /* @__PURE__ */ jsxs14("div", { className: "mt-2 flex flex-wrap gap-2", children: [
2580
+ /* @__PURE__ */ jsx16(
2597
2581
  "button",
2598
2582
  {
2599
2583
  type: "button",
@@ -2604,7 +2588,7 @@ function SuiteAiPanel({
2604
2588
  children: resolvingId === action.id ? "Working\u2026" : "Confirm"
2605
2589
  }
2606
2590
  ),
2607
- /* @__PURE__ */ jsx17(
2591
+ /* @__PURE__ */ jsx16(
2608
2592
  "button",
2609
2593
  {
2610
2594
  type: "button",
@@ -2616,11 +2600,11 @@ function SuiteAiPanel({
2616
2600
  }
2617
2601
  )
2618
2602
  ] }) : null,
2619
- action.status === "applied" ? /* @__PURE__ */ jsxs15("p", { className: "mt-1 text-xs text-ph-subtle", children: [
2603
+ action.status === "applied" ? /* @__PURE__ */ jsxs14("p", { className: "mt-1 text-xs text-ph-subtle", children: [
2620
2604
  "Done",
2621
- action.href ? /* @__PURE__ */ jsxs15(Fragment5, { children: [
2605
+ action.href ? /* @__PURE__ */ jsxs14(Fragment5, { children: [
2622
2606
  " \xB7 ",
2623
- /* @__PURE__ */ jsx17(
2607
+ /* @__PURE__ */ jsx16(
2624
2608
  "a",
2625
2609
  {
2626
2610
  href: action.href,
@@ -2630,8 +2614,8 @@ function SuiteAiPanel({
2630
2614
  )
2631
2615
  ] }) : null
2632
2616
  ] }) : null,
2633
- action.status === "cancelled" ? /* @__PURE__ */ jsx17("p", { className: "mt-1 text-xs text-ph-subtle", children: "Cancelled" }) : null,
2634
- action.status === "failed" ? /* @__PURE__ */ jsx17("p", { className: "mt-1 text-xs text-ph-danger", children: action.error || "Could not apply that." }) : null
2617
+ action.status === "cancelled" ? /* @__PURE__ */ jsx16("p", { className: "mt-1 text-xs text-ph-subtle", children: "Cancelled" }) : null,
2618
+ action.status === "failed" ? /* @__PURE__ */ jsx16("p", { className: "mt-1 text-xs text-ph-danger", children: action.error || "Could not apply that." }) : null
2635
2619
  ]
2636
2620
  },
2637
2621
  action.id
@@ -2642,31 +2626,31 @@ function SuiteAiPanel({
2642
2626
  `assistant-${index}`
2643
2627
  );
2644
2628
  }),
2645
- loading ? /* @__PURE__ */ jsxs15("div", { className: "flex items-end gap-2", "aria-hidden": true, children: [
2646
- /* @__PURE__ */ jsx17("span", { className: "mb-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-ph-brand/10 text-ph-brand", children: /* @__PURE__ */ jsx17(Icon, { className: "h-3.5 w-3.5" }) }),
2647
- /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-1.5 rounded-2xl rounded-bl-md bg-ph-muted px-3 py-2.5", children: [
2648
- /* @__PURE__ */ jsx17("span", { className: "h-1.5 w-1.5 rounded-full bg-ph-mutedtext motion-safe:animate-bounce" }),
2649
- /* @__PURE__ */ jsx17("span", { className: "h-1.5 w-1.5 rounded-full bg-ph-mutedtext motion-safe:animate-bounce [animation-delay:0.15s]" }),
2650
- /* @__PURE__ */ jsx17("span", { className: "h-1.5 w-1.5 rounded-full bg-ph-mutedtext motion-safe:animate-bounce [animation-delay:0.3s]" })
2629
+ waiting ? /* @__PURE__ */ jsxs14("div", { className: "flex items-end gap-2", "aria-hidden": true, children: [
2630
+ /* @__PURE__ */ jsx16("span", { className: "mb-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-ph-brand/10 text-ph-brand", children: /* @__PURE__ */ jsx16(Icon, { className: "h-3.5 w-3.5" }) }),
2631
+ /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-1.5 rounded-2xl rounded-bl-md bg-ph-muted px-3 py-2.5", children: [
2632
+ /* @__PURE__ */ jsx16("span", { className: "h-1.5 w-1.5 rounded-full bg-ph-mutedtext motion-safe:animate-bounce" }),
2633
+ /* @__PURE__ */ jsx16("span", { className: "h-1.5 w-1.5 rounded-full bg-ph-mutedtext motion-safe:animate-bounce [animation-delay:0.15s]" }),
2634
+ /* @__PURE__ */ jsx16("span", { className: "h-1.5 w-1.5 rounded-full bg-ph-mutedtext motion-safe:animate-bounce [animation-delay:0.3s]" })
2651
2635
  ] })
2652
2636
  ] }) : null,
2653
- loading ? /* @__PURE__ */ jsx17("span", { className: "sr-only", "aria-live": "polite", children: "Assistant is responding\u2026" }) : null,
2654
- error ? /* @__PURE__ */ jsxs15(
2637
+ waiting ? /* @__PURE__ */ jsx16("span", { className: "sr-only", "aria-live": "polite", children: "Assistant is responding\u2026" }) : null,
2638
+ error ? /* @__PURE__ */ jsxs14(
2655
2639
  "div",
2656
2640
  {
2657
2641
  role: "alert",
2658
2642
  className: "flex items-start gap-2 rounded-xl border border-ph-danger/30 bg-ph-danger/10 px-3 py-2.5 text-sm text-ph-ink",
2659
2643
  children: [
2660
- /* @__PURE__ */ jsx17(WarningTriangle, { className: "mt-0.5 h-4 w-4 shrink-0 text-ph-danger" }),
2661
- /* @__PURE__ */ jsxs15("div", { className: "min-w-0 flex-1", children: [
2662
- /* @__PURE__ */ jsx17("p", { className: "font-medium text-ph-danger", children: "Something went wrong" }),
2663
- /* @__PURE__ */ jsx17("p", { className: "mt-0.5 text-ph-subtle", children: error }),
2664
- /* @__PURE__ */ jsx17(
2644
+ /* @__PURE__ */ jsx16(WarningTriangle, { className: "mt-0.5 h-4 w-4 shrink-0 text-ph-danger" }),
2645
+ /* @__PURE__ */ jsxs14("div", { className: "min-w-0 flex-1", children: [
2646
+ /* @__PURE__ */ jsx16("p", { className: "font-medium text-ph-danger", children: "Something went wrong" }),
2647
+ /* @__PURE__ */ jsx16("p", { className: "mt-0.5 text-ph-subtle", children: error }),
2648
+ /* @__PURE__ */ jsx16(
2665
2649
  "button",
2666
2650
  {
2667
2651
  type: "button",
2668
2652
  onClick: retry,
2669
- disabled: loading,
2653
+ disabled: waiting,
2670
2654
  className: "mt-2 inline-flex min-h-8 items-center gap-1.5 rounded-lg border border-ph-border bg-ph-surface px-2.5 text-xs font-medium text-ph-ink transition-colors hover:bg-ph-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-focus disabled:opacity-40",
2671
2655
  children: "Try again"
2672
2656
  }
@@ -2678,20 +2662,20 @@ function SuiteAiPanel({
2678
2662
  ]
2679
2663
  }
2680
2664
  ),
2681
- !atBottom ? /* @__PURE__ */ jsx17("div", { className: "absolute bottom-3 left-1/2 -translate-x-1/2", children: /* @__PURE__ */ jsx17(Tooltip, { content: "Scroll to latest", children: /* @__PURE__ */ jsx17(
2665
+ !atBottom ? /* @__PURE__ */ jsx16("div", { className: "absolute bottom-3 left-1/2 -translate-x-1/2", children: /* @__PURE__ */ jsx16(Tooltip, { content: "Scroll to latest", children: /* @__PURE__ */ jsx16(
2682
2666
  "button",
2683
2667
  {
2684
2668
  type: "button",
2685
2669
  onClick: () => scrollToBottom("smooth"),
2686
2670
  className: "flex h-9 w-9 items-center justify-center rounded-full border border-ph-border bg-ph-surface text-ph-subtle shadow-ph-md transition-colors hover:text-ph-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-focus",
2687
2671
  "aria-label": "Scroll to latest",
2688
- children: /* @__PURE__ */ jsx17(ArrowDown, { className: "h-4 w-4" })
2672
+ children: /* @__PURE__ */ jsx16(ArrowDown, { className: "h-4 w-4" })
2689
2673
  }
2690
2674
  ) }) }) : null
2691
2675
  ] }),
2692
- /* @__PURE__ */ jsx17("div", { className: "px-2 pt-2 pb-[max(2rem,calc(env(safe-area-inset-bottom)+1rem))]", children: /* @__PURE__ */ jsxs15("div", { className: "flex items-end gap-1.5 rounded-2xl border border-ph-border bg-ph-surface px-1.5 py-1 transition-colors focus-within:border-ph-brand/45 focus-within:ring-2 focus-within:ring-ph-focus/35", children: [
2693
- /* @__PURE__ */ jsx17("label", { htmlFor: inputId, className: "sr-only", children: "Ask a question" }),
2694
- /* @__PURE__ */ jsx17(
2676
+ /* @__PURE__ */ jsx16("div", { className: "px-2 pt-2 pb-[max(2rem,calc(env(safe-area-inset-bottom)+1rem))]", children: /* @__PURE__ */ jsxs14("div", { className: "flex items-end gap-1.5 rounded-2xl border border-ph-border bg-ph-surface px-1.5 py-1 transition-colors focus-within:border-ph-brand/45 focus-within:ring-2 focus-within:ring-ph-focus/35", children: [
2677
+ /* @__PURE__ */ jsx16("label", { htmlFor: inputId, className: "sr-only", children: "Ask a question" }),
2678
+ /* @__PURE__ */ jsx16(
2695
2679
  "textarea",
2696
2680
  {
2697
2681
  id: inputId,
@@ -2710,7 +2694,7 @@ function SuiteAiPanel({
2710
2694
  className: "max-h-36 min-h-10 flex-1 resize-none bg-transparent px-1.5 py-2 text-sm leading-relaxed text-ph-ink outline-none placeholder:text-ph-mutedtext"
2711
2695
  }
2712
2696
  ),
2713
- loading ? /* @__PURE__ */ jsx17(Tooltip, { content: "Stop generating", children: /* @__PURE__ */ jsx17(
2697
+ loading ? /* @__PURE__ */ jsx16(Tooltip, { content: "Stop generating", children: /* @__PURE__ */ jsx16(
2714
2698
  "button",
2715
2699
  {
2716
2700
  type: "button",
@@ -2718,9 +2702,18 @@ function SuiteAiPanel({
2718
2702
  "data-test": "ask-ai-stop",
2719
2703
  className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-ph-muted text-ph-ink transition-colors hover:bg-ph-border focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-focus",
2720
2704
  "aria-label": "Stop generating",
2721
- children: /* @__PURE__ */ jsx17(Square, { className: "h-3.5 w-3.5 fill-current" })
2705
+ children: /* @__PURE__ */ jsx16(Square, { className: "h-3.5 w-3.5 fill-current" })
2706
+ }
2707
+ ) }) : isWaitingForReply ? /* @__PURE__ */ jsx16(
2708
+ "span",
2709
+ {
2710
+ className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-ph-muted text-ph-subtle",
2711
+ "data-test": "ask-ai-waiting",
2712
+ role: "status",
2713
+ "aria-label": "Shelly is responding",
2714
+ children: /* @__PURE__ */ jsx16(Spinner, { className: "h-4 w-4 animate-spin" })
2722
2715
  }
2723
- ) }) : /* @__PURE__ */ jsx17(Tooltip, { content: "Send message", children: /* @__PURE__ */ jsx17(
2716
+ ) : /* @__PURE__ */ jsx16(Tooltip, { content: "Send message", children: /* @__PURE__ */ jsx16(
2724
2717
  "button",
2725
2718
  {
2726
2719
  type: "button",
@@ -2729,7 +2722,7 @@ function SuiteAiPanel({
2729
2722
  "data-test": "ask-ai-send",
2730
2723
  className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-ph-brand text-[color:var(--ph-on-accent)] transition-opacity hover:bg-ph-brand-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-focus disabled:opacity-40",
2731
2724
  "aria-label": "Send message",
2732
- children: /* @__PURE__ */ jsx17(ArrowUp, { className: "h-4 w-4" })
2725
+ children: /* @__PURE__ */ jsx16(ArrowUp, { className: "h-4 w-4" })
2733
2726
  }
2734
2727
  ) })
2735
2728
  ] }) })
@@ -2741,7 +2734,7 @@ function SuiteAiPanel({
2741
2734
  // src/suite/components/workspace-switcher.tsx
2742
2735
  import { useState as useState8 } from "react";
2743
2736
  import { Building, Check, NavArrowDown } from "iconoir-react";
2744
- import { Fragment as Fragment6, jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
2737
+ import { Fragment as Fragment6, jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
2745
2738
  function SuiteWorkspaceSwitcher({
2746
2739
  workspaces = [],
2747
2740
  groups,
@@ -2759,7 +2752,7 @@ function SuiteWorkspaceSwitcher({
2759
2752
  var _a;
2760
2753
  const [open, setOpen] = useState8(false);
2761
2754
  const sections = (_a = groups == null ? void 0 : groups.filter((group) => group.workspaces.length > 0)) != null ? _a : workspaces.length > 0 ? [{ id: "workspaces", label: "Switch workspace", workspaces }] : [];
2762
- return /* @__PURE__ */ jsx18(
2755
+ return /* @__PURE__ */ jsx17(
2763
2756
  DropdownMenu2,
2764
2757
  {
2765
2758
  "aria-label": "Switch workspace",
@@ -2770,24 +2763,23 @@ function SuiteWorkspaceSwitcher({
2770
2763
  align: "start",
2771
2764
  open,
2772
2765
  onOpenChange: setOpen,
2773
- trigger: /* @__PURE__ */ jsxs16(
2766
+ trigger: /* @__PURE__ */ jsxs15(
2774
2767
  "span",
2775
2768
  {
2776
- className: cn(
2769
+ className: cn2(
2777
2770
  "flex min-w-0 max-w-full items-center gap-2 rounded-lg border border-ph-border bg-ph-muted text-left transition-colors hover:bg-ph-muted",
2778
2771
  collapsed ? "h-10 w-10 justify-center p-0" : "w-full px-3 py-2",
2779
2772
  open && "border-ph-brand/40"
2780
2773
  ),
2781
2774
  "data-test": "workspace-switcher-trigger",
2782
- "aria-expanded": open,
2783
2775
  children: [
2784
- /* @__PURE__ */ jsx18(Building, { className: "h-4 w-4 shrink-0 text-ph-ink", "aria-hidden": true }),
2785
- !collapsed ? /* @__PURE__ */ jsxs16(Fragment6, { children: [
2786
- /* @__PURE__ */ jsx18("span", { className: "min-w-0 flex-1 truncate text-sm font-semibold text-ph-ink", children: name }),
2787
- /* @__PURE__ */ jsx18(
2776
+ /* @__PURE__ */ jsx17(Building, { className: "h-4 w-4 shrink-0 text-ph-ink", "aria-hidden": true }),
2777
+ !collapsed ? /* @__PURE__ */ jsxs15(Fragment6, { children: [
2778
+ /* @__PURE__ */ jsx17("span", { className: "min-w-0 flex-1 truncate text-sm font-semibold text-ph-ink", children: name }),
2779
+ /* @__PURE__ */ jsx17(
2788
2780
  NavArrowDown,
2789
2781
  {
2790
- className: cn(
2782
+ className: cn2(
2791
2783
  "h-3.5 w-3.5 shrink-0 text-ph-mutedtext transition-transform",
2792
2784
  open && "rotate-180"
2793
2785
  ),
@@ -2798,21 +2790,20 @@ function SuiteWorkspaceSwitcher({
2798
2790
  ]
2799
2791
  }
2800
2792
  ),
2801
- children: /* @__PURE__ */ jsxs16(
2793
+ children: /* @__PURE__ */ jsxs15(
2802
2794
  "div",
2803
2795
  {
2804
2796
  id: "workspace-switcher-menu",
2805
2797
  className: "p-1",
2806
2798
  "data-test": "workspace-switcher-menu",
2807
2799
  children: [
2808
- sections.length === 0 ? /* @__PURE__ */ jsx18("p", { className: "px-3 py-2 text-sm text-ph-mutedtext", children: emptyLabel }) : sections.map((section) => /* @__PURE__ */ jsxs16("div", { children: [
2809
- /* @__PURE__ */ jsx18("p", { className: "px-3 py-2 text-[10px] font-semibold uppercase tracking-[0.14em] text-ph-mutedtext", children: section.label }),
2810
- section.workspaces.map((workspace) => /* @__PURE__ */ jsx18(
2800
+ sections.length === 0 ? /* @__PURE__ */ jsx17("p", { className: "px-3 py-2 text-sm text-ph-mutedtext", children: emptyLabel }) : sections.map((section) => /* @__PURE__ */ jsxs15("div", { children: [
2801
+ /* @__PURE__ */ jsx17("p", { className: "px-3 py-2 text-[10px] font-semibold uppercase tracking-[0.14em] text-ph-mutedtext", children: section.label }),
2802
+ section.workspaces.map((workspace) => /* @__PURE__ */ jsx17(
2811
2803
  DropdownItem2,
2812
2804
  {
2813
2805
  id: `workspace-option-${workspace.id}`,
2814
- role: "option",
2815
- "aria-selected": workspace.id === currentId,
2806
+ "aria-current": workspace.id === currentId ? "true" : void 0,
2816
2807
  "data-test": "workspace-option",
2817
2808
  "data-workspace-id": workspace.id,
2818
2809
  onMouseDown: (event) => event.preventDefault(),
@@ -2821,12 +2812,12 @@ function SuiteWorkspaceSwitcher({
2821
2812
  onSelect(workspace);
2822
2813
  },
2823
2814
  className: appSwitcherMenuItemClass(),
2824
- children: /* @__PURE__ */ jsxs16("span", { className: "flex min-w-0 w-full items-center gap-3", children: [
2825
- /* @__PURE__ */ jsxs16("span", { className: "min-w-0 flex-1", children: [
2826
- /* @__PURE__ */ jsx18("span", { className: "block truncate text-sm font-medium text-ph-ink", children: workspace.name }),
2827
- workspace.description ? /* @__PURE__ */ jsx18("span", { className: "block truncate text-xs text-ph-mutedtext", children: workspace.description }) : null
2815
+ children: /* @__PURE__ */ jsxs15("span", { className: "flex min-w-0 w-full items-center gap-3", children: [
2816
+ /* @__PURE__ */ jsxs15("span", { className: "min-w-0 flex-1", children: [
2817
+ /* @__PURE__ */ jsx17("span", { className: "block truncate text-sm font-medium text-ph-ink", children: workspace.name }),
2818
+ workspace.description ? /* @__PURE__ */ jsx17("span", { className: "block truncate text-xs text-ph-mutedtext", children: workspace.description }) : null
2828
2819
  ] }),
2829
- workspace.id === currentId ? /* @__PURE__ */ jsx18(
2820
+ workspace.id === currentId ? /* @__PURE__ */ jsx17(
2830
2821
  Check,
2831
2822
  {
2832
2823
  className: "h-4 w-4 shrink-0 text-ph-brand",
@@ -2838,7 +2829,7 @@ function SuiteWorkspaceSwitcher({
2838
2829
  workspace.id
2839
2830
  ))
2840
2831
  ] }, section.id)),
2841
- footer ? /* @__PURE__ */ jsx18("div", { className: "mt-1 border-t border-ph-border pt-1", children: footer }) : null
2832
+ footer ? /* @__PURE__ */ jsx17("div", { className: "mt-1 border-t border-ph-border pt-1", children: footer }) : null
2842
2833
  ]
2843
2834
  }
2844
2835
  )
@@ -2846,6 +2837,63 @@ function SuiteWorkspaceSwitcher({
2846
2837
  );
2847
2838
  }
2848
2839
 
2840
+ // src/suite/icons/suite-icon.tsx
2841
+ import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
2842
+ var TODAY_SUN_STYLE = `
2843
+ @media (prefers-reduced-motion: no-preference) {
2844
+ .suite-icon-today-sun-rays {
2845
+ animation: suite-icon-today-sun-spin 18s linear infinite;
2846
+ transform-box: fill-box;
2847
+ transform-origin: center;
2848
+ }
2849
+ }
2850
+ @keyframes suite-icon-today-sun-spin {
2851
+ to { transform: rotate(360deg); }
2852
+ }
2853
+ `;
2854
+ function SuiteIcon({
2855
+ name,
2856
+ size = 24,
2857
+ accent,
2858
+ strokeWidth = 2,
2859
+ animated = true,
2860
+ label,
2861
+ className,
2862
+ style
2863
+ }) {
2864
+ const glyph = SUITE_GLYPHS[name];
2865
+ const accentHex = accent ? APP_ACCENTS[accent].accent : void 0;
2866
+ const mergedStyle = accentHex ? __spreadProps(__spreadValues({}, style), { "--suite-icon-accent": accentHex }) : style;
2867
+ return /* @__PURE__ */ jsxs16(
2868
+ "svg",
2869
+ {
2870
+ width: size,
2871
+ height: size,
2872
+ viewBox: "0 0 24 24",
2873
+ fill: "none",
2874
+ stroke: "currentColor",
2875
+ strokeWidth,
2876
+ strokeLinecap: "round",
2877
+ strokeLinejoin: "round",
2878
+ className: cn2("shrink-0", className),
2879
+ style: mergedStyle,
2880
+ role: label ? "img" : void 0,
2881
+ "aria-label": label,
2882
+ "aria-hidden": label ? void 0 : true,
2883
+ children: [
2884
+ glyph.animatedAccent && animated ? /* @__PURE__ */ jsx18("style", { children: TODAY_SUN_STYLE }) : null,
2885
+ /* @__PURE__ */ jsx18(
2886
+ GlyphParts,
2887
+ {
2888
+ elements: glyph.elements,
2889
+ accentClassName: glyph.animatedAccent && animated ? "suite-icon-today-sun-rays" : void 0
2890
+ }
2891
+ )
2892
+ ]
2893
+ }
2894
+ );
2895
+ }
2896
+
2849
2897
  // src/suite/lib/use-sidebar-width.ts
2850
2898
  import {
2851
2899
  useCallback as useCallback3,
@@ -2863,8 +2911,7 @@ var LEGACY_SIDEBAR_WIDTH_KEYS = [
2863
2911
  "tides-sidebar-width",
2864
2912
  "tt-sidebar-width",
2865
2913
  "kraken-sidebar-width",
2866
- "shellstack-sidebar-width",
2867
- "nakama-sidebar-width"
2914
+ "shellstack-sidebar-width"
2868
2915
  ];
2869
2916
  function isSuiteSidebarKey(storageKey) {
2870
2917
  return storageKey === SUITE_SIDEBAR_WIDTH_KEY || LEGACY_SIDEBAR_WIDTH_KEYS.includes(
@@ -2872,6 +2919,7 @@ function isSuiteSidebarKey(storageKey) {
2872
2919
  );
2873
2920
  }
2874
2921
  function sidebarColumnWidth(width, collapsed, _chatOpen = false) {
2922
+ void _chatOpen;
2875
2923
  if (collapsed) return SIDEBAR_RAIL_WIDTH;
2876
2924
  return width;
2877
2925
  }
@@ -2888,50 +2936,6 @@ function parseWidth(raw) {
2888
2936
  const parsed = Number.parseInt(raw, 10);
2889
2937
  return Number.isNaN(parsed) ? null : parsed;
2890
2938
  }
2891
- function suiteCookieDomainAttr() {
2892
- var _a;
2893
- const host = window.location.hostname;
2894
- if (host === "localhost" || /^\d{1,3}(?:\.\d{1,3}){3}$/.test(host)) {
2895
- return "";
2896
- }
2897
- if (host.endsWith(".localhost")) {
2898
- return "; Domain=.localhost";
2899
- }
2900
- const known = /* @__PURE__ */ new Set([
2901
- "tides",
2902
- "kraken",
2903
- "turtletime",
2904
- "time",
2905
- "nakama",
2906
- "app",
2907
- "shellstack",
2908
- "portal"
2909
- ]);
2910
- const parts = host.split(".");
2911
- if (parts.length >= 3 && known.has((_a = parts[0]) != null ? _a : "")) {
2912
- return `; Domain=.${parts.slice(1).join(".")}`;
2913
- }
2914
- if (parts.length >= 2) return `; Domain=.${parts.slice(1).join(".")}`;
2915
- return "";
2916
- }
2917
- function readCookie(name) {
2918
- const prefix = `${name}=`;
2919
- for (const part of document.cookie.split(";")) {
2920
- const trimmed = part.trim();
2921
- if (trimmed.startsWith(prefix)) {
2922
- return decodeURIComponent(trimmed.slice(prefix.length));
2923
- }
2924
- }
2925
- return null;
2926
- }
2927
- function writeCookie(name, value) {
2928
- const secure = window.location.protocol === "https:" ? "; Secure" : "";
2929
- document.cookie = `${name}=${encodeURIComponent(value)}; Path=/; Max-Age=31536000; SameSite=Lax${suiteCookieDomainAttr()}${secure}`;
2930
- }
2931
- function clearCookie(name) {
2932
- const secure = window.location.protocol === "https:" ? "; Secure" : "";
2933
- document.cookie = `${name}=; Path=/; Max-Age=0; SameSite=Lax${suiteCookieDomainAttr()}${secure}`;
2934
- }
2935
2939
  function readSidebarWidth(storageKey) {
2936
2940
  try {
2937
2941
  if (isSuiteSidebarKey(storageKey)) {
@@ -3087,7 +3091,7 @@ function SuiteSkeleton({
3087
3091
  return /* @__PURE__ */ jsx20(
3088
3092
  "div",
3089
3093
  {
3090
- className: cn("space-y-2", circle ? "flex flex-col items-center" : ""),
3094
+ className: cn2("space-y-2", circle ? "flex flex-col items-center" : ""),
3091
3095
  "aria-hidden": true,
3092
3096
  children: Array.from({ length: lines }).map((_, index) => /* @__PURE__ */ jsx20(
3093
3097
  "div",
@@ -3097,7 +3101,7 @@ function SuiteSkeleton({
3097
3101
  children: /* @__PURE__ */ jsx20(
3098
3102
  "div",
3099
3103
  {
3100
- className: cn(
3104
+ className: cn2(
3101
3105
  "ph-skeleton",
3102
3106
  circle ? "h-10 w-10 rounded-full" : "h-3",
3103
3107
  className
@@ -3121,7 +3125,7 @@ function SuiteSkeletonCard({
3121
3125
  return /* @__PURE__ */ jsxs17(
3122
3126
  "div",
3123
3127
  {
3124
- className: cn(
3128
+ className: cn2(
3125
3129
  "ph-skeleton-card animate-[skeleton-stagger_0.5s_ease-out_both] rounded-2xl border border-ph-border bg-ph-surface p-6 shadow-sm",
3126
3130
  className
3127
3131
  ),
@@ -3164,7 +3168,7 @@ function SuiteSkeletonList({
3164
3168
  className,
3165
3169
  items = 4
3166
3170
  }) {
3167
- return /* @__PURE__ */ jsx20("div", { className: cn("space-y-3", className), "aria-hidden": true, children: Array.from({ length: items }).map((_, index) => /* @__PURE__ */ jsx20(
3171
+ return /* @__PURE__ */ jsx20("div", { className: cn2("space-y-3", className), "aria-hidden": true, children: Array.from({ length: items }).map((_, index) => /* @__PURE__ */ jsx20(
3168
3172
  "div",
3169
3173
  {
3170
3174
  className: "animate-[skeleton-stagger_0.6s_ease-out_both]",
@@ -3191,7 +3195,7 @@ function SuiteEmptyState({
3191
3195
  return /* @__PURE__ */ jsxs17(
3192
3196
  "div",
3193
3197
  {
3194
- className: cn(
3198
+ className: cn2(
3195
3199
  "relative overflow-hidden rounded-2xl border border-ph-border bg-ph-surface text-center",
3196
3200
  size === "sm" ? "px-5 py-8" : "px-6 py-12 sm:px-10 sm:py-16",
3197
3201
  className
@@ -3204,9 +3208,9 @@ function SuiteEmptyState({
3204
3208
  /* @__PURE__ */ jsxs17("div", { className: "relative", children: [
3205
3209
  icon ? /* @__PURE__ */ jsx20("div", { className: "mx-auto mb-4 inline-flex items-center justify-center rounded-2xl bg-ph-muted p-3 shadow-sm ring-1 ring-black/[0.06]", children: icon }) : null,
3206
3210
  /* @__PURE__ */ jsx20(
3207
- "h3",
3211
+ "h2",
3208
3212
  {
3209
- className: cn(
3213
+ className: cn2(
3210
3214
  "font-semibold text-ph-ink",
3211
3215
  size === "sm" ? "text-base" : "text-lg"
3212
3216
  ),
@@ -3237,14 +3241,14 @@ function SuiteSettingsMobileNav({
3237
3241
  {
3238
3242
  "data-test": dataTest,
3239
3243
  "aria-label": ariaLabel,
3240
- className: cn("suite-settings-mobile-nav lg:hidden", className),
3244
+ className: cn2("suite-settings-mobile-nav lg:hidden", className),
3241
3245
  children: /* @__PURE__ */ jsx21("div", { className: "flex snap-x gap-2 overflow-x-auto pb-3 pt-1 scrollbar-hide [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", children: items.map((item) => {
3242
3246
  const Icon = item.icon;
3243
3247
  const active = activeHref === item.href || activeHref.startsWith(`${item.href}/`);
3244
3248
  const iconNode = isValidElement(item.icon) ? item.icon : /* @__PURE__ */ jsx21(
3245
3249
  Icon,
3246
3250
  {
3247
- className: cn(
3251
+ className: cn2(
3248
3252
  "h-4 w-4 shrink-0 transition",
3249
3253
  active ? "text-ph-surface" : "text-ph-mutedtext"
3250
3254
  ),
@@ -3259,7 +3263,7 @@ function SuiteSettingsMobileNav({
3259
3263
  "data-test": item.testId,
3260
3264
  onClick: () => onSelect(item.href),
3261
3265
  "aria-current": active ? "page" : void 0,
3262
- className: cn(
3266
+ className: cn2(
3263
3267
  "group relative flex shrink-0 snap-start items-center gap-2 rounded-full px-3.5 py-2.5 text-sm font-medium transition-colors",
3264
3268
  "min-h-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-brand",
3265
3269
  active ? "bg-ph-ink text-ph-surface shadow-sm" : "bg-ph-surface text-ph-subtle ring-1 ring-ph-border hover:bg-ph-muted hover:text-ph-ink"
@@ -3344,7 +3348,7 @@ function SuiteSidebar({
3344
3348
  "aria-pressed": askAiOpen,
3345
3349
  "aria-label": askAiOpen ? "Back to navigation" : "Shelly AI",
3346
3350
  onClick: toggleAskAi,
3347
- className: cn(
3351
+ className: cn2(
3348
3352
  "inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-lg transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ph-focus-ring",
3349
3353
  askAiOpen ? "bg-ph-brand/10 text-ph-brand" : "text-ph-mutedtext hover:bg-ph-muted hover:text-ph-ink"
3350
3354
  ),
@@ -3356,7 +3360,7 @@ function SuiteSidebar({
3356
3360
  "div",
3357
3361
  {
3358
3362
  "data-suite-chat-open": "",
3359
- className: cn(
3363
+ className: cn2(
3360
3364
  "flex h-full w-full min-w-0 flex-col text-ph-ink",
3361
3365
  surface ? "bg-ph-surface" : "bg-ph-canvas",
3362
3366
  className
@@ -3365,12 +3369,12 @@ function SuiteSidebar({
3365
3369
  /* @__PURE__ */ jsxs19(
3366
3370
  "div",
3367
3371
  {
3368
- className: cn(
3372
+ className: cn2(
3369
3373
  "flex h-14 shrink-0 items-center gap-1 border-b border-ph-border px-2",
3370
3374
  surface ? "bg-ph-surface" : "bg-ph-canvas"
3371
3375
  ),
3372
3376
  children: [
3373
- /* @__PURE__ */ jsx22(Tooltip, { content: "Back to navigation", children: /* @__PURE__ */ jsx22(
3377
+ /* @__PURE__ */ jsx22(
3374
3378
  "button",
3375
3379
  {
3376
3380
  type: "button",
@@ -3380,7 +3384,7 @@ function SuiteSidebar({
3380
3384
  className: "inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-lg text-ph-subtle transition-colors hover:bg-ph-muted hover:text-ph-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-brand",
3381
3385
  children: /* @__PURE__ */ jsx22(NavArrowLeft, { className: "h-4 w-4", "aria-hidden": true })
3382
3386
  }
3383
- ) }),
3387
+ ),
3384
3388
  /* @__PURE__ */ jsx22("span", { className: "min-w-0 flex-1 truncate text-sm font-semibold text-ph-ink", children: "Shelly AI" })
3385
3389
  ]
3386
3390
  }
@@ -3393,7 +3397,7 @@ function SuiteSidebar({
3393
3397
  return /* @__PURE__ */ jsxs19(
3394
3398
  "div",
3395
3399
  {
3396
- className: cn(
3400
+ className: cn2(
3397
3401
  "flex h-full w-full min-w-0 flex-col text-ph-ink",
3398
3402
  surface ? "bg-ph-surface" : "bg-ph-canvas",
3399
3403
  className
@@ -3402,13 +3406,13 @@ function SuiteSidebar({
3402
3406
  appSwitcher || notificationBell ? /* @__PURE__ */ jsxs19(
3403
3407
  "div",
3404
3408
  {
3405
- className: cn(
3409
+ className: cn2(
3406
3410
  "flex shrink-0 border-b border-ph-border",
3407
3411
  surface ? "bg-ph-surface" : "bg-ph-canvas",
3408
3412
  collapsed ? "flex-col items-center gap-1 px-1 py-2" : "h-14 items-center justify-between gap-2 px-3"
3409
3413
  ),
3410
3414
  children: [
3411
- /* @__PURE__ */ jsx22("div", { className: cn("min-w-0", collapsed ? "shrink-0" : "flex-1"), children: renderNode(appSwitcher, collapsed) }),
3415
+ /* @__PURE__ */ jsx22("div", { className: cn2("min-w-0", collapsed ? "shrink-0" : "flex-1"), children: renderNode(appSwitcher, collapsed) }),
3412
3416
  collapsed ? null : /* @__PURE__ */ jsx22("div", { className: "shrink-0", children: renderNode(notificationBell, collapsed) })
3413
3417
  ]
3414
3418
  }
@@ -3416,14 +3420,23 @@ function SuiteSidebar({
3416
3420
  /* @__PURE__ */ jsxs19(
3417
3421
  "div",
3418
3422
  {
3419
- className: cn(
3423
+ className: cn2(
3420
3424
  "flex min-h-0 flex-1 flex-col",
3421
3425
  surface ? "bg-ph-surface" : "bg-ph-canvas",
3422
3426
  chatOpen ? "min-h-0" : "overflow-y-auto",
3423
- collapsed ? "px-1.5 py-2" : "p-2"
3427
+ collapsed ? "px-1.5 py-2" : "p-3"
3424
3428
  ),
3425
3429
  children: [
3426
- /* @__PURE__ */ jsx22("div", { className: cn("mb-3 w-full shrink-0", collapsed && "flex justify-center"), children: renderNode(contextSwitcher, collapsed) }),
3430
+ contextSwitcher ? /* @__PURE__ */ jsx22(
3431
+ "div",
3432
+ {
3433
+ className: cn2(
3434
+ "mb-4 w-full shrink-0",
3435
+ collapsed && "flex justify-center"
3436
+ ),
3437
+ children: renderNode(contextSwitcher, collapsed)
3438
+ }
3439
+ ) : null,
3427
3440
  chatOpen ? /* @__PURE__ */ jsxs19("div", { className: "flex min-h-0 flex-1 flex-col", children: [
3428
3441
  /* @__PURE__ */ jsxs19("div", { className: "mb-2 flex shrink-0 items-center gap-1", children: [
3429
3442
  /* @__PURE__ */ jsxs19(
@@ -3443,7 +3456,7 @@ function SuiteSidebar({
3443
3456
  ] }),
3444
3457
  /* @__PURE__ */ jsx22("div", { className: "min-h-0 flex-1", children: askAi })
3445
3458
  ] }) : /* @__PURE__ */ jsxs19(Fragment7, { children: [
3446
- /* @__PURE__ */ jsx22("nav", { "aria-label": "Pages", className: "shrink-0 space-y-0.5", children: /* @__PURE__ */ jsx22("div", { className: "space-y-0.5", children: navItems.map((item) => {
3459
+ /* @__PURE__ */ jsx22("nav", { "aria-label": "Pages", className: "shrink-0 space-y-1", children: /* @__PURE__ */ jsx22("div", { className: "space-y-1", children: navItems.map((item) => {
3447
3460
  var _a;
3448
3461
  const Icon = item.icon;
3449
3462
  const active = Boolean(item.active);
@@ -3455,7 +3468,7 @@ function SuiteSidebar({
3455
3468
  "data-test": (_a = item.dataTest) != null ? _a : "nav-link",
3456
3469
  "aria-current": active ? "page" : void 0,
3457
3470
  onClick: item.onClick,
3458
- className: cn(
3471
+ className: cn2(
3459
3472
  "group relative flex min-h-11 touch-manipulation items-center gap-2.5 rounded-[var(--ph-radius-app)] text-sm font-medium transition-colors",
3460
3473
  active ? "bg-ph-muted" : "text-ph-subtle hover:bg-ph-muted hover:text-ph-ink",
3461
3474
  collapsed ? "mx-auto size-11 shrink-0 justify-center gap-0 px-0 py-0" : "w-full px-2.5 py-2"
@@ -3464,7 +3477,7 @@ function SuiteSidebar({
3464
3477
  /* @__PURE__ */ jsx22(
3465
3478
  "span",
3466
3479
  {
3467
- className: cn(
3480
+ className: cn2(
3468
3481
  "relative flex h-4 w-4 shrink-0 items-center justify-center",
3469
3482
  item.iconClassName
3470
3483
  ),
@@ -3481,7 +3494,7 @@ function SuiteSidebar({
3481
3494
  /* @__PURE__ */ jsx22(
3482
3495
  "span",
3483
3496
  {
3484
- className: cn(
3497
+ className: cn2(
3485
3498
  "relative truncate",
3486
3499
  active ? "text-ph-ink" : "text-ph-subtle group-hover:text-ph-ink",
3487
3500
  collapsed && "sr-only"
@@ -3511,7 +3524,7 @@ function SuiteSidebar({
3511
3524
  /* @__PURE__ */ jsx22(
3512
3525
  "div",
3513
3526
  {
3514
- className: cn(
3527
+ className: cn2(
3515
3528
  "shrink-0 border-t border-ph-border",
3516
3529
  surface ? "bg-ph-surface" : "bg-ph-canvas",
3517
3530
  collapsed ? "p-1.5" : "p-3"
@@ -3519,20 +3532,14 @@ function SuiteSidebar({
3519
3532
  children: /* @__PURE__ */ jsxs19(
3520
3533
  "div",
3521
3534
  {
3522
- className: cn(
3535
+ className: cn2(
3523
3536
  "flex items-center gap-2",
3524
3537
  collapsed ? "flex-col items-center justify-center [&>div]:w-auto" : "w-full min-w-0"
3525
3538
  ),
3526
3539
  children: [
3527
3540
  renderNode(userMenu, collapsed),
3528
- showAskAi ? /* @__PURE__ */ jsx22(
3529
- "div",
3530
- {
3531
- className: cn("shrink-0", collapsed ? "mt-2" : "ml-auto"),
3532
- children: /* @__PURE__ */ jsx22(Tooltip, { content: "Shelly AI", side: collapsed ? "right" : "top", children: askAiButton })
3533
- }
3534
- ) : footerExtras ? /* @__PURE__ */ jsx22("div", { className: cn("shrink-0", collapsed ? "mt-2" : "ml-auto"), children: renderNode(footerExtras, collapsed) }) : null,
3535
- showAskAi && footerExtras ? /* @__PURE__ */ jsx22("div", { className: cn("shrink-0", collapsed && "mt-2"), children: renderNode(footerExtras, collapsed) }) : null
3541
+ showAskAi ? /* @__PURE__ */ jsx22("div", { className: cn2("shrink-0", collapsed ? "mt-2" : "ml-auto"), children: /* @__PURE__ */ jsx22(Tooltip, { content: "Shelly AI", side: collapsed ? "right" : "top", children: askAiButton }) }) : footerExtras ? /* @__PURE__ */ jsx22("div", { className: cn2("shrink-0", collapsed ? "mt-2" : "ml-auto"), children: renderNode(footerExtras, collapsed) }) : null,
3542
+ showAskAi && footerExtras ? /* @__PURE__ */ jsx22("div", { className: cn2("shrink-0", collapsed && "mt-2"), children: renderNode(footerExtras, collapsed) }) : null
3536
3543
  ]
3537
3544
  }
3538
3545
  )
@@ -3562,7 +3569,7 @@ function SuiteAppLayout({
3562
3569
  "div",
3563
3570
  {
3564
3571
  "data-test": "app-shell",
3565
- className: cn(
3572
+ className: cn2(
3566
3573
  "suite-app-layout flex h-dvh overflow-hidden",
3567
3574
  className
3568
3575
  ),
@@ -3570,6 +3577,7 @@ function SuiteAppLayout({
3570
3577
  /* @__PURE__ */ jsxs20(
3571
3578
  "aside",
3572
3579
  {
3580
+ "aria-label": "Sidebar",
3573
3581
  className: "relative hidden shrink-0 flex-col overflow-visible border-r border-ph-border ease-out lg:flex",
3574
3582
  style: { width: `${sidebarWidth}px` },
3575
3583
  "data-collapsed": collapsed ? "true" : "false",
@@ -3581,6 +3589,10 @@ function SuiteAppLayout({
3581
3589
  role: "separator",
3582
3590
  "aria-orientation": "vertical",
3583
3591
  "aria-label": "Resize sidebar",
3592
+ "aria-valuenow": sidebarWidth,
3593
+ "aria-valuemin": SIDEBAR_RAIL_WIDTH,
3594
+ "aria-valuemax": SIDEBAR_MAX_WIDTH,
3595
+ "aria-valuetext": `${sidebarWidth} pixels`,
3584
3596
  "data-test": "sidebar-resize-handle",
3585
3597
  tabIndex: onResizeBy ? 0 : void 0,
3586
3598
  onPointerDown: onStartResize,
@@ -3597,7 +3609,7 @@ function SuiteAppLayout({
3597
3609
  onResizeBy == null ? void 0 : onResizeBy(16);
3598
3610
  }
3599
3611
  },
3600
- className: "absolute inset-y-0 right-0 z-20 w-2 cursor-col-resize touch-none transition-colors hover:bg-[color-mix(in_oklab,var(--ph-accent)_30%,transparent)]"
3612
+ className: "absolute inset-y-0 right-0 z-20 w-2 cursor-col-resize touch-none transition-colors before:absolute before:-left-2 before:-right-2 before:inset-y-0 before:content-[''] hover:bg-[color-mix(in_oklab,var(--ph-accent)_30%,transparent)]"
3601
3613
  }
3602
3614
  ) : null
3603
3615
  ]
@@ -3609,10 +3621,10 @@ function SuiteAppLayout({
3609
3621
  "main",
3610
3622
  {
3611
3623
  id: "main-content",
3612
- tabIndex: -1,
3624
+ tabIndex: 0,
3613
3625
  "data-lock-scroll": lockMainScroll ? "true" : void 0,
3614
- className: cn(
3615
- "flex min-h-0 min-w-0 flex-1 flex-col overflow-x-hidden overscroll-contain bg-ph-canvas focus:outline-none",
3626
+ className: cn2(
3627
+ "flex min-h-0 min-w-0 flex-1 flex-col overflow-x-hidden overscroll-contain bg-ph-canvas focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ph-focus",
3616
3628
  "suite-app-layout__main",
3617
3629
  lockMainScroll ? "overflow-hidden" : "overflow-y-auto"
3618
3630
  ),
@@ -3625,6 +3637,1973 @@ function SuiteAppLayout({
3625
3637
  }
3626
3638
  );
3627
3639
  }
3640
+
3641
+ // src/suite/components/suite-integration-picker.tsx
3642
+ import {
3643
+ useEffect as useEffect8,
3644
+ useMemo,
3645
+ useRef as useRef3,
3646
+ useState as useState10
3647
+ } from "react";
3648
+ import {
3649
+ EvPlug as Plug,
3650
+ Filter,
3651
+ NavArrowDown as NavArrowDown2,
3652
+ NavArrowUp,
3653
+ Search,
3654
+ Xmark
3655
+ } from "iconoir-react";
3656
+ import { Fragment as Fragment8, jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
3657
+ var DESCRIPTION_LIMIT = 90;
3658
+ function IntegrationSkeletonCard() {
3659
+ return /* @__PURE__ */ jsxs21(
3660
+ "div",
3661
+ {
3662
+ className: "flex min-h-36 min-w-0 animate-pulse flex-col justify-between rounded-xl border border-ph-border bg-ph-surface p-4",
3663
+ "aria-hidden": "true",
3664
+ children: [
3665
+ /* @__PURE__ */ jsxs21("div", { className: "flex items-start gap-3", children: [
3666
+ /* @__PURE__ */ jsx24("div", { className: "h-10 w-10 shrink-0 rounded-lg bg-ph-muted" }),
3667
+ /* @__PURE__ */ jsxs21("div", { className: "min-w-0 flex-1 space-y-2 pt-1", children: [
3668
+ /* @__PURE__ */ jsx24("div", { className: "h-4 w-3/5 rounded bg-ph-muted" }),
3669
+ /* @__PURE__ */ jsx24("div", { className: "h-3 w-full rounded bg-ph-muted" }),
3670
+ /* @__PURE__ */ jsx24("div", { className: "h-3 w-4/5 rounded bg-ph-muted" })
3671
+ ] })
3672
+ ] }),
3673
+ /* @__PURE__ */ jsx24("div", { className: "mt-3 h-9 w-20 rounded bg-ph-muted" })
3674
+ ]
3675
+ }
3676
+ );
3677
+ }
3678
+ var SKELETON_COUNT = 6;
3679
+ var AUTH_SCHEME_LABELS = {
3680
+ API_KEY: "API key",
3681
+ BASIC_AUTH: "Basic auth",
3682
+ BEARER_TOKEN: "Bearer token",
3683
+ OAUTH2: "OAuth 2.0"
3684
+ };
3685
+ function authSchemeLabel(scheme) {
3686
+ var _a;
3687
+ const normalised = scheme.trim().toUpperCase();
3688
+ return (_a = AUTH_SCHEME_LABELS[normalised]) != null ? _a : normalised.replace(/[-_]/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase());
3689
+ }
3690
+ function authSchemesFor(item) {
3691
+ var _a;
3692
+ return Array.from(
3693
+ new Set(
3694
+ ((_a = item.authSchemes) != null ? _a : []).map((scheme) => scheme.trim().toUpperCase()).filter(Boolean)
3695
+ )
3696
+ );
3697
+ }
3698
+ var CATEGORY_APP_AFFINITY = {
3699
+ calendar: ["turtletime", "tides"],
3700
+ email: ["turtletime", "tides"],
3701
+ code: ["tides", "kraken"],
3702
+ chat: ["tides", "kraken"],
3703
+ documents: ["kraken"],
3704
+ notes: ["kraken"],
3705
+ knowledge: ["kraken"],
3706
+ file_storage: ["kraken"],
3707
+ crm: ["shellstack", "tides"],
3708
+ finance: ["shellstack", "tides"],
3709
+ payment: ["shellstack", "tides"],
3710
+ monitoring: ["tides", "kraken"],
3711
+ design: ["tides", "kraken"],
3712
+ support: ["tides", "shellstack"],
3713
+ ticketing: ["tides", "kraken"]
3714
+ };
3715
+ var DEFAULT_APP_AFFINITY = ["tides", "kraken"];
3716
+ function suiteAppsForIntegration(categories) {
3717
+ var _a;
3718
+ const apps = /* @__PURE__ */ new Set();
3719
+ for (const category of categories != null ? categories : []) {
3720
+ for (const app of (_a = CATEGORY_APP_AFFINITY[category.trim().toLowerCase()]) != null ? _a : []) {
3721
+ apps.add(app);
3722
+ }
3723
+ }
3724
+ return apps.size > 0 ? SUITE_APPS2.filter((app) => apps.has(app.slug)).map((app) => app.slug) : [...DEFAULT_APP_AFFINITY];
3725
+ }
3726
+ function SuiteIntegrationPicker({
3727
+ open,
3728
+ items,
3729
+ connectedItems = [],
3730
+ loading = false,
3731
+ catalogLoading = false,
3732
+ loadingMore = false,
3733
+ hasMore = false,
3734
+ onEndReached,
3735
+ search: controlledSearch,
3736
+ onSearchChange,
3737
+ category: controlledCategory,
3738
+ categories: controlledCategories,
3739
+ onCategoryChange,
3740
+ onClose,
3741
+ onConnect,
3742
+ onFetchAuthFields,
3743
+ onDisconnect,
3744
+ title = "Integrate an app",
3745
+ description = "Connect an app to this workspace securely.",
3746
+ dataTest = "suite-integration-picker"
3747
+ }) {
3748
+ const [query, setQuery] = useState10("");
3749
+ const [category, setCategory] = useState10("all");
3750
+ const [categoryQuery, setCategoryQuery] = useState10("");
3751
+ const [categoryMenuOpen, setCategoryMenuOpen] = useState10(false);
3752
+ const [expanded, setExpanded] = useState10(null);
3753
+ const categoryMenuRef = useRef3(null);
3754
+ const categoryTriggerRef = useRef3(null);
3755
+ const categorySearchRef = useRef3(null);
3756
+ const categoryOptionRefs = useRef3({});
3757
+ const pendingCategoryFocus = useRef3(
3758
+ null
3759
+ );
3760
+ const scrollViewportRef = useRef3(null);
3761
+ const loadMoreSentinelRef = useRef3(null);
3762
+ const loadMoreInFlightRef = useRef3(false);
3763
+ const authRequestRef = useRef3(0);
3764
+ const [methodItem, setMethodItem] = useState10(null);
3765
+ const [authItem, setAuthItem] = useState10(null);
3766
+ const [authValues, setAuthValues] = useState10({});
3767
+ const [authLoading, setAuthLoading] = useState10(false);
3768
+ const [authSubmitting, setAuthSubmitting] = useState10(false);
3769
+ const [authError, setAuthError] = useState10(null);
3770
+ const [connectionError, setConnectionError] = useState10(null);
3771
+ const [itemToDisconnect, setItemToDisconnect] = useState10(null);
3772
+ const [disconnecting, setDisconnecting] = useState10(false);
3773
+ const [disconnectError, setDisconnectError] = useState10(null);
3774
+ const itemCategories = useMemo(
3775
+ () => Array.from(
3776
+ new Set(items.flatMap((item) => {
3777
+ var _a;
3778
+ return (_a = item.categories) != null ? _a : [];
3779
+ }))
3780
+ ).sort(),
3781
+ [items]
3782
+ );
3783
+ const categories = controlledCategories != null ? controlledCategories : itemCategories;
3784
+ const activeSearch = controlledSearch != null ? controlledSearch : query;
3785
+ const activeCategory = controlledCategory != null ? controlledCategory : category;
3786
+ const categoryLabel = (value) => value.replace(/[-_]/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase());
3787
+ const filtered = onSearchChange || onCategoryChange ? items : items.filter((item) => {
3788
+ var _a;
3789
+ return item.label.toLowerCase().includes(activeSearch.trim().toLowerCase()) && (activeCategory === "all" || ((_a = item.categories) != null ? _a : []).includes(activeCategory));
3790
+ });
3791
+ const visibleCategories = categories.filter(
3792
+ (value) => categoryLabel(value).toLowerCase().includes(categoryQuery.trim().toLowerCase())
3793
+ );
3794
+ const categoryValues = ["all", ...visibleCategories];
3795
+ const focusableCategory = categoryValues.includes(activeCategory) ? activeCategory : "all";
3796
+ function focusCategory(value) {
3797
+ pendingCategoryFocus.current = value;
3798
+ }
3799
+ function openCategoryMenu(focus = null) {
3800
+ setCategoryQuery("");
3801
+ if (focus) focusCategory(focus);
3802
+ setCategoryMenuOpen(true);
3803
+ }
3804
+ function closeCategoryMenu(restoreFocus = false) {
3805
+ if (restoreFocus) focusCategory("trigger");
3806
+ setCategoryMenuOpen(false);
3807
+ }
3808
+ function selectCategory(value) {
3809
+ setCategory(value);
3810
+ onCategoryChange == null ? void 0 : onCategoryChange(value);
3811
+ closeCategoryMenu(true);
3812
+ }
3813
+ function moveCategoryFocus(event, value) {
3814
+ var _a;
3815
+ const index = categoryValues.indexOf(value);
3816
+ let nextIndex = null;
3817
+ if (event.key === "ArrowDown") nextIndex = (index + 1) % categoryValues.length;
3818
+ else if (event.key === "ArrowUp")
3819
+ nextIndex = (index - 1 + categoryValues.length) % categoryValues.length;
3820
+ else if (event.key === "Home") nextIndex = 0;
3821
+ else if (event.key === "End") nextIndex = categoryValues.length - 1;
3822
+ if (nextIndex === null) return;
3823
+ event.preventDefault();
3824
+ (_a = categoryOptionRefs.current[categoryValues[nextIndex]]) == null ? void 0 : _a.focus();
3825
+ }
3826
+ function handleCategoryTriggerKeyDown(event) {
3827
+ var _a;
3828
+ if (event.key === "ArrowDown") {
3829
+ event.preventDefault();
3830
+ openCategoryMenu(activeCategory === "all" ? "all" : activeCategory);
3831
+ } else if (event.key === "ArrowUp") {
3832
+ event.preventDefault();
3833
+ openCategoryMenu((_a = categoryValues.at(-1)) != null ? _a : "all");
3834
+ } else if (event.key === "Enter" || event.key === " ") {
3835
+ event.preventDefault();
3836
+ openCategoryMenu("search");
3837
+ }
3838
+ }
3839
+ function resetAuthForm() {
3840
+ authRequestRef.current += 1;
3841
+ setAuthItem(null);
3842
+ setAuthValues({});
3843
+ setAuthLoading(false);
3844
+ setAuthError(null);
3845
+ }
3846
+ function closeAuthForm() {
3847
+ if (authSubmitting) return;
3848
+ resetAuthForm();
3849
+ }
3850
+ async function prepareConnection(item, scheme) {
3851
+ var _a;
3852
+ setMethodItem(null);
3853
+ setAuthError(null);
3854
+ setConnectionError(null);
3855
+ setAuthValues({});
3856
+ if (!onFetchAuthFields) {
3857
+ try {
3858
+ await onConnect(item, { auth_scheme: scheme });
3859
+ } catch (cause) {
3860
+ setConnectionError(
3861
+ cause instanceof Error ? cause.message : "Could not connect the app."
3862
+ );
3863
+ }
3864
+ return;
3865
+ }
3866
+ const requestId = authRequestRef.current + 1;
3867
+ authRequestRef.current = requestId;
3868
+ setAuthItem({ item, scheme, fields: [] });
3869
+ setAuthLoading(true);
3870
+ try {
3871
+ const details = await onFetchAuthFields(item, scheme);
3872
+ if (requestId !== authRequestRef.current) return;
3873
+ const resolvedScheme = (_a = details.auth_scheme) != null ? _a : scheme;
3874
+ if (details.managed) {
3875
+ setAuthItem(null);
3876
+ await onConnect(item, { auth_scheme: resolvedScheme });
3877
+ } else if (details.fields.length === 0) {
3878
+ setAuthItem(null);
3879
+ await onConnect(item, {
3880
+ auth_scheme: resolvedScheme,
3881
+ auth_fields: {}
3882
+ });
3883
+ } else {
3884
+ setAuthItem({ item, scheme: resolvedScheme, fields: details.fields });
3885
+ }
3886
+ } catch (cause) {
3887
+ if (requestId === authRequestRef.current) {
3888
+ const message = cause instanceof Error ? cause.message : "Could not load authentication details.";
3889
+ setAuthError(message);
3890
+ setConnectionError(message);
3891
+ }
3892
+ } finally {
3893
+ if (requestId === authRequestRef.current) setAuthLoading(false);
3894
+ }
3895
+ }
3896
+ function connectItem(item) {
3897
+ setConnectionError(null);
3898
+ const schemes = authSchemesFor(item);
3899
+ if (schemes.length > 1) {
3900
+ setMethodItem(item);
3901
+ return;
3902
+ }
3903
+ if (schemes.length === 1) {
3904
+ void prepareConnection(item, schemes[0]);
3905
+ return;
3906
+ }
3907
+ void (async () => {
3908
+ try {
3909
+ await onConnect(item);
3910
+ } catch (cause) {
3911
+ setConnectionError(
3912
+ cause instanceof Error ? cause.message : "Could not connect the app."
3913
+ );
3914
+ }
3915
+ })();
3916
+ }
3917
+ function requestDisconnect(item) {
3918
+ setDisconnectError(null);
3919
+ setItemToDisconnect(item);
3920
+ }
3921
+ async function disconnectItem() {
3922
+ if (!onDisconnect || !itemToDisconnect) return;
3923
+ setDisconnecting(true);
3924
+ setDisconnectError(null);
3925
+ try {
3926
+ await onDisconnect(itemToDisconnect);
3927
+ setItemToDisconnect(null);
3928
+ } catch (cause) {
3929
+ setDisconnectError(
3930
+ cause instanceof Error ? cause.message : "Could not disconnect the app."
3931
+ );
3932
+ } finally {
3933
+ setDisconnecting(false);
3934
+ }
3935
+ }
3936
+ async function submitAuthForm(event) {
3937
+ event.preventDefault();
3938
+ if (!authItem) return;
3939
+ setAuthSubmitting(true);
3940
+ setAuthError(null);
3941
+ try {
3942
+ await onConnect(authItem.item, {
3943
+ auth_scheme: authItem.scheme,
3944
+ auth_fields: authValues
3945
+ });
3946
+ resetAuthForm();
3947
+ } catch (cause) {
3948
+ setAuthError(
3949
+ cause instanceof Error ? cause.message : "Could not connect the app."
3950
+ );
3951
+ } finally {
3952
+ setAuthSubmitting(false);
3953
+ }
3954
+ }
3955
+ useEffect8(() => {
3956
+ if (!categoryMenuOpen) return;
3957
+ const handlePointerDown = (event) => {
3958
+ var _a;
3959
+ if (!((_a = categoryMenuRef.current) == null ? void 0 : _a.contains(event.target))) {
3960
+ closeCategoryMenu();
3961
+ }
3962
+ };
3963
+ const handleKeyDown = (event) => {
3964
+ if (event.key === "Escape") closeCategoryMenu(true);
3965
+ };
3966
+ document.addEventListener("pointerdown", handlePointerDown);
3967
+ document.addEventListener("keydown", handleKeyDown);
3968
+ return () => {
3969
+ document.removeEventListener("pointerdown", handlePointerDown);
3970
+ document.removeEventListener("keydown", handleKeyDown);
3971
+ };
3972
+ }, [categoryMenuOpen]);
3973
+ useEffect8(() => {
3974
+ var _a, _b, _c;
3975
+ const target = pendingCategoryFocus.current;
3976
+ if (!target) return;
3977
+ pendingCategoryFocus.current = null;
3978
+ if (target === "trigger") (_a = categoryTriggerRef.current) == null ? void 0 : _a.focus();
3979
+ else if (target === "search") (_b = categorySearchRef.current) == null ? void 0 : _b.focus();
3980
+ else (_c = categoryOptionRefs.current[target]) == null ? void 0 : _c.focus();
3981
+ }, [activeCategory, categoryMenuOpen, categoryQuery, visibleCategories]);
3982
+ useEffect8(() => {
3983
+ if (!loadingMore) loadMoreInFlightRef.current = false;
3984
+ }, [loadingMore]);
3985
+ useEffect8(() => {
3986
+ const root = scrollViewportRef.current;
3987
+ const sentinel = loadMoreSentinelRef.current;
3988
+ if (!open || !root || !sentinel || !hasMore || !onEndReached || loading || catalogLoading || loadingMore) {
3989
+ return;
3990
+ }
3991
+ const observer = new IntersectionObserver(
3992
+ ([entry]) => {
3993
+ if (!entry.isIntersecting || loadMoreInFlightRef.current) return;
3994
+ loadMoreInFlightRef.current = true;
3995
+ observer.unobserve(entry.target);
3996
+ onEndReached();
3997
+ },
3998
+ { root, rootMargin: "0px 0px 80px", threshold: 0 }
3999
+ );
4000
+ observer.observe(sentinel);
4001
+ return () => observer.disconnect();
4002
+ }, [catalogLoading, hasMore, loading, loadingMore, onEndReached, open]);
4003
+ return /* @__PURE__ */ jsxs21(Fragment8, { children: [
4004
+ /* @__PURE__ */ jsx24(
4005
+ Modal,
4006
+ {
4007
+ open,
4008
+ onClose,
4009
+ title,
4010
+ description,
4011
+ size: "xl",
4012
+ dataTest,
4013
+ bodyClassName: "!overflow-hidden",
4014
+ children: /* @__PURE__ */ jsxs21("div", { className: "space-y-4", children: [
4015
+ connectionError ? /* @__PURE__ */ jsx24("p", { className: "text-sm text-ph-danger", role: "alert", children: connectionError }) : null,
4016
+ /* @__PURE__ */ jsxs21("div", { className: "grid gap-4 md:grid-cols-2", children: [
4017
+ /* @__PURE__ */ jsxs21("div", { className: "relative", children: [
4018
+ /* @__PURE__ */ jsx24(
4019
+ Search,
4020
+ {
4021
+ className: "pointer-events-none absolute left-3 top-1/2 z-10 h-4 w-4 -translate-y-1/2 text-ph-subtle",
4022
+ "aria-hidden": true
4023
+ }
4024
+ ),
4025
+ /* @__PURE__ */ jsx24(
4026
+ Input,
4027
+ {
4028
+ value: activeSearch,
4029
+ onChange: (event) => {
4030
+ setQuery(event.target.value);
4031
+ onSearchChange == null ? void 0 : onSearchChange(event.target.value);
4032
+ },
4033
+ placeholder: "Search apps...",
4034
+ "aria-label": "Search apps",
4035
+ className: "pl-10"
4036
+ }
4037
+ )
4038
+ ] }),
4039
+ /* @__PURE__ */ jsxs21("div", { ref: categoryMenuRef, className: "relative", children: [
4040
+ /* @__PURE__ */ jsxs21(
4041
+ "button",
4042
+ {
4043
+ ref: categoryTriggerRef,
4044
+ id: `${dataTest}-category`,
4045
+ type: "button",
4046
+ className: "ph-input flex w-full items-center justify-between text-left",
4047
+ "aria-haspopup": "listbox",
4048
+ "aria-expanded": categoryMenuOpen,
4049
+ "aria-controls": categoryMenuOpen ? `${dataTest}-category-options` : void 0,
4050
+ "aria-label": "Filter by category",
4051
+ onClick: () => {
4052
+ if (categoryMenuOpen) closeCategoryMenu();
4053
+ else openCategoryMenu();
4054
+ },
4055
+ onKeyDown: handleCategoryTriggerKeyDown,
4056
+ children: [
4057
+ /* @__PURE__ */ jsxs21("span", { className: "flex items-center gap-2", children: [
4058
+ /* @__PURE__ */ jsx24(
4059
+ Filter,
4060
+ {
4061
+ className: "h-4 w-4 shrink-0 text-ph-subtle",
4062
+ "aria-hidden": true
4063
+ }
4064
+ ),
4065
+ /* @__PURE__ */ jsx24("span", { children: activeCategory === "all" ? "All apps" : categoryLabel(activeCategory) })
4066
+ ] }),
4067
+ /* @__PURE__ */ jsx24(
4068
+ NavArrowDown2,
4069
+ {
4070
+ className: `h-4 w-4 transition-transform ${categoryMenuOpen ? "rotate-180" : ""}`,
4071
+ "aria-hidden": true
4072
+ }
4073
+ )
4074
+ ]
4075
+ }
4076
+ ),
4077
+ categoryMenuOpen ? /* @__PURE__ */ jsxs21(
4078
+ "div",
4079
+ {
4080
+ className: "absolute z-20 mt-2 max-h-[min(22rem,calc(100dvh-12rem))] w-full max-w-full overflow-hidden rounded-lg border border-ph-border bg-ph-surface p-2 shadow-lg",
4081
+ children: [
4082
+ /* @__PURE__ */ jsx24(
4083
+ Input,
4084
+ {
4085
+ ref: categorySearchRef,
4086
+ value: categoryQuery,
4087
+ onChange: (event) => setCategoryQuery(event.target.value),
4088
+ placeholder: "Search categories...",
4089
+ "aria-label": "Search categories",
4090
+ onKeyDown: (event) => {
4091
+ var _a;
4092
+ if (event.key === "ArrowDown") {
4093
+ event.preventDefault();
4094
+ (_a = categoryOptionRefs.current[categoryValues[0]]) == null ? void 0 : _a.focus();
4095
+ } else if (event.key === "Escape") {
4096
+ event.preventDefault();
4097
+ closeCategoryMenu(true);
4098
+ }
4099
+ }
4100
+ }
4101
+ ),
4102
+ /* @__PURE__ */ jsx24(
4103
+ "div",
4104
+ {
4105
+ id: `${dataTest}-category-options`,
4106
+ role: "listbox",
4107
+ "aria-label": "Integration categories",
4108
+ className: "mt-2 max-h-52 overflow-y-auto",
4109
+ "data-test": "integration-category-options",
4110
+ children: categoryValues.map((value) => /* @__PURE__ */ jsx24(
4111
+ "button",
4112
+ {
4113
+ type: "button",
4114
+ role: "option",
4115
+ "aria-selected": activeCategory === value,
4116
+ tabIndex: value === focusableCategory ? 0 : -1,
4117
+ ref: (element) => {
4118
+ categoryOptionRefs.current[value] = element;
4119
+ },
4120
+ className: `flex w-full min-w-0 items-center rounded-md px-3 py-2 text-left text-sm break-words ${activeCategory === value ? "bg-ph-brand text-[var(--ph-on-accent)]" : "text-ph-ink hover:bg-ph-muted"}`,
4121
+ onClick: () => selectCategory(value),
4122
+ onKeyDown: (event) => {
4123
+ if (event.key === "Escape") {
4124
+ event.preventDefault();
4125
+ closeCategoryMenu(true);
4126
+ } else if (event.key === "Enter" || event.key === " ") {
4127
+ event.preventDefault();
4128
+ selectCategory(value);
4129
+ } else moveCategoryFocus(event, value);
4130
+ },
4131
+ children: value === "all" ? "All apps" : categoryLabel(value)
4132
+ },
4133
+ value
4134
+ ))
4135
+ }
4136
+ )
4137
+ ]
4138
+ }
4139
+ ) : null
4140
+ ] })
4141
+ ] }),
4142
+ /* @__PURE__ */ jsxs21(
4143
+ "div",
4144
+ {
4145
+ ref: scrollViewportRef,
4146
+ className: "min-h-0 max-h-[min(60vh,32rem)] w-full overflow-y-auto pr-1",
4147
+ children: [
4148
+ loading || catalogLoading ? /* @__PURE__ */ jsx24(
4149
+ "div",
4150
+ {
4151
+ className: "grid gap-3 sm:grid-cols-2 lg:grid-cols-3",
4152
+ "aria-label": "Loading apps",
4153
+ children: Array.from({ length: SKELETON_COUNT }, (_, index) => /* @__PURE__ */ jsx24(IntegrationSkeletonCard, {}, index))
4154
+ }
4155
+ ) : /* @__PURE__ */ jsxs21("div", { className: "grid gap-3 sm:grid-cols-2 lg:grid-cols-3", children: [
4156
+ filtered.map((item) => {
4157
+ var _a, _b;
4158
+ const isExpanded = expanded === item.id;
4159
+ const longDescription = item.description.length > DESCRIPTION_LIMIT;
4160
+ const text = isExpanded || !longDescription ? item.description : `${item.description.slice(0, DESCRIPTION_LIMIT).trimEnd()}...`;
4161
+ return /* @__PURE__ */ jsxs21(
4162
+ "div",
4163
+ {
4164
+ className: "flex min-h-36 min-w-0 flex-col justify-between rounded-xl border border-ph-border bg-ph-surface p-4",
4165
+ children: [
4166
+ /* @__PURE__ */ jsx24(
4167
+ "button",
4168
+ {
4169
+ type: "button",
4170
+ className: "min-w-0 text-left",
4171
+ onClick: () => longDescription && setExpanded(isExpanded ? null : item.id),
4172
+ "aria-expanded": isExpanded,
4173
+ children: /* @__PURE__ */ jsxs21("span", { className: "flex items-start gap-3", children: [
4174
+ /* @__PURE__ */ jsx24("span", { className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-ph-muted text-ph-ink", children: (_a = item.icon) != null ? _a : /* @__PURE__ */ jsx24(Plug, { className: "h-5 w-5", "aria-hidden": true }) }),
4175
+ /* @__PURE__ */ jsxs21("span", { className: "min-w-0", children: [
4176
+ /* @__PURE__ */ jsx24("span", { className: "block truncate font-medium text-ph-ink", children: item.label }),
4177
+ /* @__PURE__ */ jsx24("span", { className: "mt-1 block text-xs text-ph-subtle", children: text }),
4178
+ longDescription ? /* @__PURE__ */ jsxs21("span", { className: "mt-1 block text-xs font-medium text-ph-brand", children: [
4179
+ isExpanded ? "See less" : "See more",
4180
+ " ",
4181
+ isExpanded ? /* @__PURE__ */ jsx24(NavArrowUp, { className: "inline h-3 w-3" }) : /* @__PURE__ */ jsx24(NavArrowDown2, { className: "inline h-3 w-3" })
4182
+ ] }) : null
4183
+ ] })
4184
+ ] })
4185
+ }
4186
+ ),
4187
+ suiteAppsForIntegration(item.categories).length > 0 ? /* @__PURE__ */ jsx24(
4188
+ "div",
4189
+ {
4190
+ className: "mt-3 flex flex-wrap items-center gap-1.5",
4191
+ "aria-label": "Works with ShellStack apps",
4192
+ children: suiteAppsForIntegration(item.categories).map(
4193
+ (app) => /* @__PURE__ */ jsx24(
4194
+ "span",
4195
+ {
4196
+ "data-test": `${dataTest}-${item.id}-app-${app}`,
4197
+ children: /* @__PURE__ */ jsx24(
4198
+ SuiteAppIcon,
4199
+ {
4200
+ app,
4201
+ size: 16,
4202
+ label: `Works with ${SUITE_APP_MAP[app].name}`,
4203
+ className: "rounded-[4px]"
4204
+ }
4205
+ )
4206
+ },
4207
+ app
4208
+ )
4209
+ )
4210
+ }
4211
+ ) : null,
4212
+ authSchemesFor(item).length > 0 ? /* @__PURE__ */ jsx24(
4213
+ "div",
4214
+ {
4215
+ className: "mt-3 flex flex-wrap gap-1.5",
4216
+ "aria-label": "Connection methods",
4217
+ children: authSchemesFor(item).map((scheme) => /* @__PURE__ */ jsx24(
4218
+ "span",
4219
+ {
4220
+ className: "rounded-full border border-ph-border bg-ph-muted px-2 py-1 text-[0.6875rem] font-medium text-ph-subtle",
4221
+ "data-test": `${dataTest}-${item.id}-auth-${scheme.toLowerCase()}`,
4222
+ children: authSchemeLabel(scheme)
4223
+ },
4224
+ scheme
4225
+ ))
4226
+ }
4227
+ ) : null,
4228
+ /* @__PURE__ */ jsx24(
4229
+ Button,
4230
+ {
4231
+ type: "button",
4232
+ variant: "primary",
4233
+ className: "mt-3 self-start",
4234
+ disabled: Boolean(item.unavailableReason) || item.connecting,
4235
+ onClick: () => connectItem(item),
4236
+ children: /* @__PURE__ */ jsxs21("span", { className: "flex items-center gap-1.5", children: [
4237
+ /* @__PURE__ */ jsx24(Plug, { className: "h-3.5 w-3.5", "aria-hidden": true }),
4238
+ item.connecting ? "Connecting..." : (_b = item.unavailableReason) != null ? _b : "Connect"
4239
+ ] })
4240
+ }
4241
+ )
4242
+ ]
4243
+ },
4244
+ item.id
4245
+ );
4246
+ }),
4247
+ loadingMore ? Array.from({ length: 3 }, (_, index) => /* @__PURE__ */ jsx24(IntegrationSkeletonCard, {}, `loading-${index}`)) : null
4248
+ ] }),
4249
+ /* @__PURE__ */ jsx24("div", { ref: loadMoreSentinelRef, className: "h-1", "aria-hidden": "true" })
4250
+ ]
4251
+ }
4252
+ ),
4253
+ connectedItems.length > 0 && onDisconnect ? /* @__PURE__ */ jsxs21("div", { className: "space-y-2 border-t border-ph-border pt-4", children: [
4254
+ /* @__PURE__ */ jsx24("h3", { className: "font-medium text-ph-ink", children: "Connected apps" }),
4255
+ connectedItems.map((item) => /* @__PURE__ */ jsxs21(
4256
+ "div",
4257
+ {
4258
+ className: "flex items-center justify-between gap-3 rounded-lg border border-ph-border bg-ph-muted p-3",
4259
+ children: [
4260
+ /* @__PURE__ */ jsxs21("span", { className: "flex min-w-0 items-center gap-2 text-sm text-ph-ink", children: [
4261
+ item.icon,
4262
+ /* @__PURE__ */ jsx24("span", { className: "truncate", children: item.label })
4263
+ ] }),
4264
+ /* @__PURE__ */ jsx24(
4265
+ Button,
4266
+ {
4267
+ type: "button",
4268
+ variant: "danger",
4269
+ onClick: () => requestDisconnect(item),
4270
+ children: /* @__PURE__ */ jsxs21("span", { className: "flex items-center gap-1.5", children: [
4271
+ /* @__PURE__ */ jsx24(Xmark, { className: "h-4 w-4", "aria-hidden": true }),
4272
+ "Disconnect"
4273
+ ] })
4274
+ }
4275
+ )
4276
+ ]
4277
+ },
4278
+ item.id
4279
+ ))
4280
+ ] }) : null
4281
+ ] })
4282
+ }
4283
+ ),
4284
+ /* @__PURE__ */ jsxs21(
4285
+ Modal,
4286
+ {
4287
+ open: itemToDisconnect !== null,
4288
+ onClose: () => {
4289
+ if (!disconnecting) setItemToDisconnect(null);
4290
+ },
4291
+ title: "Disconnect app",
4292
+ description: "This will stop syncing data from this app.",
4293
+ size: "sm",
4294
+ zIndex: 220,
4295
+ dataTest: `${dataTest}-disconnect-confirmation`,
4296
+ footer: /* @__PURE__ */ jsxs21("div", { className: "flex justify-end gap-2", children: [
4297
+ /* @__PURE__ */ jsx24(
4298
+ Button,
4299
+ {
4300
+ type: "button",
4301
+ variant: "tertiary",
4302
+ onClick: () => setItemToDisconnect(null),
4303
+ disabled: disconnecting,
4304
+ children: "Cancel"
4305
+ }
4306
+ ),
4307
+ /* @__PURE__ */ jsx24(
4308
+ Button,
4309
+ {
4310
+ type: "button",
4311
+ variant: "danger",
4312
+ onClick: () => void disconnectItem(),
4313
+ disabled: disconnecting,
4314
+ "data-test": `${dataTest}-disconnect-confirm`,
4315
+ children: disconnecting ? "Disconnecting..." : "Disconnect app"
4316
+ }
4317
+ )
4318
+ ] }),
4319
+ children: [
4320
+ disconnectError ? /* @__PURE__ */ jsx24("p", { className: "text-sm text-ph-danger", role: "alert", children: disconnectError }) : null,
4321
+ /* @__PURE__ */ jsxs21("p", { className: "text-sm text-ph-ink", children: [
4322
+ "Disconnect ",
4323
+ itemToDisconnect == null ? void 0 : itemToDisconnect.label,
4324
+ "? You can reconnect it later."
4325
+ ] })
4326
+ ]
4327
+ }
4328
+ ),
4329
+ /* @__PURE__ */ jsx24(
4330
+ Modal,
4331
+ {
4332
+ open: Boolean(methodItem),
4333
+ onClose: () => setMethodItem(null),
4334
+ title: methodItem ? `Connect ${methodItem.label}` : "Choose connection method",
4335
+ description: "Choose how you want to connect this app.",
4336
+ size: "sm",
4337
+ zIndex: 200,
4338
+ dataTest: `${dataTest}-auth-method`,
4339
+ children: methodItem ? /* @__PURE__ */ jsx24("div", { className: "space-y-2", children: authSchemesFor(methodItem).map((scheme) => /* @__PURE__ */ jsxs21(
4340
+ "button",
4341
+ {
4342
+ type: "button",
4343
+ className: "flex w-full items-center justify-between rounded-lg border border-ph-border bg-ph-surface px-3 py-3 text-left text-sm text-ph-ink transition hover:border-ph-brand hover:bg-ph-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-brand",
4344
+ onClick: () => void prepareConnection(methodItem, scheme),
4345
+ "data-test": `${dataTest}-choose-${scheme.toLowerCase()}`,
4346
+ children: [
4347
+ /* @__PURE__ */ jsx24("span", { className: "font-medium", children: authSchemeLabel(scheme) }),
4348
+ /* @__PURE__ */ jsx24("span", { className: "text-xs text-ph-subtle", children: "Select" })
4349
+ ]
4350
+ },
4351
+ scheme
4352
+ )) }) : null
4353
+ }
4354
+ ),
4355
+ /* @__PURE__ */ jsx24(
4356
+ Modal,
4357
+ {
4358
+ open: Boolean(authItem),
4359
+ onClose: closeAuthForm,
4360
+ title: authItem ? `${authItem.item.label} authentication` : "Authentication",
4361
+ description: "Enter the credentials required by Composio. They are sent securely to the ShellStack API.",
4362
+ size: "md",
4363
+ zIndex: 210,
4364
+ dataTest: `${dataTest}-auth-form`,
4365
+ children: authLoading ? /* @__PURE__ */ jsx24("p", { className: "text-sm text-ph-subtle", children: "Loading authentication fields..." }) : authItem ? /* @__PURE__ */ jsxs21(
4366
+ "form",
4367
+ {
4368
+ className: "space-y-4",
4369
+ onSubmit: (event) => void submitAuthForm(event),
4370
+ children: [
4371
+ authError ? /* @__PURE__ */ jsx24("p", { className: "text-sm text-ph-danger", role: "alert", children: authError }) : null,
4372
+ authItem.fields.length === 0 && authError ? /* @__PURE__ */ jsx24(
4373
+ Button,
4374
+ {
4375
+ type: "button",
4376
+ variant: "tertiary",
4377
+ onClick: () => void prepareConnection(authItem.item, authItem.scheme),
4378
+ children: "Try again"
4379
+ }
4380
+ ) : null,
4381
+ authItem.fields.map((field) => {
4382
+ var _a, _b;
4383
+ return /* @__PURE__ */ jsx24(
4384
+ Input,
4385
+ {
4386
+ label: field.label,
4387
+ type: (_a = field.type) != null ? _a : "password",
4388
+ required: true,
4389
+ value: (_b = authValues[field.name]) != null ? _b : "",
4390
+ onChange: (event) => setAuthValues((current) => __spreadProps(__spreadValues({}, current), {
4391
+ [field.name]: event.target.value
4392
+ })),
4393
+ autoComplete: "off",
4394
+ "data-test": `${dataTest}-auth-field-${field.name}`
4395
+ },
4396
+ field.name
4397
+ );
4398
+ }),
4399
+ /* @__PURE__ */ jsxs21("div", { className: "flex justify-end gap-2 border-t border-ph-border pt-4", children: [
4400
+ /* @__PURE__ */ jsx24(
4401
+ Button,
4402
+ {
4403
+ type: "button",
4404
+ variant: "tertiary",
4405
+ onClick: closeAuthForm,
4406
+ disabled: authSubmitting,
4407
+ children: "Cancel"
4408
+ }
4409
+ ),
4410
+ /* @__PURE__ */ jsx24(Button, { type: "submit", variant: "primary", disabled: authSubmitting, children: authSubmitting ? "Connecting..." : "Connect" })
4411
+ ] })
4412
+ ]
4413
+ }
4414
+ ) : null
4415
+ }
4416
+ )
4417
+ ] });
4418
+ }
4419
+
4420
+ // src/suite/components/suite-integration-rules.tsx
4421
+ import { useState as useState11 } from "react";
4422
+ import { Plus, Xmark as Xmark2 } from "iconoir-react";
4423
+ import { jsx as jsx25, jsxs as jsxs22 } from "react/jsx-runtime";
4424
+ var ACTION_LABELS = {
4425
+ create_tides_task: "Create a Tides task",
4426
+ draft_time_entry: "Draft a time entry",
4427
+ create_suite_notification: "Send a suite notification"
4428
+ };
4429
+ function actionLabel(actionType) {
4430
+ var _a;
4431
+ return (_a = ACTION_LABELS[actionType]) != null ? _a : actionType;
4432
+ }
4433
+ function formatDateTime(value) {
4434
+ if (!value) return "\u2014";
4435
+ return new Date(value).toLocaleString(void 0, {
4436
+ dateStyle: "medium",
4437
+ timeStyle: "short"
4438
+ });
4439
+ }
4440
+ function SuiteIntegrationRules({
4441
+ canManage,
4442
+ projects,
4443
+ rules,
4444
+ events,
4445
+ loading = false,
4446
+ error = null,
4447
+ onCreate,
4448
+ onUpdate,
4449
+ onDelete,
4450
+ onRefresh,
4451
+ dataTest = "integration-rules"
4452
+ }) {
4453
+ const [formOpen, setFormOpen] = useState11(false);
4454
+ const [name, setName] = useState11("");
4455
+ const [trigger, setTrigger] = useState11("");
4456
+ const [actionType, setActionType] = useState11("create_tides_task");
4457
+ const [projectId, setProjectId] = useState11("");
4458
+ const [minutes, setMinutes] = useState11("");
4459
+ const [priority, setPriority] = useState11("low");
4460
+ const [submitting, setSubmitting] = useState11(false);
4461
+ const [formError, setFormError] = useState11(null);
4462
+ const [busyId, setBusyId] = useState11(null);
4463
+ const [ruleToDelete, setRuleToDelete] = useState11(null);
4464
+ const [deleteError, setDeleteError] = useState11(null);
4465
+ const needsProject = actionType === "create_tides_task" || actionType === "draft_time_entry";
4466
+ async function submitForm(event) {
4467
+ event.preventDefault();
4468
+ if (!onCreate) return;
4469
+ setSubmitting(true);
4470
+ setFormError(null);
4471
+ try {
4472
+ const actionConfig = {};
4473
+ if (projectId) actionConfig.project_id = projectId;
4474
+ if (actionType === "draft_time_entry" && minutes)
4475
+ actionConfig.minutes = minutes;
4476
+ if (actionType === "create_tides_task" && priority !== "low")
4477
+ actionConfig.priority = priority;
4478
+ await onCreate({
4479
+ name: name.trim(),
4480
+ trigger_event_type: trigger.trim(),
4481
+ action_type: actionType,
4482
+ action_config: actionConfig
4483
+ });
4484
+ setName("");
4485
+ setTrigger("");
4486
+ setProjectId("");
4487
+ setMinutes("");
4488
+ setPriority("low");
4489
+ setFormOpen(false);
4490
+ onRefresh == null ? void 0 : onRefresh();
4491
+ } catch (cause) {
4492
+ setFormError(
4493
+ cause instanceof Error ? cause.message : "Could not create the rule."
4494
+ );
4495
+ } finally {
4496
+ setSubmitting(false);
4497
+ }
4498
+ }
4499
+ async function toggleRule(rule) {
4500
+ if (!onUpdate) return;
4501
+ setBusyId(rule.id);
4502
+ try {
4503
+ await onUpdate(rule.id, { enabled: !rule.enabled });
4504
+ onRefresh == null ? void 0 : onRefresh();
4505
+ } finally {
4506
+ setBusyId(null);
4507
+ }
4508
+ }
4509
+ function requestDelete(rule) {
4510
+ setDeleteError(null);
4511
+ setRuleToDelete(rule);
4512
+ }
4513
+ async function deleteRule() {
4514
+ if (!onDelete || !ruleToDelete) return;
4515
+ setBusyId(ruleToDelete.id);
4516
+ setDeleteError(null);
4517
+ try {
4518
+ await onDelete(ruleToDelete.id);
4519
+ onRefresh == null ? void 0 : onRefresh();
4520
+ setRuleToDelete(null);
4521
+ } catch (cause) {
4522
+ setDeleteError(
4523
+ cause instanceof Error ? cause.message : "Could not delete the rule."
4524
+ );
4525
+ } finally {
4526
+ setBusyId(null);
4527
+ }
4528
+ }
4529
+ return /* @__PURE__ */ jsxs22("section", { className: "space-y-4", "data-test": dataTest, children: [
4530
+ /* @__PURE__ */ jsxs22(
4531
+ Card,
4532
+ {
4533
+ variant: "outlined",
4534
+ bodyClassName: "p-5",
4535
+ "data-test": `${dataTest}-card`,
4536
+ children: [
4537
+ /* @__PURE__ */ jsxs22("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between", children: [
4538
+ /* @__PURE__ */ jsxs22("div", { children: [
4539
+ /* @__PURE__ */ jsx25("h3", { className: "font-medium text-ph-ink", children: "Automation rules" }),
4540
+ /* @__PURE__ */ jsx25("p", { className: "mt-1 text-sm text-ph-subtle", children: "Turn incoming integration events into tasks, time entries, or notifications for this workspace." })
4541
+ ] }),
4542
+ canManage && onCreate ? /* @__PURE__ */ jsx25(
4543
+ Button,
4544
+ {
4545
+ type: "button",
4546
+ variant: "tertiary",
4547
+ size: "sm",
4548
+ onClick: () => setFormOpen((open) => !open),
4549
+ "data-test": `${dataTest}-new`,
4550
+ children: /* @__PURE__ */ jsxs22("span", { className: "flex items-center gap-1.5", children: [
4551
+ /* @__PURE__ */ jsx25(Plus, { className: "h-4 w-4", "aria-hidden": true }),
4552
+ "New rule"
4553
+ ] })
4554
+ }
4555
+ ) : null
4556
+ ] }),
4557
+ error ? /* @__PURE__ */ jsx25(
4558
+ Alert,
4559
+ {
4560
+ status: "danger",
4561
+ title: "Could not load rules",
4562
+ description: error
4563
+ }
4564
+ ) : null,
4565
+ loading ? /* @__PURE__ */ jsx25("p", { className: "mt-4 text-sm text-ph-subtle", children: "Loading rules..." }) : rules.length === 0 ? /* @__PURE__ */ jsx25(
4566
+ "div",
4567
+ {
4568
+ className: "mt-4 rounded-lg border border-dashed border-ph-border px-4 py-6 text-center",
4569
+ "data-test": `${dataTest}-empty`,
4570
+ children: /* @__PURE__ */ jsxs22("p", { className: "text-sm text-ph-subtle", children: [
4571
+ "No automation rules yet.",
4572
+ canManage ? " Create one to get started." : ""
4573
+ ] })
4574
+ }
4575
+ ) : /* @__PURE__ */ jsx25("ul", { className: "mt-4 space-y-2", "data-test": `${dataTest}-list`, children: rules.map((rule) => /* @__PURE__ */ jsxs22(
4576
+ "li",
4577
+ {
4578
+ className: "flex items-center justify-between gap-3 rounded-lg border border-ph-border bg-ph-muted px-3 py-3",
4579
+ "data-test": `${dataTest}-rule-${rule.id}`,
4580
+ children: [
4581
+ /* @__PURE__ */ jsxs22("div", { className: "min-w-0", children: [
4582
+ /* @__PURE__ */ jsx25("p", { className: "truncate text-sm font-medium text-ph-ink", children: rule.name }),
4583
+ /* @__PURE__ */ jsxs22("p", { className: "mt-0.5 truncate text-xs text-ph-subtle", children: [
4584
+ rule.trigger_event_type,
4585
+ " \u2192 ",
4586
+ actionLabel(rule.action_type)
4587
+ ] }),
4588
+ /* @__PURE__ */ jsxs22("p", { className: "mt-0.5 truncate text-xs text-ph-subtle", children: [
4589
+ "Last fired: ",
4590
+ formatDateTime(rule.last_fired_at)
4591
+ ] })
4592
+ ] }),
4593
+ canManage ? /* @__PURE__ */ jsxs22("div", { className: "flex shrink-0 items-center gap-2", children: [
4594
+ /* @__PURE__ */ jsx25(
4595
+ Toggle,
4596
+ {
4597
+ checked: rule.enabled,
4598
+ disabled: busyId === rule.id,
4599
+ onChange: () => void toggleRule(rule),
4600
+ "aria-label": `Enable ${rule.name}`
4601
+ }
4602
+ ),
4603
+ /* @__PURE__ */ jsx25(
4604
+ Button,
4605
+ {
4606
+ type: "button",
4607
+ variant: "tertiary",
4608
+ size: "sm",
4609
+ disabled: busyId === rule.id,
4610
+ onClick: () => requestDelete(rule),
4611
+ "aria-label": `Delete ${rule.name}`,
4612
+ children: /* @__PURE__ */ jsx25(Xmark2, { className: "h-4 w-4", "aria-hidden": true })
4613
+ }
4614
+ )
4615
+ ] }) : /* @__PURE__ */ jsx25(
4616
+ Badge,
4617
+ {
4618
+ variant: rule.enabled ? "success" : "neutral",
4619
+ size: "sm",
4620
+ children: rule.enabled ? "Enabled" : "Disabled"
4621
+ }
4622
+ )
4623
+ ]
4624
+ },
4625
+ rule.id
4626
+ )) }),
4627
+ canManage && formOpen && onCreate ? /* @__PURE__ */ jsxs22(
4628
+ "form",
4629
+ {
4630
+ className: "mt-4 space-y-3 rounded-lg border border-ph-border bg-ph-surface p-4",
4631
+ onSubmit: (event) => void submitForm(event),
4632
+ "data-test": `${dataTest}-form`,
4633
+ children: [
4634
+ formError ? /* @__PURE__ */ jsx25("p", { className: "text-sm text-ph-danger", role: "alert", children: formError }) : null,
4635
+ /* @__PURE__ */ jsx25(
4636
+ Input,
4637
+ {
4638
+ label: "Rule name",
4639
+ required: true,
4640
+ value: name,
4641
+ onChange: (event) => setName(event.target.value),
4642
+ placeholder: "GitHub issues to tasks",
4643
+ "data-test": `${dataTest}-name`
4644
+ }
4645
+ ),
4646
+ /* @__PURE__ */ jsx25(
4647
+ Input,
4648
+ {
4649
+ label: "Trigger event type",
4650
+ required: true,
4651
+ value: trigger,
4652
+ onChange: (event) => setTrigger(event.target.value),
4653
+ placeholder: "github.issue_assigned",
4654
+ helperText: "Provider event type, for example github.issue_assigned or googlecalendar.event_ended.",
4655
+ "data-test": `${dataTest}-trigger`
4656
+ }
4657
+ ),
4658
+ /* @__PURE__ */ jsx25(
4659
+ Select,
4660
+ {
4661
+ label: "Action",
4662
+ value: actionType,
4663
+ onChange: (event) => setActionType(
4664
+ event.target.value
4665
+ ),
4666
+ "data-test": `${dataTest}-action`,
4667
+ children: Object.entries(ACTION_LABELS).map(([value, label]) => /* @__PURE__ */ jsx25("option", { value, children: label }, value))
4668
+ }
4669
+ ),
4670
+ needsProject ? /* @__PURE__ */ jsxs22(
4671
+ Select,
4672
+ {
4673
+ label: "Project",
4674
+ value: projectId,
4675
+ onChange: (event) => setProjectId(event.target.value),
4676
+ "data-test": `${dataTest}-project`,
4677
+ children: [
4678
+ /* @__PURE__ */ jsx25("option", { value: "", children: "Choose a project..." }),
4679
+ projects.map((project) => /* @__PURE__ */ jsx25("option", { value: project.id, children: project.name }, project.id))
4680
+ ]
4681
+ }
4682
+ ) : null,
4683
+ actionType === "draft_time_entry" ? /* @__PURE__ */ jsx25(
4684
+ Input,
4685
+ {
4686
+ label: "Minutes (optional)",
4687
+ type: "number",
4688
+ min: "1",
4689
+ value: minutes,
4690
+ onChange: (event) => setMinutes(event.target.value),
4691
+ "data-test": `${dataTest}-minutes`
4692
+ }
4693
+ ) : null,
4694
+ actionType === "create_tides_task" ? /* @__PURE__ */ jsxs22(
4695
+ Select,
4696
+ {
4697
+ label: "Priority",
4698
+ value: priority,
4699
+ onChange: (event) => setPriority(event.target.value),
4700
+ "data-test": `${dataTest}-priority`,
4701
+ children: [
4702
+ /* @__PURE__ */ jsx25("option", { value: "low", children: "Low" }),
4703
+ /* @__PURE__ */ jsx25("option", { value: "medium", children: "Medium" }),
4704
+ /* @__PURE__ */ jsx25("option", { value: "high", children: "High" }),
4705
+ /* @__PURE__ */ jsx25("option", { value: "urgent", children: "Urgent" })
4706
+ ]
4707
+ }
4708
+ ) : null,
4709
+ /* @__PURE__ */ jsxs22("div", { className: "flex justify-end gap-2 border-t border-ph-border pt-3", children: [
4710
+ /* @__PURE__ */ jsx25(
4711
+ Button,
4712
+ {
4713
+ type: "button",
4714
+ variant: "tertiary",
4715
+ onClick: () => setFormOpen(false),
4716
+ disabled: submitting,
4717
+ children: "Cancel"
4718
+ }
4719
+ ),
4720
+ /* @__PURE__ */ jsx25(Button, { type: "submit", variant: "primary", disabled: submitting, children: submitting ? "Creating..." : "Create rule" })
4721
+ ] })
4722
+ ]
4723
+ }
4724
+ ) : null
4725
+ ]
4726
+ }
4727
+ ),
4728
+ /* @__PURE__ */ jsxs22(
4729
+ Modal,
4730
+ {
4731
+ open: ruleToDelete !== null,
4732
+ onClose: () => {
4733
+ if (busyId !== (ruleToDelete == null ? void 0 : ruleToDelete.id)) setRuleToDelete(null);
4734
+ },
4735
+ title: "Delete automation rule",
4736
+ description: "This action cannot be undone.",
4737
+ dataTest: `${dataTest}-delete-confirmation`,
4738
+ footer: /* @__PURE__ */ jsxs22("div", { className: "flex justify-end gap-2", children: [
4739
+ /* @__PURE__ */ jsx25(
4740
+ Button,
4741
+ {
4742
+ type: "button",
4743
+ variant: "tertiary",
4744
+ onClick: () => setRuleToDelete(null),
4745
+ disabled: busyId === (ruleToDelete == null ? void 0 : ruleToDelete.id),
4746
+ children: "Cancel"
4747
+ }
4748
+ ),
4749
+ /* @__PURE__ */ jsx25(
4750
+ Button,
4751
+ {
4752
+ type: "button",
4753
+ variant: "danger",
4754
+ onClick: () => void deleteRule(),
4755
+ disabled: busyId === (ruleToDelete == null ? void 0 : ruleToDelete.id),
4756
+ "data-test": `${dataTest}-delete-confirm`,
4757
+ children: busyId === (ruleToDelete == null ? void 0 : ruleToDelete.id) ? "Deleting..." : "Delete rule"
4758
+ }
4759
+ )
4760
+ ] }),
4761
+ children: [
4762
+ deleteError ? /* @__PURE__ */ jsx25("p", { className: "text-sm text-ph-danger", role: "alert", children: deleteError }) : null,
4763
+ /* @__PURE__ */ jsxs22("p", { className: "text-sm text-ph-ink", children: [
4764
+ "Delete ",
4765
+ ruleToDelete == null ? void 0 : ruleToDelete.name,
4766
+ "? This cannot be undone."
4767
+ ] })
4768
+ ]
4769
+ }
4770
+ ),
4771
+ /* @__PURE__ */ jsxs22(
4772
+ Card,
4773
+ {
4774
+ variant: "outlined",
4775
+ bodyClassName: "p-5",
4776
+ "data-test": `${dataTest}-events-card`,
4777
+ children: [
4778
+ /* @__PURE__ */ jsx25("h3", { className: "font-medium text-ph-ink", children: "Recent events" }),
4779
+ /* @__PURE__ */ jsx25("p", { className: "mt-1 text-sm text-ph-subtle", children: "The latest events received from your connected apps." }),
4780
+ events.length === 0 ? /* @__PURE__ */ jsx25(
4781
+ "p",
4782
+ {
4783
+ className: "mt-4 rounded-lg border border-dashed border-ph-border px-4 py-6 text-center text-sm text-ph-subtle",
4784
+ "data-test": `${dataTest}-events-empty`,
4785
+ children: "No integration events yet."
4786
+ }
4787
+ ) : /* @__PURE__ */ jsx25("ul", { className: "mt-4 space-y-2", "data-test": `${dataTest}-events-list`, children: events.map((event) => /* @__PURE__ */ jsxs22(
4788
+ "li",
4789
+ {
4790
+ className: "flex items-center justify-between gap-3 rounded-lg border border-ph-border bg-ph-muted px-3 py-2",
4791
+ children: [
4792
+ /* @__PURE__ */ jsxs22("div", { className: "min-w-0", children: [
4793
+ /* @__PURE__ */ jsxs22("p", { className: "truncate text-sm text-ph-ink", children: [
4794
+ event.provider,
4795
+ " \xB7 ",
4796
+ event.event_type
4797
+ ] }),
4798
+ /* @__PURE__ */ jsx25("p", { className: "mt-0.5 text-xs text-ph-subtle", children: formatDateTime(event.created_at) })
4799
+ ] }),
4800
+ /* @__PURE__ */ jsx25(
4801
+ Badge,
4802
+ {
4803
+ variant: event.processed_at ? "success" : "warning",
4804
+ size: "sm",
4805
+ children: event.processed_at ? "Processed" : "Pending"
4806
+ }
4807
+ )
4808
+ ]
4809
+ },
4810
+ event.id
4811
+ )) })
4812
+ ]
4813
+ }
4814
+ )
4815
+ ] });
4816
+ }
4817
+
4818
+ // src/suite/components/suite-clients-projects-directory.tsx
4819
+ import {
4820
+ useEffect as useEffect9,
4821
+ useMemo as useMemo2,
4822
+ useRef as useRef4,
4823
+ useState as useState12
4824
+ } from "react";
4825
+ import {
4826
+ ArrowLeft,
4827
+ MediaImagePlus as ImagePlus,
4828
+ MoreHoriz as MoreHorizontal,
4829
+ Plus as Plus2,
4830
+ Search as Search2,
4831
+ Trash
4832
+ } from "iconoir-react";
4833
+ import { Fragment as Fragment9, jsx as jsx26, jsxs as jsxs23 } from "react/jsx-runtime";
4834
+ var DEFAULT_ICON = "castle-emblem";
4835
+ var DEFAULT_COLOR = "#6366f1";
4836
+ var DIRECTORY_ICON_OPTIONS = [
4837
+ ["arena", "Arena"],
4838
+ ["bridge", "Bridge"],
4839
+ ["capitol", "Capitol"],
4840
+ ["castle-emblem", "Castle"],
4841
+ ["castle-flag", "Castle flag"],
4842
+ ["lighthouse", "Lighthouse"],
4843
+ ["tower", "Tower"],
4844
+ ["wooden-sign", "Sign"],
4845
+ ["anvil", "Anvil"],
4846
+ ["book", "Book"],
4847
+ ["chessboard", "Chessboard"],
4848
+ ["cog", "Settings"],
4849
+ ["hammer", "Build"],
4850
+ ["light-bulb", "Idea"],
4851
+ ["microphone", "Communication"],
4852
+ ["quill-ink", "Writing"],
4853
+ ["scroll-unfurled", "Notes"],
4854
+ ["hourglass", "Planning"],
4855
+ ["wrench", "Tools"],
4856
+ ["archer", "Archer"],
4857
+ ["archery-target", "Target"],
4858
+ ["axe", "Axe"],
4859
+ ["campfire", "Campfire"],
4860
+ ["compass", "Compass"],
4861
+ ["crossed-swords", "Battle"],
4862
+ ["knight-helmet", "Knight"],
4863
+ ["mountains", "Mountains"],
4864
+ ["shield", "Shield"],
4865
+ ["ship-emblem", "Voyage"],
4866
+ ["sword", "Sword"],
4867
+ ["trophy", "Trophy"],
4868
+ ["apple", "Apple"],
4869
+ ["butterfly", "Butterfly"],
4870
+ ["clover", "Clover"],
4871
+ ["dragon", "Dragon"],
4872
+ ["fire", "Fire"],
4873
+ ["flower", "Flower"],
4874
+ ["flowers", "Flowers"],
4875
+ ["grass", "Grass"],
4876
+ ["leaf", "Leaf"],
4877
+ ["pine-tree", "Pine tree"],
4878
+ ["sun", "Sun"],
4879
+ ["water-drop", "Water"],
4880
+ ["aura", "Aura"],
4881
+ ["crystal-ball", "Crystal ball"],
4882
+ ["diamond", "Diamond"],
4883
+ ["explosion", "Explosion"],
4884
+ ["fire-symbol", "Fire symbol"],
4885
+ ["gem", "Gem"],
4886
+ ["lightning-trio", "Lightning"],
4887
+ ["potion", "Potion"],
4888
+ ["rune-stone", "Rune stone"],
4889
+ ["skull", "Skull"],
4890
+ ["tentacle", "Tentacle"],
4891
+ ["wolf-head", "Wolf"],
4892
+ ["anchor", "Anchor"],
4893
+ ["beer", "Beer"],
4894
+ ["carrot", "Carrot"],
4895
+ ["cat", "Cat"],
4896
+ ["crown", "Crown"],
4897
+ ["gold-bar", "Gold bar"],
4898
+ ["helmet", "Helmet"],
4899
+ ["key", "Key"],
4900
+ ["three-keys", "Keys"]
4901
+ ];
4902
+ function isDirectoryIcon(value) {
4903
+ return DIRECTORY_ICON_OPTIONS.some(([name]) => name === value);
4904
+ }
4905
+ function DirectoryIconPicker({
4906
+ value,
4907
+ preview,
4908
+ onFileChange,
4909
+ onClear,
4910
+ onChange
4911
+ }) {
4912
+ const iconRefs = useRef4({});
4913
+ function moveSelection(event, index) {
4914
+ var _a;
4915
+ let nextIndex = null;
4916
+ if (event.key === "ArrowRight" || event.key === "ArrowDown") {
4917
+ nextIndex = (index + 1) % DIRECTORY_ICON_OPTIONS.length;
4918
+ } else if (event.key === "ArrowLeft" || event.key === "ArrowUp") {
4919
+ nextIndex = (index - 1 + DIRECTORY_ICON_OPTIONS.length) % DIRECTORY_ICON_OPTIONS.length;
4920
+ } else if (event.key === "Home") {
4921
+ nextIndex = 0;
4922
+ } else if (event.key === "End") {
4923
+ nextIndex = DIRECTORY_ICON_OPTIONS.length - 1;
4924
+ }
4925
+ if (nextIndex === null) return;
4926
+ event.preventDefault();
4927
+ const [nextIcon] = DIRECTORY_ICON_OPTIONS[nextIndex];
4928
+ onChange(nextIcon);
4929
+ (_a = iconRefs.current[nextIcon]) == null ? void 0 : _a.focus();
4930
+ }
4931
+ return /* @__PURE__ */ jsxs23("div", { className: "space-y-2", children: [
4932
+ /* @__PURE__ */ jsx26("span", { className: "mb-1.5 block text-sm font-medium text-ph-ink", children: "Icon" }),
4933
+ /* @__PURE__ */ jsx26(
4934
+ "div",
4935
+ {
4936
+ role: "radiogroup",
4937
+ "aria-label": "Icon",
4938
+ className: "grid grid-cols-6 gap-1.5 rounded-lg border border-ph-border p-1.5 sm:grid-cols-8",
4939
+ children: DIRECTORY_ICON_OPTIONS.map(([name, label], index) => {
4940
+ const selected = value === name;
4941
+ return /* @__PURE__ */ jsx26(
4942
+ "button",
4943
+ {
4944
+ type: "button",
4945
+ role: "radio",
4946
+ "aria-label": label,
4947
+ "aria-checked": selected,
4948
+ tabIndex: selected ? 0 : -1,
4949
+ title: label,
4950
+ onClick: () => onChange(name),
4951
+ onKeyDown: (event) => moveSelection(event, index),
4952
+ ref: (element) => {
4953
+ iconRefs.current[name] = element;
4954
+ },
4955
+ className: cn(
4956
+ "flex h-9 items-center justify-center rounded-md text-ph-mutedtext hover:bg-ph-muted hover:text-ph-ink",
4957
+ selected && "bg-ph-muted text-ph-ink ring-2 ring-ph-brand ring-inset"
4958
+ ),
4959
+ children: /* @__PURE__ */ jsx26(
4960
+ "i",
4961
+ {
4962
+ className: cn("ra", `ra-${name}`, "text-base leading-none"),
4963
+ "aria-hidden": true
4964
+ }
4965
+ )
4966
+ },
4967
+ name
4968
+ );
4969
+ })
4970
+ }
4971
+ ),
4972
+ /* @__PURE__ */ jsxs23("div", { className: "rounded-lg border border-ph-border bg-ph-muted p-2", children: [
4973
+ /* @__PURE__ */ jsxs23("div", { className: "flex items-center gap-2 text-sm font-medium text-ph-ink", children: [
4974
+ /* @__PURE__ */ jsx26(ImagePlus, { className: "h-4 w-4", "aria-hidden": true }),
4975
+ " Custom image"
4976
+ ] }),
4977
+ /* @__PURE__ */ jsx26("p", { className: "mt-1 text-xs text-ph-mutedtext", children: "PNG, JPG, GIF, WebP, or SVG \u2014 max 512 KB." }),
4978
+ /* @__PURE__ */ jsx26(
4979
+ FileUpload,
4980
+ {
4981
+ accept: "image/png,image/jpeg,image/gif,image/webp,image/svg+xml,.svg",
4982
+ onChange: (event) => {
4983
+ var _a, _b;
4984
+ return onFileChange((_b = (_a = event.target.files) == null ? void 0 : _a[0]) != null ? _b : null);
4985
+ }
4986
+ }
4987
+ ),
4988
+ preview ? /* @__PURE__ */ jsxs23("div", { className: "mt-2 flex items-center gap-2", children: [
4989
+ /* @__PURE__ */ jsx26(
4990
+ "img",
4991
+ {
4992
+ src: preview,
4993
+ alt: "",
4994
+ className: "h-8 w-8 rounded object-cover"
4995
+ }
4996
+ ),
4997
+ /* @__PURE__ */ jsxs23(
4998
+ "button",
4999
+ {
5000
+ type: "button",
5001
+ className: "text-xs text-ph-mutedtext hover:text-ph-ink",
5002
+ onClick: onClear,
5003
+ children: [
5004
+ /* @__PURE__ */ jsx26(Trash, { className: "mr-1 inline h-3.5 w-3.5", "aria-hidden": true }),
5005
+ " Remove custom image"
5006
+ ]
5007
+ }
5008
+ )
5009
+ ] }) : null
5010
+ ] })
5011
+ ] });
5012
+ }
5013
+ function DirectoryIcon({
5014
+ item
5015
+ }) {
5016
+ const icon = item.icon && isDirectoryIcon(item.icon) ? item.icon : DEFAULT_ICON;
5017
+ return /* @__PURE__ */ jsx26(
5018
+ "span",
5019
+ {
5020
+ className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg text-white",
5021
+ style: { backgroundColor: item.color || "var(--ph-brand)" },
5022
+ children: item.icon_image ? (
5023
+ // eslint-disable-next-line @next/next/no-img-element
5024
+ /* @__PURE__ */ jsx26(
5025
+ "img",
5026
+ {
5027
+ src: item.icon_image,
5028
+ alt: "",
5029
+ className: "h-full w-full rounded-lg object-cover"
5030
+ }
5031
+ )
5032
+ ) : /* @__PURE__ */ jsx26(
5033
+ "i",
5034
+ {
5035
+ className: cn("ra", `ra-${icon}`, "text-base leading-none"),
5036
+ "aria-hidden": true
5037
+ }
5038
+ )
5039
+ }
5040
+ );
5041
+ }
5042
+ function SuiteClientsProjectsDirectory({
5043
+ clients,
5044
+ projects,
5045
+ canEdit = false,
5046
+ loading = false,
5047
+ error,
5048
+ onCreateClient,
5049
+ onUpdateClient,
5050
+ onDeleteClient,
5051
+ onCreateProject,
5052
+ onUpdateProject,
5053
+ onDeleteProject,
5054
+ dataTest = "suite-clients-projects-directory"
5055
+ }) {
5056
+ var _a;
5057
+ const [query, setQuery] = useState12("");
5058
+ const [selectedClientId, setSelectedClientId] = useState12(null);
5059
+ const [mobileDetail, setMobileDetail] = useState12(false);
5060
+ const [editing, setEditing] = useState12(null);
5061
+ const [draft, setDraft] = useState12({
5062
+ name: "",
5063
+ icon: DEFAULT_ICON,
5064
+ color: DEFAULT_COLOR
5065
+ });
5066
+ const [draftClientId, setDraftClientId] = useState12(null);
5067
+ const [preview, setPreview] = useState12(null);
5068
+ const [draftArchived, setDraftArchived] = useState12(false);
5069
+ const [confirming, setConfirming] = useState12(null);
5070
+ const [saving, setSaving] = useState12(false);
5071
+ const [mutationError, setMutationError] = useState12(null);
5072
+ const clientButtonRefs = useRef4({});
5073
+ const backToClientsRef = useRef4(null);
5074
+ const mobileFocusTarget = useRef4(null);
5075
+ useEffect9(() => {
5076
+ var _a2, _b;
5077
+ if (selectedClientId && clients.some((client) => client.id === selectedClientId))
5078
+ return;
5079
+ setSelectedClientId((_b = (_a2 = clients[0]) == null ? void 0 : _a2.id) != null ? _b : null);
5080
+ }, [clients, selectedClientId]);
5081
+ useEffect9(() => {
5082
+ var _a2, _b;
5083
+ const target = mobileFocusTarget.current;
5084
+ if (!target) return;
5085
+ mobileFocusTarget.current = null;
5086
+ if (target === "detail") (_a2 = backToClientsRef.current) == null ? void 0 : _a2.focus();
5087
+ else if (selectedClientId)
5088
+ (_b = clientButtonRefs.current[selectedClientId]) == null ? void 0 : _b.focus();
5089
+ }, [mobileDetail, selectedClientId]);
5090
+ const filteredClients = useMemo2(() => {
5091
+ const value = query.trim().toLowerCase();
5092
+ return [...clients].sort((a, b) => a.name.localeCompare(b.name)).filter((client) => !value || client.name.toLowerCase().includes(value));
5093
+ }, [clients, query]);
5094
+ const selectedClient = (_a = clients.find((client) => client.id === selectedClientId)) != null ? _a : null;
5095
+ const selectedProjects = projects.filter((project) => project.clientId === selectedClientId).sort((a, b) => a.name.localeCompare(b.name));
5096
+ function isMobileDirectoryView() {
5097
+ var _a2, _b;
5098
+ return (_b = (_a2 = window.matchMedia) == null ? void 0 : _a2.call(window, "(max-width: 1023px)").matches) != null ? _b : false;
5099
+ }
5100
+ function selectClient(client) {
5101
+ setSelectedClientId(client.id);
5102
+ setMobileDetail(true);
5103
+ if (isMobileDirectoryView()) mobileFocusTarget.current = "detail";
5104
+ }
5105
+ function moveClientSelection(event, index) {
5106
+ var _a2;
5107
+ let nextIndex = null;
5108
+ if (event.key === "ArrowDown") {
5109
+ nextIndex = (index + 1) % filteredClients.length;
5110
+ } else if (event.key === "ArrowUp") {
5111
+ nextIndex = (index - 1 + filteredClients.length) % filteredClients.length;
5112
+ } else if (event.key === "Home") {
5113
+ nextIndex = 0;
5114
+ } else if (event.key === "End") {
5115
+ nextIndex = filteredClients.length - 1;
5116
+ }
5117
+ if (nextIndex === null) return;
5118
+ event.preventDefault();
5119
+ const client = filteredClients[nextIndex];
5120
+ selectClient(client);
5121
+ if (!isMobileDirectoryView()) (_a2 = clientButtonRefs.current[client.id]) == null ? void 0 : _a2.focus();
5122
+ }
5123
+ function openNew(kind) {
5124
+ setMutationError(null);
5125
+ setDraft({
5126
+ name: "",
5127
+ icon: DEFAULT_ICON,
5128
+ color: DEFAULT_COLOR,
5129
+ iconImageFile: null,
5130
+ clearIconImage: false
5131
+ });
5132
+ setPreview(null);
5133
+ setDraftArchived(false);
5134
+ setDraftClientId(kind === "project" ? selectedClientId : null);
5135
+ setEditing({ kind: kind === "client" ? "new-client" : "new-project" });
5136
+ }
5137
+ function openEdit(item, kind) {
5138
+ var _a2;
5139
+ setMutationError(null);
5140
+ setDraft({
5141
+ name: item.name,
5142
+ icon: item.icon && isDirectoryIcon(item.icon) ? item.icon : DEFAULT_ICON,
5143
+ color: item.color || DEFAULT_COLOR,
5144
+ iconImageFile: null,
5145
+ clearIconImage: false
5146
+ });
5147
+ setPreview(item.icon_image || null);
5148
+ setDraftArchived(
5149
+ kind === "project" && Boolean(item.isArchived)
5150
+ );
5151
+ setDraftClientId(
5152
+ kind === "project" ? (_a2 = item.clientId) != null ? _a2 : null : null
5153
+ );
5154
+ setEditing({ kind, item });
5155
+ }
5156
+ function chooseImage(file) {
5157
+ if (!file) return;
5158
+ if (file.size > 512 * 1024) {
5159
+ setMutationError("Icon must be 512 KB or smaller.");
5160
+ return;
5161
+ }
5162
+ setMutationError(null);
5163
+ if (preview == null ? void 0 : preview.startsWith("blob:")) URL.revokeObjectURL(preview);
5164
+ setDraft((current) => __spreadProps(__spreadValues({}, current), {
5165
+ iconImageFile: file,
5166
+ clearIconImage: false
5167
+ }));
5168
+ setPreview(URL.createObjectURL(file));
5169
+ }
5170
+ function clearImage() {
5171
+ if (preview == null ? void 0 : preview.startsWith("blob:")) URL.revokeObjectURL(preview);
5172
+ setPreview(null);
5173
+ setDraft((current) => __spreadProps(__spreadValues({}, current), {
5174
+ iconImageFile: null,
5175
+ clearIconImage: true
5176
+ }));
5177
+ }
5178
+ function closeEditor() {
5179
+ if (!saving) setEditing(null);
5180
+ }
5181
+ async function save() {
5182
+ if (!editing || !draft.name.trim() || saving) return;
5183
+ setSaving(true);
5184
+ setMutationError(null);
5185
+ try {
5186
+ const fields = __spreadProps(__spreadValues({}, draft), { name: draft.name.trim() });
5187
+ if (editing.kind === "new-client") await (onCreateClient == null ? void 0 : onCreateClient(fields));
5188
+ else if (editing.kind === "new-project")
5189
+ await (onCreateProject == null ? void 0 : onCreateProject(__spreadProps(__spreadValues({}, fields), {
5190
+ clientId: draftClientId,
5191
+ isArchived: draftArchived
5192
+ })));
5193
+ else if (editing.kind === "client")
5194
+ await (onUpdateClient == null ? void 0 : onUpdateClient(editing.item, fields));
5195
+ else
5196
+ await (onUpdateProject == null ? void 0 : onUpdateProject(editing.item, __spreadProps(__spreadValues({}, fields), {
5197
+ clientId: draftClientId,
5198
+ isArchived: draftArchived
5199
+ })));
5200
+ setEditing(null);
5201
+ } catch (err) {
5202
+ setMutationError(
5203
+ err instanceof Error ? err.message : "Failed to save directory item."
5204
+ );
5205
+ } finally {
5206
+ setSaving(false);
5207
+ }
5208
+ }
5209
+ function remove(item, kind) {
5210
+ setConfirming({ item, kind });
5211
+ }
5212
+ async function toggleArchive(project) {
5213
+ var _a2;
5214
+ if (!onUpdateProject) return;
5215
+ try {
5216
+ await onUpdateProject(project, {
5217
+ name: project.name,
5218
+ icon: project.icon && isDirectoryIcon(project.icon) ? project.icon : DEFAULT_ICON,
5219
+ color: project.color || DEFAULT_COLOR,
5220
+ clientId: (_a2 = project.clientId) != null ? _a2 : null,
5221
+ isArchived: !project.isArchived
5222
+ });
5223
+ } catch (err) {
5224
+ setMutationError(
5225
+ err instanceof Error ? err.message : "Failed to update project."
5226
+ );
5227
+ }
5228
+ }
5229
+ async function confirmRemove() {
5230
+ if (!confirming) return;
5231
+ const { item, kind } = confirming;
5232
+ setConfirming(null);
5233
+ try {
5234
+ if (kind === "client")
5235
+ await (onDeleteClient == null ? void 0 : onDeleteClient(item));
5236
+ else await (onDeleteProject == null ? void 0 : onDeleteProject(item));
5237
+ } catch (err) {
5238
+ setMutationError(
5239
+ err instanceof Error ? err.message : "Failed to delete directory item."
5240
+ );
5241
+ }
5242
+ }
5243
+ return /* @__PURE__ */ jsxs23("div", { "data-test": dataTest, className: "space-y-3", children: [
5244
+ error || mutationError ? /* @__PURE__ */ jsx26(Alert, { status: "danger", live: "assertive", children: error || mutationError }) : null,
5245
+ loading ? /* @__PURE__ */ jsx26("p", { className: "text-sm text-ph-mutedtext", children: "Loading directory..." }) : /* @__PURE__ */ jsxs23("div", { className: "overflow-hidden rounded-xl border border-ph-border bg-ph-surface lg:grid lg:min-h-[22rem] lg:grid-cols-[minmax(14rem,18rem)_1fr]", children: [
5246
+ /* @__PURE__ */ jsxs23(
5247
+ "section",
5248
+ {
5249
+ className: cn(
5250
+ "border-ph-border lg:border-r",
5251
+ mobileDetail ? "hidden lg:block" : "block"
5252
+ ),
5253
+ children: [
5254
+ /* @__PURE__ */ jsxs23("div", { className: "flex h-14 items-center gap-2 border-b border-ph-border px-3", children: [
5255
+ /* @__PURE__ */ jsxs23("div", { className: "relative min-w-0 flex-1", children: [
5256
+ /* @__PURE__ */ jsx26(
5257
+ Search2,
5258
+ {
5259
+ className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-ph-mutedtext",
5260
+ "aria-hidden": true
5261
+ }
5262
+ ),
5263
+ /* @__PURE__ */ jsx26(
5264
+ Input,
5265
+ {
5266
+ hideLabel: true,
5267
+ "aria-label": "Search clients",
5268
+ placeholder: "Search clients...",
5269
+ value: query,
5270
+ onChange: (event) => setQuery(event.target.value),
5271
+ className: "pl-9"
5272
+ }
5273
+ )
5274
+ ] }),
5275
+ canEdit && onCreateClient ? /* @__PURE__ */ jsx26(
5276
+ Button,
5277
+ {
5278
+ size: "sm",
5279
+ variant: "primary",
5280
+ icon: /* @__PURE__ */ jsx26(Plus2, { className: "h-4 w-4" }),
5281
+ onClick: () => openNew("client"),
5282
+ children: "New client"
5283
+ }
5284
+ ) : null
5285
+ ] }),
5286
+ /* @__PURE__ */ jsx26(
5287
+ "ul",
5288
+ {
5289
+ role: "listbox",
5290
+ "aria-label": "Clients",
5291
+ className: "max-h-[28rem] overflow-y-auto p-1.5",
5292
+ children: filteredClients.length ? filteredClients.map((client, index) => {
5293
+ const selected = client.id === selectedClientId;
5294
+ const count = projects.filter(
5295
+ (project) => project.clientId === client.id
5296
+ ).length;
5297
+ return /* @__PURE__ */ jsx26("li", { role: "none", children: /* @__PURE__ */ jsxs23(
5298
+ "button",
5299
+ {
5300
+ type: "button",
5301
+ role: "option",
5302
+ "aria-selected": selected,
5303
+ tabIndex: selected ? 0 : -1,
5304
+ onClick: () => selectClient(client),
5305
+ onKeyDown: (event) => moveClientSelection(event, index),
5306
+ ref: (element) => {
5307
+ clientButtonRefs.current[client.id] = element;
5308
+ },
5309
+ className: cn(
5310
+ "flex w-full items-center gap-2.5 rounded-lg px-2.5 py-2 text-left",
5311
+ selected ? "bg-ph-muted" : "hover:bg-ph-canvas"
5312
+ ),
5313
+ children: [
5314
+ /* @__PURE__ */ jsx26(DirectoryIcon, { item: client }),
5315
+ /* @__PURE__ */ jsxs23("span", { className: "min-w-0 flex-1", children: [
5316
+ /* @__PURE__ */ jsx26("span", { className: "block truncate text-sm font-medium text-ph-ink", children: client.name }),
5317
+ /* @__PURE__ */ jsxs23("span", { className: "text-xs text-ph-mutedtext", children: [
5318
+ count,
5319
+ " project",
5320
+ count === 1 ? "" : "s"
5321
+ ] })
5322
+ ] })
5323
+ ]
5324
+ }
5325
+ ) }, client.id);
5326
+ }) : /* @__PURE__ */ jsx26("li", { className: "px-3 py-8 text-center text-sm text-ph-mutedtext", children: clients.length ? "No matches." : "Add a client to get started." })
5327
+ }
5328
+ )
5329
+ ]
5330
+ }
5331
+ ),
5332
+ /* @__PURE__ */ jsxs23(
5333
+ "section",
5334
+ {
5335
+ className: cn(
5336
+ "flex min-w-0 flex-col",
5337
+ mobileDetail ? "flex" : "hidden lg:flex"
5338
+ ),
5339
+ children: [
5340
+ /* @__PURE__ */ jsx26("div", { className: "flex min-h-14 items-center gap-2 border-b border-ph-border px-3 py-2", children: selectedClient ? /* @__PURE__ */ jsxs23(Fragment9, { children: [
5341
+ /* @__PURE__ */ jsx26(
5342
+ "button",
5343
+ {
5344
+ type: "button",
5345
+ ref: backToClientsRef,
5346
+ className: "inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-md text-ph-mutedtext hover:bg-ph-muted lg:hidden",
5347
+ onClick: () => {
5348
+ mobileFocusTarget.current = "list";
5349
+ setMobileDetail(false);
5350
+ },
5351
+ "aria-label": "Back to clients",
5352
+ children: /* @__PURE__ */ jsx26(ArrowLeft, { className: "h-4 w-4" })
5353
+ }
5354
+ ),
5355
+ /* @__PURE__ */ jsx26(DirectoryIcon, { item: selectedClient }),
5356
+ /* @__PURE__ */ jsxs23("div", { className: "min-w-0 flex-1", children: [
5357
+ /* @__PURE__ */ jsx26("h3", { className: "truncate text-sm font-semibold text-ph-ink", children: selectedClient.name }),
5358
+ /* @__PURE__ */ jsxs23("p", { className: "text-xs text-ph-mutedtext", children: [
5359
+ selectedProjects.length,
5360
+ " project",
5361
+ selectedProjects.length === 1 ? "" : "s"
5362
+ ] })
5363
+ ] }),
5364
+ canEdit && (onUpdateClient || onDeleteClient) ? /* @__PURE__ */ jsx26("div", { onClick: (event) => event.stopPropagation(), children: /* @__PURE__ */ jsx26(
5365
+ DropdownMenu,
5366
+ {
5367
+ "aria-label": `Actions for ${selectedClient.name}`,
5368
+ align: "end",
5369
+ trigger: /* @__PURE__ */ jsxs23("span", { className: "inline-flex h-8 w-8 items-center justify-center rounded-md text-ph-mutedtext hover:bg-ph-muted hover:text-ph-ink", children: [
5370
+ /* @__PURE__ */ jsx26(MoreHorizontal, { className: "h-4 w-4", "aria-hidden": true }),
5371
+ /* @__PURE__ */ jsx26("span", { className: "sr-only", children: "Client actions" })
5372
+ ] }),
5373
+ children: /* @__PURE__ */ jsxs23("div", { className: "p-1", children: [
5374
+ onUpdateClient ? /* @__PURE__ */ jsx26(
5375
+ DropdownItem,
5376
+ {
5377
+ onClick: () => openEdit(selectedClient, "client"),
5378
+ children: "Edit client"
5379
+ }
5380
+ ) : null,
5381
+ onDeleteClient ? /* @__PURE__ */ jsx26(
5382
+ DropdownItem,
5383
+ {
5384
+ className: "text-red-600",
5385
+ onClick: () => void remove(selectedClient, "client"),
5386
+ children: "Delete client"
5387
+ }
5388
+ ) : null
5389
+ ] })
5390
+ }
5391
+ ) }) : null
5392
+ ] }) : /* @__PURE__ */ jsx26("p", { className: "text-sm text-ph-mutedtext", children: "Select a client" }) }),
5393
+ canEdit && onCreateProject ? /* @__PURE__ */ jsx26("div", { className: "border-b border-ph-border p-3", children: /* @__PURE__ */ jsx26(
5394
+ Button,
5395
+ {
5396
+ variant: "primary",
5397
+ icon: /* @__PURE__ */ jsx26(Plus2, { className: "h-4 w-4" }),
5398
+ onClick: () => openNew("project"),
5399
+ children: "Add project"
5400
+ }
5401
+ ) }) : null,
5402
+ /* @__PURE__ */ jsx26("ul", { className: "flex-1 p-2", children: selectedClient && selectedProjects.length ? selectedProjects.map((project) => /* @__PURE__ */ jsx26("li", { children: /* @__PURE__ */ jsxs23(
5403
+ "div",
5404
+ {
5405
+ className: "flex items-center gap-3 rounded-lg px-2 py-1 hover:bg-ph-canvas",
5406
+ onClick: () => openEdit(project, "project"),
5407
+ children: [
5408
+ /* @__PURE__ */ jsxs23(
5409
+ "button",
5410
+ {
5411
+ type: "button",
5412
+ className: "flex min-w-0 flex-1 items-center gap-3 rounded-lg py-1 text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-brand",
5413
+ onClick: () => openEdit(project, "project"),
5414
+ children: [
5415
+ /* @__PURE__ */ jsx26(DirectoryIcon, { item: project }),
5416
+ /* @__PURE__ */ jsxs23("span", { className: "min-w-0 flex-1", children: [
5417
+ /* @__PURE__ */ jsx26(
5418
+ "span",
5419
+ {
5420
+ className: cn(
5421
+ "block truncate text-sm font-medium",
5422
+ project.isArchived ? "text-ph-mutedtext line-through" : "text-ph-ink"
5423
+ ),
5424
+ children: project.name
5425
+ }
5426
+ ),
5427
+ /* @__PURE__ */ jsx26("span", { className: "text-xs text-ph-mutedtext", children: project.isArchived ? "Archived" : "Active" })
5428
+ ] })
5429
+ ]
5430
+ }
5431
+ ),
5432
+ canEdit && (onUpdateProject || onDeleteProject) ? /* @__PURE__ */ jsx26("div", { onClick: (event) => event.stopPropagation(), children: /* @__PURE__ */ jsx26(
5433
+ DropdownMenu,
5434
+ {
5435
+ "aria-label": `Actions for ${project.name}`,
5436
+ align: "end",
5437
+ trigger: /* @__PURE__ */ jsxs23("span", { className: "inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-md text-ph-mutedtext hover:bg-ph-muted hover:text-ph-ink", children: [
5438
+ /* @__PURE__ */ jsx26(
5439
+ MoreHorizontal,
5440
+ {
5441
+ className: "h-4 w-4",
5442
+ "aria-hidden": true
5443
+ }
5444
+ ),
5445
+ /* @__PURE__ */ jsx26("span", { className: "sr-only", children: "Project actions" })
5446
+ ] }),
5447
+ children: /* @__PURE__ */ jsxs23("div", { className: "p-1", children: [
5448
+ onUpdateProject ? /* @__PURE__ */ jsxs23(Fragment9, { children: [
5449
+ /* @__PURE__ */ jsx26(
5450
+ DropdownItem,
5451
+ {
5452
+ onClick: () => openEdit(project, "project"),
5453
+ children: "Edit project"
5454
+ }
5455
+ ),
5456
+ /* @__PURE__ */ jsx26(
5457
+ DropdownItem,
5458
+ {
5459
+ onClick: () => void toggleArchive(project),
5460
+ children: project.isArchived ? "Unarchive project" : "Archive project"
5461
+ }
5462
+ )
5463
+ ] }) : null,
5464
+ onDeleteProject ? /* @__PURE__ */ jsx26(
5465
+ DropdownItem,
5466
+ {
5467
+ className: "text-red-600",
5468
+ onClick: () => void remove(project, "project"),
5469
+ children: "Delete project"
5470
+ }
5471
+ ) : null
5472
+ ] })
5473
+ }
5474
+ ) }) : null
5475
+ ]
5476
+ }
5477
+ ) }, project.id)) : /* @__PURE__ */ jsx26("li", { className: "px-3 py-8 text-center text-sm text-ph-mutedtext", children: selectedClient ? "No projects yet." : "Select a client to see its projects." }) })
5478
+ ]
5479
+ }
5480
+ )
5481
+ ] }),
5482
+ /* @__PURE__ */ jsx26(
5483
+ Modal,
5484
+ {
5485
+ open: editing !== null,
5486
+ onClose: closeEditor,
5487
+ title: (editing == null ? void 0 : editing.kind.includes("project")) ? editing.kind === "new-project" ? "New project" : "Edit project" : (editing == null ? void 0 : editing.kind) === "new-client" ? "New client" : "Edit client",
5488
+ footer: /* @__PURE__ */ jsxs23("div", { className: "flex justify-end gap-2", children: [
5489
+ /* @__PURE__ */ jsx26(Button, { variant: "tertiary", onClick: closeEditor, disabled: saving, children: "Cancel" }),
5490
+ /* @__PURE__ */ jsx26(
5491
+ Button,
5492
+ {
5493
+ variant: "primary",
5494
+ onClick: () => void save(),
5495
+ disabled: saving || !draft.name.trim(),
5496
+ children: saving ? "Saving..." : "Save"
5497
+ }
5498
+ )
5499
+ ] }),
5500
+ children: /* @__PURE__ */ jsxs23("div", { className: "space-y-3", children: [
5501
+ /* @__PURE__ */ jsx26(
5502
+ Input,
5503
+ {
5504
+ label: "Name",
5505
+ autoFocus: true,
5506
+ value: draft.name,
5507
+ onChange: (event) => setDraft(__spreadProps(__spreadValues({}, draft), { name: event.target.value }))
5508
+ }
5509
+ ),
5510
+ /* @__PURE__ */ jsx26(
5511
+ DirectoryIconPicker,
5512
+ {
5513
+ value: isDirectoryIcon(draft.icon) ? draft.icon : DEFAULT_ICON,
5514
+ preview,
5515
+ onFileChange: chooseImage,
5516
+ onClear: clearImage,
5517
+ onChange: (icon) => {
5518
+ if (preview) clearImage();
5519
+ setDraft((current) => __spreadProps(__spreadValues({}, current), { icon }));
5520
+ }
5521
+ }
5522
+ ),
5523
+ /* @__PURE__ */ jsxs23("div", { children: [
5524
+ /* @__PURE__ */ jsx26("span", { className: "mb-1.5 block text-sm font-medium text-ph-ink", children: "Colour" }),
5525
+ /* @__PURE__ */ jsxs23("div", { className: "flex flex-wrap gap-2", children: [
5526
+ [
5527
+ "#6366f1",
5528
+ "#0ea5e9",
5529
+ "#10b981",
5530
+ "#f59e0b",
5531
+ "#ef4444",
5532
+ "#a855f7",
5533
+ "#64748b"
5534
+ ].map((color) => /* @__PURE__ */ jsx26(
5535
+ "button",
5536
+ {
5537
+ type: "button",
5538
+ "aria-label": `Colour ${color}`,
5539
+ "aria-pressed": draft.color === color,
5540
+ onClick: () => setDraft(__spreadProps(__spreadValues({}, draft), { color })),
5541
+ className: cn(
5542
+ "h-8 w-8 rounded-full ring-offset-2",
5543
+ draft.color === color && "ring-2 ring-ph-brand"
5544
+ ),
5545
+ style: { backgroundColor: color }
5546
+ },
5547
+ color
5548
+ )),
5549
+ /* @__PURE__ */ jsx26(
5550
+ Input,
5551
+ {
5552
+ hideLabel: true,
5553
+ label: "Custom colour",
5554
+ type: "color",
5555
+ value: draft.color,
5556
+ onChange: (event) => setDraft(__spreadProps(__spreadValues({}, draft), { color: event.target.value })),
5557
+ className: "h-8 w-8 p-0"
5558
+ }
5559
+ )
5560
+ ] })
5561
+ ] }),
5562
+ (editing == null ? void 0 : editing.kind.includes("project")) ? /* @__PURE__ */ jsxs23(
5563
+ Select,
5564
+ {
5565
+ label: "Client",
5566
+ value: draftClientId != null ? draftClientId : "",
5567
+ onChange: (event) => setDraftClientId(event.target.value || null),
5568
+ children: [
5569
+ /* @__PURE__ */ jsx26("option", { value: "", children: "No client" }),
5570
+ clients.map((client) => /* @__PURE__ */ jsx26("option", { value: client.id, children: client.name }, client.id))
5571
+ ]
5572
+ }
5573
+ ) : null,
5574
+ (editing == null ? void 0 : editing.kind.includes("project")) ? /* @__PURE__ */ jsxs23("label", { className: "flex items-center gap-2 text-sm text-ph-ink", children: [
5575
+ /* @__PURE__ */ jsx26(
5576
+ "input",
5577
+ {
5578
+ type: "checkbox",
5579
+ checked: draftArchived,
5580
+ onChange: (event) => setDraftArchived(event.target.checked)
5581
+ }
5582
+ ),
5583
+ "Archived"
5584
+ ] }) : null
5585
+ ] })
5586
+ }
5587
+ ),
5588
+ /* @__PURE__ */ jsx26(
5589
+ Modal,
5590
+ {
5591
+ open: confirming !== null,
5592
+ onClose: () => setConfirming(null),
5593
+ title: "Confirm deletion",
5594
+ footer: /* @__PURE__ */ jsxs23("div", { className: "flex justify-end gap-2", children: [
5595
+ /* @__PURE__ */ jsx26(Button, { variant: "tertiary", onClick: () => setConfirming(null), children: "Cancel" }),
5596
+ /* @__PURE__ */ jsx26(Button, { variant: "primary", onClick: () => void confirmRemove(), children: "Delete" })
5597
+ ] }),
5598
+ children: /* @__PURE__ */ jsxs23("p", { className: "text-sm text-ph-ink", children: [
5599
+ "Delete ",
5600
+ confirming == null ? void 0 : confirming.item.name,
5601
+ "? This cannot be undone."
5602
+ ] })
5603
+ }
5604
+ )
5605
+ ] });
5606
+ }
3628
5607
  export {
3629
5608
  APP_ACCENTS,
3630
5609
  APP_GLYPHS,
@@ -3651,6 +5630,7 @@ export {
3651
5630
  SUITE_SIDEBAR_WIDTH_COOKIE,
3652
5631
  SUITE_SIDEBAR_WIDTH_KEY,
3653
5632
  SUITE_SPRINGS,
5633
+ SUITE_THEME_COOKIE,
3654
5634
  SourceAppGlyph,
3655
5635
  SuiteAiPanel,
3656
5636
  SuiteAppIcon,
@@ -3658,8 +5638,11 @@ export {
3658
5638
  SuiteAppStrip,
3659
5639
  SuiteBottomNav,
3660
5640
  SuiteBreadcrumbs,
5641
+ SuiteClientsProjectsDirectory,
3661
5642
  SuiteEmptyState,
3662
5643
  SuiteIcon,
5644
+ SuiteIntegrationPicker,
5645
+ SuiteIntegrationRules,
3663
5646
  SuiteMobileDrawer,
3664
5647
  SuiteMobileHeader,
3665
5648
  SuiteMotionProvider,
@@ -3695,7 +5678,7 @@ export {
3695
5678
  appSwitcherMenuItemClass,
3696
5679
  appSwitcherTriggerClass,
3697
5680
  classifySuiteHref,
3698
- cn,
5681
+ cn2 as cn,
3699
5682
  consumePendingAskAiPrompt,
3700
5683
  consumeSuiteAskAiOpenFromLocation,
3701
5684
  getTodayGreeting,
@@ -3712,6 +5695,7 @@ export {
3712
5695
  sourceToSuiteApp,
3713
5696
  suiteAppBaseUrl,
3714
5697
  suiteAppLabel,
5698
+ suiteThemeBootScript,
3715
5699
  useIdleMount,
3716
5700
  useSidebarWidth,
3717
5701
  useSuiteTheme