@estiva-app/ui 0.58.0 → 0.60.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 (103) hide show
  1. package/dist/AppProvider.d.ts +47 -0
  2. package/dist/AppProvider.d.ts.map +1 -0
  3. package/dist/AppShell.d.ts +6 -2
  4. package/dist/AppShell.d.ts.map +1 -1
  5. package/dist/Avatar.d.ts +1 -1
  6. package/dist/Avatar.d.ts.map +1 -1
  7. package/dist/Chip.d.ts.map +1 -1
  8. package/dist/CommandPalette.d.ts.map +1 -1
  9. package/dist/ComposerTriggers.d.ts +13 -1
  10. package/dist/ComposerTriggers.d.ts.map +1 -1
  11. package/dist/IconButton.d.ts.map +1 -1
  12. package/dist/InlineChip.d.ts.map +1 -1
  13. package/dist/Kbd.d.ts.map +1 -1
  14. package/dist/Link.d.ts +1 -1
  15. package/dist/Link.d.ts.map +1 -1
  16. package/dist/MembersDialog.d.ts +57 -0
  17. package/dist/MembersDialog.d.ts.map +1 -0
  18. package/dist/MembersPill.d.ts +22 -0
  19. package/dist/MembersPill.d.ts.map +1 -0
  20. package/dist/NavItem.d.ts +1 -1
  21. package/dist/NavItem.d.ts.map +1 -1
  22. package/dist/RailItem.d.ts +1 -1
  23. package/dist/RailItem.d.ts.map +1 -1
  24. package/dist/SearchInput.d.ts +3 -3
  25. package/dist/Tabs.d.ts +2 -0
  26. package/dist/Tabs.d.ts.map +1 -1
  27. package/dist/TopBar.d.ts +14 -3
  28. package/dist/TopBar.d.ts.map +1 -1
  29. package/dist/editor.js +4 -4
  30. package/dist/editor.js.map +2 -2
  31. package/dist/index.d.ts +3 -0
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +1332 -1143
  34. package/dist/index.js.map +4 -4
  35. package/dist/looks.d.ts +2 -0
  36. package/dist/looks.d.ts.map +1 -1
  37. package/dist/registry/{app-LDGOH6UW.js → app-X2GI4WTU.js} +2 -2
  38. package/dist/registry/app.d.ts.map +1 -1
  39. package/dist/registry/{chunk-TQ6UQER3.js → chunk-V67F474L.js} +8 -3
  40. package/dist/registry/chunk-V67F474L.js.map +7 -0
  41. package/dist/registry/cli.js +1 -1
  42. package/dist/registry/index.js +1 -1
  43. package/package.json +1 -1
  44. package/registry.json +234 -14
  45. package/skill/estiva-ui.md +2 -1
  46. package/src/AppProvider.mdx +69 -0
  47. package/src/AppProvider.stories.tsx +60 -0
  48. package/src/AppProvider.test.tsx +152 -0
  49. package/src/AppProvider.tsx +76 -0
  50. package/src/AppShell.mdx +4 -1
  51. package/src/AppShell.stories.tsx +5 -5
  52. package/src/AppShell.tsx +7 -3
  53. package/src/Avatar.tsx +7 -3
  54. package/src/Breadcrumb.mdx +2 -2
  55. package/src/Card.mdx +1 -1
  56. package/src/Chip.mdx +2 -2
  57. package/src/Chip.tsx +3 -1
  58. package/src/CommandPalette.tsx +2 -1
  59. package/src/ComposerTriggers.mdx +7 -0
  60. package/src/ComposerTriggers.stories.tsx +43 -4
  61. package/src/ComposerTriggers.test.tsx +33 -0
  62. package/src/ComposerTriggers.tsx +17 -5
  63. package/src/IconButton.mdx +2 -2
  64. package/src/IconButton.tsx +4 -1
  65. package/src/InlineChip.mdx +3 -3
  66. package/src/InlineChip.tsx +3 -1
  67. package/src/Kbd.tsx +4 -2
  68. package/src/Link.mdx +5 -3
  69. package/src/Link.tsx +4 -1
  70. package/src/MembersDialog.mdx +69 -0
  71. package/src/MembersDialog.stories.tsx +68 -0
  72. package/src/MembersDialog.test.tsx +69 -0
  73. package/src/MembersDialog.tsx +184 -0
  74. package/src/MembersPill.mdx +45 -0
  75. package/src/MembersPill.stories.tsx +38 -0
  76. package/src/MembersPill.tsx +35 -0
  77. package/src/NavItem.mdx +3 -3
  78. package/src/NavItem.tsx +4 -0
  79. package/src/NavTree.mdx +3 -2
  80. package/src/RailItem.mdx +3 -3
  81. package/src/RailItem.tsx +4 -1
  82. package/src/SearchInput.mdx +3 -4
  83. package/src/SearchInput.tsx +3 -3
  84. package/src/Sidebar.mdx +2 -2
  85. package/src/Tabs.mdx +5 -0
  86. package/src/Tabs.stories.tsx +15 -0
  87. package/src/Tabs.test.tsx +8 -0
  88. package/src/Tabs.tsx +12 -0
  89. package/src/TopBar.mdx +18 -9
  90. package/src/TopBar.stories.tsx +22 -4
  91. package/src/TopBar.test.tsx +97 -0
  92. package/src/TopBar.tsx +45 -4
  93. package/src/index.ts +3 -0
  94. package/src/looks.ts +3 -0
  95. package/src/pages.test.ts +3 -1
  96. package/src/registry/app.test.ts +24 -6
  97. package/src/registry/app.ts +21 -2
  98. package/src/registry/contract.test.ts +1 -1
  99. package/src/registry/gated.test.ts +1 -0
  100. package/src/registry/registry.test.ts +4 -4
  101. package/stories/Choosing.mdx +4 -0
  102. package/dist/registry/chunk-TQ6UQER3.js.map +0 -7
  103. /package/dist/registry/{app-LDGOH6UW.js.map → app-X2GI4WTU.js.map} +0 -0
package/dist/index.js CHANGED
@@ -1,3 +1,35 @@
1
+ // src/AppProvider.tsx
2
+ import { createContext, useContext, useMemo } from "react";
3
+ import { jsx } from "react/jsx-runtime";
4
+ var Setup = createContext({});
5
+ function AppProvider({ pictureFor, navigate, children }) {
6
+ const value = useMemo(() => ({ pictureFor, navigate }), [pictureFor, navigate]);
7
+ return /* @__PURE__ */ jsx(Setup.Provider, { value, children });
8
+ }
9
+ function usePictureFor() {
10
+ return useContext(Setup).pictureFor;
11
+ }
12
+ function useInAppClick(href, onClick) {
13
+ const navigate = useContext(Setup).navigate;
14
+ if (!navigate || href === void 0) return onClick;
15
+ return (event) => {
16
+ onClick?.(event);
17
+ if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
18
+ const link = event.currentTarget;
19
+ const target = link.getAttribute("target");
20
+ if (target && target !== "_self" || link.hasAttribute("download")) return;
21
+ let url;
22
+ try {
23
+ url = new URL(href, window.location.href);
24
+ } catch {
25
+ return;
26
+ }
27
+ if (url.origin !== window.location.origin) return;
28
+ event.preventDefault();
29
+ navigate(href);
30
+ };
31
+ }
32
+
1
33
  // src/cn.ts
2
34
  import { clsx } from "clsx";
3
35
  import { extendTailwindMerge } from "tailwind-merge";
@@ -36,7 +68,7 @@ function cn(...inputs) {
36
68
  }
37
69
 
38
70
  // src/Link.tsx
39
- import { jsx } from "react/jsx-runtime";
71
+ import { jsx as jsx2 } from "react/jsx-runtime";
40
72
  var COVER_CLASSES = "after:absolute after:inset-0 after:rounded-md focus-visible:outline-none focus-visible:after:[outline-style:auto]";
