@flytedan/flytebot-design-system 0.58.0 → 0.59.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.
package/dist/index.cjs CHANGED
@@ -38,6 +38,7 @@ __export(index_exports, {
38
38
  AppShell: () => AppShell,
39
39
  AppSwitcher: () => AppSwitcher,
40
40
  AppearanceMenu: () => AppearanceMenu,
41
+ AppearanceProvider: () => AppearanceProvider,
41
42
  Avatar: () => Avatar,
42
43
  AvatarStack: () => AvatarStack,
43
44
  Badge: () => Badge,
@@ -193,6 +194,7 @@ __export(index_exports, {
193
194
  __resetLayerStackForTests: () => __resetLayerStackForTests,
194
195
  acceptMatches: () => acceptMatches,
195
196
  anyOfFilter: () => anyOfFilter,
197
+ applyAppearance: () => applyAppearance,
196
198
  applyPrefs: () => applyPrefs,
197
199
  channelWeightOf: () => channelWeightOf,
198
200
  computeNeedMore: () => computeNeedMore,
@@ -238,6 +240,7 @@ __export(index_exports, {
238
240
  toAttachment: () => toAttachment,
239
241
  tokenize: () => tokenize,
240
242
  useAppearancePrefs: () => useAppearancePrefs,
243
+ useAppearanceStore: () => useAppearanceStore,
241
244
  useChatEngine: () => useChatEngine,
242
245
  useCopyToClipboard: () => useCopyToClipboard,
243
246
  useCornerStackSlot: () => useCornerStackSlot,
@@ -253,7 +256,8 @@ __export(index_exports, {
253
256
  useStagedFiles: () => useStagedFiles,
254
257
  useToast: () => useToast,
255
258
  validateFilterValue: () => validateFilterValue,
256
- visibleMessages: () => visibleMessages
259
+ visibleMessages: () => visibleMessages,
260
+ watchAppearance: () => watchAppearance
257
261
  });
258
262
  module.exports = __toCommonJS(index_exports);
259
263
 
@@ -8318,7 +8322,7 @@ function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
8318
8322
  }
8319
8323
 
8320
8324
  // src/components/platform/AppearanceMenu.tsx
8321
- var React52 = __toESM(require("react"), 1);
8325
+ var React53 = __toESM(require("react"), 1);
8322
8326
 
8323
8327
  // src/kits/appearance.ts
8324
8328
  var React51 = __toESM(require("react"), 1);
@@ -8415,20 +8419,25 @@ function applyPrefs(prefs, root = document.documentElement) {
8415
8419
  if (prefs.reduceMotion) root.setAttribute("data-motion", "reduce");
8416
8420
  else root.removeAttribute("data-motion");
8417
8421
  }
8422
+ function applyAppearance(store, root = document.documentElement) {
8423
+ applyPrefs(store.getSnapshot(), root);
8424
+ }
8425
+ function watchAppearance(store, root = document.documentElement) {
8426
+ const apply = () => applyAppearance(store, root);
8427
+ apply();
8428
+ const unsubscribe = store.subscribe(apply);
8429
+ const mq = typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia("(prefers-color-scheme: dark)") : null;
8430
+ const onSchemeChange = () => {
8431
+ if (store.getSnapshot().theme === "system") apply();
8432
+ };
8433
+ mq?.addEventListener("change", onSchemeChange);
8434
+ return () => {
8435
+ unsubscribe();
8436
+ mq?.removeEventListener("change", onSchemeChange);
8437
+ };
8438
+ }
8418
8439
  function useAppearancePrefs(store) {
8419
8440
  const prefs = React51.useSyncExternalStore(store.subscribe, store.getSnapshot);
8420
- React51.useEffect(() => {
8421
- applyPrefs(prefs);
8422
- }, [prefs]);
8423
- React51.useEffect(() => {
8424
- if (prefs.theme !== "system" || typeof window === "undefined" || typeof window.matchMedia !== "function") {
8425
- return;
8426
- }
8427
- const mq = window.matchMedia("(prefers-color-scheme: dark)");
8428
- const onChange = () => applyPrefs(prefs);
8429
- mq.addEventListener("change", onChange);
8430
- return () => mq.removeEventListener("change", onChange);
8431
- }, [prefs]);
8432
8441
  const update = React51.useCallback(
8433
8442
  (patch) => {
8434
8443
  store.write({ ...store.getSnapshot(), ...patch });
@@ -8438,8 +8447,22 @@ function useAppearancePrefs(store) {
8438
8447
  return [prefs, update];
8439
8448
  }
8440
8449
 
8441
- // src/components/platform/AppearanceMenu.tsx
8450
+ // src/components/platform/AppearanceProvider.tsx
8451
+ var React52 = __toESM(require("react"), 1);
8442
8452
  var import_jsx_runtime78 = require("react/jsx-runtime");
8453
+ var AppearanceStoreContext = React52.createContext(null);
8454
+ function AppearanceProvider({ store, children }) {
8455
+ React52.useLayoutEffect(() => watchAppearance(store), [store]);
8456
+ return /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(AppearanceStoreContext.Provider, { value: store, children });
8457
+ }
8458
+ function useAppearanceStore() {
8459
+ const store = React52.useContext(AppearanceStoreContext);
8460
+ if (!store) throw new Error("AppearanceMenu and useAppearanceStore must be rendered inside an <AppearanceProvider>.");
8461
+ return store;
8462
+ }
8463
+
8464
+ // src/components/platform/AppearanceMenu.tsx
8465
+ var import_jsx_runtime79 = require("react/jsx-runtime");
8443
8466
  var THEME_OPTIONS = [
8444
8467
  { value: "light", label: "Light" },
8445
8468
  { value: "dark", label: "Dark" },
@@ -8451,17 +8474,13 @@ var TEXT_SCALE_OPTIONS = [
8451
8474
  { value: "lg", label: "L" },
8452
8475
  { value: "xl", label: "XL" }
8453
8476
  ];
8454
- function AppearanceMenu({ className = "", store: storeProp, storageKey, storage, defaults }) {
8455
- const store = React52.useMemo(
8456
- () => storeProp ?? createLocalStorageAppearanceStore({ storageKey, storage, defaults }),
8457
- [storeProp, storageKey, storage, defaults]
8458
- );
8459
- const [prefs, update] = useAppearancePrefs(store);
8460
- const [open2, setOpen] = React52.useState(false);
8461
- const anchorRef = React52.useRef(null);
8477
+ function AppearanceMenu({ className = "" }) {
8478
+ const [prefs, update] = useAppearancePrefs(useAppearanceStore());
8479
+ const [open2, setOpen] = React53.useState(false);
8480
+ const anchorRef = React53.useRef(null);
8462
8481
  const patch = (p) => update(p);
8463
- return /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)(React52.Fragment, { children: [
8464
- /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("span", { ref: anchorRef, className: ["fd-appearance-anchor", className].filter(Boolean).join(" "), style: { display: "inline-flex" }, children: /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(
8482
+ return /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)(React53.Fragment, { children: [
8483
+ /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { ref: anchorRef, className: ["fd-appearance-anchor", className].filter(Boolean).join(" "), style: { display: "inline-flex" }, children: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
8465
8484
  IconButton,
8466
8485
  {
8467
8486
  icon: "circle-half",
@@ -8469,7 +8488,7 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
8469
8488
  onClick: () => setOpen((v) => !v)
8470
8489
  }
8471
8490
  ) }),
8472
- /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(
8491
+ /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
8473
8492
  Popover,
8474
8493
  {
8475
8494
  open: open2,
@@ -8479,10 +8498,10 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
8479
8498
  padded: true,
8480
8499
  width: 260,
8481
8500
  label: "Appearance settings",
8482
- children: /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("div", { className: "fd-stack", style: { display: "flex", flexDirection: "column", gap: 16 }, children: [
8483
- /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
8484
- /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("span", { className: "fd-field-label", children: "Theme" }),
8485
- /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(
8501
+ children: /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-stack", style: { display: "flex", flexDirection: "column", gap: 16 }, children: [
8502
+ /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
8503
+ /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-field-label", children: "Theme" }),
8504
+ /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
8486
8505
  SegmentedControl,
8487
8506
  {
8488
8507
  options: THEME_OPTIONS,
@@ -8492,9 +8511,9 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
8492
8511
  }
8493
8512
  )
8494
8513
  ] }),
8495
- /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
8496
- /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("span", { className: "fd-field-label", children: "Text size" }),
8497
- /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(
8514
+ /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
8515
+ /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-field-label", children: "Text size" }),
8516
+ /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
8498
8517
  SegmentedControl,
8499
8518
  {
8500
8519
  options: TEXT_SCALE_OPTIONS,
@@ -8504,7 +8523,7 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
8504
8523
  }
8505
8524
  )
8506
8525
  ] }),
8507
- /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(
8526
+ /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
8508
8527
  Switch,
8509
8528
  {
8510
8529
  label: "High contrast",
@@ -8513,7 +8532,7 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
8513
8532
  onChange: (e) => patch({ highContrast: e.target.checked })
8514
8533
  }
8515
8534
  ),
8516
- /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(
8535
+ /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
8517
8536
  Switch,
8518
8537
  {
8519
8538
  label: "Reduce motion",
@@ -8529,14 +8548,14 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
8529
8548
  }
8530
8549
 
8531
8550
  // src/components/platform/ApiSpecBrowser.tsx
8532
- var React53 = __toESM(require("react"), 1);
8533
- var import_jsx_runtime79 = require("react/jsx-runtime");
8551
+ var React54 = __toESM(require("react"), 1);
8552
+ var import_jsx_runtime80 = require("react/jsx-runtime");
8534
8553
  var METHOD_TONE = { GET: "success", POST: "info", PATCH: "warning", PUT: "warning", DELETE: "danger" };
8535
8554
  function Json({ obj }) {
8536
- return /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("pre", { className: "fd-json", children: JSON.stringify(obj, null, 2) });
8555
+ return /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("pre", { className: "fd-json", children: JSON.stringify(obj, null, 2) });
8537
8556
  }
8538
8557
  function Endpoint({ s, onRequest }) {
8539
- const [tried, setTried] = React53.useState(null);
8558
+ const [tried, setTried] = React54.useState(null);
8540
8559
  const run = async () => {
8541
8560
  setTried("busy");
8542
8561
  const t0 = (window.performance || Date).now();
@@ -8547,50 +8566,50 @@ function Endpoint({ s, onRequest }) {
8547
8566
  setTried({ ms: Math.round((window.performance || Date).now() - t0), error: String(e && e.message || e) });
8548
8567
  }
8549
8568
  };
8550
- return /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Card, { elevation: "flat", padded: false, children: /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-stack", style: { gap: 0 }, children: [
8551
- /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-row", style: { gap: 10, padding: "14px 18px", flexWrap: "wrap" }, children: [
8552
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Badge, { tone: METHOD_TONE[s.method] || "neutral", children: s.method }),
8553
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("code", { className: "fd-mono", style: { fontSize: 12.5, fontWeight: 600, color: "var(--text)", wordBreak: "break-all" }, children: s.path }),
8554
- s.isList ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Badge, { tone: "neutral", icon: "rows", children: "Paged list" }) : null,
8555
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { style: { flex: 1 } }),
8556
- /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
8569
+ return /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Card, { elevation: "flat", padded: false, children: /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-stack", style: { gap: 0 }, children: [
8570
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-row", style: { gap: 10, padding: "14px 18px", flexWrap: "wrap" }, children: [
8571
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Badge, { tone: METHOD_TONE[s.method] || "neutral", children: s.method }),
8572
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("code", { className: "fd-mono", style: { fontSize: 12.5, fontWeight: 600, color: "var(--text)", wordBreak: "break-all" }, children: s.path }),
8573
+ s.isList ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Badge, { tone: "neutral", icon: "rows", children: "Paged list" }) : null,
8574
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { style: { flex: 1 } }),
8575
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
8557
8576
  s.latency[0],
8558
8577
  "\u2013",
8559
8578
  s.latency[1],
8560
8579
  "ms"
8561
8580
  ] }),
8562
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Button, { size: "sm", variant: "secondary", icon: "play", loading: tried === "busy", onClick: run, children: "Try it" })
8581
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Button, { size: "sm", variant: "secondary", icon: "play", loading: tried === "busy", onClick: run, children: "Try it" })
8563
8582
  ] }),
8564
- /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-stack", style: { gap: 14, padding: "0 18px 16px" }, children: [
8565
- /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
8566
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 700 }, children: s.title }),
8567
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: s.purpose }),
8568
- s.usedBy && s.usedBy.length ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: s.usedBy.map((u) => /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Tag, { children: u }, u)) }) : null
8583
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-stack", style: { gap: 14, padding: "0 18px 16px" }, children: [
8584
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
8585
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 700 }, children: s.title }),
8586
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: s.purpose }),
8587
+ s.usedBy && s.usedBy.length ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: s.usedBy.map((u) => /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Tag, { children: u }, u)) }) : null
8569
8588
  ] }),
8570
- /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(280px,1fr))", gap: 12, alignItems: "start" }, children: [
8571
- s.request ? /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
8572
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-overline fd-muted", children: "Request body" }),
8573
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Json, { obj: s.request })
8589
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(280px,1fr))", gap: 12, alignItems: "start" }, children: [
8590
+ s.request ? /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
8591
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-overline fd-muted", children: "Request body" }),
8592
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Json, { obj: s.request })
8574
8593
  ] }) : null,
8575
- s.query ? /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
8576
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-overline fd-muted", children: "Query" }),
8577
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Json, { obj: s.query })
8594
+ s.query ? /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
8595
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-overline fd-muted", children: "Query" }),
8596
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Json, { obj: s.query })
8578
8597
  ] }) : null,
8579
- /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
8580
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-overline fd-muted", children: "Response 200" }),
8581
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Json, { obj: s.response })
8598
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
8599
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-overline fd-muted", children: "Response 200" }),
8600
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Json, { obj: s.response })
8582
8601
  ] })
8583
8602
  ] }),
8584
- s.notes ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Flag, { tone: "info", statement: "Implementation note", cost: s.notes, actions: null }) : null,
8585
- tried && tried !== "busy" ? /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
8586
- /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("span", { className: "fd-row", style: { gap: 8 }, children: [
8587
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-overline fd-muted", children: "Simulated response" }),
8588
- /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)(Badge, { tone: tried.error ? "danger" : "success", icon: "timer", children: [
8603
+ s.notes ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Flag, { tone: "info", statement: "Implementation note", cost: s.notes, actions: null }) : null,
8604
+ tried && tried !== "busy" ? /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
8605
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fd-row", style: { gap: 8 }, children: [
8606
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-overline fd-muted", children: "Simulated response" }),
8607
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)(Badge, { tone: tried.error ? "danger" : "success", icon: "timer", children: [
8589
8608
  tried.ms,
8590
8609
  "ms"
8591
8610
  ] })
8592
8611
  ] }),
8593
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Json, { obj: tried.error ? { error: tried.error } : tried.data })
8612
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Json, { obj: tried.error ? { error: tried.error } : tried.data })
8594
8613
  ] }) : null
8595
8614
  ] })
8596
8615
  ] }) });
@@ -8609,58 +8628,58 @@ function ApiSpecBrowser({
8609
8628
  className = "",
8610
8629
  ...rest
8611
8630
  }) {
8612
- const [q, setQ] = React53.useState("");
8613
- const [method, setMethod] = React53.useState(null);
8614
- const [mod, setMod] = React53.useState(null);
8615
- const [listOnly, setListOnly] = React53.useState(false);
8631
+ const [q, setQ] = React54.useState("");
8632
+ const [method, setMethod] = React54.useState(null);
8633
+ const [mod, setMod] = React54.useState(null);
8634
+ const [listOnly, setListOnly] = React54.useState(false);
8616
8635
  const activeModule = modules && modules.find((m) => m.id === mod);
8617
8636
  const hits = spec.filter((s) => (!method || s.method === method) && (!listOnly || s.isList) && (!activeModule || activeModule.endpoints.indexOf(s.id) >= 0) && (!q || (s.path + " " + s.title + " " + s.purpose + " " + (s.usedBy || []).join(" ")).toLowerCase().includes(q.toLowerCase())));
8618
8637
  const effGroups = groups && groups.length ? groups : [["All endpoints", spec.map((s) => s.id)]];
8619
8638
  const methods = [...new Set(spec.map((s) => s.method))];
8620
8639
  const listCount = spec.filter((s) => s.isList).length;
8621
- return /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 1100 }, ...rest, children: [
8622
- /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
8623
- kicker ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-overline fd-muted", children: kicker }) : null,
8624
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
8625
- lede ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: lede }) : null
8640
+ return /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 1100 }, ...rest, children: [
8641
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
8642
+ kicker ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-overline fd-muted", children: kicker }) : null,
8643
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
8644
+ lede ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: lede }) : null
8626
8645
  ] }),
8627
- modules && modules.length ? /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-stack", style: { gap: 8 }, children: [
8628
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-overline fd-muted", children: "Filter by screen \u2014 every endpoint that screen depends on" }),
8629
- /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
8630
- /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)(Tag, { icon: "stack", selected: !mod, onClick: () => setMod(null), children: [
8646
+ modules && modules.length ? /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-stack", style: { gap: 8 }, children: [
8647
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-overline fd-muted", children: "Filter by screen \u2014 every endpoint that screen depends on" }),
8648
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
8649
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)(Tag, { icon: "stack", selected: !mod, onClick: () => setMod(null), children: [
8631
8650
  "All screens ",
8632
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-mono", children: spec.length })
8651
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-mono", children: spec.length })
8633
8652
  ] }),
8634
- modules.map((m) => /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)(Tag, { icon: m.icon, selected: mod === m.id, onClick: () => setMod(mod === m.id ? null : m.id), children: [
8653
+ modules.map((m) => /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)(Tag, { icon: m.icon, selected: mod === m.id, onClick: () => setMod(mod === m.id ? null : m.id), children: [
8635
8654
  m.label,
8636
8655
  " ",
8637
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-mono", children: m.endpoints.length })
8656
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-mono", children: m.endpoints.length })
8638
8657
  ] }, m.id))
8639
8658
  ] }),
8640
- activeModule ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
8659
+ activeModule ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
8641
8660
  Flag,
8642
8661
  {
8643
8662
  tone: "info",
8644
8663
  statement: activeModule.label + " calls " + activeModule.endpoints.length + " endpoints.",
8645
8664
  cost: "Integration checklist for this screen: " + activeModule.endpoints.join(", ") + ". Wire these and the screen is done.",
8646
- actions: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Button, { size: "sm", variant: "ghost", icon: "x", onClick: () => setMod(null), children: "Show all screens" })
8665
+ actions: /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Button, { size: "sm", variant: "ghost", icon: "x", onClick: () => setMod(null), children: "Show all screens" })
8647
8666
  }
8648
8667
  ) : null
8649
8668
  ] }) : null,
8650
- sourceNote ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Flag, { tone: "info", statement: "Design-first: this page is the spec.", cost: sourceNote, actions: null }) : null,
8651
- /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
8652
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Input, { icon: "magnifying-glass", placeholder: "Find an endpoint, screen, or behavior", value: q, onChange: (e) => setQ(e.target.value), style: { width: 300 } }),
8653
- methods.map((m) => /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)(Tag, { selected: method === m, onClick: () => setMethod(method === m ? null : m), children: [
8669
+ sourceNote ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Flag, { tone: "info", statement: "Design-first: this page is the spec.", cost: sourceNote, actions: null }) : null,
8670
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
8671
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Input, { icon: "magnifying-glass", placeholder: "Find an endpoint, screen, or behavior", value: q, onChange: (e) => setQ(e.target.value), style: { width: 300 } }),
8672
+ methods.map((m) => /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)(Tag, { selected: method === m, onClick: () => setMethod(method === m ? null : m), children: [
8654
8673
  m,
8655
8674
  " ",
8656
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-mono", children: spec.filter((s) => s.method === m).length })
8675
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-mono", children: spec.filter((s) => s.method === m).length })
8657
8676
  ] }, m)),
8658
- listCount ? /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)(Tag, { icon: "rows", selected: listOnly, onClick: () => setListOnly(!listOnly), children: [
8677
+ listCount ? /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)(Tag, { icon: "rows", selected: listOnly, onClick: () => setListOnly(!listOnly), children: [
8659
8678
  "Paged lists ",
8660
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-mono", children: listCount })
8679
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-mono", children: listCount })
8661
8680
  ] }) : null,
8662
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { style: { flex: 1 } }),
8663
- /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
8681
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { style: { flex: 1 } }),
8682
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
8664
8683
  hits.length,
8665
8684
  " of ",
8666
8685
  spec.length,
@@ -8668,31 +8687,31 @@ function ApiSpecBrowser({
8668
8687
  listCount ? " \xB7 " + listCount + " paged" : ""
8669
8688
  ] })
8670
8689
  ] }),
8671
- hits.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Card, { elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: "No endpoint matches those filters." }) }) : effGroups.map(([g, ids]) => {
8690
+ hits.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Card, { elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: "No endpoint matches those filters." }) }) : effGroups.map(([g, ids]) => {
8672
8691
  const items = hits.filter((s) => ids.indexOf(s.id) >= 0);
8673
8692
  if (!items.length) return null;
8674
- return /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-stack", style: { gap: 12 }, children: [
8675
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-label-lg", children: g }),
8676
- items.map((s) => /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Endpoint, { s, onRequest }, s.id))
8693
+ return /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-stack", style: { gap: 12 }, children: [
8694
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-label-lg", children: g }),
8695
+ items.map((s) => /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Endpoint, { s, onRequest }, s.id))
8677
8696
  ] }, g);
8678
8697
  }),
8679
- conventions && conventions.length ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Card, { title: "Cross-cutting conventions", elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("div", { className: "fd-stack", style: { gap: 10 }, children: conventions.map(([k, v]) => /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-row", style: { gap: 12, alignItems: "flex-start" }, children: [
8680
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-overline fd-muted", style: { width: 110, flex: "none", paddingTop: 2 }, children: k }),
8681
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: v })
8698
+ conventions && conventions.length ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Card, { title: "Cross-cutting conventions", elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("div", { className: "fd-stack", style: { gap: 10 }, children: conventions.map(([k, v]) => /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-row", style: { gap: 12, alignItems: "flex-start" }, children: [
8699
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-overline fd-muted", style: { width: 110, flex: "none", paddingTop: 2 }, children: k }),
8700
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: v })
8682
8701
  ] }, k)) }) }) : null,
8683
- openQuestions && openQuestions.length ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Collapsible, { icon: "list-checks", title: "Open questions before implementation", subtitle: openQuestions.length + " unresolved", children: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("div", { className: "fd-stack", style: { gap: 8 }, children: openQuestions.map(([id, question, why]) => /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start", padding: "8px 0", borderTop: "1px solid var(--border)" }, children: [
8684
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Badge, { tone: "danger", children: id }),
8685
- /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("span", { className: "fd-stack", style: { gap: 2, flex: 1 }, children: [
8686
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: question }),
8687
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-body-sm fd-muted", children: why })
8702
+ openQuestions && openQuestions.length ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Collapsible, { icon: "list-checks", title: "Open questions before implementation", subtitle: openQuestions.length + " unresolved", children: /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("div", { className: "fd-stack", style: { gap: 8 }, children: openQuestions.map(([id, question, why]) => /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start", padding: "8px 0", borderTop: "1px solid var(--border)" }, children: [
8703
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Badge, { tone: "danger", children: id }),
8704
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fd-stack", style: { gap: 2, flex: 1 }, children: [
8705
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: question }),
8706
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-body-sm fd-muted", children: why })
8688
8707
  ] })
8689
8708
  ] }, id)) }) }) : null
8690
8709
  ] });
8691
8710
  }
8692
8711
 
8693
8712
  // src/components/platform/ProfilePage.tsx
8694
- var React54 = __toESM(require("react"), 1);
8695
- var import_jsx_runtime80 = require("react/jsx-runtime");
8713
+ var React55 = __toESM(require("react"), 1);
8714
+ var import_jsx_runtime81 = require("react/jsx-runtime");
8696
8715
  function fieldInitialValue(field, user) {
8697
8716
  if (field.value) return field.value(user);
8698
8717
  const raw = user[field.key];
@@ -8727,21 +8746,21 @@ function ProfilePage({
8727
8746
  }) {
8728
8747
  const { user: sessionUser, roles, permissions, saveProfile: saveProfile2 } = useSessionContext();
8729
8748
  const user = userProp || sessionUser;
8730
- const initialFieldValues = React54.useMemo(() => {
8749
+ const initialFieldValues = React55.useMemo(() => {
8731
8750
  const values2 = {};
8732
8751
  for (const field of fields) values2[field.key] = fieldInitialValue(field, user);
8733
8752
  return values2;
8734
8753
  }, [user.id, fields]);
8735
- const initialNotify = React54.useMemo(() => {
8754
+ const initialNotify = React55.useMemo(() => {
8736
8755
  const values2 = {};
8737
8756
  for (const n of notifications) values2[n.key] = !!user.notify?.[n.key];
8738
8757
  return values2;
8739
8758
  }, [user.id, notifications]);
8740
- const [values, setValues] = React54.useState(initialFieldValues);
8741
- const [notify, setNotify] = React54.useState(initialNotify);
8742
- const [saving, setSaving] = React54.useState(false);
8743
- const [saved, setSaved] = React54.useState(false);
8744
- const [prevUserId, setPrevUserId] = React54.useState(user.id);
8759
+ const [values, setValues] = React55.useState(initialFieldValues);
8760
+ const [notify, setNotify] = React55.useState(initialNotify);
8761
+ const [saving, setSaving] = React55.useState(false);
8762
+ const [saved, setSaved] = React55.useState(false);
8763
+ const [prevUserId, setPrevUserId] = React55.useState(user.id);
8745
8764
  if (user.id !== prevUserId) {
8746
8765
  setPrevUserId(user.id);
8747
8766
  setValues(initialFieldValues);
@@ -8778,37 +8797,37 @@ function ProfilePage({
8778
8797
  };
8779
8798
  const displayName = fields.some((f) => f.key === "name") ? values.name || user.name : user.name;
8780
8799
  const fieldGroups = groupFields(fields);
8781
- return /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 860 }, children: [
8782
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
8783
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-overline fd-muted", children: "Account" }),
8784
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("h1", { className: "fd-h1", style: { margin: 0 }, children: "Your profile" }),
8785
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: "How you appear to colleagues and clients across every flytedesk app, and what we send you." })
8800
+ return /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 860 }, children: [
8801
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
8802
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fd-overline fd-muted", children: "Account" }),
8803
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("h1", { className: "fd-h1", style: { margin: 0 }, children: "Your profile" }),
8804
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: "How you appear to colleagues and clients across every flytedesk app, and what we send you." })
8786
8805
  ] }),
8787
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Card, { elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-row", style: { gap: 16, flexWrap: "wrap", alignItems: "flex-start" }, children: [
8788
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Avatar, { name: displayName, size: "lg" }),
8789
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-stack", style: { gap: 4, flex: 1, minWidth: 200 }, children: [
8790
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-h3", style: { margin: 0 }, children: displayName }),
8791
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 4 }, children: [
8792
- roles.map((r) => /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Badge, { tone: r.id === "owner" ? "success" : "neutral", children: r.name }, r.id)),
8793
- user.sso ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Badge, { tone: "info", icon: "shield-check", children: "SSO" }) : null
8806
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Card, { elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fd-row", style: { gap: 16, flexWrap: "wrap", alignItems: "flex-start" }, children: [
8807
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Avatar, { name: displayName, size: "lg" }),
8808
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fd-stack", style: { gap: 4, flex: 1, minWidth: 200 }, children: [
8809
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fd-h3", style: { margin: 0 }, children: displayName }),
8810
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 4 }, children: [
8811
+ roles.map((r) => /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Badge, { tone: r.id === "owner" ? "success" : "neutral", children: r.name }, r.id)),
8812
+ user.sso ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Badge, { tone: "info", icon: "shield-check", children: "SSO" }) : null
8794
8813
  ] })
