@flytedan/flytebot-design-system 0.57.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,
@@ -49,6 +50,7 @@ __export(index_exports, {
49
50
  CHANNEL_WEIGHTS: () => CHANNEL_WEIGHTS,
50
51
  CHAT_UNAVAILABLE: () => CHAT_UNAVAILABLE,
51
52
  COPIED_FEEDBACK_MS: () => COPIED_FEEDBACK_MS,
53
+ CORNER_STACK_INSET_PROPERTY: () => CORNER_STACK_INSET_PROPERTY,
52
54
  Calendar: () => Calendar,
53
55
  Card: () => Card,
54
56
  CardGrid: () => CardGrid,
@@ -192,6 +194,7 @@ __export(index_exports, {
192
194
  __resetLayerStackForTests: () => __resetLayerStackForTests,
193
195
  acceptMatches: () => acceptMatches,
194
196
  anyOfFilter: () => anyOfFilter,
197
+ applyAppearance: () => applyAppearance,
195
198
  applyPrefs: () => applyPrefs,
196
199
  channelWeightOf: () => channelWeightOf,
197
200
  computeNeedMore: () => computeNeedMore,
@@ -237,6 +240,7 @@ __export(index_exports, {
237
240
  toAttachment: () => toAttachment,
238
241
  tokenize: () => tokenize,
239
242
  useAppearancePrefs: () => useAppearancePrefs,
243
+ useAppearanceStore: () => useAppearanceStore,
240
244
  useChatEngine: () => useChatEngine,
241
245
  useCopyToClipboard: () => useCopyToClipboard,
242
246
  useCornerStackSlot: () => useCornerStackSlot,
@@ -252,7 +256,8 @@ __export(index_exports, {
252
256
  useStagedFiles: () => useStagedFiles,
253
257
  useToast: () => useToast,
254
258
  validateFilterValue: () => validateFilterValue,
255
- visibleMessages: () => visibleMessages
259
+ visibleMessages: () => visibleMessages,
260
+ watchAppearance: () => watchAppearance
256
261
  });
257
262
  module.exports = __toCommonJS(index_exports);
258
263
 
@@ -1386,9 +1391,11 @@ var React10 = __toESM(require("react"), 1);
1386
1391
  // src/kits/cornerStack.tsx
1387
1392
  var React9 = __toESM(require("react"), 1);
1388
1393
  var import_react_dom5 = require("react-dom");
1394
+ var CORNER_STACK_INSET_PROPERTY = "--fd-corner-stack-inset";
1389
1395
  var SLOTS = ["jobs", "toasts"];
1390
1396
  var references = /* @__PURE__ */ new Map();
1391
1397
  var host = null;
1398
+ var hostObserver = null;
1392
1399
  var slotElements = /* @__PURE__ */ new Map();
1393
1400
  function createHost() {
1394
1401
  const stack = document.createElement("div");
@@ -1402,8 +1409,18 @@ function createHost() {
1402
1409
  slotElements.set(slot, element);
1403
1410
  }
1404
1411
  document.body.appendChild(stack);
1412
+ publishInset(stack);
1413
+ if (typeof ResizeObserver === "function") {
1414
+ hostObserver = new ResizeObserver(() => publishInset(stack));
1415
+ hostObserver.observe(stack);
1416
+ }
1405
1417
  return stack;
1406
1418
  }
1419
+ function publishInset(stack) {
1420
+ const height = stack.offsetHeight;
1421
+ const inset = height > 0 ? height + parseFloat(getComputedStyle(stack).bottom) : 0;
1422
+ document.documentElement.style.setProperty(CORNER_STACK_INSET_PROPERTY, `${inset}px`);
1423
+ }
1407
1424
  function acquire(slot) {
1408
1425
  host ??= createHost();
1409
1426
  references.set(slot, (references.get(slot) ?? 0) + 1);
@@ -1414,6 +1431,9 @@ function release(slot) {
1414
1431
  if (remaining > 0) references.set(slot, remaining);
1415
1432
  else references.delete(slot);
1416
1433
  if (references.size === 0 && host) {
1434
+ hostObserver?.disconnect();
1435
+ hostObserver = null;
1436
+ document.documentElement.style.removeProperty(CORNER_STACK_INSET_PROPERTY);
1417
1437
  host.remove();
1418
1438
  host = null;
1419
1439
  slotElements.clear();
@@ -1852,7 +1872,7 @@ function AppShell({
1852
1872
  /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1853
1873
  "div",
1854
1874
  {
1855
- className: contentClassName,
1875
+ className: ["fd-app-shell-content", contentClassName].filter(Boolean).join(" "),
1856
1876
  style: {
1857
1877
  flex: 1,
1858
1878
  minWidth: 0,
@@ -1860,7 +1880,6 @@ function AppShell({
1860
1880
  // table) is contained and clipped by this scroller, never stretching the document.
1861
1881
  position: "relative",
1862
1882
  overflowY: "auto",
1863
- padding: 24,
1864
1883
  maxWidth: contentMaxWidth,
1865
1884
  margin: "0 auto",
1866
1885
  width: "100%",
@@ -8303,7 +8322,7 @@ function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
8303
8322
  }
8304
8323
 
8305
8324
  // src/components/platform/AppearanceMenu.tsx
8306
- var React52 = __toESM(require("react"), 1);
8325
+ var React53 = __toESM(require("react"), 1);
8307
8326
 
8308
8327
  // src/kits/appearance.ts
8309
8328
  var React51 = __toESM(require("react"), 1);
@@ -8400,20 +8419,25 @@ function applyPrefs(prefs, root = document.documentElement) {
8400
8419
  if (prefs.reduceMotion) root.setAttribute("data-motion", "reduce");
8401
8420
  else root.removeAttribute("data-motion");
8402
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
+ }
8403
8439
  function useAppearancePrefs(store) {
8404
8440
  const prefs = React51.useSyncExternalStore(store.subscribe, store.getSnapshot);
8405
- React51.useEffect(() => {
8406
- applyPrefs(prefs);
8407
- }, [prefs]);
8408
- React51.useEffect(() => {
8409
- if (prefs.theme !== "system" || typeof window === "undefined" || typeof window.matchMedia !== "function") {
8410
- return;
8411
- }
8412
- const mq = window.matchMedia("(prefers-color-scheme: dark)");
8413
- const onChange = () => applyPrefs(prefs);
8414
- mq.addEventListener("change", onChange);
8415
- return () => mq.removeEventListener("change", onChange);
8416
- }, [prefs]);
8417
8441
  const update = React51.useCallback(
8418
8442
  (patch) => {
8419
8443
  store.write({ ...store.getSnapshot(), ...patch });
@@ -8423,8 +8447,22 @@ function useAppearancePrefs(store) {
8423
8447
  return [prefs, update];
8424
8448
  }
8425
8449
 
8426
- // src/components/platform/AppearanceMenu.tsx
8450
+ // src/components/platform/AppearanceProvider.tsx
8451
+ var React52 = __toESM(require("react"), 1);
8427
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");
8428
8466
  var THEME_OPTIONS = [
8429
8467
  { value: "light", label: "Light" },
8430
8468
  { value: "dark", label: "Dark" },
@@ -8436,17 +8474,13 @@ var TEXT_SCALE_OPTIONS = [
8436
8474
  { value: "lg", label: "L" },
8437
8475
  { value: "xl", label: "XL" }
8438
8476
  ];
8439
- function AppearanceMenu({ className = "", store: storeProp, storageKey, storage, defaults }) {
8440
- const store = React52.useMemo(
8441
- () => storeProp ?? createLocalStorageAppearanceStore({ storageKey, storage, defaults }),
8442
- [storeProp, storageKey, storage, defaults]
8443
- );
8444
- const [prefs, update] = useAppearancePrefs(store);
8445
- const [open2, setOpen] = React52.useState(false);
8446
- 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);
8447
8481
  const patch = (p) => update(p);
8448
- return /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)(React52.Fragment, { children: [
8449
- /* @__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)(
8450
8484
  IconButton,
8451
8485
  {
8452
8486
  icon: "circle-half",
@@ -8454,7 +8488,7 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
8454
8488
  onClick: () => setOpen((v) => !v)
8455
8489
  }
8456
8490
  ) }),
8457
- /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(
8491
+ /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
8458
8492
  Popover,
8459
8493
  {
8460
8494
  open: open2,
@@ -8464,10 +8498,10 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
8464
8498
  padded: true,
8465
8499
  width: 260,
8466
8500
  label: "Appearance settings",
8467
- children: /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("div", { className: "fd-stack", style: { display: "flex", flexDirection: "column", gap: 16 }, children: [
8468
- /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
8469
- /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("span", { className: "fd-field-label", children: "Theme" }),
8470
- /* @__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)(
8471
8505
  SegmentedControl,
8472
8506
  {
8473
8507
  options: THEME_OPTIONS,
@@ -8477,9 +8511,9 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
8477
8511
  }
8478
8512
  )
8479
8513
  ] }),
8480
- /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
8481
- /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("span", { className: "fd-field-label", children: "Text size" }),
8482
- /* @__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)(
8483
8517
  SegmentedControl,
8484
8518
  {
8485
8519
  options: TEXT_SCALE_OPTIONS,
@@ -8489,7 +8523,7 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
8489
8523
  }
8490
8524
  )
8491
8525
  ] }),
8492
- /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(
8526
+ /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
8493
8527
  Switch,
8494
8528
  {
8495
8529
  label: "High contrast",
@@ -8498,7 +8532,7 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
8498
8532
  onChange: (e) => patch({ highContrast: e.target.checked })
8499
8533
  }
8500
8534
  ),
8501
- /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(
8535
+ /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
8502
8536
  Switch,
8503
8537
  {
8504
8538
  label: "Reduce motion",
@@ -8514,14 +8548,14 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
8514
8548
  }
8515
8549
 
8516
8550
  // src/components/platform/ApiSpecBrowser.tsx
8517
- var React53 = __toESM(require("react"), 1);
8518
- var import_jsx_runtime79 = require("react/jsx-runtime");
8551
+ var React54 = __toESM(require("react"), 1);
8552
+ var import_jsx_runtime80 = require("react/jsx-runtime");
8519
8553
  var METHOD_TONE = { GET: "success", POST: "info", PATCH: "warning", PUT: "warning", DELETE: "danger" };
8520
8554
  function Json({ obj }) {
8521
- 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) });
8522
8556
  }
8523
8557
  function Endpoint({ s, onRequest }) {
8524
- const [tried, setTried] = React53.useState(null);
8558
+ const [tried, setTried] = React54.useState(null);
8525
8559
  const run = async () => {
8526
8560
  setTried("busy");
8527
8561
  const t0 = (window.performance || Date).now();
@@ -8532,50 +8566,50 @@ function Endpoint({ s, onRequest }) {
8532
8566
  setTried({ ms: Math.round((window.performance || Date).now() - t0), error: String(e && e.message || e) });
8533
8567
  }
8534
8568
  };
8535
- 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: [
8536
- /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-row", style: { gap: 10, padding: "14px 18px", flexWrap: "wrap" }, children: [
8537
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Badge, { tone: METHOD_TONE[s.method] || "neutral", children: s.method }),
8538
- /* @__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 }),
8539
- s.isList ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Badge, { tone: "neutral", icon: "rows", children: "Paged list" }) : null,
8540
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { style: { flex: 1 } }),
8541
- /* @__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: [
8542
8576
  s.latency[0],
8543
8577
  "\u2013",
8544
8578
  s.latency[1],
8545
8579
  "ms"
8546
8580
  ] }),
8547
- /* @__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" })
8548
8582
  ] }),
8549
- /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-stack", style: { gap: 14, padding: "0 18px 16px" }, children: [
8550
- /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
8551
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 700 }, children: s.title }),
8552
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: s.purpose }),
8553
- 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
8554
8588
  ] }),
8555
- /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(280px,1fr))", gap: 12, alignItems: "start" }, children: [
8556
- s.request ? /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
8557
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-overline fd-muted", children: "Request body" }),
8558
- /* @__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 })
8559
8593
  ] }) : null,
8560
- s.query ? /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
8561
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-overline fd-muted", children: "Query" }),
8562
- /* @__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 })
8563
8597
  ] }) : null,
8564
- /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
8565
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-overline fd-muted", children: "Response 200" }),
8566
- /* @__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 })
8567
8601
  ] })
8568
8602
  ] }),
8569
- s.notes ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Flag, { tone: "info", statement: "Implementation note", cost: s.notes, actions: null }) : null,
8570
- tried && tried !== "busy" ? /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
8571
- /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("span", { className: "fd-row", style: { gap: 8 }, children: [
8572
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-overline fd-muted", children: "Simulated response" }),
8573
- /* @__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: [
8574
8608
  tried.ms,
8575
8609
  "ms"
8576
8610
  ] })
8577
8611
  ] }),
8578
- /* @__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 })
8579
8613
  ] }) : null
8580
8614
  ] })
8581
8615
  ] }) });
@@ -8594,58 +8628,58 @@ function ApiSpecBrowser({
8594
8628
  className = "",
8595
8629
  ...rest
8596
8630
  }) {
8597
- const [q, setQ] = React53.useState("");
8598
- const [method, setMethod] = React53.useState(null);
8599
- const [mod, setMod] = React53.useState(null);
8600
- 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);
8601
8635
  const activeModule = modules && modules.find((m) => m.id === mod);
8602
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())));
8603
8637
  const effGroups = groups && groups.length ? groups : [["All endpoints", spec.map((s) => s.id)]];
8604
8638
  const methods = [...new Set(spec.map((s) => s.method))];
8605
8639
  const listCount = spec.filter((s) => s.isList).length;
8606
- return /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 1100 }, ...rest, children: [
8607
- /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
8608
- kicker ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-overline fd-muted", children: kicker }) : null,
8609
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
8610
- 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
8611
8645
  ] }),
8612
- modules && modules.length ? /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-stack", style: { gap: 8 }, children: [
8613
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-overline fd-muted", children: "Filter by screen \u2014 every endpoint that screen depends on" }),
8614
- /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
8615
- /* @__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: [
8616
8650
  "All screens ",
8617
- /* @__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 })
8618
8652
  ] }),
8619
- 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: [
8620
8654
  m.label,
8621
8655
  " ",
8622
- /* @__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 })
8623
8657
  ] }, m.id))
8624
8658
  ] }),
8625
- activeModule ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
8659
+ activeModule ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
8626
8660
  Flag,
8627
8661
  {
8628
8662
  tone: "info",
8629
8663
  statement: activeModule.label + " calls " + activeModule.endpoints.length + " endpoints.",
8630
8664
  cost: "Integration checklist for this screen: " + activeModule.endpoints.join(", ") + ". Wire these and the screen is done.",
8631
- 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" })
8632
8666
  }
8633
8667
  ) : null
8634
8668
  ] }) : null,
8635
- sourceNote ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Flag, { tone: "info", statement: "Design-first: this page is the spec.", cost: sourceNote, actions: null }) : null,
8636
- /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
8637
- /* @__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 } }),
8638
- 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: [
8639
8673
  m,
8640
8674
  " ",
8641
- /* @__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 })
8642
8676
  ] }, m)),
8643
- 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: [
8644
8678
  "Paged lists ",
8645
- /* @__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 })
8646
8680
  ] }) : null,
8647
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { style: { flex: 1 } }),
8648
- /* @__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: [
8649
8683
  hits.length,
8650
8684
  " of ",
8651
8685
  spec.length,
@@ -8653,31 +8687,31 @@ function ApiSpecBrowser({
8653
8687
  listCount ? " \xB7 " + listCount + " paged" : ""
8654
8688
  ] })
8655
8689
  ] }),
8656
- 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]) => {
8657
8691
  const items = hits.filter((s) => ids.indexOf(s.id) >= 0);
8658
8692
  if (!items.length) return null;
8659
- return /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-stack", style: { gap: 12 }, children: [
8660
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-label-lg", children: g }),
8661
- 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))
8662
8696
  ] }, g);
8663
8697
  }),
8664
- 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: [
8665
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-overline fd-muted", style: { width: 110, flex: "none", paddingTop: 2 }, children: k }),
8666
- /* @__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 })
8667
8701
  ] }, k)) }) }) : null,
8668
- 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: [
8669
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Badge, { tone: "danger", children: id }),
8670
- /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("span", { className: "fd-stack", style: { gap: 2, flex: 1 }, children: [
8671
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: question }),
8672
- /* @__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 })
8673
8707
  ] })
8674
8708
  ] }, id)) }) }) : null
8675
8709
  ] });
8676
8710
  }
8677
8711
 
8678
8712
  // src/components/platform/ProfilePage.tsx
8679
- var React54 = __toESM(require("react"), 1);
8680
- var import_jsx_runtime80 = require("react/jsx-runtime");
8713
+ var React55 = __toESM(require("react"), 1);
8714
+ var import_jsx_runtime81 = require("react/jsx-runtime");
8681
8715
  function fieldInitialValue(field, user) {
8682
8716
  if (field.value) return field.value(user);
8683
8717
  const raw = user[field.key];
@@ -8712,21 +8746,21 @@ function ProfilePage({
8712
8746
  }) {
8713
8747
  const { user: sessionUser, roles, permissions, saveProfile: saveProfile2 } = useSessionContext();
8714
8748
  const user = userProp || sessionUser;
8715
- const initialFieldValues = React54.useMemo(() => {
8749
+ const initialFieldValues = React55.useMemo(() => {
8716
8750
  const values2 = {};
8717
8751
  for (const field of fields) values2[field.key] = fieldInitialValue(field, user);
8718
8752
  return values2;
8719
8753
  }, [user.id, fields]);
8720
- const initialNotify = React54.useMemo(() => {
8754
+ const initialNotify = React55.useMemo(() => {
8721
8755
  const values2 = {};
8722
8756
  for (const n of notifications) values2[n.key] = !!user.notify?.[n.key];
8723
8757
  return values2;
8724
8758
  }, [user.id, notifications]);
8725
- const [values, setValues] = React54.useState(initialFieldValues);
8726
- const [notify, setNotify] = React54.useState(initialNotify);
8727
- const [saving, setSaving] = React54.useState(false);
8728
- const [saved, setSaved] = React54.useState(false);
8729
- 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);
8730
8764
  if (user.id !== prevUserId) {
8731
8765
  setPrevUserId(user.id);
8732
8766
  setValues(initialFieldValues);
@@ -8763,37 +8797,37 @@ function ProfilePage({
8763
8797
  };
8764
8798
  const displayName = fields.some((f) => f.key === "name") ? values.name || user.name : user.name;
8765
8799
  const fieldGroups = groupFields(fields);
8766
- return /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 860 }, children: [
8767
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
8768
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-overline fd-muted", children: "Account" }),
8769
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("h1", { className: "fd-h1", style: { margin: 0 }, children: "Your profile" }),
8770
- /* @__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." })
8771
8805
  ] }),
8772
- /* @__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: [
8773
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Avatar, { name: displayName, size: "lg" }),
8774
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-stack", style: { gap: 4, flex: 1, minWidth: 200 }, children: [
8775
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-h3", style: { margin: 0 }, children: displayName }),
8776
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 4 }, children: [
8777
- roles.map((r) => /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Badge, { tone: r.id === "owner" ? "success" : "neutral", children: r.name }, r.id)),
8778
- 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
8779
8813
  ] })
8780
8814
  ] }),
8781
- 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
8782
8816
  ] }) }),
8783
- 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)(
8784
8818
  Card,
8785
8819
  {
8786
- title: description ? /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fd-stack", style: { gap: 2 }, children: [
8787
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { children: group }),
8788
- /* @__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 })
8789
8823
  ] }) : group,
8790
8824
  elevation: "flat",
8791
- children: /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-stack", style: { gap: 14 }, children: [
8792
- /* @__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) => {
8793
8827
  const help = typeof field.help === "function" ? field.help(user) : field.help;
8794
8828
  const readOnly = field.readOnly || field.type === "readonly";
8795
8829
  if (field.type === "select") {
8796
- return /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
8830
+ return /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
8797
8831
  Select,
8798
8832
  {
8799
8833
  label: field.label,
@@ -8807,7 +8841,7 @@ function ProfilePage({
8807
8841
  field.key
8808
8842
  );
8809
8843
  }
8810
- return /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
8844
+ return /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
8811
8845
  Input,
8812
8846
  {
8813
8847
  label: field.label,
@@ -8823,7 +8857,7 @@ function ProfilePage({
8823
8857
  }) }),
8824
8858
  groupFieldDefs.filter((f) => f.type === "textarea").map((field) => {
8825
8859
  const help = typeof field.help === "function" ? field.help(user) : field.help;
8826
- return /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
8860
+ return /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
8827
8861
  Textarea,
8828
8862
  {
8829
8863
  label: field.label,
@@ -8843,16 +8877,16 @@ function ProfilePage({
8843
8877
  group
8844
8878
  )),
8845
8879
  extra,
8846
- 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,
8847
- /* @__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)(
8848
8882
  Card,
8849
8883
  {
8850
- title: /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fd-stack", style: { gap: 2 }, children: [
8851
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { children: "Access" }),
8852
- /* @__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" })
8853
8887
  ] }),
8854
8888
  elevation: "flat",
8855
- action: /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
8889
+ action: /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
8856
8890
  Button,
8857
8891
  {
8858
8892
  size: "sm",
@@ -8863,39 +8897,39 @@ function ProfilePage({
8863
8897
  }
8864
8898
  ),
8865
8899
  children: [
8866
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-stack", style: { gap: 0 }, children: [
8867
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(CardRow, { label: "Roles", children: roles.map((r) => r.name).join(", ") || "None" }),
8868
- /* @__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: [
8869
8903
  permissions.length,
8870
8904
  " granted"
8871
8905
  ] }),
8872
- /* @__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" })
8873
8907
  ] }),
8874
- /* @__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." })
8875
8909
  ]
8876
8910
  }
8877
8911
  ),
8878
- sessions ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
8912
+ sessions ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
8879
8913
  Card,
8880
8914
  {
8881
8915
  title: "Signed-in devices",
8882
8916
  elevation: "flat",
8883
- action: /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Button, { size: "sm", variant: "ghost", icon: "sign-out", onClick: onSignOutEverywhere, children: "Sign out everywhere" }),
8884
- 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: [
8885
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("i", { className: "ph ph-device-mobile", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
8886
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fd-stack", style: { gap: 1, flex: 1, minWidth: 160 }, children: [
8887
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: s.device }),
8888
- /* @__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: [
8889
8923
  s.where,
8890
8924
  " \xB7 ",
8891
8925
  s.when
8892
8926
  ] })
8893
8927
  ] }),
8894
- 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" })
8895
8929
  ] }, s.id)) })
8896
8930
  }
8897
8931
  ) : null,
8898
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-row", style: {
8932
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fd-row", style: {
8899
8933
  gap: 10,
8900
8934
  flexWrap: "wrap",
8901
8935
  position: "sticky",
@@ -8906,16 +8940,16 @@ function ProfilePage({
8906
8940
  border: "1px solid var(--border)",
8907
8941
  boxShadow: "0 -4px 16px rgba(11,13,17,.06)"
8908
8942
  }, children: [
8909
- /* @__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" }),
8910
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Button, { size: "sm", variant: "ghost", disabled: !dirty || saving, onClick: discard, children: "Discard" }),
8911
- /* @__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" })
8912
8946
  ] })
8913
8947
  ] });
8914
8948
  }
8915
8949
 
8916
8950
  // src/components/platform/SessionScreen.tsx
8917
- var React55 = __toESM(require("react"), 1);
8918
- var import_jsx_runtime81 = require("react/jsx-runtime");
8951
+ var React56 = __toESM(require("react"), 1);
8952
+ var import_jsx_runtime82 = require("react/jsx-runtime");
8919
8953
  var COPY = {
8920
8954
  "signing-in": { busy: "Signing you in\u2026" },
8921
8955
  "session-expired": { busy: "Your session expired \u2014 signing you back in\u2026" },
@@ -8928,28 +8962,28 @@ function SessionScreen({ kind, error, onRetry, productName }) {
8928
8962
  const copy = COPY[kind];
8929
8963
  const busyMessage = "busy" in copy ? copy.busy : null;
8930
8964
  const failureTitle = "failure" in copy ? copy.failure : null;
8931
- const [announced, setAnnounced] = React55.useState("");
8932
- React55.useEffect(() => {
8965
+ const [announced, setAnnounced] = React56.useState("");
8966
+ React56.useEffect(() => {
8933
8967
  setAnnounced(busyMessage ?? "");
8934
8968
  }, [busyMessage]);
8935
- const titleRef = React55.useRef(null);
8969
+ const titleRef = React56.useRef(null);
8936
8970
  const failed = failureTitle !== null;
8937
- React55.useEffect(() => {
8971
+ React56.useEffect(() => {
8938
8972
  titleRef.current?.focus({ preventScroll: true });
8939
8973
  }, [failed]);
8940
- 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: [
8941
- /* @__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" }) }),
8942
- /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fd-session-screen-frame", children: [
8943
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("div", { className: "fd-session-screen-stripe" }),
8944
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Card, { children: /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fd-session-screen-body", children: [
8945
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("h1", { ref: titleRef, tabIndex: -1, className: "fd-h3 fd-session-screen-title", children: productName }),
8946
- /* @__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: [
8947
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fd-spinner fd-spinner-lg fd-session-screen-spinner", "aria-hidden": "true" }),
8948
- /* @__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 })
8949
8983
  ] }) : null }),
8950
- failureTitle !== null ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fd-session-screen-failure", children: [
8951
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Banner, { tone: "danger", title: failureTitle, detail: error ?? void 0 }),
8952
- 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
8953
8987
  ] }) : null
8954
8988
  ] }) })
8955
8989
  ] })
@@ -8957,10 +8991,10 @@ function SessionScreen({ kind, error, onRetry, productName }) {
8957
8991
  }
8958
8992
 
8959
8993
  // src/components/platform/RoadmapTimeline.tsx
8960
- var React58 = __toESM(require("react"), 1);
8994
+ var React59 = __toESM(require("react"), 1);
8961
8995
 
8962
8996
  // src/kits/session.ts
8963
- var React56 = __toESM(require("react"), 1);
8997
+ var React57 = __toESM(require("react"), 1);
8964
8998
  var PERMISSION_CATALOG = [
8965
8999
  { group: "Plans", items: [
8966
9000
  { key: "plan.view", label: "View plans", detail: "Read any plan in the workspace." },
@@ -10527,8 +10561,8 @@ function roadmap(overrides) {
10527
10561
  };
10528
10562
  }
10529
10563
  function useSession() {
10530
- const [s, setS] = React56.useState(getSession);
10531
- React56.useEffect(() => subscribe(setS), []);
10564
+ const [s, setS] = React57.useState(getSession);
10565
+ React57.useEffect(() => subscribe(setS), []);
10532
10566
  return s;
10533
10567
  }
10534
10568
  var SessionKit = {
@@ -10561,7 +10595,7 @@ var SessionKit = {
10561
10595
  };
10562
10596
  function DemoSessionProvider({ children }) {
10563
10597
  const session = useSession();
10564
- const value = React56.useMemo(
10598
+ const value = React57.useMemo(
10565
10599
  () => ({
10566
10600
  user: session.user,
10567
10601
  roles: session.roles,
@@ -10577,11 +10611,11 @@ function DemoSessionProvider({ children }) {
10577
10611
  }),
10578
10612
  [session]
10579
10613
  );
10580
- return React56.createElement(SessionProvider, { value }, children);
10614
+ return React57.createElement(SessionProvider, { value }, children);
10581
10615
  }
10582
10616
 
10583
10617
  // src/kits/runtime.ts
10584
- var React57 = __toESM(require("react"), 1);
10618
+ var React58 = __toESM(require("react"), 1);
10585
10619
  var WIRED_ENDPOINTS = [
10586
10620
  // Nothing yet. Every id below would come from a real service:
10587
10621
  // "plan.get", "placements.list", …
@@ -10752,8 +10786,8 @@ var RuntimeKit = {
10752
10786
  };
10753
10787
  RuntimeKit.declare(FEATURE_NEEDS);
10754
10788
  function useRuntimeMode() {
10755
- const [m, setM] = React57.useState(RuntimeKit.getMode());
10756
- React57.useEffect(() => RuntimeKit.subscribe(setM), []);
10789
+ const [m, setM] = React58.useState(RuntimeKit.getMode());
10790
+ React58.useEffect(() => RuntimeKit.subscribe(setM), []);
10757
10791
  return m;
10758
10792
  }
10759
10793
  function useFeatureStatus(key) {
@@ -10772,7 +10806,7 @@ var UseRuntimeMode = useRuntimeMode;
10772
10806
  var UseFeatureStatus = useFeatureStatus;
10773
10807
 
10774
10808
  // src/components/platform/RoadmapTimeline.tsx
10775
- var import_jsx_runtime82 = require("react/jsx-runtime");
10809
+ var import_jsx_runtime83 = require("react/jsx-runtime");
10776
10810
  var STATUS = {
10777
10811
  shipped: { tone: "success", icon: "check-circle", label: "Wired" },
10778
10812
  next: { tone: "warning", icon: "traffic-cone", label: "Not wired" },
@@ -10787,45 +10821,45 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
10787
10821
  const s = STATUS[item.status] || STATUS.planned;
10788
10822
  const deps = (item.dependsOn || []).map((k) => byKey[k]).filter(Boolean);
10789
10823
  const blocking = deps.filter((d) => !d.implemented);
10790
- 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: [
10791
- /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
10792
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fd-body", style: { fontWeight: 700, flex: 1, minWidth: 140 }, children: item.label }),
10793
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Badge, { tone: "neutral", icon: PROJECT_ICON[item.project] || "squares-four", children: item.project }),
10794
- /* @__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 })
10795
10829
  ] }),
10796
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: item.description }),
10797
- item.backend ? /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start" }, children: [
10798
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fd-overline fd-muted", style: { width: 62, flex: "none", paddingTop: 2 }, children: "Backend" }),
10799
- /* @__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 })
10800
10834
  ] }) : null,
10801
- /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
10802
- item.effort ? /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
10803
- /* @__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" }),
10804
10838
  " ",
10805
10839
  item.effort
10806
10840
  ] }) : null,
10807
- /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
10808
- /* @__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" }),
10809
10843
  " ",
10810
10844
  item.owner
10811
10845
  ] }),
10812
- item.screen ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Badge, { tone: "neutral", icon: "browser", children: "screen" }) : null,
10813
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { style: { flex: 1 } }),
10814
- /* @__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)(
10815
10849
  "button",
10816
10850
  {
10817
10851
  type: "button",
10818
10852
  onClick: () => onOpenFlag && onOpenFlag(item.key),
10819
10853
  style: { all: "unset", cursor: "pointer", display: "inline-flex", alignItems: "center", gap: 5 },
10820
- 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 })
10821
10855
  }
10822
10856
  )
10823
10857
  ] }),
10824
- 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: [
10825
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fd-overline fd-muted", style: { paddingTop: 3 }, children: "After" }),
10826
- 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))
10827
10861
  ] }) : null,
10828
- 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: [
10829
10863
  "Blocked until ",
10830
10864
  blocking.map((d) => d.label).join(" and "),
10831
10865
  " ",
@@ -10836,12 +10870,12 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
10836
10870
  }
10837
10871
  function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
10838
10872
  const session = SessionKit.useSession();
10839
- const [project, setProject] = React58.useState("");
10840
- const [q, setQ] = React58.useState("");
10841
- const scrollRef = React58.useRef(null);
10842
- const nowRef = React58.useRef(null);
10843
- const rm = React58.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
10844
- 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(() => {
10845
10879
  const m = {};
10846
10880
  rm.items.forEach((i) => {
10847
10881
  m[i.key] = i;
@@ -10850,7 +10884,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
10850
10884
  }, [rm]);
10851
10885
  const items = rm.items.filter((i) => (!project || i.project === project) && (!q || (i.label + " " + i.description + " " + (i.backend || "") + " " + i.key).toLowerCase().includes(q.toLowerCase())));
10852
10886
  const projects = [...new Set(rm.items.map((i) => i.project))];
10853
- React58.useEffect(() => {
10887
+ React59.useEffect(() => {
10854
10888
  let raf1 = 0, raf2 = 0;
10855
10889
  const place = () => {
10856
10890
  const box = scrollRef.current, mark = nowRef.current;
@@ -10878,23 +10912,23 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
10878
10912
  }, 0);
10879
10913
  const nextPhase = items.find((i) => !i.implemented);
10880
10914
  let lastPhase = null;
10881
- return /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-stack", style: { gap: 16, maxWidth: 1e3 }, children: [
10882
- /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
10883
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fd-overline fd-muted", children: "Architecture" }),
10884
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
10885
- /* @__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." })
10886
10920
  ] }),
10887
- /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-grid-stats is-thin", children: [
10888
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(StatTile, { compact: true, label: "Wired", value: String(rm.shipped), sub: "of " + rm.items.length + " features" }),
10889
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(StatTile, { compact: true, label: "Remaining", value: String(rm.remaining), sub: "backend work" }),
10890
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(StatTile, { compact: true, label: "Est. effort", value: days ? days + " days" : "\u2014", sub: "sum of estimates, not calendar" }),
10891
- /* @__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" })
10892
10926
  ] }),
10893
- /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
10894
- /* @__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 } }),
10895
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Select, { placeholder: "All projects", value: project, onChange: (e) => setProject(e.target.value), options: projects, style: { width: 190 } }),
10896
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { style: { flex: 1 } }),
10897
- /* @__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)(
10898
10932
  Button,
10899
10933
  {
10900
10934
  size: "sm",
@@ -10908,7 +10942,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
10908
10942
  }
10909
10943
  )
10910
10944
  ] }),
10911
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
10945
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
10912
10946
  Flag,
10913
10947
  {
10914
10948
  tone: "info",
@@ -10917,60 +10951,60 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
10917
10951
  actions: null
10918
10952
  }
10919
10953
  ),
10920
- /* @__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: [
10921
- /* @__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%" } }) }),
10922
10956
  items.map((item, n) => {
10923
10957
  const showPhase = item.phase !== lastPhase;
10924
10958
  lastPhase = item.phase;
10925
10959
  const inPhase = items.filter((i) => i.phase === item.phase).length;
10926
10960
  const isBoundary = n === firstPending;
10927
- return /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)(React58.Fragment, { children: [
10928
- showPhase ? /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-rm-era", children: [
10929
- /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
10930
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
10931
- 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: [
10932
10966
  fmtDate(item.phaseStart),
10933
10967
  " \u2013 ",
10934
10968
  fmtDate(item.date)
10935
10969
  ] }),
10936
- /* @__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: [
10937
10971
  "\xB7 ",
10938
10972
  inPhase,
10939
10973
  " feature",
10940
10974
  inPhase === 1 ? "" : "s"
10941
10975
  ] })
10942
10976
  ] }),
10943
- 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
10944
10978
  ] }) : null,
10945
- 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: [
10946
- /* @__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" }),
10947
10981
  " You are here \u2014 everything above is wired"
10948
10982
  ] }) }) : null,
10949
- /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-rm-row", children: [
10950
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fd-rm-dot " + (item.implemented ? "is-shipped" : item.status === "next" ? "is-next" : "") }),
10951
- /* @__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: [
10952
10986
  fmtDate(item.date),
10953
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("br", {}),
10954
- /* @__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 })
10955
10989
  ] }),
10956
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(RoadmapCard, { item, byKey, onOpenFlag })
10990
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(RoadmapCard, { item, byKey, onOpenFlag })
10957
10991
  ] })
10958
10992
  ] }, item.key);
10959
10993
  }),
10960
- !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
10961
10995
  ] }) }) }),
10962
- /* @__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: [
10963
10997
  "Derived from the feature-flag registry \u2014 each entry's status is its flag's ",
10964
- /* @__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" }),
10965
10999
  " field, so this page cannot drift from what the apps actually do."
10966
11000
  ] })
10967
11001
  ] });
10968
11002
  }
10969
11003
 
10970
11004
  // src/components/platform/ComingSoon.tsx
10971
- var React59 = __toESM(require("react"), 1);
11005
+ var React60 = __toESM(require("react"), 1);
10972
11006
  var import_react_dom7 = require("react-dom");
10973
- var import_jsx_runtime83 = require("react/jsx-runtime");
11007
+ var import_jsx_runtime84 = require("react/jsx-runtime");
10974
11008
  var BYPASS_STORE = "fd.soon.bypass.v1";
10975
11009
  function readBypassed() {
10976
11010
  try {
@@ -10986,8 +11020,8 @@ function writeBypassed(list) {
10986
11020
  }
10987
11021
  }
10988
11022
  function useBypass(key) {
10989
- const [on, setOn] = React59.useState(() => !!key && readBypassed().indexOf(key) >= 0);
10990
- React59.useEffect(() => {
11023
+ const [on, setOn] = React60.useState(() => !!key && readBypassed().indexOf(key) >= 0);
11024
+ React60.useEffect(() => {
10991
11025
  setOn(!!key && readBypassed().indexOf(key) >= 0);
10992
11026
  }, [key]);
10993
11027
  const set = (next) => {
@@ -11000,43 +11034,43 @@ function useBypass(key) {
11000
11034
  return [on, set];
11001
11035
  }
11002
11036
  function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass }) {
11003
- return /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)(import_jsx_runtime83.Fragment, { children: [
11004
- /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { className: "fd-soon-badge", children: [
11005
- /* @__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" }),
11006
11040
  label
11007
11041
  ] }),
11008
- detail ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fd-soon-detail", children: detail }) : null,
11009
- backend ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { className: "fd-soon-backend", children: [
11010
- /* @__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" }),
11011
11045
  " ",
11012
11046
  backend
11013
11047
  ] }) : null,
11014
- eta || effort || onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { className: "fd-soon-meta", children: [
11015
- eta ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { children: [
11016
- /* @__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" }),
11017
11051
  " ",
11018
11052
  eta
11019
11053
  ] }) : null,
11020
- effort ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { children: [
11021
- /* @__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" }),
11022
11056
  " ",
11023
11057
  effort
11024
11058
  ] }) : null,
11025
- 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: [
11026
11060
  "See the roadmap ",
11027
- /* @__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" })
11028
11062
  ] }) : null
11029
11063
  ] }) : null,
11030
- allowed ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("button", { type: "button", className: "fd-soon-view", onClick: onBypass, children: [
11031
- /* @__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" }),
11032
11066
  " View and use it anyway"
11033
11067
  ] }) : null
11034
11068
  ] });
11035
11069
  }
11036
11070
  function useHoverCard(open2) {
11037
- const anchor = React59.useRef(null);
11038
- const [pos, setPos] = React59.useState(null);
11039
- React59.useLayoutEffect(() => {
11071
+ const anchor = React60.useRef(null);
11072
+ const [pos, setPos] = React60.useState(null);
11073
+ React60.useLayoutEffect(() => {
11040
11074
  if (!open2 || !anchor.current) {
11041
11075
  setPos(null);
11042
11076
  return;
@@ -11088,9 +11122,9 @@ function ComingSoon({
11088
11122
  const tip = [label, detail, backend ? "Needs " + backend : null, eta ? "ETA " + eta : null, effort].filter(Boolean).join(" \xB7 ");
11089
11123
  if (inline) {
11090
11124
  if (allowed && bypassed) {
11091
- 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: [
11092
11126
  children,
11093
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
11127
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
11094
11128
  "button",
11095
11129
  {
11096
11130
  type: "button",
@@ -11098,12 +11132,12 @@ function ComingSoon({
11098
11132
  title: "Unwired \u2014 writes go to the simulated backend. " + tip + " Click to re-blur.",
11099
11133
  onClick: () => setBypassed(false),
11100
11134
  "aria-label": "Re-blur this unwired feature",
11101
- 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" })
11102
11136
  }
11103
11137
  )
11104
11138
  ] });
11105
11139
  }
11106
- return /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
11140
+ return /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
11107
11141
  InlineSoon,
11108
11142
  {
11109
11143
  label,
@@ -11123,20 +11157,20 @@ function ComingSoon({
11123
11157
  );
11124
11158
  }
11125
11159
  if (allowed && bypassed) {
11126
- return /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, ...rest, children: [
11127
- /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fd-soon-bar", role: "status", children: [
11128
- /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { className: "fd-soon-badge", children: [
11129
- /* @__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" }),
11130
11164
  "Unwired feature \u2014 you are using it anyway"
11131
11165
  ] }),
11132
- /* @__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." }),
11133
- /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { className: "fd-soon-bar-actions", children: [
11134
- 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: [
11135
11169
  "Roadmap ",
11136
- /* @__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" })
11137
11171
  ] }) : null,
11138
- /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => setBypassed(false), children: [
11139
- /* @__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" }),
11140
11174
  " Re-blur"
11141
11175
  ] })
11142
11176
  ] })
@@ -11144,10 +11178,10 @@ function ComingSoon({
11144
11178
  children
11145
11179
  ] });
11146
11180
  }
11147
- return /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: ["fd-soon", className].filter(Boolean).join(" "), style: minHeight ? { minHeight } : void 0, ...rest, children: [
11148
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: "fd-soon-under", style: { filter: "blur(" + blur + "px) saturate(.62)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
11149
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: "fd-soon-veil" }),
11150
- /* @__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)(
11151
11185
  SoonCard,
11152
11186
  {
11153
11187
  label,
@@ -11163,12 +11197,12 @@ function ComingSoon({
11163
11197
  ] });
11164
11198
  }
11165
11199
  function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass, blur, tip, className, rest, children }) {
11166
- const [open2, setOpen] = React59.useState(false);
11200
+ const [open2, setOpen] = React60.useState(false);
11167
11201
  const [anchor, pos] = useHoverCard(open2);
11168
- const hoverCardRef = React59.useRef(null);
11202
+ const hoverCardRef = React60.useRef(null);
11169
11203
  const hoverLayer = useStackedLayer({ active: open2, containerRef: hoverCardRef, returnFocus: false });
11170
11204
  const zIndex = useLayerZIndex(hoverLayer);
11171
- const close2 = React59.useRef(null);
11205
+ const close2 = React60.useRef(null);
11172
11206
  const show = () => {
11173
11207
  if (close2.current) {
11174
11208
  clearTimeout(close2.current);
@@ -11184,10 +11218,10 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
11184
11218
  setOpen(false);
11185
11219
  }, 140);
11186
11220
  };
11187
- React59.useEffect(() => () => {
11221
+ React60.useEffect(() => () => {
11188
11222
  if (close2.current) clearTimeout(close2.current);
11189
11223
  }, []);
11190
- return /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)(
11224
+ return /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(
11191
11225
  "span",
11192
11226
  {
11193
11227
  ref: anchor,
@@ -11198,8 +11232,8 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
11198
11232
  onBlur: hide,
11199
11233
  ...rest,
11200
11234
  children: [
11201
- /* @__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 }),
11202
- /* @__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)(
11203
11237
  "button",
11204
11238
  {
11205
11239
  type: "button",
@@ -11210,11 +11244,11 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
11210
11244
  onFocus: show,
11211
11245
  onBlur: hide,
11212
11246
  onClick: () => open2 ? setOpen(false) : show(),
11213
- 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" })
11214
11248
  }
11215
11249
  ),
11216
11250
  open2 && pos ? (0, import_react_dom7.createPortal)(
11217
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
11251
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
11218
11252
  "div",
11219
11253
  {
11220
11254
  ref: hoverCardRef,
@@ -11223,7 +11257,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
11223
11257
  style: { position: "fixed", left: pos.left, top: pos.top, bottom: pos.bottom, width: pos.width, zIndex },
11224
11258
  onMouseEnter: show,
11225
11259
  onMouseLeave: hide,
11226
- children: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
11260
+ children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
11227
11261
  SoonCard,
11228
11262
  {
11229
11263
  label,
@@ -11253,10 +11287,10 @@ function formatEta(iso2) {
11253
11287
  var FormatEta = formatEta;
11254
11288
 
11255
11289
  // src/components/platform/Gate.tsx
11256
- var import_jsx_runtime84 = require("react/jsx-runtime");
11290
+ var import_jsx_runtime85 = require("react/jsx-runtime");
11257
11291
  function PermissionDenied({ permission, title, detail, compact: compact3 = false, className = "", ...rest }) {
11258
11292
  const need = Array.isArray(permission) ? permission : [permission].filter(Boolean);
11259
- return /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(
11293
+ return /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)(
11260
11294
  "div",
11261
11295
  {
11262
11296
  className: ["fd-stack", className].filter(Boolean).join(" "),
@@ -11272,14 +11306,14 @@ function PermissionDenied({ permission, title, detail, compact: compact3 = false
11272
11306
  },
11273
11307
  ...rest,
11274
11308
  children: [
11275
- /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("span", { className: "fd-row", style: { gap: 8 }, children: [
11276
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-lock-simple", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
11277
- /* @__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" })
11278
11312
  ] }),
11279
- /* @__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." }),
11280
- need.length ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: [
11281
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-overline fd-muted", children: "Requires" }),
11282
- 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: {
11283
11317
  fontSize: 11.5,
11284
11318
  padding: "2px 7px",
11285
11319
  borderRadius: 5,
@@ -11292,7 +11326,7 @@ function PermissionDenied({ permission, title, detail, compact: compact3 = false
11292
11326
  );
11293
11327
  }
11294
11328
  function GatePending({ compact: compact3 = false, className = "" }) {
11295
- return /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(
11329
+ return /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)(
11296
11330
  "div",
11297
11331
  {
11298
11332
  className: ["fd-stack", className].filter(Boolean).join(" "),
@@ -11308,11 +11342,11 @@ function GatePending({ compact: compact3 = false, className = "" }) {
11308
11342
  textAlign: "left"
11309
11343
  },
11310
11344
  children: [
11311
- /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("span", { className: "fd-row", style: { gap: 8 }, children: [
11312
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-arrows-clockwise", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
11313
- /* @__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" })
11314
11348
  ] }),
11315
- /* @__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." })
11316
11350
  ]
11317
11351
  }
11318
11352
  );
@@ -11322,7 +11356,7 @@ function Gate({ perm, anyOf, role, silent = false, fallback, pendingFallback, co
11322
11356
  if (pending) {
11323
11357
  if (pendingFallback !== void 0) return pendingFallback;
11324
11358
  if (silent) return null;
11325
- return /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(GatePending, { compact: compact3 });
11359
+ return /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(GatePending, { compact: compact3 });
11326
11360
  }
11327
11361
  let ok = true;
11328
11362
  if (perm) ok = ok && can2(perm);
@@ -11331,7 +11365,7 @@ function Gate({ perm, anyOf, role, silent = false, fallback, pendingFallback, co
11331
11365
  if (ok) return children;
11332
11366
  if (fallback !== void 0) return fallback;
11333
11367
  if (silent) return null;
11334
- 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 });
11335
11369
  }
11336
11370
  function FeatureGate({
11337
11371
  flag,
@@ -11354,7 +11388,7 @@ function FeatureGate({
11354
11388
  const f = SessionKit.findFlag(flag) || {};
11355
11389
  const missing = rt.missing || [];
11356
11390
  const canBypass = pending ? false : bypassPerm === null ? false : !bypassPerm || can2(bypassPerm);
11357
- return /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
11391
+ return /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
11358
11392
  ComingSoon,
11359
11393
  {
11360
11394
  label: label || (variant === "inline" ? f.label || "Not wired yet" : "Designed \u2014 backend not wired yet"),
@@ -11375,22 +11409,22 @@ function FeatureGate({
11375
11409
  function PermissionHint({ perm, children }) {
11376
11410
  const { can: can2, pending } = useSessionContext();
11377
11411
  if (pending) {
11378
- 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 }) });
11379
11413
  }
11380
11414
  if (can2(perm)) return children;
11381
- return /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
11415
+ return /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
11382
11416
  "span",
11383
11417
  {
11384
11418
  title: "Requires " + (Array.isArray(perm) ? perm.join(", ") : perm),
11385
11419
  style: { display: "inline-flex", opacity: 0.45, cursor: "not-allowed" },
11386
11420
  "aria-disabled": "true",
11387
- 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 })
11388
11422
  }
11389
11423
  );
11390
11424
  }
11391
11425
 
11392
11426
  // src/components/platform/ModeSwitch.tsx
11393
- var import_jsx_runtime85 = require("react/jsx-runtime");
11427
+ var import_jsx_runtime86 = require("react/jsx-runtime");
11394
11428
  function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
11395
11429
  const mode2 = useRuntimeMode();
11396
11430
  const panel = useInlinePanel();
@@ -11402,8 +11436,8 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
11402
11436
  RuntimeKit.setMode(next);
11403
11437
  setOpen(false);
11404
11438
  };
11405
- return /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { style: { display: "inline-flex" }, ref, children: [
11406
- /* @__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)(
11407
11441
  "button",
11408
11442
  {
11409
11443
  type: "button",
@@ -11413,29 +11447,29 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
11413
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.",
11414
11448
  className: "fd-mode-btn" + (test ? " is-test" : "") + (open2 ? " is-open" : ""),
11415
11449
  children: [
11416
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), style: { fontSize: 17 } }),
11417
- 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
11418
11452
  ]
11419
11453
  }
11420
11454
  ),
11421
- /* @__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: [
11422
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
11423
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-badge " + (test ? "fd-badge-warning" : "fd-badge-neutral"), children: [
11424
- /* @__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" }),
11425
11459
  test ? "Test mode" : "Live mode"
11426
11460
  ] }),
11427
- 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: [
11428
11462
  requestCount,
11429
11463
  " simulated request",
11430
11464
  requestCount === 1 ? "" : "s"
11431
11465
  ] }) : null,
11432
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { style: { flex: 1 } }),
11433
- 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
11434
11468
  ] }),
11435
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { style: { display: "block", padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
11436
- /* @__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." }),
11437
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-row", style: { gap: 8, marginTop: 10, flexWrap: "wrap" }, children: [
11438
- /* @__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: [
11439
11473
  s.endpointsWired,
11440
11474
  " endpoint",
11441
11475
  s.endpointsWired === 1 ? "" : "s",
@@ -11445,58 +11479,58 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
11445
11479
  s.total,
11446
11480
  " features complete"
11447
11481
  ] }),
11448
- onOpenSpec ? /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)(import_jsx_runtime85.Fragment, { children: [
11449
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { style: { flex: 1 } }),
11450
- /* @__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: () => {
11451
11485
  setOpen(false);
11452
11486
  onOpenSpec();
11453
11487
  }, children: [
11454
11488
  "API spec ",
11455
- /* @__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" })
11456
11490
  ] })
11457
11491
  ] }) : null
11458
11492
  ] })
11459
11493
  ] }),
11460
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-mode-choice", children: [
11461
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("button", { type: "button", className: "fd-mode-opt" + (!test ? " is-on" : ""), onClick: () => go("live"), children: [
11462
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
11463
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-mode-opt-text", children: [
11464
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fd-mode-opt-title", children: "Live mode" }),
11465
- /* @__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" })
11466
11500
  ] }),
11467
- !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
11468
11502
  ] }),
11469
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("button", { type: "button", className: "fd-mode-opt" + (test ? " is-on" : ""), onClick: () => go("test"), children: [
11470
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("i", { className: "ph ph-flask", "aria-hidden": "true" }),
11471
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-mode-opt-text", children: [
11472
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fd-mode-opt-title", children: "Test mode" }),
11473
- /* @__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" })
11474
11508
  ] }),
11475
- 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
11476
11510
  ] })
11477
11511
  ] }),
11478
- 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
11479
11513
  ] })
11480
11514
  ] });
11481
11515
  }
11482
11516
  function TestModeBar({ onExit }) {
11483
11517
  const mode2 = useRuntimeMode();
11484
11518
  if (mode2 !== "test") return null;
11485
- return /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("div", { className: "fd-testbar", role: "status", children: [
11486
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-badge fd-badge-warning", children: [
11487
- /* @__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" }),
11488
11522
  "Test mode"
11489
11523
  ] }),
11490
- /* @__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." }),
11491
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => onExit ? onExit() : RuntimeKit.setMode("live"), children: [
11492
- /* @__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" }),
11493
11527
  " Back to live mode"
11494
11528
  ] })
11495
11529
  ] });
11496
11530
  }
11497
11531
 
11498
11532
  // src/components/planner/ChannelMeta.tsx
11499
- var import_jsx_runtime86 = require("react/jsx-runtime");
11533
+ var import_jsx_runtime87 = require("react/jsx-runtime");
11500
11534
  var CHANNEL_WEIGHTS = {
11501
11535
  "OOH": 50,
11502
11536
  "DOOH": 50,
@@ -11549,9 +11583,9 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
11549
11583
  const m = ChannelMeta(channel);
11550
11584
  const wt = channelWeightOf(channel || "");
11551
11585
  if (dot) {
11552
- 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 });
11553
11587
  }
11554
- return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
11588
+ return /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(
11555
11589
  "span",
11556
11590
  {
11557
11591
  className: ["fd-chan", size === "sm" ? "fd-chan-sm" : "", className].filter(Boolean).join(" "),
@@ -11559,16 +11593,16 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
11559
11593
  style: { "--chan": m.color },
11560
11594
  ...rest,
11561
11595
  children: [
11562
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }),
11563
- showLabel ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-chan-label", children: m.label }) : null,
11564
- 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
11565
11599
  ]
11566
11600
  }
11567
11601
  );
11568
11602
  }
11569
11603
 
11570
11604
  // src/components/planner/SaturationDistribution.tsx
11571
- var import_jsx_runtime87 = require("react/jsx-runtime");
11605
+ var import_jsx_runtime88 = require("react/jsx-runtime");
11572
11606
  var BANDS2 = [
11573
11607
  { key: "weak", label: "Weak", n: 1, range: "< 50" },
11574
11608
  { key: "adequate", label: "Adequate", n: 2, range: "50\u2013100" },
@@ -11579,24 +11613,24 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
11579
11613
  const grouped = BANDS2.map((b) => ({ ...b, items: campuses.filter((c) => c.band === b.key) }));
11580
11614
  const tallest = Math.max(1, ...grouped.map((g) => g.items.length));
11581
11615
  const floor = BANDS2.find((b) => b.key === floorBand) || BANDS2[0];
11582
- return /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
11583
- /* @__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) => {
11584
11618
  const mark = "var(--csi-" + g.n + "-mark)";
11585
11619
  const active = selectedBand === g.key;
11586
- return /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(
11620
+ return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)(
11587
11621
  "button",
11588
11622
  {
11589
11623
  type: "button",
11590
11624
  onClick: onSelectBand ? () => onSelectBand(active ? null : g.key) : void 0,
11591
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)" },
11592
11626
  children: [
11593
- /* @__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) => (
11594
11628
  // `overflow: hidden` + `white-space: nowrap` only clips once the span
11595
11629
  // actually HAS a bounded width to clip against (see the grid/flex
11596
11630
  // `minWidth: 0` chain above) — `textOverflow: ellipsis` then makes
11597
11631
  // that clip readable instead of a hard cut mid-letter; the full name
11598
11632
  // is still one hover away via `title`.
11599
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
11633
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
11600
11634
  "span",
11601
11635
  {
11602
11636
  title: c.name + " \xB7 " + c.crp,
@@ -11606,13 +11640,13 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
11606
11640
  c.name
11607
11641
  )
11608
11642
  )) }),
11609
- /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("span", { className: "fd-row", style: { gap: 8, alignItems: "baseline" }, children: [
11610
- /* @__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 }),
11611
- /* @__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)) })
11612
11646
  ] }),
11613
- /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("span", { className: "fd-stack", style: { gap: 1 }, children: [
11614
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-label-lg", children: g.label }),
11615
- /* @__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: [
11616
11650
  "CRP ",
11617
11651
  g.range
11618
11652
  ] })
@@ -11622,10 +11656,10 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
11622
11656
  g.key
11623
11657
  );
11624
11658
  }) }),
11625
- 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: [
11626
- /* @__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)) }),
11627
- /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("span", { className: "fd-body-sm fd-secondary", style: { flex: 1, minWidth: 240 }, children: [
11628
- /* @__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: [
11629
11663
  "Plan floor ",
11630
11664
  floorScore
11631
11665
  ] }),
@@ -11636,8 +11670,8 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
11636
11670
  }
11637
11671
 
11638
11672
  // src/components/planner/MixGap.tsx
11639
- var React60 = __toESM(require("react"), 1);
11640
- var import_jsx_runtime88 = require("react/jsx-runtime");
11673
+ var React61 = __toESM(require("react"), 1);
11674
+ var import_jsx_runtime89 = require("react/jsx-runtime");
11641
11675
  var MIX_GAP_LAYOUT = {
11642
11676
  trackHeight: 30,
11643
11677
  barHeight: 20,
@@ -11651,19 +11685,19 @@ function mixGapOffset(value, max) {
11651
11685
  }
11652
11686
  function MixGap({ rows = [], loading = false, className = "" }) {
11653
11687
  const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
11654
- const [hover, setHover] = React60.useState(null);
11688
+ const [hover, setHover] = React61.useState(null);
11655
11689
  const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
11656
11690
  const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
11657
11691
  const { trackHeight, barHeight, targetWidth, labelGap } = MIX_GAP_LAYOUT;
11658
11692
  const barTop = (trackHeight - barHeight) / 2;
11659
- return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 4 }, children: [
11660
- /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "fd-row", style: { gap: 16, justifyContent: "flex-end", paddingBottom: 6, flexWrap: "wrap" }, children: [
11661
- [["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: [
11662
- /* @__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 } }),
11663
11697
  l
11664
11698
  ] }, l)),
11665
- /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
11666
- /* @__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 } }),
11667
11701
  "Target"
11668
11702
  ] })
11669
11703
  ] }),
@@ -11672,7 +11706,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
11672
11706
  const tone = toneOf(gap);
11673
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 : "");
11674
11708
  const labelLeft = r.realized > r.target ? `calc(${mixGapOffset(r.realized, max)} + ${labelGap}px)` : `calc(${mixGapOffset(r.target, max)} + ${targetWidth / 2 + labelGap}px)`;
11675
- return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)(
11709
+ return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)(
11676
11710
  "div",
11677
11711
  {
11678
11712
  className: "fd-row",
@@ -11680,15 +11714,15 @@ function MixGap({ rows = [], loading = false, className = "" }) {
11680
11714
  onMouseEnter: () => setHover(r.channel),
11681
11715
  onMouseLeave: () => setHover(null),
11682
11716
  children: [
11683
- /* @__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" }) }),
11684
- /* @__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: [
11685
- /* @__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)" } }),
11686
- /* @__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 } }),
11687
- /* @__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: [
11688
11722
  r.realized,
11689
11723
  "%"
11690
11724
  ] }),
11691
- 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
11692
11726
  ] }) })
11693
11727
  ]
11694
11728
  },
@@ -11699,7 +11733,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
11699
11733
  }
11700
11734
 
11701
11735
  // src/components/planner/ChannelContribution.tsx
11702
- var import_jsx_runtime89 = require("react/jsx-runtime");
11736
+ var import_jsx_runtime90 = require("react/jsx-runtime");
11703
11737
  var money = (n) => "$" + Math.round(n).toLocaleString();
11704
11738
  function ChannelContribution({
11705
11739
  channels = [],
@@ -11715,9 +11749,9 @@ function ChannelContribution({
11715
11749
  const grand = total !== void 0 ? total : base + bonus;
11716
11750
  const pct = (v) => grand ? v / grand * 100 : 0;
11717
11751
  const spendTotal = channels.reduce((s, c) => s + Number(String(c.spend || 0).replace(/[^0-9.]/g, "")), 0);
11718
- return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
11719
- 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: [
11720
- 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)(
11721
11755
  "span",
11722
11756
  {
11723
11757
  title: c.name + " \xB7 " + c.crp.toFixed(1) + " CRP",
@@ -11726,7 +11760,7 @@ function ChannelContribution({
11726
11760
  },
11727
11761
  c.name
11728
11762
  )),
11729
- bonus > 0 ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(
11763
+ bonus > 0 ? /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
11730
11764
  "span",
11731
11765
  {
11732
11766
  title: "Surround-sound bonus +" + bonusPct + "%",
@@ -11735,18 +11769,18 @@ function ChannelContribution({
11735
11769
  }
11736
11770
  ) : null
11737
11771
  ] }),
11738
- showTable ? /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("table", { className: "fd-table", style: { fontSize: "var(--body-sm-size)" }, children: [
11739
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("tr", { children: [
11740
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("th", { style: { width: "34%" }, children: "Channel" }),
11741
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("th", { style: { width: "16%" }, children: "Weight" }),
11742
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("th", { className: "is-num", style: { width: "16%" }, children: "Spend" }),
11743
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("th", { className: "is-num", style: { width: "17%" }, children: "CRP" }),
11744
- /* @__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" })
11745
11779
  ] }) }),
11746
- /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("tbody", { children: [
11747
- channels.map((c) => /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("tr", { children: [
11748
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(ChannelTag, { channel: c.name, size: "sm" }) }),
11749
- /* @__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)(
11750
11784
  "span",
11751
11785
  {
11752
11786
  className: "fd-badge fd-badge-neutral",
@@ -11755,38 +11789,38 @@ function ChannelContribution({
11755
11789
  children: "weight " + (channelWeightOf(c.name) || 0)
11756
11790
  }
11757
11791
  ) }),
11758
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("td", { className: "is-num", children: c.spend }),
11759
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("td", { className: "is-num", children: c.crp.toFixed(1) }),
11760
- /* @__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: [
11761
11795
  pct(c.crp).toFixed(0),
11762
11796
  "%"
11763
11797
  ] })
11764
11798
  ] }, c.name)),
11765
- bonus > 0 ? /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("tr", { children: [
11766
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("span", { className: "fd-row", style: { gap: 9, fontWeight: 600 }, children: [
11767
- /* @__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" } }),
11768
11802
  "Surround-sound bonus"
11769
11803
  ] }) }),
11770
- /* @__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: [
11771
11805
  "+",
11772
11806
  bonusPct,
11773
11807
  "% of +",
11774
11808
  bonusMax,
11775
11809
  "%"
11776
11810
  ] }) }),
11777
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("td", { className: "is-num fd-muted", children: "\u2014" }),
11778
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("td", { className: "is-num", children: bonus.toFixed(1) }),
11779
- /* @__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: [
11780
11814
  pct(bonus).toFixed(0),
11781
11815
  "%"
11782
11816
  ] })
11783
11817
  ] }) : null,
11784
- /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("tr", { style: { background: "var(--surface-2)" }, children: [
11785
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("td", { style: { fontWeight: 700 }, children: "Campus total" }),
11786
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("td", {}),
11787
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: money(spendTotal) }),
11788
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: grand.toFixed(1) }),
11789
- /* @__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%" })
11790
11824
  ] })
11791
11825
  ] })
11792
11826
  ] }) : null
@@ -11794,8 +11828,8 @@ function ChannelContribution({
11794
11828
  }
11795
11829
 
11796
11830
  // src/components/planner/BudgetReallocator.tsx
11797
- var React61 = __toESM(require("react"), 1);
11798
- var import_jsx_runtime90 = require("react/jsx-runtime");
11831
+ var React62 = __toESM(require("react"), 1);
11832
+ var import_jsx_runtime91 = require("react/jsx-runtime");
11799
11833
  var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
11800
11834
  function BudgetReallocator({
11801
11835
  campus,
@@ -11810,8 +11844,8 @@ function BudgetReallocator({
11810
11844
  onCancel,
11811
11845
  className = ""
11812
11846
  }) {
11813
- const [draft, setDraft] = React61.useState(spend);
11814
- React61.useEffect(() => setDraft(spend), [spend]);
11847
+ const [draft, setDraft] = React62.useState(spend);
11848
+ React62.useEffect(() => setDraft(spend), [spend]);
11815
11849
  const dirty = draft !== spend;
11816
11850
  const nextCrp = scoreFor ? scoreFor(draft) : crp;
11817
11851
  const nextBand = bandFor(nextCrp);
@@ -11826,10 +11860,10 @@ function BudgetReallocator({
11826
11860
  setDraft(spend);
11827
11861
  if (onCancel) onCancel();
11828
11862
  };
11829
- const trackRef = React61.useRef(null);
11830
- const chipRef = React61.useRef(null);
11831
- const [chipLeft, setChipLeft] = React61.useState(null);
11832
- React61.useLayoutEffect(() => {
11863
+ const trackRef = React62.useRef(null);
11864
+ const chipRef = React62.useRef(null);
11865
+ const [chipLeft, setChipLeft] = React62.useState(null);
11866
+ React62.useLayoutEffect(() => {
11833
11867
  const track = trackRef.current;
11834
11868
  if (!dirty || !track) {
11835
11869
  setChipLeft(null);
@@ -11850,23 +11884,23 @@ function BudgetReallocator({
11850
11884
  ro.observe(track);
11851
11885
  return () => ro.disconnect();
11852
11886
  }, [dirty, pct]);
11853
- return /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)(
11887
+ return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(
11854
11888
  "div",
11855
11889
  {
11856
11890
  className: ["fd-stack", className].filter(Boolean).join(" "),
11857
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)" },
11858
11892
  children: [
11859
- /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
11860
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("span", { className: "fd-h4", style: { flex: 1, minWidth: 140 }, children: campus }),
11861
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(CsiBadge, { band: nowBand, crp, size: "medium" }),
11862
- dirty ? /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)(import_jsx_runtime90.Fragment, { children: [
11863
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("i", { className: "ph ph-arrow-right fd-muted", "aria-hidden": "true" }),
11864
- /* @__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 })
11865
11899
  ] }) : null
11866
11900
  ] }),
11867
- /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("div", { className: "fd-slider", ref: trackRef, children: [
11868
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
11869
- 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)(
11870
11904
  "span",
11871
11905
  {
11872
11906
  ref: chipRef,
@@ -11878,7 +11912,7 @@ function BudgetReallocator({
11878
11912
  children: (delta < 0 ? "\u2212$" : "+$") + Math.abs(delta).toLocaleString()
11879
11913
  }
11880
11914
  ) : null,
11881
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
11915
+ /* @__PURE__ */ (0, import_jsx_runtime91.jsx)(
11882
11916
  "input",
11883
11917
  {
11884
11918
  type: "range",
@@ -11894,13 +11928,13 @@ function BudgetReallocator({
11894
11928
  }
11895
11929
  )
11896
11930
  ] }),
11897
- /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
11898
- /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("span", { className: "fd-stack", style: { gap: 2, flex: 1, minWidth: 150 }, children: [
11899
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("span", { className: "fd-num", style: { fontSize: 19, fontWeight: 700 }, children: "$" + draft.toLocaleString() }),
11900
- /* @__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." })
11901
11935
  ] }),
11902
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("button", { type: "button", className: "fd-btn fd-btn-ghost", disabled: !dirty, onClick: revert, children: "Cancel" }),
11903
- /* @__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)(
11904
11938
  "button",
11905
11939
  {
11906
11940
  type: "button",
@@ -11919,7 +11953,7 @@ function BudgetReallocator({
11919
11953
  }
11920
11954
 
11921
11955
  // src/components/planner/SurroundSound.tsx
11922
- var import_jsx_runtime91 = require("react/jsx-runtime");
11956
+ var import_jsx_runtime92 = require("react/jsx-runtime");
11923
11957
  var CATEGORIES = [
11924
11958
  { key: "ooh", label: "OOH", icon: "flag-banner", color: "var(--ch-ooh)" },
11925
11959
  { key: "transit", label: "Transit", icon: "bus", color: "var(--ch-transit)" },
@@ -11931,26 +11965,26 @@ var CATEGORIES = [
11931
11965
  function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost, className = "" }) {
11932
11966
  const earned = Math.max(0, Math.min(1, bonusPct / bonusMax));
11933
11967
  const single = present.length <= 2;
11934
- return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, children: [
11935
- /* @__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) => {
11936
11970
  const on = present.includes(c.key);
11937
- return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(
11971
+ return /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)(
11938
11972
  "span",
11939
11973
  {
11940
11974
  title: c.label + (on ? " \u2014 present" : " \u2014 not bought"),
11941
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)" },
11942
11976
  children: [
11943
- /* @__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" }),
11944
- /* @__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 })
11945
11979
  ]
11946
11980
  },
11947
11981
  c.key
11948
11982
  );
11949
11983
  }) }),
11950
- /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("div", { className: "fd-stack", style: { gap: 8 }, children: [
11951
- /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
11952
- /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("span", { className: "fd-label-lg", children: "Surround-sound bonus earned" }),
11953
- /* @__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: [
11954
11988
  "+",
11955
11989
  bonusPct,
11956
11990
  "% of +",
@@ -11958,8 +11992,8 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
11958
11992
  "%"
11959
11993
  ] })
11960
11994
  ] }),
11961
- /* @__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)" } }) }),
11962
- /* @__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: [
11963
11997
  present.length,
11964
11998
  " of 6 channel categories present.",
11965
11999
  " ",
@@ -11971,7 +12005,7 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
11971
12005
  }
11972
12006
 
11973
12007
  // src/components/planner/Importance.tsx
11974
- var import_jsx_runtime92 = require("react/jsx-runtime");
12008
+ var import_jsx_runtime93 = require("react/jsx-runtime");
11975
12009
  var IMPORTANCE_LEVELS = [
11976
12010
  { id: "nudge", rank: 1, label: "Nudge", icon: "feather", description: "Breaks a tie, nothing more." },
11977
12011
  { id: "lean", rank: 2, label: "Lean", icon: "arrow-bend-up-right", description: "A mild preference between otherwise equal options." },
@@ -12001,7 +12035,7 @@ function importanceTokens(id) {
12001
12035
  function ImportanceTag({ level, showLabel = true, size = "sm", className = "", disabled = false }) {
12002
12036
  const lvl = importanceLevel(level);
12003
12037
  const t = importanceTokens(level);
12004
- return /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)(
12038
+ return /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)(
12005
12039
  "span",
12006
12040
  {
12007
12041
  className: ["fd-imp-tag", size === "md" ? "is-md" : "", disabled ? "is-disabled" : "", className].filter(Boolean).join(" "),
@@ -12009,16 +12043,16 @@ function ImportanceTag({ level, showLabel = true, size = "sm", className = "", d
12009
12043
  title: lvl.label + " \u2014 " + lvl.description,
12010
12044
  "aria-disabled": disabled ? "true" : void 0,
12011
12045
  children: [
12012
- /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("i", { className: "ph ph-" + lvl.icon, "aria-hidden": "true" }),
12013
- 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 })
12014
12048
  ]
12015
12049
  }
12016
12050
  );
12017
12051
  }
12018
12052
 
12019
12053
  // src/components/planner/PreferenceMeter.tsx
12020
- var React62 = __toESM(require("react"), 1);
12021
- var import_jsx_runtime93 = require("react/jsx-runtime");
12054
+ var React63 = __toESM(require("react"), 1);
12055
+ var import_jsx_runtime94 = require("react/jsx-runtime");
12022
12056
  function preferenceScore(criteria) {
12023
12057
  const earned = criteria.reduce((n, c) => n + (Number(c.earned) || 0), 0);
12024
12058
  const weight = criteria.reduce((n, c) => n + (Number(c.weight) || 0), 0);
@@ -12047,8 +12081,8 @@ function PreferenceMeter({
12047
12081
  className = ""
12048
12082
  }) {
12049
12083
  const value = score == null ? preferenceScore(criteria) : score;
12050
- const segments = React62.useMemo(() => preferenceSegments(criteria), [criteria]);
12051
- return /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(
12084
+ const segments = React63.useMemo(() => preferenceSegments(criteria), [criteria]);
12085
+ return /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(
12052
12086
  ScoreMeter,
12053
12087
  {
12054
12088
  score: value,
@@ -12060,22 +12094,22 @@ function PreferenceMeter({
12060
12094
  placement,
12061
12095
  className,
12062
12096
  breakdownLabel: breakdownTitle,
12063
- breakdown: /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)("div", { className: "fd-prefbreak", children: [
12064
- /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)("div", { className: "fd-prefbreak-head", children: [
12065
- /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("span", { className: "fd-label-lg", children: breakdownTitle }),
12066
- /* @__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) })
12067
12101
  ] }),
12068
- /* @__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) => {
12069
12103
  const pct = c.weight > 0 ? Math.round((Number(c.earned) || 0) / c.weight * 100) : 0;
12070
- return /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)("li", { className: pct === 0 ? "fd-prefbreak-item is-unmet" : "fd-prefbreak-item", children: [
12071
- /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(ImportanceTag, { level: c.importance }),
12072
- /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)("span", { className: "fd-prefbreak-text", children: [
12073
- /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("span", { className: "fd-prefbreak-label", children: c.label }),
12074
- 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
12075
12109
  ] }),
12076
- /* @__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: [
12077
12111
  Math.round(Number(c.earned) || 0),
12078
- /* @__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: "/" }),
12079
12113
  Math.round(c.weight)
12080
12114
  ] })
12081
12115
  ] }, c.id);
@@ -12086,10 +12120,10 @@ function PreferenceMeter({
12086
12120
  }
12087
12121
 
12088
12122
  // src/components/chat/AgentChatPanel.tsx
12089
- var React68 = __toESM(require("react"), 1);
12123
+ var React69 = __toESM(require("react"), 1);
12090
12124
 
12091
12125
  // src/components/chat/chatEngine.ts
12092
- var React63 = __toESM(require("react"), 1);
12126
+ var React64 = __toESM(require("react"), 1);
12093
12127
  var CHAT_UNAVAILABLE = "chat_unavailable";
12094
12128
  var JOB_PENDING = ["queued", "running"];
12095
12129
  var JOB_SUCCESS = ["completed", "recovered"];
@@ -12143,22 +12177,22 @@ function useChatEngine(opts) {
12143
12177
  onClear,
12144
12178
  onFeedback
12145
12179
  } = opts || {};
12146
- const [status, setStatus] = React63.useState("idle");
12147
- const [threadId, setThreadId] = React63.useState(null);
12148
- const [messages, setMessages] = React63.useState([]);
12149
- const [queue, setQueue] = React63.useState([]);
12150
- const [fatal, setFatal] = React63.useState(null);
12151
- const [busy, setBusy] = React63.useState(false);
12152
- const [turnStartedAt, setTurnStartedAt] = React63.useState(null);
12153
- const listRef = React63.useRef([]);
12154
- const queueRef = React63.useRef([]);
12155
- const busyRef = React63.useRef(false);
12156
- const stoppedRef = React63.useRef(false);
12157
- const abortRef = React63.useRef(null);
12158
- const serverCount = React63.useRef(0);
12159
- const threadRef = React63.useRef(null);
12160
- const mounted = React63.useRef(true);
12161
- 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(() => {
12162
12196
  mounted.current = true;
12163
12197
  return () => {
12164
12198
  mounted.current = false;
@@ -12180,14 +12214,14 @@ function useChatEngine(opts) {
12180
12214
  }
12181
12215
  return false;
12182
12216
  };
12183
- const loadThread = React63.useCallback(async (id) => {
12217
+ const loadThread = React64.useCallback(async (id) => {
12184
12218
  const data = await apiAdapter.getThread(id);
12185
12219
  const list = [...data && data.messages || []];
12186
12220
  serverCount.current = list.length;
12187
12221
  commit(list);
12188
12222
  return list;
12189
12223
  }, [apiAdapter]);
12190
- React63.useEffect(() => {
12224
+ React64.useEffect(() => {
12191
12225
  if (!apiAdapter) {
12192
12226
  setStatus("idle");
12193
12227
  setFatal(null);
@@ -12400,7 +12434,7 @@ function useChatEngine(opts) {
12400
12434
  await dispatchTurn(turn);
12401
12435
  }
12402
12436
  }
12403
- const send = React63.useCallback((text, attachments) => {
12437
+ const send = React64.useCallback((text, attachments) => {
12404
12438
  const body = (text || "").trim();
12405
12439
  if (!body && !(attachments && attachments.length)) return;
12406
12440
  if (status === "disconnected") return;
@@ -12410,7 +12444,7 @@ function useChatEngine(opts) {
12410
12444
  stoppedRef.current = false;
12411
12445
  drain();
12412
12446
  }, [status]);
12413
- const stop = React63.useCallback(() => {
12447
+ const stop = React64.useCallback(() => {
12414
12448
  stoppedRef.current = true;
12415
12449
  const ac = abortRef.current;
12416
12450
  if (ac) {
@@ -12429,11 +12463,11 @@ function useChatEngine(opts) {
12429
12463
  store.del(STORAGE_PREFIX + threadRef.current);
12430
12464
  }
12431
12465
  }, [apiAdapter]);
12432
- const removeQueued = React63.useCallback((id) => {
12466
+ const removeQueued = React64.useCallback((id) => {
12433
12467
  queueRef.current = queueRef.current.filter((t) => t.id !== id);
12434
12468
  setQueue(queueRef.current.slice());
12435
12469
  }, []);
12436
- const retry = React63.useCallback(() => {
12470
+ const retry = React64.useCallback(() => {
12437
12471
  const list = listRef.current;
12438
12472
  let at = -1;
12439
12473
  for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
@@ -12449,19 +12483,19 @@ function useChatEngine(opts) {
12449
12483
  setQueue(queueRef.current.slice());
12450
12484
  drain();
12451
12485
  }, []);
12452
- const clear = React63.useCallback(() => {
12486
+ const clear = React64.useCallback(() => {
12453
12487
  commit([]);
12454
12488
  serverCount.current = 0;
12455
12489
  queueRef.current = [];
12456
12490
  setQueue([]);
12457
12491
  onClear && onClear();
12458
12492
  }, [onClear]);
12459
- const setFeedback = React63.useCallback((id, value) => {
12493
+ const setFeedback = React64.useCallback((id, value) => {
12460
12494
  patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
12461
12495
  const msg = listRef.current.find((m) => m.id === id);
12462
12496
  onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
12463
12497
  }, [onFeedback]);
12464
- const reload = React63.useCallback(async () => {
12498
+ const reload = React64.useCallback(async () => {
12465
12499
  if (!threadRef.current) return;
12466
12500
  setStatus("loading");
12467
12501
  try {
@@ -12499,11 +12533,11 @@ var ChatKit = {
12499
12533
  };
12500
12534
 
12501
12535
  // src/components/chat/ChatTranscript.tsx
12502
- var React65 = __toESM(require("react"), 1);
12536
+ var React66 = __toESM(require("react"), 1);
12503
12537
 
12504
12538
  // src/components/chat/ChatTurn.tsx
12505
- var React64 = __toESM(require("react"), 1);
12506
- var import_jsx_runtime94 = require("react/jsx-runtime");
12539
+ var React65 = __toESM(require("react"), 1);
12540
+ var import_jsx_runtime95 = require("react/jsx-runtime");
12507
12541
  function JsonView({ value }) {
12508
12542
  let text;
12509
12543
  try {
@@ -12511,67 +12545,67 @@ function JsonView({ value }) {
12511
12545
  } catch (e) {
12512
12546
  text = String(value);
12513
12547
  }
12514
- 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 });
12515
12549
  }
12516
12550
  function PacketCard({ packet, schema, render, onApply, applied }) {
12517
12551
  if (!packet) return null;
12518
12552
  const s = schema || {};
12519
12553
  const invalid = packet.valid === false;
12520
12554
  const title = s.heading || packet.type;
12521
- return /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("section", { className: "fdc-packet" + (invalid ? " is-invalid" : ""), "aria-label": title, children: [
12522
- /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("header", { className: "fdc-packet-head", children: [
12523
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("i", { className: "ph ph-" + (s.icon || "package"), "aria-hidden": "true" }),
12524
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fdc-packet-title", title: truncationTitle(title), children: title }),
12525
- packet.repaired ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fdc-packet-badge", children: "Repaired" }) : null,
12526
- 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
12527
12561
  ] }),
12528
- invalid ? /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("div", { className: "fdc-packet-alert", role: "alert", children: [
12529
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
12530
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { children: packet.error || "This result failed validation and can\u2019t be applied." })
12531
- ] }) : /* @__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 }) }),
12532
- !invalid && onApply ? /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("footer", { className: "fdc-packet-foot", children: [
12533
- 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", {}),
12534
- /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", disabled: applied, onClick: () => onApply(packet), children: [
12535
- /* @__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" }),
12536
12570
  applied ? "Applied" : s.applyLabel || "Apply"
12537
12571
  ] })
12538
12572
  ] }) : null
12539
12573
  ] });
12540
12574
  }
12541
12575
  function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
12542
- const [open2, setOpen] = React64.useState(defaultOpen);
12576
+ const [open2, setOpen] = React65.useState(defaultOpen);
12543
12577
  if (!text) return null;
12544
- return /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("div", { className: "fdc-think" + (open2 ? " is-open" : ""), children: [
12545
- /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open2, children: [
12546
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("i", { className: "ph ph-brain", "aria-hidden": "true" }),
12547
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { children: streaming ? "Thinking" : durationMs ? "Thought for " + formatDuration(durationMs) : "Thought process" }),
12548
- streaming ? /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("span", { className: "fdc-dots", "aria-hidden": "true", children: [
12549
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", {}),
12550
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", {}),
12551
- /* @__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", {})
12552
12586
  ] }) : null,
12553
- /* @__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" })
12554
12588
  ] }),
12555
- 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
12556
12590
  ] });
12557
12591
  }
12558
12592
  function Citations({ items = [], onOpen }) {
12559
- const [open2, setOpen] = React64.useState(false);
12593
+ const [open2, setOpen] = React65.useState(false);
12560
12594
  if (!items.length) return null;
12561
- return /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("div", { className: "fdc-cites", children: [
12562
- /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open2, children: [
12563
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("i", { className: "ph ph-quotes", "aria-hidden": "true" }),
12564
- /* @__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: [
12565
12599
  items.length,
12566
12600
  " source",
12567
12601
  items.length === 1 ? "" : "s"
12568
12602
  ] }),
12569
- /* @__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" })
12570
12604
  ] }),
12571
- 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: [
12572
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fdc-cite-n fd-tabular", children: c.marker || i + 1 }),
12573
- 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" }),
12574
- 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
12575
12609
  ] }, c.id || i)) }) : null
12576
12610
  ] });
12577
12611
  }
@@ -12582,29 +12616,29 @@ function clampText(text, max) {
12582
12616
  return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
12583
12617
  }
12584
12618
  function MessageBody({ message: m, ctx }) {
12585
- const [expanded, setExpanded] = React64.useState(false);
12619
+ const [expanded, setExpanded] = React65.useState(false);
12586
12620
  const isUser = m.role === "user";
12587
12621
  const raw = m.text || "";
12588
12622
  const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
12589
12623
  const body = clamped != null ? clamped : raw;
12590
12624
  const showMd = ctx.markdown && !isUser;
12591
- return /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("div", { className: "fdc-body", children: [
12592
- m.thinking && ctx.showThinking ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(ThinkingBlock, { text: m.thinking, durationMs: m.thinkingMs, streaming: m.streaming && !m.text }) : null,
12593
- 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,
12594
- body ? /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("div", { className: "fdc-text" + (isUser ? " is-user" : ""), children: [
12595
- 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 }),
12596
- 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
12597
12631
  ] }) : null,
12598
- clamped != null ? /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(true), children: [
12599
- /* @__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" }),
12600
12634
  "Show more",
12601
- /* @__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" })
12602
- ] }) : expanded && ctx.maxVisibleChars && raw.length > ctx.maxVisibleChars ? /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(false), children: [
12603
- /* @__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" }),
12604
12638
  "Show less"
12605
12639
  ] }) : null,
12606
- 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,
12607
- 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)(
12608
12642
  PacketCard,
12609
12643
  {
12610
12644
  packet: m.packet,
@@ -12614,35 +12648,35 @@ function MessageBody({ message: m, ctx }) {
12614
12648
  applied: ctx.appliedPackets && ctx.appliedPackets[m.id]
12615
12649
  }
12616
12650
  ) : null,
12617
- m.citations && m.citations.length ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(Citations, { items: m.citations, onOpen: ctx.onOpenCitation }) : null,
12618
- m.working ? /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("div", { className: "fdc-working", role: "status", children: [
12619
- /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("span", { className: "fdc-dots", "aria-hidden": "true", children: [
12620
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", {}),
12621
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", {}),
12622
- /* @__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", {})
12623
12657
  ] }),
12624
- /* @__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: [
12625
12659
  m.resumed ? "Resuming" : "Working",
12626
- 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: [
12627
12661
  " \xB7 ",
12628
12662
  m.job.status
12629
12663
  ] }) : null,
12630
- 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: [
12631
12665
  " \xB7 ",
12632
12666
  m.job.detail
12633
12667
  ] }) : null
12634
12668
  ] }),
12635
- 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
12636
12670
  ] }) : null,
12637
- m.stopped ? /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("div", { className: "fdc-stopped", children: [
12638
- /* @__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" }),
12639
12673
  "Stopped"
12640
12674
  ] }) : null,
12641
- m.error ? /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("div", { className: "fdc-error", role: "alert", children: [
12642
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
12643
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fdc-error-text", children: ctx.errorCopy ? ctx.errorCopy(m.error) : m.error }),
12644
- m.retryable && ctx.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("button", { type: "button", className: "fdc-error-retry", onClick: ctx.onRetry, children: [
12645
- /* @__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" }),
12646
12680
  "Retry"
12647
12681
  ] }) : null
12648
12682
  ] }) : null
@@ -12655,16 +12689,16 @@ function RunActions({ group, ctx }) {
12655
12689
  const isAssistant = group.role === "assistant";
12656
12690
  const fb = last.feedback;
12657
12691
  if (!ctx.messageActions) return null;
12658
- return /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("div", { className: "fdc-actions", role: "group", "aria-label": "Message actions", children: [
12659
- /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("button", { type: "button", className: "fdc-act" + (copied ? " is-done" : ""), onClick: () => copy(markdownToText(text)), "aria-label": "Copy message", children: [
12660
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("i", { className: "ph ph-" + (copied ? "check" : "copy"), "aria-hidden": "true" }),
12661
- /* @__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" })
12662
12696
  ] }),
12663
- 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,
12664
- 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,
12665
- isAssistant && ctx.onFeedback ? /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)(React64.Fragment, { children: [
12666
- /* @__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" }) }),
12667
- /* @__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" }) })
12668
12702
  ] }) : null,
12669
12703
  ctx.extraActions ? ctx.extraActions(group) : null
12670
12704
  ] });
@@ -12674,22 +12708,22 @@ function ChatTurn({ group, ctx }) {
12674
12708
  const name = isUser ? ctx.userName : group.author || ctx.assistantName;
12675
12709
  const avatar = isUser ? ctx.userAvatar : ctx.assistantAvatar;
12676
12710
  const stamp = group.messages[0].timestamp;
12677
- return /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("article", { className: "fdc-turn is-" + group.role, "aria-label": String(name) + (stamp ? " at " + formatClock(stamp) : ""), children: [
12678
- /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("div", { className: "fdc-turn-head", children: [
12679
- 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,
12680
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fdc-who", children: name }),
12681
- stamp ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(RelativeTime, { className: "fdc-when", value: stamp }) : null,
12682
- 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
12683
12717
  ] }),
12684
- /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("div", { className: "fdc-turn-body", children: [
12685
- 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)),
12686
- /* @__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 })
12687
12721
  ] })
12688
12722
  ] });
12689
12723
  }
12690
12724
 
12691
12725
  // src/components/chat/ChatTranscript.tsx
12692
- var import_jsx_runtime95 = require("react/jsx-runtime");
12726
+ var import_jsx_runtime96 = require("react/jsx-runtime");
12693
12727
  var GROUP_WINDOW = 6e4;
12694
12728
  var STICK_PX = 100;
12695
12729
  function groupMessages(list) {
@@ -12722,25 +12756,25 @@ function dayLabel(key) {
12722
12756
  }
12723
12757
  function Suggestions({ items = [], onPick }) {
12724
12758
  if (!items.length) return null;
12725
- 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) => {
12726
12760
  const it = typeof s === "string" ? { label: s, text: s } : s;
12727
- return /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("button", { type: "button", className: "fdc-suggest-item", onClick: () => onPick && onPick(it.text || it.label), children: [
12728
- it.icon ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-" + it.icon, "aria-hidden": "true" }) : null,
12729
- /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("span", { className: "fdc-suggest-text", children: [
12730
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-suggest-label", children: it.label }),
12731
- 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
12732
12766
  ] }),
12733
- /* @__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" })
12734
12768
  ] }, it.id || i);
12735
12769
  }) });
12736
12770
  }
12737
12771
  function LoadingTurns() {
12738
- 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: [
12739
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("div", { className: "fd-skel fd-skel-circle", style: { width: 22, height: 22 } }),
12740
- /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-skel-lines", children: [
12741
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("div", { className: "fd-skel", style: { width: i ? "62%" : "44%", height: 11 } }),
12742
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("div", { className: "fd-skel", style: { width: i ? "94%" : "78%", height: 11 } }),
12743
- /* @__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 } })
12744
12778
  ] })
12745
12779
  ] }, i)) });
12746
12780
  }
@@ -12757,10 +12791,10 @@ function ChatTranscript({
12757
12791
  renderEmpty,
12758
12792
  className = ""
12759
12793
  }) {
12760
- const scroller = React65.useRef(null);
12761
- const stick = React65.useRef(true);
12762
- const [pill, setPill] = React65.useState(0);
12763
- 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);
12764
12798
  const toBottom = (smooth) => {
12765
12799
  const el = scroller.current;
12766
12800
  if (!el) return;
@@ -12779,7 +12813,7 @@ function ChatTranscript({
12779
12813
  seen.current = messages.length;
12780
12814
  }
12781
12815
  };
12782
- React65.useLayoutEffect(() => {
12816
+ React66.useLayoutEffect(() => {
12783
12817
  const el = scroller.current;
12784
12818
  if (!el) return;
12785
12819
  if (stick.current) {
@@ -12787,7 +12821,7 @@ function ChatTranscript({
12787
12821
  seen.current = messages.length;
12788
12822
  } else setPill(Math.max(0, messages.length - seen.current));
12789
12823
  }, [messages]);
12790
- React65.useEffect(() => {
12824
+ React66.useEffect(() => {
12791
12825
  const el = scroller.current;
12792
12826
  const inner = el && el.firstChild;
12793
12827
  if (!el || !inner || typeof ResizeObserver === "undefined") return;
@@ -12797,38 +12831,38 @@ function ChatTranscript({
12797
12831
  ro.observe(inner);
12798
12832
  return () => ro.disconnect();
12799
12833
  }, []);
12800
- const groups = React65.useMemo(() => groupMessages(messages), [messages]);
12834
+ const groups = React66.useMemo(() => groupMessages(messages), [messages]);
12801
12835
  const empty = !messages.length && status === "ready";
12802
- return /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
12803
- /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
12804
- status === "loading" || status === "resolving" ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(LoadingTurns, {}) : null,
12805
- status === "disconnected" ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-dead", children: [
12806
- /* @__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" }) }),
12807
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("h3", { className: "fdc-dead-title", children: ctx.deadTitle || "The assistant isn\u2019t reachable" }),
12808
- /* @__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." }),
12809
- ctx.onReconnect ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("button", { type: "button", className: "fd-btn fd-btn-secondary fd-btn-sm", onClick: ctx.onReconnect, children: [
12810
- /* @__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" }),
12811
12845
  "Try again"
12812
12846
  ] }) : null
12813
12847
  ] }) : null,
12814
- empty ? renderEmpty ? renderEmpty() : /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-empty", children: [
12815
- /* @__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" }) }),
12816
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("h3", { className: "fdc-empty-title", children: emptyTitle }),
12817
- emptyDescription ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("p", { className: "fdc-empty-body", children: emptyDescription }) : null,
12818
- /* @__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 })
12819
12853
  ] }) : null,
12820
12854
  groups.map((g, i) => {
12821
12855
  const prev = groups[i - 1];
12822
12856
  const k = dayKey(g.messages[0].timestamp);
12823
12857
  const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
12824
- return /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)(React65.Fragment, { children: [
12825
- showDay ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("div", { className: "fdc-day", children: /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { children: dayLabel(k) }) }) : null,
12826
- /* @__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 })
12827
12861
  ] }, g.key || i);
12828
12862
  })
12829
12863
  ] }),
12830
- pill ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("button", { type: "button", className: "fdc-pill", onClick: () => toBottom(true), children: [
12831
- /* @__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" }),
12832
12866
  pill,
12833
12867
  " new message",
12834
12868
  pill === 1 ? "" : "s"
@@ -12838,8 +12872,8 @@ function ChatTranscript({
12838
12872
  var TranscriptKit = { groupMessages };
12839
12873
 
12840
12874
  // src/components/chat/ChatComposer.tsx
12841
- var React66 = __toESM(require("react"), 1);
12842
- var import_jsx_runtime96 = require("react/jsx-runtime");
12875
+ var React67 = __toESM(require("react"), 1);
12876
+ var import_jsx_runtime97 = require("react/jsx-runtime");
12843
12877
  function ChatComposer({
12844
12878
  onSubmit,
12845
12879
  onStop,
@@ -12866,17 +12900,17 @@ function ChatComposer({
12866
12900
  onReject,
12867
12901
  onOpenAttachment
12868
12902
  }) {
12869
- const [text, setText] = React66.useState(draft || "");
12870
- const [trigger, setTrigger] = React66.useState(null);
12871
- const [mentionItems, setMentionItems] = React66.useState([]);
12872
- const [listening, setListening] = React66.useState(false);
12873
- const [notice, setNotice] = React66.useState(null);
12874
- const editor = React66.useRef(null);
12875
- const wrap = React66.useRef(null);
12876
- 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);
12877
12911
  const staged = useStagedFiles(fileUploadHandler, { onError: () => {
12878
12912
  } });
12879
- React66.useEffect(() => {
12913
+ React67.useEffect(() => {
12880
12914
  if (draft != null && draft !== text) setText(draft);
12881
12915
  }, [draft]);
12882
12916
  const change = (v) => {
@@ -12912,7 +12946,7 @@ function ChatComposer({
12912
12946
  e.preventDefault();
12913
12947
  staged.add(found.files);
12914
12948
  };
12915
- React66.useEffect(() => {
12949
+ React67.useEffect(() => {
12916
12950
  if (!trigger || trigger.type !== "mention" || !mentionSources) {
12917
12951
  setMentionItems([]);
12918
12952
  return;
@@ -12930,7 +12964,7 @@ function ChatComposer({
12930
12964
  const q = (trigger.query || "").toLowerCase();
12931
12965
  setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
12932
12966
  }, [trigger, mentionSources]);
12933
- const slashItems = React66.useMemo(() => {
12967
+ const slashItems = React67.useMemo(() => {
12934
12968
  if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
12935
12969
  const q = (trigger.query || "").toLowerCase();
12936
12970
  return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
@@ -12944,7 +12978,7 @@ function ChatComposer({
12944
12978
  description: it.description,
12945
12979
  icon: it.icon,
12946
12980
  meta: mention.meta,
12947
- 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,
12948
12982
  onSelect: () => {
12949
12983
  const insert = trigger.type === "slash" ? slash.immediate ? "/" + slash.id : "/" + slash.id + " " : "@" + (mention.value || mention.label) + " ";
12950
12984
  editor.current && editor.current.replaceRange(trigger.from, trigger.to, insert);
@@ -13003,14 +13037,14 @@ function ChatComposer({
13003
13037
  stopVoice.current = typeof res === "function" ? res : () => {
13004
13038
  };
13005
13039
  };
13006
- return /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("div", { className: "fdc-composer" + (disabled ? " is-disabled" : "") + (narrow ? " is-narrow" : ""), children: [
13007
- 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: [
13008
- /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("i", { className: "ph ph-clock-countdown", "aria-hidden": "true" }),
13009
- /* @__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)" : "") }),
13010
- 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
13011
13045
  ] }, q.id)) }) : null,
13012
13046
  sessionBar,
13013
- /* @__PURE__ */ (0, import_jsx_runtime96.jsx)(
13047
+ /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
13014
13048
  Dropzone,
13015
13049
  {
13016
13050
  className: "fdc-field",
@@ -13024,9 +13058,9 @@ function ChatComposer({
13024
13058
  disabled: !fileUploadHandler || disabled,
13025
13059
  label: "Drop to attach",
13026
13060
  hint: acceptFiles ? acceptFiles.replace(/,/g, " \xB7 ") : void 0,
13027
- children: /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("div", { ref: wrap, className: "fdc-field-inner", children: [
13028
- 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,
13029
- /* @__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)(
13030
13064
  MarkdownEditor,
13031
13065
  {
13032
13066
  ref: editor,
@@ -13045,33 +13079,33 @@ function ChatComposer({
13045
13079
  ariaLabel: "Message"
13046
13080
  }
13047
13081
  ),
13048
- /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("div", { className: "fdc-tools", children: [
13049
- 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,
13050
- 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,
13051
13085
  toolbarExtras,
13052
- /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("span", { className: "fdc-tools-gap" }),
13053
- 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: [
13054
13088
  text.length,
13055
13089
  "/",
13056
13090
  maxLength
13057
13091
  ] }) : null,
13058
- busy ? /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("button", { type: "button", className: "fdc-stop", onClick: onStop, "aria-label": "Stop generating", children: [
13059
- /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
13060
- /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("span", { children: "Stop" })
13061
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("button", { type: "button", className: "fdc-send", onClick: submit, disabled: !canSend, "aria-label": "Send message", children: [
13062
- /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("i", { className: "ph ph-paper-plane-right", "aria-hidden": "true" }),
13063
- /* @__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" })
13064
13098
  ] })
13065
13099
  ] })
13066
13100
  ] })
13067
13101
  }
13068
13102
  ),
13069
- notice ? /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("div", { className: "fdc-notice", role: "status", children: [
13070
- /* @__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" }),
13071
13105
  notice
13072
13106
  ] }) : null,
13073
- hint && !notice ? /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("div", { className: "fdc-hint", children: hint }) : null,
13074
- /* @__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)(
13075
13109
  Popover,
13076
13110
  {
13077
13111
  open: menuOpen,
@@ -13085,12 +13119,12 @@ function ChatComposer({
13085
13119
  returnFocus: false,
13086
13120
  closeOnOutside: true,
13087
13121
  label: trigger && trigger.type === "slash" ? "Commands" : "Mentions",
13088
- children: /* @__PURE__ */ (0, import_jsx_runtime96.jsx)(
13122
+ children: /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
13089
13123
  Menu,
13090
13124
  {
13091
13125
  items: menuItems,
13092
13126
  autoFocus: false,
13093
- 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" }),
13094
13128
  onClose: () => setTrigger(null)
13095
13129
  }
13096
13130
  )
@@ -13100,12 +13134,12 @@ function ChatComposer({
13100
13134
  }
13101
13135
 
13102
13136
  // src/components/chat/ChatSessionBar.tsx
13103
- var React67 = __toESM(require("react"), 1);
13104
- var import_jsx_runtime97 = require("react/jsx-runtime");
13137
+ var React68 = __toESM(require("react"), 1);
13138
+ var import_jsx_runtime98 = require("react/jsx-runtime");
13105
13139
  var compact2 = meterFormats.compact;
13106
13140
  function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
13107
- const [open2, setOpen] = React67.useState(false);
13108
- const anchor = React67.useRef(null);
13141
+ const [open2, setOpen] = React68.useState(false);
13142
+ const anchor = React68.useRef(null);
13109
13143
  const stats = sessionStats || null;
13110
13144
  const cu = contextUsage || null;
13111
13145
  const limits = usageLimits || null;
@@ -13120,9 +13154,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
13120
13154
  if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
13121
13155
  if (cu) bits.push(pct + "% context");
13122
13156
  const expandable = !!(cu || limits);
13123
- return /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)(React67.Fragment, { children: [
13124
- /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("div", { className: "fdc-bar", children: [
13125
- /* @__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)(
13126
13160
  "button",
13127
13161
  {
13128
13162
  type: "button",
@@ -13133,15 +13167,15 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
13133
13167
  "aria-expanded": expandable ? open2 : void 0,
13134
13168
  "aria-label": expandable ? "Usage details" : void 0,
13135
13169
  children: [
13136
- 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,
13137
- /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("span", { className: "fdc-bar-text", title: truncationTitle(bits.join(" \xB7 ")), children: bits.join(" \xB7 ") }),
13138
- 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
13139
13173
  ]
13140
13174
  }
13141
13175
  ),
13142
13176
  extras
13143
13177
  ] }),
13144
- /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
13178
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
13145
13179
  Popover,
13146
13180
  {
13147
13181
  open: open2,
@@ -13152,15 +13186,15 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
13152
13186
  maxHeight: 460,
13153
13187
  padded: true,
13154
13188
  label: "Usage",
13155
- 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: () => {
13156
13190
  setOpen(false);
13157
13191
  onClear();
13158
13192
  }, children: [
13159
- /* @__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" }),
13160
13194
  "Clear conversation"
13161
13195
  ] }) : void 0,
13162
- children: /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("div", { className: "fdc-usage", children: [
13163
- 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)(
13164
13198
  SegmentedMeter,
13165
13199
  {
13166
13200
  total,
@@ -13172,9 +13206,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
13172
13206
  remainderLabel: "Free"
13173
13207
  }
13174
13208
  ) }) : null,
13175
- limits && limits.length ? /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("section", { className: "fdc-usage-sec", children: [
13176
- /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("h4", { className: "fdc-usage-h", children: "Usage limits" }),
13177
- /* @__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)(
13178
13212
  QuotaRow,
13179
13213
  {
13180
13214
  label: l.label,
@@ -13184,25 +13218,25 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
13184
13218
  l.id
13185
13219
  )) })
13186
13220
  ] }) : null,
13187
- stats ? /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("section", { className: "fdc-usage-sec fdc-usage-stats", children: [
13188
- stats.elapsedMs ? /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("div", { children: [
13189
- /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("span", { children: "Session" }),
13190
- /* @__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) })
13191
13225
  ] }) : null,
13192
- stats.tokens ? /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("div", { children: [
13193
- /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("span", { children: "Tokens" }),
13194
- /* @__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() })
13195
13229
  ] }) : null,
13196
- stats.costUsd != null ? /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("div", { children: [
13197
- /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("span", { children: "Cost" }),
13198
- /* @__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: [
13199
13233
  "$",
13200
13234
  Number(stats.costUsd).toFixed(3)
13201
13235
  ] })
13202
13236
  ] }) : null,
13203
- stats.turns ? /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("div", { children: [
13204
- /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("span", { children: "Turns" }),
13205
- /* @__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 })
13206
13240
  ] }) : null
13207
13241
  ] }) : null
13208
13242
  ] })
@@ -13241,7 +13275,7 @@ function ModelControls({
13241
13275
  disabled: m.disabled,
13242
13276
  checked: m.id === (current2 && current2.id),
13243
13277
  meta: m.meta,
13244
- 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,
13245
13279
  onSelect: () => onModelChange && onModelChange(m.id)
13246
13280
  });
13247
13281
  const items = [{ kind: "section", label: "Models" }].concat(flat.map(item));
@@ -13254,15 +13288,15 @@ function ModelControls({
13254
13288
  items.push({ kind: "section", label: "Fast mode" });
13255
13289
  items.push({
13256
13290
  kind: "custom",
13257
- render: () => /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("label", { className: "fdc-switchrow", children: [
13258
- /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("span", { children: fastModeLabel }),
13259
- /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("input", { type: "checkbox", className: "fd-sr", checked: !!fastMode, onChange: (e) => onFastModeChange(e.target.checked) }),
13260
- /* @__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" }) })
13261
13295
  ] })
13262
13296
  });
13263
13297
  }
13264
- return /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)(React67.Fragment, { children: [
13265
- /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
13298
+ return /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)(React68.Fragment, { children: [
13299
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
13266
13300
  MenuButton,
13267
13301
  {
13268
13302
  items,
@@ -13273,7 +13307,7 @@ function ModelControls({
13273
13307
  title: "Choose a model"
13274
13308
  }
13275
13309
  ),
13276
- effortLevels && effortLevels.length ? /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
13310
+ effortLevels && effortLevels.length ? /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
13277
13311
  MenuButton,
13278
13312
  {
13279
13313
  placement: "top-end",
@@ -13294,7 +13328,7 @@ function ModelControls({
13294
13328
  }
13295
13329
 
13296
13330
  // src/components/chat/AgentChatPanel.tsx
13297
- var import_jsx_runtime98 = require("react/jsx-runtime");
13331
+ var import_jsx_runtime99 = require("react/jsx-runtime");
13298
13332
  var SURFACES = { sidebar: "is-sidebar", inline: "is-inline", page: "is-page", modal: "is-modal", sheet: "is-sheet" };
13299
13333
  function AgentChatPanel({
13300
13334
  /* required */
@@ -13378,11 +13412,11 @@ function AgentChatPanel({
13378
13412
  onFeedback,
13379
13413
  onEditMessage
13380
13414
  }) {
13381
- const [panelWidth, setPanelWidth] = React68.useState(width);
13382
- const [applied, setApplied] = React68.useState({});
13383
- const [draft, setDraft] = React68.useState("");
13384
- const dragging = React68.useRef(null);
13385
- 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]);
13386
13420
  const engine = useChatEngine({
13387
13421
  contextType,
13388
13422
  contextId,
@@ -13448,7 +13482,7 @@ function AgentChatPanel({
13448
13482
  onReconnect: engine.reload,
13449
13483
  deadTitle: "The assistant isn\u2019t reachable"
13450
13484
  };
13451
- const sessionBar = /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
13485
+ const sessionBar = /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
13452
13486
  ChatSessionBar,
13453
13487
  {
13454
13488
  sessionStats,
@@ -13457,7 +13491,7 @@ function AgentChatPanel({
13457
13491
  onClear: engine.visible.length ? engine.clear : void 0
13458
13492
  }
13459
13493
  );
13460
- const modelControls = /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
13494
+ const modelControls = /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
13461
13495
  ModelControls,
13462
13496
  {
13463
13497
  models,
@@ -13472,7 +13506,7 @@ function AgentChatPanel({
13472
13506
  narrow
13473
13507
  }
13474
13508
  );
13475
- const threadMenu = threads && threads.length ? /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
13509
+ const threadMenu = threads && threads.length ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
13476
13510
  MenuButton,
13477
13511
  {
13478
13512
  variant: "ghost",
@@ -13499,7 +13533,7 @@ function AgentChatPanel({
13499
13533
  })))
13500
13534
  }
13501
13535
  ) : null;
13502
- return /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)(
13536
+ return /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)(
13503
13537
  "aside",
13504
13538
  {
13505
13539
  className: ["fdc-panel", SURFACES[surface] || SURFACES.sidebar, narrow ? "is-narrow" : "", className].filter(Boolean).join(" "),
@@ -13510,7 +13544,7 @@ function AgentChatPanel({
13510
13544
  },
13511
13545
  "aria-label": title,
13512
13546
  children: [
13513
- surface === "sidebar" && resizable ? /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
13547
+ surface === "sidebar" && resizable ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
13514
13548
  "div",
13515
13549
  {
13516
13550
  className: "fdc-grip",
@@ -13525,20 +13559,20 @@ function AgentChatPanel({
13525
13559
  }
13526
13560
  }
13527
13561
  ) : null,
13528
- showHeader ? /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("header", { className: "fdc-head", children: [
13529
- /* @__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 }) }),
13530
- /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("span", { className: "fdc-head-titles", children: [
13531
- /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("span", { className: "fdc-head-title", title: truncationTitle(title), children: title }),
13532
- 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
13533
13567
  ] }),
13534
- /* @__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: [
13535
13569
  headerActions,
13536
13570
  threadMenu,
13537
- 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,
13538
- 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
13539
13573
  ] })
13540
13574
  ] }) : null,
13541
- /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
13575
+ /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
13542
13576
  ChatTranscript,
13543
13577
  {
13544
13578
  messages: engine.visible,
@@ -13553,7 +13587,7 @@ function AgentChatPanel({
13553
13587
  renderEmpty
13554
13588
  }
13555
13589
  ),
13556
- /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
13590
+ /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
13557
13591
  ChatComposer,
13558
13592
  {
13559
13593
  onSubmit: (text, atts) => engine.send(text, atts),
@@ -13586,8 +13620,8 @@ function AgentChatPanel({
13586
13620
  }
13587
13621
 
13588
13622
  // src/components/files/FileViewer.tsx
13589
- var React69 = __toESM(require("react"), 1);
13590
- var import_jsx_runtime99 = require("react/jsx-runtime");
13623
+ var React70 = __toESM(require("react"), 1);
13624
+ var import_jsx_runtime100 = require("react/jsx-runtime");
13591
13625
  function previewKindOf(file) {
13592
13626
  const mime = (file.mime || "").toLowerCase();
13593
13627
  const ext = extensionOf(file.name || "");
@@ -13643,13 +13677,13 @@ function parseDelimited(text, delimiter) {
13643
13677
  return rows;
13644
13678
  }
13645
13679
  function usePreview(file, kind, resolveUrl) {
13646
- const [state, setState] = React69.useState({ status: "loading" });
13647
- const [attempt, setAttempt] = React69.useState(0);
13648
- const resolveRef = React69.useRef(resolveUrl);
13649
- 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(() => {
13650
13684
  resolveRef.current = resolveUrl;
13651
13685
  }, [resolveUrl]);
13652
- React69.useEffect(() => {
13686
+ React70.useEffect(() => {
13653
13687
  if (kind === "none") {
13654
13688
  setState({ status: "ready" });
13655
13689
  return;
@@ -13679,19 +13713,19 @@ function usePreview(file, kind, resolveUrl) {
13679
13713
  if (ac) ac.abort();
13680
13714
  };
13681
13715
  }, [file.id, kind, attempt]);
13682
- return { ...state, retry: React69.useCallback(() => setAttempt((a) => a + 1), []) };
13716
+ return { ...state, retry: React70.useCallback(() => setAttempt((a) => a + 1), []) };
13683
13717
  }
13684
13718
  function PreviewBody({ file, kind, state }) {
13685
- if (kind === "image") return /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("img", { className: "fd-fv-image", src: state.url, alt: file.name || "Preview" });
13686
- if (kind === "pdf") return /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("iframe", { className: "fd-fv-pdf", src: state.url, title: file.name || "PDF preview" });
13687
- 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 || "" });
13688
13722
  if (kind === "json") {
13689
13723
  let pretty = state.text || "";
13690
13724
  try {
13691
13725
  pretty = JSON.stringify(JSON.parse(pretty), null, 2);
13692
13726
  } catch {
13693
13727
  }
13694
- 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" });
13695
13729
  }
13696
13730
  if (kind === "csv") {
13697
13731
  const tsv = extensionOf(file.name || "") === "tsv" || (file.mime || "").toLowerCase().includes("tab-separated");
@@ -13699,12 +13733,12 @@ function PreviewBody({ file, kind, state }) {
13699
13733
  const head = rows[0] || [];
13700
13734
  const dataRows = rows.slice(1);
13701
13735
  const shown = dataRows.slice(0, FILE_VIEWER_CSV_ROW_LIMIT);
13702
- return /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("div", { className: "fd-fv-csv", children: [
13703
- /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("table", { className: "fd-fv-csv-table", children: [
13704
- /* @__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)) }) }),
13705
- /* @__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)) })
13706
13740
  ] }),
13707
- 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: [
13708
13742
  "Showing the first ",
13709
13743
  FILE_VIEWER_CSV_ROW_LIMIT.toLocaleString(),
13710
13744
  " of ",
@@ -13713,24 +13747,24 @@ function PreviewBody({ file, kind, state }) {
13713
13747
  ] }) : null
13714
13748
  ] });
13715
13749
  }
13716
- if (kind === "text") return /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(CodeBlock, { code: state.text || "", language: extensionOf(file.name || "") || void 0 });
13717
- return /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("div", { className: "fd-fv-fallback", children: [
13718
- /* @__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) }) }),
13719
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "fd-fv-fallback-title", children: "No preview available" }),
13720
- /* @__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: [
13721
13755
  file.mime || "Unknown type",
13722
13756
  file.size ? " \xB7 " + formatBytes(file.size) : ""
13723
13757
  ] })
13724
13758
  ] });
13725
13759
  }
13726
13760
  function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", onClose, actions, className = "" }) {
13727
- const kind = React69.useMemo(() => previewKindOf(file), [file]);
13761
+ const kind = React70.useMemo(() => previewKindOf(file), [file]);
13728
13762
  const preview = usePreview(file, kind, resolveUrl);
13729
- const [tab, setTab] = React69.useState("preview");
13730
- const [downloading, setDownloading] = React69.useState(false);
13731
- 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);
13732
13766
  const hasSide = sidePanel != null;
13733
- React69.useEffect(() => {
13767
+ React70.useEffect(() => {
13734
13768
  setTab("preview");
13735
13769
  }, [file.id]);
13736
13770
  const download = () => {
@@ -13746,29 +13780,29 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
13746
13780
  a.remove();
13747
13781
  }).catch((err) => setDownloadError(err && err.message || "Download failed.")).finally(() => setDownloading(false));
13748
13782
  };
13749
- return /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)(
13783
+ return /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)(
13750
13784
  "section",
13751
13785
  {
13752
13786
  className: ["fd-fv", hasSide && tab === "side" ? "is-tab-side" : "is-tab-preview", className].filter(Boolean).join(" "),
13753
13787
  "aria-label": file.name || "File",
13754
13788
  children: [
13755
- /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("header", { className: "fd-fv-head", children: [
13756
- /* @__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) }) }),
13757
- /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("span", { className: "fd-fv-head-titles", children: [
13758
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "fd-fv-head-title", title: file.name, children: file.name }),
13759
- /* @__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: [
13760
13794
  file.mime || "Unknown type",
13761
13795
  file.size ? " \xB7 " + formatBytes(file.size) : ""
13762
13796
  ] })
13763
13797
  ] }),
13764
- /* @__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: [
13765
13799
  actions,
13766
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(Button, { variant: "secondary", size: "sm", icon: "download-simple", loading: downloading, onClick: download, children: "Download" }),
13767
- 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
13768
13802
  ] })
13769
13803
  ] }),
13770
- downloadError ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("div", { className: "fd-fv-download-error", role: "alert", children: downloadError }) : null,
13771
- 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)(
13772
13806
  Tabs,
13773
13807
  {
13774
13808
  className: "fd-fv-tabs",
@@ -13777,19 +13811,19 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
13777
13811
  onChange: (v) => setTab(v)
13778
13812
  }
13779
13813
  ) : null,
13780
- /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("div", { className: "fd-fv-body", children: [
13781
- /* @__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)(
13782
13816
  LoadingRegion,
13783
13817
  {
13784
13818
  state: preview.status === "loading" ? "loading" : preview.status === "error" ? "error" : "ready",
13785
13819
  error: preview.error,
13786
13820
  label: "Loading preview of " + (file.name || "file"),
13787
13821
  onRetry: preview.status === "error" ? preview.retry : void 0,
13788
- skeleton: /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(Skeleton, { shape: "card", h: 220 }),
13789
- 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 })
13790
13824
  }
13791
13825
  ) }),
13792
- 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
13793
13827
  ] })
13794
13828
  ]
13795
13829
  }
@@ -13797,8 +13831,8 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
13797
13831
  }
13798
13832
 
13799
13833
  // src/components/files/FileBrowser.tsx
13800
- var React70 = __toESM(require("react"), 1);
13801
- var import_jsx_runtime100 = require("react/jsx-runtime");
13834
+ var React71 = __toESM(require("react"), 1);
13835
+ var import_jsx_runtime101 = require("react/jsx-runtime");
13802
13836
  function childrenOf(folders, parentId) {
13803
13837
  return folders.filter((f) => f.parentId === parentId).sort((a, b) => a.name.localeCompare(b.name));
13804
13838
  }
@@ -13870,8 +13904,8 @@ function FolderPickerMenu({
13870
13904
  }) {
13871
13905
  const panel = useInlinePanel();
13872
13906
  const { open: open2, setOpen, ref } = panel;
13873
- return /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("span", { className: "fd-fb-menu-anchor", ref, children: [
13874
- /* @__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)(
13875
13909
  IconButton,
13876
13910
  {
13877
13911
  icon: "arrows-out-cardinal",
@@ -13883,9 +13917,9 @@ function FolderPickerMenu({
13883
13917
  onClick: () => setOpen((v) => !v)
13884
13918
  }
13885
13919
  ),
13886
- /* @__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: [
13887
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "fd-overline fd-muted fd-fb-menu-title", children: "Move to\u2026" }),
13888
- 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)(
13889
13923
  "button",
13890
13924
  {
13891
13925
  type: "button",
@@ -13897,7 +13931,7 @@ function FolderPickerMenu({
13897
13931
  setOpen(false);
13898
13932
  },
13899
13933
  children: [
13900
- /* @__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" }),
13901
13935
  d.name
13902
13936
  ]
13903
13937
  },
@@ -13907,8 +13941,8 @@ function FolderPickerMenu({
13907
13941
  ] });
13908
13942
  }
13909
13943
  function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropPayload, actions, className = "" }) {
13910
- const [over, setOver] = React70.useState(false);
13911
- const dragCounter = React70.useRef(0);
13944
+ const [over, setOver] = React71.useState(false);
13945
+ const dragCounter = React71.useRef(0);
13912
13946
  const dropHandlers = isDropTarget ? {
13913
13947
  onDragEnter: (e) => {
13914
13948
  if (!hasInternalPayload(e)) return;
@@ -13933,8 +13967,8 @@ function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropP
13933
13967
  if (payload && onDropPayload) onDropPayload(payload);
13934
13968
  }
13935
13969
  } : {};
13936
- return /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: ["fd-fb-row", over ? "is-drop-target" : "", className].filter(Boolean).join(" "), ...dropHandlers, children: [
13937
- /* @__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)(
13938
13972
  "button",
13939
13973
  {
13940
13974
  type: "button",
@@ -13943,26 +13977,26 @@ function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropP
13943
13977
  draggable: !!draggableId,
13944
13978
  onDragStart: draggableId ? (e) => writeDragPayload(e, draggableId) : void 0,
13945
13979
  children: [
13946
- /* @__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 }) }),
13947
- /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("span", { className: "fd-fb-row-text", children: [
13948
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "fd-fb-row-name", title: name, children: name }),
13949
- 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
13950
13984
  ] })
13951
13985
  ]
13952
13986
  }
13953
13987
  ),
13954
- 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
13955
13989
  ] });
13956
13990
  }
13957
13991
  function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveInto, canMove }) {
13958
13992
  const kids = childrenOf(folders, folder.id);
13959
- const [expanded, setExpanded] = React70.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
13960
- React70.useEffect(() => {
13993
+ const [expanded, setExpanded] = React71.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
13994
+ React71.useEffect(() => {
13961
13995
  if (currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId)) setExpanded(true);
13962
13996
  }, [currentFolderId, folder.id, folders]);
13963
13997
  const isCurrent = folder.id === currentFolderId;
13964
- return /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: "fd-fb-tree-node", children: [
13965
- /* @__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)(
13966
14000
  RowShell,
13967
14001
  {
13968
14002
  icon: folder.id === currentFolderId ? "folder-open" : "folder-simple",
@@ -13972,7 +14006,7 @@ function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveI
13972
14006
  isDropTarget: canMove,
13973
14007
  onDropPayload: (payload) => onMoveInto(payload, folder.id),
13974
14008
  className: ["fd-fb-tree-row", isCurrent ? "is-current" : ""].filter(Boolean).join(" "),
13975
- actions: kids.length ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
14009
+ actions: kids.length ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
13976
14010
  IconButton,
13977
14011
  {
13978
14012
  icon: expanded ? "caret-down" : "caret-right",
@@ -13984,7 +14018,7 @@ function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveI
13984
14018
  ) : void 0
13985
14019
  }
13986
14020
  ),
13987
- 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)(
13988
14022
  TreeNode,
13989
14023
  {
13990
14024
  folder: k,
@@ -14023,15 +14057,15 @@ function FileBrowser({
14023
14057
  const canUpload = perm.canUpload !== false && !!onUpload;
14024
14058
  const canRemoveFile = perm.canRemoveFile !== false && !!onRemoveFile;
14025
14059
  const canDeleteFolder = perm.canDeleteFolder !== false && !!onDeleteFolder;
14026
- const [createOpen, setCreateOpen] = React70.useState(false);
14027
- const [createName, setCreateName] = React70.useState("");
14028
- const [renameTarget, setRenameTarget] = React70.useState(null);
14029
- const [renameValue, setRenameValue] = React70.useState("");
14030
- const [deleteTarget, setDeleteTarget] = React70.useState(null);
14031
- const uploadInputRef = React70.useRef(null);
14032
- const crumbFolders = React70.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
14033
- const subfolders = React70.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
14034
- 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(
14035
14069
  () => files.filter((f) => f.folderId === currentFolderId).sort((a, b) => a.name.localeCompare(b.name)),
14036
14070
  [files, currentFolderId]
14037
14071
  );
@@ -14070,10 +14104,10 @@ function FileBrowser({
14070
14104
  if (deleteTarget && onDeleteFolder) onDeleteFolder(deleteTarget);
14071
14105
  setDeleteTarget(null);
14072
14106
  };
14073
- const content = /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: ["fd-fb", className].filter(Boolean).join(" "), children: [
14074
- /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: "fd-fb-head", children: [
14075
- /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("nav", { className: "fd-fb-crumbs", "aria-label": "Folder path", children: [
14076
- /* @__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)(
14077
14111
  BreadcrumbCrumb,
14078
14112
  {
14079
14113
  label: "Home",
@@ -14083,7 +14117,7 @@ function FileBrowser({
14083
14117
  onDropPayload: (p) => moveIntoFolder(p, null)
14084
14118
  }
14085
14119
  ),
14086
- crumbFolders.map((f, i) => /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
14120
+ crumbFolders.map((f, i) => /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
14087
14121
  BreadcrumbCrumb,
14088
14122
  {
14089
14123
  label: f.name,
@@ -14095,11 +14129,11 @@ function FileBrowser({
14095
14129
  f.id
14096
14130
  ))
14097
14131
  ] }),
14098
- /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("span", { className: "fd-fb-actions", children: [
14099
- canCreateFolder ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Button, { variant: "secondary", size: "sm", icon: "folder-simple-plus", onClick: openCreate, children: "New folder" }) : null,
14100
- canUpload ? /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)(import_jsx_runtime100.Fragment, { children: [
14101
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Button, { variant: "secondary", size: "sm", icon: "upload-simple", onClick: () => uploadInputRef.current && uploadInputRef.current.click(), children: "Upload" }),
14102
- /* @__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)(
14103
14137
  "input",
14104
14138
  {
14105
14139
  ref: uploadInputRef,
@@ -14117,9 +14151,9 @@ function FileBrowser({
14117
14151
  ] }) : null
14118
14152
  ] })
14119
14153
  ] }),
14120
- /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: "fd-fb-body", children: [
14121
- /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: "fd-fb-tree", role: "region", "aria-label": "Folder tree", children: [
14122
- /* @__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)(
14123
14157
  RowShell,
14124
14158
  {
14125
14159
  icon: "house-simple",
@@ -14130,7 +14164,7 @@ function FileBrowser({
14130
14164
  className: ["fd-fb-tree-row", currentFolderId == null ? "is-current" : ""].filter(Boolean).join(" ")
14131
14165
  }
14132
14166
  ),
14133
- childrenOf(folders, null).map((f) => /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
14167
+ childrenOf(folders, null).map((f) => /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
14134
14168
  TreeNode,
14135
14169
  {
14136
14170
  folder: f,
@@ -14144,18 +14178,18 @@ function FileBrowser({
14144
14178
  f.id
14145
14179
  ))
14146
14180
  ] }),
14147
- /* @__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)(
14148
14182
  LoadingRegion,
14149
14183
  {
14150
14184
  state: loading ? "loading" : "ready",
14151
14185
  label: "Loading folder contents",
14152
- skeleton: /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: "fd-stack", style: { gap: 8, padding: 12 }, children: [
14153
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Skeleton, { h: 44, radius: "10px" }),
14154
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Skeleton, { h: 44, radius: "10px" }),
14155
- /* @__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" })
14156
14190
  ] }),
14157
- 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: [
14158
- 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)(
14159
14193
  RowShell,
14160
14194
  {
14161
14195
  icon: "folder-simple",
@@ -14164,9 +14198,9 @@ function FileBrowser({
14164
14198
  draggableId: canMove ? { kind: "folder", id: f.id } : void 0,
14165
14199
  isDropTarget: canMove,
14166
14200
  onDropPayload: (p) => moveIntoFolder(p, f.id),
14167
- actions: /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)(import_jsx_runtime100.Fragment, { children: [
14168
- canRenameFolder ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(IconButton, { icon: "pencil-simple", label: "Rename " + f.name, size: "sm", variant: "ghost", onClick: () => openRename(f) }) : null,
14169
- 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)(
14170
14204
  FolderPickerMenu,
14171
14205
  {
14172
14206
  label: "Move " + f.name,
@@ -14174,12 +14208,12 @@ function FileBrowser({
14174
14208
  onPick: (target) => moveIntoFolder({ kind: "folder", id: f.id }, target)
14175
14209
  }
14176
14210
  ) : null,
14177
- 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
14178
14212
  ] })
14179
14213
  },
14180
14214
  f.id
14181
14215
  )),
14182
- currentFiles.map((file) => /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
14216
+ currentFiles.map((file) => /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
14183
14217
  RowShell,
14184
14218
  {
14185
14219
  icon: iconForMime(file.mime, file.name),
@@ -14187,8 +14221,8 @@ function FileBrowser({
14187
14221
  meta: file.size ? formatBytes(file.size) : void 0,
14188
14222
  onOpen: onOpenFile ? () => onOpenFile(file) : void 0,
14189
14223
  draggableId: canMove ? { kind: "file", id: file.id } : void 0,
14190
- actions: /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)(import_jsx_runtime100.Fragment, { children: [
14191
- 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)(
14192
14226
  FolderPickerMenu,
14193
14227
  {
14194
14228
  label: "Move " + file.name,
@@ -14196,7 +14230,7 @@ function FileBrowser({
14196
14230
  onPick: (target) => onMoveFile && onMoveFile(file.id, target)
14197
14231
  }
14198
14232
  ) : null,
14199
- 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
14200
14234
  ] })
14201
14235
  },
14202
14236
  file.id
@@ -14205,10 +14239,10 @@ function FileBrowser({
14205
14239
  }
14206
14240
  ) })
14207
14241
  ] }),
14208
- /* @__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: [
14209
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Button, { variant: "secondary", onClick: () => setCreateOpen(false), children: "Cancel" }),
14210
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Button, { onClick: submitCreate, disabled: !createName.trim(), children: "Create" })
14211
- ] }), 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)(
14212
14246
  "input",
14213
14247
  {
14214
14248
  className: "fd-fb-input",
@@ -14222,10 +14256,10 @@ function FileBrowser({
14222
14256
  autoFocus: true
14223
14257
  }
14224
14258
  ) }),
14225
- /* @__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: [
14226
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Button, { variant: "secondary", onClick: () => setRenameTarget(null), children: "Cancel" }),
14227
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Button, { onClick: submitRename, disabled: !renameValue.trim(), children: "Save" })
14228
- ] }), 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)(
14229
14263
  "input",
14230
14264
  {
14231
14265
  className: "fd-fb-input",
@@ -14239,22 +14273,22 @@ function FileBrowser({
14239
14273
  autoFocus: true
14240
14274
  }
14241
14275
  ) }),
14242
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
14276
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
14243
14277
  Modal,
14244
14278
  {
14245
14279
  open: deleteTarget != null,
14246
14280
  title: deleteTarget ? "Delete \u201C" + deleteTarget.name + "\u201D?" : "Delete folder?",
14247
14281
  description: "This can't be undone. The folder must be empty.",
14248
14282
  onClose: () => setDeleteTarget(null),
14249
- footer: /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)(import_jsx_runtime100.Fragment, { children: [
14250
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Button, { variant: "secondary", onClick: () => setDeleteTarget(null), children: "Cancel" }),
14251
- /* @__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" })
14252
14286
  ] })
14253
14287
  }
14254
14288
  )
14255
14289
  ] });
14256
14290
  if (!canUpload) return content;
14257
- 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 });
14258
14292
  }
14259
14293
  function BreadcrumbCrumb({
14260
14294
  label,
@@ -14263,8 +14297,8 @@ function BreadcrumbCrumb({
14263
14297
  isDropTarget,
14264
14298
  onDropPayload
14265
14299
  }) {
14266
- const [over, setOver] = React70.useState(false);
14267
- const dragCounter = React70.useRef(0);
14300
+ const [over, setOver] = React71.useState(false);
14301
+ const dragCounter = React71.useRef(0);
14268
14302
  const dropHandlers = isDropTarget ? {
14269
14303
  onDragEnter: (e) => {
14270
14304
  if (!hasInternalPayload(e)) return;
@@ -14289,11 +14323,11 @@ function BreadcrumbCrumb({
14289
14323
  if (payload && onDropPayload) onDropPayload(payload);
14290
14324
  }
14291
14325
  } : {};
14292
- 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 }) });
14293
14327
  }
14294
14328
 
14295
14329
  // src/kits/query.ts
14296
- var React71 = __toESM(require("react"), 1);
14330
+ var React72 = __toESM(require("react"), 1);
14297
14331
  var isMultiSelectShaped = (v) => !!v && typeof v === "object" && Array.isArray(v.values);
14298
14332
  var isRangeShaped = (v) => !!v && typeof v === "object" && ("min" in v || "max" in v);
14299
14333
  var isDateShaped = (v) => !!v && typeof v === "object" && "kind" in v;
@@ -14348,22 +14382,22 @@ function compare(a, b, dir) {
14348
14382
  var API = null;
14349
14383
  var PREFS = null;
14350
14384
  function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
14351
- const [query, setQuery] = React71.useState(() => {
14385
+ const [query, setQuery] = React72.useState(() => {
14352
14386
  const store = PREFS || window.PlannerPrefs;
14353
14387
  const saved = prefsKey && store ? store.getTable(prefsKey) : {};
14354
14388
  return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
14355
14389
  });
14356
- const savePref = React71.useCallback((patch2) => {
14390
+ const savePref = React72.useCallback((patch2) => {
14357
14391
  const store = PREFS || window.PlannerPrefs;
14358
14392
  if (prefsKey && store) store.setTable(prefsKey, patch2);
14359
14393
  }, [prefsKey]);
14360
- const [res, setRes] = React71.useState(null);
14361
- const [loading, setLoading] = React71.useState(true);
14362
- 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);
14363
14397
  const depKey = (deps || []).join("|");
14364
14398
  const paramKey = JSON.stringify(params || {});
14365
14399
  const queryKey = JSON.stringify(query);
14366
- React71.useEffect(() => {
14400
+ React72.useEffect(() => {
14367
14401
  const id = ++seq2.current;
14368
14402
  setLoading(true);
14369
14403
  const t = setTimeout(() => {
@@ -14682,12 +14716,12 @@ function createVersionStore(initialState, options) {
14682
14716
  }
14683
14717
 
14684
14718
  // src/kits/documentTitle.ts
14685
- var React72 = __toESM(require("react"), 1);
14719
+ var React73 = __toESM(require("react"), 1);
14686
14720
  function formatDocumentTitle(routeTitle, appName) {
14687
14721
  return [routeTitle, appName, "Flytedesk"].filter((part) => !!part && part.length > 0).join(" \xB7 ");
14688
14722
  }
14689
14723
  function useDocumentTitle(routeTitle, appName) {
14690
- React72.useEffect(() => {
14724
+ React73.useEffect(() => {
14691
14725
  if (typeof document === "undefined") return;
14692
14726
  document.title = formatDocumentTitle(routeTitle, appName);
14693
14727
  }, [routeTitle, appName]);
@@ -14702,6 +14736,7 @@ function useDocumentTitle(routeTitle, appName) {
14702
14736
  AppShell,
14703
14737
  AppSwitcher,
14704
14738
  AppearanceMenu,
14739
+ AppearanceProvider,
14705
14740
  Avatar,
14706
14741
  AvatarStack,
14707
14742
  Badge,
@@ -14713,6 +14748,7 @@ function useDocumentTitle(routeTitle, appName) {
14713
14748
  CHANNEL_WEIGHTS,
14714
14749
  CHAT_UNAVAILABLE,
14715
14750
  COPIED_FEEDBACK_MS,
14751
+ CORNER_STACK_INSET_PROPERTY,
14716
14752
  Calendar,
14717
14753
  Card,
14718
14754
  CardGrid,
@@ -14856,6 +14892,7 @@ function useDocumentTitle(routeTitle, appName) {
14856
14892
  __resetLayerStackForTests,
14857
14893
  acceptMatches,
14858
14894
  anyOfFilter,
14895
+ applyAppearance,
14859
14896
  applyPrefs,
14860
14897
  channelWeightOf,
14861
14898
  computeNeedMore,
@@ -14901,6 +14938,7 @@ function useDocumentTitle(routeTitle, appName) {
14901
14938
  toAttachment,
14902
14939
  tokenize,
14903
14940
  useAppearancePrefs,
14941
+ useAppearanceStore,
14904
14942
  useChatEngine,
14905
14943
  useCopyToClipboard,
14906
14944
  useCornerStackSlot,
@@ -14916,6 +14954,7 @@ function useDocumentTitle(routeTitle, appName) {
14916
14954
  useStagedFiles,
14917
14955
  useToast,
14918
14956
  validateFilterValue,
14919
- visibleMessages
14957
+ visibleMessages,
14958
+ watchAppearance
14920
14959
  });
14921
14960
  //# sourceMappingURL=index.cjs.map