41
73
  var VARIANT_CLASSES = {
42
74
  text: "text-info-default underline underline-offset-2 hover:opacity-80",
@@ -44,21 +76,23 @@ var VARIANT_CLASSES = {
44
76
  underlined: "underline underline-offset-2 hover:text-text-primary",
45
77
  plain: ""
46
78
  };
47
- function Link({ href, variant = "text", external = false, truncate = false, cover = false, className, children, ...props }) {
48
- return /* @__PURE__ */ jsx(
79
+ function Link({ href, variant = "text", external = false, truncate = false, cover = false, className, children, onClick, ...props }) {
80
+ const inApp = useInAppClick(href, onClick);
81
+ return /* @__PURE__ */ jsx2(
49
82
  "a",
50
83
  {
51
84
  href,
52
85
  ...external ? { target: "_blank", rel: "noopener noreferrer" } : {},
53
86
  className: cn(VARIANT_CLASSES[variant], truncate && "truncate", cover && COVER_CLASSES, className),
54
87
  ...props,
88
+ onClick: inApp,
55
89
  children
56
90
  }
57
91
  );
58
92
  }
59
93
 
60
94
  // src/Card.tsx
61
- import { jsx as jsx2 } from "react/jsx-runtime";
95
+ import { jsx as jsx3 } from "react/jsx-runtime";
62
96
  var FILL_CLASSES = {
63
97
  surface: "bg-bg-surface border-border-default",
64
98
  elevated: "bg-bg-elevated border-border-default",
@@ -121,25 +155,25 @@ function Card({
121
155
  const { ref, ...anchorProps } = props;
122
156
  return (
123
157
  // @estiva-escape(no-copied-look, no-restyled-part): a card that leads somewhere is drawn on Link's anchor (UIG-27 ruling 1), so this frame is Card's own look, not Link restyled
124
- /* @__PURE__ */ jsx2(Link, { href, variant: "plain", ref, className: classes, ...anchorProps, children })
158
+ /* @__PURE__ */ jsx3(Link, { href, variant: "plain", ref, className: classes, ...anchorProps, children })
125
159
  );
126
160
  }
127
161
  return (
128
162
  // @estiva-escape(no-copied-look): N6 (Katerina, 24 September: leave alone): a card that cuts its content to its corners shares four words with the palette's window by coincidence
129
- /* @__PURE__ */ jsx2("div", { className: classes, ...props, children })
163
+ /* @__PURE__ */ jsx3("div", { className: classes, ...props, children })
130
164
  );
131
165
  }
132
166
 
133
167
  // src/ScrollArea.tsx
134
168
  import { ScrollArea as BaseScrollArea } from "@base-ui/react/scroll-area";
135
- import { jsx as jsx3, jsxs } from "react/jsx-runtime";
169
+ import { jsx as jsx4, jsxs } from "react/jsx-runtime";
136
170
  var BAR = "z-10 flex touch-none select-none rounded-full opacity-0 transition-opacity delay-300 data-[hovering]:opacity-100 data-[hovering]:delay-0 data-[scrolling]:opacity-100 data-[scrolling]:delay-0";
137
171
  var THUMB = "rounded-full bg-border-strong";
138
172
  function ScrollArea({ orientation = "vertical", className, viewportClassName, contentClassName, viewportRef, onScroll, children }) {
139
173
  const vertical = orientation !== "horizontal";
140
174
  const horizontal = orientation !== "vertical";
141
175
  return /* @__PURE__ */ jsxs(BaseScrollArea.Root, { className: cn("relative min-h-0 min-w-0", className), children: [
142
- /* @__PURE__ */ jsx3(
176
+ /* @__PURE__ */ jsx4(
143
177
  BaseScrollArea.Viewport,
144
178
  {
145
179
  ref: viewportRef,
@@ -148,35 +182,114 @@ function ScrollArea({ orientation = "vertical", className, viewportClassName, co
148
182
  "h-full w-full outline-none data-[has-overflow-x]:overscroll-x-contain data-[has-overflow-y]:overscroll-y-contain",
149
183
  viewportClassName
150
184
  ),
151
- children: /* @__PURE__ */ jsx3(BaseScrollArea.Content, { className: contentClassName, style: horizontal ? void 0 : { minWidth: 0 }, children })
185
+ children: /* @__PURE__ */ jsx4(BaseScrollArea.Content, { className: contentClassName, style: horizontal ? void 0 : { minWidth: 0 }, children })
152
186
  }
153
187
  ),
154
- vertical && /* @__PURE__ */ jsx3(BaseScrollArea.Scrollbar, { orientation: "vertical", className: cn(BAR, "w-1.5 justify-center py-0.5 pr-0.5 data-[has-overflow-y]:opacity-100"), children: /* @__PURE__ */ jsx3(BaseScrollArea.Thumb, { className: cn(THUMB, "w-full") }) }),
155
- horizontal && /* @__PURE__ */ jsx3(BaseScrollArea.Scrollbar, { orientation: "horizontal", className: cn(BAR, "h-1.5 flex-col justify-center px-0.5 pb-0.5 data-[has-overflow-x]:opacity-100"), children: /* @__PURE__ */ jsx3(BaseScrollArea.Thumb, { className: cn(THUMB, "h-full") }) }),
156
- vertical && horizontal && /* @__PURE__ */ jsx3(BaseScrollArea.Corner, {})
188
+ vertical && /* @__PURE__ */ jsx4(BaseScrollArea.Scrollbar, { orientation: "vertical", className: cn(BAR, "w-1.5 justify-center py-0.5 pr-0.5 data-[has-overflow-y]:opacity-100"), children: /* @__PURE__ */ jsx4(BaseScrollArea.Thumb, { className: cn(THUMB, "w-full") }) }),
189
+ horizontal && /* @__PURE__ */ jsx4(BaseScrollArea.Scrollbar, { orientation: "horizontal", className: cn(BAR, "h-1.5 flex-col justify-center px-0.5 pb-0.5 data-[has-overflow-x]:opacity-100"), children: /* @__PURE__ */ jsx4(BaseScrollArea.Thumb, { className: cn(THUMB, "h-full") }) }),
190
+ vertical && horizontal && /* @__PURE__ */ jsx4(BaseScrollArea.Corner, {})
157
191
  ] });
158
192
  }
159
193
 
160
194
  // src/Sidebar.tsx
161
- import { createContext, useContext } from "react";
162
- import { jsx as jsx4 } from "react/jsx-runtime";
163
- var SidebarOnGround = createContext(false);
195
+ import { createContext as createContext2, useContext as useContext2 } from "react";
196
+ import { jsx as jsx5 } from "react/jsx-runtime";
197
+ var SidebarOnGround = createContext2(false);
164
198
  function Sidebar({ "aria-label": ariaLabel = "Workspace", children, className }) {
165
- const onGround = useContext(SidebarOnGround);
166
- return /* @__PURE__ */ jsx4(
199
+ const onGround = useContext2(SidebarOnGround);
200
+ return /* @__PURE__ */ jsx5(
167
201
  "nav",
168
202
  {
169
203
  "aria-label": ariaLabel,
170
204
  className: cn("flex w-60 shrink-0 flex-col", !onGround && "border-r border-border-default bg-bg-surface", className),
171
- children: /* @__PURE__ */ jsx4(ScrollArea, { className: "min-h-0 flex-1", contentClassName: "flex flex-col gap-0.5 px-2.5 py-3", children })
205
+ children: /* @__PURE__ */ jsx5(ScrollArea, { className: "min-h-0 flex-1", contentClassName: "flex flex-col gap-0.5 px-2.5 py-3", children })
206
+ }
207
+ );
208
+ }
209
+
210
+ // src/TopBar.tsx
211
+ import { useEffect, useRef } from "react";
212
+ import { Button as BaseButton } from "@base-ui/react/button";
213
+
214
+ // src/looks.ts
215
+ var FIELD_BOX_CLASSES = "bg-bg-field border border-border-field shadow-field hover:border-border-strong group-hover/field:border-border-strong focus:border-border-focus group-hover/field:focus:border-border-focus rounded-lg";
216
+ var FIELD_TEXT_CLASSES = "text-text-primary placeholder:text-text-muted";
217
+ var FIELD_DISABLED_CLASSES = "disabled:pointer-events-none disabled:bg-bg-disabled disabled:text-text-disabled disabled:border-border-field group-hover/field:disabled:border-border-field";
218
+ var FIELD_FOCUS_RING_CLASSES = "signal:transition-shadow signal:focus:shadow-focus-ring";
219
+ var FIELD_SIZE_CLASSES = {
220
+ default: "px-3 py-2 text-input-value",
221
+ small: "h-6 min-h-6 px-2 text-caption"
222
+ };
223
+ var FIELD_SHELL_CLASSES = "bg-bg-field border border-border-field shadow-field hover:border-border-strong group-hover/field:border-border-strong rounded-lg transition-colors";
224
+ var FLOATING_SURFACE_CLASSES = "rounded-lg border border-border-default bg-bg-elevated shadow-lg";
225
+ var COUNT_TEXT_CLASSES = "font-mono text-caption tabular-nums text-text-muted";
226
+ var CHIP_TEXT_CLASSES = "text-chip signal:font-mono signal:text-small signal:font-semibold signal:tabular-nums";
227
+ var MONO_CAPTION_CLASSES = "text-caption text-text-secondary signal:font-mono signal:text-small";
228
+ var BARE_INPUT_CLASSES = "bg-transparent text-text-primary placeholder:text-text-muted outline-none";
229
+ var SIDEBAR_ROW_CLASSES = "rounded-lg transition-colors";
230
+ var SIDEBAR_ROW_TEXT_CLASSES = "text-text-secondary hover:text-text-primary";
231
+ var MUTED_CONTROL_CLASSES = "text-text-secondary hover:bg-bg-hover hover:text-text-primary";
232
+ var MENU_TRIGGER_CLASSES = "cursor-pointer rounded-md transition-colors hover:bg-bg-hover data-[popup-open]:bg-bg-hover";
233
+ var COLLAPSIBLE_PANEL_CLASSES = "h-[var(--collapsible-panel-height)] overflow-hidden transition-[height] duration-150 ease-out motion-reduce:transition-none data-[starting-style]:h-0 data-[ending-style]:h-0";
234
+
235
+ // src/Kbd.tsx
236
+ import { jsx as jsx6 } from "react/jsx-runtime";
237
+ function Kbd({ children, className, tone = "default" }) {
238
+ return /* @__PURE__ */ jsx6(
239
+ "kbd",
240
+ {
241
+ className: cn(
242
+ "inline-flex shrink-0 items-center justify-center whitespace-nowrap rounded-sm border border-border-strong bg-bg-inset px-1 py-px font-sans",
243
+ MONO_CAPTION_CLASSES,
244
+ "signal:border-b-2 signal:pt-[2px] signal:pb-px signal:bg-bg-wash",
245
+ "ship:border-b-2 ship:pt-[2px] ship:pb-px ship:bg-bg-wash ship:font-mono ship:text-small",
246
+ // Leaf sets its keys in mono, as Signal does (Katerina, 28 September): the type, not the key's shape.
247
+ "leaf:font-mono leaf:text-small",
248
+ tone === "tooltip" && "border-border-tooltip-key bg-bg-tooltip-key text-text-tooltip-key signal:bg-bg-tooltip-key ship:bg-bg-tooltip-key",
249
+ className
250
+ ),
251
+ children
172
252
  }
173
253
  );
174
254
  }
175
255
 
256
+ // src/shortcuts.ts
257
+ function isApplePlatform() {
258
+ if (typeof navigator === "undefined") return false;
259
+ return /Mac|iPhone|iPad|iPod/.test(navigator.platform || navigator.userAgent || "");
260
+ }
261
+ function shortcutLabel(keys, apple = isApplePlatform()) {
262
+ return keys.split("-").map((part, i, all) => {
263
+ if (i === all.length - 1) return part.length === 1 ? part.toUpperCase() : part;
264
+ if (part === "Mod") return apple ? "Cmd" : "Ctrl";
265
+ return part;
266
+ }).join("+");
267
+ }
268
+
176
269
  // src/TopBar.tsx
177
- import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
178
- function TopBar({ variant = "solid", menu, logo, search, right, className }) {
270
+ import { jsx as jsx7, jsxs as jsxs2 } from "react/jsx-runtime";
271
+ function TopBar({ variant = "solid", menu, logo, search, onSearch, searchPlaceholder = "Search\u2026", right, className }) {
179
272
  const floating = variant === "floating";
273
+ const searchRef = useRef(onSearch);
274
+ useEffect(() => {
275
+ searchRef.current = onSearch;
276
+ });
277
+ const searches = onSearch !== void 0;
278
+ useEffect(() => {
279
+ if (!searches) return;
280
+ const onKey = (event) => {
281
+ if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "k") {
282
+ event.preventDefault();
283
+ searchRef.current?.();
284
+ }
285
+ };
286
+ window.addEventListener("keydown", onKey);
287
+ return () => window.removeEventListener("keydown", onKey);
288
+ }, [searches]);
289
+ const centre = search ?? (onSearch && /* @__PURE__ */ jsxs2(BaseButton, { type: "button", onClick: onSearch, className: cn("flex w-[290px] cursor-pointer items-center gap-2 px-3 py-2", FIELD_SHELL_CLASSES), children: [
290
+ /* @__PURE__ */ jsx7("span", { className: "min-w-0 flex-1 truncate text-left text-input-value text-text-muted", children: searchPlaceholder }),
291
+ /* @__PURE__ */ jsx7(Kbd, { children: shortcutLabel("Mod-K") })
292
+ ] }));
180
293
  return /* @__PURE__ */ jsxs2(
181
294
  "header",
182
295
  {
@@ -188,19 +301,19 @@ function TopBar({ variant = "solid", menu, logo, search, right, className }) {
188
301
  children: [
189
302
  (menu || logo) && /* @__PURE__ */ jsxs2("div", { className: cn("flex shrink-0 items-center gap-2", floating && "pointer-events-auto"), children: [
190
303
  menu,
191
- logo && /* @__PURE__ */ jsx5("div", { className: "flex items-center text-body-2-strong text-text-primary", children: logo })
304
+ logo && /* @__PURE__ */ jsx7("div", { className: "flex items-center text-body-2-strong text-text-primary", children: logo })
192
305
  ] }),
193
- /* @__PURE__ */ jsx5("div", { className: cn("flex min-w-0 flex-1 items-center justify-center", floating && "pointer-events-auto"), children: search }),
194
- /* @__PURE__ */ jsx5("div", { className: cn("flex shrink-0 items-center gap-[6px]", floating && "pointer-events-auto"), children: right })
306
+ /* @__PURE__ */ jsx7("div", { className: cn("flex min-w-0 flex-1 items-center justify-center", floating && "pointer-events-auto"), children: centre }),
307
+ /* @__PURE__ */ jsx7("div", { className: cn("flex shrink-0 items-center gap-[6px]", floating && "pointer-events-auto"), children: right })
195
308
  ]
196
309
  }
197
310
  );
198
311
  }
199
312
 
200
313
  // src/AppShell.tsx
201
- import { Fragment, jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
202
- function AppShell({ variant = "solid", menu, logo, search, identity, banner, nav, children }) {
203
- const bar = /* @__PURE__ */ jsx6(TopBar, { variant, menu, logo, search, right: identity });
314
+ import { Fragment, jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
315
+ function AppShell({ variant = "solid", menu, logo, search, onSearch, searchPlaceholder, identity, banner, nav, children }) {
316
+ const bar = /* @__PURE__ */ jsx8(TopBar, { variant, menu, logo, search, onSearch, searchPlaceholder, right: identity });
204
317
  const inset = variant === "inset";
205
318
  if (variant === "floating") {
206
319
  return (
@@ -220,7 +333,7 @@ function AppShell({ variant = "solid", menu, logo, search, identity, banner, nav
220
333
  ),
221
334
  children: [
222
335
  banner,
223
- /* @__PURE__ */ jsx6("main", { className: "flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden", children })
336
+ /* @__PURE__ */ jsx8("main", { className: "flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden", children })
224
337
  ]
225
338
  }
226
339
  )
@@ -230,7 +343,7 @@ function AppShell({ variant = "solid", menu, logo, search, identity, banner, nav
230
343
  }
231
344
  const column = /* @__PURE__ */ jsxs3(Fragment, { children: [
232
345
  banner,
233
- /* @__PURE__ */ jsx6(ScrollArea, { className: "min-h-0 flex-1", contentClassName: "flex min-h-full flex-col", children: /* @__PURE__ */ jsx6("main", { className: "flex min-w-0 flex-1 flex-col", children }) })
346
+ /* @__PURE__ */ jsx8(ScrollArea, { className: "min-h-0 flex-1", contentClassName: "flex min-h-full flex-col", children: /* @__PURE__ */ jsx8("main", { className: "flex min-w-0 flex-1 flex-col", children }) })
234
347
  ] });
235
348
  return (
236
349
  /* `relative overflow-hidden` is the seal the floating manner already has
@@ -245,16 +358,16 @@ function AppShell({ variant = "solid", menu, logo, search, identity, banner, nav
245
358
  /* @__PURE__ */ jsxs3("div", { className: "relative flex h-full min-h-0 flex-col overflow-hidden bg-bg-base text-text-primary", children: [
246
359
  bar,
247
360
  /* @__PURE__ */ jsxs3("div", { className: "flex min-h-0 flex-1", children: [
248
- /* @__PURE__ */ jsx6(SidebarOnGround.Provider, { value: inset, children: nav }),
249
- inset ? /* @__PURE__ */ jsx6(Card, { fill: "surface", clip: true, className: "mb-4 mr-4 flex min-h-0 min-w-0 flex-1 flex-col", children: column }) : /* @__PURE__ */ jsx6("div", { className: "flex min-h-0 min-w-0 flex-1 flex-col", children: column })
361
+ /* @__PURE__ */ jsx8(SidebarOnGround.Provider, { value: inset, children: nav }),
362
+ inset ? /* @__PURE__ */ jsx8(Card, { fill: "surface", clip: true, className: "mb-4 mr-4 flex min-h-0 min-w-0 flex-1 flex-col", children: column }) : /* @__PURE__ */ jsx8("div", { className: "flex min-h-0 min-w-0 flex-1 flex-col", children: column })
250
363
  ] })
251
364
  ] })
252
365
  );
253
366
  }
254
367
 
255
368
  // src/AttachmentCard.tsx
256
- import { useEffect, useLayoutEffect, useRef as useRef2, useState } from "react";
257
- import { Button as BaseButton2 } from "@base-ui/react/button";
369
+ import { useEffect as useEffect2, useLayoutEffect, useRef as useRef3, useState } from "react";
370
+ import { Button as BaseButton3 } from "@base-ui/react/button";
258
371
  import {
259
372
  IconAlertCircle,
260
373
  IconAlertTriangle,
@@ -274,74 +387,32 @@ import {
274
387
  } from "@tabler/icons-react";
275
388
 
276
389
  // src/IconButton.tsx
277
- import { Button as BaseButton } from "@base-ui/react/button";
278
-
279
- // src/looks.ts
280
- var FIELD_BOX_CLASSES = "bg-bg-field border border-border-field shadow-field hover:border-border-strong group-hover/field:border-border-strong focus:border-border-focus group-hover/field:focus:border-border-focus rounded-lg";
281
- var FIELD_TEXT_CLASSES = "text-text-primary placeholder:text-text-muted";
282
- var FIELD_DISABLED_CLASSES = "disabled:pointer-events-none disabled:bg-bg-disabled disabled:text-text-disabled disabled:border-border-field group-hover/field:disabled:border-border-field";
283
- var FIELD_FOCUS_RING_CLASSES = "signal:transition-shadow signal:focus:shadow-focus-ring";
284
- var FIELD_SIZE_CLASSES = {
285
- default: "px-3 py-2 text-input-value",
286
- small: "h-6 min-h-6 px-2 text-caption"
287
- };
288
- var FIELD_SHELL_CLASSES = "bg-bg-field border border-border-field shadow-field hover:border-border-strong group-hover/field:border-border-strong rounded-lg transition-colors";
289
- var FLOATING_SURFACE_CLASSES = "rounded-lg border border-border-default bg-bg-elevated shadow-lg";
290
- var COUNT_TEXT_CLASSES = "font-mono text-caption tabular-nums text-text-muted";
291
- var CHIP_TEXT_CLASSES = "text-chip signal:font-mono signal:text-small signal:font-semibold signal:tabular-nums";
292
- var BARE_INPUT_CLASSES = "bg-transparent text-text-primary placeholder:text-text-muted outline-none";
293
- var SIDEBAR_ROW_CLASSES = "rounded-lg transition-colors";
294
- var SIDEBAR_ROW_TEXT_CLASSES = "text-text-secondary hover:text-text-primary";
295
- var MUTED_CONTROL_CLASSES = "text-text-secondary hover:bg-bg-hover hover:text-text-primary";
296
- var MENU_TRIGGER_CLASSES = "cursor-pointer rounded-md transition-colors hover:bg-bg-hover data-[popup-open]:bg-bg-hover";
297
- var COLLAPSIBLE_PANEL_CLASSES = "h-[var(--collapsible-panel-height)] overflow-hidden transition-[height] duration-150 ease-out motion-reduce:transition-none data-[starting-style]:h-0 data-[ending-style]:h-0";
390
+ import { Button as BaseButton2 } from "@base-ui/react/button";
298
391
 
299
392
  // src/formBusy.ts
300
- import { createContext as createContext2, useContext as useContext2 } from "react";
301
- var FormBusyContext = createContext2(false);
393
+ import { createContext as createContext3, useContext as useContext3 } from "react";
394
+ var FormBusyContext = createContext3(false);
302
395
  function useFormBusy() {
303
- return useContext2(FormBusyContext);
396
+ return useContext3(FormBusyContext);
304
397
  }
305
398
 
306
399
  // src/Tooltip.tsx
307
400
  import { Tooltip as BaseTooltip } from "@base-ui/react/tooltip";
308
-
309
- // src/Kbd.tsx
310
- import { jsx as jsx7 } from "react/jsx-runtime";
311
- function Kbd({ children, className, tone = "default" }) {
312
- return /* @__PURE__ */ jsx7(
313
- "kbd",
314
- {
315
- className: cn(
316
- "inline-flex shrink-0 items-center justify-center whitespace-nowrap rounded-sm border border-border-strong bg-bg-inset px-1 py-px font-sans text-caption text-text-secondary",
317
- "signal:border-b-2 signal:pt-[2px] signal:pb-px signal:bg-bg-wash signal:font-mono signal:text-small",
318
- "ship:border-b-2 ship:pt-[2px] ship:pb-px ship:bg-bg-wash ship:font-mono ship:text-small",
319
- // Leaf sets its keys in mono, as Signal does (Katerina, 28 September): the type, not the key's shape.
320
- "leaf:font-mono leaf:text-small",
321
- tone === "tooltip" && "border-border-tooltip-key bg-bg-tooltip-key text-text-tooltip-key signal:bg-bg-tooltip-key ship:bg-bg-tooltip-key",
322
- className
323
- ),
324
- children
325
- }
326
- );
327
- }
328
-
329
- // src/Tooltip.tsx
330
- import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
401
+ import { jsx as jsx9, jsxs as jsxs4 } from "react/jsx-runtime";
331
402
  var OPEN_DELAY = 300;
332
403
  function TooltipProvider({ delay = OPEN_DELAY, closeDelay, timeout, children }) {
333
- return /* @__PURE__ */ jsx8(BaseTooltip.Provider, { delay, closeDelay, timeout, children });
404
+ return /* @__PURE__ */ jsx9(BaseTooltip.Provider, { delay, closeDelay, timeout, children });
334
405
  }
335
406
  function Tooltip({ label, shortcut, className, ...props }) {
336
407
  return /* @__PURE__ */ jsxs4("div", { role: "tooltip", className: cn(FLOATING_SURFACE_CLASSES, "border-border-tooltip bg-bg-tooltip", "min-h-[30px] max-w-80 flex items-center justify-center gap-1.5 px-2 py-1", className), ...props, children: [
337
- /* @__PURE__ */ jsx8("span", { className: "min-w-0 text-caption text-text-tooltip break-words", children: label }),
338
- shortcut && /* @__PURE__ */ jsx8(Kbd, { tone: "tooltip", children: shortcut })
408
+ /* @__PURE__ */ jsx9("span", { className: "min-w-0 text-caption text-text-tooltip break-words", children: label }),
409
+ shortcut && /* @__PURE__ */ jsx9(Kbd, { tone: "tooltip", children: shortcut })
339
410
  ] });
340
411
  }
341
412
  var GAP = 6;
342
413
  var VIEWPORT_PAD = 8;
343
414
  function TooltipSurface({ label, shortcut, placement }) {
344
- return /* @__PURE__ */ jsx8(BaseTooltip.Portal, { children: /* @__PURE__ */ jsx8(
415
+ return /* @__PURE__ */ jsx9(BaseTooltip.Portal, { children: /* @__PURE__ */ jsx9(
345
416
  BaseTooltip.Positioner,
346
417
  {
347
418
  side: placement,
@@ -350,10 +421,10 @@ function TooltipSurface({ label, shortcut, placement }) {
350
421
  collisionPadding: VIEWPORT_PAD,
351
422
  positionMethod: "fixed",
352
423
  className: "pointer-events-none z-[9999]",
353
- children: /* @__PURE__ */ jsx8(
424
+ children: /* @__PURE__ */ jsx9(
354
425
  BaseTooltip.Popup,
355
426
  {
356
- render: /* @__PURE__ */ jsx8(Tooltip, { label, shortcut }),
427
+ render: /* @__PURE__ */ jsx9(Tooltip, { label, shortcut }),
357
428
  className: cn(
358
429
  "transition-[opacity,transform] duration-[120ms] ease-out motion-reduce:transition-none",
359
430
  "data-[ending-style]:duration-[80ms] data-[instant]:duration-0",
@@ -369,19 +440,19 @@ function TooltipSurface({ label, shortcut, placement }) {
369
440
  function WithTooltip({ label, shortcut, placement = "top", wrapperClassName, inline = false, children }) {
370
441
  const Wrapper = inline ? "span" : "div";
371
442
  return /* @__PURE__ */ jsxs4(BaseTooltip.Root, { disableHoverablePopup: true, children: [
372
- /* @__PURE__ */ jsx8(BaseTooltip.Trigger, { delay: OPEN_DELAY, render: /* @__PURE__ */ jsx8(Wrapper, { className: cn("inline-flex shrink-0", inline && "align-top", wrapperClassName) }), children }),
373
- /* @__PURE__ */ jsx8(TooltipSurface, { label, shortcut, placement })
443
+ /* @__PURE__ */ jsx9(BaseTooltip.Trigger, { delay: OPEN_DELAY, render: /* @__PURE__ */ jsx9(Wrapper, { className: cn("inline-flex shrink-0", inline && "align-top", wrapperClassName) }), children }),
444
+ /* @__PURE__ */ jsx9(TooltipSurface, { label, shortcut, placement })
374
445
  ] });
375
446
  }
376
447
  function TooltipTrigger({ label, shortcut, placement = "top", children }) {
377
448
  return /* @__PURE__ */ jsxs4(BaseTooltip.Root, { disableHoverablePopup: true, children: [
378
- /* @__PURE__ */ jsx8(BaseTooltip.Trigger, { delay: OPEN_DELAY, render: children }),
379
- /* @__PURE__ */ jsx8(TooltipSurface, { label, shortcut, placement })
449
+ /* @__PURE__ */ jsx9(BaseTooltip.Trigger, { delay: OPEN_DELAY, render: children }),
450
+ /* @__PURE__ */ jsx9(TooltipSurface, { label, shortcut, placement })
380
451
  ] });
381
452
  }
382
453
 
383
454
  // src/IconButton.tsx
384
- import { jsx as jsx9 } from "react/jsx-runtime";
455
+ import { jsx as jsx10 } from "react/jsx-runtime";
385
456
  function IconButton({
386
457
  variant = "muted",
387
458
  pressed,
@@ -398,6 +469,8 @@ function IconButton({
398
469
  ...props
399
470
  }) {
400
471
  const formBusy = useFormBusy();
472
+ const anchor = props;
473
+ const inApp = useInAppClick(href, anchor.onClick);
401
474
  const unusable = disabled || !!disabledReason || formBusy;
402
475
  const look = (off) => cn(
403
476
  // `shrink-0` stops a flex parent squashing the button; `self-center`
@@ -432,8 +505,8 @@ function IconButton({
432
505
  off && "cursor-not-allowed",
433
506
  className
434
507
  );
435
- const button = href && !unusable ? /* @__PURE__ */ jsx9("a", { href, className: look(false), ...props, children }) : /* @__PURE__ */ jsx9(
436
- BaseButton,
508
+ const button = href && !unusable ? /* @__PURE__ */ jsx10("a", { href, className: look(false), ...anchor, onClick: inApp, children }) : /* @__PURE__ */ jsx10(
509
+ BaseButton2,
437
510
  {
438
511
  type,
439
512
  disabled: unusable,
@@ -446,19 +519,19 @@ function IconButton({
446
519
  );
447
520
  const label = disabledReason ?? tooltip;
448
521
  if (label) {
449
- return /* @__PURE__ */ jsx9(TooltipTrigger, { label, shortcut: disabledReason ? void 0 : tooltipShortcut, placement: tooltipPlacement, children: button });
522
+ return /* @__PURE__ */ jsx10(TooltipTrigger, { label, shortcut: disabledReason ? void 0 : tooltipShortcut, placement: tooltipPlacement, children: button });
450
523
  }
451
524
  return button;
452
525
  }
453
526
 
454
527
  // src/Lightbox.tsx
455
- import { useRef } from "react";
528
+ import { useRef as useRef2 } from "react";
456
529
  import { Dialog } from "@base-ui/react/dialog";
457
530
  import { IconX } from "@tabler/icons-react";
458
- import { jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
531
+ import { jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
459
532
  function Lightbox({ src, alt, onClose, className }) {
460
- const popupRef = useRef(null);
461
- return /* @__PURE__ */ jsx10(
533
+ const popupRef = useRef2(null);
534
+ return /* @__PURE__ */ jsx11(
462
535
  Dialog.Root,
463
536
  {
464
537
  open: true,
@@ -466,7 +539,7 @@ function Lightbox({ src, alt, onClose, className }) {
466
539
  if (!open) onClose();
467
540
  },
468
541
  children: /* @__PURE__ */ jsxs5(Dialog.Portal, { children: [
469
- /* @__PURE__ */ jsx10(Dialog.Backdrop, { className: "fixed inset-0 z-40 bg-scrim-strong" }),
542
+ /* @__PURE__ */ jsx11(Dialog.Backdrop, { className: "fixed inset-0 z-40 bg-scrim-strong" }),
470
543
  /* @__PURE__ */ jsxs5(
471
544
  Dialog.Popup,
472
545
  {
@@ -476,7 +549,7 @@ function Lightbox({ src, alt, onClose, className }) {
476
549
  className: "fixed inset-0 z-50 flex items-center justify-center p-8 outline-none",
477
550
  onClick: onClose,
478
551
  children: [
479
- /* @__PURE__ */ jsx10(
552
+ /* @__PURE__ */ jsx11(
480
553
  "img",
481
554
  {
482
555
  src,
@@ -485,12 +558,12 @@ function Lightbox({ src, alt, onClose, className }) {
485
558
  className: cn("max-w-full max-h-full object-contain rounded-lg", className)
486
559
  }
487
560
  ),
488
- /* @__PURE__ */ jsx10(
561
+ /* @__PURE__ */ jsx11(
489
562
  Dialog.Close,
490
563
  {
491
564
  "aria-label": "Close",
492
565
  className: "absolute top-4 right-4 size-8 rounded-full bg-bg-tooltip border border-border-tooltip-key flex items-center justify-center text-text-tooltip-key hover:text-text-tooltip",
493
- children: /* @__PURE__ */ jsx10(IconX, { size: 16, stroke: 1.5 })
566
+ children: /* @__PURE__ */ jsx11(IconX, { size: 16, stroke: 1.5 })
494
567
  }
495
568
  )
496
569
  ]
@@ -502,7 +575,7 @@ function Lightbox({ src, alt, onClose, className }) {
502
575
  }
503
576
 
504
577
  // src/AttachmentCard.tsx
505
- import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
578
+ import { Fragment as Fragment2, jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
506
579
  var ICON_BY_EXTENSION = {
507
580
  pdf: IconFileTypePdf,
508
581
  doc: IconFileTypeDocx,
@@ -536,10 +609,10 @@ var NAME_CLASSES = "text-caption font-medium text-text-primary truncate";
536
609
  var NOTE_CLASSES = "text-small tracking-wide leading-tight truncate";
537
610
  function TypeIcon({ name }) {
538
611
  const Icon = ICON_BY_EXTENSION[extensionOf(name)] ?? IconFile;
539
- return /* @__PURE__ */ jsx11(Icon, { size: 20, stroke: 1.5 });
612
+ return /* @__PURE__ */ jsx12(Icon, { size: 20, stroke: 1.5 });
540
613
  }
541
614
  function Truncating({ text, hint, className, wrapperClassName, placement }) {
542
- const ref = useRef2(null);
615
+ const ref = useRef3(null);
543
616
  const [cut, setCut] = useState(false);
544
617
  useLayoutEffect(() => {
545
618
  const el = ref.current;
@@ -558,15 +631,15 @@ function Truncating({ text, hint, className, wrapperClassName, placement }) {
558
631
  observer.disconnect();
559
632
  };
560
633
  }, [text, cut]);
561
- const line = /* @__PURE__ */ jsx11("span", { ref, className, children: text });
634
+ const line = /* @__PURE__ */ jsx12("span", { ref, className, children: text });
562
635
  if (!hint && !cut) return line;
563
- return /* @__PURE__ */ jsx11(WithTooltip, { label: hint ?? text, placement, wrapperClassName: cn("min-w-0 flex-col", wrapperClassName), children: line });
636
+ return /* @__PURE__ */ jsx12(WithTooltip, { label: hint ?? text, placement, wrapperClassName: cn("min-w-0 flex-col", wrapperClassName), children: line });
564
637
  }
565
638
  function useRemoteImage(url, fetchImage) {
566
639
  const [result, setResult] = useState({});
567
- const fetcher = useRef2(fetchImage);
640
+ const fetcher = useRef3(fetchImage);
568
641
  fetcher.current = fetchImage;
569
- useEffect(() => {
642
+ useEffect2(() => {
570
643
  if (!url || !fetcher.current) return;
571
644
  let live = true;
572
645
  fetcher.current(url).then(
@@ -639,7 +712,7 @@ function AttachmentCard({
639
712
  const full = useRemoteImage(opened ? remoteFullSrc : void 0, fetchImage);
640
713
  const openable = image && !!picture && !pending;
641
714
  const openPicture = onOpen ?? (openable ? () => setOpened(true) : void 0);
642
- const viewer = opened && picture ? /* @__PURE__ */ jsx11(Lightbox, { src: full.src ?? picture, alt: alt ?? name, onClose: () => setOpened(false) }) : null;
715
+ const viewer = opened && picture ? /* @__PURE__ */ jsx12(Lightbox, { src: full.src ?? picture, alt: alt ?? name, onClose: () => setOpened(false) }) : null;
643
716
  const saveHere = download ? () => {
644
717
  const source = remoteFullSrc ?? remoteSrc;
645
718
  if (source && fetchImage) {
@@ -668,10 +741,10 @@ function AttachmentCard({
668
741
  className: cn("group relative flex items-center gap-2 w-[200px] p-1.5 pr-3", failed ? "border-error-default" : warning && "border-warning-default", className),
669
742
  ...props,
670
743
  children: [
671
- /* @__PURE__ */ jsx11("div", { className: cn(TILE_CLASSES, "overflow-hidden"), children: state === "uploading" ? /* @__PURE__ */ jsx11(IconLoader2, { size: 16, stroke: 1.5, className: "animate-spin" }) : failed ? /* @__PURE__ */ jsx11(IconAlertCircle, { size: 16, stroke: 1.5, className: "text-error-default" }) : warning ? /* @__PURE__ */ jsx11(IconAlertTriangle, { size: 16, stroke: 1.5, className: "text-warning-default" }) : image && src ? /* @__PURE__ */ jsx11("img", { src, alt: name, className: "size-full object-cover" }) : /* @__PURE__ */ jsx11("span", { className: "text-menu font-semibold", children: typeLabelOf(name) }) }),
744
+ /* @__PURE__ */ jsx12("div", { className: cn(TILE_CLASSES, "overflow-hidden"), children: state === "uploading" ? /* @__PURE__ */ jsx12(IconLoader2, { size: 16, stroke: 1.5, className: "animate-spin" }) : failed ? /* @__PURE__ */ jsx12(IconAlertCircle, { size: 16, stroke: 1.5, className: "text-error-default" }) : warning ? /* @__PURE__ */ jsx12(IconAlertTriangle, { size: 16, stroke: 1.5, className: "text-warning-default" }) : image && src ? /* @__PURE__ */ jsx12("img", { src, alt: name, className: "size-full object-cover" }) : /* @__PURE__ */ jsx12("span", { className: "text-menu font-semibold", children: typeLabelOf(name) }) }),
672
745
  /* @__PURE__ */ jsxs6("div", { className: "flex flex-col gap-[1px] min-w-0", children: [
673
- /* @__PURE__ */ jsx11(Truncating, { text: name, className: NAME_CLASSES, placement: onRemove ? "bottom" : void 0 }),
674
- /* @__PURE__ */ jsx11(
746
+ /* @__PURE__ */ jsx12(Truncating, { text: name, className: NAME_CLASSES, placement: onRemove ? "bottom" : void 0 }),
747
+ /* @__PURE__ */ jsx12(
675
748
  Truncating,
676
749
  {
677
750
  text: (failed || warning ? note : state === "uploading" ? note ?? "Uploading\u2026" : note ?? sizeText) ?? "",
@@ -680,8 +753,8 @@ function AttachmentCard({
680
753
  }
681
754
  )
682
755
  ] }),
683
- onRemove && /* @__PURE__ */ jsx11(
684
- BaseButton2,
756
+ onRemove && /* @__PURE__ */ jsx12(
757
+ BaseButton3,
685
758
  {
686
759
  type: "button",
687
760
  "aria-label": `Remove ${name}`,
@@ -690,7 +763,7 @@ function AttachmentCard({
690
763
  event.stopPropagation();
691
764
  onRemove();
692
765
  },
693
- children: /* @__PURE__ */ jsx11(IconX2, { size: 11, stroke: 1.75 })
766
+ children: /* @__PURE__ */ jsx12(IconX2, { size: 11, stroke: 1.75 })
694
767
  }
695
768
  )
696
769
  ]
@@ -700,7 +773,7 @@ function AttachmentCard({
700
773
  }
701
774
  const downloadControl = saving ? (
702
775
  // @estiva-escape(no-restyled-part): Download shows when its card is pointed at or focused, AttachmentCard's own action; IconButton has no reveal on its card's hover (UIG-9, Katerina 17 September)
703
- /* @__PURE__ */ jsx11(
776
+ /* @__PURE__ */ jsx12(
704
777
  IconButton,
705
778
  {
706
779
  variant: "muted",
@@ -711,7 +784,7 @@ function AttachmentCard({
711
784
  event.stopPropagation();
712
785
  saving();
713
786
  },
714
- children: /* @__PURE__ */ jsx11(IconDownload, { size: 16, stroke: 1.5 })
787
+ children: /* @__PURE__ */ jsx12(IconDownload, { size: 16, stroke: 1.5 })
715
788
  }
716
789
  )
717
790
  ) : null;
@@ -720,27 +793,27 @@ function AttachmentCard({
720
793
  // `role="status"`: a plain box may not carry a name (axe, aria-prohibited-attr), and a
721
794
  // status says what it is doing — loading — to a reader that cannot see the pulse.
722
795
  // @estiva-escape(no-restyled-part): the loading pulse is AttachmentCard's own state; Card has no loading state (UIG-9, Katerina 17 September)
723
- /* @__PURE__ */ jsx11(Card, { role: "status", fill: "inset", "aria-busy": "true", "aria-label": `Loading ${name}`, className: cn("w-[180px] h-28 animate-pulse", className), ...props, children: null })
796
+ /* @__PURE__ */ jsx12(Card, { role: "status", fill: "inset", "aria-busy": "true", "aria-label": `Loading ${name}`, className: cn("w-[180px] h-28 animate-pulse", className), ...props, children: null })
724
797
  );
725
798
  }
726
799
  if (drawnState === "unreadable") {
727
800
  return (
728
801
  // @estiva-escape(no-restyled-part): a file that could not be read is faded as well as dashed, AttachmentCard's own state; Card has no faded state (UIG-9, Katerina 17 September)
729
802
  /* @__PURE__ */ jsxs6(Card, { fill: "inset", unreadable: true, className: cn("flex items-center gap-2 w-[240px] p-1.5 opacity-70", className), ...props, children: [
730
- /* @__PURE__ */ jsx11("div", { className: TILE_CLASSES, children: /* @__PURE__ */ jsx11(TypeIcon, { name }) }),
803
+ /* @__PURE__ */ jsx12("div", { className: TILE_CLASSES, children: /* @__PURE__ */ jsx12(TypeIcon, { name }) }),
731
804
  /* @__PURE__ */ jsxs6("div", { className: "flex flex-col gap-[1px] min-w-0 text-left", children: [
732
- /* @__PURE__ */ jsx11(Truncating, { text: name, className: NAME_CLASSES }),
733
- /* @__PURE__ */ jsx11("span", { className: cn(NOTE_CLASSES, "text-text-secondary"), children: note ?? "Could not be loaded" })
805
+ /* @__PURE__ */ jsx12(Truncating, { text: name, className: NAME_CLASSES }),
806
+ /* @__PURE__ */ jsx12("span", { className: cn(NOTE_CLASSES, "text-text-secondary"), children: note ?? "Could not be loaded" })
734
807
  ] })
735
808
  ] })
736
809
  );
737
810
  }
738
811
  if (image && picture) {
739
- const thumbnail = /* @__PURE__ */ jsx11("img", { src: picture, alt: alt ?? name, className: "w-full h-28 object-cover" });
812
+ const thumbnail = /* @__PURE__ */ jsx12("img", { src: picture, alt: alt ?? name, className: "w-full h-28 object-cover" });
740
813
  return /* @__PURE__ */ jsxs6(Fragment2, { children: [
741
814
  /* @__PURE__ */ jsxs6(Card, { fill: "inset", hover: "hairline", clip: true, className: cn("group relative flex flex-col w-[180px]", className), ...props, children: [
742
- openPicture ? /* @__PURE__ */ jsx11(
743
- BaseButton2,
815
+ openPicture ? /* @__PURE__ */ jsx12(
816
+ BaseButton3,
744
817
  {
745
818
  type: "button",
746
819
  className: "block w-full",
@@ -751,9 +824,9 @@ function AttachmentCard({
751
824
  },
752
825
  children: thumbnail
753
826
  }
754
- ) : /* @__PURE__ */ jsx11("div", { className: "block w-full", children: thumbnail }),
827
+ ) : /* @__PURE__ */ jsx12("div", { className: "block w-full", children: thumbnail }),
755
828
  /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-1 pl-2 pr-1 py-1 min-w-0", children: [
756
- /* @__PURE__ */ jsx11(Truncating, { text: name, className: "flex-1 text-caption text-text-primary truncate", wrapperClassName: "flex-1" }),
829
+ /* @__PURE__ */ jsx12(Truncating, { text: name, className: "flex-1 text-caption text-text-primary truncate", wrapperClassName: "flex-1" }),
757
830
  downloadControl
758
831
  ] })
759
832
  ] }),
@@ -761,16 +834,16 @@ function AttachmentCard({
761
834
  ] });
762
835
  }
763
836
  const body = /* @__PURE__ */ jsxs6(Fragment2, { children: [
764
- /* @__PURE__ */ jsx11("div", { className: TILE_CLASSES, children: /* @__PURE__ */ jsx11(TypeIcon, { name }) }),
837
+ /* @__PURE__ */ jsx12("div", { className: TILE_CLASSES, children: /* @__PURE__ */ jsx12(TypeIcon, { name }) }),
765
838
  /* @__PURE__ */ jsxs6("div", { className: "flex flex-col gap-[1px] min-w-0 text-left", children: [
766
- /* @__PURE__ */ jsx11(Truncating, { text: name, className: NAME_CLASSES }),
767
- /* @__PURE__ */ jsx11("span", { className: cn(NOTE_CLASSES, "text-text-secondary"), children: note ?? `${typeLabelOf(name)} \xB7 ${sizeText}` })
839
+ /* @__PURE__ */ jsx12(Truncating, { text: name, className: NAME_CLASSES }),
840
+ /* @__PURE__ */ jsx12("span", { className: cn(NOTE_CLASSES, "text-text-secondary"), children: note ?? `${typeLabelOf(name)} \xB7 ${sizeText}` })
768
841
  ] })
769
842
  ] });
770
843
  return (
771
844
  // @estiva-escape(no-restyled-part): a file that cannot be opened is faded, AttachmentCard's own state; Card has no faded state (UIG-9, Katerina 17 September)
772
845
  /* @__PURE__ */ jsxs6(Card, { fill: "inset", hover: address ? "hairline" : "none", className: cn("group flex items-center gap-2 w-[240px] p-1.5 pr-1", !address && "opacity-70", className), ...props, children: [
773
- address ? /* @__PURE__ */ jsx11(Link, { href: address, external: true, variant: "plain", className: "flex items-center gap-2 min-w-0 flex-1", onClick: (event) => event.stopPropagation(), children: body }) : /* @__PURE__ */ jsx11("div", { className: "flex items-center gap-2 min-w-0 flex-1", children: body }),
846
+ address ? /* @__PURE__ */ jsx12(Link, { href: address, external: true, variant: "plain", className: "flex items-center gap-2 min-w-0 flex-1", onClick: (event) => event.stopPropagation(), children: body }) : /* @__PURE__ */ jsx12("div", { className: "flex items-center gap-2 min-w-0 flex-1", children: body }),
774
847
  downloadControl
775
848
  ] })
776
849
  );
@@ -779,7 +852,7 @@ function AttachmentCard({
779
852
  // src/Avatar.tsx
780
853
  import { Avatar as BaseAvatar } from "@base-ui/react/avatar";
781
854
  import { IconUserFilled } from "@tabler/icons-react";
782
- import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
855
+ import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
783
856
  var HUES = ["#56c8ff", "#ff8f6b", "#4ade8c", "#b18cff", "#ffc94d", "#ff7eb0", "#7ea8ff", "#5fdfd6"];
784
857
  var hueFor = (key) => {
785
858
  let h = 0;
@@ -793,27 +866,29 @@ var initialsFor = (name) => {
793
866
  };
794
867
  function Avatar({ src, name, alt = "", size = 36, label: spoken, className }) {
795
868
  const label = name || alt;
869
+ const pictureFor = usePictureFor();
870
+ const picture = src ?? (label && pictureFor ? pictureFor(label) ?? void 0 : void 0);
796
871
  return /* @__PURE__ */ jsxs7(
797
872
  BaseAvatar.Root,
798
873
  {
799
- render: /* @__PURE__ */ jsx12("div", {}),
874
+ render: /* @__PURE__ */ jsx13("div", {}),
800
875
  ...spoken ? { role: "img", "aria-label": spoken } : { "aria-hidden": true },
801
876
  className: cn("rounded-sm overflow-hidden shrink-0 bg-bg-inset", className),
802
877
  style: { width: size, height: size },
803
878
  children: [
804
- src && /* @__PURE__ */ jsx12(
879
+ picture && /* @__PURE__ */ jsx13(
805
880
  BaseAvatar.Image,
806
881
  {
807
- src,
882
+ src: picture,
808
883
  alt: "",
809
884
  keepMounted: true,
810
885
  className: "w-full h-full object-cover data-[error]:hidden"
811
886
  }
812
887
  ),
813
- label ? /* @__PURE__ */ jsx12(
888
+ label ? /* @__PURE__ */ jsx13(
814
889
  BaseAvatar.Fallback,
815
890
  {
816
- render: /* @__PURE__ */ jsx12("div", {}),
891
+ render: /* @__PURE__ */ jsx13("div", {}),
817
892
  className: "w-full h-full flex items-center justify-center font-semibold leading-none",
818
893
  style: {
819
894
  /* eslint-disable no-restricted-syntax -- @estiva-escape: the per-person palette (the note at
@@ -827,44 +902,41 @@ function Avatar({ src, name, alt = "", size = 36, label: spoken, className }) {
827
902
  background: `linear-gradient(160deg, color-mix(in srgb, ${hueFor(label)} 92%, #fff) 0%, color-mix(in srgb, ${hueFor(label)} 70%, #0b0d11) 100%)`
828
903
  /* eslint-enable no-restricted-syntax */
829
904
  },
830
- children: /* @__PURE__ */ jsx12("span", { className: "[text-box:trim-both_cap_alphabetic]", children: initialsFor(label) })
905
+ children: /* @__PURE__ */ jsx13("span", { className: "[text-box:trim-both_cap_alphabetic]", children: initialsFor(label) })
831
906
  }
832
- ) : /* @__PURE__ */ jsx12(BaseAvatar.Fallback, { render: /* @__PURE__ */ jsx12("div", {}), className: "w-full h-full bg-accent-muted flex items-center justify-center text-text-muted", children: /* @__PURE__ */ jsx12(IconUserFilled, { size: Math.round(size * 0.5) }) })
907
+ ) : /* @__PURE__ */ jsx13(BaseAvatar.Fallback, { render: /* @__PURE__ */ jsx13("div", {}), className: "w-full h-full bg-accent-muted flex items-center justify-center text-text-muted", children: /* @__PURE__ */ jsx13(IconUserFilled, { size: Math.round(size * 0.5) }) })
833
908
  ]
834
909
  }
835
910
  );
836
911
  }
837
912
 
838
913
  // src/AvatarGroup.tsx
839
- import { jsx as jsx13 } from "react/jsx-runtime";
914
+ import { jsx as jsx14 } from "react/jsx-runtime";
840
915
  function AvatarGroup({ members, size = 24 }) {
841
916
  const visible = members.slice(0, 3);
842
917
  const overlap = Math.round(size / 3);
843
918
  const ring = size / 12;
844
- return /* @__PURE__ */ jsx13("div", { className: "flex items-center", style: { paddingRight: overlap }, children: visible.map((member, i) => (
919
+ return /* @__PURE__ */ jsx14("div", { className: "flex items-center", style: { paddingRight: overlap }, children: visible.map((member, i) => (
845
920
  /*
846
921
  The wrapper carries the overlap and the ring; the face carries
847
922
  neither. It must never clip — see the note at the top of the file —
848
923
  so it has the avatar's own radius and no overflow of its own.
849
924
  */
850
- /* @__PURE__ */ jsx13(
925
+ /* @__PURE__ */ jsx14(
851
926
  "span",
852
927
  {
853
928
  className: "relative flex rounded-sm",
854
929
  style: { marginRight: -overlap, boxShadow: `0 0 0 ${ring}px var(--bg-surface)` },
855
- children: /* @__PURE__ */ jsx13(Avatar, { size, name: member.name, src: member.picture, label: member.name })
930
+ children: /* @__PURE__ */ jsx14(Avatar, { size, name: member.name, src: member.picture, label: member.name })
856
931
  },
857
932
  i
858
933
  )
859
934
  )) });
860
935
  }
861
936
 
862
- // src/Banner.tsx
863
- import { IconX as IconX3 } from "@tabler/icons-react";
864
-
865
937
  // src/Button.tsx
866
- import { Button as BaseButton3 } from "@base-ui/react/button";
867
- import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
938
+ import { Button as BaseButton4 } from "@base-ui/react/button";
939
+ import { jsx as jsx15, jsxs as jsxs8 } from "react/jsx-runtime";
868
940
  function Button({
869
941
  variant = "muted",
870
942
  size = "default",
@@ -879,7 +951,7 @@ function Button({
879
951
  const hasLeadingIcon = !!leadingIcon;
880
952
  const formBusy = useFormBusy();
881
953
  const button = /* @__PURE__ */ jsxs8(
882
- BaseButton3,
954
+ BaseButton4,
883
955
  {
884
956
  type,
885
957
  disabled: disabled || !!disabledReason || formBusy,
@@ -926,64 +998,89 @@ function Button({
926
998
  ]
927
999
  }
928
1000
  );
929
- return disabledReason ? /* @__PURE__ */ jsx14(TooltipTrigger, { label: disabledReason, children: button }) : button;
1001
+ return disabledReason ? /* @__PURE__ */ jsx15(TooltipTrigger, { label: disabledReason, children: button }) : button;
930
1002
  }
931
1003
 
932
- // src/Banner.tsx
933
- import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
934
- var TONE_STYLES = {
935
- ok: "bg-success-muted text-success-default",
936
- error: "bg-error-muted text-error-default",
937
- info: "bg-info-muted text-info-default",
938
- warning: "bg-warning-muted text-warning-default"
1004
+ // src/MembersPill.tsx
1005
+ import { jsx as jsx16, jsxs as jsxs9 } from "react/jsx-runtime";
1006
+ function MembersPill({ members, count, onClick, className }) {
1007
+ const total = count ?? members.length;
1008
+ if (total === 0) return null;
1009
+ return /* @__PURE__ */ jsxs9(Button, { variant: "outlined", "aria-label": `${total} ${total === 1 ? "member" : "members"}`, disabled: !onClick, onClick, className: cn("gap-2 pl-[3px] pr-2", className), children: [
1010
+ /* @__PURE__ */ jsx16(AvatarGroup, { members }),
1011
+ /* @__PURE__ */ jsx16("span", { className: cn(MONO_CAPTION_CLASSES, "signal:tabular-nums"), children: total })
1012
+ ] });
1013
+ }
1014
+
1015
+ // src/MembersDialog.tsx
1016
+ import { useId, useState as useState3 } from "react";
1017
+ import { IconArrowLeft, IconUserMinus, IconUserPlus } from "@tabler/icons-react";
1018
+
1019
+ // src/Chip.tsx
1020
+ import { Fragment as Fragment3, jsx as jsx17, jsxs as jsxs10 } from "react/jsx-runtime";
1021
+ var typeStyles = {
1022
+ neutral: "bg-bg-inset text-text-primary",
1023
+ brand: "bg-accent-muted text-accent-text signal:border signal:border-accent-outline",
1024
+ info: "bg-info-muted text-info-default signal:border signal:border-info-outline",
1025
+ warning: "bg-warning-muted text-warning-default signal:border signal:border-warning-outline signal:shadow-glow-warning",
1026
+ success: "bg-success-muted text-success-default signal:border signal:border-success-outline",
1027
+ error: "bg-error-muted text-error-default signal:border signal:border-error-outline"
939
1028
  };
940
- function Banner({ tone, children, icon, action, onDismiss, dismissLabel = "Dismiss", className }) {
941
- const role = tone === "error" ? "alert" : "status";
942
- if (!onDismiss && !icon && !action) {
943
- return /* @__PURE__ */ jsx15("div", { role, className: cn("px-4 py-2 text-body-2", TONE_STYLES[tone], className), children });
944
- }
945
- const oneLine = Boolean(icon || action);
946
- return /* @__PURE__ */ jsxs9("div", { role, className: cn("flex items-center gap-3 px-4 py-2 text-body-2", TONE_STYLES[tone], className), children: [
947
- icon && /* @__PURE__ */ jsx15("span", { className: "flex shrink-0", children: icon }),
948
- /* @__PURE__ */ jsx15("span", { className: cn("min-w-0 flex-1", oneLine && "truncate"), children }),
949
- action && /* @__PURE__ */ jsx15(Button, { variant: "muted", size: "small", className: "shrink-0", onClick: action.onClick, children: action.label }),
950
- onDismiss && /* @__PURE__ */ jsx15(IconButton, { variant: "current", "aria-label": dismissLabel, onClick: onDismiss, className: "-mr-1 shrink-0", children: /* @__PURE__ */ jsx15(IconX3, { size: 16, stroke: 1.5 }) })
1029
+ function Chip({ type = "neutral", label, leadingIcon, trailingIcon, href, onClick, className }) {
1030
+ const inApp = useInAppClick(href, onClick);
1031
+ const classes = cn("inline-flex min-w-0 items-center justify-center gap-1.5 rounded-full max-h-[20px] px-2 py-1", typeStyles[type], className);
1032
+ const inside = /* @__PURE__ */ jsxs10(Fragment3, { children: [
1033
+ leadingIcon && /* @__PURE__ */ jsx17("span", { className: "flex size-3 shrink-0 items-center justify-center", children: leadingIcon }),
1034
+ label && // A chip given a `max-w-*` cuts a long label with an ellipsis instead
1035
+ // of growing past it — Ship's project chip on an issue row
1036
+ // (2026-09-09). Clipped sideways only: `overflow-x-clip`, not
1037
+ // `truncate`, because `truncate` is `overflow: hidden` on both axes and
1038
+ // the label's line box (11px under Signal) is tighter than its glyphs —
1039
+ // the screenshot diff caught every descender cut off. `clip` is the
1040
+ // one overflow that leaves the other axis visible. A chip with no cap
1041
+ // draws exactly as before.
1042
+ /* @__PURE__ */ jsx17("span", { className: cn("min-w-0 overflow-x-clip text-ellipsis whitespace-nowrap signal:tracking-wide", CHIP_TEXT_CLASSES), children: label }),
1043
+ trailingIcon && /* @__PURE__ */ jsx17("span", { className: "flex size-3 shrink-0 items-center justify-center", children: trailingIcon })
951
1044
  ] });
1045
+ if (href) return /* @__PURE__ */ jsx17("a", { href, onClick: inApp, className: cn("relative", classes), children: inside });
1046
+ return /* @__PURE__ */ jsx17("div", { className: classes, children: inside });
952
1047
  }
953
1048
 
954
- // src/BlockHandle.tsx
955
- import { useCallback, useEffect as useEffect2, useRef as useRef3, useState as useState2 } from "react";
956
- import { IconGripVertical } from "@tabler/icons-react";
1049
+ // src/ChipInput.tsx
1050
+ import { useMemo as useMemo2, useState as useState2 } from "react";
1051
+ import { Button as BaseButton5 } from "@base-ui/react/button";
1052
+ import { Combobox } from "@base-ui/react/combobox";
1053
+ import { IconX as IconX3 } from "@tabler/icons-react";
957
1054
 
958
1055
  // src/Menu.tsx
959
- import { createContext as createContext4, useContext as useContext4 } from "react";
1056
+ import { createContext as createContext5, useContext as useContext5 } from "react";
960
1057
  import { IconChevronRight } from "@tabler/icons-react";
961
1058
  import { Menu as BaseMenu } from "@base-ui/react/menu";
962
1059
 
963
1060
  // src/Divider.tsx
964
- import { createContext as createContext3, useContext as useContext3 } from "react";
1061
+ import { createContext as createContext4, useContext as useContext4 } from "react";
965
1062
  import { Separator } from "@base-ui/react/separator";
966
- import { jsx as jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
967
- var DividerInPanel = createContext3(false);
1063
+ import { jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
1064
+ var DividerInPanel = createContext4(false);
968
1065
  function Divider({ orientation = "horizontal", label, tone = "default", className }) {
969
- const inset = useContext3(DividerInPanel) ? "mx-0" : "mx-3";
1066
+ const inset = useContext4(DividerInPanel) ? "mx-0" : "mx-3";
970
1067
  if (label && orientation === "horizontal") {
971
1068
  const line = tone === "warning" ? "bg-warning-muted" : "bg-border-subtle";
972
- return /* @__PURE__ */ jsxs10(
1069
+ return /* @__PURE__ */ jsxs11(
973
1070
  Separator,
974
1071
  {
975
1072
  orientation: "horizontal",
976
1073
  "aria-label": label,
977
1074
  className: cn("flex shrink-0 items-center gap-2", inset, className),
978
1075
  children: [
979
- /* @__PURE__ */ jsx16("span", { "aria-hidden": "true", className: cn("h-px flex-1", line) }),
980
- /* @__PURE__ */ jsx16("span", { className: cn("shrink-0 text-caption", tone === "warning" ? "text-warning-default" : "text-text-muted"), children: label }),
981
- /* @__PURE__ */ jsx16("span", { "aria-hidden": "true", className: cn("h-px flex-1", line) })
1076
+ /* @__PURE__ */ jsx18("span", { "aria-hidden": "true", className: cn("h-px flex-1", line) }),
1077
+ /* @__PURE__ */ jsx18("span", { className: cn("shrink-0 text-caption", tone === "warning" ? "text-warning-default" : "text-text-muted"), children: label }),
1078
+ /* @__PURE__ */ jsx18("span", { "aria-hidden": "true", className: cn("h-px flex-1", line) })
982
1079
  ]
983
1080
  }
984
1081
  );
985
1082
  }
986
- return /* @__PURE__ */ jsx16(
1083
+ return /* @__PURE__ */ jsx18(
987
1084
  Separator,
988
1085
  {
989
1086
  orientation,
@@ -999,7 +1096,7 @@ function triggerDisabled(trigger) {
999
1096
  }
1000
1097
 
1001
1098
  // src/SectionLabel.tsx
1002
- import { jsx as jsx17 } from "react/jsx-runtime";
1099
+ import { jsx as jsx19 } from "react/jsx-runtime";
1003
1100
  function SectionLabel({
1004
1101
  children,
1005
1102
  tone = "primary",
@@ -1007,7 +1104,7 @@ function SectionLabel({
1007
1104
  folds = false,
1008
1105
  className
1009
1106
  }) {
1010
- return /* @__PURE__ */ jsx17(
1107
+ return /* @__PURE__ */ jsx19(
1011
1108
  "span",
1012
1109
  {
1013
1110
  className: cn(
@@ -1028,10 +1125,10 @@ function SectionLabel({
1028
1125
  }
1029
1126
 
1030
1127
  // src/Menu.tsx
1031
- import { Fragment as Fragment3, jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
1032
- var MenuContext = createContext4(null);
1128
+ import { Fragment as Fragment4, jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
1129
+ var MenuContext = createContext5(null);
1033
1130
  function MenuPanel({ children, className, ...props }) {
1034
- return /* @__PURE__ */ jsx18(
1131
+ return /* @__PURE__ */ jsx20(
1035
1132
  "div",
1036
1133
  {
1037
1134
  className: cn(
@@ -1063,7 +1160,7 @@ var VIEWPORT_PAD2 = 8;
1063
1160
  var HOVER_OPEN_DELAY = 0;
1064
1161
  var HOVER_CLOSE_DELAY = 150;
1065
1162
  function Menu({ trigger, align = "left", openOnHover = false, open, onOpenChange, actionsRef, children, className, contentClassName }) {
1066
- return /* @__PURE__ */ jsxs11(
1163
+ return /* @__PURE__ */ jsxs12(
1067
1164
  BaseMenu.Root,
1068
1165
  {
1069
1166
  open,
@@ -1071,7 +1168,7 @@ function Menu({ trigger, align = "left", openOnHover = false, open, onOpenChange
1071
1168
  actionsRef,
1072
1169
  modal: false,
1073
1170
  children: [
1074
- /* @__PURE__ */ jsx18(
1171
+ /* @__PURE__ */ jsx20(
1075
1172
  BaseMenu.Trigger,
1076
1173
  {
1077
1174
  render: trigger,
@@ -1081,7 +1178,7 @@ function Menu({ trigger, align = "left", openOnHover = false, open, onOpenChange
1081
1178
  closeDelay: HOVER_CLOSE_DELAY
1082
1179
  }
1083
1180
  ),
1084
- /* @__PURE__ */ jsx18(BaseMenu.Portal, { children: /* @__PURE__ */ jsx18(
1181
+ /* @__PURE__ */ jsx20(BaseMenu.Portal, { children: /* @__PURE__ */ jsx20(
1085
1182
  BaseMenu.Positioner,
1086
1183
  {
1087
1184
  side: "bottom",
@@ -1089,13 +1186,13 @@ function Menu({ trigger, align = "left", openOnHover = false, open, onOpenChange
1089
1186
  sideOffset: GAP2,
1090
1187
  collisionPadding: VIEWPORT_PAD2,
1091
1188
  className: "z-50 data-[anchor-hidden]:hidden",
1092
- children: /* @__PURE__ */ jsx18(
1189
+ children: /* @__PURE__ */ jsx20(
1093
1190
  BaseMenu.Popup,
1094
1191
  {
1095
1192
  "data-interactive": true,
1096
1193
  className: cn("min-w-[180px] outline-none p-0", className),
1097
- render: /* @__PURE__ */ jsx18(MenuPanel, {}),
1098
- children: /* @__PURE__ */ jsx18(ScrollArea, { viewportClassName: "max-h-[var(--available-height)]", contentClassName: cn("flex flex-col gap-0.5 p-2", contentClassName), children: /* @__PURE__ */ jsx18(MenuContext.Provider, { value: { openOnHover }, children: /* @__PURE__ */ jsx18(DividerInPanel.Provider, { value: true, children }) }) })
1194
+ render: /* @__PURE__ */ jsx20(MenuPanel, {}),
1195
+ children: /* @__PURE__ */ jsx20(ScrollArea, { viewportClassName: "max-h-[var(--available-height)]", contentClassName: cn("flex flex-col gap-0.5 p-2", contentClassName), children: /* @__PURE__ */ jsx20(MenuContext.Provider, { value: { openOnHover }, children: /* @__PURE__ */ jsx20(DividerInPanel.Provider, { value: true, children }) }) })
1099
1196
  }
1100
1197
  )
1101
1198
  }
@@ -1105,26 +1202,26 @@ function Menu({ trigger, align = "left", openOnHover = false, open, onOpenChange
1105
1202
  );
1106
1203
  }
1107
1204
  function MenuSub({ label, leading, selected, children, className }) {
1108
- const menu = useContext4(MenuContext);
1205
+ const menu = useContext5(MenuContext);
1109
1206
  if (!isProduction() && menu?.openOnHover) {
1110
1207
  console.error(
1111
1208
  '[@estiva-app/ui] Menu: `openOnHover` and `MenuSub` cannot be used together \u2014 leaving the submenu panel strands the menu open. Open this menu on a press instead. See Menu.mdx, "Hover-opened menus".'
1112
1209
  );
1113
1210
  }
1114
- return /* @__PURE__ */ jsxs11(BaseMenu.SubmenuRoot, { children: [
1115
- /* @__PURE__ */ jsx18(
1211
+ return /* @__PURE__ */ jsxs12(BaseMenu.SubmenuRoot, { children: [
1212
+ /* @__PURE__ */ jsx20(
1116
1213
  BaseMenu.SubmenuTrigger,
1117
1214
  {
1118
1215
  openOnHover: true,
1119
1216
  delay: 0,
1120
1217
  closeDelay: 150,
1121
1218
  nativeButton: true,
1122
- render: /* @__PURE__ */ jsx18("button", { type: "button" }),
1219
+ render: /* @__PURE__ */ jsx20("button", { type: "button" }),
1123
1220
  className: menuItemClassName({ size: "default", selected }),
1124
- children: /* @__PURE__ */ jsx18(MenuItemBody, { label, leading, submenu: true })
1221
+ children: /* @__PURE__ */ jsx20(MenuItemBody, { label, leading, submenu: true })
1125
1222
  }
1126
1223
  ),
1127
- /* @__PURE__ */ jsx18(BaseMenu.Portal, { children: /* @__PURE__ */ jsx18(
1224
+ /* @__PURE__ */ jsx20(BaseMenu.Portal, { children: /* @__PURE__ */ jsx20(
1128
1225
  BaseMenu.Positioner,
1129
1226
  {
1130
1227
  side: "inline-end",
@@ -1132,7 +1229,7 @@ function MenuSub({ label, leading, selected, children, className }) {
1132
1229
  sideOffset: GAP2,
1133
1230
  collisionPadding: VIEWPORT_PAD2,
1134
1231
  className: "z-50 data-[anchor-hidden]:hidden",
1135
- children: /* @__PURE__ */ jsx18(BaseMenu.Popup, { className: cn("w-[160px]", className), "data-interactive": true, render: /* @__PURE__ */ jsx18(MenuPanel, {}), children })
1232
+ children: /* @__PURE__ */ jsx20(BaseMenu.Popup, { className: cn("w-[160px]", className), "data-interactive": true, render: /* @__PURE__ */ jsx20(MenuPanel, {}), children })
1136
1233
  }
1137
1234
  ) })
1138
1235
  ] });
@@ -1167,25 +1264,25 @@ function menuItemClassName({ size, selected, className }) {
1167
1264
  );
1168
1265
  }
1169
1266
  function MenuItemBody({ label, children, size = "default", description, leading, trailing, hint, shortcut, submenu, destructive, selected }) {
1170
- const edge = trailing ?? (shortcut ? /* @__PURE__ */ jsx18(Kbd, { children: shortcut }) : submenu ? /* @__PURE__ */ jsx18(IconChevronRight, { size: 16, stroke: 1.5, className: "shrink-0 text-text-muted" }) : null);
1171
- return /* @__PURE__ */ jsxs11(Fragment3, { children: [
1172
- leading && /* @__PURE__ */ jsx18("span", { className: "flex shrink-0 items-center", children: leading }),
1173
- children ?? /* @__PURE__ */ jsxs11("span", { className: cn("flex min-w-0 flex-1 flex-col", size === "tall" && "gap-[2px]"), children: [
1174
- /* @__PURE__ */ jsx18("span", { className: cn("truncate text-body-2", destructive ? "text-error-default" : "text-text-primary"), children: label }),
1175
- description && /* @__PURE__ */ jsx18("span", { className: "truncate text-caption text-text-secondary", children: description })
1267
+ const edge = trailing ?? (shortcut ? /* @__PURE__ */ jsx20(Kbd, { children: shortcut }) : submenu ? /* @__PURE__ */ jsx20(IconChevronRight, { size: 16, stroke: 1.5, className: "shrink-0 text-text-muted" }) : null);
1268
+ return /* @__PURE__ */ jsxs12(Fragment4, { children: [
1269
+ leading && /* @__PURE__ */ jsx20("span", { className: "flex shrink-0 items-center", children: leading }),
1270
+ children ?? /* @__PURE__ */ jsxs12("span", { className: cn("flex min-w-0 flex-1 flex-col", size === "tall" && "gap-[2px]"), children: [
1271
+ /* @__PURE__ */ jsx20("span", { className: cn("truncate text-body-2", destructive ? "text-error-default" : "text-text-primary"), children: label }),
1272
+ description && /* @__PURE__ */ jsx20("span", { className: "truncate text-caption text-text-secondary", children: description })
1176
1273
  ] }),
1177
1274
  (edge || hint) && // One grid cell holding both, right-aligned: the slot is as wide as
1178
1275
  // the wider of the two and never changes, so revealing the hint moves
1179
1276
  // nothing. No transition here either — the hint switches on the same
1180
1277
  // :hover / `selected` as the fill, in the same frame.
1181
- /* @__PURE__ */ jsxs11("span", { className: "grid shrink-0 items-center justify-items-end [&>*]:col-start-1 [&>*]:row-start-1", children: [
1182
- edge && /* @__PURE__ */ jsx18("span", { className: cn("flex items-center", hint && "group-hover:opacity-0 group-data-[highlighted]:opacity-0", hint && selected && "opacity-0"), children: edge }),
1183
- hint && /* @__PURE__ */ jsx18("span", { className: cn("flex items-center opacity-0 group-hover:opacity-100 group-data-[highlighted]:opacity-100", selected && "opacity-100"), children: hint })
1278
+ /* @__PURE__ */ jsxs12("span", { className: "grid shrink-0 items-center justify-items-end [&>*]:col-start-1 [&>*]:row-start-1", children: [
1279
+ edge && /* @__PURE__ */ jsx20("span", { className: cn("flex items-center", hint && "group-hover:opacity-0 group-data-[highlighted]:opacity-0", hint && selected && "opacity-0"), children: edge }),
1280
+ hint && /* @__PURE__ */ jsx20("span", { className: cn("flex items-center opacity-0 group-hover:opacity-100 group-data-[highlighted]:opacity-100", selected && "opacity-100"), children: hint })
1184
1281
  ] })
1185
1282
  ] });
1186
1283
  }
1187
1284
  function MenuItem({ label, children, size = "default", description, leading, trailing, hint, shortcut, submenu, destructive, selected, className, ...props }) {
1188
- const body = /* @__PURE__ */ jsx18(
1285
+ const body = /* @__PURE__ */ jsx20(
1189
1286
  MenuItemBody,
1190
1287
  {
1191
1288
  label,
@@ -1202,14 +1299,14 @@ function MenuItem({ label, children, size = "default", description, leading, tra
1202
1299
  }
1203
1300
  );
1204
1301
  const rowClassName = menuItemClassName({ size, selected, className });
1205
- if (!useContext4(MenuContext)) {
1206
- return /* @__PURE__ */ jsx18("button", { type: "button", className: rowClassName, ...props, children: body });
1302
+ if (!useContext5(MenuContext)) {
1303
+ return /* @__PURE__ */ jsx20("button", { type: "button", className: rowClassName, ...props, children: body });
1207
1304
  }
1208
- return /* @__PURE__ */ jsx18(
1305
+ return /* @__PURE__ */ jsx20(
1209
1306
  BaseMenu.Item,
1210
1307
  {
1211
1308
  nativeButton: true,
1212
- render: /* @__PURE__ */ jsx18("button", { type: "button" }),
1309
+ render: /* @__PURE__ */ jsx20("button", { type: "button" }),
1213
1310
  className: rowClassName,
1214
1311
  ...props,
1215
1312
  children: body
@@ -1217,86 +1314,581 @@ function MenuItem({ label, children, size = "default", description, leading, tra
1217
1314
  );
1218
1315
  }
1219
1316
  function EnterHint({ target }) {
1220
- return /* @__PURE__ */ jsxs11("span", { className: "flex shrink-0 items-center gap-1.5 text-text-muted", children: [
1221
- /* @__PURE__ */ jsx18(Kbd, { children: "\u21A9 Enter" }),
1222
- target && /* @__PURE__ */ jsx18("span", { className: "text-menu signal:font-mono signal:text-small signal:tracking-wider leaf:font-mono leaf:text-small leaf:tracking-wider", children: target })
1317
+ return /* @__PURE__ */ jsxs12("span", { className: "flex shrink-0 items-center gap-1.5 text-text-muted", children: [
1318
+ /* @__PURE__ */ jsx20(Kbd, { children: "\u21A9 Enter" }),
1319
+ target && /* @__PURE__ */ jsx20("span", { className: "text-menu signal:font-mono signal:text-small signal:tracking-wider leaf:font-mono leaf:text-small leaf:tracking-wider", children: target })
1223
1320
  ] });
1224
1321
  }
1225
1322
  function MenuSection({ label, children, className }) {
1226
- const inMenu = useContext4(MenuContext) !== null;
1227
- const heading = /* @__PURE__ */ jsx18("div", { className: cn("flex h-8 items-center px-2", className), children: /* @__PURE__ */ jsx18(SectionLabel, { tone: "secondary", children: label }) });
1323
+ const inMenu = useContext5(MenuContext) !== null;
1324
+ const heading = /* @__PURE__ */ jsx20("div", { className: cn("flex h-8 items-center px-2", className), children: /* @__PURE__ */ jsx20(SectionLabel, { tone: "secondary", children: label }) });
1228
1325
  if (!inMenu) {
1229
- return /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-0.5", children: [
1326
+ return /* @__PURE__ */ jsxs12("div", { className: "flex flex-col gap-0.5", children: [
1230
1327
  heading,
1231
1328
  children
1232
1329
  ] });
1233
1330
  }
1234
- return /* @__PURE__ */ jsxs11(BaseMenu.Group, { className: "flex flex-col gap-0.5", children: [
1235
- /* @__PURE__ */ jsx18(BaseMenu.GroupLabel, { render: heading }),
1331
+ return /* @__PURE__ */ jsxs12(BaseMenu.Group, { className: "flex flex-col gap-0.5", children: [
1332
+ /* @__PURE__ */ jsx20(BaseMenu.GroupLabel, { render: heading }),
1236
1333
  children
1237
1334
  ] });
1238
1335
  }
1239
1336
  function MenuSeparator() {
1240
- return /* @__PURE__ */ jsx18(Divider, { className: "my-1" });
1337
+ return /* @__PURE__ */ jsx20(Divider, { className: "my-1" });
1241
1338
  }
1242
1339
  function MenuRow({ children, className }) {
1243
- return /* @__PURE__ */ jsx18("div", { className: cn("flex items-center gap-2 px-2 py-1.5", className), children });
1340
+ return /* @__PURE__ */ jsx20("div", { className: cn("flex items-center gap-2 px-2 py-1.5", className), children });
1244
1341
  }
1245
1342
 
1246
- // src/BlockHandle.tsx
1247
- import { jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
1248
- function readId(element) {
1249
- const own = element.getAttribute("data-block-id") ?? element.querySelector("[data-block-id]")?.getAttribute("data-block-id");
1250
- return own || void 0;
1251
- }
1252
- function blockAtY(blocks, y) {
1253
- let found = null;
1254
- for (const block of blocks) {
1255
- if (block.element.getBoundingClientRect().top > y) break;
1256
- found = block;
1257
- }
1258
- return found ?? blocks[0] ?? null;
1259
- }
1260
- function readingBlocks(root) {
1261
- if (!root) return [];
1262
- return Array.from(root.children).filter((el) => el instanceof HTMLElement).map((element) => ({ id: readId(element), element })).filter((b) => b.id !== void 0);
1263
- }
1264
- var HANDLE = 24;
1265
- function firstLineOffset(element) {
1266
- const text = element.querySelector("p, h1, h2, h3, pre, li") ?? element;
1267
- const line = parseFloat(getComputedStyle(text).lineHeight);
1268
- if (!Number.isFinite(line)) return 0;
1269
- const inset = text === element ? 0 : text.getBoundingClientRect().top - element.getBoundingClientRect().top;
1270
- return inset + (line - HANDLE) / 2;
1343
+ // src/ChipInput.tsx
1344
+ import { jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
1345
+ var CHIP_BOX = (
1346
+ // Curved, not a pill (Katerina, 2026-09-01): the Avatar keeps its own
1347
+ // rounded-sm corners — never a forced circle — and the chip's corner
1348
+ // follows concentrically: 4px face + 2px inset = rounded-md.
1349
+ "inline-flex items-center gap-1.5 bg-bg-elevated border border-border-subtle rounded-md py-0.5 max-h-[24px]"
1350
+ );
1351
+ var CHIP_LABEL = "text-caption font-medium text-text-primary";
1352
+ var CHIP_REMOVE = "size-4 flex items-center justify-center rounded-full hover:bg-bg-hover text-text-secondary";
1353
+ var chipPadding = (leading, removable) => cn(leading ? "pl-[2px]" : "pl-2", removable ? "pr-1" : "pr-2");
1354
+ function InputChip({ label, leading, onRemove, removeLabel, truncate, className }) {
1355
+ return /* @__PURE__ */ jsxs13("div", { className: cn(CHIP_BOX, chipPadding(!!leading, !!onRemove), className), children: [
1356
+ leading && /* @__PURE__ */ jsx21("span", { className: "flex shrink-0 items-center", children: leading }),
1357
+ /* @__PURE__ */ jsx21("span", { className: cn(CHIP_LABEL, truncate && "min-w-0 truncate"), children: label }),
1358
+ onRemove && /* @__PURE__ */ jsx21(
1359
+ BaseButton5,
1360
+ {
1361
+ type: "button",
1362
+ onClick: (e) => {
1363
+ e.stopPropagation();
1364
+ onRemove();
1365
+ },
1366
+ className: cn(CHIP_REMOVE, truncate && "shrink-0"),
1367
+ "aria-label": removeLabel ?? `Remove ${label}`,
1368
+ children: /* @__PURE__ */ jsx21(IconX3, { size: 10, stroke: 1.5 })
1369
+ }
1370
+ )
1371
+ ] });
1271
1372
  }
1272
- function BlockHandle({ actions, editing, children, className }) {
1273
- const frame = useRef3(null);
1274
- const content = useRef3(null);
1275
- const [block, setBlock] = useState2(null);
1276
- const [top, setTop] = useState2(0);
1277
- const [open, setOpen] = useState2(false);
1278
- const follow = useCallback(
1279
- (y) => {
1280
- if (!content.current || !frame.current) return;
1281
- const found = editing ? editing.find(y) : blockAtY(readingBlocks(content.current.firstElementChild), y);
1282
- setBlock(found);
1283
- if (found) setTop(found.element.getBoundingClientRect().top - frame.current.getBoundingClientRect().top + firstLineOffset(found.element));
1373
+ function ChipInput({
1374
+ value,
1375
+ onChange,
1376
+ options,
1377
+ placeholder = "Search\u2026",
1378
+ autoFocus,
1379
+ excludeIds = [],
1380
+ chipLeading,
1381
+ rowLeading,
1382
+ ...aria
1383
+ }) {
1384
+ const [query, setQuery] = useState2("");
1385
+ const [box, setBox] = useState2(null);
1386
+ const available = useMemo2(() => {
1387
+ const chosen = new Set(value.map((o) => o.id));
1388
+ const excluded = new Set(excludeIds);
1389
+ return options.filter((o) => !chosen.has(o.id) && !excluded.has(o.id));
1390
+ }, [options, value, excludeIds]);
1391
+ const filter = useMemo2(
1392
+ () => (item, q) => {
1393
+ const needle = q.trim().toLowerCase();
1394
+ if (!needle) return true;
1395
+ return item.label.toLowerCase().includes(needle) || (item.description ?? "").toLowerCase().includes(needle);
1284
1396
  },
1285
- [editing]
1397
+ []
1286
1398
  );
1287
- useEffect2(() => {
1288
- if (!editing) return;
1289
- return editing.onChange(() => {
1290
- if (!open) setBlock(null);
1291
- });
1292
- }, [editing, open]);
1293
- const rows = editing && block ? editing.rows(block) : null;
1294
- const own = actions && block ? actions(block) : null;
1295
- const dragging = useRef3(false);
1296
- const [line, setLine] = useState2(null);
1297
- const inGutter = (e) => dragging.current && !!editing && !!content.current && !content.current.contains(e.target);
1298
- const landing = (y) => {
1299
- const target = editing?.find(y);
1399
+ const open = query.trim().length > 0;
1400
+ const ariaLabel = aria["aria-label"] ?? (value.length > 0 ? placeholder : void 0);
1401
+ const naming = {
1402
+ ...ariaLabel !== void 0 && { "aria-label": ariaLabel },
1403
+ ...aria["aria-labelledby"] !== void 0 && { "aria-labelledby": aria["aria-labelledby"] }
1404
+ };
1405
+ function removeLast() {
1406
+ if (value.length > 0) onChange(value.slice(0, -1));
1407
+ }
1408
+ function onInputKeyDown(event) {
1409
+ if (event.key === "Backspace" && query === "" && value.length > 0) {
1410
+ event.preventDefault();
1411
+ event.stopPropagation();
1412
+ removeLast();
1413
+ return;
1414
+ }
1415
+ if (event.key === "Escape" && query !== "") {
1416
+ event.preventDefault();
1417
+ event.stopPropagation();
1418
+ setQuery("");
1419
+ }
1420
+ }
1421
+ return /* @__PURE__ */ jsxs13(
1422
+ Combobox.Root,
1423
+ {
1424
+ multiple: true,
1425
+ items: available,
1426
+ value,
1427
+ onValueChange: (next) => {
1428
+ onChange(next);
1429
+ setQuery("");
1430
+ },
1431
+ inputValue: query,
1432
+ onInputValueChange: setQuery,
1433
+ open,
1434
+ openOnInputClick: false,
1435
+ filter,
1436
+ itemToStringLabel: (option) => option.label,
1437
+ children: [
1438
+ /* @__PURE__ */ jsxs13(Combobox.Chips, { ref: setBox, className: cn(FIELD_SHELL_CLASSES, "focus-within:border-border-focus focus-within:hover:border-border-focus group-hover/field:focus-within:border-border-focus px-3 py-1.5 flex flex-wrap items-center gap-1.5 min-h-[38px] cursor-text signal:transition-shadow signal:focus-within:shadow-focus-ring"), children: [
1439
+ value.map((option) => /* @__PURE__ */ jsxs13(Combobox.Chip, { className: cn(CHIP_BOX, chipPadding(!!chipLeading, true)), children: [
1440
+ chipLeading && /* @__PURE__ */ jsx21("span", { className: "flex shrink-0 items-center", children: chipLeading(option) }),
1441
+ /* @__PURE__ */ jsx21("span", { className: CHIP_LABEL, children: option.label }),
1442
+ /* @__PURE__ */ jsx21(Combobox.ChipRemove, { className: CHIP_REMOVE, "aria-label": `Remove ${option.label}`, children: /* @__PURE__ */ jsx21(IconX3, { size: 10, stroke: 1.5 }) })
1443
+ ] }, option.id)),
1444
+ /* @__PURE__ */ jsx21(
1445
+ Combobox.Input,
1446
+ {
1447
+ autoFocus,
1448
+ placeholder: value.length === 0 ? placeholder : "",
1449
+ "aria-required": aria["aria-required"],
1450
+ ...naming,
1451
+ onKeyDown: onInputKeyDown,
1452
+ className: cn("flex-1 min-w-[120px] text-body-2 border-none", BARE_INPUT_CLASSES)
1453
+ }
1454
+ )
1455
+ ] }),
1456
+ /* @__PURE__ */ jsx21(Combobox.Portal, { children: /* @__PURE__ */ jsx21(
1457
+ Combobox.Positioner,
1458
+ {
1459
+ anchor: box,
1460
+ sideOffset: GAP3,
1461
+ collisionPadding: VIEWPORT_PAD3,
1462
+ className: "z-50 data-[anchor-hidden]:hidden",
1463
+ children: /* @__PURE__ */ jsx21(Combobox.Popup, { className: "w-[var(--anchor-width)] p-0", render: /* @__PURE__ */ jsx21(MenuPanel, {}), children: /* @__PURE__ */ jsx21(ScrollArea, { viewportClassName: "max-h-[240px]", contentClassName: "flex flex-col p-2", children: /* @__PURE__ */ jsx21(Combobox.List, { className: "flex flex-col gap-0.5", children: (option) => /* @__PURE__ */ jsx21(
1464
+ Combobox.Item,
1465
+ {
1466
+ value: option,
1467
+ render: /* @__PURE__ */ jsx21(
1468
+ MenuItem,
1469
+ {
1470
+ size: "tall",
1471
+ leading: rowLeading?.(option),
1472
+ label: option.label,
1473
+ description: option.description
1474
+ }
1475
+ )
1476
+ },
1477
+ option.id
1478
+ ) }) }) })
1479
+ }
1480
+ ) })
1481
+ ]
1482
+ }
1483
+ );
1484
+ }
1485
+ var GAP3 = 4;
1486
+ var VIEWPORT_PAD3 = 8;
1487
+
1488
+ // src/DialogShell.tsx
1489
+ import { useRef as useRef4 } from "react";
1490
+ import { Dialog as Dialog2 } from "@base-ui/react/dialog";
1491
+ import { AlertDialog } from "@base-ui/react/alert-dialog";
1492
+ import { IconX as IconX4 } from "@tabler/icons-react";
1493
+
1494
+ // src/ContainerHeader.tsx
1495
+ import { IconChevronDown } from "@tabler/icons-react";
1496
+ import { Button as BaseButton6 } from "@base-ui/react/button";
1497
+ import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
1498
+ function ContainerHeader({ title, chevron = false, titleMenu, actions, className }) {
1499
+ const text = typeof title === "string";
1500
+ const name = /* @__PURE__ */ jsxs14("div", { className: cn("flex items-center gap-1", text ? "shrink-0" : "min-w-0 flex-1"), children: [
1501
+ text ? /* @__PURE__ */ jsx22("span", { className: "whitespace-nowrap text-body-2-strong text-text-primary", children: title }) : /* @__PURE__ */ jsx22("div", { className: "min-w-0 flex-1", children: title }),
1502
+ (chevron || titleMenu != null) && /* @__PURE__ */ jsx22(IconChevronDown, { size: 12, stroke: 1.5, className: "shrink-0 text-text-secondary" })
1503
+ ] });
1504
+ return (
1505
+ // The title 16px in, where the column's content starts (Katerina, 7 October; it was 20px).
1506
+ // With a title menu the bar gives the button 6px of its left padding
1507
+ // (pl-2.5 + the button's px-1.5 = pl-4): the words stay where a title's
1508
+ // are, and the fill is inside the bar — a negative margin had it clipped
1509
+ // (Katerina, 5 October).
1510
+ /* @__PURE__ */ jsxs14("div", { className: cn("flex h-12 shrink-0 items-center justify-between overflow-hidden border-b border-border-subtle py-2 pr-4", titleMenu != null ? "pl-2.5" : "pl-4", className), children: [
1511
+ /* @__PURE__ */ jsx22("div", { className: cn("flex items-center gap-2 overflow-hidden", text ? "shrink-0" : "min-w-0 flex-1"), children: titleMenu != null ? /* @__PURE__ */ jsx22(
1512
+ Menu,
1513
+ {
1514
+ trigger: /* @__PURE__ */ jsx22(BaseButton6, { type: "button", className: cn("flex min-w-0 items-center px-1.5 py-1", MENU_TRIGGER_CLASSES), children: name }),
1515
+ children: titleMenu
1516
+ }
1517
+ ) : name }),
1518
+ actions && /* @__PURE__ */ jsx22("div", { className: "flex shrink-0 items-center justify-end gap-3", children: /* @__PURE__ */ jsx22("div", { className: "flex shrink-0 items-center gap-1", children: actions }) })
1519
+ ] })
1520
+ );
1521
+ }
1522
+
1523
+ // src/DialogShell.tsx
1524
+ import { jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
1525
+ function DialogShell({ title, onClose, headerContent, footer, children, bodyClassName, bodyMaxHeight, width = 502, alert = false }) {
1526
+ const Parts = alert ? AlertDialog : Dialog2;
1527
+ const popupRef = useRef4(null);
1528
+ return /* @__PURE__ */ jsx23(
1529
+ Parts.Root,
1530
+ {
1531
+ open: true,
1532
+ onOpenChange: (open) => {
1533
+ if (!open) onClose();
1534
+ },
1535
+ children: /* @__PURE__ */ jsxs15(Parts.Portal, { children: [
1536
+ /* @__PURE__ */ jsx23(Parts.Backdrop, { className: "fixed inset-0 z-40 bg-scrim" }),
1537
+ /* @__PURE__ */ jsx23("div", { className: "fixed inset-0 z-50 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxs15(
1538
+ Parts.Popup,
1539
+ {
1540
+ ref: popupRef,
1541
+ initialFocus: popupRef,
1542
+ "aria-label": headerContent != null ? title : void 0,
1543
+ className: "bg-bg-elevated border border-border-subtle rounded-lg shadow-lg pointer-events-auto flex flex-col overflow-hidden outline-none",
1544
+ style: { width },
1545
+ children: [
1546
+ /* @__PURE__ */ jsx23(
1547
+ ContainerHeader,
1548
+ {
1549
+ className: "pl-5",
1550
+ title: headerContent ?? /* @__PURE__ */ jsx23(Parts.Title, { className: "block truncate text-h4 text-text-primary", render: /* @__PURE__ */ jsx23("span", {}), children: title }),
1551
+ actions: (
1552
+ /*
1553
+ The ✕ IS the `Close` part now, rather than a button that calls
1554
+ `onClose` beside one (stage 4, 2026-09-07). Stage 3 could not do
1555
+ this: an `IconButton` carrying a `tooltip` returned the tooltip
1556
+ wrapper `<div>` as its root, so the part composed onto the
1557
+ wrapper and not the button. Porting Tooltip removed the wrapper
1558
+ — the trigger is the button itself — and the composition works.
1559
+
1560
+ What it buys: the dialog closes through its own state machine,
1561
+ so the ✕, Escape and the outside press are one path with one
1562
+ reason attached, instead of one of the three going around.
1563
+ */
1564
+ /* @__PURE__ */ jsx23(
1565
+ Parts.Close,
1566
+ {
1567
+ render: /* @__PURE__ */ jsx23(IconButton, { tooltip: "Close", "aria-label": "Close", children: /* @__PURE__ */ jsx23(IconX4, { size: 16, stroke: 1.5 }) })
1568
+ }
1569
+ )
1570
+ )
1571
+ }
1572
+ ),
1573
+ bodyMaxHeight ? (
1574
+ // The line above the footer on a box of the shell's own, not pushed into ScrollArea (UIG-9).
1575
+ /* @__PURE__ */ jsx23("div", { className: cn(footer != null && "border-b border-border-subtle"), children: /* @__PURE__ */ jsx23(ScrollArea, { viewportClassName: bodyMaxHeight, contentClassName: cn("pl-5 pr-4 py-4", bodyClassName), children }) })
1576
+ ) : /* @__PURE__ */ jsx23("div", { className: cn("pl-5 pr-4 py-4", footer != null && "border-b border-border-subtle", bodyClassName), children }),
1577
+ footer != null && /* @__PURE__ */ jsx23("div", { className: "h-12 flex items-center justify-end gap-2 pl-5 pr-4 shrink-0", children: footer })
1578
+ ]
1579
+ }
1580
+ ) })
1581
+ ] })
1582
+ }
1583
+ );
1584
+ }
1585
+
1586
+ // src/Field.tsx
1587
+ import { cloneElement, isValidElement } from "react";
1588
+ import { Field as BaseField } from "@base-ui/react/field";
1589
+ import { jsx as jsx24, jsxs as jsxs16 } from "react/jsx-runtime";
1590
+ var LINE_STYLES = {
1591
+ helper: "text-caption text-text-muted",
1592
+ warning: "text-caption text-warning-default",
1593
+ error: "text-caption text-error-default"
1594
+ };
1595
+ function Field({ label, required = false, helper, error, children }) {
1596
+ const control = required && isValidElement(children) ? cloneElement(children, {
1597
+ "aria-required": children.props["aria-required"] ?? true
1598
+ }) : children;
1599
+ return (
1600
+ // `group/field`: the label, the box and the line under it are one thing under the pointer —
1601
+ // anywhere in it strengthens the box's border, as hovering the box does (Katerina, 28 September).
1602
+ // Before, the 8px between the label and the box was a gap where the border went out again.
1603
+ /* @__PURE__ */ jsxs16(BaseField.Root, { invalid: !!error, className: "group/field flex flex-col gap-2", children: [
1604
+ /* @__PURE__ */ jsxs16(BaseField.Label, { className: cn("text-input-label text-text-primary", required && "flex items-center"), children: [
1605
+ label,
1606
+ required && /* @__PURE__ */ jsx24("span", { "aria-hidden": "true", className: "text-error-default ml-0.5", children: "*" })
1607
+ ] }),
1608
+ /* @__PURE__ */ jsxs16("div", { className: "flex flex-col gap-1.5", children: [
1609
+ control,
1610
+ error != null ? /* @__PURE__ */ jsx24(BaseField.Error, { match: true, className: LINE_STYLES.error, children: error }) : helper != null ? /* @__PURE__ */ jsx24(BaseField.Description, { className: LINE_STYLES.helper, children: helper }) : null
1611
+ ] })
1612
+ ] })
1613
+ );
1614
+ }
1615
+ function FieldLine({ tone = "helper", children, className }) {
1616
+ return /* @__PURE__ */ jsx24("p", { role: tone === "error" ? "alert" : "status", className: cn(LINE_STYLES[tone], className), children });
1617
+ }
1618
+
1619
+ // src/Form.tsx
1620
+ import { useLayoutEffect as useLayoutEffect2, useRef as useRef5 } from "react";
1621
+ import { Fieldset } from "@base-ui/react/fieldset";
1622
+ import { Form as BaseForm } from "@base-ui/react/form";
1623
+ import { jsx as jsx25 } from "react/jsx-runtime";
1624
+ var FIELDS_CLASSES = "flex flex-col gap-6";
1625
+ var CONTROL = 'input:not([type="hidden"]), textarea, select, button, [role="checkbox"], [role="combobox"], [tabindex]:not([tabindex="-1"])';
1626
+ var ONE_LINE = /* @__PURE__ */ new Set(["", "text", "search", "email", "url", "tel", "password", "number"]);
1627
+ function usable(element) {
1628
+ return element instanceof HTMLElement && element.isConnected && element.matches(CONTROL) && !element.matches(":disabled") && element.getAttribute("aria-disabled") !== "true";
1629
+ }
1630
+ function firstInvalid(form) {
1631
+ for (const marked of form.querySelectorAll("[data-invalid]")) {
1632
+ if (usable(marked)) return marked;
1633
+ const inside = Array.from(marked.querySelectorAll(CONTROL)).find(usable);
1634
+ if (inside) return inside;
1635
+ }
1636
+ return void 0;
1637
+ }
1638
+ function Form({ onSubmit, busy: ownBusy = false, enterSends = true, layout = "fields", className, children, ...props }) {
1639
+ const outerBusy = useFormBusy();
1640
+ const busy = ownBusy || outerBusy;
1641
+ const form = useRef5(null);
1642
+ const busyNow = useRef5(busy);
1643
+ busyNow.current = busy;
1644
+ const sender = useRef5(null);
1645
+ const holding = useRef5(false);
1646
+ const lastInside = useRef5(null);
1647
+ useLayoutEffect2(() => {
1648
+ const element = form.current;
1649
+ if (!element) return;
1650
+ if (busy) {
1651
+ const active = document.activeElement;
1652
+ const from = active && active !== element && element.contains(active) ? active : !active || active === document.body ? lastInside.current : null;
1653
+ if (from?.isConnected) {
1654
+ sender.current = from;
1655
+ holding.current = true;
1656
+ element.focus();
1657
+ }
1658
+ return;
1659
+ }
1660
+ if (!holding.current) return;
1661
+ holding.current = false;
1662
+ if (document.activeElement !== element && document.activeElement !== document.body) return;
1663
+ const target = firstInvalid(element) ?? (usable(sender.current) ? sender.current : Array.from(element.querySelectorAll(CONTROL)).find(usable));
1664
+ sender.current = null;
1665
+ target?.focus();
1666
+ }, [busy]);
1667
+ const onKeyDown = (event) => {
1668
+ props.onKeyDown?.(event);
1669
+ if (event.key !== "Enter" || event.defaultPrevented || event.nativeEvent.isComposing) return;
1670
+ const target = event.target;
1671
+ const inInput = target instanceof HTMLInputElement;
1672
+ if (inInput) event.preventDefault();
1673
+ if (event.altKey || event.shiftKey) return;
1674
+ if (event.ctrlKey || event.metaKey) {
1675
+ event.preventDefault();
1676
+ form.current?.requestSubmit();
1677
+ return;
1678
+ }
1679
+ if (!inInput) return;
1680
+ const oneLine = ONE_LINE.has((target.getAttribute("type") ?? "").toLowerCase()) && target.getAttribute("role") !== "combobox";
1681
+ if (enterSends && oneLine) form.current?.requestSubmit();
1682
+ };
1683
+ return /* @__PURE__ */ jsx25(
1684
+ BaseForm,
1685
+ {
1686
+ ref: form,
1687
+ ...props,
1688
+ tabIndex: busy ? -1 : props.tabIndex,
1689
+ className: cn("outline-none", layout === "fields" && FIELDS_CLASSES, className),
1690
+ onFocus: (event) => {
1691
+ if (event.target !== form.current) lastInside.current = event.target;
1692
+ props.onFocus?.(event);
1693
+ },
1694
+ onBlur: (event) => {
1695
+ const next = event.relatedTarget;
1696
+ if (next && !form.current?.contains(next)) lastInside.current = null;
1697
+ props.onBlur?.(event);
1698
+ },
1699
+ onKeyDown,
1700
+ onSubmit: (event) => {
1701
+ if (event.target !== event.currentTarget) return;
1702
+ event.preventDefault();
1703
+ if (busyNow.current) return;
1704
+ void onSubmit();
1705
+ },
1706
+ children: /* @__PURE__ */ jsx25(Fieldset.Root, { disabled: busy, className: "contents", children: /* @__PURE__ */ jsx25(FormBusyContext.Provider, { value: busy, children }) })
1707
+ }
1708
+ );
1709
+ }
1710
+
1711
+ // src/MembersDialog.tsx
1712
+ import { Fragment as Fragment5, jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
1713
+ var LEADING_CLASSES = "size-8 rounded-md bg-accent-muted flex items-center justify-center shrink-0 text-accent-primary";
1714
+ function MembersDialog({ members, count, self, candidates = [], onAdd, note, initialView = "list", onClose }) {
1715
+ const [view, setView] = useState3(onAdd ? initialView : "list");
1716
+ const [chosen, setChosen] = useState3([]);
1717
+ const [toggling, setToggling] = useState3(false);
1718
+ const formId = useId();
1719
+ const toggle = async () => {
1720
+ if (!self || toggling) return;
1721
+ setToggling(true);
1722
+ try {
1723
+ await self.onToggle();
1724
+ } finally {
1725
+ setToggling(false);
1726
+ }
1727
+ };
1728
+ const add = async () => {
1729
+ if (!onAdd || chosen.length === 0) return;
1730
+ if (await onAdd(chosen) === false) return;
1731
+ setChosen([]);
1732
+ setView("list");
1733
+ };
1734
+ if (view === "add" && onAdd) {
1735
+ return /* @__PURE__ */ jsx26(
1736
+ DialogShell,
1737
+ {
1738
+ title: "Add members",
1739
+ onClose,
1740
+ headerContent: /* @__PURE__ */ jsxs17("div", { className: "flex min-w-0 items-center gap-2", children: [
1741
+ /* @__PURE__ */ jsx26(IconButton, { tooltip: "Back to members", "aria-label": "Back to members", className: "-ml-2", onClick: () => setView("list"), children: /* @__PURE__ */ jsx26(IconArrowLeft, { size: 16, stroke: 1.5 }) }),
1742
+ /* @__PURE__ */ jsx26("span", { className: "truncate text-h4 text-text-primary", children: "Add members" })
1743
+ ] }),
1744
+ bodyClassName: "flex flex-col gap-6",
1745
+ footer: /* @__PURE__ */ jsxs17(Fragment5, { children: [
1746
+ /* @__PURE__ */ jsx26(Button, { variant: "muted", onClick: onClose, children: "Cancel" }),
1747
+ /* @__PURE__ */ jsx26(Button, { variant: "primary", type: "submit", form: formId, disabled: chosen.length === 0, children: "Invite" })
1748
+ ] }),
1749
+ children: /* @__PURE__ */ jsx26(Form, { id: formId, onSubmit: add, children: /* @__PURE__ */ jsx26(Field, { label: "Invite people", required: true, children: /* @__PURE__ */ jsx26(
1750
+ ChipInput,
1751
+ {
1752
+ value: chosen,
1753
+ onChange: setChosen,
1754
+ options: candidates,
1755
+ placeholder: "Search people...",
1756
+ excludeIds: members.map((m) => m.id),
1757
+ chipLeading: (o) => /* @__PURE__ */ jsx26(Avatar, { name: o.label, src: o.picture, size: 16 }),
1758
+ rowLeading: (o) => /* @__PURE__ */ jsx26(Avatar, { name: o.label, src: o.picture, size: 32 }),
1759
+ autoFocus: true
1760
+ }
1761
+ ) }) })
1762
+ }
1763
+ );
1764
+ }
1765
+ return /* @__PURE__ */ jsxs17(
1766
+ DialogShell,
1767
+ {
1768
+ title: "Members",
1769
+ onClose,
1770
+ headerContent: /* @__PURE__ */ jsxs17("div", { className: "flex min-w-0 items-center gap-2", children: [
1771
+ /* @__PURE__ */ jsx26("span", { className: "truncate text-h4 text-text-primary", children: "Members" }),
1772
+ /* @__PURE__ */ jsx26(Chip, { label: String(count ?? members.length) })
1773
+ ] }),
1774
+ bodyMaxHeight: "max-h-[400px]",
1775
+ bodyClassName: "p-0 py-2",
1776
+ children: [
1777
+ (self || onAdd) && /* @__PURE__ */ jsxs17("div", { className: "flex flex-col px-2", children: [
1778
+ self && /* @__PURE__ */ jsx26(
1779
+ MenuItem,
1780
+ {
1781
+ size: "tall",
1782
+ className: "py-2",
1783
+ disabled: toggling,
1784
+ onClick: () => void toggle(),
1785
+ leading: /* @__PURE__ */ jsx26("span", { className: LEADING_CLASSES, children: self.action === "join" ? /* @__PURE__ */ jsx26(IconUserPlus, { size: 16, stroke: 1.5 }) : /* @__PURE__ */ jsx26(IconUserMinus, { size: 16, stroke: 1.5 }) }),
1786
+ label: self.action === "join" ? "Join" : "Leave"
1787
+ }
1788
+ ),
1789
+ onAdd && /* @__PURE__ */ jsx26(
1790
+ MenuItem,
1791
+ {
1792
+ size: "tall",
1793
+ className: "py-2",
1794
+ onClick: () => setView("add"),
1795
+ leading: /* @__PURE__ */ jsx26("span", { className: LEADING_CLASSES, children: /* @__PURE__ */ jsx26(IconUserPlus, { size: 16, stroke: 1.5 }) }),
1796
+ label: "Add members"
1797
+ }
1798
+ )
1799
+ ] }),
1800
+ members.map((member) => /* @__PURE__ */ jsxs17("div", { className: "flex h-12 items-center gap-3 px-5", children: [
1801
+ /* @__PURE__ */ jsx26(Avatar, { size: 32, name: member.name, src: member.picture }),
1802
+ /* @__PURE__ */ jsxs17("div", { className: "flex min-w-0 flex-1 flex-col justify-center gap-[2px]", children: [
1803
+ /* @__PURE__ */ jsx26("div", { className: "truncate text-body-2 text-text-primary", children: member.name }),
1804
+ member.caption && /* @__PURE__ */ jsx26("div", { className: "truncate text-caption text-text-secondary", children: member.caption })
1805
+ ] })
1806
+ ] }, member.id)),
1807
+ note && /* @__PURE__ */ jsx26("div", { className: "px-5 pb-2 pt-3 text-caption text-text-secondary", children: note })
1808
+ ]
1809
+ }
1810
+ );
1811
+ }
1812
+
1813
+ // src/Banner.tsx
1814
+ import { IconX as IconX5 } from "@tabler/icons-react";
1815
+ import { jsx as jsx27, jsxs as jsxs18 } from "react/jsx-runtime";
1816
+ var TONE_STYLES = {
1817
+ ok: "bg-success-muted text-success-default",
1818
+ error: "bg-error-muted text-error-default",
1819
+ info: "bg-info-muted text-info-default",
1820
+ warning: "bg-warning-muted text-warning-default"
1821
+ };
1822
+ function Banner({ tone, children, icon, action, onDismiss, dismissLabel = "Dismiss", className }) {
1823
+ const role = tone === "error" ? "alert" : "status";
1824
+ if (!onDismiss && !icon && !action) {
1825
+ return /* @__PURE__ */ jsx27("div", { role, className: cn("px-4 py-2 text-body-2", TONE_STYLES[tone], className), children });
1826
+ }
1827
+ const oneLine = Boolean(icon || action);
1828
+ return /* @__PURE__ */ jsxs18("div", { role, className: cn("flex items-center gap-3 px-4 py-2 text-body-2", TONE_STYLES[tone], className), children: [
1829
+ icon && /* @__PURE__ */ jsx27("span", { className: "flex shrink-0", children: icon }),
1830
+ /* @__PURE__ */ jsx27("span", { className: cn("min-w-0 flex-1", oneLine && "truncate"), children }),
1831
+ action && /* @__PURE__ */ jsx27(Button, { variant: "muted", size: "small", className: "shrink-0", onClick: action.onClick, children: action.label }),
1832
+ onDismiss && /* @__PURE__ */ jsx27(IconButton, { variant: "current", "aria-label": dismissLabel, onClick: onDismiss, className: "-mr-1 shrink-0", children: /* @__PURE__ */ jsx27(IconX5, { size: 16, stroke: 1.5 }) })
1833
+ ] });
1834
+ }
1835
+
1836
+ // src/BlockHandle.tsx
1837
+ import { useCallback, useEffect as useEffect3, useRef as useRef6, useState as useState4 } from "react";
1838
+ import { IconGripVertical } from "@tabler/icons-react";
1839
+ import { jsx as jsx28, jsxs as jsxs19 } from "react/jsx-runtime";
1840
+ function readId(element) {
1841
+ const own = element.getAttribute("data-block-id") ?? element.querySelector("[data-block-id]")?.getAttribute("data-block-id");
1842
+ return own || void 0;
1843
+ }
1844
+ function blockAtY(blocks, y) {
1845
+ let found = null;
1846
+ for (const block of blocks) {
1847
+ if (block.element.getBoundingClientRect().top > y) break;
1848
+ found = block;
1849
+ }
1850
+ return found ?? blocks[0] ?? null;
1851
+ }
1852
+ function readingBlocks(root) {
1853
+ if (!root) return [];
1854
+ return Array.from(root.children).filter((el) => el instanceof HTMLElement).map((element) => ({ id: readId(element), element })).filter((b) => b.id !== void 0);
1855
+ }
1856
+ var HANDLE = 24;
1857
+ function firstLineOffset(element) {
1858
+ const text = element.querySelector("p, h1, h2, h3, pre, li") ?? element;
1859
+ const line = parseFloat(getComputedStyle(text).lineHeight);
1860
+ if (!Number.isFinite(line)) return 0;
1861
+ const inset = text === element ? 0 : text.getBoundingClientRect().top - element.getBoundingClientRect().top;
1862
+ return inset + (line - HANDLE) / 2;
1863
+ }
1864
+ function BlockHandle({ actions, editing, children, className }) {
1865
+ const frame = useRef6(null);
1866
+ const content = useRef6(null);
1867
+ const [block, setBlock] = useState4(null);
1868
+ const [top, setTop] = useState4(0);
1869
+ const [open, setOpen] = useState4(false);
1870
+ const follow = useCallback(
1871
+ (y) => {
1872
+ if (!content.current || !frame.current) return;
1873
+ const found = editing ? editing.find(y) : blockAtY(readingBlocks(content.current.firstElementChild), y);
1874
+ setBlock(found);
1875
+ if (found) setTop(found.element.getBoundingClientRect().top - frame.current.getBoundingClientRect().top + firstLineOffset(found.element));
1876
+ },
1877
+ [editing]
1878
+ );
1879
+ useEffect3(() => {
1880
+ if (!editing) return;
1881
+ return editing.onChange(() => {
1882
+ if (!open) setBlock(null);
1883
+ });
1884
+ }, [editing, open]);
1885
+ const rows = editing && block ? editing.rows(block) : null;
1886
+ const own = actions && block ? actions(block) : null;
1887
+ const dragging = useRef6(false);
1888
+ const [line, setLine] = useState4(null);
1889
+ const inGutter = (e) => dragging.current && !!editing && !!content.current && !content.current.contains(e.target);
1890
+ const landing = (y) => {
1891
+ const target = editing?.find(y);
1300
1892
  if (!target || !frame.current) return null;
1301
1893
  const box = target.element.getBoundingClientRect();
1302
1894
  const after = y > box.top + box.height / 2;
@@ -1309,7 +1901,7 @@ function BlockHandle({ actions, editing, children, className }) {
1309
1901
  setLine(null);
1310
1902
  editing?.endDrag();
1311
1903
  };
1312
- return /* @__PURE__ */ jsxs12(
1904
+ return /* @__PURE__ */ jsxs19(
1313
1905
  "div",
1314
1906
  {
1315
1907
  ref: frame,
@@ -1337,16 +1929,16 @@ function BlockHandle({ actions, editing, children, className }) {
1337
1929
  if (!frame.current?.contains(e.relatedTarget)) setLine(null);
1338
1930
  },
1339
1931
  children: [
1340
- /* @__PURE__ */ jsx19("div", { ref: content, children }),
1341
- /* @__PURE__ */ jsx19("div", { "aria-hidden": true, className: "absolute inset-y-0 -left-7 w-7" }),
1342
- line !== null && /* @__PURE__ */ jsx19("div", { "aria-hidden": true, className: "pointer-events-none absolute inset-x-0 h-px bg-accent-primary", style: { top: line } }),
1932
+ /* @__PURE__ */ jsx28("div", { ref: content, children }),
1933
+ /* @__PURE__ */ jsx28("div", { "aria-hidden": true, className: "absolute inset-y-0 -left-7 w-7" }),
1934
+ line !== null && /* @__PURE__ */ jsx28("div", { "aria-hidden": true, className: "pointer-events-none absolute inset-x-0 h-px bg-accent-primary", style: { top: line } }),
1343
1935
  block && (rows || own) && // The top is the block's, measured: it depends on the document, not on a size of ours.
1344
- /* @__PURE__ */ jsx19("div", { className: cn("absolute -left-7", rows && "cursor-grab active:cursor-grabbing"), style: { top }, children: /* @__PURE__ */ jsxs12(
1936
+ /* @__PURE__ */ jsx28("div", { className: cn("absolute -left-7", rows && "cursor-grab active:cursor-grabbing"), style: { top }, children: /* @__PURE__ */ jsxs19(
1345
1937
  Menu,
1346
1938
  {
1347
1939
  open,
1348
1940
  onOpenChange: setOpen,
1349
- trigger: /* @__PURE__ */ jsx19(
1941
+ trigger: /* @__PURE__ */ jsx28(
1350
1942
  IconButton,
1351
1943
  {
1352
1944
  "aria-label": "Block menu",
@@ -1367,12 +1959,12 @@ function BlockHandle({ actions, editing, children, className }) {
1367
1959
  endDrag();
1368
1960
  setBlock(null);
1369
1961
  },
1370
- children: /* @__PURE__ */ jsx19(IconGripVertical, { size: 16, stroke: 1.5 })
1962
+ children: /* @__PURE__ */ jsx28(IconGripVertical, { size: 16, stroke: 1.5 })
1371
1963
  }
1372
1964
  ),
1373
1965
  children: [
1374
1966
  rows,
1375
- rows && own && /* @__PURE__ */ jsx19(MenuSeparator, {}),
1967
+ rows && own && /* @__PURE__ */ jsx28(MenuSeparator, {}),
1376
1968
  own
1377
1969
  ]
1378
1970
  }
@@ -1384,9 +1976,9 @@ function BlockHandle({ actions, editing, children, className }) {
1384
1976
 
1385
1977
  // src/Checkbox.tsx
1386
1978
  import { Checkbox as BaseCheckbox } from "@base-ui/react/checkbox";
1387
- import { Field as BaseField } from "@base-ui/react/field";
1979
+ import { Field as BaseField2 } from "@base-ui/react/field";
1388
1980
  import { IconCheck } from "@tabler/icons-react";
1389
- import { jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
1981
+ import { jsx as jsx29, jsxs as jsxs20 } from "react/jsx-runtime";
1390
1982
  function squareClasses(checked, disabled, interactive, className) {
1391
1983
  return cn(
1392
1984
  "inline-flex items-center justify-center size-4 shrink-0 rounded-sm border transition-colors",
@@ -1403,392 +1995,89 @@ function Checkbox({ checked, onChange, disabled: ownDisabled = false, label, row
1403
1995
  const formBusy = useFormBusy();
1404
1996
  const disabled = ownDisabled || formBusy;
1405
1997
  if (!onChange) {
1406
- const picture = /* @__PURE__ */ jsx20("span", { "aria-hidden": "true", className: squareClasses(checked, disabled, false, className), children: /* @__PURE__ */ jsx20("span", { className: tickClasses(checked), children: /* @__PURE__ */ jsx20(IconCheck, { size: 12, stroke: 3 }) }) });
1998
+ const picture = /* @__PURE__ */ jsx29("span", { "aria-hidden": "true", className: squareClasses(checked, disabled, false, className), children: /* @__PURE__ */ jsx29("span", { className: tickClasses(checked), children: /* @__PURE__ */ jsx29(IconCheck, { size: 12, stroke: 3 }) }) });
1407
1999
  if (label === void 0) return picture;
1408
- return /* @__PURE__ */ jsxs13("span", { className: "flex items-center gap-2", children: [
2000
+ return /* @__PURE__ */ jsxs20("span", { className: "flex items-center gap-2", children: [
1409
2001
  picture,
1410
- /* @__PURE__ */ jsx20("span", { className: WORDS_CLASSES, children: label })
2002
+ /* @__PURE__ */ jsx29("span", { className: WORDS_CLASSES, children: label })
1411
2003
  ] });
1412
2004
  }
1413
- const box = /* @__PURE__ */ jsx20(
2005
+ const box = /* @__PURE__ */ jsx29(
1414
2006
  BaseCheckbox.Root,
1415
2007
  {
1416
2008
  checked,
1417
2009
  disabled,
1418
- "aria-label": aria["aria-label"],
1419
- "aria-required": aria["aria-required"],
1420
- onCheckedChange: (next) => onChange(next),
1421
- onClick: (e) => e.stopPropagation(),
1422
- className: (state) => squareClasses(state.checked, state.disabled, true, className),
1423
- children: /* @__PURE__ */ jsx20(BaseCheckbox.Indicator, { keepMounted: true, className: (state) => tickClasses(state.checked), children: /* @__PURE__ */ jsx20(IconCheck, { size: 12, stroke: 3 }) })
1424
- }
1425
- );
1426
- if (label === void 0) return box;
1427
- if (row) {
1428
- return /* @__PURE__ */ jsx20(BaseField.Root, { disabled, children: /* @__PURE__ */ jsxs13(BaseField.Label, { className: cn(ROW_CLASSES, checked && "bg-bg-selected", !disabled && "cursor-pointer hover:bg-bg-hover"), children: [
1429
- leading,
1430
- /* @__PURE__ */ jsx20("span", { className: cn("flex-1 min-w-0 truncate", WORDS_CLASSES), children: label }),
1431
- box
1432
- ] }) });
1433
- }
1434
- return /* @__PURE__ */ jsx20(BaseField.Root, { disabled, children: /* @__PURE__ */ jsxs13(BaseField.Label, { className: cn("flex items-center gap-2", !disabled && "cursor-pointer"), children: [
1435
- box,
1436
- /* @__PURE__ */ jsx20("span", { className: WORDS_CLASSES, children: label })
1437
- ] }) });
1438
- }
1439
-
1440
- // src/Chip.tsx
1441
- import { Fragment as Fragment4, jsx as jsx21, jsxs as jsxs14 } from "react/jsx-runtime";
1442
- var typeStyles = {
1443
- neutral: "bg-bg-inset text-text-primary",
1444
- brand: "bg-accent-muted text-accent-text signal:border signal:border-accent-outline",
1445
- info: "bg-info-muted text-info-default signal:border signal:border-info-outline",
1446
- warning: "bg-warning-muted text-warning-default signal:border signal:border-warning-outline signal:shadow-glow-warning",
1447
- success: "bg-success-muted text-success-default signal:border signal:border-success-outline",
1448
- error: "bg-error-muted text-error-default signal:border signal:border-error-outline"
1449
- };
1450
- function Chip({ type = "neutral", label, leadingIcon, trailingIcon, href, onClick, className }) {
1451
- const classes = cn("inline-flex min-w-0 items-center justify-center gap-1.5 rounded-full max-h-[20px] px-2 py-1", typeStyles[type], className);
1452
- const inside = /* @__PURE__ */ jsxs14(Fragment4, { children: [
1453
- leadingIcon && /* @__PURE__ */ jsx21("span", { className: "flex size-3 shrink-0 items-center justify-center", children: leadingIcon }),
1454
- label && // A chip given a `max-w-*` cuts a long label with an ellipsis instead
1455
- // of growing past it — Ship's project chip on an issue row
1456
- // (2026-09-09). Clipped sideways only: `overflow-x-clip`, not
1457
- // `truncate`, because `truncate` is `overflow: hidden` on both axes and
1458
- // the label's line box (11px under Signal) is tighter than its glyphs —
1459
- // the screenshot diff caught every descender cut off. `clip` is the
1460
- // one overflow that leaves the other axis visible. A chip with no cap
1461
- // draws exactly as before.
1462
- /* @__PURE__ */ jsx21("span", { className: cn("min-w-0 overflow-x-clip text-ellipsis whitespace-nowrap signal:tracking-wide", CHIP_TEXT_CLASSES), children: label }),
1463
- trailingIcon && /* @__PURE__ */ jsx21("span", { className: "flex size-3 shrink-0 items-center justify-center", children: trailingIcon })
1464
- ] });
1465
- if (href) return /* @__PURE__ */ jsx21("a", { href, onClick, className: cn("relative", classes), children: inside });
1466
- return /* @__PURE__ */ jsx21("div", { className: classes, children: inside });
1467
- }
1468
-
1469
- // src/CommandPalette.tsx
1470
- import {
1471
- createContext as createContext5,
1472
- useContext as useContext5,
1473
- useEffect as useEffect3,
1474
- useLayoutEffect as useLayoutEffect3,
1475
- useMemo as useMemo2,
1476
- useRef as useRef5,
1477
- useState as useState4
1478
- } from "react";
1479
- import { Dialog as Dialog2 } from "@base-ui/react/dialog";
1480
- import { Autocomplete } from "@base-ui/react/autocomplete";
1481
- import { IconLoader2 as IconLoader22, IconSearch } from "@tabler/icons-react";
1482
-
1483
- // src/ChipInput.tsx
1484
- import { useMemo, useState as useState3 } from "react";
1485
- import { Button as BaseButton4 } from "@base-ui/react/button";
1486
- import { Combobox } from "@base-ui/react/combobox";
1487
- import { IconX as IconX4 } from "@tabler/icons-react";
1488
- import { jsx as jsx22, jsxs as jsxs15 } from "react/jsx-runtime";
1489
- var CHIP_BOX = (
1490
- // Curved, not a pill (Katerina, 2026-09-01): the Avatar keeps its own
1491
- // rounded-sm corners — never a forced circle — and the chip's corner
1492
- // follows concentrically: 4px face + 2px inset = rounded-md.
1493
- "inline-flex items-center gap-1.5 bg-bg-elevated border border-border-subtle rounded-md py-0.5 max-h-[24px]"
1494
- );
1495
- var CHIP_LABEL = "text-caption font-medium text-text-primary";
1496
- var CHIP_REMOVE = "size-4 flex items-center justify-center rounded-full hover:bg-bg-hover text-text-secondary";
1497
- var chipPadding = (leading, removable) => cn(leading ? "pl-[2px]" : "pl-2", removable ? "pr-1" : "pr-2");
1498
- function InputChip({ label, leading, onRemove, removeLabel, truncate, className }) {
1499
- return /* @__PURE__ */ jsxs15("div", { className: cn(CHIP_BOX, chipPadding(!!leading, !!onRemove), className), children: [
1500
- leading && /* @__PURE__ */ jsx22("span", { className: "flex shrink-0 items-center", children: leading }),
1501
- /* @__PURE__ */ jsx22("span", { className: cn(CHIP_LABEL, truncate && "min-w-0 truncate"), children: label }),
1502
- onRemove && /* @__PURE__ */ jsx22(
1503
- BaseButton4,
1504
- {
1505
- type: "button",
1506
- onClick: (e) => {
1507
- e.stopPropagation();
1508
- onRemove();
1509
- },
1510
- className: cn(CHIP_REMOVE, truncate && "shrink-0"),
1511
- "aria-label": removeLabel ?? `Remove ${label}`,
1512
- children: /* @__PURE__ */ jsx22(IconX4, { size: 10, stroke: 1.5 })
1513
- }
1514
- )
1515
- ] });
1516
- }
1517
- function ChipInput({
1518
- value,
1519
- onChange,
1520
- options,
1521
- placeholder = "Search\u2026",
1522
- autoFocus,
1523
- excludeIds = [],
1524
- chipLeading,
1525
- rowLeading,
1526
- ...aria
1527
- }) {
1528
- const [query, setQuery] = useState3("");
1529
- const [box, setBox] = useState3(null);
1530
- const available = useMemo(() => {
1531
- const chosen = new Set(value.map((o) => o.id));
1532
- const excluded = new Set(excludeIds);
1533
- return options.filter((o) => !chosen.has(o.id) && !excluded.has(o.id));
1534
- }, [options, value, excludeIds]);
1535
- const filter = useMemo(
1536
- () => (item, q) => {
1537
- const needle = q.trim().toLowerCase();
1538
- if (!needle) return true;
1539
- return item.label.toLowerCase().includes(needle) || (item.description ?? "").toLowerCase().includes(needle);
1540
- },
1541
- []
1542
- );
1543
- const open = query.trim().length > 0;
1544
- const ariaLabel = aria["aria-label"] ?? (value.length > 0 ? placeholder : void 0);
1545
- const naming = {
1546
- ...ariaLabel !== void 0 && { "aria-label": ariaLabel },
1547
- ...aria["aria-labelledby"] !== void 0 && { "aria-labelledby": aria["aria-labelledby"] }
1548
- };
1549
- function removeLast() {
1550
- if (value.length > 0) onChange(value.slice(0, -1));
1551
- }
1552
- function onInputKeyDown(event) {
1553
- if (event.key === "Backspace" && query === "" && value.length > 0) {
1554
- event.preventDefault();
1555
- event.stopPropagation();
1556
- removeLast();
1557
- return;
1558
- }
1559
- if (event.key === "Escape" && query !== "") {
1560
- event.preventDefault();
1561
- event.stopPropagation();
1562
- setQuery("");
1563
- }
1564
- }
1565
- return /* @__PURE__ */ jsxs15(
1566
- Combobox.Root,
1567
- {
1568
- multiple: true,
1569
- items: available,
1570
- value,
1571
- onValueChange: (next) => {
1572
- onChange(next);
1573
- setQuery("");
1574
- },
1575
- inputValue: query,
1576
- onInputValueChange: setQuery,
1577
- open,
1578
- openOnInputClick: false,
1579
- filter,
1580
- itemToStringLabel: (option) => option.label,
1581
- children: [
1582
- /* @__PURE__ */ jsxs15(Combobox.Chips, { ref: setBox, className: cn(FIELD_SHELL_CLASSES, "focus-within:border-border-focus focus-within:hover:border-border-focus group-hover/field:focus-within:border-border-focus px-3 py-1.5 flex flex-wrap items-center gap-1.5 min-h-[38px] cursor-text signal:transition-shadow signal:focus-within:shadow-focus-ring"), children: [
1583
- value.map((option) => /* @__PURE__ */ jsxs15(Combobox.Chip, { className: cn(CHIP_BOX, chipPadding(!!chipLeading, true)), children: [
1584
- chipLeading && /* @__PURE__ */ jsx22("span", { className: "flex shrink-0 items-center", children: chipLeading(option) }),
1585
- /* @__PURE__ */ jsx22("span", { className: CHIP_LABEL, children: option.label }),
1586
- /* @__PURE__ */ jsx22(Combobox.ChipRemove, { className: CHIP_REMOVE, "aria-label": `Remove ${option.label}`, children: /* @__PURE__ */ jsx22(IconX4, { size: 10, stroke: 1.5 }) })
1587
- ] }, option.id)),
1588
- /* @__PURE__ */ jsx22(
1589
- Combobox.Input,
1590
- {
1591
- autoFocus,
1592
- placeholder: value.length === 0 ? placeholder : "",
1593
- "aria-required": aria["aria-required"],
1594
- ...naming,
1595
- onKeyDown: onInputKeyDown,
1596
- className: cn("flex-1 min-w-[120px] text-body-2 border-none", BARE_INPUT_CLASSES)
1597
- }
1598
- )
1599
- ] }),
1600
- /* @__PURE__ */ jsx22(Combobox.Portal, { children: /* @__PURE__ */ jsx22(
1601
- Combobox.Positioner,
1602
- {
1603
- anchor: box,
1604
- sideOffset: GAP3,
1605
- collisionPadding: VIEWPORT_PAD3,
1606
- className: "z-50 data-[anchor-hidden]:hidden",
1607
- children: /* @__PURE__ */ jsx22(Combobox.Popup, { className: "w-[var(--anchor-width)] p-0", render: /* @__PURE__ */ jsx22(MenuPanel, {}), children: /* @__PURE__ */ jsx22(ScrollArea, { viewportClassName: "max-h-[240px]", contentClassName: "flex flex-col p-2", children: /* @__PURE__ */ jsx22(Combobox.List, { className: "flex flex-col gap-0.5", children: (option) => /* @__PURE__ */ jsx22(
1608
- Combobox.Item,
1609
- {
1610
- value: option,
1611
- render: /* @__PURE__ */ jsx22(
1612
- MenuItem,
1613
- {
1614
- size: "tall",
1615
- leading: rowLeading?.(option),
1616
- label: option.label,
1617
- description: option.description
1618
- }
1619
- )
1620
- },
1621
- option.id
1622
- ) }) }) })
1623
- }
1624
- ) })
1625
- ]
2010
+ "aria-label": aria["aria-label"],
2011
+ "aria-required": aria["aria-required"],
2012
+ onCheckedChange: (next) => onChange(next),
2013
+ onClick: (e) => e.stopPropagation(),
2014
+ className: (state) => squareClasses(state.checked, state.disabled, true, className),
2015
+ children: /* @__PURE__ */ jsx29(BaseCheckbox.Indicator, { keepMounted: true, className: (state) => tickClasses(state.checked), children: /* @__PURE__ */ jsx29(IconCheck, { size: 12, stroke: 3 }) })
1626
2016
  }
1627
2017
  );
2018
+ if (label === void 0) return box;
2019
+ if (row) {
2020
+ return /* @__PURE__ */ jsx29(BaseField2.Root, { disabled, children: /* @__PURE__ */ jsxs20(BaseField2.Label, { className: cn(ROW_CLASSES, checked && "bg-bg-selected", !disabled && "cursor-pointer hover:bg-bg-hover"), children: [
2021
+ leading,
2022
+ /* @__PURE__ */ jsx29("span", { className: cn("flex-1 min-w-0 truncate", WORDS_CLASSES), children: label }),
2023
+ box
2024
+ ] }) });
2025
+ }
2026
+ return /* @__PURE__ */ jsx29(BaseField2.Root, { disabled, children: /* @__PURE__ */ jsxs20(BaseField2.Label, { className: cn("flex items-center gap-2", !disabled && "cursor-pointer"), children: [
2027
+ box,
2028
+ /* @__PURE__ */ jsx29("span", { className: WORDS_CLASSES, children: label })
2029
+ ] }) });
1628
2030
  }
1629
- var GAP3 = 4;
1630
- var VIEWPORT_PAD3 = 8;
2031
+
2032
+ // src/CommandPalette.tsx
2033
+ import {
2034
+ createContext as createContext6,
2035
+ useContext as useContext6,
2036
+ useEffect as useEffect4,
2037
+ useLayoutEffect as useLayoutEffect3,
2038
+ useMemo as useMemo3,
2039
+ useRef as useRef7,
2040
+ useState as useState5
2041
+ } from "react";
2042
+ import { Dialog as Dialog3 } from "@base-ui/react/dialog";
2043
+ import { Autocomplete } from "@base-ui/react/autocomplete";
2044
+ import { IconLoader2 as IconLoader22, IconSearch } from "@tabler/icons-react";
1631
2045
 
1632
2046
  // src/EmptyState.tsx
1633
2047
  import { IconMessage2 } from "@tabler/icons-react";
1634
- import { jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
2048
+ import { jsx as jsx30, jsxs as jsxs21 } from "react/jsx-runtime";
1635
2049
  function EmptyState({ icon, message, scope = "page", action, className }) {
1636
2050
  if (scope === "section") {
1637
- return /* @__PURE__ */ jsx23("p", { className: cn("text-caption text-text-muted", className), children: message });
2051
+ return /* @__PURE__ */ jsx30("p", { className: cn("text-caption text-text-muted", className), children: message });
1638
2052
  }
1639
- return /* @__PURE__ */ jsxs16("div", { className: cn("flex flex-1 flex-col items-center justify-center gap-2", className), children: [
1640
- /* @__PURE__ */ jsx23("span", { className: "text-text-secondary", children: icon ?? /* @__PURE__ */ jsx23(IconMessage2, { size: 16, stroke: 1.5 }) }),
1641
- /* @__PURE__ */ jsx23("p", { className: "text-body-2 text-text-secondary text-center", children: message }),
1642
- action && /* @__PURE__ */ jsx23(Button, { variant: "outlined", className: "mt-2", onClick: action.onClick, children: action.label })
2053
+ return /* @__PURE__ */ jsxs21("div", { className: cn("flex flex-1 flex-col items-center justify-center gap-2", className), children: [
2054
+ /* @__PURE__ */ jsx30("span", { className: "text-text-secondary", children: icon ?? /* @__PURE__ */ jsx30(IconMessage2, { size: 16, stroke: 1.5 }) }),
2055
+ /* @__PURE__ */ jsx30("p", { className: "text-body-2 text-text-secondary text-center", children: message }),
2056
+ action && /* @__PURE__ */ jsx30(Button, { variant: "outlined", className: "mt-2", onClick: action.onClick, children: action.label })
1643
2057
  ] });
1644
2058
  }
1645
2059
 
1646
- // src/Field.tsx
1647
- import { cloneElement, isValidElement } from "react";
1648
- import { Field as BaseField2 } from "@base-ui/react/field";
1649
- import { jsx as jsx24, jsxs as jsxs17 } from "react/jsx-runtime";
1650
- var LINE_STYLES = {
1651
- helper: "text-caption text-text-muted",
1652
- warning: "text-caption text-warning-default",
1653
- error: "text-caption text-error-default"
1654
- };
1655
- function Field({ label, required = false, helper, error, children }) {
1656
- const control = required && isValidElement(children) ? cloneElement(children, {
1657
- "aria-required": children.props["aria-required"] ?? true
1658
- }) : children;
1659
- return (
1660
- // `group/field`: the label, the box and the line under it are one thing under the pointer —
1661
- // anywhere in it strengthens the box's border, as hovering the box does (Katerina, 28 September).
1662
- // Before, the 8px between the label and the box was a gap where the border went out again.
1663
- /* @__PURE__ */ jsxs17(BaseField2.Root, { invalid: !!error, className: "group/field flex flex-col gap-2", children: [
1664
- /* @__PURE__ */ jsxs17(BaseField2.Label, { className: cn("text-input-label text-text-primary", required && "flex items-center"), children: [
1665
- label,
1666
- required && /* @__PURE__ */ jsx24("span", { "aria-hidden": "true", className: "text-error-default ml-0.5", children: "*" })
1667
- ] }),
1668
- /* @__PURE__ */ jsxs17("div", { className: "flex flex-col gap-1.5", children: [
1669
- control,
1670
- error != null ? /* @__PURE__ */ jsx24(BaseField2.Error, { match: true, className: LINE_STYLES.error, children: error }) : helper != null ? /* @__PURE__ */ jsx24(BaseField2.Description, { className: LINE_STYLES.helper, children: helper }) : null
1671
- ] })
1672
- ] })
1673
- );
1674
- }
1675
- function FieldLine({ tone = "helper", children, className }) {
1676
- return /* @__PURE__ */ jsx24("p", { role: tone === "error" ? "alert" : "status", className: cn(LINE_STYLES[tone], className), children });
1677
- }
1678
-
1679
- // src/Form.tsx
1680
- import { useLayoutEffect as useLayoutEffect2, useRef as useRef4 } from "react";
1681
- import { Fieldset } from "@base-ui/react/fieldset";
1682
- import { Form as BaseForm } from "@base-ui/react/form";
1683
- import { jsx as jsx25 } from "react/jsx-runtime";
1684
- var FIELDS_CLASSES = "flex flex-col gap-6";
1685
- var CONTROL = 'input:not([type="hidden"]), textarea, select, button, [role="checkbox"], [role="combobox"], [tabindex]:not([tabindex="-1"])';
1686
- var ONE_LINE = /* @__PURE__ */ new Set(["", "text", "search", "email", "url", "tel", "password", "number"]);
1687
- function usable(element) {
1688
- return element instanceof HTMLElement && element.isConnected && element.matches(CONTROL) && !element.matches(":disabled") && element.getAttribute("aria-disabled") !== "true";
1689
- }
1690
- function firstInvalid(form) {
1691
- for (const marked of form.querySelectorAll("[data-invalid]")) {
1692
- if (usable(marked)) return marked;
1693
- const inside = Array.from(marked.querySelectorAll(CONTROL)).find(usable);
1694
- if (inside) return inside;
1695
- }
1696
- return void 0;
1697
- }
1698
- function Form({ onSubmit, busy: ownBusy = false, enterSends = true, layout = "fields", className, children, ...props }) {
1699
- const outerBusy = useFormBusy();
1700
- const busy = ownBusy || outerBusy;
1701
- const form = useRef4(null);
1702
- const busyNow = useRef4(busy);
1703
- busyNow.current = busy;
1704
- const sender = useRef4(null);
1705
- const holding = useRef4(false);
1706
- const lastInside = useRef4(null);
1707
- useLayoutEffect2(() => {
1708
- const element = form.current;
1709
- if (!element) return;
1710
- if (busy) {
1711
- const active = document.activeElement;
1712
- const from = active && active !== element && element.contains(active) ? active : !active || active === document.body ? lastInside.current : null;
1713
- if (from?.isConnected) {
1714
- sender.current = from;
1715
- holding.current = true;
1716
- element.focus();
1717
- }
1718
- return;
1719
- }
1720
- if (!holding.current) return;
1721
- holding.current = false;
1722
- if (document.activeElement !== element && document.activeElement !== document.body) return;
1723
- const target = firstInvalid(element) ?? (usable(sender.current) ? sender.current : Array.from(element.querySelectorAll(CONTROL)).find(usable));
1724
- sender.current = null;
1725
- target?.focus();
1726
- }, [busy]);
1727
- const onKeyDown = (event) => {
1728
- props.onKeyDown?.(event);
1729
- if (event.key !== "Enter" || event.defaultPrevented || event.nativeEvent.isComposing) return;
1730
- const target = event.target;
1731
- const inInput = target instanceof HTMLInputElement;
1732
- if (inInput) event.preventDefault();
1733
- if (event.altKey || event.shiftKey) return;
1734
- if (event.ctrlKey || event.metaKey) {
1735
- event.preventDefault();
1736
- form.current?.requestSubmit();
1737
- return;
1738
- }
1739
- if (!inInput) return;
1740
- const oneLine = ONE_LINE.has((target.getAttribute("type") ?? "").toLowerCase()) && target.getAttribute("role") !== "combobox";
1741
- if (enterSends && oneLine) form.current?.requestSubmit();
1742
- };
1743
- return /* @__PURE__ */ jsx25(
1744
- BaseForm,
1745
- {
1746
- ref: form,
1747
- ...props,
1748
- tabIndex: busy ? -1 : props.tabIndex,
1749
- className: cn("outline-none", layout === "fields" && FIELDS_CLASSES, className),
1750
- onFocus: (event) => {
1751
- if (event.target !== form.current) lastInside.current = event.target;
1752
- props.onFocus?.(event);
1753
- },
1754
- onBlur: (event) => {
1755
- const next = event.relatedTarget;
1756
- if (next && !form.current?.contains(next)) lastInside.current = null;
1757
- props.onBlur?.(event);
1758
- },
1759
- onKeyDown,
1760
- onSubmit: (event) => {
1761
- if (event.target !== event.currentTarget) return;
1762
- event.preventDefault();
1763
- if (busyNow.current) return;
1764
- void onSubmit();
1765
- },
1766
- children: /* @__PURE__ */ jsx25(Fieldset.Root, { disabled: busy, className: "contents", children: /* @__PURE__ */ jsx25(FormBusyContext.Provider, { value: busy, children }) })
1767
- }
1768
- );
1769
- }
1770
-
1771
2060
  // src/Skeleton.tsx
1772
- import { jsx as jsx26, jsxs as jsxs18 } from "react/jsx-runtime";
2061
+ import { jsx as jsx31, jsxs as jsxs22 } from "react/jsx-runtime";
1773
2062
  function SkeletonBar({ className, style }) {
1774
- return /* @__PURE__ */ jsx26("div", { className: cn("bg-bg-inset rounded-sm animate-pulse", className), style });
2063
+ return /* @__PURE__ */ jsx31("div", { className: cn("bg-bg-inset rounded-sm animate-pulse", className), style });
1775
2064
  }
1776
2065
  var ROW_BAR_WIDTHS = [150, 100, 170, 120, 90, 140, 110, 160];
1777
2066
  function SkeletonRow({ barWidth = 130 }) {
1778
- return /* @__PURE__ */ jsxs18("div", { className: "flex shrink-0 items-center gap-2 px-2 h-[32px] rounded-lg", children: [
1779
- /* @__PURE__ */ jsx26(SkeletonBar, { className: "w-4 h-4 shrink-0" }),
1780
- /* @__PURE__ */ jsx26(SkeletonBar, { className: "h-3.5", style: { width: barWidth } })
2067
+ return /* @__PURE__ */ jsxs22("div", { className: "flex shrink-0 items-center gap-2 px-2 h-[32px] rounded-lg", children: [
2068
+ /* @__PURE__ */ jsx31(SkeletonBar, { className: "w-4 h-4 shrink-0" }),
2069
+ /* @__PURE__ */ jsx31(SkeletonBar, { className: "h-3.5", style: { width: barWidth } })
1781
2070
  ] });
1782
2071
  }
1783
2072
  function SkeletonList({ rows = 8, className }) {
1784
- return /* @__PURE__ */ jsx26("div", { className: cn("flex flex-col gap-0.5 animate-skeleton-in", className), "aria-hidden": true, children: Array.from({ length: rows }, (_, i) => /* @__PURE__ */ jsx26(SkeletonRow, { barWidth: ROW_BAR_WIDTHS[i % ROW_BAR_WIDTHS.length] }, i)) });
2073
+ return /* @__PURE__ */ jsx31("div", { className: cn("flex flex-col gap-0.5 animate-skeleton-in", className), "aria-hidden": true, children: Array.from({ length: rows }, (_, i) => /* @__PURE__ */ jsx31(SkeletonRow, { barWidth: ROW_BAR_WIDTHS[i % ROW_BAR_WIDTHS.length] }, i)) });
1785
2074
  }
1786
2075
 
1787
2076
  // src/CommandPalette.tsx
1788
- import { Fragment as Fragment5, jsx as jsx27, jsxs as jsxs19 } from "react/jsx-runtime";
1789
- var PaletteContext = createContext5(null);
2077
+ import { Fragment as Fragment6, jsx as jsx32, jsxs as jsxs23 } from "react/jsx-runtime";
2078
+ var PaletteContext = createContext6(null);
1790
2079
  function usePalette(part) {
1791
- const palette = useContext5(PaletteContext);
2080
+ const palette = useContext6(PaletteContext);
1792
2081
  if (!palette) throw new Error(`[@estiva-app/ui] ${part} must be inside a CommandPalette.`);
1793
2082
  return palette;
1794
2083
  }
@@ -1800,8 +2089,8 @@ function firstControl(popup) {
1800
2089
  return popup.querySelector("[data-command-palette-fields]")?.querySelector(CONTROL2) ?? null;
1801
2090
  }
1802
2091
  function CommandPalette({ open, onOpenChange, label, where, modKey = "Ctrl", children }) {
1803
- const popupRef = useRef5(null);
1804
- useEffect3(() => {
2092
+ const popupRef = useRef7(null);
2093
+ useEffect4(() => {
1805
2094
  if (!open) return;
1806
2095
  const frame = requestAnimationFrame(() => {
1807
2096
  const popup = popupRef.current;
@@ -1810,11 +2099,11 @@ function CommandPalette({ open, onOpenChange, label, where, modKey = "Ctrl", chi
1810
2099
  });
1811
2100
  return () => cancelAnimationFrame(frame);
1812
2101
  });
1813
- const context = useMemo2(() => ({ where, modKey, popupRef }), [where, modKey]);
1814
- return /* @__PURE__ */ jsx27(Dialog2.Root, { open, onOpenChange: (next) => onOpenChange(next), children: /* @__PURE__ */ jsxs19(Dialog2.Portal, { children: [
1815
- /* @__PURE__ */ jsx27(Dialog2.Backdrop, { className: "fixed inset-0 z-40 bg-scrim" }),
1816
- /* @__PURE__ */ jsx27(Dialog2.Viewport, { className: "fixed inset-0 z-50 flex items-start justify-center pt-[16vh]", children: /* @__PURE__ */ jsx27(
1817
- Dialog2.Popup,
2102
+ const context = useMemo3(() => ({ where, modKey, popupRef }), [where, modKey]);
2103
+ return /* @__PURE__ */ jsx32(Dialog3.Root, { open, onOpenChange: (next) => onOpenChange(next), children: /* @__PURE__ */ jsxs23(Dialog3.Portal, { children: [
2104
+ /* @__PURE__ */ jsx32(Dialog3.Backdrop, { className: "fixed inset-0 z-40 bg-scrim" }),
2105
+ /* @__PURE__ */ jsx32(Dialog3.Viewport, { className: "fixed inset-0 z-50 flex items-start justify-center pt-[16vh]", children: /* @__PURE__ */ jsx32(
2106
+ Dialog3.Popup,
1818
2107
  {
1819
2108
  ref: popupRef,
1820
2109
  "aria-label": label,
@@ -1823,13 +2112,13 @@ function CommandPalette({ open, onOpenChange, label, where, modKey = "Ctrl", chi
1823
2112
  if (e.target === popupRef.current) firstControl(popupRef.current)?.focus();
1824
2113
  },
1825
2114
  className: "flex w-[658px] max-w-[calc(100vw-32px)] flex-col overflow-hidden rounded-lg border border-border-default bg-bg-elevated shadow-lg outline-none",
1826
- children: /* @__PURE__ */ jsx27(PaletteContext.Provider, { value: context, children })
2115
+ children: /* @__PURE__ */ jsx32(PaletteContext.Provider, { value: context, children })
1827
2116
  }
1828
2117
  ) })
1829
2118
  ] }) });
1830
2119
  }
1831
2120
  function LevelChip({ chip, onBack }) {
1832
- return /* @__PURE__ */ jsx27(InputChip, { label: chip.label, leading: chip.leading, onRemove: onBack, removeLabel: `Leave ${chip.label}`, truncate: true, className: "max-w-[272px] shrink-0" });
2121
+ return /* @__PURE__ */ jsx32(InputChip, { label: chip.label, leading: chip.leading, onRemove: onBack, removeLabel: `Leave ${chip.label}`, truncate: true, className: "max-w-[272px] shrink-0" });
1833
2122
  }
1834
2123
  function useBack(chip, popupRef) {
1835
2124
  return () => {
@@ -1840,10 +2129,10 @@ function useBack(chip, popupRef) {
1840
2129
  }
1841
2130
  function Footer({ keys }) {
1842
2131
  const { where } = usePalette("The footer");
1843
- return /* @__PURE__ */ jsxs19("div", { className: "flex h-9 shrink-0 items-center gap-4 border-t border-border-subtle px-5 text-caption text-text-secondary signal:font-mono signal:text-small signal:text-text-muted leaf:font-mono leaf:text-small", children: [
1844
- /* @__PURE__ */ jsx27("span", { className: "min-w-0 flex-1 truncate", children: where }),
1845
- keys.map(([key, word]) => /* @__PURE__ */ jsxs19("span", { className: "flex shrink-0 items-center gap-1.5", children: [
1846
- /* @__PURE__ */ jsx27(Kbd, { children: key }),
2132
+ return /* @__PURE__ */ jsxs23("div", { className: cn("flex h-9 shrink-0 items-center gap-4 border-t border-border-subtle px-5", MONO_CAPTION_CLASSES, "signal:text-text-muted leaf:font-mono leaf:text-small"), children: [
2133
+ /* @__PURE__ */ jsx32("span", { className: "min-w-0 flex-1 truncate", children: where }),
2134
+ keys.map(([key, word]) => /* @__PURE__ */ jsxs23("span", { className: "flex shrink-0 items-center gap-1.5", children: [
2135
+ /* @__PURE__ */ jsx32(Kbd, { children: key }),
1847
2136
  " ",
1848
2137
  word
1849
2138
  ] }, key))
@@ -1853,14 +2142,14 @@ var lowerFirst = (s) => s.charAt(0).toLowerCase() + s.slice(1);
1853
2142
  function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip, pending, notes = [], empty, children }) {
1854
2143
  const { modKey, popupRef } = usePalette("CommandPaletteSearch");
1855
2144
  const back = useBack(chip, popupRef);
1856
- const items = useMemo2(() => groups.filter((g) => g.rows.length > 0).map((g) => ({ value: g.label, items: g.rows })), [groups]);
2145
+ const items = useMemo3(() => groups.filter((g) => g.rows.length > 0).map((g) => ({ value: g.label, items: g.rows })), [groups]);
1857
2146
  const rows = items.flatMap((g) => g.items);
1858
- const [litId, setLitId] = useState4();
2147
+ const [litId, setLitId] = useState5();
1859
2148
  const lit = litId === void 0 ? void 0 : rows.find((r) => r.id === litId);
1860
- const inputRef = useRef5(null);
1861
- const reported = useRef5({});
1862
- const settled = useRef5(null);
1863
- const moved = useRef5(false);
2149
+ const inputRef = useRef7(null);
2150
+ const reported = useRef7({});
2151
+ const settled = useRef7(null);
2152
+ const moved = useRef7(false);
1864
2153
  useLayoutEffect3(() => {
1865
2154
  const before = settled.current;
1866
2155
  const now = reported.current;
@@ -1920,7 +2209,7 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
1920
2209
  ...chip && query === "" ? [["Backspace", "back"]] : [],
1921
2210
  ["Esc", "close"]
1922
2211
  ];
1923
- return /* @__PURE__ */ jsxs19(
2212
+ return /* @__PURE__ */ jsxs23(
1924
2213
  Autocomplete.Root,
1925
2214
  {
1926
2215
  items,
@@ -1943,10 +2232,10 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
1943
2232
  setLitId(id);
1944
2233
  },
1945
2234
  children: [
1946
- /* @__PURE__ */ jsxs19("div", { className: "flex h-12 shrink-0 items-center gap-3 border-b border-border-subtle px-5", children: [
1947
- /* @__PURE__ */ jsx27(IconSearch, { size: 16, stroke: 1.5, className: "shrink-0 text-text-secondary" }),
1948
- chip && /* @__PURE__ */ jsx27(LevelChip, { chip, onBack: back }),
1949
- /* @__PURE__ */ jsx27(
2235
+ /* @__PURE__ */ jsxs23("div", { className: "flex h-12 shrink-0 items-center gap-3 border-b border-border-subtle px-5", children: [
2236
+ /* @__PURE__ */ jsx32(IconSearch, { size: 16, stroke: 1.5, className: "shrink-0 text-text-secondary" }),
2237
+ chip && /* @__PURE__ */ jsx32(LevelChip, { chip, onBack: back }),
2238
+ /* @__PURE__ */ jsx32(
1950
2239
  Autocomplete.Input,
1951
2240
  {
1952
2241
  ref: inputRef,
@@ -1958,43 +2247,43 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
1958
2247
  }
1959
2248
  )
1960
2249
  ] }),
1961
- /* @__PURE__ */ jsxs19(ScrollArea, { viewportClassName: "max-h-[420px]", contentClassName: "flex flex-col p-2", children: [
1962
- children != null && /* @__PURE__ */ jsx27("div", { className: "flex flex-col gap-2 px-3 pb-2 pt-3", children }),
1963
- /* @__PURE__ */ jsx27(Autocomplete.List, { className: "flex flex-col", children: (group) => /* @__PURE__ */ jsxs19(Autocomplete.Group, { items: group.items, className: "flex flex-col gap-0.5", children: [
1964
- /* @__PURE__ */ jsx27(Autocomplete.GroupLabel, { className: "flex h-7 shrink-0 items-center px-3", children: /* @__PURE__ */ jsx27(SectionLabel, { tone: "secondary", children: group.value }) }),
1965
- /* @__PURE__ */ jsx27(Autocomplete.Collection, { children: (row) => (
2250
+ /* @__PURE__ */ jsxs23(ScrollArea, { viewportClassName: "max-h-[420px]", contentClassName: "flex flex-col p-2", children: [
2251
+ children != null && /* @__PURE__ */ jsx32("div", { className: "flex flex-col gap-2 px-3 pb-2 pt-3", children }),
2252
+ /* @__PURE__ */ jsx32(Autocomplete.List, { className: "flex flex-col", children: (group) => /* @__PURE__ */ jsxs23(Autocomplete.Group, { items: group.items, className: "flex flex-col gap-0.5", children: [
2253
+ /* @__PURE__ */ jsx32(Autocomplete.GroupLabel, { className: "flex h-7 shrink-0 items-center px-3", children: /* @__PURE__ */ jsx32(SectionLabel, { tone: "secondary", children: group.value }) }),
2254
+ /* @__PURE__ */ jsx32(Autocomplete.Collection, { children: (row) => (
1966
2255
  /* The menu row, as the list's own option — the way Select
1967
2256
  puts it on `Select.Item`. One row, two parts. */
1968
- /* @__PURE__ */ jsx27(Autocomplete.Item, { value: row, onClick: () => row.onSelect(), className: menuItemClassName({ size: "tall" }), children: /* @__PURE__ */ jsx27(
2257
+ /* @__PURE__ */ jsx32(Autocomplete.Item, { value: row, onClick: () => row.onSelect(), className: menuItemClassName({ size: "tall" }), children: /* @__PURE__ */ jsx32(
1969
2258
  MenuItemBody,
1970
2259
  {
1971
2260
  size: "tall",
1972
2261
  label: row.label,
1973
2262
  description: row.description,
1974
- leading: /* @__PURE__ */ jsx27(RowLeading, { row }),
2263
+ leading: /* @__PURE__ */ jsx32(RowLeading, { row }),
1975
2264
  submenu: !!row.onGoIn,
1976
- hint: row.onGoIn ? /* @__PURE__ */ jsx27(Kbd, { children: "Tab" }) : /* @__PURE__ */ jsx27(EnterHint, {})
2265
+ hint: row.onGoIn ? /* @__PURE__ */ jsx32(Kbd, { children: "Tab" }) : /* @__PURE__ */ jsx32(EnterHint, {})
1977
2266
  }
1978
2267
  ) }, row.id)
1979
2268
  ) })
1980
2269
  ] }, group.value) }),
1981
- /* @__PURE__ */ jsx27(Autocomplete.Status, { className: "flex items-center gap-2 px-3 [&:not(:empty)]:h-8", children: pending && /* @__PURE__ */ jsxs19(Fragment5, { children: [
1982
- /* @__PURE__ */ jsx27(IconLoader22, { size: 12, stroke: 1.5, className: "shrink-0 animate-spin text-text-muted" }),
1983
- /* @__PURE__ */ jsx27("span", { className: "text-caption text-text-muted", children: pending })
2270
+ /* @__PURE__ */ jsx32(Autocomplete.Status, { className: "flex items-center gap-2 px-3 [&:not(:empty)]:h-8", children: pending && /* @__PURE__ */ jsxs23(Fragment6, { children: [
2271
+ /* @__PURE__ */ jsx32(IconLoader22, { size: 12, stroke: 1.5, className: "shrink-0 animate-spin text-text-muted" }),
2272
+ /* @__PURE__ */ jsx32("span", { className: "text-caption text-text-muted", children: pending })
1984
2273
  ] }) }),
1985
- notes.map((note) => /* @__PURE__ */ jsx27("div", { className: "flex min-h-8 items-center px-3", children: /* @__PURE__ */ jsx27(FieldLine, { children: note }) }, note)),
1986
- /* @__PURE__ */ jsx27(Autocomplete.Empty, { className: "flex items-center px-3 [&:not(:empty)]:min-h-10", children: empty && /* @__PURE__ */ jsx27(EmptyState, { scope: "section", message: empty }) })
2274
+ notes.map((note) => /* @__PURE__ */ jsx32("div", { className: "flex min-h-8 items-center px-3", children: /* @__PURE__ */ jsx32(FieldLine, { children: note }) }, note)),
2275
+ /* @__PURE__ */ jsx32(Autocomplete.Empty, { className: "flex items-center px-3 [&:not(:empty)]:min-h-10", children: empty && /* @__PURE__ */ jsx32(EmptyState, { scope: "section", message: empty }) })
1987
2276
  ] }),
1988
- /* @__PURE__ */ jsx27(Footer, { keys })
2277
+ /* @__PURE__ */ jsx32(Footer, { keys })
1989
2278
  ]
1990
2279
  }
1991
2280
  );
1992
2281
  }
1993
2282
  function RowLeading({ row }) {
1994
2283
  if (row.icon != null) {
1995
- return /* @__PURE__ */ jsx27("span", { className: "flex size-8 items-center justify-center rounded-sm bg-bg-inset text-text-secondary", children: row.icon });
2284
+ return /* @__PURE__ */ jsx32("span", { className: "flex size-8 items-center justify-center rounded-sm bg-bg-inset text-text-secondary", children: row.icon });
1996
2285
  }
1997
- return /* @__PURE__ */ jsx27("span", { className: "flex size-8 items-center justify-center", children: row.leading });
2286
+ return /* @__PURE__ */ jsx32("span", { className: "flex size-8 items-center justify-center", children: row.leading });
1998
2287
  }
1999
2288
  var TEXT_TYPES = /* @__PURE__ */ new Set(["", "text", "search", "email", "url", "tel", "password", "number"]);
2000
2289
  function isTextField(el) {
@@ -2004,9 +2293,9 @@ function isTextField(el) {
2004
2293
  function CommandPaletteForm({ chip, icon, submitLabel, onSubmit, submitWaits, working, error, children }) {
2005
2294
  const { modKey, popupRef } = usePalette("CommandPaletteForm");
2006
2295
  const back = useBack(chip, popupRef);
2007
- const frameRef = useRef5(null);
2296
+ const frameRef = useRef7(null);
2008
2297
  const busy = !!working;
2009
- const busyRef = useRef5(busy);
2298
+ const busyRef = useRef7(busy);
2010
2299
  busyRef.current = busy;
2011
2300
  const firstInvalid2 = () => frameRef.current?.querySelector("[data-invalid]")?.querySelector(CONTROL2) ?? null;
2012
2301
  const submit = () => {
@@ -2022,7 +2311,7 @@ function CommandPaletteForm({ chip, icon, submitLabel, onSubmit, submitWaits, wo
2022
2311
  if (isTextField(el)) return el.value === "";
2023
2312
  return ![...frame.querySelectorAll("input, textarea")].some(isTextField);
2024
2313
  };
2025
- const [backNamed, setBackNamed] = useState4(false);
2314
+ const [backNamed, setBackNamed] = useState5(false);
2026
2315
  const measure = () => setBackNamed(backWorksFrom(document.activeElement));
2027
2316
  useLayoutEffect3(measure);
2028
2317
  const onKeyDown = (e) => {
@@ -2036,65 +2325,65 @@ function CommandPaletteForm({ chip, icon, submitLabel, onSubmit, submitWaits, wo
2036
2325
  ...backNamed ? [["Backspace", "back"]] : [],
2037
2326
  ["Esc", "close"]
2038
2327
  ];
2039
- return /* @__PURE__ */ jsxs19("div", { ref: frameRef, tabIndex: -1, onKeyDown, onFocus: measure, onBlur: measure, onInput: measure, className: "flex min-h-0 flex-col outline-none", children: [
2040
- /* @__PURE__ */ jsxs19("div", { className: "flex h-12 shrink-0 items-center gap-3 border-b border-border-subtle px-5", children: [
2041
- icon != null && /* @__PURE__ */ jsx27("span", { className: "flex shrink-0 items-center text-text-secondary", children: icon }),
2042
- /* @__PURE__ */ jsx27(LevelChip, { chip, onBack: back })
2328
+ return /* @__PURE__ */ jsxs23("div", { ref: frameRef, tabIndex: -1, onKeyDown, onFocus: measure, onBlur: measure, onInput: measure, className: "flex min-h-0 flex-col outline-none", children: [
2329
+ /* @__PURE__ */ jsxs23("div", { className: "flex h-12 shrink-0 items-center gap-3 border-b border-border-subtle px-5", children: [
2330
+ icon != null && /* @__PURE__ */ jsx32("span", { className: "flex shrink-0 items-center text-text-secondary", children: icon }),
2331
+ /* @__PURE__ */ jsx32(LevelChip, { chip, onBack: back })
2043
2332
  ] }),
2044
- /* @__PURE__ */ jsxs19(Form, { "data-command-palette-fields": "", busy, enterSends: false, onSubmit: submit, layout: "free", className: "flex min-h-0 flex-col", children: [
2045
- /* @__PURE__ */ jsx27(ScrollArea, { viewportClassName: "max-h-[420px]", contentClassName: "flex flex-col px-5 py-4", children: /* @__PURE__ */ jsx27("div", { className: FIELDS_CLASSES, children }) }),
2046
- /* @__PURE__ */ jsxs19("div", { className: "flex shrink-0 items-center gap-3 px-5 pb-4", children: [
2047
- /* @__PURE__ */ jsx27("div", { className: "min-w-0 flex-1", children: working ? /* @__PURE__ */ jsx27(FieldLine, { children: working.line }) : error ? /* @__PURE__ */ jsx27(FieldLine, { tone: "error", children: error }) : null }),
2048
- /* @__PURE__ */ jsx27(
2333
+ /* @__PURE__ */ jsxs23(Form, { "data-command-palette-fields": "", busy, enterSends: false, onSubmit: submit, layout: "free", className: "flex min-h-0 flex-col", children: [
2334
+ /* @__PURE__ */ jsx32(ScrollArea, { viewportClassName: "max-h-[420px]", contentClassName: "flex flex-col px-5 py-4", children: /* @__PURE__ */ jsx32("div", { className: FIELDS_CLASSES, children }) }),
2335
+ /* @__PURE__ */ jsxs23("div", { className: "flex shrink-0 items-center gap-3 px-5 pb-4", children: [
2336
+ /* @__PURE__ */ jsx32("div", { className: "min-w-0 flex-1", children: working ? /* @__PURE__ */ jsx32(FieldLine, { children: working.line }) : error ? /* @__PURE__ */ jsx32(FieldLine, { tone: "error", children: error }) : null }),
2337
+ /* @__PURE__ */ jsx32(
2049
2338
  Button,
2050
2339
  {
2051
2340
  type: "submit",
2052
2341
  variant: "primary",
2053
2342
  disabled: busy,
2054
2343
  disabledReason: busy ? void 0 : submitWaits,
2055
- leadingIcon: busy ? /* @__PURE__ */ jsx27(IconLoader22, { size: 16, stroke: 1.5, className: "animate-spin" }) : void 0,
2344
+ leadingIcon: busy ? /* @__PURE__ */ jsx32(IconLoader22, { size: 16, stroke: 1.5, className: "animate-spin" }) : void 0,
2056
2345
  children: working ? working.button : submitLabel
2057
2346
  }
2058
2347
  )
2059
2348
  ] })
2060
2349
  ] }),
2061
- /* @__PURE__ */ jsx27(Footer, { keys })
2350
+ /* @__PURE__ */ jsx32(Footer, { keys })
2062
2351
  ] });
2063
2352
  }
2064
2353
  var BAR_WIDTHS = ["w-4/5", "w-3/5", "w-2/3"];
2065
2354
  function CommandPaletteWorking({ children, bars = 2 }) {
2066
- return /* @__PURE__ */ jsxs19("div", { role: "status", className: "flex flex-col gap-2", children: [
2067
- /* @__PURE__ */ jsxs19("span", { className: "flex items-center gap-2 text-caption text-text-secondary", children: [
2068
- /* @__PURE__ */ jsx27(IconLoader22, { size: 14, stroke: 1.5, className: "shrink-0 animate-spin" }),
2355
+ return /* @__PURE__ */ jsxs23("div", { role: "status", className: "flex flex-col gap-2", children: [
2356
+ /* @__PURE__ */ jsxs23("span", { className: "flex items-center gap-2 text-caption text-text-secondary", children: [
2357
+ /* @__PURE__ */ jsx32(IconLoader22, { size: 14, stroke: 1.5, className: "shrink-0 animate-spin" }),
2069
2358
  children
2070
2359
  ] }),
2071
- BAR_WIDTHS.slice(0, bars).map((width) => /* @__PURE__ */ jsx27(SkeletonBar, { className: cn("h-3", width) }, width))
2360
+ BAR_WIDTHS.slice(0, bars).map((width) => /* @__PURE__ */ jsx32(SkeletonBar, { className: cn("h-3", width) }, width))
2072
2361
  ] });
2073
2362
  }
2074
2363
  function CommandPaletteAnswer({ children, note }) {
2075
2364
  const paragraphs = children.split(/\n\s*\n/).filter((p) => p.trim() !== "");
2076
- return /* @__PURE__ */ jsxs19("div", { className: "flex flex-col gap-2", children: [
2077
- paragraphs.map((paragraph, i) => /* @__PURE__ */ jsx27("p", { className: "whitespace-pre-wrap text-body-2 text-text-primary", children: paragraph.split(/\s*(\[\d+\])/).map(
2078
- (part, j) => /^\[\d+\]$/.test(part) ? /* @__PURE__ */ jsx27("sup", { className: "ml-0.5 font-mono text-small text-accent-text", children: part.slice(1, -1) }, j) : part
2365
+ return /* @__PURE__ */ jsxs23("div", { className: "flex flex-col gap-2", children: [
2366
+ paragraphs.map((paragraph, i) => /* @__PURE__ */ jsx32("p", { className: "whitespace-pre-wrap text-body-2 text-text-primary", children: paragraph.split(/\s*(\[\d+\])/).map(
2367
+ (part, j) => /^\[\d+\]$/.test(part) ? /* @__PURE__ */ jsx32("sup", { className: "ml-0.5 font-mono text-small text-accent-text", children: part.slice(1, -1) }, j) : part
2079
2368
  ) }, i)),
2080
- note && /* @__PURE__ */ jsx27(FieldLine, { children: note })
2369
+ note && /* @__PURE__ */ jsx32(FieldLine, { children: note })
2081
2370
  ] });
2082
2371
  }
2083
2372
  function CommandPaletteQuote({ children }) {
2084
- return /* @__PURE__ */ jsx27("p", { className: "whitespace-pre-wrap border-l-2 border-border-default pl-3 text-body-2 text-text-primary", children });
2373
+ return /* @__PURE__ */ jsx32("p", { className: "whitespace-pre-wrap border-l-2 border-border-default pl-3 text-body-2 text-text-primary", children });
2085
2374
  }
2086
2375
  function CommandPaletteProposal({ source, mark, children }) {
2087
- return /* @__PURE__ */ jsxs19(Card, { fill: "surface", className: "flex flex-col gap-1 p-3", children: [
2088
- /* @__PURE__ */ jsxs19("span", { className: "flex items-center gap-2 text-caption text-text-secondary", children: [
2376
+ return /* @__PURE__ */ jsxs23(Card, { fill: "surface", className: "flex flex-col gap-1 p-3", children: [
2377
+ /* @__PURE__ */ jsxs23("span", { className: "flex items-center gap-2 text-caption text-text-secondary", children: [
2089
2378
  mark,
2090
2379
  source
2091
2380
  ] }),
2092
- /* @__PURE__ */ jsx27("span", { className: "text-body-2 text-text-primary", children })
2381
+ /* @__PURE__ */ jsx32("span", { className: "text-body-2 text-text-primary", children })
2093
2382
  ] });
2094
2383
  }
2095
2384
 
2096
2385
  // src/InlineChip.tsx
2097
- import { Fragment as Fragment6, jsx as jsx28, jsxs as jsxs20 } from "react/jsx-runtime";
2386
+ import { Fragment as Fragment7, jsx as jsx33, jsxs as jsxs24 } from "react/jsx-runtime";
2098
2387
  var INLINE_CHIP_CLASSES = "inline-flex h-[1.4em] items-center gap-1 rounded-sm px-1 mx-0.5 align-top text-body-2 font-normal select-none";
2099
2388
  var INLINE_CHIP_TONE_CLASSES = {
2100
2389
  /** A thing or a place — anything that is not a person. */
@@ -2116,19 +2405,20 @@ function inlineChipClassName(tone, className) {
2116
2405
  return cn(INLINE_CHIP_CLASSES, INLINE_CHIP_TONE_CLASSES[tone], className);
2117
2406
  }
2118
2407
  function InlineChip({ tone = "neutral", icon, href, className, children, ...props }) {
2119
- const body = /* @__PURE__ */ jsxs20(Fragment6, { children: [
2120
- icon && /* @__PURE__ */ jsx28("span", { className: "flex size-4 shrink-0 items-center justify-center text-text-secondary", children: icon }),
2408
+ const inApp = useInAppClick(href, props.onClick);
2409
+ const body = /* @__PURE__ */ jsxs24(Fragment7, { children: [
2410
+ icon && /* @__PURE__ */ jsx33("span", { className: "flex size-4 shrink-0 items-center justify-center text-text-secondary", children: icon }),
2121
2411
  children
2122
2412
  ] });
2123
2413
  const classes = inlineChipClassName(tone, className);
2124
2414
  if (href === void 0) {
2125
- return /* @__PURE__ */ jsx28("span", { className: classes, ...props, children: body });
2415
+ return /* @__PURE__ */ jsx33("span", { className: classes, ...props, children: body });
2126
2416
  }
2127
- return /* @__PURE__ */ jsx28("a", { href, className: classes, ...props, children: body });
2417
+ return /* @__PURE__ */ jsx33("a", { href, className: classes, ...props, onClick: inApp, children: body });
2128
2418
  }
2129
2419
 
2130
2420
  // src/RichText.tsx
2131
- import { Fragment as Fragment7, jsx as jsx29, jsxs as jsxs21 } from "react/jsx-runtime";
2421
+ import { Fragment as Fragment8, jsx as jsx34, jsxs as jsxs25 } from "react/jsx-runtime";
2132
2422
  var RICH_TEXT_CLASSES = {
2133
2423
  base: "flex flex-col gap-1 break-words text-text-secondary",
2134
2424
  /* A heading binds to what follows it: 12px above (8 and the 4px gap), 8px below (4 and the gap); two headings in a row, 12px apart. Level 3 keeps the text's colour, one step lower. */
@@ -2160,35 +2450,35 @@ function textWithLinks(text, renderText) {
2160
2450
  return parts.map((part, i) => {
2161
2451
  const written = part.match(WRITTEN_LINK);
2162
2452
  if (written) {
2163
- return /* @__PURE__ */ jsx29("span", { className: "break-words", children: /* @__PURE__ */ jsx29(Link, { href: written[2], external: true, onClick: keepToLink, children: written[1] }) }, i);
2453
+ return /* @__PURE__ */ jsx34("span", { className: "break-words", children: /* @__PURE__ */ jsx34(Link, { href: written[2], external: true, onClick: keepToLink, children: written[1] }) }, i);
2164
2454
  }
2165
2455
  const bare = i % 2 === 1 ? part.match(BARE_LINK) : null;
2166
2456
  if (bare) {
2167
2457
  return (
2168
2458
  // An address has no spaces to wrap at, so it may break anywhere.
2169
- /* @__PURE__ */ jsxs21("span", { className: "break-all", children: [
2170
- /* @__PURE__ */ jsx29(Link, { href: bare[1], external: true, onClick: keepToLink, children: bare[1] }),
2459
+ /* @__PURE__ */ jsxs25("span", { className: "break-all", children: [
2460
+ /* @__PURE__ */ jsx34(Link, { href: bare[1], external: true, onClick: keepToLink, children: bare[1] }),
2171
2461
  bare[2]
2172
2462
  ] }, i)
2173
2463
  );
2174
2464
  }
2175
- return part ? /* @__PURE__ */ jsx29("span", { children: renderText(part) }, i) : null;
2465
+ return part ? /* @__PURE__ */ jsx34("span", { children: renderText(part) }, i) : null;
2176
2466
  });
2177
2467
  }
2178
2468
  function Runs({ runs, draw }) {
2179
- return /* @__PURE__ */ jsx29(Fragment7, { children: (runs ?? []).map((run, i) => {
2180
- if (run.reference) return /* @__PURE__ */ jsx29("span", { children: draw.renderReference(run.reference, run) }, i);
2469
+ return /* @__PURE__ */ jsx34(Fragment8, { children: (runs ?? []).map((run, i) => {
2470
+ if (run.reference) return /* @__PURE__ */ jsx34("span", { children: draw.renderReference(run.reference, run) }, i);
2181
2471
  if (run.marks.includes("code")) {
2182
- return /* @__PURE__ */ jsx29("code", { children: run.text }, i);
2472
+ return /* @__PURE__ */ jsx34("code", { children: run.text }, i);
2183
2473
  }
2184
- let node = run.text.split("\n").map((line, j) => /* @__PURE__ */ jsxs21("span", { children: [
2185
- j > 0 && /* @__PURE__ */ jsx29("br", {}),
2474
+ let node = run.text.split("\n").map((line, j) => /* @__PURE__ */ jsxs25("span", { children: [
2475
+ j > 0 && /* @__PURE__ */ jsx34("br", {}),
2186
2476
  textWithLinks(line, draw.renderText)
2187
2477
  ] }, j));
2188
- if (run.marks.includes("underline")) node = /* @__PURE__ */ jsx29("u", { children: node });
2189
- if (run.marks.includes("italic")) node = /* @__PURE__ */ jsx29("em", { children: node });
2190
- if (run.marks.includes("bold")) node = /* @__PURE__ */ jsx29("strong", { children: node });
2191
- return /* @__PURE__ */ jsx29("span", { children: node }, i);
2478
+ if (run.marks.includes("underline")) node = /* @__PURE__ */ jsx34("u", { children: node });
2479
+ if (run.marks.includes("italic")) node = /* @__PURE__ */ jsx34("em", { children: node });
2480
+ if (run.marks.includes("bold")) node = /* @__PURE__ */ jsx34("strong", { children: node });
2481
+ return /* @__PURE__ */ jsx34("span", { children: node }, i);
2192
2482
  }) });
2193
2483
  }
2194
2484
  var named = (block) => block.typeName ?? block.type;
@@ -2199,15 +2489,15 @@ function Table({ block, draw }) {
2199
2489
  const header = named(cell) === "tableHeader";
2200
2490
  const Cell = header ? "th" : "td";
2201
2491
  const { colspan, rowspan } = cell.attrs ?? {};
2202
- return /* @__PURE__ */ jsxs21(
2492
+ return /* @__PURE__ */ jsxs25(
2203
2493
  Cell,
2204
2494
  {
2205
2495
  "data-block-id": cell.id,
2206
2496
  colSpan: colspan && colspan > 1 ? colspan : void 0,
2207
2497
  rowSpan: rowspan && rowspan > 1 ? rowspan : void 0,
2208
2498
  children: [
2209
- (cell.children ?? []).map((child, j) => /* @__PURE__ */ jsx29(Runs, { runs: child.inline, draw }, j)),
2210
- /* @__PURE__ */ jsx29(Runs, { runs: cell.inline, draw })
2499
+ (cell.children ?? []).map((child, j) => /* @__PURE__ */ jsx34(Runs, { runs: child.inline, draw }, j)),
2500
+ /* @__PURE__ */ jsx34(Runs, { runs: cell.inline, draw })
2211
2501
  ]
2212
2502
  },
2213
2503
  cell.id ?? i
@@ -2215,43 +2505,43 @@ function Table({ block, draw }) {
2215
2505
  });
2216
2506
  const first = rows[0].children ?? [];
2217
2507
  const headerRow = first.length > 0 && first.every((cell) => named(cell) === "tableHeader");
2218
- return /* @__PURE__ */ jsxs21("table", { "data-block-id": block.id, children: [
2219
- headerRow && /* @__PURE__ */ jsx29("thead", { children: /* @__PURE__ */ jsx29("tr", { "data-block-id": rows[0].id, children: cells(rows[0]) }) }),
2220
- /* @__PURE__ */ jsx29("tbody", { children: (headerRow ? rows.slice(1) : rows).map((row, i) => /* @__PURE__ */ jsx29("tr", { "data-block-id": row.id, children: cells(row) }, row.id ?? i)) })
2508
+ return /* @__PURE__ */ jsxs25("table", { "data-block-id": block.id, children: [
2509
+ headerRow && /* @__PURE__ */ jsx34("thead", { children: /* @__PURE__ */ jsx34("tr", { "data-block-id": rows[0].id, children: cells(rows[0]) }) }),
2510
+ /* @__PURE__ */ jsx34("tbody", { children: (headerRow ? rows.slice(1) : rows).map((row, i) => /* @__PURE__ */ jsx34("tr", { "data-block-id": row.id, children: cells(row) }, row.id ?? i)) })
2221
2511
  ] });
2222
2512
  }
2223
2513
  function Block({ block, draw }) {
2224
2514
  const own = draw.renderBlock?.(block);
2225
2515
  if (own !== void 0) return own;
2226
- const runs = /* @__PURE__ */ jsx29(Runs, { runs: block.inline, draw });
2516
+ const runs = /* @__PURE__ */ jsx34(Runs, { runs: block.inline, draw });
2227
2517
  switch (block.type) {
2228
2518
  case "heading": {
2229
- if (block.level === 1) return /* @__PURE__ */ jsx29("h1", { "data-block-id": block.id, children: runs });
2230
- if (block.level === 3) return /* @__PURE__ */ jsx29("h3", { "data-block-id": block.id, children: runs });
2231
- return /* @__PURE__ */ jsx29("h2", { "data-block-id": block.id, children: runs });
2519
+ if (block.level === 1) return /* @__PURE__ */ jsx34("h1", { "data-block-id": block.id, children: runs });
2520
+ if (block.level === 3) return /* @__PURE__ */ jsx34("h3", { "data-block-id": block.id, children: runs });
2521
+ return /* @__PURE__ */ jsx34("h2", { "data-block-id": block.id, children: runs });
2232
2522
  }
2233
2523
  case "paragraph":
2234
- return /* @__PURE__ */ jsx29("p", { "data-block-id": block.id, children: runs });
2524
+ return /* @__PURE__ */ jsx34("p", { "data-block-id": block.id, children: runs });
2235
2525
  case "bulletList":
2236
2526
  case "orderedList": {
2237
- const items = (block.children ?? []).map((item, i) => /* @__PURE__ */ jsx29("li", { "data-block-id": item.id, children: /* @__PURE__ */ jsx29(Runs, { runs: item.inline, draw }) }, item.id ?? i));
2238
- return block.type === "bulletList" ? /* @__PURE__ */ jsx29("ul", { "data-block-id": block.id, children: items }) : /* @__PURE__ */ jsx29("ol", { "data-block-id": block.id, start: block.start, children: items });
2527
+ const items = (block.children ?? []).map((item, i) => /* @__PURE__ */ jsx34("li", { "data-block-id": item.id, children: /* @__PURE__ */ jsx34(Runs, { runs: item.inline, draw }) }, item.id ?? i));
2528
+ return block.type === "bulletList" ? /* @__PURE__ */ jsx34("ul", { "data-block-id": block.id, children: items }) : /* @__PURE__ */ jsx34("ol", { "data-block-id": block.id, start: block.start, children: items });
2239
2529
  }
2240
2530
  case "blockquote":
2241
- return /* @__PURE__ */ jsx29("blockquote", { "data-block-id": block.id, children: runs });
2531
+ return /* @__PURE__ */ jsx34("blockquote", { "data-block-id": block.id, children: runs });
2242
2532
  case "codeBlock":
2243
- return /* @__PURE__ */ jsx29("pre", { "data-block-id": block.id, "data-language": block.language, children: /* @__PURE__ */ jsx29("code", { children: (block.inline ?? []).map((run) => run.text).join("") }) });
2533
+ return /* @__PURE__ */ jsx34("pre", { "data-block-id": block.id, "data-language": block.language, children: /* @__PURE__ */ jsx34("code", { children: (block.inline ?? []).map((run) => run.text).join("") }) });
2244
2534
  case "horizontalRule":
2245
- return /* @__PURE__ */ jsx29("hr", { "data-block-id": block.id });
2535
+ return /* @__PURE__ */ jsx34("hr", { "data-block-id": block.id });
2246
2536
  case "table": {
2247
- const table = /* @__PURE__ */ jsx29(Table, { block, draw });
2537
+ const table = /* @__PURE__ */ jsx34(Table, { block, draw });
2248
2538
  if ((block.children ?? []).some((row) => named(row) === "tableRow")) return table;
2249
2539
  break;
2250
2540
  }
2251
2541
  }
2252
- return /* @__PURE__ */ jsxs21("div", { "data-block-id": block.id, "data-block-type": named(block), children: [
2542
+ return /* @__PURE__ */ jsxs25("div", { "data-block-id": block.id, "data-block-type": named(block), children: [
2253
2543
  runs,
2254
- (block.children ?? []).map((child, i) => /* @__PURE__ */ jsx29(Block, { block: child, draw }, child.id ?? i))
2544
+ (block.children ?? []).map((child, i) => /* @__PURE__ */ jsx34(Block, { block: child, draw }, child.id ?? i))
2255
2545
  ] });
2256
2546
  }
2257
2547
  function RichText({
@@ -2263,34 +2553,34 @@ function RichText({
2263
2553
  }) {
2264
2554
  if (blocks.length === 0) return null;
2265
2555
  const draw = { renderText, renderReference, renderBlock };
2266
- return /* @__PURE__ */ jsx29("div", { "data-rich-text": true, className: richTextClassName(size), children: blocks.map((block, i) => /* @__PURE__ */ jsx29(Block, { block, draw }, block.id ?? i)) });
2556
+ return /* @__PURE__ */ jsx34("div", { "data-rich-text": true, className: richTextClassName(size), children: blocks.map((block, i) => /* @__PURE__ */ jsx34(Block, { block, draw }, block.id ?? i)) });
2267
2557
  }
2268
2558
 
2269
2559
  // src/IdentityMenu.tsx
2270
- import { useCallback as useCallback2, useRef as useRef6 } from "react";
2560
+ import { useCallback as useCallback2, useRef as useRef8 } from "react";
2271
2561
 
2272
2562
  // src/Person.tsx
2273
- import { jsx as jsx30, jsxs as jsxs22 } from "react/jsx-runtime";
2563
+ import { jsx as jsx35, jsxs as jsxs26 } from "react/jsx-runtime";
2274
2564
  function Person({ name, picture, fallback = "\u2014", size = 20, className }) {
2275
2565
  return (
2276
2566
  // gap-2: the face-to-name distance is one rule (8px) wherever a person
2277
2567
  // appears — Katerina, 2026-09-01, set on Person so PersonTrigger and every
2278
2568
  // row agree by construction.
2279
- /* @__PURE__ */ jsxs22("span", { className: cn("flex min-w-0 items-center gap-2", className), children: [
2280
- /* @__PURE__ */ jsx30(Avatar, { name, src: picture, size }),
2281
- /* @__PURE__ */ jsx30("span", { className: cn("truncate", !name && "text-text-muted"), children: name ?? fallback })
2569
+ /* @__PURE__ */ jsxs26("span", { className: cn("flex min-w-0 items-center gap-2", className), children: [
2570
+ /* @__PURE__ */ jsx35(Avatar, { name, src: picture, size }),
2571
+ /* @__PURE__ */ jsx35("span", { className: cn("truncate", !name && "text-text-muted"), children: name ?? fallback })
2282
2572
  ] })
2283
2573
  );
2284
2574
  }
2285
2575
 
2286
2576
  // src/PersonTrigger.tsx
2287
- import { Button as BaseButton5 } from "@base-ui/react/button";
2288
- import { IconChevronDown } from "@tabler/icons-react";
2289
- import { jsx as jsx31, jsxs as jsxs23 } from "react/jsx-runtime";
2577
+ import { Button as BaseButton7 } from "@base-ui/react/button";
2578
+ import { IconChevronDown as IconChevronDown2 } from "@tabler/icons-react";
2579
+ import { jsx as jsx36, jsxs as jsxs27 } from "react/jsx-runtime";
2290
2580
  function PersonTrigger({ name, picture, fallback, size, open = false, compact = false, className, ...props }) {
2291
2581
  if (compact) {
2292
- return /* @__PURE__ */ jsx31(
2293
- BaseButton5,
2582
+ return /* @__PURE__ */ jsx36(
2583
+ BaseButton7,
2294
2584
  {
2295
2585
  type: "button",
2296
2586
  "aria-haspopup": "menu",
@@ -2298,14 +2588,14 @@ function PersonTrigger({ name, picture, fallback, size, open = false, compact =
2298
2588
  "aria-label": props["aria-label"] ?? name ?? fallback,
2299
2589
  className: cn("cursor-pointer rounded-full", className),
2300
2590
  ...props,
2301
- children: /* @__PURE__ */ jsx31(Avatar, { name, src: picture, size: size ?? 36 })
2591
+ children: /* @__PURE__ */ jsx36(Avatar, { name, src: picture, size: size ?? 36 })
2302
2592
  }
2303
2593
  );
2304
2594
  }
2305
2595
  return (
2306
2596
  // @estiva-escape(no-copied-look): N5 (Katerina, 24 September: record only): a row that fills on hover, as NavItem also does
2307
- /* @__PURE__ */ jsxs23(
2308
- BaseButton5,
2597
+ /* @__PURE__ */ jsxs27(
2598
+ BaseButton7,
2309
2599
  {
2310
2600
  type: "button",
2311
2601
  "aria-haspopup": "menu",
@@ -2322,8 +2612,8 @@ function PersonTrigger({ name, picture, fallback, size, open = false, compact =
2322
2612
  ),
2323
2613
  ...props,
2324
2614
  children: [
2325
- /* @__PURE__ */ jsx31(Person, { name, picture, fallback, size: size ?? 22 }),
2326
- /* @__PURE__ */ jsx31(IconChevronDown, { size: 14, stroke: 1.5, className: "shrink-0 text-text-muted" })
2615
+ /* @__PURE__ */ jsx36(Person, { name, picture, fallback, size: size ?? 22 }),
2616
+ /* @__PURE__ */ jsx36(IconChevronDown2, { size: 14, stroke: 1.5, className: "shrink-0 text-text-muted" })
2327
2617
  ]
2328
2618
  }
2329
2619
  )
@@ -2331,10 +2621,10 @@ function PersonTrigger({ name, picture, fallback, size, open = false, compact =
2331
2621
  }
2332
2622
 
2333
2623
  // src/IdentityMenu.tsx
2334
- import { Fragment as Fragment8, jsx as jsx32, jsxs as jsxs24 } from "react/jsx-runtime";
2624
+ import { Fragment as Fragment9, jsx as jsx37, jsxs as jsxs28 } from "react/jsx-runtime";
2335
2625
  function IdentityPanel({ className, onClose = () => {
2336
2626
  }, ...rest }) {
2337
- return /* @__PURE__ */ jsx32(MenuPanel, { className: cn("w-72", className), children: /* @__PURE__ */ jsx32(IdentityRows, { ...rest, onClose }) });
2627
+ return /* @__PURE__ */ jsx37(MenuPanel, { className: cn("w-72", className), children: /* @__PURE__ */ jsx37(IdentityRows, { ...rest, onClose }) });
2338
2628
  }
2339
2629
  function IdentityRows({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, onClose, children }) {
2340
2630
  const act = (action) => () => {
@@ -2342,53 +2632,53 @@ function IdentityRows({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, on
2342
2632
  action();
2343
2633
  };
2344
2634
  const appRows = typeof children === "function" ? children(onClose) : children;
2345
- return /* @__PURE__ */ jsxs24(Fragment8, { children: [
2346
- /* @__PURE__ */ jsxs24(MenuSection, { label: signedIn ? "Signed in as" : "Acting as", children: [
2347
- /* @__PURE__ */ jsx32(MenuRow, { children: /* @__PURE__ */ jsx32("div", { className: "flex min-w-0 text-body-2-strong", children: /* @__PURE__ */ jsx32(Person, { name: me.name, picture: me.picture, fallback: "Anonymous", size: 28 }) }) }),
2348
- /* @__PURE__ */ jsx32(Note, { children: signedIn ? "Your Estiva ID. The same person you are in every Estiva app." : "A key held by this browser only. Nobody else knows who you are." }),
2349
- me.email && /* @__PURE__ */ jsxs24(Note, { children: [
2635
+ return /* @__PURE__ */ jsxs28(Fragment9, { children: [
2636
+ /* @__PURE__ */ jsxs28(MenuSection, { label: signedIn ? "Signed in as" : "Acting as", children: [
2637
+ /* @__PURE__ */ jsx37(MenuRow, { children: /* @__PURE__ */ jsx37("div", { className: "flex min-w-0 text-body-2-strong", children: /* @__PURE__ */ jsx37(Person, { name: me.name, picture: me.picture, fallback: "Anonymous", size: 28 }) }) }),
2638
+ /* @__PURE__ */ jsx37(Note, { children: signedIn ? "Your Estiva ID. The same person you are in every Estiva app." : "A key held by this browser only. Nobody else knows who you are." }),
2639
+ me.email && /* @__PURE__ */ jsxs28(Note, { children: [
2350
2640
  me.email,
2351
2641
  " \xB7 known to Estiva, never published to the relay"
2352
2642
  ] })
2353
2643
  ] }),
2354
- relayUrl && /* @__PURE__ */ jsxs24(Fragment8, { children: [
2355
- /* @__PURE__ */ jsx32(Divider, { className: "mx-0 my-2" }),
2356
- /* @__PURE__ */ jsxs24(MenuSection, { label: "Workspace", children: [
2357
- /* @__PURE__ */ jsx32(MenuRow, { children: /* @__PURE__ */ jsx32("span", { className: "break-all font-mono text-caption text-text-primary", children: relayUrl }) }),
2358
- /* @__PURE__ */ jsx32(Note, { children: "Everyone on this relay shares this workspace, in every app." })
2644
+ relayUrl && /* @__PURE__ */ jsxs28(Fragment9, { children: [
2645
+ /* @__PURE__ */ jsx37(Divider, { className: "mx-0 my-2" }),
2646
+ /* @__PURE__ */ jsxs28(MenuSection, { label: "Workspace", children: [
2647
+ /* @__PURE__ */ jsx37(MenuRow, { children: /* @__PURE__ */ jsx37("span", { className: "break-all font-mono text-caption text-text-primary", children: relayUrl }) }),
2648
+ /* @__PURE__ */ jsx37(Note, { children: "Everyone on this relay shares this workspace, in every app." })
2359
2649
  ] })
2360
2650
  ] }),
2361
- appRows && /* @__PURE__ */ jsxs24(Fragment8, { children: [
2362
- /* @__PURE__ */ jsx32(Divider, { className: "mx-0 my-2" }),
2651
+ appRows && /* @__PURE__ */ jsxs28(Fragment9, { children: [
2652
+ /* @__PURE__ */ jsx37(Divider, { className: "mx-0 my-2" }),
2363
2653
  appRows
2364
2654
  ] }),
2365
- signedIn && idBase || onCopyKey || idBase && onSignOut ? /* @__PURE__ */ jsx32(Divider, { className: "mx-0 my-2" }) : null,
2366
- signedIn && idBase && /* @__PURE__ */ jsx32(
2655
+ signedIn && idBase || onCopyKey || idBase && onSignOut ? /* @__PURE__ */ jsx37(Divider, { className: "mx-0 my-2" }) : null,
2656
+ signedIn && idBase && /* @__PURE__ */ jsx37(
2367
2657
  MenuItem,
2368
2658
  {
2369
2659
  label: "Edit your profile in Estiva ID",
2370
2660
  onClick: act(() => window.open(idBase, "_blank", "noopener,noreferrer"))
2371
2661
  }
2372
2662
  ),
2373
- onCopyKey && /* @__PURE__ */ jsx32(MenuItem, { label: "Copy public key", onClick: act(onCopyKey) }),
2374
- idBase && onSignOut && /* @__PURE__ */ jsx32(MenuItem, { label: "Sign out", onClick: act(onSignOut) })
2663
+ onCopyKey && /* @__PURE__ */ jsx37(MenuItem, { label: "Copy public key", onClick: act(onCopyKey) }),
2664
+ idBase && onSignOut && /* @__PURE__ */ jsx37(MenuItem, { label: "Sign out", onClick: act(onSignOut) })
2375
2665
  ] });
2376
2666
  }
2377
2667
  function IdentityMenu({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, compact = false, className, children }) {
2378
- const actions = useRef6(null);
2668
+ const actions = useRef8(null);
2379
2669
  const close = useCallback2(() => actions.current?.close(), []);
2380
2670
  return (
2381
2671
  /* The wrapper carries the caller's `className` and nothing else. It used
2382
2672
  to be `relative`, because the panel was positioned against it; the panel
2383
2673
  hangs from the trigger and portals now, so a positioning context here
2384
2674
  would only be a lie about what this box does. */
2385
- /* @__PURE__ */ jsx32("div", { className, children: /* @__PURE__ */ jsx32(
2675
+ /* @__PURE__ */ jsx37("div", { className, children: /* @__PURE__ */ jsx37(
2386
2676
  Menu,
2387
2677
  {
2388
2678
  align: "right",
2389
2679
  actionsRef: actions,
2390
2680
  className: "w-72",
2391
- trigger: /* @__PURE__ */ jsx32(
2681
+ trigger: /* @__PURE__ */ jsx37(
2392
2682
  PersonTrigger,
2393
2683
  {
2394
2684
  name: me.name,
@@ -2399,7 +2689,7 @@ function IdentityMenu({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, co
2399
2689
  "aria-label": compact ? "Account menu" : void 0
2400
2690
  }
2401
2691
  ),
2402
- children: /* @__PURE__ */ jsx32(
2692
+ children: /* @__PURE__ */ jsx37(
2403
2693
  IdentityRows,
2404
2694
  {
2405
2695
  me,
@@ -2417,14 +2707,14 @@ function IdentityMenu({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, co
2417
2707
  );
2418
2708
  }
2419
2709
  function Note({ children }) {
2420
- return /* @__PURE__ */ jsx32("span", { className: "px-2 pb-1.5 text-caption text-text-secondary", children });
2710
+ return /* @__PURE__ */ jsx37("span", { className: "px-2 pb-1.5 text-caption text-text-secondary", children });
2421
2711
  }
2422
2712
 
2423
2713
  // src/FilePicker.tsx
2424
2714
  import { forwardRef } from "react";
2425
- import { jsx as jsx33 } from "react/jsx-runtime";
2715
+ import { jsx as jsx38 } from "react/jsx-runtime";
2426
2716
  var FilePicker = forwardRef(function FilePicker2({ onPick, ...props }, ref) {
2427
- return /* @__PURE__ */ jsx33(
2717
+ return /* @__PURE__ */ jsx38(
2428
2718
  "input",
2429
2719
  {
2430
2720
  ref,
@@ -2443,9 +2733,9 @@ var FilePicker = forwardRef(function FilePicker2({ onPick, ...props }, ref) {
2443
2733
  });
2444
2734
 
2445
2735
  // src/Select.tsx
2446
- import { IconCheck as IconCheck2, IconChevronDown as IconChevronDown2 } from "@tabler/icons-react";
2736
+ import { IconCheck as IconCheck2, IconChevronDown as IconChevronDown3 } from "@tabler/icons-react";
2447
2737
  import { Select as BaseSelect } from "@base-ui/react/select";
2448
- import { jsx as jsx34, jsxs as jsxs25 } from "react/jsx-runtime";
2738
+ import { jsx as jsx39, jsxs as jsxs29 } from "react/jsx-runtime";
2449
2739
  var GAP4 = 4;
2450
2740
  var VIEWPORT_PAD4 = 8;
2451
2741
  function Select({ value, onChange, options, size = "default", ariaLabel, placeholder = "Select\u2026", disabled, disabledReason, className, ...aria }) {
@@ -2453,7 +2743,7 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
2453
2743
  const held = Boolean(disabledReason);
2454
2744
  const trigger = (
2455
2745
  // @estiva-escape(no-copied-look): N1 (Katerina, 24 September: record only): Select's box drops the hover while held, so it cannot take FIELD_SHELL_CLASSES as it is
2456
- /* @__PURE__ */ jsxs25(
2746
+ /* @__PURE__ */ jsxs29(
2457
2747
  BaseSelect.Trigger,
2458
2748
  {
2459
2749
  "aria-label": ariaLabel,
@@ -2486,21 +2776,21 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
2486
2776
  className
2487
2777
  ),
2488
2778
  children: [
2489
- /* @__PURE__ */ jsxs25("span", { className: cn("flex min-w-0 items-center gap-2", !selected && "text-text-muted"), children: [
2490
- selected?.leading && /* @__PURE__ */ jsx34("span", { className: "flex shrink-0 items-center", children: selected.leading }),
2491
- /* @__PURE__ */ jsx34(BaseSelect.Value, { className: "truncate", children: () => selected?.label ?? placeholder })
2779
+ /* @__PURE__ */ jsxs29("span", { className: cn("flex min-w-0 items-center gap-2", !selected && "text-text-muted"), children: [
2780
+ selected?.leading && /* @__PURE__ */ jsx39("span", { className: "flex shrink-0 items-center", children: selected.leading }),
2781
+ /* @__PURE__ */ jsx39(BaseSelect.Value, { className: "truncate", children: () => selected?.label ?? placeholder })
2492
2782
  ] }),
2493
- /* @__PURE__ */ jsx34(
2783
+ /* @__PURE__ */ jsx39(
2494
2784
  BaseSelect.Icon,
2495
2785
  {
2496
- render: /* @__PURE__ */ jsx34(IconChevronDown2, { size: size === "small" ? 14 : 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
2786
+ render: /* @__PURE__ */ jsx39(IconChevronDown3, { size: size === "small" ? 14 : 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
2497
2787
  }
2498
2788
  )
2499
2789
  ]
2500
2790
  }
2501
2791
  )
2502
2792
  );
2503
- return /* @__PURE__ */ jsxs25(
2793
+ return /* @__PURE__ */ jsxs29(
2504
2794
  BaseSelect.Root,
2505
2795
  {
2506
2796
  value,
@@ -2512,8 +2802,8 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
2512
2802
  disabled: disabled && !held,
2513
2803
  modal: false,
2514
2804
  children: [
2515
- held ? /* @__PURE__ */ jsx34(TooltipTrigger, { label: disabledReason ?? "", children: trigger }) : trigger,
2516
- /* @__PURE__ */ jsx34(BaseSelect.Portal, { children: /* @__PURE__ */ jsx34(
2805
+ held ? /* @__PURE__ */ jsx39(TooltipTrigger, { label: disabledReason ?? "", children: trigger }) : trigger,
2806
+ /* @__PURE__ */ jsx39(BaseSelect.Portal, { children: /* @__PURE__ */ jsx39(
2517
2807
  BaseSelect.Positioner,
2518
2808
  {
2519
2809
  side: "bottom",
@@ -2522,25 +2812,25 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
2522
2812
  collisionPadding: VIEWPORT_PAD4,
2523
2813
  alignItemWithTrigger: false,
2524
2814
  className: "z-50 data-[anchor-hidden]:hidden",
2525
- children: /* @__PURE__ */ jsx34(
2815
+ children: /* @__PURE__ */ jsx39(
2526
2816
  BaseSelect.Popup,
2527
2817
  {
2528
- render: /* @__PURE__ */ jsx34(MenuPanel, {}),
2818
+ render: /* @__PURE__ */ jsx39(MenuPanel, {}),
2529
2819
  className: "min-w-[var(--anchor-width)] p-0",
2530
- children: /* @__PURE__ */ jsx34(ScrollArea, { viewportClassName: "max-h-[min(288px,var(--available-height))]", contentClassName: "flex flex-col gap-0.5 p-2", children: options.map((option) => /* @__PURE__ */ jsxs25(
2820
+ children: /* @__PURE__ */ jsx39(ScrollArea, { viewportClassName: "max-h-[min(288px,var(--available-height))]", contentClassName: "flex flex-col gap-0.5 p-2", children: options.map((option) => /* @__PURE__ */ jsxs29(
2531
2821
  BaseSelect.Item,
2532
2822
  {
2533
2823
  value: option.value,
2534
2824
  className: cn(menuItemClassName({ size: "default" }), "justify-between data-[selected]:font-medium"),
2535
2825
  children: [
2536
- /* @__PURE__ */ jsxs25("span", { className: "flex min-w-0 items-center gap-2", children: [
2537
- option.leading && /* @__PURE__ */ jsx34("span", { className: "flex shrink-0 items-center", children: option.leading }),
2538
- /* @__PURE__ */ jsx34(BaseSelect.ItemText, { className: "truncate text-body-2 text-text-primary", children: option.label })
2826
+ /* @__PURE__ */ jsxs29("span", { className: "flex min-w-0 items-center gap-2", children: [
2827
+ option.leading && /* @__PURE__ */ jsx39("span", { className: "flex shrink-0 items-center", children: option.leading }),
2828
+ /* @__PURE__ */ jsx39(BaseSelect.ItemText, { className: "truncate text-body-2 text-text-primary", children: option.label })
2539
2829
  ] }),
2540
- /* @__PURE__ */ jsx34(
2830
+ /* @__PURE__ */ jsx39(
2541
2831
  BaseSelect.ItemIndicator,
2542
2832
  {
2543
- render: /* @__PURE__ */ jsx34(IconCheck2, { size: 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
2833
+ render: /* @__PURE__ */ jsx39(IconCheck2, { size: 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
2544
2834
  }
2545
2835
  )
2546
2836
  ]
@@ -2559,9 +2849,9 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
2559
2849
  // src/TextInput.tsx
2560
2850
  import { forwardRef as forwardRef2 } from "react";
2561
2851
  import { Input } from "@base-ui/react/input";
2562
- import { jsx as jsx35 } from "react/jsx-runtime";
2852
+ import { jsx as jsx40 } from "react/jsx-runtime";
2563
2853
  var TextInput = forwardRef2(function TextInput2({ className, type = "text", size = "default", ...props }, ref) {
2564
- return /* @__PURE__ */ jsx35(
2854
+ return /* @__PURE__ */ jsx40(
2565
2855
  Input,
2566
2856
  {
2567
2857
  ref,
@@ -2587,13 +2877,13 @@ var TextInput = forwardRef2(function TextInput2({ className, type = "text", size
2587
2877
  // src/Textarea.tsx
2588
2878
  import { forwardRef as forwardRef3 } from "react";
2589
2879
  import { Field as BaseField3 } from "@base-ui/react/field";
2590
- import { jsx as jsx36 } from "react/jsx-runtime";
2880
+ import { jsx as jsx41 } from "react/jsx-runtime";
2591
2881
  var Textarea = forwardRef3(function Textarea2({ className, ...props }, ref) {
2592
- return /* @__PURE__ */ jsx36(
2882
+ return /* @__PURE__ */ jsx41(
2593
2883
  BaseField3.Control,
2594
2884
  {
2595
2885
  ref,
2596
- render: /* @__PURE__ */ jsx36("textarea", {}),
2886
+ render: /* @__PURE__ */ jsx41("textarea", {}),
2597
2887
  className: cn(
2598
2888
  // The border strengthens on hover, as Select's and ChipInput's do (Katerina, 16 September:
2599
2889
  // "aren't there hover states in text input and text area?"). Focus comes after hover in
@@ -2612,110 +2902,10 @@ var Textarea = forwardRef3(function Textarea2({ className, ...props }, ref) {
2612
2902
  });
2613
2903
 
2614
2904
  // src/ConfirmDialog.tsx
2615
- import { useState as useState5 } from "react";
2616
-
2617
- // src/DialogShell.tsx
2618
- import { useRef as useRef7 } from "react";
2619
- import { Dialog as Dialog3 } from "@base-ui/react/dialog";
2620
- import { AlertDialog } from "@base-ui/react/alert-dialog";
2621
- import { IconX as IconX5 } from "@tabler/icons-react";
2622
-
2623
- // src/ContainerHeader.tsx
2624
- import { IconChevronDown as IconChevronDown3 } from "@tabler/icons-react";
2625
- import { Button as BaseButton6 } from "@base-ui/react/button";
2626
- import { jsx as jsx37, jsxs as jsxs26 } from "react/jsx-runtime";
2627
- function ContainerHeader({ title, chevron = false, titleMenu, actions, className }) {
2628
- const text = typeof title === "string";
2629
- const name = /* @__PURE__ */ jsxs26("div", { className: cn("flex items-center gap-1", text ? "shrink-0" : "min-w-0 flex-1"), children: [
2630
- text ? /* @__PURE__ */ jsx37("span", { className: "whitespace-nowrap text-body-2-strong text-text-primary", children: title }) : /* @__PURE__ */ jsx37("div", { className: "min-w-0 flex-1", children: title }),
2631
- (chevron || titleMenu != null) && /* @__PURE__ */ jsx37(IconChevronDown3, { size: 12, stroke: 1.5, className: "shrink-0 text-text-secondary" })
2632
- ] });
2633
- return (
2634
- // The title 16px in, where the column's content starts (Katerina, 7 October; it was 20px).
2635
- // With a title menu the bar gives the button 6px of its left padding
2636
- // (pl-2.5 + the button's px-1.5 = pl-4): the words stay where a title's
2637
- // are, and the fill is inside the bar — a negative margin had it clipped
2638
- // (Katerina, 5 October).
2639
- /* @__PURE__ */ jsxs26("div", { className: cn("flex h-12 shrink-0 items-center justify-between overflow-hidden border-b border-border-subtle py-2 pr-4", titleMenu != null ? "pl-2.5" : "pl-4", className), children: [
2640
- /* @__PURE__ */ jsx37("div", { className: cn("flex items-center gap-2 overflow-hidden", text ? "shrink-0" : "min-w-0 flex-1"), children: titleMenu != null ? /* @__PURE__ */ jsx37(
2641
- Menu,
2642
- {
2643
- trigger: /* @__PURE__ */ jsx37(BaseButton6, { type: "button", className: cn("flex min-w-0 items-center px-1.5 py-1", MENU_TRIGGER_CLASSES), children: name }),
2644
- children: titleMenu
2645
- }
2646
- ) : name }),
2647
- actions && /* @__PURE__ */ jsx37("div", { className: "flex shrink-0 items-center justify-end gap-3", children: /* @__PURE__ */ jsx37("div", { className: "flex shrink-0 items-center gap-1", children: actions }) })
2648
- ] })
2649
- );
2650
- }
2651
-
2652
- // src/DialogShell.tsx
2653
- import { jsx as jsx38, jsxs as jsxs27 } from "react/jsx-runtime";
2654
- function DialogShell({ title, onClose, headerContent, footer, children, bodyClassName, bodyMaxHeight, width = 502, alert = false }) {
2655
- const Parts = alert ? AlertDialog : Dialog3;
2656
- const popupRef = useRef7(null);
2657
- return /* @__PURE__ */ jsx38(
2658
- Parts.Root,
2659
- {
2660
- open: true,
2661
- onOpenChange: (open) => {
2662
- if (!open) onClose();
2663
- },
2664
- children: /* @__PURE__ */ jsxs27(Parts.Portal, { children: [
2665
- /* @__PURE__ */ jsx38(Parts.Backdrop, { className: "fixed inset-0 z-40 bg-scrim" }),
2666
- /* @__PURE__ */ jsx38("div", { className: "fixed inset-0 z-50 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxs27(
2667
- Parts.Popup,
2668
- {
2669
- ref: popupRef,
2670
- initialFocus: popupRef,
2671
- "aria-label": headerContent != null ? title : void 0,
2672
- className: "bg-bg-elevated border border-border-subtle rounded-lg shadow-lg pointer-events-auto flex flex-col overflow-hidden outline-none",
2673
- style: { width },
2674
- children: [
2675
- /* @__PURE__ */ jsx38(
2676
- ContainerHeader,
2677
- {
2678
- className: "pl-5",
2679
- title: headerContent ?? /* @__PURE__ */ jsx38(Parts.Title, { className: "block truncate text-h4 text-text-primary", render: /* @__PURE__ */ jsx38("span", {}), children: title }),
2680
- actions: (
2681
- /*
2682
- The ✕ IS the `Close` part now, rather than a button that calls
2683
- `onClose` beside one (stage 4, 2026-09-07). Stage 3 could not do
2684
- this: an `IconButton` carrying a `tooltip` returned the tooltip
2685
- wrapper `<div>` as its root, so the part composed onto the
2686
- wrapper and not the button. Porting Tooltip removed the wrapper
2687
- — the trigger is the button itself — and the composition works.
2688
-
2689
- What it buys: the dialog closes through its own state machine,
2690
- so the ✕, Escape and the outside press are one path with one
2691
- reason attached, instead of one of the three going around.
2692
- */
2693
- /* @__PURE__ */ jsx38(
2694
- Parts.Close,
2695
- {
2696
- render: /* @__PURE__ */ jsx38(IconButton, { tooltip: "Close", "aria-label": "Close", children: /* @__PURE__ */ jsx38(IconX5, { size: 16, stroke: 1.5 }) })
2697
- }
2698
- )
2699
- )
2700
- }
2701
- ),
2702
- bodyMaxHeight ? (
2703
- // The line above the footer on a box of the shell's own, not pushed into ScrollArea (UIG-9).
2704
- /* @__PURE__ */ jsx38("div", { className: cn(footer != null && "border-b border-border-subtle"), children: /* @__PURE__ */ jsx38(ScrollArea, { viewportClassName: bodyMaxHeight, contentClassName: cn("pl-5 pr-4 py-4", bodyClassName), children }) })
2705
- ) : /* @__PURE__ */ jsx38("div", { className: cn("pl-5 pr-4 py-4", footer != null && "border-b border-border-subtle", bodyClassName), children }),
2706
- footer != null && /* @__PURE__ */ jsx38("div", { className: "h-12 flex items-center justify-end gap-2 pl-5 pr-4 shrink-0", children: footer })
2707
- ]
2708
- }
2709
- ) })
2710
- ] })
2711
- }
2712
- );
2713
- }
2714
-
2715
- // src/ConfirmDialog.tsx
2716
- import { Fragment as Fragment9, jsx as jsx39, jsxs as jsxs28 } from "react/jsx-runtime";
2905
+ import { useState as useState6 } from "react";
2906
+ import { Fragment as Fragment10, jsx as jsx42, jsxs as jsxs30 } from "react/jsx-runtime";
2717
2907
  function ConfirmDialog({ title, children, confirmLabel, destructive = false, onConfirm, onClose }) {
2718
- const [busy, setBusy] = useState5(false);
2908
+ const [busy, setBusy] = useState6(false);
2719
2909
  const confirm = async () => {
2720
2910
  setBusy(true);
2721
2911
  try {
@@ -2725,32 +2915,32 @@ function ConfirmDialog({ title, children, confirmLabel, destructive = false, onC
2725
2915
  setBusy(false);
2726
2916
  }
2727
2917
  };
2728
- return /* @__PURE__ */ jsx39(
2918
+ return /* @__PURE__ */ jsx42(
2729
2919
  DialogShell,
2730
2920
  {
2731
2921
  alert: true,
2732
2922
  title,
2733
2923
  onClose,
2734
- footer: /* @__PURE__ */ jsxs28(Fragment9, { children: [
2735
- /* @__PURE__ */ jsx39(Button, { variant: "muted", onClick: onClose, disabled: busy, children: "Cancel" }),
2736
- /* @__PURE__ */ jsx39(Button, { variant: destructive ? "destructive" : "primary", onClick: () => void confirm(), disabled: busy, children: confirmLabel })
2924
+ footer: /* @__PURE__ */ jsxs30(Fragment10, { children: [
2925
+ /* @__PURE__ */ jsx42(Button, { variant: "muted", onClick: onClose, disabled: busy, children: "Cancel" }),
2926
+ /* @__PURE__ */ jsx42(Button, { variant: destructive ? "destructive" : "primary", onClick: () => void confirm(), disabled: busy, children: confirmLabel })
2737
2927
  ] }),
2738
- children: /* @__PURE__ */ jsx39("div", { className: "flex flex-col gap-3 text-body-2 text-text-primary", children })
2928
+ children: /* @__PURE__ */ jsx42("div", { className: "flex flex-col gap-3 text-body-2 text-text-primary", children })
2739
2929
  }
2740
2930
  );
2741
2931
  }
2742
2932
 
2743
2933
  // src/EditableText.tsx
2744
- import { useEffect as useEffect4, useRef as useRef8, useState as useState6 } from "react";
2934
+ import { useEffect as useEffect5, useRef as useRef9, useState as useState7 } from "react";
2745
2935
  import { Field as BaseField4 } from "@base-ui/react/field";
2746
2936
  import { Input as Input2 } from "@base-ui/react/input";
2747
- import { jsx as jsx40 } from "react/jsx-runtime";
2937
+ import { jsx as jsx43 } from "react/jsx-runtime";
2748
2938
  function EditableText({ value, display, displayNode, placeholder, onCommit, multiline = false, className, label, readOnly = false }) {
2749
- const [editing, setEditing] = useState6(false);
2750
- const [draft, setDraft] = useState6(value);
2751
- const [busy, setBusy] = useState6(false);
2752
- const fieldRef = useRef8(null);
2753
- useEffect4(() => {
2939
+ const [editing, setEditing] = useState7(false);
2940
+ const [draft, setDraft] = useState7(value);
2941
+ const [busy, setBusy] = useState7(false);
2942
+ const fieldRef = useRef9(null);
2943
+ useEffect5(() => {
2754
2944
  if (editing) {
2755
2945
  fieldRef.current?.focus();
2756
2946
  fieldRef.current?.select();
@@ -2802,7 +2992,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
2802
2992
  written and never read. Read-only, this is a line of text: whatever
2803
2993
  names the region around it (a `Field`, a `Property`) names this too.
2804
2994
  */
2805
- /* @__PURE__ */ jsx40(
2995
+ /* @__PURE__ */ jsx43(
2806
2996
  "div",
2807
2997
  {
2808
2998
  className: cn("w-full px-2 py-1", multiline && !displayNode && "whitespace-pre-wrap", display ?? value ? "text-text-primary" : "text-text-muted", className),
@@ -2812,11 +3002,11 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
2812
3002
  );
2813
3003
  }
2814
3004
  if (editing) {
2815
- return multiline ? /* @__PURE__ */ jsx40(
3005
+ return multiline ? /* @__PURE__ */ jsx43(
2816
3006
  BaseField4.Control,
2817
3007
  {
2818
3008
  ref: fieldRef,
2819
- render: /* @__PURE__ */ jsx40("textarea", { rows: 4 }),
3009
+ render: /* @__PURE__ */ jsx43("textarea", { rows: 4 }),
2820
3010
  "aria-label": label,
2821
3011
  value: draft,
2822
3012
  disabled: busy,
@@ -2825,7 +3015,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
2825
3015
  onBlur: () => void commit(),
2826
3016
  className: fieldClass
2827
3017
  }
2828
- ) : /* @__PURE__ */ jsx40(
3018
+ ) : /* @__PURE__ */ jsx43(
2829
3019
  Input2,
2830
3020
  {
2831
3021
  ref: fieldRef,
@@ -2839,7 +3029,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
2839
3029
  }
2840
3030
  );
2841
3031
  }
2842
- return /* @__PURE__ */ jsx40(
3032
+ return /* @__PURE__ */ jsx43(
2843
3033
  "button",
2844
3034
  {
2845
3035
  type: "button",
@@ -2859,7 +3049,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
2859
3049
  // src/ErrorBoundary.tsx
2860
3050
  import { Component } from "react";
2861
3051
  import { IconAlertTriangle as IconAlertTriangle2 } from "@tabler/icons-react";
2862
- import { jsx as jsx41 } from "react/jsx-runtime";
3052
+ import { jsx as jsx44 } from "react/jsx-runtime";
2863
3053
  var ErrorBoundary = class extends Component {
2864
3054
  state = { hasError: false };
2865
3055
  static getDerivedStateFromError() {
@@ -2870,22 +3060,22 @@ var ErrorBoundary = class extends Component {
2870
3060
  }
2871
3061
  render() {
2872
3062
  if (!this.state.hasError) return this.props.children;
2873
- const message = /* @__PURE__ */ jsx41(
3063
+ const message = /* @__PURE__ */ jsx44(
2874
3064
  EmptyState,
2875
3065
  {
2876
- icon: /* @__PURE__ */ jsx41(IconAlertTriangle2, { size: 16, stroke: 1.5 }),
3066
+ icon: /* @__PURE__ */ jsx44(IconAlertTriangle2, { size: 16, stroke: 1.5 }),
2877
3067
  message: `Something went wrong${this.props.label ? ` in the ${this.props.label}` : ""}. Your data is safe \u2014 try again.`,
2878
3068
  action: { label: "Try again", onClick: () => this.setState({ hasError: false }) }
2879
3069
  }
2880
3070
  );
2881
3071
  if (this.props.frame) return this.props.frame(message);
2882
- return this.props.fallbackClassName ? /* @__PURE__ */ jsx41("div", { className: this.props.fallbackClassName, children: message }) : message;
3072
+ return this.props.fallbackClassName ? /* @__PURE__ */ jsx44("div", { className: this.props.fallbackClassName, children: message }) : message;
2883
3073
  }
2884
3074
  };
2885
3075
 
2886
3076
  // src/ProgressBar.tsx
2887
3077
  import { Progress } from "@base-ui/react/progress";
2888
- import { jsx as jsx42 } from "react/jsx-runtime";
3078
+ import { jsx as jsx45 } from "react/jsx-runtime";
2889
3079
  var TRACK_CLASSES = {
2890
3080
  default: "h-1.5 w-full overflow-hidden rounded-full bg-bg-inset",
2891
3081
  // 4px, Katerina's ruling of 14 September; Peek's own bar is 3px until it takes this one.
@@ -2898,17 +3088,17 @@ var INDICATOR_CLASSES = {
2898
3088
  function ProgressBar({ value, max, label, variant = "default", className }) {
2899
3089
  return (
2900
3090
  // `max={0}` needs no guard: Base UI reads the 0/0 share as an empty bar.
2901
- /* @__PURE__ */ jsx42(Progress.Root, { value, max, "aria-label": label, className, children: /* @__PURE__ */ jsx42(Progress.Track, { className: TRACK_CLASSES[variant], children: /* @__PURE__ */ jsx42(Progress.Indicator, { className: INDICATOR_CLASSES[variant] }) }) })
3091
+ /* @__PURE__ */ jsx45(Progress.Root, { value, max, "aria-label": label, className, children: /* @__PURE__ */ jsx45(Progress.Track, { className: TRACK_CLASSES[variant], children: /* @__PURE__ */ jsx45(Progress.Indicator, { className: INDICATOR_CLASSES[variant] }) }) })
2902
3092
  );
2903
3093
  }
2904
3094
 
2905
3095
  // src/Breadcrumb.tsx
2906
- import { Fragment as Fragment10, useCallback as useCallback3, useLayoutEffect as useLayoutEffect4, useRef as useRef9, useState as useState7 } from "react";
2907
- import { jsx as jsx43, jsxs as jsxs29 } from "react/jsx-runtime";
3096
+ import { Fragment as Fragment11, useCallback as useCallback3, useLayoutEffect as useLayoutEffect4, useRef as useRef10, useState as useState8 } from "react";
3097
+ import { jsx as jsx46, jsxs as jsxs31 } from "react/jsx-runtime";
2908
3098
  function Breadcrumb({ items, className }) {
2909
- const navRef = useRef9(null);
2910
- const labelRefs = useRef9([]);
2911
- const [truncated, setTruncated] = useState7(/* @__PURE__ */ new Set());
3099
+ const navRef = useRef10(null);
3100
+ const labelRefs = useRef10([]);
3101
+ const [truncated, setTruncated] = useState8(/* @__PURE__ */ new Set());
2912
3102
  const measure = useCallback3(() => {
2913
3103
  const next = /* @__PURE__ */ new Set();
2914
3104
  labelRefs.current.forEach((el, index) => {
@@ -2924,7 +3114,7 @@ function Breadcrumb({ items, className }) {
2924
3114
  observer.observe(nav);
2925
3115
  return () => observer.disconnect();
2926
3116
  }, [measure, items]);
2927
- return /* @__PURE__ */ jsx43("nav", { ref: navRef, "aria-label": "Breadcrumb", className: cn("flex min-w-0 items-center gap-1.5 text-body-2", className), children: items.map((item, index) => {
3117
+ return /* @__PURE__ */ jsx46("nav", { ref: navRef, "aria-label": "Breadcrumb", className: cn("flex min-w-0 items-center gap-1.5 text-body-2", className), children: items.map((item, index) => {
2928
3118
  const last = index === items.length - 1;
2929
3119
  const tone = item.muted || last && item.mono ? "text-text-muted" : last ? "text-text-primary" : "text-text-secondary";
2930
3120
  const text = cn(
@@ -2945,34 +3135,34 @@ function Breadcrumb({ items, className }) {
2945
3135
  // on a box around it, which the link takes them from, rather than
2946
3136
  // pushed into it (UIG-9); the link is still the one element that
2947
3137
  // truncates and is measured.
2948
- /* @__PURE__ */ jsx43("span", { className: cn("flex min-w-0", item.mono && "shrink-0 font-mono text-caption", tone, "hover:text-text-primary"), children: /* @__PURE__ */ jsx43(Link, { ref: setLabelRef, variant: "plain", truncate: true, href: item.href, onClick: item.onClick, children: item.label }) })
2949
- ) : /* @__PURE__ */ jsx43("span", { ref: setLabelRef, className: text, "aria-current": last ? "page" : void 0, children: item.label });
2950
- return /* @__PURE__ */ jsxs29(Fragment10, { children: [
2951
- index > 0 && /* @__PURE__ */ jsx43("span", { "aria-hidden": "true", className: "shrink-0 text-text-muted", children: "/" }),
2952
- item.icon && /* @__PURE__ */ jsx43("span", { "aria-hidden": "true", className: cn("flex shrink-0", tone), children: item.icon }),
3138
+ /* @__PURE__ */ jsx46("span", { className: cn("flex min-w-0", item.mono && "shrink-0 font-mono text-caption", tone, "hover:text-text-primary"), children: /* @__PURE__ */ jsx46(Link, { ref: setLabelRef, variant: "plain", truncate: true, href: item.href, onClick: item.onClick, children: item.label }) })
3139
+ ) : /* @__PURE__ */ jsx46("span", { ref: setLabelRef, className: text, "aria-current": last ? "page" : void 0, children: item.label });
3140
+ return /* @__PURE__ */ jsxs31(Fragment11, { children: [
3141
+ index > 0 && /* @__PURE__ */ jsx46("span", { "aria-hidden": "true", className: "shrink-0 text-text-muted", children: "/" }),
3142
+ item.icon && /* @__PURE__ */ jsx46("span", { "aria-hidden": "true", className: cn("flex shrink-0", tone), children: item.icon }),
2953
3143
  truncated.has(index) ? (
2954
3144
  // `min-w-0 shrink` undoes the wrapper's own shrink-0 — the crumb
2955
3145
  // must keep truncating inside it, or wrapping it would widen the
2956
3146
  // trail and the tooltip would never be needed again.
2957
- /* @__PURE__ */ jsx43(WithTooltip, { label: item.label, wrapperClassName: "min-w-0 shrink", children: crumb })
3147
+ /* @__PURE__ */ jsx46(WithTooltip, { label: item.label, wrapperClassName: "min-w-0 shrink", children: crumb })
2958
3148
  ) : crumb
2959
3149
  ] }, `${item.label}-${index}`);
2960
3150
  }) });
2961
3151
  }
2962
3152
 
2963
3153
  // src/NavItem.tsx
2964
- import { useId, useState as useState8 } from "react";
3154
+ import { useId as useId2, useState as useState9 } from "react";
2965
3155
  import { Collapsible } from "@base-ui/react/collapsible";
2966
3156
  import { IconAlertSquareRounded, IconChevronRight as IconChevronRight2, IconDotsVertical } from "@tabler/icons-react";
2967
3157
 
2968
3158
  // src/UnreadDot.tsx
2969
- import { jsx as jsx44 } from "react/jsx-runtime";
3159
+ import { jsx as jsx47 } from "react/jsx-runtime";
2970
3160
  function UnreadDot({ className }) {
2971
- return /* @__PURE__ */ jsx44("div", { className: cn("flex h-6 w-6 shrink-0 items-center justify-center", className), "data-unread": true, children: /* @__PURE__ */ jsx44("div", { className: "h-1.5 w-1.5 rounded-full bg-accent-primary" }) });
3161
+ return /* @__PURE__ */ jsx47("div", { className: cn("flex h-6 w-6 shrink-0 items-center justify-center", className), "data-unread": true, children: /* @__PURE__ */ jsx47("div", { className: "h-1.5 w-1.5 rounded-full bg-accent-primary" }) });
2972
3162
  }
2973
3163
 
2974
3164
  // src/NavItem.tsx
2975
- import { jsx as jsx45, jsxs as jsxs30 } from "react/jsx-runtime";
3165
+ import { jsx as jsx48, jsxs as jsxs32 } from "react/jsx-runtime";
2976
3166
  function NavItem({
2977
3167
  label,
2978
3168
  href,
@@ -2990,10 +3180,12 @@ function NavItem({
2990
3180
  open: openProp,
2991
3181
  onOpenChange,
2992
3182
  className,
3183
+ onClick,
2993
3184
  ...props
2994
3185
  }) {
2995
- const [openState, setOpenState] = useState8(defaultOpen);
2996
- const panelId = useId();
3186
+ const inApp = useInAppClick(href, onClick);
3187
+ const [openState, setOpenState] = useState9(defaultOpen);
3188
+ const panelId = useId2();
2997
3189
  const hasRows = children != null && children !== false;
2998
3190
  const open = openProp ?? openState;
2999
3191
  const setOpen = (next) => {
@@ -3001,9 +3193,9 @@ function NavItem({
3001
3193
  onOpenChange?.(next);
3002
3194
  };
3003
3195
  const besides = menu != null || hasRows;
3004
- const mark = unread ? urgent ? /* @__PURE__ */ jsx45(UrgentMark, {}) : /* @__PURE__ */ jsx45(UnreadDot, {}) : null;
3196
+ const mark = unread ? urgent ? /* @__PURE__ */ jsx48(UrgentMark, {}) : /* @__PURE__ */ jsx48(UnreadDot, {}) : null;
3005
3197
  const stepsAside = menu != null && "transition-opacity group-hover/nav:opacity-0 group-has-[:focus-visible]/nav:opacity-0 group-has-[[data-nav-menu]_[aria-expanded=true]]/nav:opacity-0 [@media(hover:none)]:opacity-0";
3006
- const row = /* @__PURE__ */ jsxs30(
3198
+ const row = /* @__PURE__ */ jsxs32(
3007
3199
  "a",
3008
3200
  {
3009
3201
  href,
@@ -3023,8 +3215,9 @@ function NavItem({
3023
3215
  className
3024
3216
  ),
3025
3217
  ...props,
3218
+ onClick: inApp,
3026
3219
  children: [
3027
- (icon || hasRows) && /* @__PURE__ */ jsx45(
3220
+ (icon || hasRows) && /* @__PURE__ */ jsx48(
3028
3221
  "span",
3029
3222
  {
3030
3223
  className: cn(
@@ -3035,10 +3228,10 @@ function NavItem({
3035
3228
  children: icon
3036
3229
  }
3037
3230
  ),
3038
- /* @__PURE__ */ jsx45("span", { className: cn("flex-1 truncate", unread && "font-medium"), children: label }),
3231
+ /* @__PURE__ */ jsx48("span", { className: cn("flex-1 truncate", unread && "font-medium"), children: label }),
3039
3232
  hint != null && // Takes room only while it shows, so the label gives way to it.
3040
- /* @__PURE__ */ jsx45("span", { className: "hidden shrink-0 items-center group-hover/nav:flex group-has-[:focus-visible]/nav:flex", children: hint }),
3041
- count ? /* @__PURE__ */ jsx45(WithTooltip, { label: countLabel ?? `${count} open`, children: /* @__PURE__ */ jsx45(
3233
+ /* @__PURE__ */ jsx48("span", { className: "hidden shrink-0 items-center group-hover/nav:flex group-has-[:focus-visible]/nav:flex", children: hint }),
3234
+ count ? /* @__PURE__ */ jsx48(WithTooltip, { label: countLabel ?? `${count} open`, children: /* @__PURE__ */ jsx48(
3042
3235
  "span",
3043
3236
  {
3044
3237
  className: cn(
@@ -3054,7 +3247,7 @@ function NavItem({
3054
3247
  // `-mr-1`: the 24px slot's dot then sits on the axis of a count and
3055
3248
  // of the ⋮ (8px from the edge to the 16px box), one column with a
3056
3249
  // folder heading's dot and ⋮ (Katerina, 5 October).
3057
- /* @__PURE__ */ jsx45("span", { className: cn("-mr-1 flex shrink-0", stepsAside), children: mark })
3250
+ /* @__PURE__ */ jsx48("span", { className: cn("-mr-1 flex shrink-0", stepsAside), children: mark })
3058
3251
  ) : menu != null && !count ? (
3059
3252
  // Nothing at the right, but a menu: no room is kept at rest, so the
3060
3253
  // label has the row's whole width; while the ⋮ shows, its 24px slot
@@ -3062,18 +3255,18 @@ function NavItem({
3062
3255
  // `-mr-1`: the ⋮ sits at `right-1`, 4px into the row's padding, so the
3063
3256
  // slot does too — at the padding's edge it kept 4px the ⋮ never
3064
3257
  // covers, and the label stopped 12px short of the button, not 8.
3065
- /* @__PURE__ */ jsx45("span", { "aria-hidden": "true", className: "-mr-1 hidden w-6 shrink-0 group-hover/nav:block group-has-[:focus-visible]/nav:block group-has-[[data-nav-menu]_[aria-expanded=true]]/nav:block [@media(hover:none)]:block" })
3258
+ /* @__PURE__ */ jsx48("span", { "aria-hidden": "true", className: "-mr-1 hidden w-6 shrink-0 group-hover/nav:block group-has-[:focus-visible]/nav:block group-has-[[data-nav-menu]_[aria-expanded=true]]/nav:block [@media(hover:none)]:block" })
3066
3259
  ) : null
3067
3260
  ]
3068
3261
  }
3069
3262
  );
3070
3263
  if (!besides && hint == null) return row;
3071
3264
  const name = menuLabel ?? `More options for ${label}`;
3072
- const line = /* @__PURE__ */ jsxs30("div", { className: "group/nav relative shrink-0", children: [
3265
+ const line = /* @__PURE__ */ jsxs32("div", { className: "group/nav relative shrink-0", children: [
3073
3266
  row,
3074
3267
  hasRows && // `left-1`: the 24px button's 16px arrow then sits where the icon
3075
3268
  // sits (the row's px-2), so the icon turns into the arrow in place.
3076
- /* @__PURE__ */ jsx45("div", { className: "absolute inset-y-0 left-1 flex items-center opacity-0 transition-opacity group-hover/nav:opacity-100 group-has-[:focus-visible]/nav:opacity-100", children: /* @__PURE__ */ jsx45(
3269
+ /* @__PURE__ */ jsx48("div", { className: "absolute inset-y-0 left-1 flex items-center opacity-0 transition-opacity group-hover/nav:opacity-100 group-has-[:focus-visible]/nav:opacity-100", children: /* @__PURE__ */ jsx48(
3077
3270
  IconButton,
3078
3271
  {
3079
3272
  tooltip: open ? "Collapse" : "Expand",
@@ -3081,7 +3274,7 @@ function NavItem({
3081
3274
  "aria-expanded": open,
3082
3275
  "aria-controls": panelId,
3083
3276
  onClick: () => setOpen(!open),
3084
- children: /* @__PURE__ */ jsx45(IconChevronRight2, { size: 16, stroke: 1.5, className: cn("transition-transform duration-150", open && "rotate-90") })
3277
+ children: /* @__PURE__ */ jsx48(IconChevronRight2, { size: 16, stroke: 1.5, className: cn("transition-transform duration-150", open && "rotate-90") })
3085
3278
  }
3086
3279
  ) }),
3087
3280
  menu != null && // `right-1`: the 24px button's 16px icon ends 8px from the row's
@@ -3092,61 +3285,61 @@ function NavItem({
3092
3285
  // right of the slot's centre.
3093
3286
  // On a screen with no hover it always shows: nothing there can point
3094
3287
  // at the row, and the menu has no other way in.
3095
- /* @__PURE__ */ jsx45("div", { "data-nav-menu": true, className: cn("absolute inset-y-0 right-1 flex items-center", "opacity-0 transition-opacity group-hover/nav:opacity-100 group-has-[:focus-visible]/nav:opacity-100 has-[[aria-expanded=true]]:opacity-100 [@media(hover:none)]:opacity-100"), children: /* @__PURE__ */ jsx45(
3288
+ /* @__PURE__ */ jsx48("div", { "data-nav-menu": true, className: cn("absolute inset-y-0 right-1 flex items-center", "opacity-0 transition-opacity group-hover/nav:opacity-100 group-has-[:focus-visible]/nav:opacity-100 has-[[aria-expanded=true]]:opacity-100 [@media(hover:none)]:opacity-100"), children: /* @__PURE__ */ jsx48(
3096
3289
  Menu,
3097
3290
  {
3098
3291
  align: "right",
3099
- trigger: /* @__PURE__ */ jsx45(IconButton, { tooltip: "More options", "aria-label": name, children: /* @__PURE__ */ jsx45(IconDotsVertical, { size: 16, stroke: 1.5 }) }),
3292
+ trigger: /* @__PURE__ */ jsx48(IconButton, { tooltip: "More options", "aria-label": name, children: /* @__PURE__ */ jsx48(IconDotsVertical, { size: 16, stroke: 1.5 }) }),
3100
3293
  children: menu
3101
3294
  }
3102
3295
  ) })
3103
3296
  ] });
3104
3297
  if (!hasRows) return line;
3105
- return /* @__PURE__ */ jsxs30(Collapsible.Root, { open, onOpenChange: setOpen, className: "flex shrink-0 flex-col", children: [
3298
+ return /* @__PURE__ */ jsxs32(Collapsible.Root, { open, onOpenChange: setOpen, className: "flex shrink-0 flex-col", children: [
3106
3299
  line,
3107
- /* @__PURE__ */ jsx45(
3300
+ /* @__PURE__ */ jsx48(
3108
3301
  Collapsible.Panel,
3109
3302
  {
3110
3303
  id: panelId,
3111
3304
  hiddenUntilFound: true,
3112
3305
  className: COLLAPSIBLE_PANEL_CLASSES,
3113
- children: /* @__PURE__ */ jsx45("div", { className: "flex flex-col gap-0.5 pt-0.5 pl-6", children })
3306
+ children: /* @__PURE__ */ jsx48("div", { className: "flex flex-col gap-0.5 pt-0.5 pl-6", children })
3114
3307
  }
3115
3308
  )
3116
3309
  ] });
3117
3310
  }
3118
3311
  function UrgentMark() {
3119
- return /* @__PURE__ */ jsx45("div", { className: "flex h-6 w-6 shrink-0 items-center justify-center", "data-urgent": true, children: /* @__PURE__ */ jsx45("div", { className: "flex items-center rounded-full bg-warning-muted p-0.5 signal:shadow-glow-warning", children: /* @__PURE__ */ jsx45(IconAlertSquareRounded, { size: 12, stroke: 2.5, className: "text-warning-default" }) }) });
3312
+ return /* @__PURE__ */ jsx48("div", { className: "flex h-6 w-6 shrink-0 items-center justify-center", "data-urgent": true, children: /* @__PURE__ */ jsx48("div", { className: "flex items-center rounded-full bg-warning-muted p-0.5 signal:shadow-glow-warning", children: /* @__PURE__ */ jsx48(IconAlertSquareRounded, { size: 12, stroke: 2.5, className: "text-warning-default" }) }) });
3120
3313
  }
3121
3314
 
3122
3315
  // src/NavTree.tsx
3123
- import { useEffect as useEffect5, useRef as useRef10 } from "react";
3316
+ import { useEffect as useEffect6, useRef as useRef11 } from "react";
3124
3317
 
3125
3318
  // src/CollapsibleSection.tsx
3126
- import { useState as useState9 } from "react";
3319
+ import { useState as useState10 } from "react";
3127
3320
  import { Collapsible as Collapsible2 } from "@base-ui/react/collapsible";
3128
3321
 
3129
3322
  // src/SectionHeader.tsx
3130
3323
  import { IconChevronRight as IconChevronRight3, IconDotsVertical as IconDotsVertical2 } from "@tabler/icons-react";
3131
3324
  import { useRender } from "@base-ui/react/use-render";
3132
- import { Fragment as Fragment11, jsx as jsx46, jsxs as jsxs31 } from "react/jsx-runtime";
3325
+ import { Fragment as Fragment12, jsx as jsx49, jsxs as jsxs33 } from "react/jsx-runtime";
3133
3326
  function SectionHeader({ title, chevron = false, icon, isExpanded = true, onToggle, trailing, count, actions, menu, menuLabel, showActions = "hover", hover = "fill", look = "heading", render, className }) {
3134
3327
  const row = look === "row";
3135
3328
  const acts = actions && actions.length > 0 || menu != null;
3136
3329
  const trailingClasses = !acts ? "has-[[data-unread]]:-mr-1" : showActions === "hover" && "has-[[data-unread]]:pointer-events-none has-[[data-unread]]:absolute has-[[data-unread]]:inset-y-0 has-[[data-unread]]:right-1 has-[[data-unread]]:w-6 has-[[data-unread]]:justify-center has-[[data-unread]]:transition-opacity group-hover:has-[[data-unread]]:opacity-0 group-has-[:focus-visible]:has-[[data-unread]]:opacity-0 group-has-[[data-section-menu]_[aria-expanded=true]]:has-[[data-unread]]:opacity-0 [@media(hover:none)]:has-[[data-unread]]:opacity-0";
3137
3330
  const reveal = showActions === "hover" && "opacity-0 transition-opacity group-hover:opacity-100 group-has-[:focus-visible]:opacity-100 has-[[aria-expanded=true]]:opacity-100 [@media(hover:none)]:opacity-100";
3138
3331
  const titleElement = useRender({
3139
- render: render ?? (chevron ? /* @__PURE__ */ jsx46("button", { type: "button", onClick: onToggle, "aria-expanded": isExpanded }) : /* @__PURE__ */ jsx46("span", {})),
3332
+ render: render ?? (chevron ? /* @__PURE__ */ jsx49("button", { type: "button", onClick: onToggle, "aria-expanded": isExpanded }) : /* @__PURE__ */ jsx49("span", {})),
3140
3333
  props: {
3141
3334
  // `text-left`: a button centres its text. `h-full` and `flex-1`: the
3142
3335
  // whole row up to the actions is the hit target, as it was when the
3143
3336
  // row itself carried the click.
3144
3337
  // An icon is a row's: NavItem's 8px after it.
3145
3338
  className: cn("flex h-full min-w-0 flex-1 items-center text-left", row || chevron || icon != null ? "gap-2" : "gap-1"),
3146
- children: /* @__PURE__ */ jsxs31(Fragment11, { children: [
3147
- icon != null ? /* @__PURE__ */ jsxs31("span", { className: "relative flex size-4 shrink-0 items-center justify-center text-text-secondary", children: [
3148
- /* @__PURE__ */ jsx46("span", { className: cn("flex", chevron && "transition-opacity group-hover:opacity-0 group-has-[:focus-visible]:opacity-0"), children: icon }),
3149
- chevron && /* @__PURE__ */ jsx46(
3339
+ children: /* @__PURE__ */ jsxs33(Fragment12, { children: [
3340
+ icon != null ? /* @__PURE__ */ jsxs33("span", { className: "relative flex size-4 shrink-0 items-center justify-center text-text-secondary", children: [
3341
+ /* @__PURE__ */ jsx49("span", { className: cn("flex", chevron && "transition-opacity group-hover:opacity-0 group-has-[:focus-visible]:opacity-0"), children: icon }),
3342
+ chevron && /* @__PURE__ */ jsx49(
3150
3343
  IconChevronRight3,
3151
3344
  {
3152
3345
  size: 16,
@@ -3154,7 +3347,7 @@ function SectionHeader({ title, chevron = false, icon, isExpanded = true, onTogg
3154
3347
  className: cn("absolute opacity-0 transition-[opacity,transform] duration-150 group-hover:opacity-100 group-has-[:focus-visible]:opacity-100", isExpanded && "rotate-90")
3155
3348
  }
3156
3349
  )
3157
- ] }) : chevron && /* @__PURE__ */ jsx46(
3350
+ ] }) : chevron && /* @__PURE__ */ jsx49(
3158
3351
  IconChevronRight3,
3159
3352
  {
3160
3353
  size: 16,
@@ -3162,15 +3355,15 @@ function SectionHeader({ title, chevron = false, icon, isExpanded = true, onTogg
3162
3355
  className: cn("shrink-0 transition-transform duration-150", !row && "text-text-secondary", isExpanded && "rotate-90")
3163
3356
  }
3164
3357
  ),
3165
- look === "quiet" ? /* @__PURE__ */ jsx46("span", { className: "min-w-0 truncate text-caption text-text-muted", children: title }) : row ? (
3358
+ look === "quiet" ? /* @__PURE__ */ jsx49("span", { className: "min-w-0 truncate text-caption text-text-muted", children: title }) : row ? (
3166
3359
  // A row's words: NavItem's size and colour, brightening under the pointer with the row.
3167
- /* @__PURE__ */ jsx46("span", { className: "min-w-0 flex-1 truncate text-body-2", children: title })
3168
- ) : /* @__PURE__ */ jsx46(SectionLabel, { folds: chevron, children: title }),
3169
- count != null && /* @__PURE__ */ jsx46("span", { className: cn("ml-1 shrink-0", COUNT_TEXT_CLASSES), children: count })
3360
+ /* @__PURE__ */ jsx49("span", { className: "min-w-0 flex-1 truncate text-body-2", children: title })
3361
+ ) : /* @__PURE__ */ jsx49(SectionLabel, { folds: chevron, children: title }),
3362
+ count != null && /* @__PURE__ */ jsx49("span", { className: cn("ml-1 shrink-0", COUNT_TEXT_CLASSES), children: count })
3170
3363
  ] })
3171
3364
  }
3172
3365
  });
3173
- return /* @__PURE__ */ jsxs31(
3366
+ return /* @__PURE__ */ jsxs33(
3174
3367
  "div",
3175
3368
  {
3176
3369
  className: cn(
@@ -3191,18 +3384,18 @@ function SectionHeader({ title, chevron = false, icon, isExpanded = true, onTogg
3191
3384
  ),
3192
3385
  children: [
3193
3386
  titleElement,
3194
- trailing != null && /* @__PURE__ */ jsx46("div", { className: cn("flex shrink-0 items-center", trailingClasses), children: trailing }),
3195
- acts && /* @__PURE__ */ jsx46(
3387
+ trailing != null && /* @__PURE__ */ jsx49("div", { className: cn("flex shrink-0 items-center", trailingClasses), children: trailing }),
3388
+ acts && /* @__PURE__ */ jsx49(
3196
3389
  "div",
3197
3390
  {
3198
3391
  className: "-mr-1 flex shrink-0 items-center",
3199
- children: /* @__PURE__ */ jsxs31("div", { className: cn("flex items-center gap-1", reveal), children: [
3200
- actions?.map((action) => /* @__PURE__ */ jsx46(IconButton, { tooltip: action.tooltip, "aria-label": action.tooltip, onClick: action.onClick, children: action.icon }, action.tooltip)),
3201
- menu != null && /* @__PURE__ */ jsx46("div", { "data-section-menu": true, className: "flex items-center", children: /* @__PURE__ */ jsx46(
3392
+ children: /* @__PURE__ */ jsxs33("div", { className: cn("flex items-center gap-1", reveal), children: [
3393
+ actions?.map((action) => /* @__PURE__ */ jsx49(IconButton, { tooltip: action.tooltip, "aria-label": action.tooltip, onClick: action.onClick, children: action.icon }, action.tooltip)),
3394
+ menu != null && /* @__PURE__ */ jsx49("div", { "data-section-menu": true, className: "flex items-center", children: /* @__PURE__ */ jsx49(
3202
3395
  Menu,
3203
3396
  {
3204
3397
  align: "right",
3205
- trigger: /* @__PURE__ */ jsx46(IconButton, { tooltip: "More options", "aria-label": menuLabel ?? `More options for ${title}`, children: /* @__PURE__ */ jsx46(IconDotsVertical2, { size: 16, stroke: 1.5 }) }),
3398
+ trigger: /* @__PURE__ */ jsx49(IconButton, { tooltip: "More options", "aria-label": menuLabel ?? `More options for ${title}`, children: /* @__PURE__ */ jsx49(IconDotsVertical2, { size: 16, stroke: 1.5 }) }),
3206
3399
  children: menu
3207
3400
  }
3208
3401
  ) })
@@ -3215,7 +3408,7 @@ function SectionHeader({ title, chevron = false, icon, isExpanded = true, onTogg
3215
3408
  }
3216
3409
 
3217
3410
  // src/CollapsibleSection.tsx
3218
- import { jsx as jsx47, jsxs as jsxs32 } from "react/jsx-runtime";
3411
+ import { jsx as jsx50, jsxs as jsxs34 } from "react/jsx-runtime";
3219
3412
  var OPEN = "open";
3220
3413
  var CLOSED = "closed";
3221
3414
  function readStored(key) {
@@ -3235,38 +3428,38 @@ function writeStored(key, open) {
3235
3428
  }
3236
3429
  }
3237
3430
  function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenChange, storageKey, icon, trailing, actions, menu, menuLabel, showActions, look = "heading", indent = false, children, className, contentClassName }) {
3238
- const [openState, setOpenState] = useState9(() => readStored(storageKey) ?? defaultOpen);
3431
+ const [openState, setOpenState] = useState10(() => readStored(storageKey) ?? defaultOpen);
3239
3432
  const open = openProp ?? openState;
3240
3433
  const setOpen = (next) => {
3241
3434
  setOpenState(next);
3242
3435
  writeStored(storageKey, next);
3243
3436
  onOpenChange?.(next);
3244
3437
  };
3245
- return /* @__PURE__ */ jsxs32(Collapsible2.Root, { open, onOpenChange: setOpen, className: cn("flex flex-col", className), children: [
3246
- /* @__PURE__ */ jsx47(SectionHeader, { title, chevron: true, icon, isExpanded: open, trailing, actions, menu, menuLabel, showActions, look, className: "shrink-0", render: /* @__PURE__ */ jsx47(Collapsible2.Trigger, {}) }),
3247
- /* @__PURE__ */ jsx47(
3438
+ return /* @__PURE__ */ jsxs34(Collapsible2.Root, { open, onOpenChange: setOpen, className: cn("flex flex-col", className), children: [
3439
+ /* @__PURE__ */ jsx50(SectionHeader, { title, chevron: true, icon, isExpanded: open, trailing, actions, menu, menuLabel, showActions, look, className: "shrink-0", render: /* @__PURE__ */ jsx50(Collapsible2.Trigger, {}) }),
3440
+ /* @__PURE__ */ jsx50(
3248
3441
  Collapsible2.Panel,
3249
3442
  {
3250
3443
  hiddenUntilFound: true,
3251
3444
  className: COLLAPSIBLE_PANEL_CLASSES,
3252
- children: /* @__PURE__ */ jsx47("div", { className: cn("flex flex-col pt-0.5", (look === "row" || indent) && "pl-6", contentClassName), children })
3445
+ children: /* @__PURE__ */ jsx50("div", { className: cn("flex flex-col pt-0.5", (look === "row" || indent) && "pl-6", contentClassName), children })
3253
3446
  }
3254
3447
  )
3255
3448
  ] });
3256
3449
  }
3257
3450
 
3258
3451
  // src/NavTree.tsx
3259
- import { Fragment as Fragment12, jsx as jsx48, jsxs as jsxs33 } from "react/jsx-runtime";
3452
+ import { Fragment as Fragment13, jsx as jsx51, jsxs as jsxs35 } from "react/jsx-runtime";
3260
3453
  var NAV_TREE_INTENT_MS = 150;
3261
3454
  function holds(nodes, id) {
3262
3455
  return !!nodes && id !== void 0 && nodes.some((node) => node.id === id || holds(node.children ?? null, id));
3263
3456
  }
3264
3457
  function Line({ message }) {
3265
- return /* @__PURE__ */ jsx48("div", { className: "px-2 py-1", children: /* @__PURE__ */ jsx48(EmptyState, { scope: "section", message }) });
3458
+ return /* @__PURE__ */ jsx51("div", { className: "px-2 py-1", children: /* @__PURE__ */ jsx51(EmptyState, { scope: "section", message }) });
3266
3459
  }
3267
3460
  function Row({ node, selected, onSelect }) {
3268
- const under = node.childrenMessage !== void 0 ? /* @__PURE__ */ jsx48(Line, { message: node.childrenMessage }) : node.children?.length ? node.children.map((child) => /* @__PURE__ */ jsx48(Row, { node: child, selected, onSelect }, child.id)) : node.children === null || node.hasChildren && node.children === void 0 ? /* @__PURE__ */ jsx48(SkeletonList, { rows: 2 }) : void 0;
3269
- return /* @__PURE__ */ jsx48(
3461
+ const under = node.childrenMessage !== void 0 ? /* @__PURE__ */ jsx51(Line, { message: node.childrenMessage }) : node.children?.length ? node.children.map((child) => /* @__PURE__ */ jsx51(Row, { node: child, selected, onSelect }, child.id)) : node.children === null || node.hasChildren && node.children === void 0 ? /* @__PURE__ */ jsx51(SkeletonList, { rows: 2 }) : void 0;
3462
+ return /* @__PURE__ */ jsx51(
3270
3463
  NavItem,
3271
3464
  {
3272
3465
  href: node.href,
@@ -3288,7 +3481,7 @@ function Row({ node, selected, onSelect }) {
3288
3481
  );
3289
3482
  }
3290
3483
  function Group({ group, selected, onSelect, storageKey }) {
3291
- return /* @__PURE__ */ jsx48(
3484
+ return /* @__PURE__ */ jsx51(
3292
3485
  NavTreeSection,
3293
3486
  {
3294
3487
  id: group.id,
@@ -3304,15 +3497,15 @@ function Group({ group, selected, onSelect, storageKey }) {
3304
3497
  onOpenChange: group.onOpenChange,
3305
3498
  storageKey: storageKey ? `${storageKey}.${group.id}` : void 0,
3306
3499
  onIntent: group.onIntent,
3307
- children: group.nodes?.map((node) => /* @__PURE__ */ jsx48(Row, { node, selected, onSelect }, node.id))
3500
+ children: group.nodes?.map((node) => /* @__PURE__ */ jsx51(Row, { node, selected, onSelect }, node.id))
3308
3501
  }
3309
3502
  );
3310
3503
  }
3311
3504
  function NavTreeSection({ id, title, message, loading = false, trailing, actions, menu, icon, defaultOpen = true, open, onOpenChange, storageKey, onIntent, children }) {
3312
- const timer = useRef10(void 0);
3313
- useEffect5(() => () => clearTimeout(timer.current), []);
3505
+ const timer = useRef11(void 0);
3506
+ useEffect6(() => () => clearTimeout(timer.current), []);
3314
3507
  const intent = onIntent;
3315
- return /* @__PURE__ */ jsx48(
3508
+ return /* @__PURE__ */ jsx51(
3316
3509
  "div",
3317
3510
  {
3318
3511
  className: "shrink-0 [&+&]:mt-1",
@@ -3323,7 +3516,7 @@ function NavTreeSection({ id, title, message, loading = false, trailing, actions
3323
3516
  } : void 0,
3324
3517
  onPointerLeave: intent ? () => clearTimeout(timer.current) : void 0,
3325
3518
  onFocus: intent,
3326
- children: /* @__PURE__ */ jsx48(
3519
+ children: /* @__PURE__ */ jsx51(
3327
3520
  CollapsibleSection,
3328
3521
  {
3329
3522
  title,
@@ -3338,35 +3531,35 @@ function NavTreeSection({ id, title, message, loading = false, trailing, actions
3338
3531
  icon,
3339
3532
  className: "shrink-0",
3340
3533
  contentClassName: "gap-0.5",
3341
- children: message !== void 0 ? /* @__PURE__ */ jsx48(Line, { message }) : loading ? /* @__PURE__ */ jsx48(SkeletonList, { rows: 3 }) : children
3534
+ children: message !== void 0 ? /* @__PURE__ */ jsx51(Line, { message }) : loading ? /* @__PURE__ */ jsx51(SkeletonList, { rows: 3 }) : children
3342
3535
  }
3343
3536
  )
3344
3537
  }
3345
3538
  );
3346
3539
  }
3347
3540
  function NavTree({ title, titleActions, groups, children, selected, onSelect, emptyMessage = "", storageKey }) {
3348
- return /* @__PURE__ */ jsxs33(Fragment12, { children: [
3349
- title && /* @__PURE__ */ jsx48(SectionHeader, { title, look: "quiet", showActions: "always", actions: titleActions, className: "mt-4 shrink-0" }),
3350
- groups === void 0 ? children : groups === null ? /* @__PURE__ */ jsx48(SkeletonList, { rows: 5 }) : groups.length === 0 ? (
3541
+ return /* @__PURE__ */ jsxs35(Fragment13, { children: [
3542
+ title && /* @__PURE__ */ jsx51(SectionHeader, { title, look: "quiet", showActions: "always", actions: titleActions, className: "mt-4 shrink-0" }),
3543
+ groups === void 0 ? children : groups === null ? /* @__PURE__ */ jsx51(SkeletonList, { rows: 5 }) : groups.length === 0 ? (
3351
3544
  // No words, no line: an app that says nothing when it has no groups.
3352
- emptyMessage ? /* @__PURE__ */ jsx48(Line, { message: emptyMessage }) : null
3353
- ) : groups.map((group) => /* @__PURE__ */ jsx48(Group, { group, selected, onSelect, storageKey }, group.id))
3545
+ emptyMessage ? /* @__PURE__ */ jsx51(Line, { message: emptyMessage }) : null
3546
+ ) : groups.map((group) => /* @__PURE__ */ jsx51(Group, { group, selected, onSelect, storageKey }, group.id))
3354
3547
  ] });
3355
3548
  }
3356
3549
 
3357
3550
  // src/Popover.tsx
3358
- import { useMemo as useMemo3 } from "react";
3551
+ import { useMemo as useMemo4 } from "react";
3359
3552
  import { Popover as BasePopover } from "@base-ui/react/popover";
3360
- import { jsx as jsx49, jsxs as jsxs34 } from "react/jsx-runtime";
3553
+ import { jsx as jsx52, jsxs as jsxs36 } from "react/jsx-runtime";
3361
3554
  var GAP5 = 4;
3362
3555
  var VIEWPORT_PAD5 = 8;
3363
3556
  function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpenChange, finalFocus, actionsRef, ariaLabel, children, className, contentClassName, maxHeight }) {
3364
- const anchorTarget = useMemo3(() => {
3557
+ const anchorTarget = useMemo4(() => {
3365
3558
  if (!anchor) return void 0;
3366
3559
  if (anchor instanceof Element) return anchor;
3367
3560
  return { getBoundingClientRect: () => anchor };
3368
3561
  }, [anchor]);
3369
- return /* @__PURE__ */ jsxs34(
3562
+ return /* @__PURE__ */ jsxs36(
3370
3563
  BasePopover.Root,
3371
3564
  {
3372
3565
  open,
@@ -3374,8 +3567,8 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
3374
3567
  actionsRef,
3375
3568
  modal: false,
3376
3569
  children: [
3377
- trigger && /* @__PURE__ */ jsx49(BasePopover.Trigger, { render: trigger, disabled: triggerDisabled(trigger) }),
3378
- /* @__PURE__ */ jsx49(BasePopover.Portal, { children: /* @__PURE__ */ jsx49(
3570
+ trigger && /* @__PURE__ */ jsx52(BasePopover.Trigger, { render: trigger, disabled: triggerDisabled(trigger) }),
3571
+ /* @__PURE__ */ jsx52(BasePopover.Portal, { children: /* @__PURE__ */ jsx52(
3379
3572
  BasePopover.Positioner,
3380
3573
  {
3381
3574
  anchor: anchorTarget,
@@ -3384,20 +3577,20 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
3384
3577
  sideOffset: GAP5,
3385
3578
  collisionPadding: VIEWPORT_PAD5,
3386
3579
  className: "z-50 data-[anchor-hidden]:hidden",
3387
- children: /* @__PURE__ */ jsx49(
3580
+ children: /* @__PURE__ */ jsx52(
3388
3581
  BasePopover.Popup,
3389
3582
  {
3390
3583
  "aria-label": ariaLabel,
3391
3584
  initialFocus: trigger ? void 0 : false,
3392
3585
  finalFocus,
3393
3586
  className: cn("min-w-[180px] outline-none p-0", className),
3394
- render: /* @__PURE__ */ jsx49(MenuPanel, {}),
3395
- children: /* @__PURE__ */ jsx49(
3587
+ render: /* @__PURE__ */ jsx52(MenuPanel, {}),
3588
+ children: /* @__PURE__ */ jsx52(
3396
3589
  ScrollArea,
3397
3590
  {
3398
3591
  viewportClassName: maxHeight ?? "max-h-[var(--available-height)]",
3399
3592
  contentClassName: cn("flex flex-col p-2", contentClassName),
3400
- children: /* @__PURE__ */ jsx49(DividerInPanel.Provider, { value: true, children })
3593
+ children: /* @__PURE__ */ jsx52(DividerInPanel.Provider, { value: true, children })
3401
3594
  }
3402
3595
  )
3403
3596
  }
@@ -3410,18 +3603,18 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
3410
3603
  }
3411
3604
 
3412
3605
  // src/SuggestionMenu.tsx
3413
- import { useCallback as useCallback4, useEffect as useEffect6, useId as useId2, useImperativeHandle, useMemo as useMemo4, useRef as useRef11, useState as useState10 } from "react";
3414
- import { jsx as jsx50, jsxs as jsxs35 } from "react/jsx-runtime";
3606
+ import { useCallback as useCallback4, useEffect as useEffect7, useId as useId3, useImperativeHandle, useMemo as useMemo5, useRef as useRef12, useState as useState11 } from "react";
3607
+ import { jsx as jsx53, jsxs as jsxs37 } from "react/jsx-runtime";
3415
3608
  function SuggestionMenu({ rect, editorElement, ariaLabel, width, maxHeight, sections, itemKey, row, onSelect, handle }) {
3416
- const shown = useMemo4(() => sections.filter((section) => section.items.length > 0), [sections]);
3417
- const items = useMemo4(() => shown.flatMap((section) => section.items), [shown]);
3609
+ const shown = useMemo5(() => sections.filter((section) => section.items.length > 0), [sections]);
3610
+ const items = useMemo5(() => shown.flatMap((section) => section.items), [shown]);
3418
3611
  const keys = items.map(itemKey).join("\n");
3419
- const [highlight, setHighlight] = useState10(0);
3420
- const base = useId2();
3612
+ const [highlight, setHighlight] = useState11(0);
3613
+ const base = useId3();
3421
3614
  const listboxId = `${base}-list`;
3422
- const chosen = useRef11(null);
3423
- useEffect6(() => void (chosen.current = highlight > 0 ? keys.split("\n")[highlight] ?? null : null), [highlight]);
3424
- useEffect6(() => {
3615
+ const chosen = useRef12(null);
3616
+ useEffect7(() => void (chosen.current = highlight > 0 ? keys.split("\n")[highlight] ?? null : null), [highlight]);
3617
+ useEffect7(() => {
3425
3618
  const at = chosen.current ? keys.split("\n").indexOf(chosen.current) : -1;
3426
3619
  setHighlight(at > 0 ? at : 0);
3427
3620
  }, [keys]);
@@ -3446,7 +3639,7 @@ function SuggestionMenu({ rect, editorElement, ariaLabel, width, maxHeight, sect
3446
3639
  }
3447
3640
  }), [items, highlight, onSelect]);
3448
3641
  const open = rect !== null && items.length > 0;
3449
- useEffect6(() => {
3642
+ useEffect7(() => {
3450
3643
  if (!editorElement || !open) return;
3451
3644
  editorElement.setAttribute("aria-autocomplete", "list");
3452
3645
  editorElement.setAttribute("aria-haspopup", "listbox");
@@ -3455,7 +3648,7 @@ function SuggestionMenu({ rect, editorElement, ariaLabel, width, maxHeight, sect
3455
3648
  for (const name of ["aria-autocomplete", "aria-haspopup", "aria-controls", "aria-activedescendant"]) editorElement.removeAttribute(name);
3456
3649
  };
3457
3650
  }, [editorElement, open, listboxId]);
3458
- useEffect6(() => {
3651
+ useEffect7(() => {
3459
3652
  if (!editorElement || !open) return;
3460
3653
  editorElement.setAttribute("aria-activedescendant", `${base}-${highlight}`);
3461
3654
  }, [editorElement, open, base, highlight]);
@@ -3476,7 +3669,7 @@ function SuggestionMenu({ rect, editorElement, ariaLabel, width, maxHeight, sect
3476
3669
  const { label, description, leading, shortcut, hint, size } = row(item);
3477
3670
  return (
3478
3671
  // A row of a list the editor drives from its caret: focus stays in the text, so the row is no Tab stop.
3479
- /* @__PURE__ */ jsx50(
3672
+ /* @__PURE__ */ jsx53(
3480
3673
  MenuItem,
3481
3674
  {
3482
3675
  role: "option",
@@ -3503,21 +3696,21 @@ function SuggestionMenu({ rect, editorElement, ariaLabel, width, maxHeight, sect
3503
3696
  };
3504
3697
  return (
3505
3698
  // finalFocus={false}: focus never left the text, and a list that closes because focus moved elsewhere must not pull it back (71a4577b).
3506
- /* @__PURE__ */ jsx50(Popover, { anchor: rect, open: rect !== null, side: "top", align: "left", className: width, maxHeight, ariaLabel, finalFocus: false, children: /* @__PURE__ */ jsx50("div", { ref: keepFocus, id: listboxId, role: "listbox", "aria-label": ariaLabel, className: "flex flex-col gap-0.5", children: shown.map((section, i) => /* @__PURE__ */ jsxs35("div", { className: "contents", children: [
3507
- i > 0 && /* @__PURE__ */ jsx50(MenuSeparator, {}),
3508
- section.label ? /* @__PURE__ */ jsx50("div", { role: "group", "aria-label": section.label, children: /* @__PURE__ */ jsx50(MenuSection, { label: section.label, className: section.className, children: section.items.map(drawRow) }) }) : section.items.map(drawRow)
3699
+ /* @__PURE__ */ jsx53(Popover, { anchor: rect, open: rect !== null, side: "top", align: "left", className: width, maxHeight, ariaLabel, finalFocus: false, children: /* @__PURE__ */ jsx53("div", { ref: keepFocus, id: listboxId, role: "listbox", "aria-label": ariaLabel, className: "flex flex-col gap-0.5", children: shown.map((section, i) => /* @__PURE__ */ jsxs37("div", { className: "contents", children: [
3700
+ i > 0 && /* @__PURE__ */ jsx53(MenuSeparator, {}),
3701
+ section.label ? /* @__PURE__ */ jsx53("div", { role: "group", "aria-label": section.label, children: /* @__PURE__ */ jsx53(MenuSection, { label: section.label, className: section.className, children: section.items.map(drawRow) }) }) : section.items.map(drawRow)
3509
3702
  ] }, section.label ?? i)) }) })
3510
3703
  );
3511
3704
  }
3512
3705
 
3513
3706
  // src/ShowMore.tsx
3514
- import { useLayoutEffect as useLayoutEffect5, useRef as useRef12, useState as useState11 } from "react";
3515
- import { jsx as jsx51, jsxs as jsxs36 } from "react/jsx-runtime";
3707
+ import { useLayoutEffect as useLayoutEffect5, useRef as useRef13, useState as useState12 } from "react";
3708
+ import { jsx as jsx54, jsxs as jsxs38 } from "react/jsx-runtime";
3516
3709
  var FADE_CLASSES = { surface: "from-bg-surface", inset: "from-bg-inset" };
3517
3710
  function ShowMore({ children, maxHeight = 96, surface = "surface", className }) {
3518
- const box = useRef12(null);
3519
- const [open, setOpen] = useState11(false);
3520
- const [overflows, setOverflows] = useState11(false);
3711
+ const box = useRef13(null);
3712
+ const [open, setOpen] = useState12(false);
3713
+ const [overflows, setOverflows] = useState12(false);
3521
3714
  useLayoutEffect5(() => {
3522
3715
  const el = box.current;
3523
3716
  if (!el) return;
@@ -3529,21 +3722,21 @@ function ShowMore({ children, maxHeight = 96, surface = "surface", className })
3529
3722
  return () => observer.disconnect();
3530
3723
  }, [maxHeight]);
3531
3724
  const cut = overflows && !open;
3532
- return /* @__PURE__ */ jsxs36("div", { className: cn("flex flex-col items-start", className), children: [
3533
- /* @__PURE__ */ jsxs36("div", { ref: box, className: cn("relative w-full", cut && "overflow-hidden"), style: cut ? { maxHeight } : void 0, onFocus: cut ? () => setOpen(true) : void 0, children: [
3725
+ return /* @__PURE__ */ jsxs38("div", { className: cn("flex flex-col items-start", className), children: [
3726
+ /* @__PURE__ */ jsxs38("div", { ref: box, className: cn("relative w-full", cut && "overflow-hidden"), style: cut ? { maxHeight } : void 0, onFocus: cut ? () => setOpen(true) : void 0, children: [
3534
3727
  children,
3535
- cut && /* @__PURE__ */ jsx51("div", { "aria-hidden": true, className: cn("pointer-events-none absolute inset-x-0 bottom-0 h-10 bg-gradient-to-t to-transparent", FADE_CLASSES[surface]) })
3728
+ cut && /* @__PURE__ */ jsx54("div", { "aria-hidden": true, className: cn("pointer-events-none absolute inset-x-0 bottom-0 h-10 bg-gradient-to-t to-transparent", FADE_CLASSES[surface]) })
3536
3729
  ] }),
3537
3730
  overflows && // `-ml-1.5`: the small button's own 6px inset, so its words start where the content's do.
3538
- /* @__PURE__ */ jsx51(Button, { variant: "muted", size: "small", className: "-ml-1.5 mt-1", "aria-expanded": open, onClick: () => setOpen((o) => !o), children: open ? "Show less" : "Show more" })
3731
+ /* @__PURE__ */ jsx54(Button, { variant: "muted", size: "small", className: "-ml-1.5 mt-1", "aria-expanded": open, onClick: () => setOpen((o) => !o), children: open ? "Show less" : "Show more" })
3539
3732
  ] });
3540
3733
  }
3541
3734
 
3542
3735
  // src/Toolbar.tsx
3543
3736
  import { Toolbar as BaseToolbar } from "@base-ui/react/toolbar";
3544
- import { jsx as jsx52 } from "react/jsx-runtime";
3737
+ import { jsx as jsx55 } from "react/jsx-runtime";
3545
3738
  function Toolbar({ "aria-label": ariaLabel, orientation = "horizontal", loopFocus = true, surface = true, children, className }) {
3546
- const strip = /* @__PURE__ */ jsx52(
3739
+ const strip = /* @__PURE__ */ jsx55(
3547
3740
  BaseToolbar.Root,
3548
3741
  {
3549
3742
  "aria-label": ariaLabel,
@@ -3554,27 +3747,27 @@ function Toolbar({ "aria-label": ariaLabel, orientation = "horizontal", loopFocu
3554
3747
  }
3555
3748
  );
3556
3749
  if (!surface) return strip;
3557
- return /* @__PURE__ */ jsx52(MenuPanel, { className: "w-fit p-1", children: strip });
3750
+ return /* @__PURE__ */ jsx55(MenuPanel, { className: "w-fit p-1", children: strip });
3558
3751
  }
3559
3752
  function ToolbarButton({ ref, disabled, disabledReason, ...props }) {
3560
- return /* @__PURE__ */ jsx52(
3753
+ return /* @__PURE__ */ jsx55(
3561
3754
  BaseToolbar.Button,
3562
3755
  {
3563
3756
  ref,
3564
3757
  disabled: disabled || !!disabledReason,
3565
3758
  focusableWhenDisabled: true,
3566
- render: /* @__PURE__ */ jsx52(IconButton, { disabled, disabledReason, ...props })
3759
+ render: /* @__PURE__ */ jsx55(IconButton, { disabled, disabledReason, ...props })
3567
3760
  }
3568
3761
  );
3569
3762
  }
3570
3763
  function ToolbarLink({ ref, href, ...props }) {
3571
- return /* @__PURE__ */ jsx52(BaseToolbar.Link, { ref, render: /* @__PURE__ */ jsx52(IconButton, { href, ...props }) });
3764
+ return /* @__PURE__ */ jsx55(BaseToolbar.Link, { ref, render: /* @__PURE__ */ jsx55(IconButton, { href, ...props }) });
3572
3765
  }
3573
3766
  function ToolbarInput({ size, ...props }) {
3574
- return /* @__PURE__ */ jsx52(BaseToolbar.Input, { render: /* @__PURE__ */ jsx52(TextInput, { size }), ...props });
3767
+ return /* @__PURE__ */ jsx55(BaseToolbar.Input, { render: /* @__PURE__ */ jsx55(TextInput, { size }), ...props });
3575
3768
  }
3576
3769
  function ToolbarSeparator({ className }) {
3577
- return /* @__PURE__ */ jsx52(
3770
+ return /* @__PURE__ */ jsx55(
3578
3771
  BaseToolbar.Separator,
3579
3772
  {
3580
3773
  orientation: "vertical",
@@ -3584,9 +3777,9 @@ function ToolbarSeparator({ className }) {
3584
3777
  }
3585
3778
 
3586
3779
  // src/ReactionPicker.tsx
3587
- import { jsx as jsx53 } from "react/jsx-runtime";
3780
+ import { jsx as jsx56 } from "react/jsx-runtime";
3588
3781
  function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reactions", surface = true, className }) {
3589
- return /* @__PURE__ */ jsx53(Toolbar, { "aria-label": ariaLabel, surface, className: cn("gap-0.5", className), children: options.map((option) => (
3782
+ return /* @__PURE__ */ jsx56(Toolbar, { "aria-label": ariaLabel, surface, className: cn("gap-0.5", className), children: options.map((option) => (
3590
3783
  /*
3591
3784
  A `ToolbarButton`, not a button in a tooltip wrapper. The wrapper
3592
3785
  would become the toolbar's item and the button inside it would never
@@ -3596,14 +3789,14 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
3596
3789
  The tooltip names it for a pointer, `aria-label` for everything else,
3597
3790
  and both say the meaning rather than the glyph.
3598
3791
  */
3599
- /* @__PURE__ */ jsx53(
3792
+ /* @__PURE__ */ jsx56(
3600
3793
  ToolbarButton,
3601
3794
  {
3602
3795
  "aria-label": option.label,
3603
3796
  tooltip: option.label,
3604
3797
  onClick: () => onSelect(option.emoji),
3605
3798
  className: "size-7",
3606
- children: /* @__PURE__ */ jsx53("span", { "aria-hidden": "true", className: "text-h3 leading-none", children: option.emoji })
3799
+ children: /* @__PURE__ */ jsx56("span", { "aria-hidden": "true", className: "text-h3 leading-none", children: option.emoji })
3607
3800
  },
3608
3801
  option.emoji
3609
3802
  )
@@ -3612,23 +3805,23 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
3612
3805
 
3613
3806
  // src/PreviewCard.tsx
3614
3807
  import { PreviewCard as BasePreviewCard } from "@base-ui/react/preview-card";
3615
- import { jsx as jsx54, jsxs as jsxs37 } from "react/jsx-runtime";
3808
+ import { jsx as jsx57, jsxs as jsxs39 } from "react/jsx-runtime";
3616
3809
  var GAP6 = 12;
3617
3810
  var VIEWPORT_PAD6 = 8;
3618
3811
  var OPEN_DELAY2 = 350;
3619
3812
  var CLOSE_DELAY = 200;
3620
3813
  function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, closeDelay = CLOSE_DELAY, className, contentClassName, wrapperClassName }) {
3621
- return /* @__PURE__ */ jsxs37(BasePreviewCard.Root, { children: [
3622
- /* @__PURE__ */ jsx54(
3814
+ return /* @__PURE__ */ jsxs39(BasePreviewCard.Root, { children: [
3815
+ /* @__PURE__ */ jsx57(
3623
3816
  BasePreviewCard.Trigger,
3624
3817
  {
3625
3818
  delay,
3626
3819
  closeDelay,
3627
- render: /* @__PURE__ */ jsx54("span", { className: cn("inline-flex", wrapperClassName) }),
3820
+ render: /* @__PURE__ */ jsx57("span", { className: cn("inline-flex", wrapperClassName) }),
3628
3821
  children
3629
3822
  }
3630
3823
  ),
3631
- /* @__PURE__ */ jsx54(BasePreviewCard.Portal, { children: /* @__PURE__ */ jsx54(
3824
+ /* @__PURE__ */ jsx57(BasePreviewCard.Portal, { children: /* @__PURE__ */ jsx57(
3632
3825
  BasePreviewCard.Positioner,
3633
3826
  {
3634
3827
  side,
@@ -3636,12 +3829,12 @@ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, c
3636
3829
  sideOffset: GAP6,
3637
3830
  collisionPadding: VIEWPORT_PAD6,
3638
3831
  className: "z-50 data-[anchor-hidden]:hidden",
3639
- children: /* @__PURE__ */ jsx54(
3832
+ children: /* @__PURE__ */ jsx57(
3640
3833
  BasePreviewCard.Popup,
3641
3834
  {
3642
3835
  className: cn("w-[360px] p-0 outline-none", className),
3643
- render: /* @__PURE__ */ jsx54(MenuPanel, {}),
3644
- children: /* @__PURE__ */ jsx54(ScrollArea, { viewportClassName: "max-h-[min(300px,var(--available-height))]", contentClassName: cn("flex flex-col gap-3 p-3", contentClassName), children: content })
3836
+ render: /* @__PURE__ */ jsx57(MenuPanel, {}),
3837
+ children: /* @__PURE__ */ jsx57(ScrollArea, { viewportClassName: "max-h-[min(300px,var(--available-height))]", contentClassName: cn("flex flex-col gap-3 p-3", contentClassName), children: content })
3645
3838
  }
3646
3839
  )
3647
3840
  }
@@ -3650,30 +3843,32 @@ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, c
3650
3843
  }
3651
3844
 
3652
3845
  // src/Rail.tsx
3653
- import { jsx as jsx55 } from "react/jsx-runtime";
3846
+ import { jsx as jsx58 } from "react/jsx-runtime";
3654
3847
  function Rail({ "aria-label": ariaLabel = "Navigation", children, className }) {
3655
- return /* @__PURE__ */ jsx55("nav", { "aria-label": ariaLabel, className: cn("flex w-16 shrink-0 flex-col items-start gap-2 px-2 py-3", className), children });
3848
+ return /* @__PURE__ */ jsx58("nav", { "aria-label": ariaLabel, className: cn("flex w-16 shrink-0 flex-col items-start gap-2 px-2 py-3", className), children });
3656
3849
  }
3657
3850
 
3658
3851
  // src/RailItem.tsx
3659
- import { jsx as jsx56, jsxs as jsxs38 } from "react/jsx-runtime";
3660
- function RailItem({ href, icon, label, active = false, className, ...props }) {
3661
- return /* @__PURE__ */ jsxs38(
3852
+ import { jsx as jsx59, jsxs as jsxs40 } from "react/jsx-runtime";
3853
+ function RailItem({ href, icon, label, active = false, className, onClick, ...props }) {
3854
+ const inApp = useInAppClick(href, onClick);
3855
+ return /* @__PURE__ */ jsxs40(
3662
3856
  "a",
3663
3857
  {
3664
3858
  href,
3665
3859
  "aria-current": active ? "page" : void 0,
3666
3860
  className: cn("group flex h-12 w-full shrink-0 flex-col items-center gap-0.5 px-2 py-0.5", className),
3667
3861
  ...props,
3862
+ onClick: inApp,
3668
3863
  children: [
3669
- /* @__PURE__ */ jsx56(
3864
+ /* @__PURE__ */ jsx59(
3670
3865
  "div",
3671
3866
  {
3672
3867
  className: cn(
3673
3868
  "flex items-center justify-center rounded-lg p-2 transition-colors",
3674
3869
  active ? "bg-bg-selected" : "group-hover:bg-bg-hover"
3675
3870
  ),
3676
- children: /* @__PURE__ */ jsx56(
3871
+ children: /* @__PURE__ */ jsx59(
3677
3872
  "span",
3678
3873
  {
3679
3874
  className: cn(
@@ -3685,14 +3880,14 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
3685
3880
  )
3686
3881
  }
3687
3882
  ),
3688
- /* @__PURE__ */ jsx56("span", { className: cn("text-center text-menu", active ? "text-text-primary" : "text-text-secondary"), children: label })
3883
+ /* @__PURE__ */ jsx59("span", { className: cn("text-center text-menu", active ? "text-text-primary" : "text-text-secondary"), children: label })
3689
3884
  ]
3690
3885
  }
3691
3886
  );
3692
3887
  }
3693
3888
 
3694
3889
  // src/Property.tsx
3695
- import { jsx as jsx57, jsxs as jsxs39 } from "react/jsx-runtime";
3890
+ import { jsx as jsx60, jsxs as jsxs41 } from "react/jsx-runtime";
3696
3891
  var VALUE_CLASSES = "contents";
3697
3892
  function Property({ label, layout = "row", children, className }) {
3698
3893
  if (layout === "stacked") {
@@ -3700,25 +3895,25 @@ function Property({ label, layout = "row", children, className }) {
3700
3895
  // gap-3 — the one label-above-content distance (Katerina, 2026-09-01):
3701
3896
  // Peek's topic-details sections already sit at 12px, Ship's rail was
3702
3897
  // 6px, and unifying means the bigger, calmer one.
3703
- /* @__PURE__ */ jsxs39("dl", { className: cn("flex flex-col gap-3", className), children: [
3704
- /* @__PURE__ */ jsx57("dt", { className: "text-menu uppercase tracking-widest text-text-secondary", children: label }),
3705
- /* @__PURE__ */ jsx57("dd", { className: VALUE_CLASSES, children })
3898
+ /* @__PURE__ */ jsxs41("dl", { className: cn("flex flex-col gap-3", className), children: [
3899
+ /* @__PURE__ */ jsx60("dt", { className: "text-menu uppercase tracking-widest text-text-secondary", children: label }),
3900
+ /* @__PURE__ */ jsx60("dd", { className: VALUE_CLASSES, children })
3706
3901
  ] })
3707
3902
  );
3708
3903
  }
3709
- return /* @__PURE__ */ jsxs39("dl", { className: cn("flex items-center gap-2", className), children: [
3710
- /* @__PURE__ */ jsx57("dt", { className: "w-[68px] shrink-0 text-caption text-text-secondary", children: label }),
3711
- /* @__PURE__ */ jsx57("dd", { className: VALUE_CLASSES, children })
3904
+ return /* @__PURE__ */ jsxs41("dl", { className: cn("flex items-center gap-2", className), children: [
3905
+ /* @__PURE__ */ jsx60("dt", { className: "w-[68px] shrink-0 text-caption text-text-secondary", children: label }),
3906
+ /* @__PURE__ */ jsx60("dd", { className: VALUE_CLASSES, children })
3712
3907
  ] });
3713
3908
  }
3714
3909
 
3715
3910
  // src/Reaction.tsx
3716
3911
  import { Toggle } from "@base-ui/react/toggle";
3717
- import { jsx as jsx58, jsxs as jsxs40 } from "react/jsx-runtime";
3912
+ import { jsx as jsx61, jsxs as jsxs42 } from "react/jsx-runtime";
3718
3913
  function Reaction({ emoji, count, pressed = false, className, ...props }) {
3719
3914
  return (
3720
3915
  // @estiva-escape(no-copied-look): W1 (Katerina, 24 September: leave alone): a reaction pill shares four words with a field's box by coincidence
3721
- /* @__PURE__ */ jsxs40(
3916
+ /* @__PURE__ */ jsxs42(
3722
3917
  Toggle,
3723
3918
  {
3724
3919
  pressed,
@@ -3740,8 +3935,8 @@ function Reaction({ emoji, count, pressed = false, className, ...props }) {
3740
3935
  ),
3741
3936
  ...props,
3742
3937
  children: [
3743
- /* @__PURE__ */ jsx58("span", { "aria-hidden": "true", className: "shrink-0 text-body-1 leading-none", children: emoji }),
3744
- /* @__PURE__ */ jsx58("span", { className: CHIP_TEXT_CLASSES, children: count })
3938
+ /* @__PURE__ */ jsx61("span", { "aria-hidden": "true", className: "shrink-0 text-body-1 leading-none", children: emoji }),
3939
+ /* @__PURE__ */ jsx61("span", { className: CHIP_TEXT_CLASSES, children: count })
3745
3940
  ]
3746
3941
  }
3747
3942
  )
@@ -3751,9 +3946,9 @@ function Reaction({ emoji, count, pressed = false, className, ...props }) {
3751
3946
  // src/SearchInput.tsx
3752
3947
  import "react";
3753
3948
  import { Input as Input3 } from "@base-ui/react/input";
3754
- import { jsx as jsx59, jsxs as jsxs41 } from "react/jsx-runtime";
3949
+ import { jsx as jsx62, jsxs as jsxs43 } from "react/jsx-runtime";
3755
3950
  function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...props }) {
3756
- return /* @__PURE__ */ jsxs41(
3951
+ return /* @__PURE__ */ jsxs43(
3757
3952
  "div",
3758
3953
  {
3759
3954
  className: cn(
@@ -3765,7 +3960,7 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
3765
3960
  className
3766
3961
  ),
3767
3962
  children: [
3768
- /* @__PURE__ */ jsx59(
3963
+ /* @__PURE__ */ jsx62(
3769
3964
  Input3,
3770
3965
  {
3771
3966
  className: cn("flex-1 min-w-0 text-input-value", BARE_INPUT_CLASSES),
@@ -3773,42 +3968,42 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
3773
3968
  ...props
3774
3969
  }
3775
3970
  ),
3776
- shortcut && /* @__PURE__ */ jsx59(Kbd, { children: shortcut })
3971
+ shortcut && /* @__PURE__ */ jsx62(Kbd, { children: shortcut })
3777
3972
  ]
3778
3973
  }
3779
3974
  );
3780
3975
  }
3781
3976
 
3782
3977
  // src/Panel.tsx
3783
- import { jsx as jsx60, jsxs as jsxs42 } from "react/jsx-runtime";
3978
+ import { jsx as jsx63, jsxs as jsxs44 } from "react/jsx-runtime";
3784
3979
  function Frame({ title, chevron = false, actions, children, footer, bodyClassName, bodyRef, onBodyScroll, className, broken = false }) {
3785
- return /* @__PURE__ */ jsxs42("div", { className: cn("flex h-full min-h-0 flex-1 flex-col", className), children: [
3786
- /* @__PURE__ */ jsx60(ContainerHeader, { title, chevron, actions }),
3980
+ return /* @__PURE__ */ jsxs44("div", { className: cn("flex h-full min-h-0 flex-1 flex-col", className), children: [
3981
+ /* @__PURE__ */ jsx63(ContainerHeader, { title, chevron, actions }),
3787
3982
  broken ? (
3788
3983
  // The message takes the room the body had and centres itself in it.
3789
- /* @__PURE__ */ jsx60("div", { className: "flex min-h-0 flex-1 flex-col px-4", children })
3790
- ) : /* @__PURE__ */ jsx60(ScrollArea, { className: "min-h-0 flex-1", contentClassName: bodyClassName, viewportRef: bodyRef, onScroll: onBodyScroll, children }),
3791
- !broken && footer && /* @__PURE__ */ jsx60("div", { className: "shrink-0", children: footer })
3984
+ /* @__PURE__ */ jsx63("div", { className: "flex min-h-0 flex-1 flex-col px-4", children })
3985
+ ) : /* @__PURE__ */ jsx63(ScrollArea, { className: "min-h-0 flex-1", contentClassName: bodyClassName, viewportRef: bodyRef, onScroll: onBodyScroll, children }),
3986
+ !broken && footer && /* @__PURE__ */ jsx63("div", { className: "shrink-0", children: footer })
3792
3987
  ] });
3793
3988
  }
3794
3989
  function Panel(props) {
3795
- return /* @__PURE__ */ jsx60(
3990
+ return /* @__PURE__ */ jsx63(
3796
3991
  ErrorBoundary,
3797
3992
  {
3798
3993
  label: "panel",
3799
3994
  frame: (message) => (
3800
3995
  // Only the name comes back with the message: the actions and the footer may be what threw.
3801
- /* @__PURE__ */ jsx60(Frame, { title: props.title, chevron: props.chevron, className: props.className, broken: true, children: message })
3996
+ /* @__PURE__ */ jsx63(Frame, { title: props.title, chevron: props.chevron, className: props.className, broken: true, children: message })
3802
3997
  ),
3803
- children: /* @__PURE__ */ jsx60(Frame, { ...props })
3998
+ children: /* @__PURE__ */ jsx63(Frame, { ...props })
3804
3999
  }
3805
4000
  );
3806
4001
  }
3807
4002
 
3808
4003
  // src/ListColumn.tsx
3809
- import { jsx as jsx61, jsxs as jsxs43 } from "react/jsx-runtime";
4004
+ import { jsx as jsx64, jsxs as jsxs45 } from "react/jsx-runtime";
3810
4005
  function Column({ title, chevron = false, titleMenu, actions, above, collapsed = false, children, className, broken = false }) {
3811
- return /* @__PURE__ */ jsxs43(
4006
+ return /* @__PURE__ */ jsxs45(
3812
4007
  "div",
3813
4008
  {
3814
4009
  className: cn(
@@ -3819,35 +4014,35 @@ function Column({ title, chevron = false, titleMenu, actions, above, collapsed =
3819
4014
  ),
3820
4015
  "data-collapsed": collapsed || void 0,
3821
4016
  children: [
3822
- /* @__PURE__ */ jsx61(ContainerHeader, { title, chevron, titleMenu, actions }),
4017
+ /* @__PURE__ */ jsx64(ContainerHeader, { title, chevron, titleMenu, actions }),
3823
4018
  above,
3824
4019
  broken ? (
3825
4020
  // The message takes the room the list had and centres itself in it (Katerina, 19 September).
3826
- /* @__PURE__ */ jsx61("div", { className: "flex min-h-0 flex-1 flex-col px-3", children })
3827
- ) : /* @__PURE__ */ jsx61(ScrollArea, { className: "flex-1", contentClassName: "flex flex-col gap-0.5 px-3 pt-4 pb-3", children })
4021
+ /* @__PURE__ */ jsx64("div", { className: "flex min-h-0 flex-1 flex-col px-3", children })
4022
+ ) : /* @__PURE__ */ jsx64(ScrollArea, { className: "flex-1", contentClassName: "flex flex-col gap-0.5 px-3 pt-4 pb-3", children })
3828
4023
  ]
3829
4024
  }
3830
4025
  );
3831
4026
  }
3832
4027
  function ListColumn(props) {
3833
- return /* @__PURE__ */ jsx61(
4028
+ return /* @__PURE__ */ jsx64(
3834
4029
  ErrorBoundary,
3835
4030
  {
3836
4031
  label: "list panel",
3837
4032
  frame: (message) => (
3838
4033
  // Only the name comes back with the message: the actions and the row above may be what threw.
3839
- /* @__PURE__ */ jsx61(Column, { title: props.title, chevron: props.chevron, collapsed: props.collapsed, className: props.className, broken: true, children: message })
4034
+ /* @__PURE__ */ jsx64(Column, { title: props.title, chevron: props.chevron, collapsed: props.collapsed, className: props.className, broken: true, children: message })
3840
4035
  ),
3841
- children: /* @__PURE__ */ jsx61(Column, { ...props })
4036
+ children: /* @__PURE__ */ jsx64(Column, { ...props })
3842
4037
  }
3843
4038
  );
3844
4039
  }
3845
4040
 
3846
4041
  // src/Tabs.tsx
3847
4042
  import { Tabs as BaseTabs } from "@base-ui/react/tabs";
3848
- import { jsx as jsx62, jsxs as jsxs44 } from "react/jsx-runtime";
4043
+ import { Fragment as Fragment14, jsx as jsx65, jsxs as jsxs46 } from "react/jsx-runtime";
3849
4044
  function Tabs({ tabs, active, onChange, size = "default", className, ...aria }) {
3850
- return /* @__PURE__ */ jsx62(
4045
+ return /* @__PURE__ */ jsx65(
3851
4046
  BaseTabs.Root,
3852
4047
  {
3853
4048
  value: active,
@@ -3855,14 +4050,14 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
3855
4050
  if (details.reason === "none") onChange(value);
3856
4051
  },
3857
4052
  className,
3858
- children: /* @__PURE__ */ jsx62(
4053
+ children: /* @__PURE__ */ jsx65(
3859
4054
  BaseTabs.List,
3860
4055
  {
3861
4056
  activateOnFocus: true,
3862
4057
  "aria-label": aria["aria-label"],
3863
4058
  "aria-labelledby": aria["aria-labelledby"],
3864
4059
  className: "flex items-center gap-2",
3865
- children: tabs.map((tab) => /* @__PURE__ */ jsxs44(
4060
+ children: tabs.map((tab) => /* @__PURE__ */ jsxs46(
3866
4061
  BaseTabs.Tab,
3867
4062
  {
3868
4063
  value: tab.id,
@@ -3875,10 +4070,14 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
3875
4070
  ),
3876
4071
  children: [
3877
4072
  tab.icon,
3878
- /* @__PURE__ */ jsxs44("span", { className: "flex items-baseline", children: [
4073
+ /* @__PURE__ */ jsxs46("span", { className: "flex items-baseline", children: [
3879
4074
  tab.label,
3880
- tab.count !== void 0 ? /* @__PURE__ */ jsx62("span", { className: "ml-2.5 font-mono text-caption tabular-nums text-text-secondary", children: tab.count }) : null
3881
- ] })
4075
+ tab.count !== void 0 ? /* @__PURE__ */ jsx65("span", { className: "ml-2.5 font-mono text-caption tabular-nums text-text-secondary", children: tab.count }) : null
4076
+ ] }),
4077
+ tab.unread ? /* @__PURE__ */ jsxs46(Fragment14, { children: [
4078
+ /* @__PURE__ */ jsx65(UnreadDot, { className: "h-auto w-auto" }),
4079
+ /* @__PURE__ */ jsx65("span", { className: "sr-only", children: "new" })
4080
+ ] }) : null
3882
4081
  ]
3883
4082
  },
3884
4083
  tab.id
@@ -3890,10 +4089,10 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
3890
4089
  }
3891
4090
 
3892
4091
  // src/Toast.tsx
3893
- import { createContext as createContext6, useContext as useContext6, useMemo as useMemo5 } from "react";
4092
+ import { createContext as createContext7, useContext as useContext7, useMemo as useMemo6 } from "react";
3894
4093
  import { Toast as BaseToast } from "@base-ui/react/toast";
3895
4094
  import { IconAlertCircle as IconAlertCircle2, IconCircleCheck, IconCircleX } from "@tabler/icons-react";
3896
- import { jsx as jsx63, jsxs as jsxs45 } from "react/jsx-runtime";
4095
+ import { jsx as jsx66, jsxs as jsxs47 } from "react/jsx-runtime";
3897
4096
  var SURFACE_STYLES = {
3898
4097
  success: "bg-success-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md leaf:bg-bg-inset leaf:border leaf:border-border-default leaf:shadow-md",
3899
4098
  brand: "bg-accent-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md leaf:bg-bg-inset leaf:border leaf:border-border-default leaf:shadow-md",
@@ -3929,23 +4128,23 @@ var pillClassName = (type, hasAction, className) => cn(
3929
4128
  );
3930
4129
  function LeadingIcon({ type }) {
3931
4130
  const Icon = ICONS[type];
3932
- return /* @__PURE__ */ jsx63(Icon, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_STYLES[type]) });
4131
+ return /* @__PURE__ */ jsx66(Icon, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_STYLES[type]) });
3933
4132
  }
3934
4133
  function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAction, className }) {
3935
4134
  const hasAction = !!(actionLabel && onAction);
3936
- return /* @__PURE__ */ jsxs45("div", { className: pillClassName(type, hasAction, className), children: [
3937
- /* @__PURE__ */ jsxs45("div", { className: "flex items-center gap-2 shrink-0", children: [
3938
- leadingIcon && /* @__PURE__ */ jsx63(LeadingIcon, { type }),
3939
- /* @__PURE__ */ jsx63("span", { className: LABEL_CLASSES, children: label })
4135
+ return /* @__PURE__ */ jsxs47("div", { className: pillClassName(type, hasAction, className), children: [
4136
+ /* @__PURE__ */ jsxs47("div", { className: "flex items-center gap-2 shrink-0", children: [
4137
+ leadingIcon && /* @__PURE__ */ jsx66(LeadingIcon, { type }),
4138
+ /* @__PURE__ */ jsx66("span", { className: LABEL_CLASSES, children: label })
3940
4139
  ] }),
3941
- hasAction && /* @__PURE__ */ jsx63(Button, { variant: "outlined", size: "small", onClick: onAction, children: actionLabel })
4140
+ hasAction && /* @__PURE__ */ jsx66(Button, { variant: "outlined", size: "small", onClick: onAction, children: actionLabel })
3942
4141
  ] });
3943
4142
  }
3944
- var ToastContext = createContext6(null);
4143
+ var ToastContext = createContext7(null);
3945
4144
  var VISIBLE_TOASTS = 3;
3946
4145
  function ToastProvider({ children }) {
3947
- const manager = useMemo5(() => BaseToast.createToastManager(), []);
3948
- const value = useMemo5(
4146
+ const manager = useMemo6(() => BaseToast.createToastManager(), []);
4147
+ const value = useMemo6(
3949
4148
  () => ({
3950
4149
  showToast: ({ label, type = "neutral", leadingIcon = true, actionLabel, onAction, durationMs = 5e3 }) => manager.add({
3951
4150
  title: label,
@@ -3959,9 +4158,9 @@ function ToastProvider({ children }) {
3959
4158
  }),
3960
4159
  [manager]
3961
4160
  );
3962
- return /* @__PURE__ */ jsx63(ToastContext.Provider, { value, children: /* @__PURE__ */ jsxs45(BaseToast.Provider, { toastManager: manager, limit: VISIBLE_TOASTS, children: [
4161
+ return /* @__PURE__ */ jsx66(ToastContext.Provider, { value, children: /* @__PURE__ */ jsxs47(BaseToast.Provider, { toastManager: manager, limit: VISIBLE_TOASTS, children: [
3963
4162
  children,
3964
- /* @__PURE__ */ jsx63(BaseToast.Portal, { children: /* @__PURE__ */ jsx63(BaseToast.Viewport, { className: "fixed bottom-4 left-4 z-[100] flex flex-col-reverse items-start gap-2 pointer-events-none", children: /* @__PURE__ */ jsx63(ToastList, {}) }) })
4163
+ /* @__PURE__ */ jsx66(BaseToast.Portal, { children: /* @__PURE__ */ jsx66(BaseToast.Viewport, { className: "fixed bottom-4 left-4 z-[100] flex flex-col-reverse items-start gap-2 pointer-events-none", children: /* @__PURE__ */ jsx66(ToastList, {}) }) })
3965
4164
  ] }) });
3966
4165
  }
3967
4166
  function ToastList() {
@@ -3969,25 +4168,25 @@ function ToastList() {
3969
4168
  return toasts.map((toast) => {
3970
4169
  const type = toast.type ?? "neutral";
3971
4170
  const { leadingIcon = true, actionLabel, onAction } = toast.data ?? {};
3972
- return /* @__PURE__ */ jsxs45(
4171
+ return /* @__PURE__ */ jsxs47(
3973
4172
  BaseToast.Root,
3974
4173
  {
3975
4174
  toast,
3976
4175
  swipeDirection: ["left", "down"],
3977
4176
  className: pillClassName(type, !!actionLabel, "pointer-events-auto data-[limited]:hidden"),
3978
4177
  children: [
3979
- /* @__PURE__ */ jsxs45("div", { className: "flex items-center gap-2 shrink-0", children: [
3980
- leadingIcon && /* @__PURE__ */ jsx63(LeadingIcon, { type }),
3981
- /* @__PURE__ */ jsx63(BaseToast.Title, { render: /* @__PURE__ */ jsx63("span", {}), className: LABEL_CLASSES })
4178
+ /* @__PURE__ */ jsxs47("div", { className: "flex items-center gap-2 shrink-0", children: [
4179
+ leadingIcon && /* @__PURE__ */ jsx66(LeadingIcon, { type }),
4180
+ /* @__PURE__ */ jsx66(BaseToast.Title, { render: /* @__PURE__ */ jsx66("span", {}), className: LABEL_CLASSES })
3982
4181
  ] }),
3983
- actionLabel && /* @__PURE__ */ jsx63(
4182
+ actionLabel && /* @__PURE__ */ jsx66(
3984
4183
  BaseToast.Action,
3985
4184
  {
3986
4185
  onClick: () => {
3987
4186
  onAction?.();
3988
4187
  close(toast.id);
3989
4188
  },
3990
- render: /* @__PURE__ */ jsx63(Button, { variant: "outlined", size: "small", children: actionLabel })
4189
+ render: /* @__PURE__ */ jsx66(Button, { variant: "outlined", size: "small", children: actionLabel })
3991
4190
  }
3992
4191
  )
3993
4192
  ]
@@ -3997,24 +4196,12 @@ function ToastList() {
3997
4196
  });
3998
4197
  }
3999
4198
  function useToast() {
4000
- const ctx = useContext6(ToastContext);
4199
+ const ctx = useContext7(ToastContext);
4001
4200
  if (!ctx) throw new Error("useToast must be used within ToastProvider");
4002
4201
  return ctx;
4003
4202
  }
4004
-
4005
- // src/shortcuts.ts
4006
- function isApplePlatform() {
4007
- if (typeof navigator === "undefined") return false;
4008
- return /Mac|iPhone|iPad|iPod/.test(navigator.platform || navigator.userAgent || "");
4009
- }
4010
- function shortcutLabel(keys, apple = isApplePlatform()) {
4011
- return keys.split("-").map((part, i, all) => {
4012
- if (i === all.length - 1) return part.length === 1 ? part.toUpperCase() : part;
4013
- if (part === "Mod") return apple ? "Cmd" : "Ctrl";
4014
- return part;
4015
- }).join("+");
4016
- }
4017
4203
  export {
4204
+ AppProvider,
4018
4205
  AppShell,
4019
4206
  AttachmentCard,
4020
4207
  Avatar,
@@ -4058,6 +4245,8 @@ export {
4058
4245
  Lightbox,
4059
4246
  Link,
4060
4247
  ListColumn,
4248
+ MembersDialog,
4249
+ MembersPill,
4061
4250
  Menu,
4062
4251
  MenuItem,
4063
4252
  MenuPanel,