8795
8814
  ] }),
8796
- onChangePhoto ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Button, { variant: "secondary", size: "sm", icon: "image", onClick: onChangePhoto, children: "Change photo" }) : null
8815
+ onChangePhoto ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Button, { variant: "secondary", size: "sm", icon: "image", onClick: onChangePhoto, children: "Change photo" }) : null
8797
8816
  ] }) }),
8798
- fieldGroups.map(({ group, description, fields: groupFieldDefs }) => /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
8817
+ fieldGroups.map(({ group, description, fields: groupFieldDefs }) => /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
8799
8818
  Card,
8800
8819
  {
8801
- title: description ? /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fd-stack", style: { gap: 2 }, children: [
8802
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { children: group }),
8803
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: description })
8820
+ title: description ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("span", { className: "fd-stack", style: { gap: 2 }, children: [
8821
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { children: group }),
8822
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: description })
8804
8823
  ] }) : group,
8805
8824
  elevation: "flat",
8806
- children: /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-stack", style: { gap: 14 }, children: [
8807
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: groupFieldDefs.filter((f) => f.type !== "textarea").map((field) => {
8825
+ children: /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fd-stack", style: { gap: 14 }, children: [
8826
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: groupFieldDefs.filter((f) => f.type !== "textarea").map((field) => {
8808
8827
  const help = typeof field.help === "function" ? field.help(user) : field.help;
8809
8828
  const readOnly = field.readOnly || field.type === "readonly";
8810
8829
  if (field.type === "select") {
8811
- return /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
8830
+ return /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
8812
8831
  Select,
8813
8832
  {
8814
8833
  label: field.label,
@@ -8822,7 +8841,7 @@ function ProfilePage({
8822
8841
  field.key
8823
8842
  );
8824
8843
  }
8825
- return /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
8844
+ return /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
8826
8845
  Input,
8827
8846
  {
8828
8847
  label: field.label,
@@ -8838,7 +8857,7 @@ function ProfilePage({
8838
8857
  }) }),
8839
8858
  groupFieldDefs.filter((f) => f.type === "textarea").map((field) => {
8840
8859
  const help = typeof field.help === "function" ? field.help(user) : field.help;
8841
- return /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
8860
+ return /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
8842
8861
  Textarea,
8843
8862
  {
8844
8863
  label: field.label,
@@ -8858,16 +8877,16 @@ function ProfilePage({
8858
8877
  group
8859
8878
  )),
8860
8879
  extra,
8861
- notifications.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Card, { title: "Notifications", elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("div", { className: "fd-stack", style: { gap: 14 }, children: notifications.map((n) => /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Switch, { checked: !!notify[n.key], onChange: () => toggleNotify(n.key), label: n.label, description: n.description }, n.key)) }) }) : null,
8862
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)(
8880
+ notifications.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Card, { title: "Notifications", elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("div", { className: "fd-stack", style: { gap: 14 }, children: notifications.map((n) => /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Switch, { checked: !!notify[n.key], onChange: () => toggleNotify(n.key), label: n.label, description: n.description }, n.key)) }) }) : null,
8881
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)(
8863
8882
  Card,
8864
8883
  {
8865
- title: /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fd-stack", style: { gap: 2 }, children: [
8866
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { children: "Access" }),
8867
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "What your roles grant you" })
8884
+ title: /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("span", { className: "fd-stack", style: { gap: 2 }, children: [
8885
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { children: "Access" }),
8886
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "What your roles grant you" })
8868
8887
  ] }),
8869
8888
  elevation: "flat",
8870
- action: /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
8889
+ action: /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
8871
8890
  Button,
8872
8891
  {
8873
8892
  size: "sm",
@@ -8878,39 +8897,39 @@ function ProfilePage({
8878
8897
  }
8879
8898
  ),
8880
8899
  children: [
8881
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-stack", style: { gap: 0 }, children: [
8882
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(CardRow, { label: "Roles", children: roles.map((r) => r.name).join(", ") || "None" }),
8883
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)(CardRow, { label: "Permissions", children: [
8900
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fd-stack", style: { gap: 0 }, children: [
8901
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(CardRow, { label: "Roles", children: roles.map((r) => r.name).join(", ") || "None" }),
8902
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)(CardRow, { label: "Permissions", children: [
8884
8903
  permissions.length,
8885
8904
  " granted"
8886
8905
  ] }),
8887
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(CardRow, { label: "Member since", children: user.joined || "\u2014" })
8906
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(CardRow, { label: "Member since", children: user.joined || "\u2014" })
8888
8907
  ] }),
8889
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("p", { className: "fd-body-sm fd-muted", style: { margin: "12px 0 0" }, children: "You cannot change your own roles \u2014 that is the point of them. An administrator manages roles from Admin \u2192 Users." })
8908
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("p", { className: "fd-body-sm fd-muted", style: { margin: "12px 0 0" }, children: "You cannot change your own roles \u2014 that is the point of them. An administrator manages roles from Admin \u2192 Users." })
8890
8909
  ]
8891
8910
  }
8892
8911
  ),
8893
- sessions ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
8912
+ sessions ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
8894
8913
  Card,
8895
8914
  {
8896
8915
  title: "Signed-in devices",
8897
8916
  elevation: "flat",
8898
- action: /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Button, { size: "sm", variant: "ghost", icon: "sign-out", onClick: onSignOutEverywhere, children: "Sign out everywhere" }),
8899
- children: /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("div", { className: "fd-stack", style: { gap: 0 }, children: sessions.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: "No other signed-in devices." }) : sessions.map((s) => /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-row", style: { gap: 12, padding: "10px 0", borderTop: "1px solid var(--border)", flexWrap: "wrap" }, children: [
8900
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("i", { className: "ph ph-device-mobile", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
8901
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fd-stack", style: { gap: 1, flex: 1, minWidth: 160 }, children: [
8902
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: s.device }),
8903
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
8917
+ action: /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Button, { size: "sm", variant: "ghost", icon: "sign-out", onClick: onSignOutEverywhere, children: "Sign out everywhere" }),
8918
+ children: /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("div", { className: "fd-stack", style: { gap: 0 }, children: sessions.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: "No other signed-in devices." }) : sessions.map((s) => /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fd-row", style: { gap: 12, padding: "10px 0", borderTop: "1px solid var(--border)", flexWrap: "wrap" }, children: [
8919
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-device-mobile", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
8920
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("span", { className: "fd-stack", style: { gap: 1, flex: 1, minWidth: 160 }, children: [
8921
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: s.device }),
8922
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
8904
8923
  s.where,
8905
8924
  " \xB7 ",
8906
8925
  s.when
8907
8926
  ] })
8908
8927
  ] }),
8909
- s.current ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Badge, { tone: "success", dot: true, children: "This device" }) : /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Button, { size: "sm", variant: "ghost", children: "Revoke" })
8928
+ s.current ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Badge, { tone: "success", dot: true, children: "This device" }) : /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Button, { size: "sm", variant: "ghost", children: "Revoke" })
8910
8929
  ] }, s.id)) })
8911
8930
  }
8912
8931
  ) : null,
8913
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-row", style: {
8932
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fd-row", style: {
8914
8933
  gap: 10,
8915
8934
  flexWrap: "wrap",
8916
8935
  position: "sticky",
@@ -8921,16 +8940,16 @@ function ProfilePage({
8921
8940
  border: "1px solid var(--border)",
8922
8941
  boxShadow: "0 -4px 16px rgba(11,13,17,.06)"
8923
8942
  }, children: [
8924
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 600, flex: 1 }, children: saved ? "Saved." : dirty ? "Unsaved changes" : "No pending changes" }),
8925
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Button, { size: "sm", variant: "ghost", disabled: !dirty || saving, onClick: discard, children: "Discard" }),
8926
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Button, { size: "sm", icon: "check", disabled: !dirty || !canSave, loading: saving, onClick: save, children: "Save changes" })
8943
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 600, flex: 1 }, children: saved ? "Saved." : dirty ? "Unsaved changes" : "No pending changes" }),
8944
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Button, { size: "sm", variant: "ghost", disabled: !dirty || saving, onClick: discard, children: "Discard" }),
8945
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Button, { size: "sm", icon: "check", disabled: !dirty || !canSave, loading: saving, onClick: save, children: "Save changes" })
8927
8946
  ] })
8928
8947
  ] });
8929
8948
  }
8930
8949
 
8931
8950
  // src/components/platform/SessionScreen.tsx
8932
- var React55 = __toESM(require("react"), 1);
8933
- var import_jsx_runtime81 = require("react/jsx-runtime");
8951
+ var React56 = __toESM(require("react"), 1);
8952
+ var import_jsx_runtime82 = require("react/jsx-runtime");
8934
8953
  var COPY = {
8935
8954
  "signing-in": { busy: "Signing you in\u2026" },
8936
8955
  "session-expired": { busy: "Your session expired \u2014 signing you back in\u2026" },
@@ -8943,28 +8962,28 @@ function SessionScreen({ kind, error, onRetry, productName }) {
8943
8962
  const copy = COPY[kind];
8944
8963
  const busyMessage = "busy" in copy ? copy.busy : null;
8945
8964
  const failureTitle = "failure" in copy ? copy.failure : null;
8946
- const [announced, setAnnounced] = React55.useState("");
8947
- React55.useEffect(() => {
8965
+ const [announced, setAnnounced] = React56.useState("");
8966
+ React56.useEffect(() => {
8948
8967
  setAnnounced(busyMessage ?? "");
8949
8968
  }, [busyMessage]);
8950
- const titleRef = React55.useRef(null);
8969
+ const titleRef = React56.useRef(null);
8951
8970
  const failed = failureTitle !== null;
8952
- React55.useEffect(() => {
8971
+ React56.useEffect(() => {
8953
8972
  titleRef.current?.focus({ preventScroll: true });
8954
8973
  }, [failed]);
8955
- return /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("main", { className: "fd-session-screen", children: /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fd-session-screen-inner", children: [
8956
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("div", { className: "fd-session-screen-mark", "data-theme": "dark", children: /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(FlytedeskMark, { size: "lg" }) }),
8957
- /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fd-session-screen-frame", children: [
8958
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("div", { className: "fd-session-screen-stripe" }),
8959
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Card, { children: /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fd-session-screen-body", children: [
8960
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("h1", { ref: titleRef, tabIndex: -1, className: "fd-h3 fd-session-screen-title", children: productName }),
8961
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("div", { role: "status", "aria-live": "polite", className: "fd-session-screen-status", children: busyMessage !== null ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)(import_jsx_runtime81.Fragment, { children: [
8962
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fd-spinner fd-spinner-lg fd-session-screen-spinner", "aria-hidden": "true" }),
8963
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("p", { className: "fd-body fd-session-screen-message", children: announced })
8974
+ return /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("main", { className: "fd-session-screen", children: /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-session-screen-inner", children: [
8975
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fd-session-screen-mark", "data-theme": "dark", children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(FlytedeskMark, { size: "lg" }) }),
8976
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-session-screen-frame", children: [
8977
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fd-session-screen-stripe" }),
8978
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Card, { children: /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-session-screen-body", children: [
8979
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("h1", { ref: titleRef, tabIndex: -1, className: "fd-h3 fd-session-screen-title", children: productName }),
8980
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { role: "status", "aria-live": "polite", className: "fd-session-screen-status", children: busyMessage !== null ? /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)(import_jsx_runtime82.Fragment, { children: [
8981
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fd-spinner fd-spinner-lg fd-session-screen-spinner", "aria-hidden": "true" }),
8982
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("p", { className: "fd-body fd-session-screen-message", children: announced })
8964
8983
  ] }) : null }),
8965
- failureTitle !== null ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fd-session-screen-failure", children: [
8966
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Banner, { tone: "danger", title: failureTitle, detail: error ?? void 0 }),
8967
- onRetry !== null ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Button, { variant: "primary", block: true, onClick: onRetry, children: "Try again" }) : null
8984
+ failureTitle !== null ? /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-session-screen-failure", children: [
8985
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Banner, { tone: "danger", title: failureTitle, detail: error ?? void 0 }),
8986
+ onRetry !== null ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Button, { variant: "primary", block: true, onClick: onRetry, children: "Try again" }) : null
8968
8987
  ] }) : null
8969
8988
  ] }) })
8970
8989
  ] })
@@ -8972,10 +8991,10 @@ function SessionScreen({ kind, error, onRetry, productName }) {
8972
8991
  }
8973
8992
 
8974
8993
  // src/components/platform/RoadmapTimeline.tsx
8975
- var React58 = __toESM(require("react"), 1);
8994
+ var React59 = __toESM(require("react"), 1);
8976
8995
 
8977
8996
  // src/kits/session.ts
8978
- var React56 = __toESM(require("react"), 1);
8997
+ var React57 = __toESM(require("react"), 1);
8979
8998
  var PERMISSION_CATALOG = [
8980
8999
  { group: "Plans", items: [
8981
9000
  { key: "plan.view", label: "View plans", detail: "Read any plan in the workspace." },
@@ -10542,8 +10561,8 @@ function roadmap(overrides) {
10542
10561
  };
10543
10562
  }
10544
10563
  function useSession() {
10545
- const [s, setS] = React56.useState(getSession);
10546
- React56.useEffect(() => subscribe(setS), []);
10564
+ const [s, setS] = React57.useState(getSession);
10565
+ React57.useEffect(() => subscribe(setS), []);
10547
10566
  return s;
10548
10567
  }
10549
10568
  var SessionKit = {
@@ -10576,7 +10595,7 @@ var SessionKit = {
10576
10595
  };
10577
10596
  function DemoSessionProvider({ children }) {
10578
10597
  const session = useSession();
10579
- const value = React56.useMemo(
10598
+ const value = React57.useMemo(
10580
10599
  () => ({
10581
10600
  user: session.user,
10582
10601
  roles: session.roles,
@@ -10592,11 +10611,11 @@ function DemoSessionProvider({ children }) {
10592
10611
  }),
10593
10612
  [session]
10594
10613
  );
10595
- return React56.createElement(SessionProvider, { value }, children);
10614
+ return React57.createElement(SessionProvider, { value }, children);
10596
10615
  }
10597
10616
 
10598
10617
  // src/kits/runtime.ts
10599
- var React57 = __toESM(require("react"), 1);
10618
+ var React58 = __toESM(require("react"), 1);
10600
10619
  var WIRED_ENDPOINTS = [
10601
10620
  // Nothing yet. Every id below would come from a real service:
10602
10621
  // "plan.get", "placements.list", …
@@ -10767,8 +10786,8 @@ var RuntimeKit = {
10767
10786
  };
10768
10787
  RuntimeKit.declare(FEATURE_NEEDS);
10769
10788
  function useRuntimeMode() {
10770
- const [m, setM] = React57.useState(RuntimeKit.getMode());
10771
- React57.useEffect(() => RuntimeKit.subscribe(setM), []);
10789
+ const [m, setM] = React58.useState(RuntimeKit.getMode());
10790
+ React58.useEffect(() => RuntimeKit.subscribe(setM), []);
10772
10791
  return m;
10773
10792
  }
10774
10793
  function useFeatureStatus(key) {
@@ -10787,7 +10806,7 @@ var UseRuntimeMode = useRuntimeMode;
10787
10806
  var UseFeatureStatus = useFeatureStatus;
10788
10807
 
10789
10808
  // src/components/platform/RoadmapTimeline.tsx
10790
- var import_jsx_runtime82 = require("react/jsx-runtime");
10809
+ var import_jsx_runtime83 = require("react/jsx-runtime");
10791
10810
  var STATUS = {
10792
10811
  shipped: { tone: "success", icon: "check-circle", label: "Wired" },
10793
10812
  next: { tone: "warning", icon: "traffic-cone", label: "Not wired" },
@@ -10802,45 +10821,45 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
10802
10821
  const s = STATUS[item.status] || STATUS.planned;
10803
10822
  const deps = (item.dependsOn || []).map((k) => byKey[k]).filter(Boolean);
10804
10823
  const blocking = deps.filter((d) => !d.implemented);
10805
- return /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Card, { elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
10806
- /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
10807
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fd-body", style: { fontWeight: 700, flex: 1, minWidth: 140 }, children: item.label }),
10808
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Badge, { tone: "neutral", icon: PROJECT_ICON[item.project] || "squares-four", children: item.project }),
10809
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Badge, { tone: s.tone, icon: s.icon, children: s.label })
10824
+ return /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(Card, { elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
10825
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
10826
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fd-body", style: { fontWeight: 700, flex: 1, minWidth: 140 }, children: item.label }),
10827
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(Badge, { tone: "neutral", icon: PROJECT_ICON[item.project] || "squares-four", children: item.project }),
10828
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(Badge, { tone: s.tone, icon: s.icon, children: s.label })
10810
10829
  ] }),
10811
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: item.description }),
10812
- item.backend ? /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start" }, children: [
10813
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fd-overline fd-muted", style: { width: 62, flex: "none", paddingTop: 2 }, children: "Backend" }),
10814
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fd-body-sm", style: { flex: 1, textWrap: "pretty" }, children: item.backend })
10830
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: item.description }),
10831
+ item.backend ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start" }, children: [
10832
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fd-overline fd-muted", style: { width: 62, flex: "none", paddingTop: 2 }, children: "Backend" }),
10833
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fd-body-sm", style: { flex: 1, textWrap: "pretty" }, children: item.backend })
10815
10834
  ] }) : null,
10816
- /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
10817
- item.effort ? /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
10818
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-hourglass-medium" }),
10835
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
10836
+ item.effort ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
10837
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-hourglass-medium" }),
10819
10838
  " ",
10820
10839
  item.effort
10821
10840
  ] }) : null,
10822
- /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
10823
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-user" }),
10841
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
10842
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-user" }),
10824
10843
  " ",
10825
10844
  item.owner
10826
10845
  ] }),
10827
- item.screen ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Badge, { tone: "neutral", icon: "browser", children: "screen" }) : null,
10828
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { style: { flex: 1 } }),
10829
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
10846
+ item.screen ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(Badge, { tone: "neutral", icon: "browser", children: "screen" }) : null,
10847
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { style: { flex: 1 } }),
10848
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
10830
10849
  "button",
10831
10850
  {
10832
10851
  type: "button",
10833
10852
  onClick: () => onOpenFlag && onOpenFlag(item.key),
10834
10853
  style: { all: "unset", cursor: "pointer", display: "inline-flex", alignItems: "center", gap: 5 },
10835
- children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("code", { className: "fd-mono", style: { fontSize: 11, color: "var(--brand)" }, children: item.key })
10854
+ children: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("code", { className: "fd-mono", style: { fontSize: 11, color: "var(--brand)" }, children: item.key })
10836
10855
  }
10837
10856
  )
10838
10857
  ] }),
10839
- deps.length ? /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 6, borderTop: "1px solid var(--border)" }, children: [
10840
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fd-overline fd-muted", style: { paddingTop: 3 }, children: "After" }),
10841
- deps.map((d) => /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Tag, { icon: d.implemented ? "check" : "clock", children: d.label }, d.key))
10858
+ deps.length ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 6, borderTop: "1px solid var(--border)" }, children: [
10859
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fd-overline fd-muted", style: { paddingTop: 3 }, children: "After" }),
10860
+ deps.map((d) => /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(Tag, { icon: d.implemented ? "check" : "clock", children: d.label }, d.key))
10842
10861
  ] }) : null,
10843
- blocking.length && !item.implemented ? /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("span", { className: "fd-body-sm", style: { color: "var(--warn-text)" }, children: [
10862
+ blocking.length && !item.implemented ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { className: "fd-body-sm", style: { color: "var(--warn-text)" }, children: [
10844
10863
  "Blocked until ",
10845
10864
  blocking.map((d) => d.label).join(" and "),
10846
10865
  " ",
@@ -10851,12 +10870,12 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
10851
10870
  }
10852
10871
  function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
10853
10872
  const session = SessionKit.useSession();
10854
- const [project, setProject] = React58.useState("");
10855
- const [q, setQ] = React58.useState("");
10856
- const scrollRef = React58.useRef(null);
10857
- const nowRef = React58.useRef(null);
10858
- const rm = React58.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
10859
- const byKey = React58.useMemo(() => {
10873
+ const [project, setProject] = React59.useState("");
10874
+ const [q, setQ] = React59.useState("");
10875
+ const scrollRef = React59.useRef(null);
10876
+ const nowRef = React59.useRef(null);
10877
+ const rm = React59.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
10878
+ const byKey = React59.useMemo(() => {
10860
10879
  const m = {};
10861
10880
  rm.items.forEach((i) => {
10862
10881
  m[i.key] = i;
@@ -10865,7 +10884,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
10865
10884
  }, [rm]);
10866
10885
  const items = rm.items.filter((i) => (!project || i.project === project) && (!q || (i.label + " " + i.description + " " + (i.backend || "") + " " + i.key).toLowerCase().includes(q.toLowerCase())));
10867
10886
  const projects = [...new Set(rm.items.map((i) => i.project))];
10868
- React58.useEffect(() => {
10887
+ React59.useEffect(() => {
10869
10888
  let raf1 = 0, raf2 = 0;
10870
10889
  const place = () => {
10871
10890
  const box = scrollRef.current, mark = nowRef.current;
@@ -10893,23 +10912,23 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
10893
10912
  }, 0);
10894
10913
  const nextPhase = items.find((i) => !i.implemented);
10895
10914
  let lastPhase = null;
10896
- return /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-stack", style: { gap: 16, maxWidth: 1e3 }, children: [
10897
- /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
10898
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fd-overline fd-muted", children: "Architecture" }),
10899
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
10900
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: lede || "Every screen and feature in these tools is already designed and working against a simulated backend. This is the plan for connecting them to the real one \u2014 so the only work described here is server work." })
10915
+ return /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fd-stack", style: { gap: 16, maxWidth: 1e3 }, children: [
10916
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
10917
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fd-overline fd-muted", children: "Architecture" }),
10918
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
10919
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: lede || "Every screen and feature in these tools is already designed and working against a simulated backend. This is the plan for connecting them to the real one \u2014 so the only work described here is server work." })
10901
10920
  ] }),
10902
- /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-grid-stats is-thin", children: [
10903
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(StatTile, { compact: true, label: "Wired", value: String(rm.shipped), sub: "of " + rm.items.length + " features" }),
10904
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(StatTile, { compact: true, label: "Remaining", value: String(rm.remaining), sub: "backend work" }),
10905
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(StatTile, { compact: true, label: "Est. effort", value: days ? days + " days" : "\u2014", sub: "sum of estimates, not calendar" }),
10906
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(StatTile, { compact: true, label: "Up next", value: nextPhase ? "Phase " + nextPhase.phase : "\u2014", sub: nextPhase ? nextPhase.phaseName : "all wired" })
10921
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fd-grid-stats is-thin", children: [
10922
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(StatTile, { compact: true, label: "Wired", value: String(rm.shipped), sub: "of " + rm.items.length + " features" }),
10923
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(StatTile, { compact: true, label: "Remaining", value: String(rm.remaining), sub: "backend work" }),
10924
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(StatTile, { compact: true, label: "Est. effort", value: days ? days + " days" : "\u2014", sub: "sum of estimates, not calendar" }),
10925
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(StatTile, { compact: true, label: "Up next", value: nextPhase ? "Phase " + nextPhase.phase : "\u2014", sub: nextPhase ? nextPhase.phaseName : "all wired" })
10907
10926
  ] }),
10908
- /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
10909
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Input, { icon: "magnifying-glass", placeholder: "Find a feature or a piece of backend work", value: q, onChange: (e) => setQ(e.target.value), style: { width: 300 } }),
10910
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Select, { placeholder: "All projects", value: project, onChange: (e) => setProject(e.target.value), options: projects, style: { width: 190 } }),
10911
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { style: { flex: 1 } }),
10912
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
10927
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
10928
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(Input, { icon: "magnifying-glass", placeholder: "Find a feature or a piece of backend work", value: q, onChange: (e) => setQ(e.target.value), style: { width: 300 } }),
10929
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(Select, { placeholder: "All projects", value: project, onChange: (e) => setProject(e.target.value), options: projects, style: { width: 190 } }),
10930
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { style: { flex: 1 } }),
10931
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
10913
10932
  Button,
10914
10933
  {
10915
10934
  size: "sm",
@@ -10923,7 +10942,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
10923
10942
  }
10924
10943
  )
10925
10944
  ] }),
10926
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
10945
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
10927
10946
  Flag,
10928
10947
  {
10929
10948
  tone: "info",
@@ -10932,60 +10951,60 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
10932
10951
  actions: null
10933
10952
  }
10934
10953
  ),
10935
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fd-rm", children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fd-rm-scroll", ref: scrollRef, children: /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-rm-track", children: [
10936
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fd-rm-spine", children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fd-rm-spine-done", style: { height: items.length ? 100 * shippedShown / items.length + "%" : "0%" } }) }),
10954
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: "fd-rm", children: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: "fd-rm-scroll", ref: scrollRef, children: /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fd-rm-track", children: [
10955
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fd-rm-spine", children: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fd-rm-spine-done", style: { height: items.length ? 100 * shippedShown / items.length + "%" : "0%" } }) }),
10937
10956
  items.map((item, n) => {
10938
10957
  const showPhase = item.phase !== lastPhase;
10939
10958
  lastPhase = item.phase;
10940
10959
  const inPhase = items.filter((i) => i.phase === item.phase).length;
10941
10960
  const isBoundary = n === firstPending;
10942
- return /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)(React58.Fragment, { children: [
10943
- showPhase ? /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-rm-era", children: [
10944
- /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
10945
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
10946
- item.phase === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("span", { className: "fd-mono", style: { opacity: 0.7, fontWeight: 400 }, children: [
10961
+ return /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)(React59.Fragment, { children: [
10962
+ showPhase ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fd-rm-era", children: [
10963
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
10964
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
10965
+ item.phase === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { className: "fd-mono", style: { opacity: 0.7, fontWeight: 400 }, children: [
10947
10966
  fmtDate(item.phaseStart),
10948
10967
  " \u2013 ",
10949
10968
  fmtDate(item.date)
10950
10969
  ] }),
10951
- /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("span", { style: { opacity: 0.7, fontWeight: 400 }, children: [
10970
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { style: { opacity: 0.7, fontWeight: 400 }, children: [
10952
10971
  "\xB7 ",
10953
10972
  inPhase,
10954
10973
  " feature",
10955
10974
  inPhase === 1 ? "" : "s"
10956
10975
  ] })
10957
10976
  ] }),
10958
- item.phaseWhy ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("p", { className: "fd-rm-era-why", children: item.phaseWhy }) : null
10977
+ item.phaseWhy ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("p", { className: "fd-rm-era-why", children: item.phaseWhy }) : null
10959
10978
  ] }) : null,
10960
- isBoundary ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fd-rm-now", ref: nowRef, children: /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("span", { className: "fd-rm-now-pill", children: [
10961
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-map-pin" }),
10979
+ isBoundary ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: "fd-rm-now", ref: nowRef, children: /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { className: "fd-rm-now-pill", children: [
10980
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-map-pin" }),
10962
10981
  " You are here \u2014 everything above is wired"
10963
10982
  ] }) }) : null,
10964
- /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-rm-row", children: [
10965
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fd-rm-dot " + (item.implemented ? "is-shipped" : item.status === "next" ? "is-next" : "") }),
10966
- /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-rm-date", children: [
10983
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fd-rm-row", children: [
10984
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fd-rm-dot " + (item.implemented ? "is-shipped" : item.status === "next" ? "is-next" : "") }),
10985
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fd-rm-date", children: [
10967
10986
  fmtDate(item.date),
10968
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("br", {}),
10969
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { style: { opacity: 0.75 }, children: item.implemented ? "shipped" : "phase " + item.phase })
10987
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("br", {}),
10988
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { style: { opacity: 0.75 }, children: item.implemented ? "shipped" : "phase " + item.phase })
10970
10989
  ] }),
10971
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(RoadmapCard, { item, byKey, onOpenFlag })
10990
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(RoadmapCard, { item, byKey, onOpenFlag })
10972
10991
  ] })
10973
10992
  ] }, item.key);
10974
10993
  }),
10975
- !items.length ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("p", { className: "fd-body-sm fd-muted", children: "Nothing matches that filter." }) : null
10994
+ !items.length ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("p", { className: "fd-body-sm fd-muted", children: "Nothing matches that filter." }) : null
10976
10995
  ] }) }) }),
10977
- /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: [
10996
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: [
10978
10997
  "Derived from the feature-flag registry \u2014 each entry's status is its flag's ",
10979
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("code", { className: "fd-mono", children: "implemented" }),
10998
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("code", { className: "fd-mono", children: "implemented" }),
10980
10999
  " field, so this page cannot drift from what the apps actually do."
10981
11000
  ] })
10982
11001
  ] });
10983
11002
  }
10984
11003
 
10985
11004
  // src/components/platform/ComingSoon.tsx
10986
- var React59 = __toESM(require("react"), 1);
11005
+ var React60 = __toESM(require("react"), 1);
10987
11006
  var import_react_dom7 = require("react-dom");
10988
- var import_jsx_runtime83 = require("react/jsx-runtime");
11007
+ var import_jsx_runtime84 = require("react/jsx-runtime");
10989
11008
  var BYPASS_STORE = "fd.soon.bypass.v1";
10990
11009
  function readBypassed() {
10991
11010
  try {
@@ -11001,8 +11020,8 @@ function writeBypassed(list) {
11001
11020
  }
11002
11021
  }
11003
11022
  function useBypass(key) {
11004
- const [on, setOn] = React59.useState(() => !!key && readBypassed().indexOf(key) >= 0);
11005
- React59.useEffect(() => {
11023
+ const [on, setOn] = React60.useState(() => !!key && readBypassed().indexOf(key) >= 0);
11024
+ React60.useEffect(() => {
11006
11025
  setOn(!!key && readBypassed().indexOf(key) >= 0);
11007
11026
  }, [key]);
11008
11027
  const set = (next) => {
@@ -11015,43 +11034,43 @@ function useBypass(key) {
11015
11034
  return [on, set];
11016
11035
  }
11017
11036
  function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass }) {
11018
- return /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)(import_jsx_runtime83.Fragment, { children: [
11019
- /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { className: "fd-soon-badge", children: [
11020
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
11037
+ return /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(import_jsx_runtime84.Fragment, { children: [
11038
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("span", { className: "fd-soon-badge", children: [
11039
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
11021
11040
  label
11022
11041
  ] }),
11023
- detail ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fd-soon-detail", children: detail }) : null,
11024
- backend ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { className: "fd-soon-backend", children: [
11025
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fd-overline", children: "Needs" }),
11042
+ detail ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-soon-detail", children: detail }) : null,
11043
+ backend ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("span", { className: "fd-soon-backend", children: [
11044
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-overline", children: "Needs" }),
11026
11045
  " ",
11027
11046
  backend
11028
11047
  ] }) : null,
11029
- eta || effort || onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { className: "fd-soon-meta", children: [
11030
- eta ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { children: [
11031
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }),
11048
+ eta || effort || onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("span", { className: "fd-soon-meta", children: [
11049
+ eta ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("span", { children: [
11050
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }),
11032
11051
  " ",
11033
11052
  eta
11034
11053
  ] }) : null,
11035
- effort ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { children: [
11036
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-hourglass-medium", "aria-hidden": "true" }),
11054
+ effort ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("span", { children: [
11055
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-hourglass-medium", "aria-hidden": "true" }),
11037
11056
  " ",
11038
11057
  effort
11039
11058
  ] }) : null,
11040
- onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
11059
+ onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
11041
11060
  "See the roadmap ",
11042
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
11061
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
11043
11062
  ] }) : null
11044
11063
  ] }) : null,
11045
- allowed ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("button", { type: "button", className: "fd-soon-view", onClick: onBypass, children: [
11046
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-eye", "aria-hidden": "true" }),
11064
+ allowed ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("button", { type: "button", className: "fd-soon-view", onClick: onBypass, children: [
11065
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-eye", "aria-hidden": "true" }),
11047
11066
  " View and use it anyway"
11048
11067
  ] }) : null
11049
11068
  ] });
11050
11069
  }
11051
11070
  function useHoverCard(open2) {
11052
- const anchor = React59.useRef(null);
11053
- const [pos, setPos] = React59.useState(null);
11054
- React59.useLayoutEffect(() => {
11071
+ const anchor = React60.useRef(null);
11072
+ const [pos, setPos] = React60.useState(null);
11073
+ React60.useLayoutEffect(() => {
11055
11074
  if (!open2 || !anchor.current) {
11056
11075
  setPos(null);
11057
11076
  return;
@@ -11103,9 +11122,9 @@ function ComingSoon({
11103
11122
  const tip = [label, detail, backend ? "Needs " + backend : null, eta ? "ETA " + eta : null, effort].filter(Boolean).join(" \xB7 ");
11104
11123
  if (inline) {
11105
11124
  if (allowed && bypassed) {
11106
- return /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { className: ["fd-soon-inline-on", className].filter(Boolean).join(" "), ...rest, children: [
11125
+ return /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("span", { className: ["fd-soon-inline-on", className].filter(Boolean).join(" "), ...rest, children: [
11107
11126
  children,
11108
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
11127
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
11109
11128
  "button",
11110
11129
  {
11111
11130
  type: "button",
@@ -11113,12 +11132,12 @@ function ComingSoon({
11113
11132
  title: "Unwired \u2014 writes go to the simulated backend. " + tip + " Click to re-blur.",
11114
11133
  onClick: () => setBypassed(false),
11115
11134
  "aria-label": "Re-blur this unwired feature",
11116
- children: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
11135
+ children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
11117
11136
  }
11118
11137
  )
11119
11138
  ] });
11120
11139
  }
11121
- return /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
11140
+ return /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
11122
11141
  InlineSoon,
11123
11142
  {
11124
11143
  label,
@@ -11138,20 +11157,20 @@ function ComingSoon({
11138
11157
  );
11139
11158
  }
11140
11159
  if (allowed && bypassed) {
11141
- return /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, ...rest, children: [
11142
- /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fd-soon-bar", role: "status", children: [
11143
- /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { className: "fd-soon-badge", children: [
11144
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
11160
+ return /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, ...rest, children: [
11161
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: "fd-soon-bar", role: "status", children: [
11162
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("span", { className: "fd-soon-badge", children: [
11163
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
11145
11164
  "Unwired feature \u2014 you are using it anyway"
11146
11165
  ] }),
11147
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fd-soon-bar-detail", children: "Every action here writes to the simulated backend, so nothing you do persists beyond this session." }),
11148
- /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { className: "fd-soon-bar-actions", children: [
11149
- onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
11166
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-soon-bar-detail", children: "Every action here writes to the simulated backend, so nothing you do persists beyond this session." }),
11167
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("span", { className: "fd-soon-bar-actions", children: [
11168
+ onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
11150
11169
  "Roadmap ",
11151
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
11170
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
11152
11171
  ] }) : null,
11153
- /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => setBypassed(false), children: [
11154
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-eye-slash", "aria-hidden": "true" }),
11172
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => setBypassed(false), children: [
11173
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-eye-slash", "aria-hidden": "true" }),
11155
11174
  " Re-blur"
11156
11175
  ] })
11157
11176
  ] })
@@ -11159,10 +11178,10 @@ function ComingSoon({
11159
11178
  children
11160
11179
  ] });
11161
11180
  }
11162
- return /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: ["fd-soon", className].filter(Boolean).join(" "), style: minHeight ? { minHeight } : void 0, ...rest, children: [
11163
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: "fd-soon-under", style: { filter: "blur(" + blur + "px) saturate(.62)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
11164
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: "fd-soon-veil" }),
11165
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: "fd-soon-note", role: "note", children: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
11181
+ return /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: ["fd-soon", className].filter(Boolean).join(" "), style: minHeight ? { minHeight } : void 0, ...rest, children: [
11182
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("div", { className: "fd-soon-under", style: { filter: "blur(" + blur + "px) saturate(.62)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
11183
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("div", { className: "fd-soon-veil" }),
11184
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("div", { className: "fd-soon-note", role: "note", children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
11166
11185
  SoonCard,
11167
11186
  {
11168
11187
  label,
@@ -11178,12 +11197,12 @@ function ComingSoon({
11178
11197
  ] });
11179
11198
  }
11180
11199
  function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass, blur, tip, className, rest, children }) {
11181
- const [open2, setOpen] = React59.useState(false);
11200
+ const [open2, setOpen] = React60.useState(false);
11182
11201
  const [anchor, pos] = useHoverCard(open2);
11183
- const hoverCardRef = React59.useRef(null);
11202
+ const hoverCardRef = React60.useRef(null);
11184
11203
  const hoverLayer = useStackedLayer({ active: open2, containerRef: hoverCardRef, returnFocus: false });
11185
11204
  const zIndex = useLayerZIndex(hoverLayer);
11186
- const close2 = React59.useRef(null);
11205
+ const close2 = React60.useRef(null);
11187
11206
  const show = () => {
11188
11207
  if (close2.current) {
11189
11208
  clearTimeout(close2.current);
@@ -11199,10 +11218,10 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
11199
11218
  setOpen(false);
11200
11219
  }, 140);
11201
11220
  };
11202
- React59.useEffect(() => () => {
11221
+ React60.useEffect(() => () => {
11203
11222
  if (close2.current) clearTimeout(close2.current);
11204
11223
  }, []);
11205
- return /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)(
11224
+ return /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(
11206
11225
  "span",
11207
11226
  {
11208
11227
  ref: anchor,
@@ -11213,8 +11232,8 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
11213
11232
  onBlur: hide,
11214
11233
  ...rest,
11215
11234
  children: [
11216
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fd-soon-under", style: { filter: "blur(" + Math.min(blur, 1.1) + "px) saturate(.66)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
11217
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
11235
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-soon-under", style: { filter: "blur(" + Math.min(blur, 1.1) + "px) saturate(.66)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
11236
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
11218
11237
  "button",
11219
11238
  {
11220
11239
  type: "button",
@@ -11225,11 +11244,11 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
11225
11244
  onFocus: show,
11226
11245
  onBlur: hide,
11227
11246
  onClick: () => open2 ? setOpen(false) : show(),
11228
- children: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
11247
+ children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
11229
11248
  }
11230
11249
  ),
11231
11250
  open2 && pos ? (0, import_react_dom7.createPortal)(
11232
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
11251
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
11233
11252
  "div",
11234
11253
  {
11235
11254
  ref: hoverCardRef,
@@ -11238,7 +11257,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
11238
11257
  style: { position: "fixed", left: pos.left, top: pos.top, bottom: pos.bottom, width: pos.width, zIndex },
11239
11258
  onMouseEnter: show,
11240
11259
  onMouseLeave: hide,
11241
- children: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
11260
+ children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
11242
11261
  SoonCard,
11243
11262
  {
11244
11263
  label,
@@ -11268,10 +11287,10 @@ function formatEta(iso2) {
11268
11287
  var FormatEta = formatEta;
11269
11288
 
11270
11289
  // src/components/platform/Gate.tsx
11271
- var import_jsx_runtime84 = require("react/jsx-runtime");
11290
+ var import_jsx_runtime85 = require("react/jsx-runtime");
11272
11291
  function PermissionDenied({ permission, title, detail, compact: compact3 = false, className = "", ...rest }) {
11273
11292
  const need = Array.isArray(permission) ? permission : [permission].filter(Boolean);
11274
- return /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(
11293
+ return /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)(
11275
11294
  "div",
11276
11295
  {
11277
11296
  className: ["fd-stack", className].filter(Boolean).join(" "),
@@ -11287,14 +11306,14 @@ function PermissionDenied({ permission, title, detail, compact: compact3 = false
11287
11306
  },
11288
11307
  ...rest,
11289
11308
  children: [
11290
- /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("span", { className: "fd-row", style: { gap: 8 }, children: [
11291
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-lock-simple", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
11292
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: compact3 ? "fd-label-lg" : "fd-h3", children: title || "You do not have access to this" })
11309
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-row", style: { gap: 8 }, children: [
11310
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("i", { className: "ph ph-lock-simple", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
11311
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: compact3 ? "fd-label-lg" : "fd-h3", children: title || "You do not have access to this" })
11293
11312
  ] }),
11294
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: detail || "Your roles do not grant this. An administrator can change that from Admin \u2192 Users." }),
11295
- need.length ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: [
11296
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-overline fd-muted", children: "Requires" }),
11297
- need.map((p) => /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("code", { className: "fd-mono", style: {
11313
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: detail || "Your roles do not grant this. An administrator can change that from Admin \u2192 Users." }),
11314
+ need.length ? /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: [
11315
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fd-overline fd-muted", children: "Requires" }),
11316
+ need.map((p) => /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("code", { className: "fd-mono", style: {
11298
11317
  fontSize: 11.5,
11299
11318
  padding: "2px 7px",
11300
11319
  borderRadius: 5,
@@ -11307,7 +11326,7 @@ function PermissionDenied({ permission, title, detail, compact: compact3 = false
11307
11326
  );
11308
11327
  }
11309
11328
  function GatePending({ compact: compact3 = false, className = "" }) {
11310
- return /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(
11329
+ return /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)(
11311
11330
  "div",
11312
11331
  {
11313
11332
  className: ["fd-stack", className].filter(Boolean).join(" "),
@@ -11323,11 +11342,11 @@ function GatePending({ compact: compact3 = false, className = "" }) {
11323
11342
  textAlign: "left"
11324
11343
  },
11325
11344
  children: [
11326
- /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("span", { className: "fd-row", style: { gap: 8 }, children: [
11327
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-arrows-clockwise", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
11328
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: compact3 ? "fd-label-lg" : "fd-h3", children: "Reconnecting\u2026" })
11345
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-row", style: { gap: 8 }, children: [
11346
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("i", { className: "ph ph-arrows-clockwise", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
11347
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: compact3 ? "fd-label-lg" : "fd-h3", children: "Reconnecting\u2026" })
11329
11348
  ] }),
11330
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: "Your access can't be verified right now. This will resolve on its own once the connection is back." })
11349
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: "Your access can't be verified right now. This will resolve on its own once the connection is back." })
11331
11350
  ]
11332
11351
  }
11333
11352
  );
@@ -11337,7 +11356,7 @@ function Gate({ perm, anyOf, role, silent = false, fallback, pendingFallback, co
11337
11356
  if (pending) {
11338
11357
  if (pendingFallback !== void 0) return pendingFallback;
11339
11358
  if (silent) return null;
11340
- return /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(GatePending, { compact: compact3 });
11359
+ return /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(GatePending, { compact: compact3 });
11341
11360
  }
11342
11361
  let ok = true;
11343
11362
  if (perm) ok = ok && can2(perm);
@@ -11346,7 +11365,7 @@ function Gate({ perm, anyOf, role, silent = false, fallback, pendingFallback, co
11346
11365
  if (ok) return children;
11347
11366
  if (fallback !== void 0) return fallback;
11348
11367
  if (silent) return null;
11349
- return /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(PermissionDenied, { permission: perm || anyOf, compact: compact3 });
11368
+ return /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(PermissionDenied, { permission: perm || anyOf, compact: compact3 });
11350
11369
  }
11351
11370
  function FeatureGate({
11352
11371
  flag,
@@ -11369,7 +11388,7 @@ function FeatureGate({
11369
11388
  const f = SessionKit.findFlag(flag) || {};
11370
11389
  const missing = rt.missing || [];
11371
11390
  const canBypass = pending ? false : bypassPerm === null ? false : !bypassPerm || can2(bypassPerm);
11372
- return /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
11391
+ return /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
11373
11392
  ComingSoon,
11374
11393
  {
11375
11394
  label: label || (variant === "inline" ? f.label || "Not wired yet" : "Designed \u2014 backend not wired yet"),
@@ -11390,22 +11409,22 @@ function FeatureGate({
11390
11409
  function PermissionHint({ perm, children }) {
11391
11410
  const { can: can2, pending } = useSessionContext();
11392
11411
  if (pending) {
11393
- return /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { title: "Access can't be verified right now", style: { display: "inline-flex", opacity: 0.45, cursor: "not-allowed" }, "aria-disabled": "true", children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { style: { pointerEvents: "none" }, children }) });
11412
+ return /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { title: "Access can't be verified right now", style: { display: "inline-flex", opacity: 0.45, cursor: "not-allowed" }, "aria-disabled": "true", children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { style: { pointerEvents: "none" }, children }) });
11394
11413
  }
11395
11414
  if (can2(perm)) return children;
11396
- return /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
11415
+ return /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
11397
11416
  "span",
11398
11417
  {
11399
11418
  title: "Requires " + (Array.isArray(perm) ? perm.join(", ") : perm),
11400
11419
  style: { display: "inline-flex", opacity: 0.45, cursor: "not-allowed" },
11401
11420
  "aria-disabled": "true",
11402
- children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { style: { pointerEvents: "none" }, children })
11421
+ children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { style: { pointerEvents: "none" }, children })
11403
11422
  }
11404
11423
  );
11405
11424
  }
11406
11425
 
11407
11426
  // src/components/platform/ModeSwitch.tsx
11408
- var import_jsx_runtime85 = require("react/jsx-runtime");
11427
+ var import_jsx_runtime86 = require("react/jsx-runtime");
11409
11428
  function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
11410
11429
  const mode2 = useRuntimeMode();
11411
11430
  const panel = useInlinePanel();
@@ -11417,8 +11436,8 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
11417
11436
  RuntimeKit.setMode(next);
11418
11437
  setOpen(false);
11419
11438
  };
11420
- return /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { style: { display: "inline-flex" }, ref, children: [
11421
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)(
11439
+ return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { style: { display: "inline-flex" }, ref, children: [
11440
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
11422
11441
  "button",
11423
11442
  {
11424
11443
  type: "button",
@@ -11428,29 +11447,29 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
11428
11447
  title: test ? "Test mode \u2014 every response is simulated. Click to inspect requests or return to live mode." : "Live mode \u2014 incomplete features are shown under construction. Click for test mode.",
11429
11448
  className: "fd-mode-btn" + (test ? " is-test" : "") + (open2 ? " is-open" : ""),
11430
11449
  children: [
11431
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), style: { fontSize: 17 } }),
11432
- test && requestCount ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fd-mono fd-mode-count", children: requestCount > 99 ? "99+" : requestCount }, requestCount) : null
11450
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), style: { fontSize: 17 } }),
11451
+ test && requestCount ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-mono fd-mode-count", children: requestCount > 99 ? "99+" : requestCount }, requestCount) : null
11433
11452
  ]
11434
11453
  }
11435
11454
  ),
11436
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)(InlinePanelSurface, { panel, align: "right", offset: 8, width: 400, className: "fd-mode-pop", label: test ? "Test mode" : "Live mode", children: [
11437
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
11438
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-badge " + (test ? "fd-badge-warning" : "fd-badge-neutral"), children: [
11439
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), "aria-hidden": "true" }),
11455
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(InlinePanelSurface, { panel, align: "right", offset: 8, width: 400, className: "fd-mode-pop", label: test ? "Test mode" : "Live mode", children: [
11456
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
11457
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-badge " + (test ? "fd-badge-warning" : "fd-badge-neutral"), children: [
11458
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), "aria-hidden": "true" }),
11440
11459
  test ? "Test mode" : "Live mode"
11441
11460
  ] }),
11442
- test ? /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
11461
+ test ? /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
11443
11462
  requestCount,
11444
11463
  " simulated request",
11445
11464
  requestCount === 1 ? "" : "s"
11446
11465
  ] }) : null,
11447
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { style: { flex: 1 } }),
11448
- test && onClearLog ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("button", { type: "button", className: "fd-soon-link", onClick: onClearLog, children: "Clear" }) : null
11466
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { style: { flex: 1 } }),
11467
+ test && onClearLog ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("button", { type: "button", className: "fd-soon-link", onClick: onClearLog, children: "Clear" }) : null
11449
11468
  ] }),
11450
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { style: { display: "block", padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
11451
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fd-body-sm fd-secondary", style: { display: "block", textWrap: "pretty" }, children: test ? "Every feature is usable and nothing is obstructed, but no response comes from a real service \u2014 nothing you do here persists. Use this to review and demo the design." : "This is what a user would see today. " + s.incomplete + " of " + s.total + " features depend on backend work that is not wired yet, so they render under construction." }),
11452
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-row", style: { gap: 8, marginTop: 10, flexWrap: "wrap" }, children: [
11453
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
11469
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { style: { display: "block", padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
11470
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-body-sm fd-secondary", style: { display: "block", textWrap: "pretty" }, children: test ? "Every feature is usable and nothing is obstructed, but no response comes from a real service \u2014 nothing you do here persists. Use this to review and demo the design." : "This is what a user would see today. " + s.incomplete + " of " + s.total + " features depend on backend work that is not wired yet, so they render under construction." }),
11471
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-row", style: { gap: 8, marginTop: 10, flexWrap: "wrap" }, children: [
11472
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
11454
11473
  s.endpointsWired,
11455
11474
  " endpoint",
11456
11475
  s.endpointsWired === 1 ? "" : "s",
@@ -11460,58 +11479,58 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
11460
11479
  s.total,
11461
11480
  " features complete"
11462
11481
  ] }),
11463
- onOpenSpec ? /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)(import_jsx_runtime85.Fragment, { children: [
11464
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { style: { flex: 1 } }),
11465
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => {
11482
+ onOpenSpec ? /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(import_jsx_runtime86.Fragment, { children: [
11483
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { style: { flex: 1 } }),
11484
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => {
11466
11485
  setOpen(false);
11467
11486
  onOpenSpec();
11468
11487
  }, children: [
11469
11488
  "API spec ",
11470
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
11489
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
11471
11490
  ] })
11472
11491
  ] }) : null
11473
11492
  ] })
11474
11493
  ] }),
11475
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-mode-choice", children: [
11476
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("button", { type: "button", className: "fd-mode-opt" + (!test ? " is-on" : ""), onClick: () => go("live"), children: [
11477
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
11478
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-mode-opt-text", children: [
11479
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fd-mode-opt-title", children: "Live mode" }),
11480
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fd-mode-opt-desc", children: "Incomplete features under construction" })
11494
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-mode-choice", children: [
11495
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("button", { type: "button", className: "fd-mode-opt" + (!test ? " is-on" : ""), onClick: () => go("live"), children: [
11496
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
11497
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-mode-opt-text", children: [
11498
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-mode-opt-title", children: "Live mode" }),
11499
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-mode-opt-desc", children: "Incomplete features under construction" })
11481
11500
  ] }),
11482
- !test ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
11501
+ !test ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
11483
11502
  ] }),
11484
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("button", { type: "button", className: "fd-mode-opt" + (test ? " is-on" : ""), onClick: () => go("test"), children: [
11485
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("i", { className: "ph ph-flask", "aria-hidden": "true" }),
11486
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-mode-opt-text", children: [
11487
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fd-mode-opt-title", children: "Test mode" }),
11488
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fd-mode-opt-desc", children: "Everything usable, all data simulated" })
11503
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("button", { type: "button", className: "fd-mode-opt" + (test ? " is-on" : ""), onClick: () => go("test"), children: [
11504
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph ph-flask", "aria-hidden": "true" }),
11505
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-mode-opt-text", children: [
11506
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-mode-opt-title", children: "Test mode" }),
11507
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-mode-opt-desc", children: "Everything usable, all data simulated" })
11489
11508
  ] }),
11490
- test ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
11509
+ test ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
11491
11510
  ] })
11492
11511
  ] }),
11493
- test && renderLog ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { style: { display: "block", maxHeight: 340, overflowY: "auto", borderTop: "1px solid var(--border)" }, children: renderLog() }) : null
11512
+ test && renderLog ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { style: { display: "block", maxHeight: 340, overflowY: "auto", borderTop: "1px solid var(--border)" }, children: renderLog() }) : null
11494
11513
  ] })
11495
11514
  ] });
11496
11515
  }
11497
11516
  function TestModeBar({ onExit }) {
11498
11517
  const mode2 = useRuntimeMode();
11499
11518
  if (mode2 !== "test") return null;
11500
- return /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("div", { className: "fd-testbar", role: "status", children: [
11501
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-badge fd-badge-warning", children: [
11502
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("i", { className: "ph ph-flask", "aria-hidden": "true" }),
11519
+ return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-testbar", role: "status", children: [
11520
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-badge fd-badge-warning", children: [
11521
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph ph-flask", "aria-hidden": "true" }),
11503
11522
  "Test mode"
11504
11523
  ] }),
11505
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fd-testbar-detail", children: "Every feature is unlocked and every response is simulated \u2014 nothing here persists." }),
11506
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => onExit ? onExit() : RuntimeKit.setMode("live"), children: [
11507
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
11524
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-testbar-detail", children: "Every feature is unlocked and every response is simulated \u2014 nothing here persists." }),
11525
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => onExit ? onExit() : RuntimeKit.setMode("live"), children: [
11526
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
11508
11527
  " Back to live mode"
11509
11528
  ] })
11510
11529
  ] });
11511
11530
  }
11512
11531
 
11513
11532
  // src/components/planner/ChannelMeta.tsx
11514
- var import_jsx_runtime86 = require("react/jsx-runtime");
11533
+ var import_jsx_runtime87 = require("react/jsx-runtime");
11515
11534
  var CHANNEL_WEIGHTS = {
11516
11535
  "OOH": 50,
11517
11536
  "DOOH": 50,
@@ -11564,9 +11583,9 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
11564
11583
  const m = ChannelMeta(channel);
11565
11584
  const wt = channelWeightOf(channel || "");
11566
11585
  if (dot) {
11567
- return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: ["fd-chan-dot", className].filter(Boolean).join(" "), title: m.name, style: { background: m.color }, ...rest });
11586
+ return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: ["fd-chan-dot", className].filter(Boolean).join(" "), title: m.name, style: { background: m.color }, ...rest });
11568
11587
  }
11569
- return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
11588
+ return /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(
11570
11589
  "span",
11571
11590
  {
11572
11591
  className: ["fd-chan", size === "sm" ? "fd-chan-sm" : "", className].filter(Boolean).join(" "),
@@ -11574,16 +11593,16 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
11574
11593
  style: { "--chan": m.color },
11575
11594
  ...rest,
11576
11595
  children: [
11577
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }),
11578
- showLabel ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-chan-label", children: m.label }) : null,
11579
- weight ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-chan-weight", children: wt || 0 }) : null
11596
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }),
11597
+ showLabel ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-chan-label", children: m.label }) : null,
11598
+ weight ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-chan-weight", children: wt || 0 }) : null
11580
11599
  ]
11581
11600
  }
11582
11601
  );
11583
11602
  }
11584
11603
 
11585
11604
  // src/components/planner/SaturationDistribution.tsx
11586
- var import_jsx_runtime87 = require("react/jsx-runtime");
11605
+ var import_jsx_runtime88 = require("react/jsx-runtime");
11587
11606
  var BANDS2 = [
11588
11607
  { key: "weak", label: "Weak", n: 1, range: "< 50" },
11589
11608
  { key: "adequate", label: "Adequate", n: 2, range: "50\u2013100" },
@@ -11594,24 +11613,24 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
11594
11613
  const grouped = BANDS2.map((b) => ({ ...b, items: campuses.filter((c) => c.band === b.key) }));
11595
11614
  const tallest = Math.max(1, ...grouped.map((g) => g.items.length));
11596
11615
  const floor = BANDS2.find((b) => b.key === floorBand) || BANDS2[0];
11597
- return /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
11598
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("div", { style: { display: "grid", gridTemplateColumns: "repeat(4,minmax(0,1fr))", gap: 12, alignItems: "end" }, children: grouped.map((g) => {
11616
+ return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
11617
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("div", { style: { display: "grid", gridTemplateColumns: "repeat(4,minmax(0,1fr))", gap: 12, alignItems: "end" }, children: grouped.map((g) => {
11599
11618
  const mark = "var(--csi-" + g.n + "-mark)";
11600
11619
  const active = selectedBand === g.key;
11601
- return /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(
11620
+ return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)(
11602
11621
  "button",
11603
11622
  {
11604
11623
  type: "button",
11605
11624
  onClick: onSelectBand ? () => onSelectBand(active ? null : g.key) : void 0,
11606
11625
  style: { display: "flex", flexDirection: "column", justifyContent: "flex-end", gap: 10, padding: 12, border: "1px solid " + (active ? "var(--border-strong)" : "var(--border)"), borderRadius: "var(--r-lg)", background: active ? "var(--surface-2)" : "var(--surface)", cursor: onSelectBand ? "pointer" : "default", textAlign: "left", minHeight: 190, minWidth: 0, transition: "background var(--dur-fast) var(--ease),border-color var(--dur-fast) var(--ease)" },
11607
11626
  children: [
11608
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { style: { display: "flex", flexDirection: "column-reverse", gap: 4, minHeight: tallest * 24, minWidth: 0 }, children: loading ? Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-skel", style: { height: 16, borderRadius: 4 } }, i)) : g.items.map((c) => (
11627
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { style: { display: "flex", flexDirection: "column-reverse", gap: 4, minHeight: tallest * 24, minWidth: 0 }, children: loading ? Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "fd-skel", style: { height: 16, borderRadius: 4 } }, i)) : g.items.map((c) => (
11609
11628
  // `overflow: hidden` + `white-space: nowrap` only clips once the span
11610
11629
  // actually HAS a bounded width to clip against (see the grid/flex
11611
11630
  // `minWidth: 0` chain above) — `textOverflow: ellipsis` then makes
11612
11631
  // that clip readable instead of a hard cut mid-letter; the full name
11613
11632
  // is still one hover away via `title`.
11614
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
11633
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
11615
11634
  "span",
11616
11635
  {
11617
11636
  title: c.name + " \xB7 " + c.crp,
@@ -11621,13 +11640,13 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
11621
11640
  c.name
11622
11641
  )
11623
11642
  )) }),
11624
- /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("span", { className: "fd-row", style: { gap: 8, alignItems: "baseline" }, children: [
11625
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-num-hero", style: { fontSize: 30, color: g.items.length ? "var(--text)" : "var(--text-disabled)" }, children: loading ? "\u2013" : g.items.length }),
11626
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-meter", style: { gap: 2, color: mark }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-meter-seg" + (i <= g.n ? " is-on" : ""), style: { width: 4, height: 9 } }, i)) })
11643
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("span", { className: "fd-row", style: { gap: 8, alignItems: "baseline" }, children: [
11644
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "fd-num-hero", style: { fontSize: 30, color: g.items.length ? "var(--text)" : "var(--text-disabled)" }, children: loading ? "\u2013" : g.items.length }),
11645
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "fd-meter", style: { gap: 2, color: mark }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "fd-meter-seg" + (i <= g.n ? " is-on" : ""), style: { width: 4, height: 9 } }, i)) })
11627
11646
  ] }),
11628
- /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("span", { className: "fd-stack", style: { gap: 1 }, children: [
11629
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-label-lg", children: g.label }),
11630
- /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("span", { className: "fd-body-sm fd-muted", style: { fontSize: 11.5 }, children: [
11647
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("span", { className: "fd-stack", style: { gap: 1 }, children: [
11648
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "fd-label-lg", children: g.label }),
11649
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("span", { className: "fd-body-sm fd-muted", style: { fontSize: 11.5 }, children: [
11631
11650
  "CRP ",
11632
11651
  g.range
11633
11652
  ] })
@@ -11637,10 +11656,10 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
11637
11656
  g.key
11638
11657
  );
11639
11658
  }) }),
11640
- floorBand ? /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderRadius: "var(--r-md)", background: "var(--surface-2)", border: "1px solid var(--border)", flexWrap: "wrap" }, children: [
11641
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-meter", style: { gap: 2, color: "var(--csi-" + floor.n + "-mark)" }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-meter-seg" + (i <= floor.n ? " is-on" : ""), style: { width: 5, height: 12 } }, i)) }),
11642
- /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("span", { className: "fd-body-sm fd-secondary", style: { flex: 1, minWidth: 240 }, children: [
11643
- /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("strong", { style: { color: "var(--text)" }, children: [
11659
+ floorBand ? /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderRadius: "var(--r-md)", background: "var(--surface-2)", border: "1px solid var(--border)", flexWrap: "wrap" }, children: [
11660
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "fd-meter", style: { gap: 2, color: "var(--csi-" + floor.n + "-mark)" }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "fd-meter-seg" + (i <= floor.n ? " is-on" : ""), style: { width: 5, height: 12 } }, i)) }),
11661
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("span", { className: "fd-body-sm fd-secondary", style: { flex: 1, minWidth: 240 }, children: [
11662
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("strong", { style: { color: "var(--text)" }, children: [
11644
11663
  "Plan floor ",
11645
11664
  floorScore
11646
11665
  ] }),
@@ -11651,8 +11670,8 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
11651
11670
  }
11652
11671
 
11653
11672
  // src/components/planner/MixGap.tsx
11654
- var React60 = __toESM(require("react"), 1);
11655
- var import_jsx_runtime88 = require("react/jsx-runtime");
11673
+ var React61 = __toESM(require("react"), 1);
11674
+ var import_jsx_runtime89 = require("react/jsx-runtime");
11656
11675
  var MIX_GAP_LAYOUT = {
11657
11676
  trackHeight: 30,
11658
11677
  barHeight: 20,
@@ -11666,19 +11685,19 @@ function mixGapOffset(value, max) {
11666
11685
  }
11667
11686
  function MixGap({ rows = [], loading = false, className = "" }) {
11668
11687
  const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
11669
- const [hover, setHover] = React60.useState(null);
11688
+ const [hover, setHover] = React61.useState(null);
11670
11689
  const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
11671
11690
  const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
11672
11691
  const { trackHeight, barHeight, targetWidth, labelGap } = MIX_GAP_LAYOUT;
11673
11692
  const barTop = (trackHeight - barHeight) / 2;
11674
- return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 4 }, children: [
11675
- /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "fd-row", style: { gap: 16, justifyContent: "flex-end", paddingBottom: 6, flexWrap: "wrap" }, children: [
11676
- [["On target", TONE.ok], ["Close", TONE.warn], ["Short", TONE.danger]].map(([l, c]) => /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
11677
- /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { style: { width: 14, height: 9, borderRadius: 2, background: c } }),
11693
+ return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 4 }, children: [
11694
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "fd-row", style: { gap: 16, justifyContent: "flex-end", paddingBottom: 6, flexWrap: "wrap" }, children: [
11695
+ [["On target", TONE.ok], ["Close", TONE.warn], ["Short", TONE.danger]].map(([l, c]) => /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
11696
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { style: { width: 14, height: 9, borderRadius: 2, background: c } }),
11678
11697
  l
11679
11698
  ] }, l)),
11680
- /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
11681
- /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { "data-mixgap-legend-target": "", style: { width: targetWidth, height: 16, borderRadius: 1, background: MIX_GAP_TARGET_STRIPE } }),
11699
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
11700
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { "data-mixgap-legend-target": "", style: { width: targetWidth, height: 16, borderRadius: 1, background: MIX_GAP_TARGET_STRIPE } }),
11682
11701
  "Target"
11683
11702
  ] })
11684
11703
  ] }),
@@ -11687,7 +11706,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
11687
11706
  const tone = toneOf(gap);
11688
11707
  const tip = "Realized " + r.realized + "% vs " + r.target + "% target" + (gap < -1 ? " \xB7 " + Math.abs(gap).toFixed(0) + " pts short" : gap > 1 ? " \xB7 " + gap.toFixed(0) + " pts over" : " \xB7 on target") + (r.note ? " \u2014 " + r.note : "");
11689
11708
  const labelLeft = r.realized > r.target ? `calc(${mixGapOffset(r.realized, max)} + ${labelGap}px)` : `calc(${mixGapOffset(r.target, max)} + ${targetWidth / 2 + labelGap}px)`;
11690
- return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)(
11709
+ return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)(
11691
11710
  "div",
11692
11711
  {
11693
11712
  className: "fd-row",
@@ -11695,15 +11714,15 @@ function MixGap({ rows = [], loading = false, className = "" }) {
11695
11714
  onMouseEnter: () => setHover(r.channel),
11696
11715
  onMouseLeave: () => setHover(null),
11697
11716
  children: [
11698
- /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { style: { width: 128, flex: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(ChannelTag, { channel: r.channel, size: "sm" }) }),
11699
- /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { style: { position: "relative", flex: 1, height: trackHeight, minWidth: 120 }, children: loading ? /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "fd-skel", style: { position: "absolute", left: 0, right: 0, top: barTop, height: barHeight, borderRadius: 3 } }) : /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)(import_jsx_runtime88.Fragment, { children: [
11700
- /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { "data-mixgap-bar": "", style: { position: "absolute", left: 0, top: barTop, height: barHeight, width: mixGapOffset(r.realized, max), background: TONE[tone], borderRadius: "2px 3px 3px 2px", transition: "width var(--dur-slow) var(--ease), background var(--dur-base) var(--ease)" } }),
11701
- /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { "data-mixgap-target": "", style: { position: "absolute", left: `calc(${mixGapOffset(r.target, max)} - ${targetWidth / 2}px)`, top: 0, width: targetWidth, height: trackHeight, background: MIX_GAP_TARGET_STRIPE, borderRadius: 1 } }),
11702
- /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("span", { "data-mixgap-label": "", className: "fd-num", style: { position: "absolute", left: labelLeft, top: "50%", transform: "translateY(-50%)", fontSize: 12, color: "var(--text-muted)", whiteSpace: "nowrap" }, children: [
11717
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { style: { width: 128, flex: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(ChannelTag, { channel: r.channel, size: "sm" }) }),
11718
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { style: { position: "relative", flex: 1, height: trackHeight, minWidth: 120 }, children: loading ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { className: "fd-skel", style: { position: "absolute", left: 0, right: 0, top: barTop, height: barHeight, borderRadius: 3 } }) : /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)(import_jsx_runtime89.Fragment, { children: [
11719
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { "data-mixgap-bar": "", style: { position: "absolute", left: 0, top: barTop, height: barHeight, width: mixGapOffset(r.realized, max), background: TONE[tone], borderRadius: "2px 3px 3px 2px", transition: "width var(--dur-slow) var(--ease), background var(--dur-base) var(--ease)" } }),
11720
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { "data-mixgap-target": "", style: { position: "absolute", left: `calc(${mixGapOffset(r.target, max)} - ${targetWidth / 2}px)`, top: 0, width: targetWidth, height: trackHeight, background: MIX_GAP_TARGET_STRIPE, borderRadius: 1 } }),
11721
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("span", { "data-mixgap-label": "", className: "fd-num", style: { position: "absolute", left: labelLeft, top: "50%", transform: "translateY(-50%)", fontSize: 12, color: "var(--text-muted)", whiteSpace: "nowrap" }, children: [
11703
11722
  r.realized,
11704
11723
  "%"
11705
11724
  ] }),
11706
- hover === r.channel ? /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "fd-tooltip", role: "tooltip", style: { position: "absolute", left: 0, right: "auto", bottom: trackHeight + 4, maxWidth: "min(340px, 100%)", whiteSpace: "normal", textAlign: "left", width: "max-content" }, children: tip }) : null
11725
+ hover === r.channel ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { className: "fd-tooltip", role: "tooltip", style: { position: "absolute", left: 0, right: "auto", bottom: trackHeight + 4, maxWidth: "min(340px, 100%)", whiteSpace: "normal", textAlign: "left", width: "max-content" }, children: tip }) : null
11707
11726
  ] }) })
11708
11727
  ]
11709
11728
  },
@@ -11714,7 +11733,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
11714
11733
  }
11715
11734
 
11716
11735
  // src/components/planner/ChannelContribution.tsx
11717
- var import_jsx_runtime89 = require("react/jsx-runtime");
11736
+ var import_jsx_runtime90 = require("react/jsx-runtime");
11718
11737
  var money = (n) => "$" + Math.round(n).toLocaleString();
11719
11738
  function ChannelContribution({
11720
11739
  channels = [],
@@ -11730,9 +11749,9 @@ function ChannelContribution({
11730
11749
  const grand = total !== void 0 ? total : base + bonus;
11731
11750
  const pct = (v) => grand ? v / grand * 100 : 0;
11732
11751
  const spendTotal = channels.reduce((s, c) => s + Number(String(c.spend || 0).replace(/[^0-9.]/g, "")), 0);
11733
- return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
11734
- loading ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { className: "fd-skel", style: { height: 34, borderRadius: "var(--r-sm)" } }) : /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "fd-row", style: { height: 34, borderRadius: "var(--r-sm)", overflow: "hidden", gap: 2, background: "var(--surface-3)" }, children: [
11735
- channels.map((c) => /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(
11752
+ return /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
11753
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("span", { className: "fd-skel", style: { height: 34, borderRadius: "var(--r-sm)" } }) : /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("div", { className: "fd-row", style: { height: 34, borderRadius: "var(--r-sm)", overflow: "hidden", gap: 2, background: "var(--surface-3)" }, children: [
11754
+ channels.map((c) => /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
11736
11755
  "span",
11737
11756
  {
11738
11757
  title: c.name + " \xB7 " + c.crp.toFixed(1) + " CRP",
@@ -11741,7 +11760,7 @@ function ChannelContribution({
11741
11760
  },
11742
11761
  c.name
11743
11762
  )),
11744
- bonus > 0 ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(
11763
+ bonus > 0 ? /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
11745
11764
  "span",
11746
11765
  {
11747
11766
  title: "Surround-sound bonus +" + bonusPct + "%",
@@ -11750,18 +11769,18 @@ function ChannelContribution({
11750
11769
  }
11751
11770
  ) : null
11752
11771
  ] }),
11753
- showTable ? /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("table", { className: "fd-table", style: { fontSize: "var(--body-sm-size)" }, children: [
11754
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("tr", { children: [
11755
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("th", { style: { width: "34%" }, children: "Channel" }),
11756
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("th", { style: { width: "16%" }, children: "Weight" }),
11757
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("th", { className: "is-num", style: { width: "16%" }, children: "Spend" }),
11758
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("th", { className: "is-num", style: { width: "17%" }, children: "CRP" }),
11759
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("th", { className: "is-num", style: { width: "17%" }, children: "Share" })
11772
+ showTable ? /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("table", { className: "fd-table", style: { fontSize: "var(--body-sm-size)" }, children: [
11773
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("tr", { children: [
11774
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("th", { style: { width: "34%" }, children: "Channel" }),
11775
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("th", { style: { width: "16%" }, children: "Weight" }),
11776
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("th", { className: "is-num", style: { width: "16%" }, children: "Spend" }),
11777
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("th", { className: "is-num", style: { width: "17%" }, children: "CRP" }),
11778
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("th", { className: "is-num", style: { width: "17%" }, children: "Share" })
11760
11779
  ] }) }),
11761
- /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("tbody", { children: [
11762
- channels.map((c) => /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("tr", { children: [
11763
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(ChannelTag, { channel: c.name, size: "sm" }) }),
11764
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(
11780
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("tbody", { children: [
11781
+ channels.map((c) => /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("tr", { children: [
11782
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(ChannelTag, { channel: c.name, size: "sm" }) }),
11783
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
11765
11784
  "span",
11766
11785
  {
11767
11786
  className: "fd-badge fd-badge-neutral",
@@ -11770,38 +11789,38 @@ function ChannelContribution({
11770
11789
  children: "weight " + (channelWeightOf(c.name) || 0)
11771
11790
  }
11772
11791
  ) }),
11773
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("td", { className: "is-num", children: c.spend }),
11774
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("td", { className: "is-num", children: c.crp.toFixed(1) }),
11775
- /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("td", { className: "is-num", children: [
11792
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("td", { className: "is-num", children: c.spend }),
11793
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("td", { className: "is-num", children: c.crp.toFixed(1) }),
11794
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("td", { className: "is-num", children: [
11776
11795
  pct(c.crp).toFixed(0),
11777
11796
  "%"
11778
11797
  ] })
11779
11798
  ] }, c.name)),
11780
- bonus > 0 ? /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("tr", { children: [
11781
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("span", { className: "fd-row", style: { gap: 9, fontWeight: 600 }, children: [
11782
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { style: { width: 9, height: 9, borderRadius: 2, background: "repeating-linear-gradient(135deg,var(--csi-3-mark) 0 3px,var(--csi-2-mark) 3px 6px)", flex: "none" } }),
11799
+ bonus > 0 ? /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("tr", { children: [
11800
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("span", { className: "fd-row", style: { gap: 9, fontWeight: 600 }, children: [
11801
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("span", { style: { width: 9, height: 9, borderRadius: 2, background: "repeating-linear-gradient(135deg,var(--csi-3-mark) 0 3px,var(--csi-2-mark) 3px 6px)", flex: "none" } }),
11783
11802
  "Surround-sound bonus"
11784
11803
  ] }) }),
11785
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("span", { className: "fd-badge fd-badge-success", style: { height: 20, fontSize: 11 }, children: [
11804
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("span", { className: "fd-badge fd-badge-success", style: { height: 20, fontSize: 11 }, children: [
11786
11805
  "+",
11787
11806
  bonusPct,
11788
11807
  "% of +",
11789
11808
  bonusMax,
11790
11809
  "%"
11791
11810
  ] }) }),
11792
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("td", { className: "is-num fd-muted", children: "\u2014" }),
11793
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("td", { className: "is-num", children: bonus.toFixed(1) }),
11794
- /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("td", { className: "is-num", children: [
11811
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("td", { className: "is-num fd-muted", children: "\u2014" }),
11812
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("td", { className: "is-num", children: bonus.toFixed(1) }),
11813
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("td", { className: "is-num", children: [
11795
11814
  pct(bonus).toFixed(0),
11796
11815
  "%"
11797
11816
  ] })
11798
11817
  ] }) : null,
11799
- /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("tr", { style: { background: "var(--surface-2)" }, children: [
11800
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("td", { style: { fontWeight: 700 }, children: "Campus total" }),
11801
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("td", {}),
11802
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: money(spendTotal) }),
11803
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: grand.toFixed(1) }),
11804
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: "100%" })
11818
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("tr", { style: { background: "var(--surface-2)" }, children: [
11819
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("td", { style: { fontWeight: 700 }, children: "Campus total" }),
11820
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("td", {}),
11821
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: money(spendTotal) }),
11822
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: grand.toFixed(1) }),
11823
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: "100%" })
11805
11824
  ] })
11806
11825
  ] })
11807
11826
  ] }) : null
@@ -11809,8 +11828,8 @@ function ChannelContribution({
11809
11828
  }
11810
11829
 
11811
11830
  // src/components/planner/BudgetReallocator.tsx
11812
- var React61 = __toESM(require("react"), 1);
11813
- var import_jsx_runtime90 = require("react/jsx-runtime");
11831
+ var React62 = __toESM(require("react"), 1);
11832
+ var import_jsx_runtime91 = require("react/jsx-runtime");
11814
11833
  var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
11815
11834
  function BudgetReallocator({
11816
11835
  campus,
@@ -11825,8 +11844,8 @@ function BudgetReallocator({
11825
11844
  onCancel,
11826
11845
  className = ""
11827
11846
  }) {
11828
- const [draft, setDraft] = React61.useState(spend);
11829
- React61.useEffect(() => setDraft(spend), [spend]);
11847
+ const [draft, setDraft] = React62.useState(spend);
11848
+ React62.useEffect(() => setDraft(spend), [spend]);
11830
11849
  const dirty = draft !== spend;
11831
11850
  const nextCrp = scoreFor ? scoreFor(draft) : crp;
11832
11851
  const nextBand = bandFor(nextCrp);
@@ -11841,10 +11860,10 @@ function BudgetReallocator({
11841
11860
  setDraft(spend);
11842
11861
  if (onCancel) onCancel();
11843
11862
  };
11844
- const trackRef = React61.useRef(null);
11845
- const chipRef = React61.useRef(null);
11846
- const [chipLeft, setChipLeft] = React61.useState(null);
11847
- React61.useLayoutEffect(() => {
11863
+ const trackRef = React62.useRef(null);
11864
+ const chipRef = React62.useRef(null);
11865
+ const [chipLeft, setChipLeft] = React62.useState(null);
11866
+ React62.useLayoutEffect(() => {
11848
11867
  const track = trackRef.current;
11849
11868
  if (!dirty || !track) {
11850
11869
  setChipLeft(null);
@@ -11865,23 +11884,23 @@ function BudgetReallocator({
11865
11884
  ro.observe(track);
11866
11885
  return () => ro.disconnect();
11867
11886
  }, [dirty, pct]);
11868
- return /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)(
11887
+ return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(
11869
11888
  "div",
11870
11889
  {
11871
11890
  className: ["fd-stack", className].filter(Boolean).join(" "),
11872
11891
  style: { gap: 14, padding: 18, border: "1px solid " + (dirty ? "var(--border-brand)" : "var(--border)"), borderRadius: "var(--r-lg)", background: dirty ? "var(--surface-brand)" : "var(--surface)", color: "var(--text)", transition: "background var(--dur-base) var(--ease),border-color var(--dur-base) var(--ease)" },
11873
11892
  children: [
11874
- /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
11875
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("span", { className: "fd-h4", style: { flex: 1, minWidth: 140 }, children: campus }),
11876
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(CsiBadge, { band: nowBand, crp, size: "medium" }),
11877
- dirty ? /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)(import_jsx_runtime90.Fragment, { children: [
11878
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("i", { className: "ph ph-arrow-right fd-muted", "aria-hidden": "true" }),
11879
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(CsiBadge, { band: nextBand, crp: nextCrp, size: "medium", preview: true })
11893
+ /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
11894
+ /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("span", { className: "fd-h4", style: { flex: 1, minWidth: 140 }, children: campus }),
11895
+ /* @__PURE__ */ (0, import_jsx_runtime91.jsx)(CsiBadge, { band: nowBand, crp, size: "medium" }),
11896
+ dirty ? /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(import_jsx_runtime91.Fragment, { children: [
11897
+ /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("i", { className: "ph ph-arrow-right fd-muted", "aria-hidden": "true" }),
11898
+ /* @__PURE__ */ (0, import_jsx_runtime91.jsx)(CsiBadge, { band: nextBand, crp: nextCrp, size: "medium", preview: true })
11880
11899
  ] }) : null
11881
11900
  ] }),
11882
- /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("div", { className: "fd-slider", ref: trackRef, children: [
11883
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
11884
- dirty ? /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
11901
+ /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("div", { className: "fd-slider", ref: trackRef, children: [
11902
+ /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
11903
+ dirty ? /* @__PURE__ */ (0, import_jsx_runtime91.jsx)(
11885
11904
  "span",
11886
11905
  {
11887
11906
  ref: chipRef,
@@ -11893,7 +11912,7 @@ function BudgetReallocator({
11893
11912
  children: (delta < 0 ? "\u2212$" : "+$") + Math.abs(delta).toLocaleString()
11894
11913
  }
11895
11914
  ) : null,
11896
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
11915
+ /* @__PURE__ */ (0, import_jsx_runtime91.jsx)(
11897
11916
  "input",
11898
11917
  {
11899
11918
  type: "range",
@@ -11909,13 +11928,13 @@ function BudgetReallocator({
11909
11928
  }
11910
11929
  )
11911
11930
  ] }),
11912
- /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
11913
- /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("span", { className: "fd-stack", style: { gap: 2, flex: 1, minWidth: 150 }, children: [
11914
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("span", { className: "fd-num", style: { fontSize: 19, fontWeight: 700 }, children: "$" + draft.toLocaleString() }),
11915
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("span", { className: "fd-body-sm fd-muted", children: "Arrow keys step $100, shift+arrow $1,000. Escape reverts." })
11931
+ /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
11932
+ /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("span", { className: "fd-stack", style: { gap: 2, flex: 1, minWidth: 150 }, children: [
11933
+ /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("span", { className: "fd-num", style: { fontSize: 19, fontWeight: 700 }, children: "$" + draft.toLocaleString() }),
11934
+ /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("span", { className: "fd-body-sm fd-muted", children: "Arrow keys step $100, shift+arrow $1,000. Escape reverts." })
11916
11935
  ] }),
11917
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("button", { type: "button", className: "fd-btn fd-btn-ghost", disabled: !dirty, onClick: revert, children: "Cancel" }),
11918
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
11936
+ /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("button", { type: "button", className: "fd-btn fd-btn-ghost", disabled: !dirty, onClick: revert, children: "Cancel" }),
11937
+ /* @__PURE__ */ (0, import_jsx_runtime91.jsx)(
11919
11938
  "button",
11920
11939
  {
11921
11940
  type: "button",
@@ -11934,7 +11953,7 @@ function BudgetReallocator({
11934
11953
  }
11935
11954
 
11936
11955
  // src/components/planner/SurroundSound.tsx
11937
- var import_jsx_runtime91 = require("react/jsx-runtime");
11956
+ var import_jsx_runtime92 = require("react/jsx-runtime");
11938
11957
  var CATEGORIES = [
11939
11958
  { key: "ooh", label: "OOH", icon: "flag-banner", color: "var(--ch-ooh)" },
11940
11959
  { key: "transit", label: "Transit", icon: "bus", color: "var(--ch-transit)" },
@@ -11946,26 +11965,26 @@ var CATEGORIES = [
11946
11965
  function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost, className = "" }) {
11947
11966
  const earned = Math.max(0, Math.min(1, bonusPct / bonusMax));
11948
11967
  const single = present.length <= 2;
11949
- return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, children: [
11950
- /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: CATEGORIES.map((c) => {
11968
+ return /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, children: [
11969
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: CATEGORIES.map((c) => {
11951
11970
  const on = present.includes(c.key);
11952
- return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(
11971
+ return /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)(
11953
11972
  "span",
11954
11973
  {
11955
11974
  title: c.label + (on ? " \u2014 present" : " \u2014 not bought"),
11956
11975
  style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 5, width: 62, padding: "10px 0", borderRadius: "var(--r-md)", border: "1px solid " + (on ? "var(--csi-2-edge)" : "var(--border)"), background: on ? "var(--csi-2-fill)" : "var(--surface-2)", color: on ? "var(--csi-2-text)" : "var(--text-disabled)" },
11957
11976
  children: [
11958
- /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("i", { className: "ph ph-" + c.icon, style: { fontSize: 19, color: on ? c.color : "var(--text-muted)" }, "aria-hidden": "true" }),
11959
- /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("span", { style: { fontSize: 10.5, fontWeight: 700 }, children: c.label })
11977
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("i", { className: "ph ph-" + c.icon, style: { fontSize: 19, color: on ? c.color : "var(--text-muted)" }, "aria-hidden": "true" }),
11978
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("span", { style: { fontSize: 10.5, fontWeight: 700 }, children: c.label })
11960
11979
  ]
11961
11980
  },
11962
11981
  c.key
11963
11982
  );
11964
11983
  }) }),
11965
- /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("div", { className: "fd-stack", style: { gap: 8 }, children: [
11966
- /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
11967
- /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("span", { className: "fd-label-lg", children: "Surround-sound bonus earned" }),
11968
- /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("span", { className: "fd-num", style: { color: single ? "var(--warn-text)" : "var(--csi-3-mark)", fontWeight: 700 }, children: [
11984
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("div", { className: "fd-stack", style: { gap: 8 }, children: [
11985
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
11986
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("span", { className: "fd-label-lg", children: "Surround-sound bonus earned" }),
11987
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("span", { className: "fd-num", style: { color: single ? "var(--warn-text)" : "var(--csi-3-mark)", fontWeight: 700 }, children: [
11969
11988
  "+",
11970
11989
  bonusPct,
11971
11990
  "% of +",
@@ -11973,8 +11992,8 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
11973
11992
  "%"
11974
11993
  ] })
11975
11994
  ] }),
11976
- /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("div", { style: { height: 8, borderRadius: "var(--r-xs)", background: "var(--surface-3)", overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("div", { style: { height: "100%", width: earned * 100 + "%", background: "var(--csi-3-mark)", borderRadius: "inherit", transition: "width var(--dur-slow) var(--ease)" } }) }),
11977
- /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: [
11995
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("div", { style: { height: 8, borderRadius: "var(--r-xs)", background: "var(--surface-3)", overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("div", { style: { height: "100%", width: earned * 100 + "%", background: "var(--csi-3-mark)", borderRadius: "inherit", transition: "width var(--dur-slow) var(--ease)" } }) }),
11996
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: [
11978
11997
  present.length,
11979
11998
  " of 6 channel categories present.",
11980
11999
  " ",
@@ -11986,7 +12005,7 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
11986
12005
  }
11987
12006
 
11988
12007
  // src/components/planner/Importance.tsx
11989
- var import_jsx_runtime92 = require("react/jsx-runtime");
12008
+ var import_jsx_runtime93 = require("react/jsx-runtime");
11990
12009
  var IMPORTANCE_LEVELS = [
11991
12010
  { id: "nudge", rank: 1, label: "Nudge", icon: "feather", description: "Breaks a tie, nothing more." },
11992
12011
  { id: "lean", rank: 2, label: "Lean", icon: "arrow-bend-up-right", description: "A mild preference between otherwise equal options." },
@@ -12016,7 +12035,7 @@ function importanceTokens(id) {
12016
12035
  function ImportanceTag({ level, showLabel = true, size = "sm", className = "", disabled = false }) {
12017
12036
  const lvl = importanceLevel(level);
12018
12037
  const t = importanceTokens(level);
12019
- return /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)(
12038
+ return /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)(
12020
12039
  "span",
12021
12040
  {
12022
12041
  className: ["fd-imp-tag", size === "md" ? "is-md" : "", disabled ? "is-disabled" : "", className].filter(Boolean).join(" "),
@@ -12024,16 +12043,16 @@ function ImportanceTag({ level, showLabel = true, size = "sm", className = "", d
12024
12043
  title: lvl.label + " \u2014 " + lvl.description,
12025
12044
  "aria-disabled": disabled ? "true" : void 0,
12026
12045
  children: [
12027
- /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("i", { className: "ph ph-" + lvl.icon, "aria-hidden": "true" }),
12028
- showLabel ? lvl.label : /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("span", { className: "fd-sr", children: lvl.label })
12046
+ /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("i", { className: "ph ph-" + lvl.icon, "aria-hidden": "true" }),
12047
+ showLabel ? lvl.label : /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("span", { className: "fd-sr", children: lvl.label })
12029
12048
  ]
12030
12049
  }
12031
12050
  );
12032
12051
  }
12033
12052
 
12034
12053
  // src/components/planner/PreferenceMeter.tsx
12035
- var React62 = __toESM(require("react"), 1);
12036
- var import_jsx_runtime93 = require("react/jsx-runtime");
12054
+ var React63 = __toESM(require("react"), 1);
12055
+ var import_jsx_runtime94 = require("react/jsx-runtime");
12037
12056
  function preferenceScore(criteria) {
12038
12057
  const earned = criteria.reduce((n, c) => n + (Number(c.earned) || 0), 0);
12039
12058
  const weight = criteria.reduce((n, c) => n + (Number(c.weight) || 0), 0);
@@ -12062,8 +12081,8 @@ function PreferenceMeter({
12062
12081
  className = ""
12063
12082
  }) {
12064
12083
  const value = score == null ? preferenceScore(criteria) : score;
12065
- const segments = React62.useMemo(() => preferenceSegments(criteria), [criteria]);
12066
- return /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(
12084
+ const segments = React63.useMemo(() => preferenceSegments(criteria), [criteria]);
12085
+ return /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(
12067
12086
  ScoreMeter,
12068
12087
  {
12069
12088
  score: value,
@@ -12075,22 +12094,22 @@ function PreferenceMeter({
12075
12094
  placement,
12076
12095
  className,
12077
12096
  breakdownLabel: breakdownTitle,
12078
- breakdown: /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)("div", { className: "fd-prefbreak", children: [
12079
- /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)("div", { className: "fd-prefbreak-head", children: [
12080
- /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("span", { className: "fd-label-lg", children: breakdownTitle }),
12081
- /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("span", { className: "fd-prefbreak-score fd-tabular", children: Math.round(value) })
12097
+ breakdown: /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("div", { className: "fd-prefbreak", children: [
12098
+ /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("div", { className: "fd-prefbreak-head", children: [
12099
+ /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fd-label-lg", children: breakdownTitle }),
12100
+ /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fd-prefbreak-score fd-tabular", children: Math.round(value) })
12082
12101
  ] }),
12083
- /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("ul", { className: "fd-prefbreak-list", children: criteria.map((c) => {
12102
+ /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("ul", { className: "fd-prefbreak-list", children: criteria.map((c) => {
12084
12103
  const pct = c.weight > 0 ? Math.round((Number(c.earned) || 0) / c.weight * 100) : 0;
12085
- return /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)("li", { className: pct === 0 ? "fd-prefbreak-item is-unmet" : "fd-prefbreak-item", children: [
12086
- /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(ImportanceTag, { level: c.importance }),
12087
- /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)("span", { className: "fd-prefbreak-text", children: [
12088
- /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("span", { className: "fd-prefbreak-label", children: c.label }),
12089
- c.note ? /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("span", { className: "fd-prefbreak-note", children: c.note }) : null
12104
+ return /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("li", { className: pct === 0 ? "fd-prefbreak-item is-unmet" : "fd-prefbreak-item", children: [
12105
+ /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(ImportanceTag, { level: c.importance }),
12106
+ /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("span", { className: "fd-prefbreak-text", children: [
12107
+ /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fd-prefbreak-label", children: c.label }),
12108
+ c.note ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fd-prefbreak-note", children: c.note }) : null
12090
12109
  ] }),
12091
- /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)("span", { className: "fd-prefbreak-val fd-tabular", children: [
12110
+ /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("span", { className: "fd-prefbreak-val fd-tabular", children: [
12092
12111
  Math.round(Number(c.earned) || 0),
12093
- /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("span", { className: "fd-prefbreak-sep", children: "/" }),
12112
+ /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fd-prefbreak-sep", children: "/" }),
12094
12113
  Math.round(c.weight)
12095
12114
  ] })
12096
12115
  ] }, c.id);
@@ -12101,10 +12120,10 @@ function PreferenceMeter({
12101
12120
  }
12102
12121
 
12103
12122
  // src/components/chat/AgentChatPanel.tsx
12104
- var React68 = __toESM(require("react"), 1);
12123
+ var React69 = __toESM(require("react"), 1);
12105
12124
 
12106
12125
  // src/components/chat/chatEngine.ts
12107
- var React63 = __toESM(require("react"), 1);
12126
+ var React64 = __toESM(require("react"), 1);
12108
12127
  var CHAT_UNAVAILABLE = "chat_unavailable";
12109
12128
  var JOB_PENDING = ["queued", "running"];
12110
12129
  var JOB_SUCCESS = ["completed", "recovered"];
@@ -12158,22 +12177,22 @@ function useChatEngine(opts) {
12158
12177
  onClear,
12159
12178
  onFeedback
12160
12179
  } = opts || {};
12161
- const [status, setStatus] = React63.useState("idle");
12162
- const [threadId, setThreadId] = React63.useState(null);
12163
- const [messages, setMessages] = React63.useState([]);
12164
- const [queue, setQueue] = React63.useState([]);
12165
- const [fatal, setFatal] = React63.useState(null);
12166
- const [busy, setBusy] = React63.useState(false);
12167
- const [turnStartedAt, setTurnStartedAt] = React63.useState(null);
12168
- const listRef = React63.useRef([]);
12169
- const queueRef = React63.useRef([]);
12170
- const busyRef = React63.useRef(false);
12171
- const stoppedRef = React63.useRef(false);
12172
- const abortRef = React63.useRef(null);
12173
- const serverCount = React63.useRef(0);
12174
- const threadRef = React63.useRef(null);
12175
- const mounted = React63.useRef(true);
12176
- React63.useEffect(() => {
12180
+ const [status, setStatus] = React64.useState("idle");
12181
+ const [threadId, setThreadId] = React64.useState(null);
12182
+ const [messages, setMessages] = React64.useState([]);
12183
+ const [queue, setQueue] = React64.useState([]);
12184
+ const [fatal, setFatal] = React64.useState(null);
12185
+ const [busy, setBusy] = React64.useState(false);
12186
+ const [turnStartedAt, setTurnStartedAt] = React64.useState(null);
12187
+ const listRef = React64.useRef([]);
12188
+ const queueRef = React64.useRef([]);
12189
+ const busyRef = React64.useRef(false);
12190
+ const stoppedRef = React64.useRef(false);
12191
+ const abortRef = React64.useRef(null);
12192
+ const serverCount = React64.useRef(0);
12193
+ const threadRef = React64.useRef(null);
12194
+ const mounted = React64.useRef(true);
12195
+ React64.useEffect(() => {
12177
12196
  mounted.current = true;
12178
12197
  return () => {
12179
12198
  mounted.current = false;
@@ -12195,14 +12214,14 @@ function useChatEngine(opts) {
12195
12214
  }
12196
12215
  return false;
12197
12216
  };
12198
- const loadThread = React63.useCallback(async (id) => {
12217
+ const loadThread = React64.useCallback(async (id) => {
12199
12218
  const data = await apiAdapter.getThread(id);
12200
12219
  const list = [...data && data.messages || []];
12201
12220
  serverCount.current = list.length;
12202
12221
  commit(list);
12203
12222
  return list;
12204
12223
  }, [apiAdapter]);
12205
- React63.useEffect(() => {
12224
+ React64.useEffect(() => {
12206
12225
  if (!apiAdapter) {
12207
12226
  setStatus("idle");
12208
12227
  setFatal(null);
@@ -12415,7 +12434,7 @@ function useChatEngine(opts) {
12415
12434
  await dispatchTurn(turn);
12416
12435
  }
12417
12436
  }
12418
- const send = React63.useCallback((text, attachments) => {
12437
+ const send = React64.useCallback((text, attachments) => {
12419
12438
  const body = (text || "").trim();
12420
12439
  if (!body && !(attachments && attachments.length)) return;
12421
12440
  if (status === "disconnected") return;
@@ -12425,7 +12444,7 @@ function useChatEngine(opts) {
12425
12444
  stoppedRef.current = false;
12426
12445
  drain();
12427
12446
  }, [status]);
12428
- const stop = React63.useCallback(() => {
12447
+ const stop = React64.useCallback(() => {
12429
12448
  stoppedRef.current = true;
12430
12449
  const ac = abortRef.current;
12431
12450
  if (ac) {
@@ -12444,11 +12463,11 @@ function useChatEngine(opts) {
12444
12463
  store.del(STORAGE_PREFIX + threadRef.current);
12445
12464
  }
12446
12465
  }, [apiAdapter]);
12447
- const removeQueued = React63.useCallback((id) => {
12466
+ const removeQueued = React64.useCallback((id) => {
12448
12467
  queueRef.current = queueRef.current.filter((t) => t.id !== id);
12449
12468
  setQueue(queueRef.current.slice());
12450
12469
  }, []);
12451
- const retry = React63.useCallback(() => {
12470
+ const retry = React64.useCallback(() => {
12452
12471
  const list = listRef.current;
12453
12472
  let at = -1;
12454
12473
  for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
@@ -12464,19 +12483,19 @@ function useChatEngine(opts) {
12464
12483
  setQueue(queueRef.current.slice());
12465
12484
  drain();
12466
12485
  }, []);
12467
- const clear = React63.useCallback(() => {
12486
+ const clear = React64.useCallback(() => {
12468
12487
  commit([]);
12469
12488
  serverCount.current = 0;
12470
12489
  queueRef.current = [];
12471
12490
  setQueue([]);
12472
12491
  onClear && onClear();
12473
12492
  }, [onClear]);
12474
- const setFeedback = React63.useCallback((id, value) => {
12493
+ const setFeedback = React64.useCallback((id, value) => {
12475
12494
  patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
12476
12495
  const msg = listRef.current.find((m) => m.id === id);
12477
12496
  onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
12478
12497
  }, [onFeedback]);
12479
- const reload = React63.useCallback(async () => {
12498
+ const reload = React64.useCallback(async () => {
12480
12499
  if (!threadRef.current) return;
12481
12500
  setStatus("loading");
12482
12501
  try {
@@ -12514,11 +12533,11 @@ var ChatKit = {
12514
12533
  };
12515
12534
 
12516
12535
  // src/components/chat/ChatTranscript.tsx
12517
- var React65 = __toESM(require("react"), 1);
12536
+ var React66 = __toESM(require("react"), 1);
12518
12537
 
12519
12538
  // src/components/chat/ChatTurn.tsx
12520
- var React64 = __toESM(require("react"), 1);
12521
- var import_jsx_runtime94 = require("react/jsx-runtime");
12539
+ var React65 = __toESM(require("react"), 1);
12540
+ var import_jsx_runtime95 = require("react/jsx-runtime");
12522
12541
  function JsonView({ value }) {
12523
12542
  let text;
12524
12543
  try {
@@ -12526,67 +12545,67 @@ function JsonView({ value }) {
12526
12545
  } catch (e) {
12527
12546
  text = String(value);
12528
12547
  }
12529
- return /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(CodeBlock, { code: text, language: "json", collapseAfter: 18 });
12548
+ return /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(CodeBlock, { code: text, language: "json", collapseAfter: 18 });
12530
12549
  }
12531
12550
  function PacketCard({ packet, schema, render, onApply, applied }) {
12532
12551
  if (!packet) return null;
12533
12552
  const s = schema || {};
12534
12553
  const invalid = packet.valid === false;
12535
12554
  const title = s.heading || packet.type;
12536
- return /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("section", { className: "fdc-packet" + (invalid ? " is-invalid" : ""), "aria-label": title, children: [
12537
- /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("header", { className: "fdc-packet-head", children: [
12538
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("i", { className: "ph ph-" + (s.icon || "package"), "aria-hidden": "true" }),
12539
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fdc-packet-title", title: truncationTitle(title), children: title }),
12540
- packet.repaired ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fdc-packet-badge", children: "Repaired" }) : null,
12541
- invalid ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fdc-packet-badge is-danger", children: "Invalid" }) : null
12555
+ return /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("section", { className: "fdc-packet" + (invalid ? " is-invalid" : ""), "aria-label": title, children: [
12556
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("header", { className: "fdc-packet-head", children: [
12557
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-" + (s.icon || "package"), "aria-hidden": "true" }),
12558
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-packet-title", title: truncationTitle(title), children: title }),
12559
+ packet.repaired ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-packet-badge", children: "Repaired" }) : null,
12560
+ invalid ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-packet-badge is-danger", children: "Invalid" }) : null
12542
12561
  ] }),
12543
- invalid ? /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("div", { className: "fdc-packet-alert", role: "alert", children: [
12544
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
12545
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { children: packet.error || "This result failed validation and can\u2019t be applied." })
12546
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("div", { className: "fdc-packet-body", children: render ? render(packet) : /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(JsonView, { value: packet.payload }) }),
12547
- !invalid && onApply ? /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("footer", { className: "fdc-packet-foot", children: [
12548
- packet.repaired ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fdc-packet-note", children: "Corrected by the backend after a first attempt." }) : /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", {}),
12549
- /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", disabled: applied, onClick: () => onApply(packet), children: [
12550
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("i", { className: "ph ph-" + (applied ? "check" : "arrow-square-in"), "aria-hidden": "true" }),
12562
+ invalid ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-packet-alert", role: "alert", children: [
12563
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
12564
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { children: packet.error || "This result failed validation and can\u2019t be applied." })
12565
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("div", { className: "fdc-packet-body", children: render ? render(packet) : /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(JsonView, { value: packet.payload }) }),
12566
+ !invalid && onApply ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("footer", { className: "fdc-packet-foot", children: [
12567
+ packet.repaired ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-packet-note", children: "Corrected by the backend after a first attempt." }) : /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", {}),
12568
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", disabled: applied, onClick: () => onApply(packet), children: [
12569
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-" + (applied ? "check" : "arrow-square-in"), "aria-hidden": "true" }),
12551
12570
  applied ? "Applied" : s.applyLabel || "Apply"
12552
12571
  ] })
12553
12572
  ] }) : null
12554
12573
  ] });
12555
12574
  }
12556
12575
  function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
12557
- const [open2, setOpen] = React64.useState(defaultOpen);
12576
+ const [open2, setOpen] = React65.useState(defaultOpen);
12558
12577
  if (!text) return null;
12559
- return /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("div", { className: "fdc-think" + (open2 ? " is-open" : ""), children: [
12560
- /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open2, children: [
12561
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("i", { className: "ph ph-brain", "aria-hidden": "true" }),
12562
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { children: streaming ? "Thinking" : durationMs ? "Thought for " + formatDuration(durationMs) : "Thought process" }),
12563
- streaming ? /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("span", { className: "fdc-dots", "aria-hidden": "true", children: [
12564
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", {}),
12565
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", {}),
12566
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", {})
12578
+ return /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-think" + (open2 ? " is-open" : ""), children: [
12579
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open2, children: [
12580
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-brain", "aria-hidden": "true" }),
12581
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { children: streaming ? "Thinking" : durationMs ? "Thought for " + formatDuration(durationMs) : "Thought process" }),
12582
+ streaming ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("span", { className: "fdc-dots", "aria-hidden": "true", children: [
12583
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", {}),
12584
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", {}),
12585
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", {})
12567
12586
  ] }) : null,
12568
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("i", { className: "ph ph-caret-" + (open2 ? "up" : "down"), "aria-hidden": "true" })
12587
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-caret-" + (open2 ? "up" : "down"), "aria-hidden": "true" })
12569
12588
  ] }),
12570
- open2 ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("div", { className: "fdc-think-body", children: text }) : null
12589
+ open2 ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("div", { className: "fdc-think-body", children: text }) : null
12571
12590
  ] });
12572
12591
  }
12573
12592
  function Citations({ items = [], onOpen }) {
12574
- const [open2, setOpen] = React64.useState(false);
12593
+ const [open2, setOpen] = React65.useState(false);
12575
12594
  if (!items.length) return null;
12576
- return /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("div", { className: "fdc-cites", children: [
12577
- /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open2, children: [
12578
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("i", { className: "ph ph-quotes", "aria-hidden": "true" }),
12579
- /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("span", { children: [
12595
+ return /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-cites", children: [
12596
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open2, children: [
12597
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-quotes", "aria-hidden": "true" }),
12598
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("span", { children: [
12580
12599
  items.length,
12581
12600
  " source",
12582
12601
  items.length === 1 ? "" : "s"
12583
12602
  ] }),
12584
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("i", { className: "ph ph-caret-" + (open2 ? "up" : "down"), "aria-hidden": "true" })
12603
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-caret-" + (open2 ? "up" : "down"), "aria-hidden": "true" })
12585
12604
  ] }),
12586
- open2 ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("ol", { className: "fdc-cites-list", children: items.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("li", { children: [
12587
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fdc-cite-n fd-tabular", children: c.marker || i + 1 }),
12588
- c.url ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("a", { href: c.url, target: "_blank", rel: "noopener noreferrer", onClick: onOpen ? (e) => onOpen(c, e) : void 0, children: c.title || c.url }) : /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { children: c.title || "Source" }),
12589
- c.detail ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fdc-cite-detail", children: c.detail }) : null
12605
+ open2 ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("ol", { className: "fdc-cites-list", children: items.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("li", { children: [
12606
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-cite-n fd-tabular", children: c.marker || i + 1 }),
12607
+ c.url ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("a", { href: c.url, target: "_blank", rel: "noopener noreferrer", onClick: onOpen ? (e) => onOpen(c, e) : void 0, children: c.title || c.url }) : /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { children: c.title || "Source" }),
12608
+ c.detail ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-cite-detail", children: c.detail }) : null
12590
12609
  ] }, c.id || i)) }) : null
12591
12610
  ] });
12592
12611
  }
@@ -12597,29 +12616,29 @@ function clampText(text, max) {
12597
12616
  return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
12598
12617
  }
12599
12618
  function MessageBody({ message: m, ctx }) {
12600
- const [expanded, setExpanded] = React64.useState(false);
12619
+ const [expanded, setExpanded] = React65.useState(false);
12601
12620
  const isUser = m.role === "user";
12602
12621
  const raw = m.text || "";
12603
12622
  const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
12604
12623
  const body = clamped != null ? clamped : raw;
12605
12624
  const showMd = ctx.markdown && !isUser;
12606
- return /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("div", { className: "fdc-body", children: [
12607
- m.thinking && ctx.showThinking ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(ThinkingBlock, { text: m.thinking, durationMs: m.thinkingMs, streaming: m.streaming && !m.text }) : null,
12608
- m.steps && m.steps.length && ctx.showSteps ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(StepList, { steps: m.steps, defaultOpen: m.steps.some((s) => s.status === "running"), dense: true }) : null,
12609
- body ? /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("div", { className: "fdc-text" + (isUser ? " is-user" : ""), children: [
12610
- showMd ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(Markdown, { source: body, headingOffset: 2, codeProps: { collapseAfter: 22 }, renderCitation: ctx.renderCitation }) : /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("div", { className: "fdc-plain", children: body }),
12611
- m.streaming ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fdc-caret", "aria-hidden": "true" }) : null
12625
+ return /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-body", children: [
12626
+ m.thinking && ctx.showThinking ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(ThinkingBlock, { text: m.thinking, durationMs: m.thinkingMs, streaming: m.streaming && !m.text }) : null,
12627
+ m.steps && m.steps.length && ctx.showSteps ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(StepList, { steps: m.steps, defaultOpen: m.steps.some((s) => s.status === "running"), dense: true }) : null,
12628
+ body ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-text" + (isUser ? " is-user" : ""), children: [
12629
+ showMd ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(Markdown, { source: body, headingOffset: 2, codeProps: { collapseAfter: 22 }, renderCitation: ctx.renderCitation }) : /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("div", { className: "fdc-plain", children: body }),
12630
+ m.streaming ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-caret", "aria-hidden": "true" }) : null
12612
12631
  ] }) : null,
12613
- clamped != null ? /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(true), children: [
12614
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("i", { className: "ph ph-caret-down", "aria-hidden": "true" }),
12632
+ clamped != null ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(true), children: [
12633
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-caret-down", "aria-hidden": "true" }),
12615
12634
  "Show more",
12616
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fdc-more-len fd-tabular", children: raw.length < 2e3 ? raw.length.toLocaleString() + " characters" : Math.round(raw.length / 100) / 10 + "k characters" })
12617
- ] }) : expanded && ctx.maxVisibleChars && raw.length > ctx.maxVisibleChars ? /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(false), children: [
12618
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("i", { className: "ph ph-caret-up", "aria-hidden": "true" }),
12635
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-more-len fd-tabular", children: raw.length < 2e3 ? raw.length.toLocaleString() + " characters" : Math.round(raw.length / 100) / 10 + "k characters" })
12636
+ ] }) : expanded && ctx.maxVisibleChars && raw.length > ctx.maxVisibleChars ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(false), children: [
12637
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-caret-up", "aria-hidden": "true" }),
12619
12638
  "Show less"
12620
12639
  ] }) : null,
12621
- m.attachments && m.attachments.length ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(FileGrid, { files: m.attachments, onOpen: ctx.onOpenAttachment, tiles: true, maxHeight: ctx.attachmentHeight || 220, compact: ctx.narrow }) : null,
12622
- m.packet ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(
12640
+ m.attachments && m.attachments.length ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(FileGrid, { files: m.attachments, onOpen: ctx.onOpenAttachment, tiles: true, maxHeight: ctx.attachmentHeight || 220, compact: ctx.narrow }) : null,
12641
+ m.packet ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(
12623
12642
  PacketCard,
12624
12643
  {
12625
12644
  packet: m.packet,
@@ -12629,35 +12648,35 @@ function MessageBody({ message: m, ctx }) {
12629
12648
  applied: ctx.appliedPackets && ctx.appliedPackets[m.id]
12630
12649
  }
12631
12650
  ) : null,
12632
- m.citations && m.citations.length ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(Citations, { items: m.citations, onOpen: ctx.onOpenCitation }) : null,
12633
- m.working ? /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("div", { className: "fdc-working", role: "status", children: [
12634
- /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("span", { className: "fdc-dots", "aria-hidden": "true", children: [
12635
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", {}),
12636
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", {}),
12637
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", {})
12651
+ m.citations && m.citations.length ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(Citations, { items: m.citations, onOpen: ctx.onOpenCitation }) : null,
12652
+ m.working ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-working", role: "status", children: [
12653
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("span", { className: "fdc-dots", "aria-hidden": "true", children: [
12654
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", {}),
12655
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", {}),
12656
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", {})
12638
12657
  ] }),
12639
- /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("span", { className: "fdc-working-label", children: [
12658
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("span", { className: "fdc-working-label", children: [
12640
12659
  m.resumed ? "Resuming" : "Working",
12641
- m.job && m.job.status ? /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("span", { className: "fdc-working-job", children: [
12660
+ m.job && m.job.status ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("span", { className: "fdc-working-job", children: [
12642
12661
  " \xB7 ",
12643
12662
  m.job.status
12644
12663
  ] }) : null,
12645
- m.job && m.job.detail ? /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("span", { className: "fdc-working-job", children: [
12664
+ m.job && m.job.detail ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("span", { className: "fdc-working-job", children: [
12646
12665
  " \xB7 ",
12647
12666
  m.job.detail
12648
12667
  ] }) : null
12649
12668
  ] }),
12650
- m.jobId ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fdc-working-id fd-mono", children: String(m.jobId).slice(0, 12) }) : null
12669
+ m.jobId ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-working-id fd-mono", children: String(m.jobId).slice(0, 12) }) : null
12651
12670
  ] }) : null,
12652
- m.stopped ? /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("div", { className: "fdc-stopped", children: [
12653
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
12671
+ m.stopped ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-stopped", children: [
12672
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
12654
12673
  "Stopped"
12655
12674
  ] }) : null,
12656
- m.error ? /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("div", { className: "fdc-error", role: "alert", children: [
12657
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
12658
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fdc-error-text", children: ctx.errorCopy ? ctx.errorCopy(m.error) : m.error }),
12659
- m.retryable && ctx.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("button", { type: "button", className: "fdc-error-retry", onClick: ctx.onRetry, children: [
12660
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
12675
+ m.error ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-error", role: "alert", children: [
12676
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
12677
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-error-text", children: ctx.errorCopy ? ctx.errorCopy(m.error) : m.error }),
12678
+ m.retryable && ctx.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("button", { type: "button", className: "fdc-error-retry", onClick: ctx.onRetry, children: [
12679
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
12661
12680
  "Retry"
12662
12681
  ] }) : null
12663
12682
  ] }) : null
@@ -12670,16 +12689,16 @@ function RunActions({ group, ctx }) {
12670
12689
  const isAssistant = group.role === "assistant";
12671
12690
  const fb = last.feedback;
12672
12691
  if (!ctx.messageActions) return null;
12673
- return /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("div", { className: "fdc-actions", role: "group", "aria-label": "Message actions", children: [
12674
- /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("button", { type: "button", className: "fdc-act" + (copied ? " is-done" : ""), onClick: () => copy(markdownToText(text)), "aria-label": "Copy message", children: [
12675
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("i", { className: "ph ph-" + (copied ? "check" : "copy"), "aria-hidden": "true" }),
12676
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fdc-act-label", children: copied ? "Copied" : "Copy" })
12692
+ return /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-actions", role: "group", "aria-label": "Message actions", children: [
12693
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("button", { type: "button", className: "fdc-act" + (copied ? " is-done" : ""), onClick: () => copy(markdownToText(text)), "aria-label": "Copy message", children: [
12694
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-" + (copied ? "check" : "copy"), "aria-hidden": "true" }),
12695
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-act-label", children: copied ? "Copied" : "Copy" })
12677
12696
  ] }),
12678
- isAssistant && ctx.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("button", { type: "button", className: "fdc-act", onClick: ctx.onRetry, "aria-label": "Retry this turn", children: /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
12679
- group.role === "user" && ctx.onEdit ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("button", { type: "button", className: "fdc-act", onClick: () => ctx.onEdit(last), "aria-label": "Edit and resend", children: /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("i", { className: "ph ph-pencil-simple", "aria-hidden": "true" }) }) : null,
12680
- isAssistant && ctx.onFeedback ? /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)(React64.Fragment, { children: [
12681
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("button", { type: "button", className: "fdc-act" + (fb === "up" ? " is-on" : ""), onClick: () => ctx.onFeedback(last.id, "up"), "aria-pressed": fb === "up", "aria-label": "Good response", children: /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("i", { className: "ph ph-thumbs-up", "aria-hidden": "true" }) }),
12682
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("button", { type: "button", className: "fdc-act" + (fb === "down" ? " is-on" : ""), onClick: () => ctx.onFeedback(last.id, "down"), "aria-pressed": fb === "down", "aria-label": "Bad response", children: /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("i", { className: "ph ph-thumbs-down", "aria-hidden": "true" }) })
12697
+ isAssistant && ctx.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("button", { type: "button", className: "fdc-act", onClick: ctx.onRetry, "aria-label": "Retry this turn", children: /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
12698
+ group.role === "user" && ctx.onEdit ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("button", { type: "button", className: "fdc-act", onClick: () => ctx.onEdit(last), "aria-label": "Edit and resend", children: /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-pencil-simple", "aria-hidden": "true" }) }) : null,
12699
+ isAssistant && ctx.onFeedback ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)(React65.Fragment, { children: [
12700
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("button", { type: "button", className: "fdc-act" + (fb === "up" ? " is-on" : ""), onClick: () => ctx.onFeedback(last.id, "up"), "aria-pressed": fb === "up", "aria-label": "Good response", children: /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-thumbs-up", "aria-hidden": "true" }) }),
12701
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("button", { type: "button", className: "fdc-act" + (fb === "down" ? " is-on" : ""), onClick: () => ctx.onFeedback(last.id, "down"), "aria-pressed": fb === "down", "aria-label": "Bad response", children: /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-thumbs-down", "aria-hidden": "true" }) })
12683
12702
  ] }) : null,
12684
12703
  ctx.extraActions ? ctx.extraActions(group) : null
12685
12704
  ] });
@@ -12689,22 +12708,22 @@ function ChatTurn({ group, ctx }) {
12689
12708
  const name = isUser ? ctx.userName : group.author || ctx.assistantName;
12690
12709
  const avatar = isUser ? ctx.userAvatar : ctx.assistantAvatar;
12691
12710
  const stamp = group.messages[0].timestamp;
12692
- return /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("article", { className: "fdc-turn is-" + group.role, "aria-label": String(name) + (stamp ? " at " + formatClock(stamp) : ""), children: [
12693
- /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("div", { className: "fdc-turn-head", children: [
12694
- ctx.showAvatars ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fdc-avatar is-" + group.role, "aria-hidden": "true", children: avatar ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("img", { src: avatar, alt: "" }) : isUser ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fdc-avatar-txt", children: (name || "You").slice(0, 1).toUpperCase() }) : /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("i", { className: "ph ph-" + (ctx.assistantIcon || "sparkle") }) }) : null,
12695
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fdc-who", children: name }),
12696
- stamp ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(RelativeTime, { className: "fdc-when", value: stamp }) : null,
12697
- group.messages.some((m) => m.model) ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fdc-turn-model", children: group.messages.find((m) => m.model).model }) : null
12711
+ return /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("article", { className: "fdc-turn is-" + group.role, "aria-label": String(name) + (stamp ? " at " + formatClock(stamp) : ""), children: [
12712
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-turn-head", children: [
12713
+ ctx.showAvatars ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-avatar is-" + group.role, "aria-hidden": "true", children: avatar ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("img", { src: avatar, alt: "" }) : isUser ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-avatar-txt", children: (name || "You").slice(0, 1).toUpperCase() }) : /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-" + (ctx.assistantIcon || "sparkle") }) }) : null,
12714
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-who", children: name }),
12715
+ stamp ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(RelativeTime, { className: "fdc-when", value: stamp }) : null,
12716
+ group.messages.some((m) => m.model) ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-turn-model", children: group.messages.find((m) => m.model).model }) : null
12698
12717
  ] }),
12699
- /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("div", { className: "fdc-turn-body", children: [
12700
- group.messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("div", { className: "fdc-msg" + (m.pending ? " is-pending" : ""), children: /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(MessageBody, { message: m, ctx }) }, m.id)),
12701
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(RunActions, { group, ctx })
12718
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-turn-body", children: [
12719
+ group.messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("div", { className: "fdc-msg" + (m.pending ? " is-pending" : ""), children: /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(MessageBody, { message: m, ctx }) }, m.id)),
12720
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(RunActions, { group, ctx })
12702
12721
  ] })
12703
12722
  ] });
12704
12723
  }
12705
12724
 
12706
12725
  // src/components/chat/ChatTranscript.tsx
12707
- var import_jsx_runtime95 = require("react/jsx-runtime");
12726
+ var import_jsx_runtime96 = require("react/jsx-runtime");
12708
12727
  var GROUP_WINDOW = 6e4;
12709
12728
  var STICK_PX = 100;
12710
12729
  function groupMessages(list) {
@@ -12737,25 +12756,25 @@ function dayLabel(key) {
12737
12756
  }
12738
12757
  function Suggestions({ items = [], onPick }) {
12739
12758
  if (!items.length) return null;
12740
- return /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("div", { className: "fdc-suggest", children: items.map((s, i) => {
12759
+ return /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("div", { className: "fdc-suggest", children: items.map((s, i) => {
12741
12760
  const it = typeof s === "string" ? { label: s, text: s } : s;
12742
- return /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("button", { type: "button", className: "fdc-suggest-item", onClick: () => onPick && onPick(it.text || it.label), children: [
12743
- it.icon ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-" + it.icon, "aria-hidden": "true" }) : null,
12744
- /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("span", { className: "fdc-suggest-text", children: [
12745
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-suggest-label", children: it.label }),
12746
- it.description ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-suggest-desc", children: it.description }) : null
12761
+ return /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("button", { type: "button", className: "fdc-suggest-item", onClick: () => onPick && onPick(it.text || it.label), children: [
12762
+ it.icon ? /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("i", { className: "ph ph-" + it.icon, "aria-hidden": "true" }) : null,
12763
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("span", { className: "fdc-suggest-text", children: [
12764
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("span", { className: "fdc-suggest-label", children: it.label }),
12765
+ it.description ? /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("span", { className: "fdc-suggest-desc", children: it.description }) : null
12747
12766
  ] }),
12748
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-arrow-up-right fdc-suggest-go", "aria-hidden": "true" })
12767
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("i", { className: "ph ph-arrow-up-right fdc-suggest-go", "aria-hidden": "true" })
12749
12768
  ] }, it.id || i);
12750
12769
  }) });
12751
12770
  }
12752
12771
  function LoadingTurns() {
12753
- return /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("div", { className: "fdc-skel", "aria-hidden": "true", children: [0, 1].map((i) => /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-skel-turn", children: [
12754
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("div", { className: "fd-skel fd-skel-circle", style: { width: 22, height: 22 } }),
12755
- /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-skel-lines", children: [
12756
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("div", { className: "fd-skel", style: { width: i ? "62%" : "44%", height: 11 } }),
12757
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("div", { className: "fd-skel", style: { width: i ? "94%" : "78%", height: 11 } }),
12758
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("div", { className: "fd-skel", style: { width: i ? "71%" : "56%", height: 11 } })
12772
+ return /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("div", { className: "fdc-skel", "aria-hidden": "true", children: [0, 1].map((i) => /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("div", { className: "fdc-skel-turn", children: [
12773
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("div", { className: "fd-skel fd-skel-circle", style: { width: 22, height: 22 } }),
12774
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("div", { className: "fdc-skel-lines", children: [
12775
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("div", { className: "fd-skel", style: { width: i ? "62%" : "44%", height: 11 } }),
12776
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("div", { className: "fd-skel", style: { width: i ? "94%" : "78%", height: 11 } }),
12777
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("div", { className: "fd-skel", style: { width: i ? "71%" : "56%", height: 11 } })
12759
12778
  ] })
12760
12779
  ] }, i)) });
12761
12780
  }
@@ -12772,10 +12791,10 @@ function ChatTranscript({
12772
12791
  renderEmpty,
12773
12792
  className = ""
12774
12793
  }) {
12775
- const scroller = React65.useRef(null);
12776
- const stick = React65.useRef(true);
12777
- const [pill, setPill] = React65.useState(0);
12778
- const seen = React65.useRef(0);
12794
+ const scroller = React66.useRef(null);
12795
+ const stick = React66.useRef(true);
12796
+ const [pill, setPill] = React66.useState(0);
12797
+ const seen = React66.useRef(0);
12779
12798
  const toBottom = (smooth) => {
12780
12799
  const el = scroller.current;
12781
12800
  if (!el) return;
@@ -12794,7 +12813,7 @@ function ChatTranscript({
12794
12813
  seen.current = messages.length;
12795
12814
  }
12796
12815
  };
12797
- React65.useLayoutEffect(() => {
12816
+ React66.useLayoutEffect(() => {
12798
12817
  const el = scroller.current;
12799
12818
  if (!el) return;
12800
12819
  if (stick.current) {
@@ -12802,7 +12821,7 @@ function ChatTranscript({
12802
12821
  seen.current = messages.length;
12803
12822
  } else setPill(Math.max(0, messages.length - seen.current));
12804
12823
  }, [messages]);
12805
- React65.useEffect(() => {
12824
+ React66.useEffect(() => {
12806
12825
  const el = scroller.current;
12807
12826
  const inner = el && el.firstChild;
12808
12827
  if (!el || !inner || typeof ResizeObserver === "undefined") return;
@@ -12812,38 +12831,38 @@ function ChatTranscript({
12812
12831
  ro.observe(inner);
12813
12832
  return () => ro.disconnect();
12814
12833
  }, []);
12815
- const groups = React65.useMemo(() => groupMessages(messages), [messages]);
12834
+ const groups = React66.useMemo(() => groupMessages(messages), [messages]);
12816
12835
  const empty = !messages.length && status === "ready";
12817
- return /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
12818
- /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
12819
- status === "loading" || status === "resolving" ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(LoadingTurns, {}) : null,
12820
- status === "disconnected" ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-dead", children: [
12821
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-dead-icon", children: /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-plugs", "aria-hidden": "true" }) }),
12822
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("h3", { className: "fdc-dead-title", children: ctx.deadTitle || "The assistant isn\u2019t reachable" }),
12823
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("p", { className: "fdc-dead-body", children: fatal === "chat_unavailable" ? "The service reported chat_unavailable. Nothing you type will be lost \u2014 reopen the panel once it\u2019s back." : "The thread couldn\u2019t be resolved" + (fatal ? " (" + fatal + ")" : "") + ". The composer stays disabled until it resolves." }),
12824
- ctx.onReconnect ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("button", { type: "button", className: "fd-btn fd-btn-secondary fd-btn-sm", onClick: ctx.onReconnect, children: [
12825
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
12836
+ return /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
12837
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
12838
+ status === "loading" || status === "resolving" ? /* @__PURE__ */ (0, import_jsx_runtime96.jsx)(LoadingTurns, {}) : null,
12839
+ status === "disconnected" ? /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("div", { className: "fdc-dead", children: [
12840
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("span", { className: "fdc-dead-icon", children: /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("i", { className: "ph ph-plugs", "aria-hidden": "true" }) }),
12841
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("h3", { className: "fdc-dead-title", children: ctx.deadTitle || "The assistant isn\u2019t reachable" }),
12842
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("p", { className: "fdc-dead-body", children: fatal === "chat_unavailable" ? "The service reported chat_unavailable. Nothing you type will be lost \u2014 reopen the panel once it\u2019s back." : "The thread couldn\u2019t be resolved" + (fatal ? " (" + fatal + ")" : "") + ". The composer stays disabled until it resolves." }),
12843
+ ctx.onReconnect ? /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("button", { type: "button", className: "fd-btn fd-btn-secondary fd-btn-sm", onClick: ctx.onReconnect, children: [
12844
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
12826
12845
  "Try again"
12827
12846
  ] }) : null
12828
12847
  ] }) : null,
12829
- empty ? renderEmpty ? renderEmpty() : /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-empty", children: [
12830
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-empty-icon", children: /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-" + emptyIcon, "aria-hidden": "true" }) }),
12831
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("h3", { className: "fdc-empty-title", children: emptyTitle }),
12832
- emptyDescription ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("p", { className: "fdc-empty-body", children: emptyDescription }) : null,
12833
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(Suggestions, { items: suggestions, onPick })
12848
+ empty ? renderEmpty ? renderEmpty() : /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("div", { className: "fdc-empty", children: [
12849
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("span", { className: "fdc-empty-icon", children: /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("i", { className: "ph ph-" + emptyIcon, "aria-hidden": "true" }) }),
12850
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("h3", { className: "fdc-empty-title", children: emptyTitle }),
12851
+ emptyDescription ? /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("p", { className: "fdc-empty-body", children: emptyDescription }) : null,
12852
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)(Suggestions, { items: suggestions, onPick })
12834
12853
  ] }) : null,
12835
12854
  groups.map((g, i) => {
12836
12855
  const prev = groups[i - 1];
12837
12856
  const k = dayKey(g.messages[0].timestamp);
12838
12857
  const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
12839
- return /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)(React65.Fragment, { children: [
12840
- showDay ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("div", { className: "fdc-day", children: /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { children: dayLabel(k) }) }) : null,
12841
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(ChatTurn, { group: g, ctx })
12858
+ return /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)(React66.Fragment, { children: [
12859
+ showDay ? /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("div", { className: "fdc-day", children: /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("span", { children: dayLabel(k) }) }) : null,
12860
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)(ChatTurn, { group: g, ctx })
12842
12861
  ] }, g.key || i);
12843
12862
  })
12844
12863
  ] }),
12845
- pill ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("button", { type: "button", className: "fdc-pill", onClick: () => toBottom(true), children: [
12846
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-arrow-down", "aria-hidden": "true" }),
12864
+ pill ? /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("button", { type: "button", className: "fdc-pill", onClick: () => toBottom(true), children: [
12865
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("i", { className: "ph ph-arrow-down", "aria-hidden": "true" }),
12847
12866
  pill,
12848
12867
  " new message",
12849
12868
  pill === 1 ? "" : "s"
@@ -12853,8 +12872,8 @@ function ChatTranscript({
12853
12872
  var TranscriptKit = { groupMessages };
12854
12873
 
12855
12874
  // src/components/chat/ChatComposer.tsx
12856
- var React66 = __toESM(require("react"), 1);
12857
- var import_jsx_runtime96 = require("react/jsx-runtime");
12875
+ var React67 = __toESM(require("react"), 1);
12876
+ var import_jsx_runtime97 = require("react/jsx-runtime");
12858
12877
  function ChatComposer({
12859
12878
  onSubmit,
12860
12879
  onStop,
@@ -12881,17 +12900,17 @@ function ChatComposer({
12881
12900
  onReject,
12882
12901
  onOpenAttachment
12883
12902
  }) {
12884
- const [text, setText] = React66.useState(draft || "");
12885
- const [trigger, setTrigger] = React66.useState(null);
12886
- const [mentionItems, setMentionItems] = React66.useState([]);
12887
- const [listening, setListening] = React66.useState(false);
12888
- const [notice, setNotice] = React66.useState(null);
12889
- const editor = React66.useRef(null);
12890
- const wrap = React66.useRef(null);
12891
- const stopVoice = React66.useRef(null);
12903
+ const [text, setText] = React67.useState(draft || "");
12904
+ const [trigger, setTrigger] = React67.useState(null);
12905
+ const [mentionItems, setMentionItems] = React67.useState([]);
12906
+ const [listening, setListening] = React67.useState(false);
12907
+ const [notice, setNotice] = React67.useState(null);
12908
+ const editor = React67.useRef(null);
12909
+ const wrap = React67.useRef(null);
12910
+ const stopVoice = React67.useRef(null);
12892
12911
  const staged = useStagedFiles(fileUploadHandler, { onError: () => {
12893
12912
  } });
12894
- React66.useEffect(() => {
12913
+ React67.useEffect(() => {
12895
12914
  if (draft != null && draft !== text) setText(draft);
12896
12915
  }, [draft]);
12897
12916
  const change = (v) => {
@@ -12927,7 +12946,7 @@ function ChatComposer({
12927
12946
  e.preventDefault();
12928
12947
  staged.add(found.files);
12929
12948
  };
12930
- React66.useEffect(() => {
12949
+ React67.useEffect(() => {
12931
12950
  if (!trigger || trigger.type !== "mention" || !mentionSources) {
12932
12951
  setMentionItems([]);
12933
12952
  return;
@@ -12945,7 +12964,7 @@ function ChatComposer({
12945
12964
  const q = (trigger.query || "").toLowerCase();
12946
12965
  setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
12947
12966
  }, [trigger, mentionSources]);
12948
- const slashItems = React66.useMemo(() => {
12967
+ const slashItems = React67.useMemo(() => {
12949
12968
  if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
12950
12969
  const q = (trigger.query || "").toLowerCase();
12951
12970
  return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
@@ -12959,7 +12978,7 @@ function ChatComposer({
12959
12978
  description: it.description,
12960
12979
  icon: it.icon,
12961
12980
  meta: mention.meta,
12962
- shortcut: slash.shortcut ? /* @__PURE__ */ (0, import_jsx_runtime96.jsx)(KeyHint, { keys: slash.shortcut, size: "sm" }) : void 0,
12981
+ shortcut: slash.shortcut ? /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(KeyHint, { keys: slash.shortcut, size: "sm" }) : void 0,
12963
12982
  onSelect: () => {
12964
12983
  const insert = trigger.type === "slash" ? slash.immediate ? "/" + slash.id : "/" + slash.id + " " : "@" + (mention.value || mention.label) + " ";
12965
12984
  editor.current && editor.current.replaceRange(trigger.from, trigger.to, insert);
@@ -13018,14 +13037,14 @@ function ChatComposer({
13018
13037
  stopVoice.current = typeof res === "function" ? res : () => {
13019
13038
  };
13020
13039
  };
13021
- return /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("div", { className: "fdc-composer" + (disabled ? " is-disabled" : "") + (narrow ? " is-narrow" : ""), children: [
13022
- queue.length ? /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("div", { className: "fdc-queue", "aria-label": "Queued messages", children: queue.map((q) => /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("div", { className: "fdc-queue-row", children: [
13023
- /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("i", { className: "ph ph-clock-countdown", "aria-hidden": "true" }),
13024
- /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("span", { className: "fdc-queue-text", title: truncationTitle(q.text || (q.attachments ? q.attachments.length + " file(s)" : "")), children: q.text || (q.attachments ? q.attachments.length + " file(s)" : "") }),
13025
- onRemoveQueued ? /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("button", { type: "button", className: "fdc-queue-x", onClick: () => onRemoveQueued(q.id), "aria-label": "Remove queued message", children: /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
13040
+ return /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("div", { className: "fdc-composer" + (disabled ? " is-disabled" : "") + (narrow ? " is-narrow" : ""), children: [
13041
+ queue.length ? /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("div", { className: "fdc-queue", "aria-label": "Queued messages", children: queue.map((q) => /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("div", { className: "fdc-queue-row", children: [
13042
+ /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("i", { className: "ph ph-clock-countdown", "aria-hidden": "true" }),
13043
+ /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("span", { className: "fdc-queue-text", title: truncationTitle(q.text || (q.attachments ? q.attachments.length + " file(s)" : "")), children: q.text || (q.attachments ? q.attachments.length + " file(s)" : "") }),
13044
+ onRemoveQueued ? /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("button", { type: "button", className: "fdc-queue-x", onClick: () => onRemoveQueued(q.id), "aria-label": "Remove queued message", children: /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
13026
13045
  ] }, q.id)) }) : null,
13027
13046
  sessionBar,
13028
- /* @__PURE__ */ (0, import_jsx_runtime96.jsx)(
13047
+ /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
13029
13048
  Dropzone,
13030
13049
  {
13031
13050
  className: "fdc-field",
@@ -13039,9 +13058,9 @@ function ChatComposer({
13039
13058
  disabled: !fileUploadHandler || disabled,
13040
13059
  label: "Drop to attach",
13041
13060
  hint: acceptFiles ? acceptFiles.replace(/,/g, " \xB7 ") : void 0,
13042
- children: /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("div", { ref: wrap, className: "fdc-field-inner", children: [
13043
- staged.items.length ? /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("div", { className: "fdc-staged", children: /* @__PURE__ */ (0, import_jsx_runtime96.jsx)(FileStrip, { files: staged.items, size: narrow ? 60 : 68, onRemove: staged.remove, onRetry: staged.retry, onOpen: onOpenAttachment }) }) : null,
13044
- /* @__PURE__ */ (0, import_jsx_runtime96.jsx)(
13061
+ children: /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("div", { ref: wrap, className: "fdc-field-inner", children: [
13062
+ staged.items.length ? /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("div", { className: "fdc-staged", children: /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(FileStrip, { files: staged.items, size: narrow ? 60 : 68, onRemove: staged.remove, onRetry: staged.retry, onOpen: onOpenAttachment }) }) : null,
13063
+ /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
13045
13064
  MarkdownEditor,
13046
13065
  {
13047
13066
  ref: editor,
@@ -13060,33 +13079,33 @@ function ChatComposer({
13060
13079
  ariaLabel: "Message"
13061
13080
  }
13062
13081
  ),
13063
- /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("div", { className: "fdc-tools", children: [
13064
- fileUploadHandler ? /* @__PURE__ */ (0, import_jsx_runtime96.jsx)(FilePickButton, { onFiles: staged.add, onReject: (r) => flash(r[0].message), accept: acceptFiles, maxFileSize, label: "Attach files", icon: "plus" }) : null,
13065
- voiceHandler ? /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("button", { type: "button", className: "fd-attachbtn" + (listening ? " is-live" : ""), onClick: voice, "aria-pressed": listening, "aria-label": listening ? "Stop dictation" : "Dictate", children: /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("i", { className: "ph ph-" + (listening ? "waveform" : "microphone"), "aria-hidden": "true" }) }) : null,
13082
+ /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("div", { className: "fdc-tools", children: [
13083
+ fileUploadHandler ? /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(FilePickButton, { onFiles: staged.add, onReject: (r) => flash(r[0].message), accept: acceptFiles, maxFileSize, label: "Attach files", icon: "plus" }) : null,
13084
+ voiceHandler ? /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("button", { type: "button", className: "fd-attachbtn" + (listening ? " is-live" : ""), onClick: voice, "aria-pressed": listening, "aria-label": listening ? "Stop dictation" : "Dictate", children: /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("i", { className: "ph ph-" + (listening ? "waveform" : "microphone"), "aria-hidden": "true" }) }) : null,
13066
13085
  toolbarExtras,
13067
- /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("span", { className: "fdc-tools-gap" }),
13068
- maxLength && text.length > maxLength * 0.6 ? /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("span", { className: "fdc-count fd-tabular" + (text.length > maxLength * 0.95 ? " is-hot" : ""), children: [
13086
+ /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("span", { className: "fdc-tools-gap" }),
13087
+ maxLength && text.length > maxLength * 0.6 ? /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("span", { className: "fdc-count fd-tabular" + (text.length > maxLength * 0.95 ? " is-hot" : ""), children: [
13069
13088
  text.length,
13070
13089
  "/",
13071
13090
  maxLength
13072
13091
  ] }) : null,
13073
- busy ? /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("button", { type: "button", className: "fdc-stop", onClick: onStop, "aria-label": "Stop generating", children: [
13074
- /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
13075
- /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("span", { children: "Stop" })
13076
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("button", { type: "button", className: "fdc-send", onClick: submit, disabled: !canSend, "aria-label": "Send message", children: [
13077
- /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("i", { className: "ph ph-paper-plane-right", "aria-hidden": "true" }),
13078
- /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("span", { className: "fdc-send-label", children: "Send" })
13092
+ busy ? /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("button", { type: "button", className: "fdc-stop", onClick: onStop, "aria-label": "Stop generating", children: [
13093
+ /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
13094
+ /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("span", { children: "Stop" })
13095
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("button", { type: "button", className: "fdc-send", onClick: submit, disabled: !canSend, "aria-label": "Send message", children: [
13096
+ /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("i", { className: "ph ph-paper-plane-right", "aria-hidden": "true" }),
13097
+ /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("span", { className: "fdc-send-label", children: "Send" })
13079
13098
  ] })
13080
13099
  ] })
13081
13100
  ] })
13082
13101
  }
13083
13102
  ),
13084
- notice ? /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("div", { className: "fdc-notice", role: "status", children: [
13085
- /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
13103
+ notice ? /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("div", { className: "fdc-notice", role: "status", children: [
13104
+ /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
13086
13105
  notice
13087
13106
  ] }) : null,
13088
- hint && !notice ? /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("div", { className: "fdc-hint", children: hint }) : null,
13089
- /* @__PURE__ */ (0, import_jsx_runtime96.jsx)(
13107
+ hint && !notice ? /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("div", { className: "fdc-hint", children: hint }) : null,
13108
+ /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
13090
13109
  Popover,
13091
13110
  {
13092
13111
  open: menuOpen,
@@ -13100,12 +13119,12 @@ function ChatComposer({
13100
13119
  returnFocus: false,
13101
13120
  closeOnOutside: true,
13102
13121
  label: trigger && trigger.type === "slash" ? "Commands" : "Mentions",
13103
- children: /* @__PURE__ */ (0, import_jsx_runtime96.jsx)(
13122
+ children: /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
13104
13123
  Menu,
13105
13124
  {
13106
13125
  items: menuItems,
13107
13126
  autoFocus: false,
13108
- header: /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("div", { className: "fd-pop-group", children: trigger && trigger.type === "slash" ? "Commands" : "Attach context" }),
13127
+ header: /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("div", { className: "fd-pop-group", children: trigger && trigger.type === "slash" ? "Commands" : "Attach context" }),
13109
13128
  onClose: () => setTrigger(null)
13110
13129
  }
13111
13130
  )
@@ -13115,12 +13134,12 @@ function ChatComposer({
13115
13134
  }
13116
13135
 
13117
13136
  // src/components/chat/ChatSessionBar.tsx
13118
- var React67 = __toESM(require("react"), 1);
13119
- var import_jsx_runtime97 = require("react/jsx-runtime");
13137
+ var React68 = __toESM(require("react"), 1);
13138
+ var import_jsx_runtime98 = require("react/jsx-runtime");
13120
13139
  var compact2 = meterFormats.compact;
13121
13140
  function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
13122
- const [open2, setOpen] = React67.useState(false);
13123
- const anchor = React67.useRef(null);
13141
+ const [open2, setOpen] = React68.useState(false);
13142
+ const anchor = React68.useRef(null);
13124
13143
  const stats = sessionStats || null;
13125
13144
  const cu = contextUsage || null;
13126
13145
  const limits = usageLimits || null;
@@ -13135,9 +13154,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
13135
13154
  if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
13136
13155
  if (cu) bits.push(pct + "% context");
13137
13156
  const expandable = !!(cu || limits);
13138
- return /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)(React67.Fragment, { children: [
13139
- /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("div", { className: "fdc-bar", children: [
13140
- /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)(
13157
+ return /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)(React68.Fragment, { children: [
13158
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("div", { className: "fdc-bar", children: [
13159
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)(
13141
13160
  "button",
13142
13161
  {
13143
13162
  type: "button",
@@ -13148,15 +13167,15 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
13148
13167
  "aria-expanded": expandable ? open2 : void 0,
13149
13168
  "aria-label": expandable ? "Usage details" : void 0,
13150
13169
  children: [
13151
- cu ? /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("span", { className: "fdc-bar-mini", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(SegmentedMeter, { total, segments: cu.segments, height: 4, showTotal: false }) }) : null,
13152
- /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("span", { className: "fdc-bar-text", title: truncationTitle(bits.join(" \xB7 ")), children: bits.join(" \xB7 ") }),
13153
- expandable ? /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("i", { className: "ph ph-caret-right fdc-bar-caret", "aria-hidden": "true" }) : null
13170
+ cu ? /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("span", { className: "fdc-bar-mini", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(SegmentedMeter, { total, segments: cu.segments, height: 4, showTotal: false }) }) : null,
13171
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("span", { className: "fdc-bar-text", title: truncationTitle(bits.join(" \xB7 ")), children: bits.join(" \xB7 ") }),
13172
+ expandable ? /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("i", { className: "ph ph-caret-right fdc-bar-caret", "aria-hidden": "true" }) : null
13154
13173
  ]
13155
13174
  }
13156
13175
  ),
13157
13176
  extras
13158
13177
  ] }),
13159
- /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
13178
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
13160
13179
  Popover,
13161
13180
  {
13162
13181
  open: open2,
@@ -13167,15 +13186,15 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
13167
13186
  maxHeight: 460,
13168
13187
  padded: true,
13169
13188
  label: "Usage",
13170
- footer: onClear ? /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("button", { type: "button", className: "fdc-usage-clear", onClick: () => {
13189
+ footer: onClear ? /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("button", { type: "button", className: "fdc-usage-clear", onClick: () => {
13171
13190
  setOpen(false);
13172
13191
  onClear();
13173
13192
  }, children: [
13174
- /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("i", { className: "ph ph-trash", "aria-hidden": "true" }),
13193
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("i", { className: "ph ph-trash", "aria-hidden": "true" }),
13175
13194
  "Clear conversation"
13176
13195
  ] }) : void 0,
13177
- children: /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("div", { className: "fdc-usage", children: [
13178
- cu ? /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("section", { className: "fdc-usage-sec", children: /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
13196
+ children: /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("div", { className: "fdc-usage", children: [
13197
+ cu ? /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("section", { className: "fdc-usage-sec", children: /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
13179
13198
  SegmentedMeter,
13180
13199
  {
13181
13200
  total,
@@ -13187,9 +13206,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
13187
13206
  remainderLabel: "Free"
13188
13207
  }
13189
13208
  ) }) : null,
13190
- limits && limits.length ? /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("section", { className: "fdc-usage-sec", children: [
13191
- /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("h4", { className: "fdc-usage-h", children: "Usage limits" }),
13192
- /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("div", { className: "fdc-usage-rows", children: limits.map((l) => /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
13209
+ limits && limits.length ? /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("section", { className: "fdc-usage-sec", children: [
13210
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("h4", { className: "fdc-usage-h", children: "Usage limits" }),
13211
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("div", { className: "fdc-usage-rows", children: limits.map((l) => /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
13193
13212
  QuotaRow,
13194
13213
  {
13195
13214
  label: l.label,
@@ -13199,25 +13218,25 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
13199
13218
  l.id
13200
13219
  )) })
13201
13220
  ] }) : null,
13202
- stats ? /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("section", { className: "fdc-usage-sec fdc-usage-stats", children: [
13203
- stats.elapsedMs ? /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("div", { children: [
13204
- /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("span", { children: "Session" }),
13205
- /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("b", { className: "fd-tabular", children: formatDuration(stats.elapsedMs) })
13221
+ stats ? /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("section", { className: "fdc-usage-sec fdc-usage-stats", children: [
13222
+ stats.elapsedMs ? /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("div", { children: [
13223
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("span", { children: "Session" }),
13224
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("b", { className: "fd-tabular", children: formatDuration(stats.elapsedMs) })
13206
13225
  ] }) : null,
13207
- stats.tokens ? /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("div", { children: [
13208
- /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("span", { children: "Tokens" }),
13209
- /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("b", { className: "fd-tabular", children: stats.tokens.toLocaleString() })
13226
+ stats.tokens ? /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("div", { children: [
13227
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("span", { children: "Tokens" }),
13228
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("b", { className: "fd-tabular", children: stats.tokens.toLocaleString() })
13210
13229
  ] }) : null,
13211
- stats.costUsd != null ? /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("div", { children: [
13212
- /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("span", { children: "Cost" }),
13213
- /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("b", { className: "fd-tabular", children: [
13230
+ stats.costUsd != null ? /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("div", { children: [
13231
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("span", { children: "Cost" }),
13232
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("b", { className: "fd-tabular", children: [
13214
13233
  "$",
13215
13234
  Number(stats.costUsd).toFixed(3)
13216
13235
  ] })
13217
13236
  ] }) : null,
13218
- stats.turns ? /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("div", { children: [
13219
- /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("span", { children: "Turns" }),
13220
- /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("b", { className: "fd-tabular", children: stats.turns })
13237
+ stats.turns ? /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("div", { children: [
13238
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("span", { children: "Turns" }),
13239
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("b", { className: "fd-tabular", children: stats.turns })
13221
13240
  ] }) : null
13222
13241
  ] }) : null
13223
13242
  ] })
@@ -13256,7 +13275,7 @@ function ModelControls({
13256
13275
  disabled: m.disabled,
13257
13276
  checked: m.id === (current2 && current2.id),
13258
13277
  meta: m.meta,
13259
- shortcut: m.shortcut ? /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(KeyHint, { keys: m.shortcut, size: "sm" }) : void 0,
13278
+ shortcut: m.shortcut ? /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(KeyHint, { keys: m.shortcut, size: "sm" }) : void 0,
13260
13279
  onSelect: () => onModelChange && onModelChange(m.id)
13261
13280
  });
13262
13281
  const items = [{ kind: "section", label: "Models" }].concat(flat.map(item));
@@ -13269,15 +13288,15 @@ function ModelControls({
13269
13288
  items.push({ kind: "section", label: "Fast mode" });
13270
13289
  items.push({
13271
13290
  kind: "custom",
13272
- render: () => /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("label", { className: "fdc-switchrow", children: [
13273
- /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("span", { children: fastModeLabel }),
13274
- /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("input", { type: "checkbox", className: "fd-sr", checked: !!fastMode, onChange: (e) => onFastModeChange(e.target.checked) }),
13275
- /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("span", { className: "fd-switch-track" + (fastMode ? " is-on" : ""), "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("span", { className: "fd-switch-thumb" }) })
13291
+ render: () => /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("label", { className: "fdc-switchrow", children: [
13292
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("span", { children: fastModeLabel }),
13293
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("input", { type: "checkbox", className: "fd-sr", checked: !!fastMode, onChange: (e) => onFastModeChange(e.target.checked) }),
13294
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("span", { className: "fd-switch-track" + (fastMode ? " is-on" : ""), "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("span", { className: "fd-switch-thumb" }) })
13276
13295
  ] })
13277
13296
  });
13278
13297
  }
13279
- return /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)(React67.Fragment, { children: [
13280
- /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
13298
+ return /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)(React68.Fragment, { children: [
13299
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
13281
13300
  MenuButton,
13282
13301
  {
13283
13302
  items,
@@ -13288,7 +13307,7 @@ function ModelControls({
13288
13307
  title: "Choose a model"
13289
13308
  }
13290
13309
  ),
13291
- effortLevels && effortLevels.length ? /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
13310
+ effortLevels && effortLevels.length ? /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
13292
13311
  MenuButton,
13293
13312
  {
13294
13313
  placement: "top-end",
@@ -13309,7 +13328,7 @@ function ModelControls({
13309
13328
  }
13310
13329
 
13311
13330
  // src/components/chat/AgentChatPanel.tsx
13312
- var import_jsx_runtime98 = require("react/jsx-runtime");
13331
+ var import_jsx_runtime99 = require("react/jsx-runtime");
13313
13332
  var SURFACES = { sidebar: "is-sidebar", inline: "is-inline", page: "is-page", modal: "is-modal", sheet: "is-sheet" };
13314
13333
  function AgentChatPanel({
13315
13334
  /* required */
@@ -13393,11 +13412,11 @@ function AgentChatPanel({
13393
13412
  onFeedback,
13394
13413
  onEditMessage
13395
13414
  }) {
13396
- const [panelWidth, setPanelWidth] = React68.useState(width);
13397
- const [applied, setApplied] = React68.useState({});
13398
- const [draft, setDraft] = React68.useState("");
13399
- const dragging = React68.useRef(null);
13400
- React68.useEffect(() => setPanelWidth(width), [width]);
13415
+ const [panelWidth, setPanelWidth] = React69.useState(width);
13416
+ const [applied, setApplied] = React69.useState({});
13417
+ const [draft, setDraft] = React69.useState("");
13418
+ const dragging = React69.useRef(null);
13419
+ React69.useEffect(() => setPanelWidth(width), [width]);
13401
13420
  const engine = useChatEngine({
13402
13421
  contextType,
13403
13422
  contextId,
@@ -13463,7 +13482,7 @@ function AgentChatPanel({
13463
13482
  onReconnect: engine.reload,
13464
13483
  deadTitle: "The assistant isn\u2019t reachable"
13465
13484
  };
13466
- const sessionBar = /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
13485
+ const sessionBar = /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
13467
13486
  ChatSessionBar,
13468
13487
  {
13469
13488
  sessionStats,
@@ -13472,7 +13491,7 @@ function AgentChatPanel({
13472
13491
  onClear: engine.visible.length ? engine.clear : void 0
13473
13492
  }
13474
13493
  );
13475
- const modelControls = /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
13494
+ const modelControls = /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
13476
13495
  ModelControls,
13477
13496
  {
13478
13497
  models,
@@ -13487,7 +13506,7 @@ function AgentChatPanel({
13487
13506
  narrow
13488
13507
  }
13489
13508
  );
13490
- const threadMenu = threads && threads.length ? /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
13509
+ const threadMenu = threads && threads.length ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
13491
13510
  MenuButton,
13492
13511
  {
13493
13512
  variant: "ghost",
@@ -13514,7 +13533,7 @@ function AgentChatPanel({
13514
13533
  })))
13515
13534
  }
13516
13535
  ) : null;
13517
- return /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)(
13536
+ return /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)(
13518
13537
  "aside",
13519
13538
  {
13520
13539
  className: ["fdc-panel", SURFACES[surface] || SURFACES.sidebar, narrow ? "is-narrow" : "", className].filter(Boolean).join(" "),
@@ -13525,7 +13544,7 @@ function AgentChatPanel({
13525
13544
  },
13526
13545
  "aria-label": title,
13527
13546
  children: [
13528
- surface === "sidebar" && resizable ? /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
13547
+ surface === "sidebar" && resizable ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
13529
13548
  "div",
13530
13549
  {
13531
13550
  className: "fdc-grip",
@@ -13540,20 +13559,20 @@ function AgentChatPanel({
13540
13559
  }
13541
13560
  }
13542
13561
  ) : null,
13543
- showHeader ? /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("header", { className: "fdc-head", children: [
13544
- /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("span", { className: "fdc-head-mark", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("i", { className: "ph ph-" + assistantIcon }) }),
13545
- /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("span", { className: "fdc-head-titles", children: [
13546
- /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("span", { className: "fdc-head-title", title: truncationTitle(title), children: title }),
13547
- subtitle ? /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("span", { className: "fdc-head-sub", title: truncationTitle(subtitle), children: subtitle }) : null
13562
+ showHeader ? /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("header", { className: "fdc-head", children: [
13563
+ /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "fdc-head-mark", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("i", { className: "ph ph-" + assistantIcon }) }),
13564
+ /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("span", { className: "fdc-head-titles", children: [
13565
+ /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "fdc-head-title", title: truncationTitle(title), children: title }),
13566
+ subtitle ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "fdc-head-sub", title: truncationTitle(subtitle), children: subtitle }) : null
13548
13567
  ] }),
13549
- /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("span", { className: "fdc-head-acts", children: [
13568
+ /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("span", { className: "fdc-head-acts", children: [
13550
13569
  headerActions,
13551
13570
  threadMenu,
13552
- onNewThread ? /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("button", { type: "button", className: "fdc-iconbtn", onClick: onNewThread, "aria-label": "New conversation", title: "New conversation", children: /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("i", { className: "ph ph-plus", "aria-hidden": "true" }) }) : null,
13553
- onClose ? /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("button", { type: "button", className: "fdc-iconbtn", onClick: onClose, "aria-label": "Close panel", title: "Close", children: /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
13571
+ onNewThread ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("button", { type: "button", className: "fdc-iconbtn", onClick: onNewThread, "aria-label": "New conversation", title: "New conversation", children: /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("i", { className: "ph ph-plus", "aria-hidden": "true" }) }) : null,
13572
+ onClose ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("button", { type: "button", className: "fdc-iconbtn", onClick: onClose, "aria-label": "Close panel", title: "Close", children: /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
13554
13573
  ] })
13555
13574
  ] }) : null,
13556
- /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
13575
+ /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
13557
13576
  ChatTranscript,
13558
13577
  {
13559
13578
  messages: engine.visible,
@@ -13568,7 +13587,7 @@ function AgentChatPanel({
13568
13587
  renderEmpty
13569
13588
  }
13570
13589
  ),
13571
- /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
13590
+ /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
13572
13591
  ChatComposer,
13573
13592
  {
13574
13593
  onSubmit: (text, atts) => engine.send(text, atts),
@@ -13601,8 +13620,8 @@ function AgentChatPanel({
13601
13620
  }
13602
13621
 
13603
13622
  // src/components/files/FileViewer.tsx
13604
- var React69 = __toESM(require("react"), 1);
13605
- var import_jsx_runtime99 = require("react/jsx-runtime");
13623
+ var React70 = __toESM(require("react"), 1);
13624
+ var import_jsx_runtime100 = require("react/jsx-runtime");
13606
13625
  function previewKindOf(file) {
13607
13626
  const mime = (file.mime || "").toLowerCase();
13608
13627
  const ext = extensionOf(file.name || "");
@@ -13658,13 +13677,13 @@ function parseDelimited(text, delimiter) {
13658
13677
  return rows;
13659
13678
  }
13660
13679
  function usePreview(file, kind, resolveUrl) {
13661
- const [state, setState] = React69.useState({ status: "loading" });
13662
- const [attempt, setAttempt] = React69.useState(0);
13663
- const resolveRef = React69.useRef(resolveUrl);
13664
- React69.useEffect(() => {
13680
+ const [state, setState] = React70.useState({ status: "loading" });
13681
+ const [attempt, setAttempt] = React70.useState(0);
13682
+ const resolveRef = React70.useRef(resolveUrl);
13683
+ React70.useEffect(() => {
13665
13684
  resolveRef.current = resolveUrl;
13666
13685
  }, [resolveUrl]);
13667
- React69.useEffect(() => {
13686
+ React70.useEffect(() => {
13668
13687
  if (kind === "none") {
13669
13688
  setState({ status: "ready" });
13670
13689
  return;
@@ -13694,19 +13713,19 @@ function usePreview(file, kind, resolveUrl) {
13694
13713
  if (ac) ac.abort();
13695
13714
  };
13696
13715
  }, [file.id, kind, attempt]);
13697
- return { ...state, retry: React69.useCallback(() => setAttempt((a) => a + 1), []) };
13716
+ return { ...state, retry: React70.useCallback(() => setAttempt((a) => a + 1), []) };
13698
13717
  }
13699
13718
  function PreviewBody({ file, kind, state }) {
13700
- if (kind === "image") return /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("img", { className: "fd-fv-image", src: state.url, alt: file.name || "Preview" });
13701
- if (kind === "pdf") return /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("iframe", { className: "fd-fv-pdf", src: state.url, title: file.name || "PDF preview" });
13702
- if (kind === "markdown") return /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(Markdown, { className: "fd-fv-markdown", source: state.text || "" });
13719
+ if (kind === "image") return /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("img", { className: "fd-fv-image", src: state.url, alt: file.name || "Preview" });
13720
+ if (kind === "pdf") return /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("iframe", { className: "fd-fv-pdf", src: state.url, title: file.name || "PDF preview" });
13721
+ if (kind === "markdown") return /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Markdown, { className: "fd-fv-markdown", source: state.text || "" });
13703
13722
  if (kind === "json") {
13704
13723
  let pretty = state.text || "";
13705
13724
  try {
13706
13725
  pretty = JSON.stringify(JSON.parse(pretty), null, 2);
13707
13726
  } catch {
13708
13727
  }
13709
- return /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(CodeBlock, { code: pretty, language: "json" });
13728
+ return /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(CodeBlock, { code: pretty, language: "json" });
13710
13729
  }
13711
13730
  if (kind === "csv") {
13712
13731
  const tsv = extensionOf(file.name || "") === "tsv" || (file.mime || "").toLowerCase().includes("tab-separated");
@@ -13714,12 +13733,12 @@ function PreviewBody({ file, kind, state }) {
13714
13733
  const head = rows[0] || [];
13715
13734
  const dataRows = rows.slice(1);
13716
13735
  const shown = dataRows.slice(0, FILE_VIEWER_CSV_ROW_LIMIT);
13717
- return /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("div", { className: "fd-fv-csv", children: [
13718
- /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("table", { className: "fd-fv-csv-table", children: [
13719
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("tr", { children: head.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("th", { children: c }, i)) }) }),
13720
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("tbody", { children: shown.map((r, ri) => /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("tr", { children: head.map((_, ci) => /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("td", { children: r[ci] ?? "" }, ci)) }, ri)) })
13736
+ return /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: "fd-fv-csv", children: [
13737
+ /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("table", { className: "fd-fv-csv-table", children: [
13738
+ /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("tr", { children: head.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("th", { children: c }, i)) }) }),
13739
+ /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("tbody", { children: shown.map((r, ri) => /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("tr", { children: head.map((_, ci) => /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("td", { children: r[ci] ?? "" }, ci)) }, ri)) })
13721
13740
  ] }),
13722
- dataRows.length > FILE_VIEWER_CSV_ROW_LIMIT ? /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("p", { className: "fd-fv-csv-note fd-body-sm fd-muted", children: [
13741
+ dataRows.length > FILE_VIEWER_CSV_ROW_LIMIT ? /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("p", { className: "fd-fv-csv-note fd-body-sm fd-muted", children: [
13723
13742
  "Showing the first ",
13724
13743
  FILE_VIEWER_CSV_ROW_LIMIT.toLocaleString(),
13725
13744
  " of ",
@@ -13728,24 +13747,24 @@ function PreviewBody({ file, kind, state }) {
13728
13747
  ] }) : null
13729
13748
  ] });
13730
13749
  }
13731
- if (kind === "text") return /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(CodeBlock, { code: state.text || "", language: extensionOf(file.name || "") || void 0 });
13732
- return /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("div", { className: "fd-fv-fallback", children: [
13733
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "fd-fv-fallback-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("i", { className: "ph ph-" + iconForMime(file.mime, file.name) }) }),
13734
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "fd-fv-fallback-title", children: "No preview available" }),
13735
- /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("span", { className: "fd-fv-fallback-meta", children: [
13750
+ if (kind === "text") return /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(CodeBlock, { code: state.text || "", language: extensionOf(file.name || "") || void 0 });
13751
+ return /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: "fd-fv-fallback", children: [
13752
+ /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "fd-fv-fallback-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("i", { className: "ph ph-" + iconForMime(file.mime, file.name) }) }),
13753
+ /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "fd-fv-fallback-title", children: "No preview available" }),
13754
+ /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("span", { className: "fd-fv-fallback-meta", children: [
13736
13755
  file.mime || "Unknown type",
13737
13756
  file.size ? " \xB7 " + formatBytes(file.size) : ""
13738
13757
  ] })
13739
13758
  ] });
13740
13759
  }
13741
13760
  function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", onClose, actions, className = "" }) {
13742
- const kind = React69.useMemo(() => previewKindOf(file), [file]);
13761
+ const kind = React70.useMemo(() => previewKindOf(file), [file]);
13743
13762
  const preview = usePreview(file, kind, resolveUrl);
13744
- const [tab, setTab] = React69.useState("preview");
13745
- const [downloading, setDownloading] = React69.useState(false);
13746
- const [downloadError, setDownloadError] = React69.useState(null);
13763
+ const [tab, setTab] = React70.useState("preview");
13764
+ const [downloading, setDownloading] = React70.useState(false);
13765
+ const [downloadError, setDownloadError] = React70.useState(null);
13747
13766
  const hasSide = sidePanel != null;
13748
- React69.useEffect(() => {
13767
+ React70.useEffect(() => {
13749
13768
  setTab("preview");
13750
13769
  }, [file.id]);
13751
13770
  const download = () => {
@@ -13761,29 +13780,29 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
13761
13780
  a.remove();
13762
13781
  }).catch((err) => setDownloadError(err && err.message || "Download failed.")).finally(() => setDownloading(false));
13763
13782
  };
13764
- return /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)(
13783
+ return /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)(
13765
13784
  "section",
13766
13785
  {
13767
13786
  className: ["fd-fv", hasSide && tab === "side" ? "is-tab-side" : "is-tab-preview", className].filter(Boolean).join(" "),
13768
13787
  "aria-label": file.name || "File",
13769
13788
  children: [
13770
- /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("header", { className: "fd-fv-head", children: [
13771
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "fd-fv-head-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("i", { className: "ph ph-" + iconForMime(file.mime, file.name) }) }),
13772
- /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("span", { className: "fd-fv-head-titles", children: [
13773
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "fd-fv-head-title", title: file.name, children: file.name }),
13774
- /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("span", { className: "fd-fv-head-meta", children: [
13789
+ /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("header", { className: "fd-fv-head", children: [
13790
+ /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "fd-fv-head-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("i", { className: "ph ph-" + iconForMime(file.mime, file.name) }) }),
13791
+ /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("span", { className: "fd-fv-head-titles", children: [
13792
+ /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "fd-fv-head-title", title: file.name, children: file.name }),
13793
+ /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("span", { className: "fd-fv-head-meta", children: [
13775
13794
  file.mime || "Unknown type",
13776
13795
  file.size ? " \xB7 " + formatBytes(file.size) : ""
13777
13796
  ] })
13778
13797
  ] }),
13779
- /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("span", { className: "fd-fv-head-actions", children: [
13798
+ /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("span", { className: "fd-fv-head-actions", children: [
13780
13799
  actions,
13781
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(Button, { variant: "secondary", size: "sm", icon: "download-simple", loading: downloading, onClick: download, children: "Download" }),
13782
- onClose ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(IconButton, { icon: "x", label: "Close", onClick: onClose }) : null
13800
+ /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Button, { variant: "secondary", size: "sm", icon: "download-simple", loading: downloading, onClick: download, children: "Download" }),
13801
+ onClose ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(IconButton, { icon: "x", label: "Close", onClick: onClose }) : null
13783
13802
  ] })
13784
13803
  ] }),
13785
- downloadError ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("div", { className: "fd-fv-download-error", role: "alert", children: downloadError }) : null,
13786
- hasSide ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
13804
+ downloadError ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("div", { className: "fd-fv-download-error", role: "alert", children: downloadError }) : null,
13805
+ hasSide ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
13787
13806
  Tabs,
13788
13807
  {
13789
13808
  className: "fd-fv-tabs",
@@ -13792,19 +13811,19 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
13792
13811
  onChange: (v) => setTab(v)
13793
13812
  }
13794
13813
  ) : null,
13795
- /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("div", { className: "fd-fv-body", children: [
13796
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("div", { className: "fd-fv-preview", role: "region", "aria-label": "Preview of " + (file.name || "file"), children: /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
13814
+ /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: "fd-fv-body", children: [
13815
+ /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("div", { className: "fd-fv-preview", role: "region", "aria-label": "Preview of " + (file.name || "file"), children: /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
13797
13816
  LoadingRegion,
13798
13817
  {
13799
13818
  state: preview.status === "loading" ? "loading" : preview.status === "error" ? "error" : "ready",
13800
13819
  error: preview.error,
13801
13820
  label: "Loading preview of " + (file.name || "file"),
13802
13821
  onRetry: preview.status === "error" ? preview.retry : void 0,
13803
- skeleton: /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(Skeleton, { shape: "card", h: 220 }),
13804
- children: /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(PreviewBody, { file, kind, state: preview })
13822
+ skeleton: /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Skeleton, { shape: "card", h: 220 }),
13823
+ children: /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(PreviewBody, { file, kind, state: preview })
13805
13824
  }
13806
13825
  ) }),
13807
- hasSide ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("div", { className: "fd-fv-side", role: "region", "aria-label": sidePanelLabel, children: sidePanel }) : null
13826
+ hasSide ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("div", { className: "fd-fv-side", role: "region", "aria-label": sidePanelLabel, children: sidePanel }) : null
13808
13827
  ] })
13809
13828
  ]
13810
13829
  }
@@ -13812,8 +13831,8 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
13812
13831
  }
13813
13832
 
13814
13833
  // src/components/files/FileBrowser.tsx
13815
- var React70 = __toESM(require("react"), 1);
13816
- var import_jsx_runtime100 = require("react/jsx-runtime");
13834
+ var React71 = __toESM(require("react"), 1);
13835
+ var import_jsx_runtime101 = require("react/jsx-runtime");
13817
13836
  function childrenOf(folders, parentId) {
13818
13837
  return folders.filter((f) => f.parentId === parentId).sort((a, b) => a.name.localeCompare(b.name));
13819
13838
  }
@@ -13885,8 +13904,8 @@ function FolderPickerMenu({
13885
13904
  }) {
13886
13905
  const panel = useInlinePanel();
13887
13906
  const { open: open2, setOpen, ref } = panel;
13888
- return /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("span", { className: "fd-fb-menu-anchor", ref, children: [
13889
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
13907
+ return /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("span", { className: "fd-fb-menu-anchor", ref, children: [
13908
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
13890
13909
  IconButton,
13891
13910
  {
13892
13911
  icon: "arrows-out-cardinal",
@@ -13898,9 +13917,9 @@ function FolderPickerMenu({
13898
13917
  onClick: () => setOpen((v) => !v)
13899
13918
  }
13900
13919
  ),
13901
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(InlinePanelSurface, { panel, align: "right", offset: 4, width: 220, maxHeight: 280, role: "menu", label, children: /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: "fd-fb-menu", children: [
13902
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "fd-overline fd-muted fd-fb-menu-title", children: "Move to\u2026" }),
13903
- destinations.map((d) => /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)(
13920
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(InlinePanelSurface, { panel, align: "right", offset: 4, width: 220, maxHeight: 280, role: "menu", label, children: /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fd-fb-menu", children: [
13921
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fd-overline fd-muted fd-fb-menu-title", children: "Move to\u2026" }),
13922
+ destinations.map((d) => /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)(
13904
13923
  "button",
13905
13924
  {
13906
13925
  type: "button",
@@ -13912,7 +13931,7 @@ function FolderPickerMenu({
13912
13931
  setOpen(false);
13913
13932
  },
13914
13933
  children: [
13915
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("i", { className: "ph ph-" + (d.id == null ? "house-simple" : "folder-simple"), "aria-hidden": "true" }),
13934
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("i", { className: "ph ph-" + (d.id == null ? "house-simple" : "folder-simple"), "aria-hidden": "true" }),
13916
13935
  d.name
13917
13936
  ]
13918
13937
  },
@@ -13922,8 +13941,8 @@ function FolderPickerMenu({
13922
13941
  ] });
13923
13942
  }
13924
13943
  function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropPayload, actions, className = "" }) {
13925
- const [over, setOver] = React70.useState(false);
13926
- const dragCounter = React70.useRef(0);
13944
+ const [over, setOver] = React71.useState(false);
13945
+ const dragCounter = React71.useRef(0);
13927
13946
  const dropHandlers = isDropTarget ? {
13928
13947
  onDragEnter: (e) => {
13929
13948
  if (!hasInternalPayload(e)) return;
@@ -13948,8 +13967,8 @@ function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropP
13948
13967
  if (payload && onDropPayload) onDropPayload(payload);
13949
13968
  }
13950
13969
  } : {};
13951
- return /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: ["fd-fb-row", over ? "is-drop-target" : "", className].filter(Boolean).join(" "), ...dropHandlers, children: [
13952
- /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)(
13970
+ return /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: ["fd-fb-row", over ? "is-drop-target" : "", className].filter(Boolean).join(" "), ...dropHandlers, children: [
13971
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)(
13953
13972
  "button",
13954
13973
  {
13955
13974
  type: "button",
@@ -13958,26 +13977,26 @@ function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropP
13958
13977
  draggable: !!draggableId,
13959
13978
  onDragStart: draggableId ? (e) => writeDragPayload(e, draggableId) : void 0,
13960
13979
  children: [
13961
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "fd-fb-row-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("i", { className: "ph ph-" + icon }) }),
13962
- /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("span", { className: "fd-fb-row-text", children: [
13963
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "fd-fb-row-name", title: name, children: name }),
13964
- meta ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "fd-fb-row-meta", children: meta }) : null
13980
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fd-fb-row-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("i", { className: "ph ph-" + icon }) }),
13981
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("span", { className: "fd-fb-row-text", children: [
13982
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fd-fb-row-name", title: name, children: name }),
13983
+ meta ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fd-fb-row-meta", children: meta }) : null
13965
13984
  ] })
13966
13985
  ]
13967
13986
  }
13968
13987
  ),
13969
- actions ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "fd-fb-row-actions", children: actions }) : null
13988
+ actions ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fd-fb-row-actions", children: actions }) : null
13970
13989
  ] });
13971
13990
  }
13972
13991
  function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveInto, canMove }) {
13973
13992
  const kids = childrenOf(folders, folder.id);
13974
- const [expanded, setExpanded] = React70.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
13975
- React70.useEffect(() => {
13993
+ const [expanded, setExpanded] = React71.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
13994
+ React71.useEffect(() => {
13976
13995
  if (currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId)) setExpanded(true);
13977
13996
  }, [currentFolderId, folder.id, folders]);
13978
13997
  const isCurrent = folder.id === currentFolderId;
13979
- return /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: "fd-fb-tree-node", children: [
13980
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
13998
+ return /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fd-fb-tree-node", children: [
13999
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
13981
14000
  RowShell,
13982
14001
  {
13983
14002
  icon: folder.id === currentFolderId ? "folder-open" : "folder-simple",
@@ -13987,7 +14006,7 @@ function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveI
13987
14006
  isDropTarget: canMove,
13988
14007
  onDropPayload: (payload) => onMoveInto(payload, folder.id),
13989
14008
  className: ["fd-fb-tree-row", isCurrent ? "is-current" : ""].filter(Boolean).join(" "),
13990
- actions: kids.length ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
14009
+ actions: kids.length ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
13991
14010
  IconButton,
13992
14011
  {
13993
14012
  icon: expanded ? "caret-down" : "caret-right",
@@ -13999,7 +14018,7 @@ function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveI
13999
14018
  ) : void 0
14000
14019
  }
14001
14020
  ),
14002
- expanded && kids.length ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("div", { className: "fd-fb-tree-children", style: { paddingLeft: 14 }, children: kids.map((k) => /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
14021
+ expanded && kids.length ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("div", { className: "fd-fb-tree-children", style: { paddingLeft: 14 }, children: kids.map((k) => /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
14003
14022
  TreeNode,
14004
14023
  {
14005
14024
  folder: k,
@@ -14038,15 +14057,15 @@ function FileBrowser({
14038
14057
  const canUpload = perm.canUpload !== false && !!onUpload;
14039
14058
  const canRemoveFile = perm.canRemoveFile !== false && !!onRemoveFile;
14040
14059
  const canDeleteFolder = perm.canDeleteFolder !== false && !!onDeleteFolder;
14041
- const [createOpen, setCreateOpen] = React70.useState(false);
14042
- const [createName, setCreateName] = React70.useState("");
14043
- const [renameTarget, setRenameTarget] = React70.useState(null);
14044
- const [renameValue, setRenameValue] = React70.useState("");
14045
- const [deleteTarget, setDeleteTarget] = React70.useState(null);
14046
- const uploadInputRef = React70.useRef(null);
14047
- const crumbFolders = React70.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
14048
- const subfolders = React70.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
14049
- const currentFiles = React70.useMemo(
14060
+ const [createOpen, setCreateOpen] = React71.useState(false);
14061
+ const [createName, setCreateName] = React71.useState("");
14062
+ const [renameTarget, setRenameTarget] = React71.useState(null);
14063
+ const [renameValue, setRenameValue] = React71.useState("");
14064
+ const [deleteTarget, setDeleteTarget] = React71.useState(null);
14065
+ const uploadInputRef = React71.useRef(null);
14066
+ const crumbFolders = React71.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
14067
+ const subfolders = React71.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
14068
+ const currentFiles = React71.useMemo(
14050
14069
  () => files.filter((f) => f.folderId === currentFolderId).sort((a, b) => a.name.localeCompare(b.name)),
14051
14070
  [files, currentFolderId]
14052
14071
  );
@@ -14085,10 +14104,10 @@ function FileBrowser({
14085
14104
  if (deleteTarget && onDeleteFolder) onDeleteFolder(deleteTarget);
14086
14105
  setDeleteTarget(null);
14087
14106
  };
14088
- const content = /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: ["fd-fb", className].filter(Boolean).join(" "), children: [
14089
- /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: "fd-fb-head", children: [
14090
- /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("nav", { className: "fd-fb-crumbs", "aria-label": "Folder path", children: [
14091
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
14107
+ const content = /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: ["fd-fb", className].filter(Boolean).join(" "), children: [
14108
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fd-fb-head", children: [
14109
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("nav", { className: "fd-fb-crumbs", "aria-label": "Folder path", children: [
14110
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
14092
14111
  BreadcrumbCrumb,
14093
14112
  {
14094
14113
  label: "Home",
@@ -14098,7 +14117,7 @@ function FileBrowser({
14098
14117
  onDropPayload: (p) => moveIntoFolder(p, null)
14099
14118
  }
14100
14119
  ),
14101
- crumbFolders.map((f, i) => /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
14120
+ crumbFolders.map((f, i) => /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
14102
14121
  BreadcrumbCrumb,
14103
14122
  {
14104
14123
  label: f.name,
@@ -14110,11 +14129,11 @@ function FileBrowser({
14110
14129
  f.id
14111
14130
  ))
14112
14131
  ] }),
14113
- /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("span", { className: "fd-fb-actions", children: [
14114
- canCreateFolder ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Button, { variant: "secondary", size: "sm", icon: "folder-simple-plus", onClick: openCreate, children: "New folder" }) : null,
14115
- canUpload ? /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)(import_jsx_runtime100.Fragment, { children: [
14116
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Button, { variant: "secondary", size: "sm", icon: "upload-simple", onClick: () => uploadInputRef.current && uploadInputRef.current.click(), children: "Upload" }),
14117
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
14132
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("span", { className: "fd-fb-actions", children: [
14133
+ canCreateFolder ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Button, { variant: "secondary", size: "sm", icon: "folder-simple-plus", onClick: openCreate, children: "New folder" }) : null,
14134
+ canUpload ? /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)(import_jsx_runtime101.Fragment, { children: [
14135
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Button, { variant: "secondary", size: "sm", icon: "upload-simple", onClick: () => uploadInputRef.current && uploadInputRef.current.click(), children: "Upload" }),
14136
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
14118
14137
  "input",
14119
14138
  {
14120
14139
  ref: uploadInputRef,
@@ -14132,9 +14151,9 @@ function FileBrowser({
14132
14151
  ] }) : null
14133
14152
  ] })
14134
14153
  ] }),
14135
- /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: "fd-fb-body", children: [
14136
- /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: "fd-fb-tree", role: "region", "aria-label": "Folder tree", children: [
14137
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
14154
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fd-fb-body", children: [
14155
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fd-fb-tree", role: "region", "aria-label": "Folder tree", children: [
14156
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
14138
14157
  RowShell,
14139
14158
  {
14140
14159
  icon: "house-simple",
@@ -14145,7 +14164,7 @@ function FileBrowser({
14145
14164
  className: ["fd-fb-tree-row", currentFolderId == null ? "is-current" : ""].filter(Boolean).join(" ")
14146
14165
  }
14147
14166
  ),
14148
- childrenOf(folders, null).map((f) => /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
14167
+ childrenOf(folders, null).map((f) => /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
14149
14168
  TreeNode,
14150
14169
  {
14151
14170
  folder: f,
@@ -14159,18 +14178,18 @@ function FileBrowser({
14159
14178
  f.id
14160
14179
  ))
14161
14180
  ] }),
14162
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("div", { className: "fd-fb-main", role: "region", "aria-label": "Folder contents", children: /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
14181
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("div", { className: "fd-fb-main", role: "region", "aria-label": "Folder contents", children: /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
14163
14182
  LoadingRegion,
14164
14183
  {
14165
14184
  state: loading ? "loading" : "ready",
14166
14185
  label: "Loading folder contents",
14167
- skeleton: /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: "fd-stack", style: { gap: 8, padding: 12 }, children: [
14168
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Skeleton, { h: 44, radius: "10px" }),
14169
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Skeleton, { h: 44, radius: "10px" }),
14170
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Skeleton, { h: 44, radius: "10px" })
14186
+ skeleton: /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fd-stack", style: { gap: 8, padding: 12 }, children: [
14187
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Skeleton, { h: 44, radius: "10px" }),
14188
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Skeleton, { h: 44, radius: "10px" }),
14189
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Skeleton, { h: 44, radius: "10px" })
14171
14190
  ] }),
14172
- children: isEmpty ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(EmptyState, { icon: "folder-open", title: "This folder is empty", children: canUpload ? "Drop files here, or use Upload above." : "Nothing has been filed here yet." }) : /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: "fd-fb-list", children: [
14173
- subfolders.map((f) => /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
14191
+ children: isEmpty ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(EmptyState, { icon: "folder-open", title: "This folder is empty", children: canUpload ? "Drop files here, or use Upload above." : "Nothing has been filed here yet." }) : /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fd-fb-list", children: [
14192
+ subfolders.map((f) => /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
14174
14193
  RowShell,
14175
14194
  {
14176
14195
  icon: "folder-simple",
@@ -14179,9 +14198,9 @@ function FileBrowser({
14179
14198
  draggableId: canMove ? { kind: "folder", id: f.id } : void 0,
14180
14199
  isDropTarget: canMove,
14181
14200
  onDropPayload: (p) => moveIntoFolder(p, f.id),
14182
- actions: /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)(import_jsx_runtime100.Fragment, { children: [
14183
- canRenameFolder ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(IconButton, { icon: "pencil-simple", label: "Rename " + f.name, size: "sm", variant: "ghost", onClick: () => openRename(f) }) : null,
14184
- canMove ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
14201
+ actions: /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)(import_jsx_runtime101.Fragment, { children: [
14202
+ canRenameFolder ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(IconButton, { icon: "pencil-simple", label: "Rename " + f.name, size: "sm", variant: "ghost", onClick: () => openRename(f) }) : null,
14203
+ canMove ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
14185
14204
  FolderPickerMenu,
14186
14205
  {
14187
14206
  label: "Move " + f.name,
@@ -14189,12 +14208,12 @@ function FileBrowser({
14189
14208
  onPick: (target) => moveIntoFolder({ kind: "folder", id: f.id }, target)
14190
14209
  }
14191
14210
  ) : null,
14192
- canDeleteFolder ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(IconButton, { icon: "trash-simple", label: "Delete " + f.name, size: "sm", variant: "ghost", onClick: () => openDelete(f) }) : null
14211
+ canDeleteFolder ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(IconButton, { icon: "trash-simple", label: "Delete " + f.name, size: "sm", variant: "ghost", onClick: () => openDelete(f) }) : null
14193
14212
  ] })
14194
14213
  },
14195
14214
  f.id
14196
14215
  )),
14197
- currentFiles.map((file) => /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
14216
+ currentFiles.map((file) => /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
14198
14217
  RowShell,
14199
14218
  {
14200
14219
  icon: iconForMime(file.mime, file.name),
@@ -14202,8 +14221,8 @@ function FileBrowser({
14202
14221
  meta: file.size ? formatBytes(file.size) : void 0,
14203
14222
  onOpen: onOpenFile ? () => onOpenFile(file) : void 0,
14204
14223
  draggableId: canMove ? { kind: "file", id: file.id } : void 0,
14205
- actions: /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)(import_jsx_runtime100.Fragment, { children: [
14206
- canMove ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
14224
+ actions: /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)(import_jsx_runtime101.Fragment, { children: [
14225
+ canMove ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
14207
14226
  FolderPickerMenu,
14208
14227
  {
14209
14228
  label: "Move " + file.name,
@@ -14211,7 +14230,7 @@ function FileBrowser({
14211
14230
  onPick: (target) => onMoveFile && onMoveFile(file.id, target)
14212
14231
  }
14213
14232
  ) : null,
14214
- canRemoveFile ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(IconButton, { icon: "trash-simple", label: "Remove " + file.name, size: "sm", variant: "ghost", onClick: () => onRemoveFile && onRemoveFile(file) }) : null
14233
+ canRemoveFile ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(IconButton, { icon: "trash-simple", label: "Remove " + file.name, size: "sm", variant: "ghost", onClick: () => onRemoveFile && onRemoveFile(file) }) : null
14215
14234
  ] })
14216
14235
  },
14217
14236
  file.id
@@ -14220,10 +14239,10 @@ function FileBrowser({
14220
14239
  }
14221
14240
  ) })
14222
14241
  ] }),
14223
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Modal, { open: createOpen, title: "New folder", onClose: () => setCreateOpen(false), footer: /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)(import_jsx_runtime100.Fragment, { children: [
14224
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Button, { variant: "secondary", onClick: () => setCreateOpen(false), children: "Cancel" }),
14225
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Button, { onClick: submitCreate, disabled: !createName.trim(), children: "Create" })
14226
- ] }), children: /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
14242
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Modal, { open: createOpen, title: "New folder", onClose: () => setCreateOpen(false), footer: /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)(import_jsx_runtime101.Fragment, { children: [
14243
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Button, { variant: "secondary", onClick: () => setCreateOpen(false), children: "Cancel" }),
14244
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Button, { onClick: submitCreate, disabled: !createName.trim(), children: "Create" })
14245
+ ] }), children: /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
14227
14246
  "input",
14228
14247
  {
14229
14248
  className: "fd-fb-input",
@@ -14237,10 +14256,10 @@ function FileBrowser({
14237
14256
  autoFocus: true
14238
14257
  }
14239
14258
  ) }),
14240
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Modal, { open: renameTarget != null, title: "Rename folder", onClose: () => setRenameTarget(null), footer: /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)(import_jsx_runtime100.Fragment, { children: [
14241
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Button, { variant: "secondary", onClick: () => setRenameTarget(null), children: "Cancel" }),
14242
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Button, { onClick: submitRename, disabled: !renameValue.trim(), children: "Save" })
14243
- ] }), children: /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
14259
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Modal, { open: renameTarget != null, title: "Rename folder", onClose: () => setRenameTarget(null), footer: /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)(import_jsx_runtime101.Fragment, { children: [
14260
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Button, { variant: "secondary", onClick: () => setRenameTarget(null), children: "Cancel" }),
14261
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Button, { onClick: submitRename, disabled: !renameValue.trim(), children: "Save" })
14262
+ ] }), children: /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
14244
14263
  "input",
14245
14264
  {
14246
14265
  className: "fd-fb-input",
@@ -14254,22 +14273,22 @@ function FileBrowser({
14254
14273
  autoFocus: true
14255
14274
  }
14256
14275
  ) }),
14257
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
14276
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
14258
14277
  Modal,
14259
14278
  {
14260
14279
  open: deleteTarget != null,
14261
14280
  title: deleteTarget ? "Delete \u201C" + deleteTarget.name + "\u201D?" : "Delete folder?",
14262
14281
  description: "This can't be undone. The folder must be empty.",
14263
14282
  onClose: () => setDeleteTarget(null),
14264
- footer: /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)(import_jsx_runtime100.Fragment, { children: [
14265
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Button, { variant: "secondary", onClick: () => setDeleteTarget(null), children: "Cancel" }),
14266
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Button, { variant: "danger", onClick: confirmDelete, children: "Delete" })
14283
+ footer: /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)(import_jsx_runtime101.Fragment, { children: [
14284
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Button, { variant: "secondary", onClick: () => setDeleteTarget(null), children: "Cancel" }),
14285
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Button, { variant: "danger", onClick: confirmDelete, children: "Delete" })
14267
14286
  ] })
14268
14287
  }
14269
14288
  )
14270
14289
  ] });
14271
14290
  if (!canUpload) return content;
14272
- return /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Dropzone, { className: "fd-fb-dropzone", onFiles: (picked) => onUpload && onUpload(picked, currentFolderId), label: "Drop files to upload", children: content });
14291
+ return /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Dropzone, { className: "fd-fb-dropzone", onFiles: (picked) => onUpload && onUpload(picked, currentFolderId), label: "Drop files to upload", children: content });
14273
14292
  }
14274
14293
  function BreadcrumbCrumb({
14275
14294
  label,
@@ -14278,8 +14297,8 @@ function BreadcrumbCrumb({
14278
14297
  isDropTarget,
14279
14298
  onDropPayload
14280
14299
  }) {
14281
- const [over, setOver] = React70.useState(false);
14282
- const dragCounter = React70.useRef(0);
14300
+ const [over, setOver] = React71.useState(false);
14301
+ const dragCounter = React71.useRef(0);
14283
14302
  const dropHandlers = isDropTarget ? {
14284
14303
  onDragEnter: (e) => {
14285
14304
  if (!hasInternalPayload(e)) return;
@@ -14304,11 +14323,11 @@ function BreadcrumbCrumb({
14304
14323
  if (payload && onDropPayload) onDropPayload(payload);
14305
14324
  }
14306
14325
  } : {};
14307
- return /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: ["fd-fb-crumb", over ? "is-drop-target" : ""].filter(Boolean).join(" "), ...dropHandlers, children: isCurrent ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "fd-fb-crumb-current", "aria-current": "page", children: label }) : /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("button", { type: "button", className: "fd-fb-crumb-link", onClick, children: label }) });
14326
+ return /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: ["fd-fb-crumb", over ? "is-drop-target" : ""].filter(Boolean).join(" "), ...dropHandlers, children: isCurrent ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fd-fb-crumb-current", "aria-current": "page", children: label }) : /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("button", { type: "button", className: "fd-fb-crumb-link", onClick, children: label }) });
14308
14327
  }
14309
14328
 
14310
14329
  // src/kits/query.ts
14311
- var React71 = __toESM(require("react"), 1);
14330
+ var React72 = __toESM(require("react"), 1);
14312
14331
  var isMultiSelectShaped = (v) => !!v && typeof v === "object" && Array.isArray(v.values);
14313
14332
  var isRangeShaped = (v) => !!v && typeof v === "object" && ("min" in v || "max" in v);
14314
14333
  var isDateShaped = (v) => !!v && typeof v === "object" && "kind" in v;
@@ -14363,22 +14382,22 @@ function compare(a, b, dir) {
14363
14382
  var API = null;
14364
14383
  var PREFS = null;
14365
14384
  function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
14366
- const [query, setQuery] = React71.useState(() => {
14385
+ const [query, setQuery] = React72.useState(() => {
14367
14386
  const store = PREFS || window.PlannerPrefs;
14368
14387
  const saved = prefsKey && store ? store.getTable(prefsKey) : {};
14369
14388
  return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
14370
14389
  });
14371
- const savePref = React71.useCallback((patch2) => {
14390
+ const savePref = React72.useCallback((patch2) => {
14372
14391
  const store = PREFS || window.PlannerPrefs;
14373
14392
  if (prefsKey && store) store.setTable(prefsKey, patch2);
14374
14393
  }, [prefsKey]);
14375
- const [res, setRes] = React71.useState(null);
14376
- const [loading, setLoading] = React71.useState(true);
14377
- const seq2 = React71.useRef(0);
14394
+ const [res, setRes] = React72.useState(null);
14395
+ const [loading, setLoading] = React72.useState(true);
14396
+ const seq2 = React72.useRef(0);
14378
14397
  const depKey = (deps || []).join("|");
14379
14398
  const paramKey = JSON.stringify(params || {});
14380
14399
  const queryKey = JSON.stringify(query);
14381
- React71.useEffect(() => {
14400
+ React72.useEffect(() => {
14382
14401
  const id = ++seq2.current;
14383
14402
  setLoading(true);
14384
14403
  const t = setTimeout(() => {
@@ -14697,12 +14716,12 @@ function createVersionStore(initialState, options) {
14697
14716
  }
14698
14717
 
14699
14718
  // src/kits/documentTitle.ts
14700
- var React72 = __toESM(require("react"), 1);
14719
+ var React73 = __toESM(require("react"), 1);
14701
14720
  function formatDocumentTitle(routeTitle, appName) {
14702
14721
  return [routeTitle, appName, "Flytedesk"].filter((part) => !!part && part.length > 0).join(" \xB7 ");
14703
14722
  }
14704
14723
  function useDocumentTitle(routeTitle, appName) {
14705
- React72.useEffect(() => {
14724
+ React73.useEffect(() => {
14706
14725
  if (typeof document === "undefined") return;
14707
14726
  document.title = formatDocumentTitle(routeTitle, appName);
14708
14727
  }, [routeTitle, appName]);
@@ -14717,6 +14736,7 @@ function useDocumentTitle(routeTitle, appName) {
14717
14736
  AppShell,
14718
14737
  AppSwitcher,
14719
14738
  AppearanceMenu,
14739
+ AppearanceProvider,
14720
14740
  Avatar,
14721
14741
  AvatarStack,
14722
14742
  Badge,
@@ -14872,6 +14892,7 @@ function useDocumentTitle(routeTitle, appName) {
14872
14892
  __resetLayerStackForTests,
14873
14893
  acceptMatches,
14874
14894
  anyOfFilter,
14895
+ applyAppearance,
14875
14896
  applyPrefs,
14876
14897
  channelWeightOf,
14877
14898
  computeNeedMore,
@@ -14917,6 +14938,7 @@ function useDocumentTitle(routeTitle, appName) {
14917
14938
  toAttachment,
14918
14939
  tokenize,
14919
14940
  useAppearancePrefs,
14941
+ useAppearanceStore,
14920
14942
  useChatEngine,
14921
14943
  useCopyToClipboard,
14922
14944
  useCornerStackSlot,
@@ -14932,6 +14954,7 @@ function useDocumentTitle(routeTitle, appName) {
14932
14954
  useStagedFiles,
14933
14955
  useToast,
14934
14956
  validateFilterValue,
14935
- visibleMessages
14957
+ visibleMessages,
14958
+ watchAppearance
14936
14959
  });
14937
14960
  //# sourceMappingURL=index.cjs.map