@flytedan/flytebot-design-system 0.68.0 → 0.71.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
@@ -974,6 +974,7 @@ __export(index_exports, {
974
974
  FILE_VIEWER_TEXT_LIMIT: () => FILE_VIEWER_TEXT_LIMIT,
975
975
  FactList: () => FactList,
976
976
  FeatureGate: () => FeatureGate,
977
+ Fieldset: () => Fieldset,
977
978
  FileBrowser: () => FileBrowser,
978
979
  FileChip: () => FileChip,
979
980
  FileGrid: () => FileGrid,
@@ -1027,6 +1028,7 @@ __export(index_exports, {
1027
1028
  QuotaRow: () => QuotaRow,
1028
1029
  ROOT_STEP: () => ROOT_STEP,
1029
1030
  Radio: () => Radio,
1031
+ RadioGroup: () => RadioGroup,
1030
1032
  RangeSlider: () => RangeSlider,
1031
1033
  RelativeTime: () => RelativeTime,
1032
1034
  RoadmapTimeline: () => RoadmapTimeline,
@@ -6353,6 +6355,21 @@ function DiffBlock({ diff = "", filename, collapseAfter = 34, className = "" })
6353
6355
 
6354
6356
  // src/components/data/Markdown.tsx
6355
6357
  var React35 = __toESM(require("react"), 1);
6358
+
6359
+ // src/components/data/markdownEscape.ts
6360
+ var ESCAPABLE = /\\([!-/:-@[-`{-~])/g;
6361
+ var STAND_IN_BASE = 57344;
6362
+ var STAND_IN = /[-]/g;
6363
+ var hideEscapes = (s) => s.replace(STAND_IN, "\uFFFD").replace(ESCAPABLE, (_, c) => String.fromCharCode(STAND_IN_BASE + c.charCodeAt(0)));
6364
+ var showEscapes = (s) => s.replace(STAND_IN, (c) => String.fromCharCode(c.charCodeAt(0) - STAND_IN_BASE));
6365
+ var showEscapesRaw = (s) => s.replace(STAND_IN, (c) => "\\" + String.fromCharCode(c.charCodeAt(0) - STAND_IN_BASE));
6366
+ function markdownToText(src) {
6367
+ return showEscapes(
6368
+ hideEscapes(String(src == null ? "" : src)).replace(/```[\w+#-]*\n?([\s\S]*?)```/g, (_, c) => showEscapesRaw(c)).replace(/`([^`]+)`/g, (_, c) => showEscapesRaw(c)).replace(/!\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/\[([^\]]+)\]\([^)]*\)/g, "$1").replace(/^\s{0,3}#{1,6}\s+/gm, "").replace(/\*\*\*([^*]+)\*\*\*|\*\*([^*]+)\*\*|__([^_]+)__/g, "$1$2$3").replace(/(^|\W)[*_]([^*_\n]+)[*_](\W|$)/g, "$1$2$3").replace(/~~([^~]+)~~/g, "$1").replace(/^\s*>\s?/gm, "").trim()
6369
+ );
6370
+ }
6371
+
6372
+ // src/components/data/Markdown.tsx
6356
6373
  var import_jsx_runtime54 = require("react/jsx-runtime");
6357
6374
  var SAFE = /^(?:https?:|mailto:|tel:|#|\/|\.{1,2}\/)/i;
6358
6375
  var safeHref = (h) => SAFE.test(String(h || "").trim()) ? String(h).trim() : null;
@@ -6370,7 +6387,8 @@ var INLINE = [
6370
6387
  ];
6371
6388
  function inlineNodes(src, ctx, keyBase) {
6372
6389
  const out = [];
6373
- let rest = String(src == null ? "" : src), guard = 0;
6390
+ let rest = hideEscapes(String(src == null ? "" : src)), guard = 0;
6391
+ const d = showEscapes;
6374
6392
  const key = () => keyBase + "-" + out.length;
6375
6393
  while (rest && guard++ < 800) {
6376
6394
  let best = null;
@@ -6381,28 +6399,28 @@ function inlineNodes(src, ctx, keyBase) {
6381
6399
  }
6382
6400
  if (!best) break;
6383
6401
  const { kind, m } = best;
6384
- if (m.index > 0) out.push(rest.slice(0, m.index));
6402
+ if (m.index > 0) out.push(d(rest.slice(0, m.index)));
6385
6403
  const g = (i) => m[i];
6386
- if (kind === "code") out.push(/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("code", { className: "fd-md-code", children: g(1) }, key()));
6404
+ if (kind === "code") out.push(/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("code", { className: "fd-md-code", children: showEscapesRaw(g(1)) }, key()));
6387
6405
  else if (kind === "image") {
6388
- const src2 = safeHref(g(2));
6389
- out.push(ctx.allowImages && src2 ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("img", { className: "fd-md-img", src: src2, alt: g(1) || "", title: g(3) || void 0, loading: "lazy" }, key()) : /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "fd-md-imgalt", children: g(1) || "image" }, key()));
6406
+ const src2 = safeHref(d(g(2)));
6407
+ out.push(ctx.allowImages && src2 ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("img", { className: "fd-md-img", src: src2, alt: d(g(1) || ""), title: g(3) ? d(g(3)) : void 0, loading: "lazy" }, key()) : /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "fd-md-imgalt", children: d(g(1) || "image") }, key()));
6390
6408
  } else if (kind === "link") {
6391
- const href = safeHref(g(2));
6392
- out.push(href ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("a", { href, title: g(3) || void 0, target: /^https?:/i.test(href) ? "_blank" : void 0, rel: "noopener noreferrer", onClick: ctx.onLinkClick, children: inlineNodes(g(1), ctx, key()) }, key()) : /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { children: g(1) }, key()));
6409
+ const href = safeHref(d(g(2)));
6410
+ out.push(href ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("a", { href, title: g(3) ? d(g(3)) : void 0, target: /^https?:/i.test(href) ? "_blank" : void 0, rel: "noopener noreferrer", onClick: ctx.onLinkClick, children: inlineNodes(g(1), ctx, key()) }, key()) : /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { children: d(g(1)) }, key()));
6393
6411
  } else if (kind === "cite") {
6394
- out.push(ctx.renderCitation ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(React35.Fragment, { children: ctx.renderCitation(g(1)) }, key()) : /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("sup", { className: "fd-md-cite", children: g(1) }, key()));
6412
+ out.push(ctx.renderCitation ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(React35.Fragment, { children: ctx.renderCitation(d(g(1))) }, key()) : /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("sup", { className: "fd-md-cite", children: d(g(1)) }, key()));
6395
6413
  } else if (kind === "strongem") out.push(/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("strong", { children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("em", { children: inlineNodes(g(1), ctx, key()) }) }, key()));
6396
6414
  else if (kind === "strong") out.push(/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("strong", { children: inlineNodes(g(1) || g(2), ctx, key()) }, key()));
6397
6415
  else if (kind === "em") out.push(/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("em", { children: inlineNodes(g(1) || g(2), ctx, key()) }, key()));
6398
6416
  else if (kind === "del") out.push(/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("del", { children: inlineNodes(g(1), ctx, key()) }, key()));
6399
6417
  else if (kind === "autolink" || kind === "bare") {
6400
- const href = safeHref(g(1));
6401
- out.push(href ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", onClick: ctx.onLinkClick, children: g(1).replace(/^mailto:/, "") }, key()) : g(1));
6418
+ const href = safeHref(d(g(1)));
6419
+ out.push(href ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", onClick: ctx.onLinkClick, children: d(g(1)).replace(/^mailto:/, "") }, key()) : d(g(1)));
6402
6420
  }
6403
6421
  rest = rest.slice(m.index + m[0].length);
6404
6422
  }
6405
- if (rest) out.push(rest);
6423
+ if (rest) out.push(d(rest));
6406
6424
  return out;
6407
6425
  }
6408
6426
  var RE = {
@@ -6414,7 +6432,26 @@ var RE = {
6414
6432
  task: /^\[([ xX])\]\s+(.*)$/,
6415
6433
  tableSep: /^\s*\|?[\s:|-]*-[\s:|-]*\|?\s*$/
6416
6434
  };
6417
- var splitRow = (line) => line.replace(/^\s*\|/, "").replace(/\|\s*$/, "").split("|").map((c) => c.trim());
6435
+ var splitRow = (line) => {
6436
+ const t = line.trim();
6437
+ const cells = [];
6438
+ let cur = "";
6439
+ for (let i = t.startsWith("|") ? 1 : 0; i < t.length; i++) {
6440
+ const c = t[i];
6441
+ if (c === "\\" && i + 1 < t.length) {
6442
+ cur += c + t[++i];
6443
+ continue;
6444
+ }
6445
+ if (c === "|") {
6446
+ cells.push(cur.trim());
6447
+ cur = "";
6448
+ continue;
6449
+ }
6450
+ cur += c;
6451
+ }
6452
+ if (cur.trim() || !t.endsWith("|")) cells.push(cur.trim());
6453
+ return cells;
6454
+ };
6418
6455
  function parseBlocks(src) {
6419
6456
  const lines = String(src == null ? "" : src).replace(/\r\n?/g, "\n").split("\n");
6420
6457
  const blocks = [];
@@ -6546,6 +6583,7 @@ function renderBlocks(blocks, ctx, path) {
6546
6583
  }
6547
6584
  });
6548
6585
  }
6586
+ var mdClass = (base, size, tone, className) => [base, size && `${base}--${size}`, tone === "muted" && `${base}--muted`, className].filter(Boolean).join(" ");
6549
6587
  function Markdown({
6550
6588
  source = "",
6551
6589
  className = "",
@@ -6553,17 +6591,16 @@ function Markdown({
6553
6591
  allowImages = true,
6554
6592
  headingOffset = 0,
6555
6593
  renderCitation,
6556
- onLinkClick
6594
+ onLinkClick,
6595
+ size = "body",
6596
+ tone = "default"
6557
6597
  }) {
6558
6598
  const ctx = { allowImages, headingOffset, renderCitation, onLinkClick, codeProps };
6559
6599
  const blocks = React35.useMemo(() => parseBlocks(source), [source]);
6560
- return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: ["fd-md", className].filter(Boolean).join(" "), children: renderBlocks(blocks, ctx, "b") });
6561
- }
6562
- function MarkdownInline({ source = "", className = "", onLinkClick }) {
6563
- return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: ["fd-md-inline", className].filter(Boolean).join(" "), children: inlineNodes(source, { allowImages: false, onLinkClick }, "i") });
6600
+ return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: mdClass("fd-md", size, tone, className), children: renderBlocks(blocks, ctx, "b") });
6564
6601
  }
6565
- function markdownToText(src) {
6566
- return String(src == null ? "" : src).replace(/```[\w+#-]*\n?([\s\S]*?)```/g, "$1").replace(/`([^`]+)`/g, "$1").replace(/!\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/\[([^\]]+)\]\([^)]*\)/g, "$1").replace(/^\s{0,3}#{1,6}\s+/gm, "").replace(/\*\*\*([^*]+)\*\*\*|\*\*([^*]+)\*\*|__([^_]+)__/g, "$1$2$3").replace(/(^|\W)[*_]([^*_\n]+)[*_](\W|$)/g, "$1$2$3").replace(/~~([^~]+)~~/g, "$1").replace(/^\s*>\s?/gm, "").trim();
6602
+ function MarkdownInline({ source = "", className = "", onLinkClick, size, tone }) {
6603
+ return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: mdClass("fd-md-inline", size, tone, className), children: inlineNodes(source, { allowImages: false, onLinkClick }, "i") });
6567
6604
  }
6568
6605
 
6569
6606
  // src/components/data/Meter.tsx
@@ -7829,14 +7866,17 @@ function Checkbox({ label, description, card = false, indeterminate = false, cla
7829
7866
 
7830
7867
  // src/components/forms/Radio.tsx
7831
7868
  var import_jsx_runtime70 = require("react/jsx-runtime");
7832
- function Radio({ label, description, card = false, className = "", ...rest }) {
7869
+ function Radio({ label, description, badge, card = false, className = "", ...rest }) {
7833
7870
  return /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
7834
7871
  /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { className: "fd-choice-input", children: [
7835
7872
  /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("input", { type: "radio", ...rest }),
7836
7873
  /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("span", { className: "fd-choice-box fd-choice-box-round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("span", { className: "fd-choice-dot" }) })
7837
7874
  ] }),
7838
7875
  /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { className: "fd-choice-text", children: [
7839
- /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("span", { className: "fd-choice-title", children: label }),
7876
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { className: "fd-choice-title", children: [
7877
+ label,
7878
+ badge ? /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("span", { className: "fd-choice-badge", children: badge }) : null
7879
+ ] }),
7840
7880
  description ? /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("span", { className: "fd-choice-desc", children: description }) : null
7841
7881
  ] })
7842
7882
  ] });
@@ -9428,17 +9468,49 @@ function CodeEditor({
9428
9468
  ] });
9429
9469
  }
9430
9470
 
9471
+ // src/components/forms/RadioGroup.tsx
9472
+ var React53 = __toESM(require("react"), 1);
9473
+ var import_jsx_runtime80 = require("react/jsx-runtime");
9474
+ function RadioGroup({ label, labelledBy, options, value, onChange, card = false, disabled = false, name, className = "" }) {
9475
+ const autoName = React53.useId();
9476
+ const labelId = React53.useId();
9477
+ return /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { role: "radiogroup", "aria-labelledby": labelledBy ?? labelId, "aria-disabled": disabled || void 0, className: ["fd-radiogroup", className].filter(Boolean).join(" "), children: [
9478
+ labelledBy === void 0 && /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { id: labelId, className: "fd-radiogroup-label", children: label }),
9479
+ options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
9480
+ Radio,
9481
+ {
9482
+ card,
9483
+ name: name ?? autoName,
9484
+ value: o.value,
9485
+ label: o.label,
9486
+ description: o.description,
9487
+ badge: o.badge,
9488
+ checked: o.value === value,
9489
+ disabled: disabled || o.disabled,
9490
+ onChange: () => onChange(o.value)
9491
+ },
9492
+ o.value
9493
+ ))
9494
+ ] });
9495
+ }
9496
+
9497
+ // src/components/forms/Fieldset.tsx
9498
+ var import_jsx_runtime81 = require("react/jsx-runtime");
9499
+ function Fieldset({ busy = false, className = "", ...rest }) {
9500
+ return /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("fieldset", { disabled: busy, "aria-busy": busy || void 0, className: ["fd-fieldset", className].filter(Boolean).join(" "), ...rest });
9501
+ }
9502
+
9431
9503
  // src/components/platform/AccountMenu.tsx
9432
- var React54 = __toESM(require("react"), 1);
9504
+ var React55 = __toESM(require("react"), 1);
9433
9505
 
9434
9506
  // src/kits/sessionContext.tsx
9435
- var React53 = __toESM(require("react"), 1);
9436
- var SessionContext = React53.createContext(null);
9507
+ var React54 = __toESM(require("react"), 1);
9508
+ var SessionContext = React54.createContext(null);
9437
9509
  function SessionProvider({ value, children }) {
9438
- return React53.createElement(SessionContext.Provider, { value }, children);
9510
+ return React54.createElement(SessionContext.Provider, { value }, children);
9439
9511
  }
9440
9512
  function useSessionContext() {
9441
- const ctx = React53.useContext(SessionContext);
9513
+ const ctx = React54.useContext(SessionContext);
9442
9514
  if (!ctx) {
9443
9515
  throw new Error(
9444
9516
  "useSessionContext() was called outside a <SessionProvider>. Wrap your app root in <SessionProvider value={...}> with your real session, or \u2014 in the docs site or a demo \u2014 in <DemoSessionProvider>, before rendering AccountMenu, Gate, ProfilePage or AppSwitcher."
@@ -9448,11 +9520,11 @@ function useSessionContext() {
9448
9520
  }
9449
9521
 
9450
9522
  // src/components/platform/AccountMenu.tsx
9451
- var import_jsx_runtime80 = require("react/jsx-runtime");
9523
+ var import_jsx_runtime82 = require("react/jsx-runtime");
9452
9524
  var DEFAULT_LINKS = [];
9453
9525
  var DEFAULT_GROUPS = [];
9454
9526
  function Item({ item, onPick }) {
9455
- return /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)(
9527
+ return /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)(
9456
9528
  "button",
9457
9529
  {
9458
9530
  type: "button",
@@ -9460,9 +9532,9 @@ function Item({ item, onPick }) {
9460
9532
  className: "fd-acct-item",
9461
9533
  onClick: () => onPick(item),
9462
9534
  children: [
9463
- item.icon ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("i", { className: "ph ph-" + item.icon, "aria-hidden": "true" }) : null,
9464
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { style: { flex: 1 }, children: item.label }),
9465
- item.badge ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Badge, { tone: "neutral", children: item.badge }) : null
9535
+ item.icon ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-" + item.icon, "aria-hidden": "true" }) : null,
9536
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { style: { flex: 1 }, children: item.label }),
9537
+ item.badge ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Badge, { tone: "neutral", children: item.badge }) : null
9466
9538
  ]
9467
9539
  }
9468
9540
  );
@@ -9478,11 +9550,11 @@ function AccountMenu({
9478
9550
  ...rest
9479
9551
  }) {
9480
9552
  const { user, roles, can: can2, signOut: ctxSignOut, demo, pending } = useSessionContext();
9481
- const [open2, setOpen] = React54.useState(false);
9482
- const [switching, setSwitching] = React54.useState(false);
9483
- const [signingOut, setSigningOut] = React54.useState(false);
9484
- const [signOutError, setSignOutError] = React54.useState(null);
9485
- const ref = React54.useRef(null);
9553
+ const [open2, setOpen] = React55.useState(false);
9554
+ const [switching, setSwitching] = React55.useState(false);
9555
+ const [signingOut, setSigningOut] = React55.useState(false);
9556
+ const [signOutError, setSignOutError] = React55.useState(null);
9557
+ const ref = React55.useRef(null);
9486
9558
  const visibleLinks = links.filter((l) => !l.perm || !pending && can2(l.perm));
9487
9559
  const visibleGroups = groups.map((g) => ({ label: g.label, links: g.links.filter((l) => !l.perm || !pending && can2(l.perm)) })).filter((g) => g.links.length);
9488
9560
  const closeMenu = () => {
@@ -9510,8 +9582,8 @@ function AccountMenu({
9510
9582
  }
9511
9583
  };
9512
9584
  const showSwitcher = allowUserSwitch && !!demo;
9513
- return /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)(import_jsx_runtime80.Fragment, { children: [
9514
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)(
9585
+ return /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)(import_jsx_runtime82.Fragment, { children: [
9586
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)(
9515
9587
  "button",
9516
9588
  {
9517
9589
  type: "button",
@@ -9523,12 +9595,12 @@ function AccountMenu({
9523
9595
  onClick: () => open2 ? closeMenu() : setOpen(true),
9524
9596
  ...rest,
9525
9597
  children: [
9526
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Avatar, { name: user.name, size: "sm" }),
9527
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("i", { className: "ph ph-caret-down", "aria-hidden": "true", style: { fontSize: 11, color: "var(--text-muted)" } })
9598
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Avatar, { name: user.name, size: "sm" }),
9599
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-caret-down", "aria-hidden": "true", style: { fontSize: 11, color: "var(--text-muted)" } })
9528
9600
  ]
9529
9601
  }
9530
9602
  ),
9531
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
9603
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
9532
9604
  Popover,
9533
9605
  {
9534
9606
  open: open2,
@@ -9536,27 +9608,27 @@ function AccountMenu({
9536
9608
  onClose: closeMenu,
9537
9609
  placement: "bottom-end",
9538
9610
  width: 272,
9539
- children: /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { role: "menu", className: "fd-stack", style: { gap: 0 }, children: [
9540
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
9541
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Avatar, { name: user.name }),
9542
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fd-stack", style: { gap: 1, minWidth: 0, flex: 1 }, children: [
9543
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 700 }, children: user.name }),
9544
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-body-sm fd-muted fd-table-trunc", title: truncationTitle(user.email), children: user.email })
9611
+ children: /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { role: "menu", className: "fd-stack", style: { gap: 0 }, children: [
9612
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
9613
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Avatar, { name: user.name }),
9614
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("span", { className: "fd-stack", style: { gap: 1, minWidth: 0, flex: 1 }, children: [
9615
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 700 }, children: user.name }),
9616
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fd-body-sm fd-muted fd-table-trunc", title: truncationTitle(user.email), children: user.email })
9545
9617
  ] })
9546
9618
  ] }),
9547
- showRoles && roles.length ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("div", { className: "fd-row", style: { gap: 6, padding: "10px 14px", flexWrap: "wrap", borderBottom: "1px solid var(--border)" }, children: roles.map((r) => /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Badge, { tone: r.id === "owner" ? "success" : "neutral", children: r.name }, r.id)) }) : null,
9548
- visibleLinks.length ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("div", { className: "fd-acct-group", children: visibleLinks.map((l) => /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Item, { item: l, onPick: pick }, l.id)) }) : null,
9549
- visibleGroups.map((g) => /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: [
9550
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-overline fd-muted", style: { padding: "8px 14px 4px", display: "block" }, children: g.label }),
9551
- g.links.map((l) => /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Item, { item: l, onPick: pick }, l.id))
9619
+ showRoles && roles.length ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fd-row", style: { gap: 6, padding: "10px 14px", flexWrap: "wrap", borderBottom: "1px solid var(--border)" }, children: roles.map((r) => /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Badge, { tone: r.id === "owner" ? "success" : "neutral", children: r.name }, r.id)) }) : null,
9620
+ visibleLinks.length ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fd-acct-group", children: visibleLinks.map((l) => /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Item, { item: l, onPick: pick }, l.id)) }) : null,
9621
+ visibleGroups.map((g) => /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: [
9622
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fd-overline fd-muted", style: { padding: "8px 14px 4px", display: "block" }, children: g.label }),
9623
+ g.links.map((l) => /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Item, { item: l, onPick: pick }, l.id))
9552
9624
  ] }, g.label)),
9553
- showSwitcher && demo ? /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: [
9554
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("button", { type: "button", role: "menuitem", className: "fd-acct-item", onClick: () => setSwitching((s) => !s), children: [
9555
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("i", { className: "ph ph-user-switch", "aria-hidden": "true" }),
9556
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { style: { flex: 1 }, children: "View as another member" }),
9557
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("i", { className: "ph ph-caret-" + (switching ? "up" : "down"), "aria-hidden": "true", style: { fontSize: 11 } })
9625
+ showSwitcher && demo ? /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: [
9626
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("button", { type: "button", role: "menuitem", className: "fd-acct-item", onClick: () => setSwitching((s) => !s), children: [
9627
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-user-switch", "aria-hidden": "true" }),
9628
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { style: { flex: 1 }, children: "View as another member" }),
9629
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-caret-" + (switching ? "up" : "down"), "aria-hidden": "true", style: { fontSize: 11 } })
9558
9630
  ] }),
9559
- switching ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("div", { className: "fd-stack", style: { gap: 0 }, children: demo.allUsers.map((u) => /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)(
9631
+ switching ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fd-stack", style: { gap: 0 }, children: demo.allUsers.map((u) => /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)(
9560
9632
  "button",
9561
9633
  {
9562
9634
  type: "button",
@@ -9568,19 +9640,19 @@ function AccountMenu({
9568
9640
  setSwitching(false);
9569
9641
  },
9570
9642
  children: [
9571
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Avatar, { name: u.name, size: "sm" }),
9572
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fd-stack", style: { gap: 0, flex: 1, minWidth: 0, alignItems: "flex-start" }, children: [
9573
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { style: { fontWeight: u.id === user.id ? 700 : 500 }, children: u.name }),
9574
- u.roles ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-muted", style: { fontSize: 11.5 }, children: u.roles.join(", ") }) : null
9643
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Avatar, { name: u.name, size: "sm" }),
9644
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("span", { className: "fd-stack", style: { gap: 0, flex: 1, minWidth: 0, alignItems: "flex-start" }, children: [
9645
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { style: { fontWeight: u.id === user.id ? 700 : 500 }, children: u.name }),
9646
+ u.roles ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fd-muted", style: { fontSize: 11.5 }, children: u.roles.join(", ") }) : null
9575
9647
  ] }),
9576
- u.id === user.id ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("i", { className: "ph ph-check", "aria-hidden": "true", style: { color: "var(--ok-text)" } }) : null
9648
+ u.id === user.id ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-check", "aria-hidden": "true", style: { color: "var(--ok-text)" } }) : null
9577
9649
  ]
9578
9650
  },
9579
9651
  u.id
9580
9652
  )) }) : null
9581
9653
  ] }) : null,
9582
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: [
9583
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)(
9654
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: [
9655
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)(
9584
9656
  "button",
9585
9657
  {
9586
9658
  type: "button",
@@ -9590,14 +9662,14 @@ function AccountMenu({
9590
9662
  disabled: signingOut,
9591
9663
  onClick: signOut,
9592
9664
  children: [
9593
- signingOut ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Spinner, { size: "sm" }) : /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("i", { className: "ph ph-sign-out", "aria-hidden": "true" }),
9594
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { style: { flex: 1 }, children: signingOut ? "Signing out\u2026" : "Sign out" })
9665
+ signingOut ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Spinner, { size: "sm" }) : /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-sign-out", "aria-hidden": "true" }),
9666
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { style: { flex: 1 }, children: signingOut ? "Signing out\u2026" : "Sign out" })
9595
9667
  ]
9596
9668
  }
9597
9669
  ),
9598
- signOutError ? /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { role: "alert", className: "fd-body-sm", style: { padding: "0 14px 12px" }, children: [
9599
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { style: { display: "block", color: "var(--danger-text)", marginBottom: 6 }, children: signOutError }),
9600
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("button", { type: "button", className: "fd-soon-link", disabled: signingOut, onClick: signOut, children: "Retry" })
9670
+ signOutError ? /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { role: "alert", className: "fd-body-sm", style: { padding: "0 14px 12px" }, children: [
9671
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { style: { display: "block", color: "var(--danger-text)", marginBottom: 6 }, children: signOutError }),
9672
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("button", { type: "button", className: "fd-soon-link", disabled: signingOut, onClick: signOut, children: "Retry" })
9601
9673
  ] }) : null
9602
9674
  ] })
9603
9675
  ] })
@@ -9607,13 +9679,13 @@ function AccountMenu({
9607
9679
  }
9608
9680
 
9609
9681
  // src/components/platform/AppSwitcher.tsx
9610
- var React55 = __toESM(require("react"), 1);
9611
- var import_jsx_runtime81 = require("react/jsx-runtime");
9682
+ var React56 = __toESM(require("react"), 1);
9683
+ var import_jsx_runtime83 = require("react/jsx-runtime");
9612
9684
  function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
9613
9685
  const { apps: contextApps } = useSessionContext();
9614
9686
  const apps = appsProp ?? contextApps ?? [];
9615
- const [open2, setOpen] = React55.useState(false);
9616
- const anchorRef = React55.useRef(null);
9687
+ const [open2, setOpen] = React56.useState(false);
9688
+ const anchorRef = React56.useRef(null);
9617
9689
  if (!apps.length) return null;
9618
9690
  const items = apps.map((app) => ({
9619
9691
  id: app.key,
@@ -9627,8 +9699,8 @@ function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
9627
9699
  window.location.href = app.url;
9628
9700
  }
9629
9701
  }));
9630
- return /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)(React55.Fragment, { children: [
9631
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { ref: anchorRef, className: ["fd-appswitch-anchor", className].filter(Boolean).join(" "), style: { display: "inline-flex" }, children: /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
9702
+ return /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)(React56.Fragment, { children: [
9703
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { ref: anchorRef, className: ["fd-appswitch-anchor", className].filter(Boolean).join(" "), style: { display: "inline-flex" }, children: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
9632
9704
  IconButton,
9633
9705
  {
9634
9706
  icon: "squares-four",
@@ -9638,7 +9710,7 @@ function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
9638
9710
  onClick: () => setOpen((v) => !v)
9639
9711
  }
9640
9712
  ) }),
9641
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
9713
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
9642
9714
  Popover,
9643
9715
  {
9644
9716
  open: open2,
@@ -9649,17 +9721,17 @@ function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
9649
9721
  label: "All flytedesk apps",
9650
9722
  width: 240,
9651
9723
  maxHeight: 360,
9652
- children: /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Menu, { items, onClose: () => setOpen(false) })
9724
+ children: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(Menu, { items, onClose: () => setOpen(false) })
9653
9725
  }
9654
9726
  )
9655
9727
  ] });
9656
9728
  }
9657
9729
 
9658
9730
  // src/components/platform/AppearanceMenu.tsx
9659
- var React58 = __toESM(require("react"), 1);
9731
+ var React59 = __toESM(require("react"), 1);
9660
9732
 
9661
9733
  // src/kits/appearance.ts
9662
- var React56 = __toESM(require("react"), 1);
9734
+ var React57 = __toESM(require("react"), 1);
9663
9735
  var DEFAULT_STORAGE_KEY = "fd-appearance";
9664
9736
  var DEFAULT_PREFS = {
9665
9737
  theme: "system",
@@ -9771,8 +9843,8 @@ function watchAppearance(store, root = document.documentElement) {
9771
9843
  };
9772
9844
  }
9773
9845
  function useAppearancePrefs(store) {
9774
- const prefs = React56.useSyncExternalStore(store.subscribe, store.getSnapshot);
9775
- const update = React56.useCallback(
9846
+ const prefs = React57.useSyncExternalStore(store.subscribe, store.getSnapshot);
9847
+ const update = React57.useCallback(
9776
9848
  (patch) => {
9777
9849
  store.write({ ...store.getSnapshot(), ...patch });
9778
9850
  },
@@ -9782,21 +9854,21 @@ function useAppearancePrefs(store) {
9782
9854
  }
9783
9855
 
9784
9856
  // src/components/platform/AppearanceProvider.tsx
9785
- var React57 = __toESM(require("react"), 1);
9786
- var import_jsx_runtime82 = require("react/jsx-runtime");
9787
- var AppearanceStoreContext = React57.createContext(null);
9857
+ var React58 = __toESM(require("react"), 1);
9858
+ var import_jsx_runtime84 = require("react/jsx-runtime");
9859
+ var AppearanceStoreContext = React58.createContext(null);
9788
9860
  function AppearanceProvider({ store, children }) {
9789
- React57.useLayoutEffect(() => watchAppearance(store), [store]);
9790
- return /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(AppearanceStoreContext.Provider, { value: store, children });
9861
+ React58.useLayoutEffect(() => watchAppearance(store), [store]);
9862
+ return /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(AppearanceStoreContext.Provider, { value: store, children });
9791
9863
  }
9792
9864
  function useAppearanceStore() {
9793
- const store = React57.useContext(AppearanceStoreContext);
9865
+ const store = React58.useContext(AppearanceStoreContext);
9794
9866
  if (!store) throw new Error("AppearanceMenu and useAppearanceStore must be rendered inside an <AppearanceProvider>.");
9795
9867
  return store;
9796
9868
  }
9797
9869
 
9798
9870
  // src/components/platform/AppearanceMenu.tsx
9799
- var import_jsx_runtime83 = require("react/jsx-runtime");
9871
+ var import_jsx_runtime85 = require("react/jsx-runtime");
9800
9872
  var THEME_OPTIONS = [
9801
9873
  { value: "light", label: "Light" },
9802
9874
  { value: "dark", label: "Dark" },
@@ -9810,11 +9882,11 @@ var TEXT_SCALE_OPTIONS = [
9810
9882
  ];
9811
9883
  function AppearanceMenu({ className = "" }) {
9812
9884
  const [prefs, update] = useAppearancePrefs(useAppearanceStore());
9813
- const [open2, setOpen] = React58.useState(false);
9814
- const anchorRef = React58.useRef(null);
9885
+ const [open2, setOpen] = React59.useState(false);
9886
+ const anchorRef = React59.useRef(null);
9815
9887
  const patch = (p) => update(p);
9816
- return /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)(React58.Fragment, { children: [
9817
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { ref: anchorRef, className: ["fd-appearance-anchor", className].filter(Boolean).join(" "), style: { display: "inline-flex" }, children: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
9888
+ return /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)(React59.Fragment, { children: [
9889
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { ref: anchorRef, className: ["fd-appearance-anchor", className].filter(Boolean).join(" "), style: { display: "inline-flex" }, children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
9818
9890
  IconButton,
9819
9891
  {
9820
9892
  icon: "circle-half",
@@ -9822,7 +9894,7 @@ function AppearanceMenu({ className = "" }) {
9822
9894
  onClick: () => setOpen((v) => !v)
9823
9895
  }
9824
9896
  ) }),
9825
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
9897
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
9826
9898
  Popover,
9827
9899
  {
9828
9900
  open: open2,
@@ -9832,10 +9904,10 @@ function AppearanceMenu({ className = "" }) {
9832
9904
  padded: true,
9833
9905
  width: 260,
9834
9906
  label: "Appearance settings",
9835
- children: /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fd-stack", style: { display: "flex", flexDirection: "column", gap: 16 }, children: [
9836
- /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
9837
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fd-field-label", children: "Theme" }),
9838
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
9907
+ children: /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("div", { className: "fd-stack", style: { display: "flex", flexDirection: "column", gap: 16 }, children: [
9908
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
9909
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fd-field-label", children: "Theme" }),
9910
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
9839
9911
  SegmentedControl,
9840
9912
  {
9841
9913
  options: THEME_OPTIONS,
@@ -9845,9 +9917,9 @@ function AppearanceMenu({ className = "" }) {
9845
9917
  }
9846
9918
  )
9847
9919
  ] }),
9848
- /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
9849
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fd-field-label", children: "Text size" }),
9850
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
9920
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
9921
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fd-field-label", children: "Text size" }),
9922
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
9851
9923
  SegmentedControl,
9852
9924
  {
9853
9925
  options: TEXT_SCALE_OPTIONS,
@@ -9857,7 +9929,7 @@ function AppearanceMenu({ className = "" }) {
9857
9929
  }
9858
9930
  )
9859
9931
  ] }),
9860
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
9932
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
9861
9933
  Switch,
9862
9934
  {
9863
9935
  label: "High contrast",
@@ -9866,7 +9938,7 @@ function AppearanceMenu({ className = "" }) {
9866
9938
  onChange: (e) => patch({ highContrast: e.target.checked })
9867
9939
  }
9868
9940
  ),
9869
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
9941
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
9870
9942
  Switch,
9871
9943
  {
9872
9944
  label: "Reduce motion",
@@ -9882,14 +9954,14 @@ function AppearanceMenu({ className = "" }) {
9882
9954
  }
9883
9955
 
9884
9956
  // src/components/platform/ApiSpecBrowser.tsx
9885
- var React59 = __toESM(require("react"), 1);
9886
- var import_jsx_runtime84 = require("react/jsx-runtime");
9957
+ var React60 = __toESM(require("react"), 1);
9958
+ var import_jsx_runtime86 = require("react/jsx-runtime");
9887
9959
  var METHOD_TONE = { GET: "success", POST: "info", PATCH: "warning", PUT: "warning", DELETE: "danger" };
9888
9960
  function Json({ obj }) {
9889
- return /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("pre", { className: "fd-json", children: JSON.stringify(obj, null, 2) });
9961
+ return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("pre", { className: "fd-json", children: JSON.stringify(obj, null, 2) });
9890
9962
  }
9891
9963
  function Endpoint({ s, onRequest }) {
9892
- const [tried, setTried] = React59.useState(null);
9964
+ const [tried, setTried] = React60.useState(null);
9893
9965
  const run = async () => {
9894
9966
  setTried("busy");
9895
9967
  const t0 = (window.performance || Date).now();
@@ -9900,50 +9972,50 @@ function Endpoint({ s, onRequest }) {
9900
9972
  setTried({ ms: Math.round((window.performance || Date).now() - t0), error: String(e && e.message || e) });
9901
9973
  }
9902
9974
  };
9903
- return /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(Card, { elevation: "flat", padded: false, children: /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: "fd-stack", style: { gap: 0 }, children: [
9904
- /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: "fd-row", style: { gap: 10, padding: "14px 18px", flexWrap: "wrap" }, children: [
9905
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(Badge, { tone: METHOD_TONE[s.method] || "neutral", children: s.method }),
9906
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("code", { className: "fd-mono", style: { fontSize: 12.5, fontWeight: 600, color: "var(--text)", wordBreak: "break-all" }, children: s.path }),
9907
- s.isList ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(Badge, { tone: "neutral", icon: "rows", children: "Paged list" }) : null,
9908
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { style: { flex: 1 } }),
9909
- /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
9975
+ return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Card, { elevation: "flat", padded: false, children: /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-stack", style: { gap: 0 }, children: [
9976
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-row", style: { gap: 10, padding: "14px 18px", flexWrap: "wrap" }, children: [
9977
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Badge, { tone: METHOD_TONE[s.method] || "neutral", children: s.method }),
9978
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("code", { className: "fd-mono", style: { fontSize: 12.5, fontWeight: 600, color: "var(--text)", wordBreak: "break-all" }, children: s.path }),
9979
+ s.isList ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Badge, { tone: "neutral", icon: "rows", children: "Paged list" }) : null,
9980
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { style: { flex: 1 } }),
9981
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
9910
9982
  s.latency[0],
9911
9983
  "\u2013",
9912
9984
  s.latency[1],
9913
9985
  "ms"
9914
9986
  ] }),
9915
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(Button, { size: "sm", variant: "secondary", icon: "play", loading: tried === "busy", onClick: run, children: "Try it" })
9987
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Button, { size: "sm", variant: "secondary", icon: "play", loading: tried === "busy", onClick: run, children: "Try it" })
9916
9988
  ] }),
9917
- /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: "fd-stack", style: { gap: 14, padding: "0 18px 16px" }, children: [
9918
- /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
9919
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 700 }, children: s.title }),
9920
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: s.purpose }),
9921
- s.usedBy && s.usedBy.length ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: s.usedBy.map((u) => /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(Tag, { children: u }, u)) }) : null
9989
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-stack", style: { gap: 14, padding: "0 18px 16px" }, children: [
9990
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
9991
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 700 }, children: s.title }),
9992
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: s.purpose }),
9993
+ s.usedBy && s.usedBy.length ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: s.usedBy.map((u) => /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Tag, { children: u }, u)) }) : null
9922
9994
  ] }),
9923
- /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(280px,1fr))", gap: 12, alignItems: "start" }, children: [
9924
- s.request ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
9925
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-overline fd-muted", children: "Request body" }),
9926
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(Json, { obj: s.request })
9995
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(280px,1fr))", gap: 12, alignItems: "start" }, children: [
9996
+ s.request ? /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
9997
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-overline fd-muted", children: "Request body" }),
9998
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Json, { obj: s.request })
9927
9999
  ] }) : null,
9928
- s.query ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
9929
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-overline fd-muted", children: "Query" }),
9930
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(Json, { obj: s.query })
10000
+ s.query ? /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
10001
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-overline fd-muted", children: "Query" }),
10002
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Json, { obj: s.query })
9931
10003
  ] }) : null,
9932
- /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
9933
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-overline fd-muted", children: "Response 200" }),
9934
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(Json, { obj: s.response })
10004
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
10005
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-overline fd-muted", children: "Response 200" }),
10006
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Json, { obj: s.response })
9935
10007
  ] })
9936
10008
  ] }),
9937
- s.notes ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(Flag, { tone: "info", statement: "Implementation note", cost: s.notes, actions: null }) : null,
9938
- tried && tried !== "busy" ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
9939
- /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("span", { className: "fd-row", style: { gap: 8 }, children: [
9940
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-overline fd-muted", children: "Simulated response" }),
9941
- /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(Badge, { tone: tried.error ? "danger" : "success", icon: "timer", children: [
10009
+ s.notes ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Flag, { tone: "info", statement: "Implementation note", cost: s.notes, actions: null }) : null,
10010
+ tried && tried !== "busy" ? /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
10011
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-row", style: { gap: 8 }, children: [
10012
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-overline fd-muted", children: "Simulated response" }),
10013
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(Badge, { tone: tried.error ? "danger" : "success", icon: "timer", children: [
9942
10014
  tried.ms,
9943
10015
  "ms"
9944
10016
  ] })
9945
10017
  ] }),
9946
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(Json, { obj: tried.error ? { error: tried.error } : tried.data })
10018
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Json, { obj: tried.error ? { error: tried.error } : tried.data })
9947
10019
  ] }) : null
9948
10020
  ] })
9949
10021
  ] }) });
@@ -9962,58 +10034,58 @@ function ApiSpecBrowser({
9962
10034
  className = "",
9963
10035
  ...rest
9964
10036
  }) {
9965
- const [q, setQ] = React59.useState("");
9966
- const [method, setMethod] = React59.useState(null);
9967
- const [mod, setMod] = React59.useState(null);
9968
- const [listOnly, setListOnly] = React59.useState(false);
10037
+ const [q, setQ] = React60.useState("");
10038
+ const [method, setMethod] = React60.useState(null);
10039
+ const [mod, setMod] = React60.useState(null);
10040
+ const [listOnly, setListOnly] = React60.useState(false);
9969
10041
  const activeModule = modules && modules.find((m) => m.id === mod);
9970
10042
  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())));
9971
10043
  const effGroups = groups && groups.length ? groups : [["All endpoints", spec.map((s) => s.id)]];
9972
10044
  const methods = [...new Set(spec.map((s) => s.method))];
9973
10045
  const listCount = spec.filter((s) => s.isList).length;
9974
- return /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 1100 }, ...rest, children: [
9975
- /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
9976
- kicker ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-overline fd-muted", children: kicker }) : null,
9977
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
9978
- lede ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: lede }) : null
10046
+ return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 1100 }, ...rest, children: [
10047
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
10048
+ kicker ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-overline fd-muted", children: kicker }) : null,
10049
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
10050
+ lede ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: lede }) : null
9979
10051
  ] }),
9980
- modules && modules.length ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: "fd-stack", style: { gap: 8 }, children: [
9981
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-overline fd-muted", children: "Filter by screen \u2014 every endpoint that screen depends on" }),
9982
- /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
9983
- /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(Tag, { icon: "stack", selected: !mod, onClick: () => setMod(null), children: [
10052
+ modules && modules.length ? /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-stack", style: { gap: 8 }, children: [
10053
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-overline fd-muted", children: "Filter by screen \u2014 every endpoint that screen depends on" }),
10054
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
10055
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(Tag, { icon: "stack", selected: !mod, onClick: () => setMod(null), children: [
9984
10056
  "All screens ",
9985
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-mono", children: spec.length })
10057
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-mono", children: spec.length })
9986
10058
  ] }),
9987
- modules.map((m) => /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(Tag, { icon: m.icon, selected: mod === m.id, onClick: () => setMod(mod === m.id ? null : m.id), children: [
10059
+ modules.map((m) => /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(Tag, { icon: m.icon, selected: mod === m.id, onClick: () => setMod(mod === m.id ? null : m.id), children: [
9988
10060
  m.label,
9989
10061
  " ",
9990
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-mono", children: m.endpoints.length })
10062
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-mono", children: m.endpoints.length })
9991
10063
  ] }, m.id))
9992
10064
  ] }),
9993
- activeModule ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
10065
+ activeModule ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
9994
10066
  Flag,
9995
10067
  {
9996
10068
  tone: "info",
9997
10069
  statement: activeModule.label + " calls " + activeModule.endpoints.length + " endpoints.",
9998
10070
  cost: "Integration checklist for this screen: " + activeModule.endpoints.join(", ") + ". Wire these and the screen is done.",
9999
- actions: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(Button, { size: "sm", variant: "ghost", icon: "x", onClick: () => setMod(null), children: "Show all screens" })
10071
+ actions: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Button, { size: "sm", variant: "ghost", icon: "x", onClick: () => setMod(null), children: "Show all screens" })
10000
10072
  }
10001
10073
  ) : null
10002
10074
  ] }) : null,
10003
- sourceNote ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(Flag, { tone: "info", statement: "Design-first: this page is the spec.", cost: sourceNote, actions: null }) : null,
10004
- /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
10005
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(Input, { icon: "magnifying-glass", placeholder: "Find an endpoint, screen, or behavior", value: q, onChange: (e) => setQ(e.target.value), style: { width: 300 } }),
10006
- methods.map((m) => /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(Tag, { selected: method === m, onClick: () => setMethod(method === m ? null : m), children: [
10075
+ sourceNote ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Flag, { tone: "info", statement: "Design-first: this page is the spec.", cost: sourceNote, actions: null }) : null,
10076
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
10077
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Input, { icon: "magnifying-glass", placeholder: "Find an endpoint, screen, or behavior", value: q, onChange: (e) => setQ(e.target.value), style: { width: 300 } }),
10078
+ methods.map((m) => /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(Tag, { selected: method === m, onClick: () => setMethod(method === m ? null : m), children: [
10007
10079
  m,
10008
10080
  " ",
10009
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-mono", children: spec.filter((s) => s.method === m).length })
10081
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-mono", children: spec.filter((s) => s.method === m).length })
10010
10082
  ] }, m)),
10011
- listCount ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(Tag, { icon: "rows", selected: listOnly, onClick: () => setListOnly(!listOnly), children: [
10083
+ listCount ? /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(Tag, { icon: "rows", selected: listOnly, onClick: () => setListOnly(!listOnly), children: [
10012
10084
  "Paged lists ",
10013
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-mono", children: listCount })
10085
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-mono", children: listCount })
10014
10086
  ] }) : null,
10015
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { style: { flex: 1 } }),
10016
- /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
10087
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { style: { flex: 1 } }),
10088
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
10017
10089
  hits.length,
10018
10090
  " of ",
10019
10091
  spec.length,
@@ -10021,31 +10093,31 @@ function ApiSpecBrowser({
10021
10093
  listCount ? " \xB7 " + listCount + " paged" : ""
10022
10094
  ] })
10023
10095
  ] }),
10024
- hits.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(Card, { elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: "No endpoint matches those filters." }) }) : effGroups.map(([g, ids]) => {
10096
+ hits.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Card, { elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: "No endpoint matches those filters." }) }) : effGroups.map(([g, ids]) => {
10025
10097
  const items = hits.filter((s) => ids.indexOf(s.id) >= 0);
10026
10098
  if (!items.length) return null;
10027
- return /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: "fd-stack", style: { gap: 12 }, children: [
10028
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-label-lg", children: g }),
10029
- items.map((s) => /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(Endpoint, { s, onRequest }, s.id))
10099
+ return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-stack", style: { gap: 12 }, children: [
10100
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-label-lg", children: g }),
10101
+ items.map((s) => /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Endpoint, { s, onRequest }, s.id))
10030
10102
  ] }, g);
10031
10103
  }),
10032
- conventions && conventions.length ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(Card, { title: "Cross-cutting conventions", elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("div", { className: "fd-stack", style: { gap: 10 }, children: conventions.map(([k, v]) => /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: "fd-row", style: { gap: 12, alignItems: "flex-start" }, children: [
10033
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-overline fd-muted", style: { width: 110, flex: "none", paddingTop: 2 }, children: k }),
10034
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: v })
10104
+ conventions && conventions.length ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Card, { title: "Cross-cutting conventions", elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "fd-stack", style: { gap: 10 }, children: conventions.map(([k, v]) => /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-row", style: { gap: 12, alignItems: "flex-start" }, children: [
10105
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-overline fd-muted", style: { width: 110, flex: "none", paddingTop: 2 }, children: k }),
10106
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: v })
10035
10107
  ] }, k)) }) }) : null,
10036
- openQuestions && openQuestions.length ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(Collapsible, { icon: "list-checks", title: "Open questions before implementation", subtitle: openQuestions.length + " unresolved", children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("div", { className: "fd-stack", style: { gap: 8 }, children: openQuestions.map(([id, question, why]) => /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start", padding: "8px 0", borderTop: "1px solid var(--border)" }, children: [
10037
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(Badge, { tone: "danger", children: id }),
10038
- /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("span", { className: "fd-stack", style: { gap: 2, flex: 1 }, children: [
10039
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: question }),
10040
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-body-sm fd-muted", children: why })
10108
+ openQuestions && openQuestions.length ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Collapsible, { icon: "list-checks", title: "Open questions before implementation", subtitle: openQuestions.length + " unresolved", children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "fd-stack", style: { gap: 8 }, children: openQuestions.map(([id, question, why]) => /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start", padding: "8px 0", borderTop: "1px solid var(--border)" }, children: [
10109
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Badge, { tone: "danger", children: id }),
10110
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-stack", style: { gap: 2, flex: 1 }, children: [
10111
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: question }),
10112
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-body-sm fd-muted", children: why })
10041
10113
  ] })
10042
10114
  ] }, id)) }) }) : null
10043
10115
  ] });
10044
10116
  }
10045
10117
 
10046
10118
  // src/components/platform/ProfilePage.tsx
10047
- var React60 = __toESM(require("react"), 1);
10048
- var import_jsx_runtime85 = require("react/jsx-runtime");
10119
+ var React61 = __toESM(require("react"), 1);
10120
+ var import_jsx_runtime87 = require("react/jsx-runtime");
10049
10121
  function fieldInitialValue(field, user) {
10050
10122
  if (field.value) return field.value(user);
10051
10123
  const raw = user[field.key];
@@ -10080,21 +10152,21 @@ function ProfilePage({
10080
10152
  }) {
10081
10153
  const { user: sessionUser, roles, permissions, saveProfile: saveProfile2 } = useSessionContext();
10082
10154
  const user = userProp || sessionUser;
10083
- const initialFieldValues = React60.useMemo(() => {
10155
+ const initialFieldValues = React61.useMemo(() => {
10084
10156
  const values2 = {};
10085
10157
  for (const field of fields) values2[field.key] = fieldInitialValue(field, user);
10086
10158
  return values2;
10087
10159
  }, [user.id, fields]);
10088
- const initialNotify = React60.useMemo(() => {
10160
+ const initialNotify = React61.useMemo(() => {
10089
10161
  const values2 = {};
10090
10162
  for (const n of notifications) values2[n.key] = !!user.notify?.[n.key];
10091
10163
  return values2;
10092
10164
  }, [user.id, notifications]);
10093
- const [values, setValues] = React60.useState(initialFieldValues);
10094
- const [notify, setNotify] = React60.useState(initialNotify);
10095
- const [saving, setSaving] = React60.useState(false);
10096
- const [saved, setSaved] = React60.useState(false);
10097
- const [prevUserId, setPrevUserId] = React60.useState(user.id);
10165
+ const [values, setValues] = React61.useState(initialFieldValues);
10166
+ const [notify, setNotify] = React61.useState(initialNotify);
10167
+ const [saving, setSaving] = React61.useState(false);
10168
+ const [saved, setSaved] = React61.useState(false);
10169
+ const [prevUserId, setPrevUserId] = React61.useState(user.id);
10098
10170
  if (user.id !== prevUserId) {
10099
10171
  setPrevUserId(user.id);
10100
10172
  setValues(initialFieldValues);
@@ -10131,37 +10203,37 @@ function ProfilePage({
10131
10203
  };
10132
10204
  const displayName = fields.some((f) => f.key === "name") ? values.name || user.name : user.name;
10133
10205
  const fieldGroups = groupFields(fields);
10134
- return /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 860 }, children: [
10135
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
10136
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fd-overline fd-muted", children: "Account" }),
10137
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("h1", { className: "fd-h1", style: { margin: 0 }, children: "Your profile" }),
10138
- /* @__PURE__ */ (0, import_jsx_runtime85.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." })
10206
+ return /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 860 }, children: [
10207
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
10208
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-overline fd-muted", children: "Account" }),
10209
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("h1", { className: "fd-h1", style: { margin: 0 }, children: "Your profile" }),
10210
+ /* @__PURE__ */ (0, import_jsx_runtime87.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." })
10139
10211
  ] }),
10140
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(Card, { elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("div", { className: "fd-row", style: { gap: 16, flexWrap: "wrap", alignItems: "flex-start" }, children: [
10141
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(Avatar, { name: displayName, size: "lg" }),
10142
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("div", { className: "fd-stack", style: { gap: 4, flex: 1, minWidth: 200 }, children: [
10143
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fd-h3", style: { margin: 0 }, children: displayName }),
10144
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 4 }, children: [
10145
- roles.map((r) => /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(Badge, { tone: r.id === "owner" ? "success" : "neutral", children: r.name }, r.id)),
10146
- user.sso ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(Badge, { tone: "info", icon: "shield-check", children: "SSO" }) : null
10212
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Card, { elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-row", style: { gap: 16, flexWrap: "wrap", alignItems: "flex-start" }, children: [
10213
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Avatar, { name: displayName, size: "lg" }),
10214
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-stack", style: { gap: 4, flex: 1, minWidth: 200 }, children: [
10215
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-h3", style: { margin: 0 }, children: displayName }),
10216
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 4 }, children: [
10217
+ roles.map((r) => /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Badge, { tone: r.id === "owner" ? "success" : "neutral", children: r.name }, r.id)),
10218
+ user.sso ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Badge, { tone: "info", icon: "shield-check", children: "SSO" }) : null
10147
10219
  ] })
10148
10220
  ] }),
10149
- onChangePhoto ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(Button, { variant: "secondary", size: "sm", icon: "image", onClick: onChangePhoto, children: "Change photo" }) : null
10221
+ onChangePhoto ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Button, { variant: "secondary", size: "sm", icon: "image", onClick: onChangePhoto, children: "Change photo" }) : null
10150
10222
  ] }) }),
10151
- fieldGroups.map(({ group, description, fields: groupFieldDefs }) => /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
10223
+ fieldGroups.map(({ group, description, fields: groupFieldDefs }) => /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
10152
10224
  Card,
10153
10225
  {
10154
- title: description ? /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-stack", style: { gap: 2 }, children: [
10155
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { children: group }),
10156
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: description })
10226
+ title: description ? /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("span", { className: "fd-stack", style: { gap: 2 }, children: [
10227
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { children: group }),
10228
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: description })
10157
10229
  ] }) : group,
10158
10230
  elevation: "flat",
10159
- children: /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("div", { className: "fd-stack", style: { gap: 14 }, children: [
10160
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: groupFieldDefs.filter((f) => f.type !== "textarea").map((field) => {
10231
+ children: /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-stack", style: { gap: 14 }, children: [
10232
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: groupFieldDefs.filter((f) => f.type !== "textarea").map((field) => {
10161
10233
  const help = typeof field.help === "function" ? field.help(user) : field.help;
10162
10234
  const readOnly = field.readOnly || field.type === "readonly";
10163
10235
  if (field.type === "select") {
10164
- return /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
10236
+ return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
10165
10237
  Select,
10166
10238
  {
10167
10239
  label: field.label,
@@ -10175,7 +10247,7 @@ function ProfilePage({
10175
10247
  field.key
10176
10248
  );
10177
10249
  }
10178
- return /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
10250
+ return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
10179
10251
  Input,
10180
10252
  {
10181
10253
  label: field.label,
@@ -10191,7 +10263,7 @@ function ProfilePage({
10191
10263
  }) }),
10192
10264
  groupFieldDefs.filter((f) => f.type === "textarea").map((field) => {
10193
10265
  const help = typeof field.help === "function" ? field.help(user) : field.help;
10194
- return /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
10266
+ return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
10195
10267
  Textarea,
10196
10268
  {
10197
10269
  label: field.label,
@@ -10211,16 +10283,16 @@ function ProfilePage({
10211
10283
  group
10212
10284
  )),
10213
10285
  extra,
10214
- notifications.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(Card, { title: "Notifications", elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("div", { className: "fd-stack", style: { gap: 14 }, children: notifications.map((n) => /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(Switch, { checked: !!notify[n.key], onChange: () => toggleNotify(n.key), label: n.label, description: n.description }, n.key)) }) }) : null,
10215
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)(
10286
+ notifications.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Card, { title: "Notifications", elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("div", { className: "fd-stack", style: { gap: 14 }, children: notifications.map((n) => /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Switch, { checked: !!notify[n.key], onChange: () => toggleNotify(n.key), label: n.label, description: n.description }, n.key)) }) }) : null,
10287
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(
10216
10288
  Card,
10217
10289
  {
10218
- title: /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-stack", style: { gap: 2 }, children: [
10219
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { children: "Access" }),
10220
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "What your roles grant you" })
10290
+ title: /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("span", { className: "fd-stack", style: { gap: 2 }, children: [
10291
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { children: "Access" }),
10292
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "What your roles grant you" })
10221
10293
  ] }),
10222
10294
  elevation: "flat",
10223
- action: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
10295
+ action: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
10224
10296
  Button,
10225
10297
  {
10226
10298
  size: "sm",
@@ -10231,39 +10303,39 @@ function ProfilePage({
10231
10303
  }
10232
10304
  ),
10233
10305
  children: [
10234
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("div", { className: "fd-stack", style: { gap: 0 }, children: [
10235
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(CardRow, { label: "Roles", children: roles.map((r) => r.name).join(", ") || "None" }),
10236
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)(CardRow, { label: "Permissions", children: [
10306
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-stack", style: { gap: 0 }, children: [
10307
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(CardRow, { label: "Roles", children: roles.map((r) => r.name).join(", ") || "None" }),
10308
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(CardRow, { label: "Permissions", children: [
10237
10309
  permissions.length,
10238
10310
  " granted"
10239
10311
  ] }),
10240
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(CardRow, { label: "Member since", children: user.joined || "\u2014" })
10312
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(CardRow, { label: "Member since", children: user.joined || "\u2014" })
10241
10313
  ] }),
10242
- /* @__PURE__ */ (0, import_jsx_runtime85.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." })
10314
+ /* @__PURE__ */ (0, import_jsx_runtime87.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." })
10243
10315
  ]
10244
10316
  }
10245
10317
  ),
10246
- sessions ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
10318
+ sessions ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
10247
10319
  Card,
10248
10320
  {
10249
10321
  title: "Signed-in devices",
10250
10322
  elevation: "flat",
10251
- action: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(Button, { size: "sm", variant: "ghost", icon: "sign-out", onClick: onSignOutEverywhere, children: "Sign out everywhere" }),
10252
- children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("div", { className: "fd-stack", style: { gap: 0 }, children: sessions.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: "No other signed-in devices." }) : sessions.map((s) => /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("div", { className: "fd-row", style: { gap: 12, padding: "10px 0", borderTop: "1px solid var(--border)", flexWrap: "wrap" }, children: [
10253
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("i", { className: "ph ph-device-mobile", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
10254
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-stack", style: { gap: 1, flex: 1, minWidth: 160 }, children: [
10255
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: s.device }),
10256
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
10323
+ action: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Button, { size: "sm", variant: "ghost", icon: "sign-out", onClick: onSignOutEverywhere, children: "Sign out everywhere" }),
10324
+ children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("div", { className: "fd-stack", style: { gap: 0 }, children: sessions.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: "No other signed-in devices." }) : sessions.map((s) => /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-row", style: { gap: 12, padding: "10px 0", borderTop: "1px solid var(--border)", flexWrap: "wrap" }, children: [
10325
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("i", { className: "ph ph-device-mobile", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
10326
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("span", { className: "fd-stack", style: { gap: 1, flex: 1, minWidth: 160 }, children: [
10327
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: s.device }),
10328
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
10257
10329
  s.where,
10258
10330
  " \xB7 ",
10259
10331
  s.when
10260
10332
  ] })
10261
10333
  ] }),
10262
- s.current ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(Badge, { tone: "success", dot: true, children: "This device" }) : /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(Button, { size: "sm", variant: "ghost", children: "Revoke" })
10334
+ s.current ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Badge, { tone: "success", dot: true, children: "This device" }) : /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Button, { size: "sm", variant: "ghost", children: "Revoke" })
10263
10335
  ] }, s.id)) })
10264
10336
  }
10265
10337
  ) : null,
10266
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("div", { className: "fd-row", style: {
10338
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-row", style: {
10267
10339
  gap: 10,
10268
10340
  flexWrap: "wrap",
10269
10341
  position: "sticky",
@@ -10274,16 +10346,16 @@ function ProfilePage({
10274
10346
  border: "1px solid var(--border)",
10275
10347
  boxShadow: "0 -4px 16px rgba(11,13,17,.06)"
10276
10348
  }, children: [
10277
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 600, flex: 1 }, children: saved ? "Saved." : dirty ? "Unsaved changes" : "No pending changes" }),
10278
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(Button, { size: "sm", variant: "ghost", disabled: !dirty || saving, onClick: discard, children: "Discard" }),
10279
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(Button, { size: "sm", icon: "check", disabled: !dirty || !canSave, loading: saving, onClick: save, children: "Save changes" })
10349
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 600, flex: 1 }, children: saved ? "Saved." : dirty ? "Unsaved changes" : "No pending changes" }),
10350
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Button, { size: "sm", variant: "ghost", disabled: !dirty || saving, onClick: discard, children: "Discard" }),
10351
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Button, { size: "sm", icon: "check", disabled: !dirty || !canSave, loading: saving, onClick: save, children: "Save changes" })
10280
10352
  ] })
10281
10353
  ] });
10282
10354
  }
10283
10355
 
10284
10356
  // src/components/platform/SessionScreen.tsx
10285
- var React61 = __toESM(require("react"), 1);
10286
- var import_jsx_runtime86 = require("react/jsx-runtime");
10357
+ var React62 = __toESM(require("react"), 1);
10358
+ var import_jsx_runtime88 = require("react/jsx-runtime");
10287
10359
  var COPY = {
10288
10360
  "signing-in": { busy: "Signing you in\u2026" },
10289
10361
  "session-expired": { busy: "Your session expired \u2014 signing you back in\u2026" },
@@ -10296,28 +10368,28 @@ function SessionScreen({ kind, error, onRetry, productName }) {
10296
10368
  const copy = COPY[kind];
10297
10369
  const busyMessage = "busy" in copy ? copy.busy : null;
10298
10370
  const failureTitle = "failure" in copy ? copy.failure : null;
10299
- const [announced, setAnnounced] = React61.useState("");
10300
- React61.useEffect(() => {
10371
+ const [announced, setAnnounced] = React62.useState("");
10372
+ React62.useEffect(() => {
10301
10373
  setAnnounced(busyMessage ?? "");
10302
10374
  }, [busyMessage]);
10303
- const titleRef = React61.useRef(null);
10375
+ const titleRef = React62.useRef(null);
10304
10376
  const failed = failureTitle !== null;
10305
- React61.useEffect(() => {
10377
+ React62.useEffect(() => {
10306
10378
  titleRef.current?.focus({ preventScroll: true });
10307
10379
  }, [failed]);
10308
- return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("main", { className: "fd-session-screen", children: /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-session-screen-inner", children: [
10309
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "fd-session-screen-mark", "data-theme": "dark", children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(FlytedeskMark, { size: "lg" }) }),
10310
- /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-session-screen-frame", children: [
10311
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "fd-session-screen-stripe" }),
10312
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Card, { children: /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-session-screen-body", children: [
10313
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("h1", { ref: titleRef, tabIndex: -1, className: "fd-h3 fd-session-screen-title", children: productName }),
10314
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { role: "status", "aria-live": "polite", className: "fd-session-screen-status", children: busyMessage !== null ? /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(import_jsx_runtime86.Fragment, { children: [
10315
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-spinner fd-spinner-lg fd-session-screen-spinner", "aria-hidden": "true" }),
10316
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("p", { className: "fd-body fd-session-screen-message", children: announced })
10380
+ return /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("main", { className: "fd-session-screen", children: /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "fd-session-screen-inner", children: [
10381
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("div", { className: "fd-session-screen-mark", "data-theme": "dark", children: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(FlytedeskMark, { size: "lg" }) }),
10382
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "fd-session-screen-frame", children: [
10383
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("div", { className: "fd-session-screen-stripe" }),
10384
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(Card, { children: /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "fd-session-screen-body", children: [
10385
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("h1", { ref: titleRef, tabIndex: -1, className: "fd-h3 fd-session-screen-title", children: productName }),
10386
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("div", { role: "status", "aria-live": "polite", className: "fd-session-screen-status", children: busyMessage !== null ? /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)(import_jsx_runtime88.Fragment, { children: [
10387
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "fd-spinner fd-spinner-lg fd-session-screen-spinner", "aria-hidden": "true" }),
10388
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("p", { className: "fd-body fd-session-screen-message", children: announced })
10317
10389
  ] }) : null }),
10318
- failureTitle !== null ? /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-session-screen-failure", children: [
10319
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Banner, { tone: "danger", title: failureTitle, detail: error ?? void 0 }),
10320
- onRetry !== null ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Button, { variant: "primary", block: true, onClick: onRetry, children: "Try again" }) : null
10390
+ failureTitle !== null ? /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "fd-session-screen-failure", children: [
10391
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(Banner, { tone: "danger", title: failureTitle, detail: error ?? void 0 }),
10392
+ onRetry !== null ? /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(Button, { variant: "primary", block: true, onClick: onRetry, children: "Try again" }) : null
10321
10393
  ] }) : null
10322
10394
  ] }) })
10323
10395
  ] })
@@ -10325,10 +10397,10 @@ function SessionScreen({ kind, error, onRetry, productName }) {
10325
10397
  }
10326
10398
 
10327
10399
  // src/components/platform/RoadmapTimeline.tsx
10328
- var React64 = __toESM(require("react"), 1);
10400
+ var React65 = __toESM(require("react"), 1);
10329
10401
 
10330
10402
  // src/kits/session.ts
10331
- var React62 = __toESM(require("react"), 1);
10403
+ var React63 = __toESM(require("react"), 1);
10332
10404
  var PERMISSION_CATALOG = [
10333
10405
  { group: "Plans", items: [
10334
10406
  { key: "plan.view", label: "View plans", detail: "Read any plan in the workspace." },
@@ -11895,8 +11967,8 @@ function roadmap(overrides) {
11895
11967
  };
11896
11968
  }
11897
11969
  function useSession() {
11898
- const [s, setS] = React62.useState(getSession);
11899
- React62.useEffect(() => subscribe(setS), []);
11970
+ const [s, setS] = React63.useState(getSession);
11971
+ React63.useEffect(() => subscribe(setS), []);
11900
11972
  return s;
11901
11973
  }
11902
11974
  var SessionKit = {
@@ -11929,7 +12001,7 @@ var SessionKit = {
11929
12001
  };
11930
12002
  function DemoSessionProvider({ children }) {
11931
12003
  const session = useSession();
11932
- const value = React62.useMemo(
12004
+ const value = React63.useMemo(
11933
12005
  () => ({
11934
12006
  user: session.user,
11935
12007
  roles: session.roles,
@@ -11945,11 +12017,11 @@ function DemoSessionProvider({ children }) {
11945
12017
  }),
11946
12018
  [session]
11947
12019
  );
11948
- return React62.createElement(SessionProvider, { value }, children);
12020
+ return React63.createElement(SessionProvider, { value }, children);
11949
12021
  }
11950
12022
 
11951
12023
  // src/kits/runtime.ts
11952
- var React63 = __toESM(require("react"), 1);
12024
+ var React64 = __toESM(require("react"), 1);
11953
12025
  var WIRED_ENDPOINTS = [
11954
12026
  // Nothing yet. Every id below would come from a real service:
11955
12027
  // "plan.get", "placements.list", …
@@ -12120,8 +12192,8 @@ var RuntimeKit = {
12120
12192
  };
12121
12193
  RuntimeKit.declare(FEATURE_NEEDS);
12122
12194
  function useRuntimeMode() {
12123
- const [m, setM] = React63.useState(RuntimeKit.getMode());
12124
- React63.useEffect(() => RuntimeKit.subscribe(setM), []);
12195
+ const [m, setM] = React64.useState(RuntimeKit.getMode());
12196
+ React64.useEffect(() => RuntimeKit.subscribe(setM), []);
12125
12197
  return m;
12126
12198
  }
12127
12199
  function useFeatureStatus(key) {
@@ -12140,7 +12212,7 @@ var UseRuntimeMode = useRuntimeMode;
12140
12212
  var UseFeatureStatus = useFeatureStatus;
12141
12213
 
12142
12214
  // src/components/platform/RoadmapTimeline.tsx
12143
- var import_jsx_runtime87 = require("react/jsx-runtime");
12215
+ var import_jsx_runtime89 = require("react/jsx-runtime");
12144
12216
  var STATUS = {
12145
12217
  shipped: { tone: "success", icon: "check-circle", label: "Wired" },
12146
12218
  next: { tone: "warning", icon: "traffic-cone", label: "Not wired" },
@@ -12155,45 +12227,45 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
12155
12227
  const s = STATUS[item.status] || STATUS.planned;
12156
12228
  const deps = (item.dependsOn || []).map((k) => byKey[k]).filter(Boolean);
12157
12229
  const blocking = deps.filter((d) => !d.implemented);
12158
- return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Card, { elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
12159
- /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
12160
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-body", style: { fontWeight: 700, flex: 1, minWidth: 140 }, children: item.label }),
12161
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Badge, { tone: "neutral", icon: PROJECT_ICON[item.project] || "squares-four", children: item.project }),
12162
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Badge, { tone: s.tone, icon: s.icon, children: s.label })
12230
+ return /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(Card, { elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
12231
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
12232
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { className: "fd-body", style: { fontWeight: 700, flex: 1, minWidth: 140 }, children: item.label }),
12233
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(Badge, { tone: "neutral", icon: PROJECT_ICON[item.project] || "squares-four", children: item.project }),
12234
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(Badge, { tone: s.tone, icon: s.icon, children: s.label })
12163
12235
  ] }),
12164
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: item.description }),
12165
- item.backend ? /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start" }, children: [
12166
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-overline fd-muted", style: { width: 62, flex: "none", paddingTop: 2 }, children: "Backend" }),
12167
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-body-sm", style: { flex: 1, textWrap: "pretty" }, children: item.backend })
12236
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: item.description }),
12237
+ item.backend ? /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start" }, children: [
12238
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { className: "fd-overline fd-muted", style: { width: 62, flex: "none", paddingTop: 2 }, children: "Backend" }),
12239
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { className: "fd-body-sm", style: { flex: 1, textWrap: "pretty" }, children: item.backend })
12168
12240
  ] }) : null,
12169
- /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
12170
- item.effort ? /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
12171
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("i", { className: "ph ph-hourglass-medium" }),
12241
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
12242
+ item.effort ? /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
12243
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("i", { className: "ph ph-hourglass-medium" }),
12172
12244
  " ",
12173
12245
  item.effort
12174
12246
  ] }) : null,
12175
- /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
12176
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("i", { className: "ph ph-user" }),
12247
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
12248
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("i", { className: "ph ph-user" }),
12177
12249
  " ",
12178
12250
  item.owner
12179
12251
  ] }),
12180
- item.screen ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Badge, { tone: "neutral", icon: "browser", children: "screen" }) : null,
12181
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { style: { flex: 1 } }),
12182
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
12252
+ item.screen ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(Badge, { tone: "neutral", icon: "browser", children: "screen" }) : null,
12253
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { style: { flex: 1 } }),
12254
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(
12183
12255
  "button",
12184
12256
  {
12185
12257
  type: "button",
12186
12258
  onClick: () => onOpenFlag && onOpenFlag(item.key),
12187
12259
  style: { all: "unset", cursor: "pointer", display: "inline-flex", alignItems: "center", gap: 5 },
12188
- children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("code", { className: "fd-mono", style: { fontSize: 11, color: "var(--brand)" }, children: item.key })
12260
+ children: /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("code", { className: "fd-mono", style: { fontSize: 11, color: "var(--brand)" }, children: item.key })
12189
12261
  }
12190
12262
  )
12191
12263
  ] }),
12192
- deps.length ? /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 6, borderTop: "1px solid var(--border)" }, children: [
12193
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-overline fd-muted", style: { paddingTop: 3 }, children: "After" }),
12194
- deps.map((d) => /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Tag, { icon: d.implemented ? "check" : "clock", children: d.label }, d.key))
12264
+ deps.length ? /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 6, borderTop: "1px solid var(--border)" }, children: [
12265
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { className: "fd-overline fd-muted", style: { paddingTop: 3 }, children: "After" }),
12266
+ deps.map((d) => /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(Tag, { icon: d.implemented ? "check" : "clock", children: d.label }, d.key))
12195
12267
  ] }) : null,
12196
- blocking.length && !item.implemented ? /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("span", { className: "fd-body-sm", style: { color: "var(--warn-text)" }, children: [
12268
+ blocking.length && !item.implemented ? /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("span", { className: "fd-body-sm", style: { color: "var(--warn-text)" }, children: [
12197
12269
  "Blocked until ",
12198
12270
  blocking.map((d) => d.label).join(" and "),
12199
12271
  " ",
@@ -12204,12 +12276,12 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
12204
12276
  }
12205
12277
  function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
12206
12278
  const session = SessionKit.useSession();
12207
- const [project, setProject] = React64.useState("");
12208
- const [q, setQ] = React64.useState("");
12209
- const scrollRef = React64.useRef(null);
12210
- const nowRef = React64.useRef(null);
12211
- const rm = React64.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
12212
- const byKey = React64.useMemo(() => {
12279
+ const [project, setProject] = React65.useState("");
12280
+ const [q, setQ] = React65.useState("");
12281
+ const scrollRef = React65.useRef(null);
12282
+ const nowRef = React65.useRef(null);
12283
+ const rm = React65.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
12284
+ const byKey = React65.useMemo(() => {
12213
12285
  const m = {};
12214
12286
  rm.items.forEach((i) => {
12215
12287
  m[i.key] = i;
@@ -12218,7 +12290,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
12218
12290
  }, [rm]);
12219
12291
  const items = rm.items.filter((i) => (!project || i.project === project) && (!q || (i.label + " " + i.description + " " + (i.backend || "") + " " + i.key).toLowerCase().includes(q.toLowerCase())));
12220
12292
  const projects = [...new Set(rm.items.map((i) => i.project))];
12221
- React64.useEffect(() => {
12293
+ React65.useEffect(() => {
12222
12294
  let raf1 = 0, raf2 = 0;
12223
12295
  const place = () => {
12224
12296
  const box = scrollRef.current, mark = nowRef.current;
@@ -12246,23 +12318,23 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
12246
12318
  }, 0);
12247
12319
  const nextPhase = items.find((i) => !i.implemented);
12248
12320
  let lastPhase = null;
12249
- return /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-stack", style: { gap: 16, maxWidth: 1e3 }, children: [
12250
- /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
12251
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-overline fd-muted", children: "Architecture" }),
12252
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
12253
- /* @__PURE__ */ (0, import_jsx_runtime87.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." })
12321
+ return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "fd-stack", style: { gap: 16, maxWidth: 1e3 }, children: [
12322
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
12323
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { className: "fd-overline fd-muted", children: "Architecture" }),
12324
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
12325
+ /* @__PURE__ */ (0, import_jsx_runtime89.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." })
12254
12326
  ] }),
12255
- /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-grid-stats is-thin", children: [
12256
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(StatTile, { compact: true, label: "Wired", value: String(rm.shipped), sub: "of " + rm.items.length + " features" }),
12257
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(StatTile, { compact: true, label: "Remaining", value: String(rm.remaining), sub: "backend work" }),
12258
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(StatTile, { compact: true, label: "Est. effort", value: days ? days + " days" : "\u2014", sub: "sum of estimates, not calendar" }),
12259
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(StatTile, { compact: true, label: "Up next", value: nextPhase ? "Phase " + nextPhase.phase : "\u2014", sub: nextPhase ? nextPhase.phaseName : "all wired" })
12327
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "fd-grid-stats is-thin", children: [
12328
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(StatTile, { compact: true, label: "Wired", value: String(rm.shipped), sub: "of " + rm.items.length + " features" }),
12329
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(StatTile, { compact: true, label: "Remaining", value: String(rm.remaining), sub: "backend work" }),
12330
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(StatTile, { compact: true, label: "Est. effort", value: days ? days + " days" : "\u2014", sub: "sum of estimates, not calendar" }),
12331
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(StatTile, { compact: true, label: "Up next", value: nextPhase ? "Phase " + nextPhase.phase : "\u2014", sub: nextPhase ? nextPhase.phaseName : "all wired" })
12260
12332
  ] }),
12261
- /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
12262
- /* @__PURE__ */ (0, import_jsx_runtime87.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 } }),
12263
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Select, { placeholder: "All projects", value: project, onChange: (e) => setProject(e.target.value), options: projects, style: { width: 190 } }),
12264
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { style: { flex: 1 } }),
12265
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
12333
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
12334
+ /* @__PURE__ */ (0, import_jsx_runtime89.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 } }),
12335
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(Select, { placeholder: "All projects", value: project, onChange: (e) => setProject(e.target.value), options: projects, style: { width: 190 } }),
12336
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { style: { flex: 1 } }),
12337
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(
12266
12338
  Button,
12267
12339
  {
12268
12340
  size: "sm",
@@ -12276,7 +12348,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
12276
12348
  }
12277
12349
  )
12278
12350
  ] }),
12279
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
12351
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(
12280
12352
  Flag,
12281
12353
  {
12282
12354
  tone: "info",
@@ -12285,60 +12357,60 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
12285
12357
  actions: null
12286
12358
  }
12287
12359
  ),
12288
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("div", { className: "fd-rm", children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("div", { className: "fd-rm-scroll", ref: scrollRef, children: /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-rm-track", children: [
12289
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-rm-spine", children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-rm-spine-done", style: { height: items.length ? 100 * shippedShown / items.length + "%" : "0%" } }) }),
12360
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("div", { className: "fd-rm", children: /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("div", { className: "fd-rm-scroll", ref: scrollRef, children: /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "fd-rm-track", children: [
12361
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { className: "fd-rm-spine", children: /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { className: "fd-rm-spine-done", style: { height: items.length ? 100 * shippedShown / items.length + "%" : "0%" } }) }),
12290
12362
  items.map((item, n) => {
12291
12363
  const showPhase = item.phase !== lastPhase;
12292
12364
  lastPhase = item.phase;
12293
12365
  const inPhase = items.filter((i) => i.phase === item.phase).length;
12294
12366
  const isBoundary = n === firstPending;
12295
- return /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(React64.Fragment, { children: [
12296
- showPhase ? /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-rm-era", children: [
12297
- /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
12298
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
12299
- item.phase === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("span", { className: "fd-mono", style: { opacity: 0.7, fontWeight: 400 }, children: [
12367
+ return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)(React65.Fragment, { children: [
12368
+ showPhase ? /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "fd-rm-era", children: [
12369
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
12370
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
12371
+ item.phase === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("span", { className: "fd-mono", style: { opacity: 0.7, fontWeight: 400 }, children: [
12300
12372
  fmtDate(item.phaseStart),
12301
12373
  " \u2013 ",
12302
12374
  fmtDate(item.date)
12303
12375
  ] }),
12304
- /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("span", { style: { opacity: 0.7, fontWeight: 400 }, children: [
12376
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("span", { style: { opacity: 0.7, fontWeight: 400 }, children: [
12305
12377
  "\xB7 ",
12306
12378
  inPhase,
12307
12379
  " feature",
12308
12380
  inPhase === 1 ? "" : "s"
12309
12381
  ] })
12310
12382
  ] }),
12311
- item.phaseWhy ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("p", { className: "fd-rm-era-why", children: item.phaseWhy }) : null
12383
+ item.phaseWhy ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("p", { className: "fd-rm-era-why", children: item.phaseWhy }) : null
12312
12384
  ] }) : null,
12313
- isBoundary ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("div", { className: "fd-rm-now", ref: nowRef, children: /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("span", { className: "fd-rm-now-pill", children: [
12314
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("i", { className: "ph ph-map-pin" }),
12385
+ isBoundary ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("div", { className: "fd-rm-now", ref: nowRef, children: /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("span", { className: "fd-rm-now-pill", children: [
12386
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("i", { className: "ph ph-map-pin" }),
12315
12387
  " You are here \u2014 everything above is wired"
12316
12388
  ] }) }) : null,
12317
- /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-rm-row", children: [
12318
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-rm-dot " + (item.implemented ? "is-shipped" : item.status === "next" ? "is-next" : "") }),
12319
- /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-rm-date", children: [
12389
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "fd-rm-row", children: [
12390
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { className: "fd-rm-dot " + (item.implemented ? "is-shipped" : item.status === "next" ? "is-next" : "") }),
12391
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "fd-rm-date", children: [
12320
12392
  fmtDate(item.date),
12321
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("br", {}),
12322
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { style: { opacity: 0.75 }, children: item.implemented ? "shipped" : "phase " + item.phase })
12393
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("br", {}),
12394
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { style: { opacity: 0.75 }, children: item.implemented ? "shipped" : "phase " + item.phase })
12323
12395
  ] }),
12324
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(RoadmapCard, { item, byKey, onOpenFlag })
12396
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(RoadmapCard, { item, byKey, onOpenFlag })
12325
12397
  ] })
12326
12398
  ] }, item.key);
12327
12399
  }),
12328
- !items.length ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("p", { className: "fd-body-sm fd-muted", children: "Nothing matches that filter." }) : null
12400
+ !items.length ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("p", { className: "fd-body-sm fd-muted", children: "Nothing matches that filter." }) : null
12329
12401
  ] }) }) }),
12330
- /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: [
12402
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: [
12331
12403
  "Derived from the feature-flag registry \u2014 each entry's status is its flag's ",
12332
- /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("code", { className: "fd-mono", children: "implemented" }),
12404
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("code", { className: "fd-mono", children: "implemented" }),
12333
12405
  " field, so this page cannot drift from what the apps actually do."
12334
12406
  ] })
12335
12407
  ] });
12336
12408
  }
12337
12409
 
12338
12410
  // src/components/platform/ComingSoon.tsx
12339
- var React65 = __toESM(require("react"), 1);
12411
+ var React66 = __toESM(require("react"), 1);
12340
12412
  var import_react_dom7 = require("react-dom");
12341
- var import_jsx_runtime88 = require("react/jsx-runtime");
12413
+ var import_jsx_runtime90 = require("react/jsx-runtime");
12342
12414
  var BYPASS_STORE = "fd.soon.bypass.v1";
12343
12415
  function readBypassed() {
12344
12416
  try {
@@ -12354,8 +12426,8 @@ function writeBypassed(list) {
12354
12426
  }
12355
12427
  }
12356
12428
  function useBypass(key) {
12357
- const [on, setOn] = React65.useState(() => !!key && readBypassed().indexOf(key) >= 0);
12358
- React65.useEffect(() => {
12429
+ const [on, setOn] = React66.useState(() => !!key && readBypassed().indexOf(key) >= 0);
12430
+ React66.useEffect(() => {
12359
12431
  setOn(!!key && readBypassed().indexOf(key) >= 0);
12360
12432
  }, [key]);
12361
12433
  const set = (next) => {
@@ -12368,43 +12440,43 @@ function useBypass(key) {
12368
12440
  return [on, set];
12369
12441
  }
12370
12442
  function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass }) {
12371
- return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)(import_jsx_runtime88.Fragment, { children: [
12372
- /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("span", { className: "fd-soon-badge", children: [
12373
- /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
12443
+ return /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)(import_jsx_runtime90.Fragment, { children: [
12444
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("span", { className: "fd-soon-badge", children: [
12445
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
12374
12446
  label
12375
12447
  ] }),
12376
- detail ? /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "fd-soon-detail", children: detail }) : null,
12377
- backend ? /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("span", { className: "fd-soon-backend", children: [
12378
- /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "fd-overline", children: "Needs" }),
12448
+ detail ? /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("span", { className: "fd-soon-detail", children: detail }) : null,
12449
+ backend ? /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("span", { className: "fd-soon-backend", children: [
12450
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("span", { className: "fd-overline", children: "Needs" }),
12379
12451
  " ",
12380
12452
  backend
12381
12453
  ] }) : null,
12382
- eta || effort || onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("span", { className: "fd-soon-meta", children: [
12383
- eta ? /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("span", { children: [
12384
- /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }),
12454
+ eta || effort || onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("span", { className: "fd-soon-meta", children: [
12455
+ eta ? /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("span", { children: [
12456
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }),
12385
12457
  " ",
12386
12458
  eta
12387
12459
  ] }) : null,
12388
- effort ? /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("span", { children: [
12389
- /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("i", { className: "ph ph-hourglass-medium", "aria-hidden": "true" }),
12460
+ effort ? /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("span", { children: [
12461
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("i", { className: "ph ph-hourglass-medium", "aria-hidden": "true" }),
12390
12462
  " ",
12391
12463
  effort
12392
12464
  ] }) : null,
12393
- onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
12465
+ onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
12394
12466
  "See the roadmap ",
12395
- /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
12467
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
12396
12468
  ] }) : null
12397
12469
  ] }) : null,
12398
- allowed ? /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("button", { type: "button", className: "fd-soon-view", onClick: onBypass, children: [
12399
- /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("i", { className: "ph ph-eye", "aria-hidden": "true" }),
12470
+ allowed ? /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("button", { type: "button", className: "fd-soon-view", onClick: onBypass, children: [
12471
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("i", { className: "ph ph-eye", "aria-hidden": "true" }),
12400
12472
  " View and use it anyway"
12401
12473
  ] }) : null
12402
12474
  ] });
12403
12475
  }
12404
12476
  function useHoverCard(open2) {
12405
- const anchor = React65.useRef(null);
12406
- const [pos, setPos] = React65.useState(null);
12407
- React65.useLayoutEffect(() => {
12477
+ const anchor = React66.useRef(null);
12478
+ const [pos, setPos] = React66.useState(null);
12479
+ React66.useLayoutEffect(() => {
12408
12480
  if (!open2 || !anchor.current) {
12409
12481
  setPos(null);
12410
12482
  return;
@@ -12456,9 +12528,9 @@ function ComingSoon({
12456
12528
  const tip = [label, detail, backend ? "Needs " + backend : null, eta ? "ETA " + eta : null, effort].filter(Boolean).join(" \xB7 ");
12457
12529
  if (inline) {
12458
12530
  if (allowed && bypassed) {
12459
- return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("span", { className: ["fd-soon-inline-on", className].filter(Boolean).join(" "), ...rest, children: [
12531
+ return /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("span", { className: ["fd-soon-inline-on", className].filter(Boolean).join(" "), ...rest, children: [
12460
12532
  children,
12461
- /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
12533
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
12462
12534
  "button",
12463
12535
  {
12464
12536
  type: "button",
@@ -12466,12 +12538,12 @@ function ComingSoon({
12466
12538
  title: "Unwired \u2014 writes go to the simulated backend. " + tip + " Click to re-blur.",
12467
12539
  onClick: () => setBypassed(false),
12468
12540
  "aria-label": "Re-blur this unwired feature",
12469
- children: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
12541
+ children: /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
12470
12542
  }
12471
12543
  )
12472
12544
  ] });
12473
12545
  }
12474
- return /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
12546
+ return /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
12475
12547
  InlineSoon,
12476
12548
  {
12477
12549
  label,
@@ -12491,20 +12563,20 @@ function ComingSoon({
12491
12563
  );
12492
12564
  }
12493
12565
  if (allowed && bypassed) {
12494
- return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, ...rest, children: [
12495
- /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "fd-soon-bar", role: "status", children: [
12496
- /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("span", { className: "fd-soon-badge", children: [
12497
- /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
12566
+ return /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, ...rest, children: [
12567
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("div", { className: "fd-soon-bar", role: "status", children: [
12568
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("span", { className: "fd-soon-badge", children: [
12569
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
12498
12570
  "Unwired feature \u2014 you are using it anyway"
12499
12571
  ] }),
12500
- /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "fd-soon-bar-detail", children: "Every action here writes to the simulated backend, so nothing you do persists beyond this session." }),
12501
- /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("span", { className: "fd-soon-bar-actions", children: [
12502
- onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
12572
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("span", { className: "fd-soon-bar-detail", children: "Every action here writes to the simulated backend, so nothing you do persists beyond this session." }),
12573
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("span", { className: "fd-soon-bar-actions", children: [
12574
+ onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
12503
12575
  "Roadmap ",
12504
- /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
12576
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
12505
12577
  ] }) : null,
12506
- /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => setBypassed(false), children: [
12507
- /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("i", { className: "ph ph-eye-slash", "aria-hidden": "true" }),
12578
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => setBypassed(false), children: [
12579
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("i", { className: "ph ph-eye-slash", "aria-hidden": "true" }),
12508
12580
  " Re-blur"
12509
12581
  ] })
12510
12582
  ] })
@@ -12512,10 +12584,10 @@ function ComingSoon({
12512
12584
  children
12513
12585
  ] });
12514
12586
  }
12515
- return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: ["fd-soon", className].filter(Boolean).join(" "), style: minHeight ? { minHeight } : void 0, ...rest, children: [
12516
- /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("div", { className: "fd-soon-under", style: { filter: "blur(" + blur + "px) saturate(.62)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
12517
- /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("div", { className: "fd-soon-veil" }),
12518
- /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("div", { className: "fd-soon-note", role: "note", children: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
12587
+ return /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("div", { className: ["fd-soon", className].filter(Boolean).join(" "), style: minHeight ? { minHeight } : void 0, ...rest, children: [
12588
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("div", { className: "fd-soon-under", style: { filter: "blur(" + blur + "px) saturate(.62)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
12589
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("div", { className: "fd-soon-veil" }),
12590
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("div", { className: "fd-soon-note", role: "note", children: /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
12519
12591
  SoonCard,
12520
12592
  {
12521
12593
  label,
@@ -12531,12 +12603,12 @@ function ComingSoon({
12531
12603
  ] });
12532
12604
  }
12533
12605
  function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass, blur, tip, className, rest, children }) {
12534
- const [open2, setOpen] = React65.useState(false);
12606
+ const [open2, setOpen] = React66.useState(false);
12535
12607
  const [anchor, pos] = useHoverCard(open2);
12536
- const hoverCardRef = React65.useRef(null);
12608
+ const hoverCardRef = React66.useRef(null);
12537
12609
  const hoverLayer = useStackedLayer({ active: open2, containerRef: hoverCardRef, returnFocus: false });
12538
12610
  const zIndex = useLayerZIndex(hoverLayer);
12539
- const close2 = React65.useRef(null);
12611
+ const close2 = React66.useRef(null);
12540
12612
  const show = () => {
12541
12613
  if (close2.current) {
12542
12614
  clearTimeout(close2.current);
@@ -12552,10 +12624,10 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
12552
12624
  setOpen(false);
12553
12625
  }, 140);
12554
12626
  };
12555
- React65.useEffect(() => () => {
12627
+ React66.useEffect(() => () => {
12556
12628
  if (close2.current) clearTimeout(close2.current);
12557
12629
  }, []);
12558
- return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)(
12630
+ return /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)(
12559
12631
  "span",
12560
12632
  {
12561
12633
  ref: anchor,
@@ -12566,8 +12638,8 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
12566
12638
  onBlur: hide,
12567
12639
  ...rest,
12568
12640
  children: [
12569
- /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "fd-soon-under", style: { filter: "blur(" + Math.min(blur, 1.1) + "px) saturate(.66)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
12570
- /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
12641
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("span", { className: "fd-soon-under", style: { filter: "blur(" + Math.min(blur, 1.1) + "px) saturate(.66)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
12642
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
12571
12643
  "button",
12572
12644
  {
12573
12645
  type: "button",
@@ -12578,11 +12650,11 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
12578
12650
  onFocus: show,
12579
12651
  onBlur: hide,
12580
12652
  onClick: () => open2 ? setOpen(false) : show(),
12581
- children: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
12653
+ children: /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
12582
12654
  }
12583
12655
  ),
12584
12656
  open2 && pos ? (0, import_react_dom7.createPortal)(
12585
- /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
12657
+ /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
12586
12658
  "div",
12587
12659
  {
12588
12660
  ref: hoverCardRef,
@@ -12591,7 +12663,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
12591
12663
  style: { position: "fixed", left: pos.left, top: pos.top, bottom: pos.bottom, width: pos.width, zIndex },
12592
12664
  onMouseEnter: show,
12593
12665
  onMouseLeave: hide,
12594
- children: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
12666
+ children: /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
12595
12667
  SoonCard,
12596
12668
  {
12597
12669
  label,
@@ -12621,10 +12693,10 @@ function formatEta(iso2) {
12621
12693
  var FormatEta = formatEta;
12622
12694
 
12623
12695
  // src/components/platform/Gate.tsx
12624
- var import_jsx_runtime89 = require("react/jsx-runtime");
12696
+ var import_jsx_runtime91 = require("react/jsx-runtime");
12625
12697
  function PermissionDenied({ permission, title, detail, compact: compact3 = false, className = "", ...rest }) {
12626
12698
  const need = Array.isArray(permission) ? permission : [permission].filter(Boolean);
12627
- return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)(
12699
+ return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(
12628
12700
  "div",
12629
12701
  {
12630
12702
  className: ["fd-stack", className].filter(Boolean).join(" "),
@@ -12640,14 +12712,14 @@ function PermissionDenied({ permission, title, detail, compact: compact3 = false
12640
12712
  },
12641
12713
  ...rest,
12642
12714
  children: [
12643
- /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("span", { className: "fd-row", style: { gap: 8 }, children: [
12644
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("i", { className: "ph ph-lock-simple", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
12645
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { className: compact3 ? "fd-label-lg" : "fd-h3", children: title || "You do not have access to this" })
12715
+ /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("span", { className: "fd-row", style: { gap: 8 }, children: [
12716
+ /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("i", { className: "ph ph-lock-simple", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
12717
+ /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("span", { className: compact3 ? "fd-label-lg" : "fd-h3", children: title || "You do not have access to this" })
12646
12718
  ] }),
12647
- /* @__PURE__ */ (0, import_jsx_runtime89.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." }),
12648
- need.length ? /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: [
12649
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { className: "fd-overline fd-muted", children: "Requires" }),
12650
- need.map((p) => /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("code", { className: "fd-mono", style: {
12719
+ /* @__PURE__ */ (0, import_jsx_runtime91.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." }),
12720
+ need.length ? /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: [
12721
+ /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("span", { className: "fd-overline fd-muted", children: "Requires" }),
12722
+ need.map((p) => /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("code", { className: "fd-mono", style: {
12651
12723
  fontSize: 11.5,
12652
12724
  padding: "2px 7px",
12653
12725
  borderRadius: 5,
@@ -12660,7 +12732,7 @@ function PermissionDenied({ permission, title, detail, compact: compact3 = false
12660
12732
  );
12661
12733
  }
12662
12734
  function GatePending({ compact: compact3 = false, className = "" }) {
12663
- return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)(
12735
+ return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(
12664
12736
  "div",
12665
12737
  {
12666
12738
  className: ["fd-stack", className].filter(Boolean).join(" "),
@@ -12676,11 +12748,11 @@ function GatePending({ compact: compact3 = false, className = "" }) {
12676
12748
  textAlign: "left"
12677
12749
  },
12678
12750
  children: [
12679
- /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("span", { className: "fd-row", style: { gap: 8 }, children: [
12680
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("i", { className: "ph ph-arrows-clockwise", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
12681
- /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { className: compact3 ? "fd-label-lg" : "fd-h3", children: "Reconnecting\u2026" })
12751
+ /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("span", { className: "fd-row", style: { gap: 8 }, children: [
12752
+ /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("i", { className: "ph ph-arrows-clockwise", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
12753
+ /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("span", { className: compact3 ? "fd-label-lg" : "fd-h3", children: "Reconnecting\u2026" })
12682
12754
  ] }),
12683
- /* @__PURE__ */ (0, import_jsx_runtime89.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." })
12755
+ /* @__PURE__ */ (0, import_jsx_runtime91.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." })
12684
12756
  ]
12685
12757
  }
12686
12758
  );
@@ -12690,7 +12762,7 @@ function Gate({ perm, anyOf, role, silent = false, fallback, pendingFallback, co
12690
12762
  if (pending) {
12691
12763
  if (pendingFallback !== void 0) return pendingFallback;
12692
12764
  if (silent) return null;
12693
- return /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(GatePending, { compact: compact3 });
12765
+ return /* @__PURE__ */ (0, import_jsx_runtime91.jsx)(GatePending, { compact: compact3 });
12694
12766
  }
12695
12767
  let ok = true;
12696
12768
  if (perm) ok = ok && can2(perm);
@@ -12699,7 +12771,7 @@ function Gate({ perm, anyOf, role, silent = false, fallback, pendingFallback, co
12699
12771
  if (ok) return children;
12700
12772
  if (fallback !== void 0) return fallback;
12701
12773
  if (silent) return null;
12702
- return /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(PermissionDenied, { permission: perm || anyOf, compact: compact3 });
12774
+ return /* @__PURE__ */ (0, import_jsx_runtime91.jsx)(PermissionDenied, { permission: perm || anyOf, compact: compact3 });
12703
12775
  }
12704
12776
  function FeatureGate({
12705
12777
  flag,
@@ -12722,7 +12794,7 @@ function FeatureGate({
12722
12794
  const f = SessionKit.findFlag(flag) || {};
12723
12795
  const missing = rt.missing || [];
12724
12796
  const canBypass = pending ? false : bypassPerm === null ? false : !bypassPerm || can2(bypassPerm);
12725
- return /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(
12797
+ return /* @__PURE__ */ (0, import_jsx_runtime91.jsx)(
12726
12798
  ComingSoon,
12727
12799
  {
12728
12800
  label: label || (variant === "inline" ? f.label || "Not wired yet" : "Designed \u2014 backend not wired yet"),
@@ -12743,22 +12815,22 @@ function FeatureGate({
12743
12815
  function PermissionHint({ perm, children }) {
12744
12816
  const { can: can2, pending } = useSessionContext();
12745
12817
  if (pending) {
12746
- return /* @__PURE__ */ (0, import_jsx_runtime89.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_runtime89.jsx)("span", { style: { pointerEvents: "none" }, children }) });
12818
+ return /* @__PURE__ */ (0, import_jsx_runtime91.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_runtime91.jsx)("span", { style: { pointerEvents: "none" }, children }) });
12747
12819
  }
12748
12820
  if (can2(perm)) return children;
12749
- return /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(
12821
+ return /* @__PURE__ */ (0, import_jsx_runtime91.jsx)(
12750
12822
  "span",
12751
12823
  {
12752
12824
  title: "Requires " + (Array.isArray(perm) ? perm.join(", ") : perm),
12753
12825
  style: { display: "inline-flex", opacity: 0.45, cursor: "not-allowed" },
12754
12826
  "aria-disabled": "true",
12755
- children: /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { style: { pointerEvents: "none" }, children })
12827
+ children: /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("span", { style: { pointerEvents: "none" }, children })
12756
12828
  }
12757
12829
  );
12758
12830
  }
12759
12831
 
12760
12832
  // src/components/platform/ModeSwitch.tsx
12761
- var import_jsx_runtime90 = require("react/jsx-runtime");
12833
+ var import_jsx_runtime92 = require("react/jsx-runtime");
12762
12834
  function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
12763
12835
  const mode2 = useRuntimeMode();
12764
12836
  const panel = useInlinePanel();
@@ -12770,8 +12842,8 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
12770
12842
  RuntimeKit.setMode(next);
12771
12843
  setOpen(false);
12772
12844
  };
12773
- return /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("span", { style: { display: "inline-flex" }, ref, children: [
12774
- /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)(
12845
+ return /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("span", { style: { display: "inline-flex" }, ref, children: [
12846
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)(
12775
12847
  "button",
12776
12848
  {
12777
12849
  type: "button",
@@ -12781,29 +12853,29 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
12781
12853
  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.",
12782
12854
  className: "fd-mode-btn" + (test ? " is-test" : "") + (open2 ? " is-open" : ""),
12783
12855
  children: [
12784
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), style: { fontSize: 17 } }),
12785
- test && requestCount ? /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("span", { className: "fd-mono fd-mode-count", children: requestCount > 99 ? "99+" : requestCount }, requestCount) : null
12856
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), style: { fontSize: 17 } }),
12857
+ test && requestCount ? /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("span", { className: "fd-mono fd-mode-count", children: requestCount > 99 ? "99+" : requestCount }, requestCount) : null
12786
12858
  ]
12787
12859
  }
12788
12860
  ),
12789
- /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)(InlinePanelSurface, { panel, align: "right", offset: 8, width: 400, className: "fd-mode-pop", label: test ? "Test mode" : "Live mode", children: [
12790
- /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("span", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
12791
- /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("span", { className: "fd-badge " + (test ? "fd-badge-warning" : "fd-badge-neutral"), children: [
12792
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), "aria-hidden": "true" }),
12861
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)(InlinePanelSurface, { panel, align: "right", offset: 8, width: 400, className: "fd-mode-pop", label: test ? "Test mode" : "Live mode", children: [
12862
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("span", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
12863
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("span", { className: "fd-badge " + (test ? "fd-badge-warning" : "fd-badge-neutral"), children: [
12864
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), "aria-hidden": "true" }),
12793
12865
  test ? "Test mode" : "Live mode"
12794
12866
  ] }),
12795
- test ? /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
12867
+ test ? /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
12796
12868
  requestCount,
12797
12869
  " simulated request",
12798
12870
  requestCount === 1 ? "" : "s"
12799
12871
  ] }) : null,
12800
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("span", { style: { flex: 1 } }),
12801
- test && onClearLog ? /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("button", { type: "button", className: "fd-soon-link", onClick: onClearLog, children: "Clear" }) : null
12872
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("span", { style: { flex: 1 } }),
12873
+ test && onClearLog ? /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("button", { type: "button", className: "fd-soon-link", onClick: onClearLog, children: "Clear" }) : null
12802
12874
  ] }),
12803
- /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("span", { style: { display: "block", padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
12804
- /* @__PURE__ */ (0, import_jsx_runtime90.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." }),
12805
- /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("span", { className: "fd-row", style: { gap: 8, marginTop: 10, flexWrap: "wrap" }, children: [
12806
- /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
12875
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("span", { style: { display: "block", padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
12876
+ /* @__PURE__ */ (0, import_jsx_runtime92.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." }),
12877
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("span", { className: "fd-row", style: { gap: 8, marginTop: 10, flexWrap: "wrap" }, children: [
12878
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
12807
12879
  s.endpointsWired,
12808
12880
  " endpoint",
12809
12881
  s.endpointsWired === 1 ? "" : "s",
@@ -12813,58 +12885,58 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
12813
12885
  s.total,
12814
12886
  " features complete"
12815
12887
  ] }),
12816
- onOpenSpec ? /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)(import_jsx_runtime90.Fragment, { children: [
12817
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("span", { style: { flex: 1 } }),
12818
- /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => {
12888
+ onOpenSpec ? /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)(import_jsx_runtime92.Fragment, { children: [
12889
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("span", { style: { flex: 1 } }),
12890
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => {
12819
12891
  setOpen(false);
12820
12892
  onOpenSpec();
12821
12893
  }, children: [
12822
12894
  "API spec ",
12823
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
12895
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
12824
12896
  ] })
12825
12897
  ] }) : null
12826
12898
  ] })
12827
12899
  ] }),
12828
- /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("span", { className: "fd-mode-choice", children: [
12829
- /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("button", { type: "button", className: "fd-mode-opt" + (!test ? " is-on" : ""), onClick: () => go("live"), children: [
12830
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
12831
- /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("span", { className: "fd-mode-opt-text", children: [
12832
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("span", { className: "fd-mode-opt-title", children: "Live mode" }),
12833
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("span", { className: "fd-mode-opt-desc", children: "Incomplete features under construction" })
12900
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("span", { className: "fd-mode-choice", children: [
12901
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("button", { type: "button", className: "fd-mode-opt" + (!test ? " is-on" : ""), onClick: () => go("live"), children: [
12902
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
12903
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("span", { className: "fd-mode-opt-text", children: [
12904
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("span", { className: "fd-mode-opt-title", children: "Live mode" }),
12905
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("span", { className: "fd-mode-opt-desc", children: "Incomplete features under construction" })
12834
12906
  ] }),
12835
- !test ? /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
12907
+ !test ? /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
12836
12908
  ] }),
12837
- /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("button", { type: "button", className: "fd-mode-opt" + (test ? " is-on" : ""), onClick: () => go("test"), children: [
12838
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("i", { className: "ph ph-flask", "aria-hidden": "true" }),
12839
- /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("span", { className: "fd-mode-opt-text", children: [
12840
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("span", { className: "fd-mode-opt-title", children: "Test mode" }),
12841
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("span", { className: "fd-mode-opt-desc", children: "Everything usable, all data simulated" })
12909
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("button", { type: "button", className: "fd-mode-opt" + (test ? " is-on" : ""), onClick: () => go("test"), children: [
12910
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("i", { className: "ph ph-flask", "aria-hidden": "true" }),
12911
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("span", { className: "fd-mode-opt-text", children: [
12912
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("span", { className: "fd-mode-opt-title", children: "Test mode" }),
12913
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("span", { className: "fd-mode-opt-desc", children: "Everything usable, all data simulated" })
12842
12914
  ] }),
12843
- test ? /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
12915
+ test ? /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
12844
12916
  ] })
12845
12917
  ] }),
12846
- test && renderLog ? /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("span", { style: { display: "block", maxHeight: 340, overflowY: "auto", borderTop: "1px solid var(--border)" }, children: renderLog() }) : null
12918
+ test && renderLog ? /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("span", { style: { display: "block", maxHeight: 340, overflowY: "auto", borderTop: "1px solid var(--border)" }, children: renderLog() }) : null
12847
12919
  ] })
12848
12920
  ] });
12849
12921
  }
12850
12922
  function TestModeBar({ onExit }) {
12851
12923
  const mode2 = useRuntimeMode();
12852
12924
  if (mode2 !== "test") return null;
12853
- return /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("div", { className: "fd-testbar", role: "status", children: [
12854
- /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("span", { className: "fd-badge fd-badge-warning", children: [
12855
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("i", { className: "ph ph-flask", "aria-hidden": "true" }),
12925
+ return /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("div", { className: "fd-testbar", role: "status", children: [
12926
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("span", { className: "fd-badge fd-badge-warning", children: [
12927
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("i", { className: "ph ph-flask", "aria-hidden": "true" }),
12856
12928
  "Test mode"
12857
12929
  ] }),
12858
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("span", { className: "fd-testbar-detail", children: "Every feature is unlocked and every response is simulated \u2014 nothing here persists." }),
12859
- /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => onExit ? onExit() : RuntimeKit.setMode("live"), children: [
12860
- /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
12930
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("span", { className: "fd-testbar-detail", children: "Every feature is unlocked and every response is simulated \u2014 nothing here persists." }),
12931
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => onExit ? onExit() : RuntimeKit.setMode("live"), children: [
12932
+ /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
12861
12933
  " Back to live mode"
12862
12934
  ] })
12863
12935
  ] });
12864
12936
  }
12865
12937
 
12866
12938
  // src/components/planner/ChannelMeta.tsx
12867
- var import_jsx_runtime91 = require("react/jsx-runtime");
12939
+ var import_jsx_runtime93 = require("react/jsx-runtime");
12868
12940
  var CHANNEL_WEIGHTS = {
12869
12941
  "OOH": 50,
12870
12942
  "DOOH": 50,
@@ -12917,9 +12989,9 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
12917
12989
  const m = ChannelMeta(channel);
12918
12990
  const wt = channelWeightOf(channel || "");
12919
12991
  if (dot) {
12920
- return /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("span", { className: ["fd-chan-dot", className].filter(Boolean).join(" "), title: m.name, style: { background: m.color }, ...rest });
12992
+ return /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("span", { className: ["fd-chan-dot", className].filter(Boolean).join(" "), title: m.name, style: { background: m.color }, ...rest });
12921
12993
  }
12922
- return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(
12994
+ return /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)(
12923
12995
  "span",
12924
12996
  {
12925
12997
  className: ["fd-chan", size === "sm" ? "fd-chan-sm" : "", className].filter(Boolean).join(" "),
@@ -12927,16 +12999,16 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
12927
12999
  style: { "--chan": m.color },
12928
13000
  ...rest,
12929
13001
  children: [
12930
- /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }),
12931
- showLabel ? /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("span", { className: "fd-chan-label", children: m.label }) : null,
12932
- weight ? /* @__PURE__ */ (0, import_jsx_runtime91.jsx)("span", { className: "fd-chan-weight", children: wt || 0 }) : null
13002
+ /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }),
13003
+ showLabel ? /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("span", { className: "fd-chan-label", children: m.label }) : null,
13004
+ weight ? /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("span", { className: "fd-chan-weight", children: wt || 0 }) : null
12933
13005
  ]
12934
13006
  }
12935
13007
  );
12936
13008
  }
12937
13009
 
12938
13010
  // src/components/planner/SaturationDistribution.tsx
12939
- var import_jsx_runtime92 = require("react/jsx-runtime");
13011
+ var import_jsx_runtime94 = require("react/jsx-runtime");
12940
13012
  var BANDS2 = [
12941
13013
  { key: "weak", label: "Weak", n: 1, range: "< 50" },
12942
13014
  { key: "adequate", label: "Adequate", n: 2, range: "50\u2013100" },
@@ -12947,24 +13019,24 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
12947
13019
  const grouped = BANDS2.map((b) => ({ ...b, items: campuses.filter((c) => c.band === b.key) }));
12948
13020
  const tallest = Math.max(1, ...grouped.map((g) => g.items.length));
12949
13021
  const floor = BANDS2.find((b) => b.key === floorBand) || BANDS2[0];
12950
- return /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
12951
- /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("div", { style: { display: "grid", gridTemplateColumns: "repeat(4,minmax(0,1fr))", gap: 12, alignItems: "end" }, children: grouped.map((g) => {
13022
+ return /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
13023
+ /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("div", { style: { display: "grid", gridTemplateColumns: "repeat(4,minmax(0,1fr))", gap: 12, alignItems: "end" }, children: grouped.map((g) => {
12952
13024
  const mark = "var(--csi-" + g.n + "-mark)";
12953
13025
  const active = selectedBand === g.key;
12954
- return /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)(
13026
+ return /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)(
12955
13027
  "button",
12956
13028
  {
12957
13029
  type: "button",
12958
13030
  onClick: onSelectBand ? () => onSelectBand(active ? null : g.key) : void 0,
12959
13031
  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)" },
12960
13032
  children: [
12961
- /* @__PURE__ */ (0, import_jsx_runtime92.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_runtime92.jsx)("span", { className: "fd-skel", style: { height: 16, borderRadius: 4 } }, i)) : g.items.map((c) => (
13033
+ /* @__PURE__ */ (0, import_jsx_runtime94.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_runtime94.jsx)("span", { className: "fd-skel", style: { height: 16, borderRadius: 4 } }, i)) : g.items.map((c) => (
12962
13034
  // `overflow: hidden` + `white-space: nowrap` only clips once the span
12963
13035
  // actually HAS a bounded width to clip against (see the grid/flex
12964
13036
  // `minWidth: 0` chain above) — `textOverflow: ellipsis` then makes
12965
13037
  // that clip readable instead of a hard cut mid-letter; the full name
12966
13038
  // is still one hover away via `title`.
12967
- /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(
13039
+ /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(
12968
13040
  "span",
12969
13041
  {
12970
13042
  title: c.name + " \xB7 " + c.crp,
@@ -12974,13 +13046,13 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
12974
13046
  c.name
12975
13047
  )
12976
13048
  )) }),
12977
- /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("span", { className: "fd-row", style: { gap: 8, alignItems: "baseline" }, children: [
12978
- /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("span", { className: "fd-num-hero", style: { fontSize: 30, color: g.items.length ? "var(--text)" : "var(--text-disabled)" }, children: loading ? "\u2013" : g.items.length }),
12979
- /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("span", { className: "fd-meter", style: { gap: 2, color: mark }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("span", { className: "fd-meter-seg" + (i <= g.n ? " is-on" : ""), style: { width: 4, height: 9 } }, i)) })
13049
+ /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("span", { className: "fd-row", style: { gap: 8, alignItems: "baseline" }, children: [
13050
+ /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fd-num-hero", style: { fontSize: 30, color: g.items.length ? "var(--text)" : "var(--text-disabled)" }, children: loading ? "\u2013" : g.items.length }),
13051
+ /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fd-meter", style: { gap: 2, color: mark }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fd-meter-seg" + (i <= g.n ? " is-on" : ""), style: { width: 4, height: 9 } }, i)) })
12980
13052
  ] }),
12981
- /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("span", { className: "fd-stack", style: { gap: 1 }, children: [
12982
- /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("span", { className: "fd-label-lg", children: g.label }),
12983
- /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("span", { className: "fd-body-sm fd-muted", style: { fontSize: 11.5 }, children: [
13053
+ /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("span", { className: "fd-stack", style: { gap: 1 }, children: [
13054
+ /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fd-label-lg", children: g.label }),
13055
+ /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("span", { className: "fd-body-sm fd-muted", style: { fontSize: 11.5 }, children: [
12984
13056
  "CRP ",
12985
13057
  g.range
12986
13058
  ] })
@@ -12990,10 +13062,10 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
12990
13062
  g.key
12991
13063
  );
12992
13064
  }) }),
12993
- floorBand ? /* @__PURE__ */ (0, import_jsx_runtime92.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: [
12994
- /* @__PURE__ */ (0, import_jsx_runtime92.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_runtime92.jsx)("span", { className: "fd-meter-seg" + (i <= floor.n ? " is-on" : ""), style: { width: 5, height: 12 } }, i)) }),
12995
- /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("span", { className: "fd-body-sm fd-secondary", style: { flex: 1, minWidth: 240 }, children: [
12996
- /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("strong", { style: { color: "var(--text)" }, children: [
13065
+ floorBand ? /* @__PURE__ */ (0, import_jsx_runtime94.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: [
13066
+ /* @__PURE__ */ (0, import_jsx_runtime94.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_runtime94.jsx)("span", { className: "fd-meter-seg" + (i <= floor.n ? " is-on" : ""), style: { width: 5, height: 12 } }, i)) }),
13067
+ /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("span", { className: "fd-body-sm fd-secondary", style: { flex: 1, minWidth: 240 }, children: [
13068
+ /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("strong", { style: { color: "var(--text)" }, children: [
12997
13069
  "Plan floor ",
12998
13070
  floorScore
12999
13071
  ] }),
@@ -13004,8 +13076,8 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
13004
13076
  }
13005
13077
 
13006
13078
  // src/components/planner/MixGap.tsx
13007
- var React66 = __toESM(require("react"), 1);
13008
- var import_jsx_runtime93 = require("react/jsx-runtime");
13079
+ var React67 = __toESM(require("react"), 1);
13080
+ var import_jsx_runtime95 = require("react/jsx-runtime");
13009
13081
  var MIX_GAP_LAYOUT = {
13010
13082
  trackHeight: 30,
13011
13083
  barHeight: 20,
@@ -13019,19 +13091,19 @@ function mixGapOffset(value, max) {
13019
13091
  }
13020
13092
  function MixGap({ rows = [], loading = false, className = "" }) {
13021
13093
  const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
13022
- const [hover, setHover] = React66.useState(null);
13094
+ const [hover, setHover] = React67.useState(null);
13023
13095
  const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
13024
13096
  const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
13025
13097
  const { trackHeight, barHeight, targetWidth, labelGap } = MIX_GAP_LAYOUT;
13026
13098
  const barTop = (trackHeight - barHeight) / 2;
13027
- return /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 4 }, children: [
13028
- /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)("div", { className: "fd-row", style: { gap: 16, justifyContent: "flex-end", paddingBottom: 6, flexWrap: "wrap" }, children: [
13029
- [["On target", TONE.ok], ["Close", TONE.warn], ["Short", TONE.danger]].map(([l, c]) => /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
13030
- /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("span", { style: { width: 14, height: 9, borderRadius: 2, background: c } }),
13099
+ return /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 4 }, children: [
13100
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fd-row", style: { gap: 16, justifyContent: "flex-end", paddingBottom: 6, flexWrap: "wrap" }, children: [
13101
+ [["On target", TONE.ok], ["Close", TONE.warn], ["Short", TONE.danger]].map(([l, c]) => /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
13102
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { style: { width: 14, height: 9, borderRadius: 2, background: c } }),
13031
13103
  l
13032
13104
  ] }, l)),
13033
- /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
13034
- /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("span", { "data-mixgap-legend-target": "", style: { width: targetWidth, height: 16, borderRadius: 1, background: MIX_GAP_TARGET_STRIPE } }),
13105
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
13106
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { "data-mixgap-legend-target": "", style: { width: targetWidth, height: 16, borderRadius: 1, background: MIX_GAP_TARGET_STRIPE } }),
13035
13107
  "Target"
13036
13108
  ] })
13037
13109
  ] }),
@@ -13040,7 +13112,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
13040
13112
  const tone = toneOf(gap);
13041
13113
  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 : "");
13042
13114
  const labelLeft = r.realized > r.target ? `calc(${mixGapOffset(r.realized, max)} + ${labelGap}px)` : `calc(${mixGapOffset(r.target, max)} + ${targetWidth / 2 + labelGap}px)`;
13043
- return /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)(
13115
+ return /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)(
13044
13116
  "div",
13045
13117
  {
13046
13118
  className: "fd-row",
@@ -13048,15 +13120,15 @@ function MixGap({ rows = [], loading = false, className = "" }) {
13048
13120
  onMouseEnter: () => setHover(r.channel),
13049
13121
  onMouseLeave: () => setHover(null),
13050
13122
  children: [
13051
- /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("span", { style: { width: 128, flex: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(ChannelTag, { channel: r.channel, size: "sm" }) }),
13052
- /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("span", { style: { position: "relative", flex: 1, height: trackHeight, minWidth: 120 }, children: loading ? /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("span", { className: "fd-skel", style: { position: "absolute", left: 0, right: 0, top: barTop, height: barHeight, borderRadius: 3 } }) : /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)(import_jsx_runtime93.Fragment, { children: [
13053
- /* @__PURE__ */ (0, import_jsx_runtime93.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)" } }),
13054
- /* @__PURE__ */ (0, import_jsx_runtime93.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 } }),
13055
- /* @__PURE__ */ (0, import_jsx_runtime93.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: [
13123
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { style: { width: 128, flex: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(ChannelTag, { channel: r.channel, size: "sm" }) }),
13124
+ /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { style: { position: "relative", flex: 1, height: trackHeight, minWidth: 120 }, children: loading ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fd-skel", style: { position: "absolute", left: 0, right: 0, top: barTop, height: barHeight, borderRadius: 3 } }) : /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)(import_jsx_runtime95.Fragment, { children: [
13125
+ /* @__PURE__ */ (0, import_jsx_runtime95.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)" } }),
13126
+ /* @__PURE__ */ (0, import_jsx_runtime95.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 } }),
13127
+ /* @__PURE__ */ (0, import_jsx_runtime95.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: [
13056
13128
  r.realized,
13057
13129
  "%"
13058
13130
  ] }),
13059
- hover === r.channel ? /* @__PURE__ */ (0, import_jsx_runtime93.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
13131
+ hover === r.channel ? /* @__PURE__ */ (0, import_jsx_runtime95.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
13060
13132
  ] }) })
13061
13133
  ]
13062
13134
  },
@@ -13067,7 +13139,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
13067
13139
  }
13068
13140
 
13069
13141
  // src/components/planner/ChannelContribution.tsx
13070
- var import_jsx_runtime94 = require("react/jsx-runtime");
13142
+ var import_jsx_runtime96 = require("react/jsx-runtime");
13071
13143
  var money = (n) => "$" + Math.round(n).toLocaleString();
13072
13144
  function ChannelContribution({
13073
13145
  channels = [],
@@ -13083,9 +13155,9 @@ function ChannelContribution({
13083
13155
  const grand = total !== void 0 ? total : base + bonus;
13084
13156
  const pct = (v) => grand ? v / grand * 100 : 0;
13085
13157
  const spendTotal = channels.reduce((s, c) => s + Number(String(c.spend || 0).replace(/[^0-9.]/g, "")), 0);
13086
- return /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
13087
- loading ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fd-skel", style: { height: 34, borderRadius: "var(--r-sm)" } }) : /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("div", { className: "fd-row", style: { height: 34, borderRadius: "var(--r-sm)", overflow: "hidden", gap: 2, background: "var(--surface-3)" }, children: [
13088
- channels.map((c) => /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(
13158
+ return /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
13159
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("span", { className: "fd-skel", style: { height: 34, borderRadius: "var(--r-sm)" } }) : /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("div", { className: "fd-row", style: { height: 34, borderRadius: "var(--r-sm)", overflow: "hidden", gap: 2, background: "var(--surface-3)" }, children: [
13160
+ channels.map((c) => /* @__PURE__ */ (0, import_jsx_runtime96.jsx)(
13089
13161
  "span",
13090
13162
  {
13091
13163
  title: c.name + " \xB7 " + c.crp.toFixed(1) + " CRP",
@@ -13094,7 +13166,7 @@ function ChannelContribution({
13094
13166
  },
13095
13167
  c.name
13096
13168
  )),
13097
- bonus > 0 ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(
13169
+ bonus > 0 ? /* @__PURE__ */ (0, import_jsx_runtime96.jsx)(
13098
13170
  "span",
13099
13171
  {
13100
13172
  title: "Surround-sound bonus +" + bonusPct + "%",
@@ -13103,18 +13175,18 @@ function ChannelContribution({
13103
13175
  }
13104
13176
  ) : null
13105
13177
  ] }),
13106
- showTable ? /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("table", { className: "fd-table", style: { fontSize: "var(--body-sm-size)" }, children: [
13107
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("tr", { children: [
13108
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("th", { style: { width: "34%" }, children: "Channel" }),
13109
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("th", { style: { width: "16%" }, children: "Weight" }),
13110
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("th", { className: "is-num", style: { width: "16%" }, children: "Spend" }),
13111
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("th", { className: "is-num", style: { width: "17%" }, children: "CRP" }),
13112
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("th", { className: "is-num", style: { width: "17%" }, children: "Share" })
13178
+ showTable ? /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("table", { className: "fd-table", style: { fontSize: "var(--body-sm-size)" }, children: [
13179
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("tr", { children: [
13180
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("th", { style: { width: "34%" }, children: "Channel" }),
13181
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("th", { style: { width: "16%" }, children: "Weight" }),
13182
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("th", { className: "is-num", style: { width: "16%" }, children: "Spend" }),
13183
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("th", { className: "is-num", style: { width: "17%" }, children: "CRP" }),
13184
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("th", { className: "is-num", style: { width: "17%" }, children: "Share" })
13113
13185
  ] }) }),
13114
- /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("tbody", { children: [
13115
- channels.map((c) => /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("tr", { children: [
13116
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(ChannelTag, { channel: c.name, size: "sm" }) }),
13117
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(
13186
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("tbody", { children: [
13187
+ channels.map((c) => /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("tr", { children: [
13188
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime96.jsx)(ChannelTag, { channel: c.name, size: "sm" }) }),
13189
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime96.jsx)(
13118
13190
  "span",
13119
13191
  {
13120
13192
  className: "fd-badge fd-badge-neutral",
@@ -13123,38 +13195,38 @@ function ChannelContribution({
13123
13195
  children: "weight " + (channelWeightOf(c.name) || 0)
13124
13196
  }
13125
13197
  ) }),
13126
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("td", { className: "is-num", children: c.spend }),
13127
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("td", { className: "is-num", children: c.crp.toFixed(1) }),
13128
- /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("td", { className: "is-num", children: [
13198
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("td", { className: "is-num", children: c.spend }),
13199
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("td", { className: "is-num", children: c.crp.toFixed(1) }),
13200
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("td", { className: "is-num", children: [
13129
13201
  pct(c.crp).toFixed(0),
13130
13202
  "%"
13131
13203
  ] })
13132
13204
  ] }, c.name)),
13133
- bonus > 0 ? /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("tr", { children: [
13134
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("span", { className: "fd-row", style: { gap: 9, fontWeight: 600 }, children: [
13135
- /* @__PURE__ */ (0, import_jsx_runtime94.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" } }),
13205
+ bonus > 0 ? /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("tr", { children: [
13206
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("span", { className: "fd-row", style: { gap: 9, fontWeight: 600 }, children: [
13207
+ /* @__PURE__ */ (0, import_jsx_runtime96.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" } }),
13136
13208
  "Surround-sound bonus"
13137
13209
  ] }) }),
13138
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("span", { className: "fd-badge fd-badge-success", style: { height: 20, fontSize: 11 }, children: [
13210
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("span", { className: "fd-badge fd-badge-success", style: { height: 20, fontSize: 11 }, children: [
13139
13211
  "+",
13140
13212
  bonusPct,
13141
13213
  "% of +",
13142
13214
  bonusMax,
13143
13215
  "%"
13144
13216
  ] }) }),
13145
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("td", { className: "is-num fd-muted", children: "\u2014" }),
13146
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("td", { className: "is-num", children: bonus.toFixed(1) }),
13147
- /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("td", { className: "is-num", children: [
13217
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("td", { className: "is-num fd-muted", children: "\u2014" }),
13218
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("td", { className: "is-num", children: bonus.toFixed(1) }),
13219
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("td", { className: "is-num", children: [
13148
13220
  pct(bonus).toFixed(0),
13149
13221
  "%"
13150
13222
  ] })
13151
13223
  ] }) : null,
13152
- /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("tr", { style: { background: "var(--surface-2)" }, children: [
13153
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("td", { style: { fontWeight: 700 }, children: "Campus total" }),
13154
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("td", {}),
13155
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: money(spendTotal) }),
13156
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: grand.toFixed(1) }),
13157
- /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: "100%" })
13224
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("tr", { style: { background: "var(--surface-2)" }, children: [
13225
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("td", { style: { fontWeight: 700 }, children: "Campus total" }),
13226
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("td", {}),
13227
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: money(spendTotal) }),
13228
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: grand.toFixed(1) }),
13229
+ /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: "100%" })
13158
13230
  ] })
13159
13231
  ] })
13160
13232
  ] }) : null
@@ -13162,8 +13234,8 @@ function ChannelContribution({
13162
13234
  }
13163
13235
 
13164
13236
  // src/components/planner/BudgetReallocator.tsx
13165
- var React67 = __toESM(require("react"), 1);
13166
- var import_jsx_runtime95 = require("react/jsx-runtime");
13237
+ var React68 = __toESM(require("react"), 1);
13238
+ var import_jsx_runtime97 = require("react/jsx-runtime");
13167
13239
  var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
13168
13240
  function BudgetReallocator({
13169
13241
  campus,
@@ -13178,8 +13250,8 @@ function BudgetReallocator({
13178
13250
  onCancel,
13179
13251
  className = ""
13180
13252
  }) {
13181
- const [draft, setDraft] = React67.useState(spend);
13182
- React67.useEffect(() => setDraft(spend), [spend]);
13253
+ const [draft, setDraft] = React68.useState(spend);
13254
+ React68.useEffect(() => setDraft(spend), [spend]);
13183
13255
  const dirty = draft !== spend;
13184
13256
  const nextCrp = scoreFor ? scoreFor(draft) : crp;
13185
13257
  const nextBand = bandFor(nextCrp);
@@ -13194,10 +13266,10 @@ function BudgetReallocator({
13194
13266
  setDraft(spend);
13195
13267
  if (onCancel) onCancel();
13196
13268
  };
13197
- const trackRef = React67.useRef(null);
13198
- const chipRef = React67.useRef(null);
13199
- const [chipLeft, setChipLeft] = React67.useState(null);
13200
- React67.useLayoutEffect(() => {
13269
+ const trackRef = React68.useRef(null);
13270
+ const chipRef = React68.useRef(null);
13271
+ const [chipLeft, setChipLeft] = React68.useState(null);
13272
+ React68.useLayoutEffect(() => {
13201
13273
  const track = trackRef.current;
13202
13274
  if (!dirty || !track) {
13203
13275
  setChipLeft(null);
@@ -13218,23 +13290,23 @@ function BudgetReallocator({
13218
13290
  ro.observe(track);
13219
13291
  return () => ro.disconnect();
13220
13292
  }, [dirty, pct]);
13221
- return /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)(
13293
+ return /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)(
13222
13294
  "div",
13223
13295
  {
13224
13296
  className: ["fd-stack", className].filter(Boolean).join(" "),
13225
13297
  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)" },
13226
13298
  children: [
13227
- /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
13228
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fd-h4", style: { flex: 1, minWidth: 140 }, children: campus }),
13229
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(CsiBadge, { band: nowBand, crp, size: "medium" }),
13230
- dirty ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)(import_jsx_runtime95.Fragment, { children: [
13231
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-arrow-right fd-muted", "aria-hidden": "true" }),
13232
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(CsiBadge, { band: nextBand, crp: nextCrp, size: "medium", preview: true })
13299
+ /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
13300
+ /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("span", { className: "fd-h4", style: { flex: 1, minWidth: 140 }, children: campus }),
13301
+ /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(CsiBadge, { band: nowBand, crp, size: "medium" }),
13302
+ dirty ? /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)(import_jsx_runtime97.Fragment, { children: [
13303
+ /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("i", { className: "ph ph-arrow-right fd-muted", "aria-hidden": "true" }),
13304
+ /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(CsiBadge, { band: nextBand, crp: nextCrp, size: "medium", preview: true })
13233
13305
  ] }) : null
13234
13306
  ] }),
13235
- /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fd-slider", ref: trackRef, children: [
13236
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
13237
- dirty ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(
13307
+ /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("div", { className: "fd-slider", ref: trackRef, children: [
13308
+ /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
13309
+ dirty ? /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
13238
13310
  "span",
13239
13311
  {
13240
13312
  ref: chipRef,
@@ -13246,7 +13318,7 @@ function BudgetReallocator({
13246
13318
  children: (delta < 0 ? "\u2212$" : "+$") + Math.abs(delta).toLocaleString()
13247
13319
  }
13248
13320
  ) : null,
13249
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(
13321
+ /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
13250
13322
  "input",
13251
13323
  {
13252
13324
  type: "range",
@@ -13262,13 +13334,13 @@ function BudgetReallocator({
13262
13334
  }
13263
13335
  )
13264
13336
  ] }),
13265
- /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
13266
- /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("span", { className: "fd-stack", style: { gap: 2, flex: 1, minWidth: 150 }, children: [
13267
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fd-num", style: { fontSize: 19, fontWeight: 700 }, children: "$" + draft.toLocaleString() }),
13268
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fd-body-sm fd-muted", children: "Arrow keys step $100, shift+arrow $1,000. Escape reverts." })
13337
+ /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
13338
+ /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("span", { className: "fd-stack", style: { gap: 2, flex: 1, minWidth: 150 }, children: [
13339
+ /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("span", { className: "fd-num", style: { fontSize: 19, fontWeight: 700 }, children: "$" + draft.toLocaleString() }),
13340
+ /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("span", { className: "fd-body-sm fd-muted", children: "Arrow keys step $100, shift+arrow $1,000. Escape reverts." })
13269
13341
  ] }),
13270
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("button", { type: "button", className: "fd-btn fd-btn-ghost", disabled: !dirty, onClick: revert, children: "Cancel" }),
13271
- /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(
13342
+ /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("button", { type: "button", className: "fd-btn fd-btn-ghost", disabled: !dirty, onClick: revert, children: "Cancel" }),
13343
+ /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
13272
13344
  "button",
13273
13345
  {
13274
13346
  type: "button",
@@ -13287,7 +13359,7 @@ function BudgetReallocator({
13287
13359
  }
13288
13360
 
13289
13361
  // src/components/planner/SurroundSound.tsx
13290
- var import_jsx_runtime96 = require("react/jsx-runtime");
13362
+ var import_jsx_runtime98 = require("react/jsx-runtime");
13291
13363
  var CATEGORIES = [
13292
13364
  { key: "ooh", label: "OOH", icon: "flag-banner", color: "var(--ch-ooh)" },
13293
13365
  { key: "transit", label: "Transit", icon: "bus", color: "var(--ch-transit)" },
@@ -13299,26 +13371,26 @@ var CATEGORIES = [
13299
13371
  function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost, className = "" }) {
13300
13372
  const earned = Math.max(0, Math.min(1, bonusPct / bonusMax));
13301
13373
  const single = present.length <= 2;
13302
- return /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, children: [
13303
- /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: CATEGORIES.map((c) => {
13374
+ return /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, children: [
13375
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: CATEGORIES.map((c) => {
13304
13376
  const on = present.includes(c.key);
13305
- return /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)(
13377
+ return /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)(
13306
13378
  "span",
13307
13379
  {
13308
13380
  title: c.label + (on ? " \u2014 present" : " \u2014 not bought"),
13309
13381
  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)" },
13310
13382
  children: [
13311
- /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("i", { className: "ph ph-" + c.icon, style: { fontSize: 19, color: on ? c.color : "var(--text-muted)" }, "aria-hidden": "true" }),
13312
- /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("span", { style: { fontSize: 10.5, fontWeight: 700 }, children: c.label })
13383
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("i", { className: "ph ph-" + c.icon, style: { fontSize: 19, color: on ? c.color : "var(--text-muted)" }, "aria-hidden": "true" }),
13384
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("span", { style: { fontSize: 10.5, fontWeight: 700 }, children: c.label })
13313
13385
  ]
13314
13386
  },
13315
13387
  c.key
13316
13388
  );
13317
13389
  }) }),
13318
- /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("div", { className: "fd-stack", style: { gap: 8 }, children: [
13319
- /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
13320
- /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("span", { className: "fd-label-lg", children: "Surround-sound bonus earned" }),
13321
- /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("span", { className: "fd-num", style: { color: single ? "var(--warn-text)" : "var(--csi-3-mark)", fontWeight: 700 }, children: [
13390
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("div", { className: "fd-stack", style: { gap: 8 }, children: [
13391
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
13392
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("span", { className: "fd-label-lg", children: "Surround-sound bonus earned" }),
13393
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("span", { className: "fd-num", style: { color: single ? "var(--warn-text)" : "var(--csi-3-mark)", fontWeight: 700 }, children: [
13322
13394
  "+",
13323
13395
  bonusPct,
13324
13396
  "% of +",
@@ -13326,8 +13398,8 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
13326
13398
  "%"
13327
13399
  ] })
13328
13400
  ] }),
13329
- /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("div", { style: { height: 8, borderRadius: "var(--r-xs)", background: "var(--surface-3)", overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("div", { style: { height: "100%", width: earned * 100 + "%", background: "var(--csi-3-mark)", borderRadius: "inherit", transition: "width var(--dur-slow) var(--ease)" } }) }),
13330
- /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: [
13401
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("div", { style: { height: 8, borderRadius: "var(--r-xs)", background: "var(--surface-3)", overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("div", { style: { height: "100%", width: earned * 100 + "%", background: "var(--csi-3-mark)", borderRadius: "inherit", transition: "width var(--dur-slow) var(--ease)" } }) }),
13402
+ /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: [
13331
13403
  present.length,
13332
13404
  " of 6 channel categories present.",
13333
13405
  " ",
@@ -13339,7 +13411,7 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
13339
13411
  }
13340
13412
 
13341
13413
  // src/components/planner/Importance.tsx
13342
- var import_jsx_runtime97 = require("react/jsx-runtime");
13414
+ var import_jsx_runtime99 = require("react/jsx-runtime");
13343
13415
  var IMPORTANCE_LEVELS = [
13344
13416
  { id: "nudge", rank: 1, label: "Nudge", icon: "feather", description: "Breaks a tie, nothing more." },
13345
13417
  { id: "lean", rank: 2, label: "Lean", icon: "arrow-bend-up-right", description: "A mild preference between otherwise equal options." },
@@ -13369,7 +13441,7 @@ function importanceTokens(id) {
13369
13441
  function ImportanceTag({ level, showLabel = true, size = "sm", className = "", disabled = false }) {
13370
13442
  const lvl = importanceLevel(level);
13371
13443
  const t = importanceTokens(level);
13372
- return /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)(
13444
+ return /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)(
13373
13445
  "span",
13374
13446
  {
13375
13447
  className: ["fd-imp-tag", size === "md" ? "is-md" : "", disabled ? "is-disabled" : "", className].filter(Boolean).join(" "),
@@ -13377,16 +13449,16 @@ function ImportanceTag({ level, showLabel = true, size = "sm", className = "", d
13377
13449
  title: lvl.label + " \u2014 " + lvl.description,
13378
13450
  "aria-disabled": disabled ? "true" : void 0,
13379
13451
  children: [
13380
- /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("i", { className: "ph ph-" + lvl.icon, "aria-hidden": "true" }),
13381
- showLabel ? lvl.label : /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("span", { className: "fd-sr", children: lvl.label })
13452
+ /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("i", { className: "ph ph-" + lvl.icon, "aria-hidden": "true" }),
13453
+ showLabel ? lvl.label : /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "fd-sr", children: lvl.label })
13382
13454
  ]
13383
13455
  }
13384
13456
  );
13385
13457
  }
13386
13458
 
13387
13459
  // src/components/planner/PreferenceMeter.tsx
13388
- var React68 = __toESM(require("react"), 1);
13389
- var import_jsx_runtime98 = require("react/jsx-runtime");
13460
+ var React69 = __toESM(require("react"), 1);
13461
+ var import_jsx_runtime100 = require("react/jsx-runtime");
13390
13462
  function preferenceScore(criteria) {
13391
13463
  const earned = criteria.reduce((n, c) => n + (Number(c.earned) || 0), 0);
13392
13464
  const weight = criteria.reduce((n, c) => n + (Number(c.weight) || 0), 0);
@@ -13415,8 +13487,8 @@ function PreferenceMeter({
13415
13487
  className = ""
13416
13488
  }) {
13417
13489
  const value = score == null ? preferenceScore(criteria) : score;
13418
- const segments = React68.useMemo(() => preferenceSegments(criteria), [criteria]);
13419
- return /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
13490
+ const segments = React69.useMemo(() => preferenceSegments(criteria), [criteria]);
13491
+ return /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
13420
13492
  ScoreMeter,
13421
13493
  {
13422
13494
  score: value,
@@ -13428,22 +13500,22 @@ function PreferenceMeter({
13428
13500
  placement,
13429
13501
  className,
13430
13502
  breakdownLabel: breakdownTitle,
13431
- breakdown: /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("div", { className: "fd-prefbreak", children: [
13432
- /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("div", { className: "fd-prefbreak-head", children: [
13433
- /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("span", { className: "fd-label-lg", children: breakdownTitle }),
13434
- /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("span", { className: "fd-prefbreak-score fd-tabular", children: Math.round(value) })
13503
+ breakdown: /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: "fd-prefbreak", children: [
13504
+ /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: "fd-prefbreak-head", children: [
13505
+ /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "fd-label-lg", children: breakdownTitle }),
13506
+ /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "fd-prefbreak-score fd-tabular", children: Math.round(value) })
13435
13507
  ] }),
13436
- /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("ul", { className: "fd-prefbreak-list", children: criteria.map((c) => {
13508
+ /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("ul", { className: "fd-prefbreak-list", children: criteria.map((c) => {
13437
13509
  const pct = c.weight > 0 ? Math.round((Number(c.earned) || 0) / c.weight * 100) : 0;
13438
- return /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("li", { className: pct === 0 ? "fd-prefbreak-item is-unmet" : "fd-prefbreak-item", children: [
13439
- /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(ImportanceTag, { level: c.importance }),
13440
- /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("span", { className: "fd-prefbreak-text", children: [
13441
- /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("span", { className: "fd-prefbreak-label", children: c.label }),
13442
- c.note ? /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("span", { className: "fd-prefbreak-note", children: c.note }) : null
13510
+ return /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("li", { className: pct === 0 ? "fd-prefbreak-item is-unmet" : "fd-prefbreak-item", children: [
13511
+ /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(ImportanceTag, { level: c.importance }),
13512
+ /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("span", { className: "fd-prefbreak-text", children: [
13513
+ /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "fd-prefbreak-label", children: c.label }),
13514
+ c.note ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "fd-prefbreak-note", children: c.note }) : null
13443
13515
  ] }),
13444
- /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("span", { className: "fd-prefbreak-val fd-tabular", children: [
13516
+ /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("span", { className: "fd-prefbreak-val fd-tabular", children: [
13445
13517
  Math.round(Number(c.earned) || 0),
13446
- /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("span", { className: "fd-prefbreak-sep", children: "/" }),
13518
+ /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "fd-prefbreak-sep", children: "/" }),
13447
13519
  Math.round(c.weight)
13448
13520
  ] })
13449
13521
  ] }, c.id);
@@ -13454,10 +13526,10 @@ function PreferenceMeter({
13454
13526
  }
13455
13527
 
13456
13528
  // src/components/chat/AgentChatPanel.tsx
13457
- var React74 = __toESM(require("react"), 1);
13529
+ var React75 = __toESM(require("react"), 1);
13458
13530
 
13459
13531
  // src/components/chat/chatEngine.ts
13460
- var React69 = __toESM(require("react"), 1);
13532
+ var React70 = __toESM(require("react"), 1);
13461
13533
  var CHAT_UNAVAILABLE = "chat_unavailable";
13462
13534
  var JOB_PENDING = ["queued", "running"];
13463
13535
  var JOB_SUCCESS = ["completed", "recovered"];
@@ -13502,7 +13574,7 @@ function useChatEngine(opts) {
13502
13574
  initialMessage,
13503
13575
  threadId: threadIdProp,
13504
13576
  pollIntervalMs = 1500,
13505
- pollMaxAttempts = 120,
13577
+ pendingTimeoutMs = 18e4,
13506
13578
  store = safeStore,
13507
13579
  onPacket,
13508
13580
  onThreadReady,
@@ -13511,22 +13583,22 @@ function useChatEngine(opts) {
13511
13583
  onClear,
13512
13584
  onFeedback
13513
13585
  } = opts || {};
13514
- const [status, setStatus] = React69.useState("idle");
13515
- const [threadId, setThreadId] = React69.useState(null);
13516
- const [messages, setMessages] = React69.useState([]);
13517
- const [queue, setQueue] = React69.useState([]);
13518
- const [fatal, setFatal] = React69.useState(null);
13519
- const [busy, setBusy] = React69.useState(false);
13520
- const [turnStartedAt, setTurnStartedAt] = React69.useState(null);
13521
- const listRef = React69.useRef([]);
13522
- const queueRef = React69.useRef([]);
13523
- const busyRef = React69.useRef(false);
13524
- const stoppedRef = React69.useRef(false);
13525
- const abortRef = React69.useRef(null);
13526
- const serverCount = React69.useRef(0);
13527
- const threadRef = React69.useRef(null);
13528
- const mounted = React69.useRef(true);
13529
- React69.useEffect(() => {
13586
+ const [status, setStatus] = React70.useState("idle");
13587
+ const [threadId, setThreadId] = React70.useState(null);
13588
+ const [messages, setMessages] = React70.useState([]);
13589
+ const [queue, setQueue] = React70.useState([]);
13590
+ const [fatal, setFatal] = React70.useState(null);
13591
+ const [busy, setBusy] = React70.useState(false);
13592
+ const [turnStartedAt, setTurnStartedAt] = React70.useState(null);
13593
+ const listRef = React70.useRef([]);
13594
+ const queueRef = React70.useRef([]);
13595
+ const busyRef = React70.useRef(false);
13596
+ const stoppedRef = React70.useRef(false);
13597
+ const abortRef = React70.useRef(null);
13598
+ const serverCount = React70.useRef(0);
13599
+ const threadRef = React70.useRef(null);
13600
+ const mounted = React70.useRef(true);
13601
+ React70.useEffect(() => {
13530
13602
  mounted.current = true;
13531
13603
  return () => {
13532
13604
  mounted.current = false;
@@ -13548,14 +13620,21 @@ function useChatEngine(opts) {
13548
13620
  }
13549
13621
  return false;
13550
13622
  };
13551
- const loadThread = React69.useCallback(async (id) => {
13623
+ const loadThread = React70.useCallback(async (id) => {
13552
13624
  const data = await apiAdapter.getThread(id);
13553
13625
  const list = [...data && data.messages || []];
13554
13626
  serverCount.current = list.length;
13555
13627
  commit(list);
13556
13628
  return list;
13557
13629
  }, [apiAdapter]);
13558
- React69.useEffect(() => {
13630
+ async function mergeThread() {
13631
+ const data = await apiAdapter.getThread(threadRef.current);
13632
+ const server = data && data.messages || [];
13633
+ const ids = new Set(server.map((m) => m.id));
13634
+ serverCount.current = server.length;
13635
+ commit([...server, ...listRef.current.filter((m) => !ids.has(m.id))]);
13636
+ }
13637
+ React70.useEffect(() => {
13559
13638
  if (!apiAdapter) {
13560
13639
  setStatus("idle");
13561
13640
  setFatal(null);
@@ -13601,7 +13680,9 @@ function useChatEngine(opts) {
13601
13680
  setStatus("ready");
13602
13681
  onThreadReady && onThreadReady(id);
13603
13682
  const stored = store.get(STORAGE_PREFIX + id);
13683
+ const last = [...visibleMessages(listRef.current)].reverse().find((m) => m.role === "assistant");
13604
13684
  if (stored) resumeJob(stored);
13685
+ else if (last && last.working && last.jobId) resumeJob(last.jobId, last.id);
13605
13686
  else if (initialMessage) send(initialMessage);
13606
13687
  } catch (err) {
13607
13688
  if (dead) return;
@@ -13617,8 +13698,8 @@ function useChatEngine(opts) {
13617
13698
  }, [apiAdapter, contextType, contextId, threadIdProp]);
13618
13699
  async function pollJob(jobId, placeholderId) {
13619
13700
  store.set(STORAGE_PREFIX + threadRef.current, jobId);
13620
- let attempts = 0;
13621
- while (attempts++ < pollMaxAttempts) {
13701
+ const deadline = Date.now() + pendingTimeoutMs;
13702
+ while (true) {
13622
13703
  if (stoppedRef.current) break;
13623
13704
  await sleep(pollIntervalMs);
13624
13705
  if (!mounted.current) return;
@@ -13636,7 +13717,15 @@ function useChatEngine(opts) {
13636
13717
  }
13637
13718
  patch(placeholderId, { job });
13638
13719
  const bucket2 = jobBucket(job && job.status);
13639
- if (bucket2 === "pending") continue;
13720
+ if (bucket2 === "pending") {
13721
+ try {
13722
+ await mergeThread();
13723
+ } catch (err) {
13724
+ fail(err);
13725
+ }
13726
+ if (Date.now() >= deadline) break;
13727
+ continue;
13728
+ }
13640
13729
  if (bucket2 === "success") {
13641
13730
  finishJob(jobId, job);
13642
13731
  return;
@@ -13673,9 +13762,10 @@ function useChatEngine(opts) {
13673
13762
  patch(placeholderId, { working: false, streaming: false, error: code, retryable: !!retryable, job: job || void 0 });
13674
13763
  onError && onError(new Error(code));
13675
13764
  }
13676
- function resumeJob(jobId) {
13677
- const id = uid("a");
13678
- push({ id, role: "assistant", working: true, jobId, resumed: true });
13765
+ function resumeJob(jobId, existingId) {
13766
+ const id = existingId || uid("a");
13767
+ if (existingId) patch(id, { working: true, resumed: true });
13768
+ else push({ id, role: "assistant", working: true, jobId, resumed: true });
13679
13769
  setBusy(true);
13680
13770
  busyRef.current = true;
13681
13771
  setTurnStartedAt(Date.now());
@@ -13768,7 +13858,7 @@ function useChatEngine(opts) {
13768
13858
  await dispatchTurn(turn);
13769
13859
  }
13770
13860
  }
13771
- const send = React69.useCallback((text, attachments) => {
13861
+ const send = React70.useCallback((text, attachments) => {
13772
13862
  const body = (text || "").trim();
13773
13863
  if (!body && !(attachments && attachments.length)) return;
13774
13864
  if (status === "disconnected") return;
@@ -13778,7 +13868,7 @@ function useChatEngine(opts) {
13778
13868
  stoppedRef.current = false;
13779
13869
  drain();
13780
13870
  }, [status]);
13781
- const stop = React69.useCallback(() => {
13871
+ const stop = React70.useCallback(() => {
13782
13872
  stoppedRef.current = true;
13783
13873
  const ac = abortRef.current;
13784
13874
  if (ac) {
@@ -13797,11 +13887,11 @@ function useChatEngine(opts) {
13797
13887
  store.del(STORAGE_PREFIX + threadRef.current);
13798
13888
  }
13799
13889
  }, [apiAdapter]);
13800
- const removeQueued = React69.useCallback((id) => {
13890
+ const removeQueued = React70.useCallback((id) => {
13801
13891
  queueRef.current = queueRef.current.filter((t) => t.id !== id);
13802
13892
  setQueue(queueRef.current.slice());
13803
13893
  }, []);
13804
- const retry = React69.useCallback(() => {
13894
+ const retry = React70.useCallback(() => {
13805
13895
  const list = listRef.current;
13806
13896
  let at = -1;
13807
13897
  for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
@@ -13817,19 +13907,19 @@ function useChatEngine(opts) {
13817
13907
  setQueue(queueRef.current.slice());
13818
13908
  drain();
13819
13909
  }, []);
13820
- const clear = React69.useCallback(() => {
13910
+ const clear = React70.useCallback(() => {
13821
13911
  commit([]);
13822
13912
  serverCount.current = 0;
13823
13913
  queueRef.current = [];
13824
13914
  setQueue([]);
13825
13915
  onClear && onClear();
13826
13916
  }, [onClear]);
13827
- const setFeedback = React69.useCallback((id, value) => {
13917
+ const setFeedback = React70.useCallback((id, value) => {
13828
13918
  patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
13829
13919
  const msg = listRef.current.find((m) => m.id === id);
13830
13920
  onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
13831
13921
  }, [onFeedback]);
13832
- const reload = React69.useCallback(async () => {
13922
+ const reload = React70.useCallback(async () => {
13833
13923
  if (!threadRef.current) return;
13834
13924
  setStatus("loading");
13835
13925
  try {
@@ -13867,11 +13957,11 @@ var ChatKit = {
13867
13957
  };
13868
13958
 
13869
13959
  // src/components/chat/ChatTranscript.tsx
13870
- var React71 = __toESM(require("react"), 1);
13960
+ var React72 = __toESM(require("react"), 1);
13871
13961
 
13872
13962
  // src/components/chat/ChatTurn.tsx
13873
- var React70 = __toESM(require("react"), 1);
13874
- var import_jsx_runtime99 = require("react/jsx-runtime");
13963
+ var React71 = __toESM(require("react"), 1);
13964
+ var import_jsx_runtime101 = require("react/jsx-runtime");
13875
13965
  function JsonView({ value }) {
13876
13966
  let text;
13877
13967
  try {
@@ -13879,67 +13969,67 @@ function JsonView({ value }) {
13879
13969
  } catch (e) {
13880
13970
  text = String(value);
13881
13971
  }
13882
- return /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(CodeBlock, { code: text, language: "json", collapseAfter: 18 });
13972
+ return /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(CodeBlock, { code: text, language: "json", collapseAfter: 18 });
13883
13973
  }
13884
13974
  function PacketCard({ packet, schema, render, onApply, applied }) {
13885
13975
  if (!packet) return null;
13886
13976
  const s = schema || {};
13887
13977
  const invalid = packet.valid === false;
13888
13978
  const title = s.heading || packet.type;
13889
- return /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("section", { className: "fdc-packet" + (invalid ? " is-invalid" : ""), "aria-label": title, children: [
13890
- /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("header", { className: "fdc-packet-head", children: [
13891
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("i", { className: "ph ph-" + (s.icon || "package"), "aria-hidden": "true" }),
13892
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "fdc-packet-title", title: truncationTitle(title), children: title }),
13893
- packet.repaired ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "fdc-packet-badge", children: "Repaired" }) : null,
13894
- invalid ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "fdc-packet-badge is-danger", children: "Invalid" }) : null
13979
+ return /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("section", { className: "fdc-packet" + (invalid ? " is-invalid" : ""), "aria-label": title, children: [
13980
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("header", { className: "fdc-packet-head", children: [
13981
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("i", { className: "ph ph-" + (s.icon || "package"), "aria-hidden": "true" }),
13982
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fdc-packet-title", title: truncationTitle(title), children: title }),
13983
+ packet.repaired ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fdc-packet-badge", children: "Repaired" }) : null,
13984
+ invalid ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fdc-packet-badge is-danger", children: "Invalid" }) : null
13895
13985
  ] }),
13896
- invalid ? /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("div", { className: "fdc-packet-alert", role: "alert", children: [
13897
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
13898
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { children: packet.error || "This result failed validation and can\u2019t be applied." })
13899
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("div", { className: "fdc-packet-body", children: render ? render(packet) : /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(JsonView, { value: packet.payload }) }),
13900
- !invalid && onApply ? /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("footer", { className: "fdc-packet-foot", children: [
13901
- packet.repaired ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "fdc-packet-note", children: "Corrected by the backend after a first attempt." }) : /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", {}),
13902
- /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", disabled: applied, onClick: () => onApply(packet), children: [
13903
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("i", { className: "ph ph-" + (applied ? "check" : "arrow-square-in"), "aria-hidden": "true" }),
13986
+ invalid ? /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fdc-packet-alert", role: "alert", children: [
13987
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
13988
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { children: packet.error || "This result failed validation and can\u2019t be applied." })
13989
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("div", { className: "fdc-packet-body", children: render ? render(packet) : /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(JsonView, { value: packet.payload }) }),
13990
+ !invalid && onApply && s.apply !== false ? /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("footer", { className: "fdc-packet-foot", children: [
13991
+ packet.repaired ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fdc-packet-note", children: "Corrected by the backend after a first attempt." }) : /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", {}),
13992
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", disabled: applied, onClick: () => onApply(packet), children: [
13993
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("i", { className: "ph ph-" + (applied ? "check" : "arrow-square-in"), "aria-hidden": "true" }),
13904
13994
  applied ? "Applied" : s.applyLabel || "Apply"
13905
13995
  ] })
13906
13996
  ] }) : null
13907
13997
  ] });
13908
13998
  }
13909
13999
  function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
13910
- const [open2, setOpen] = React70.useState(defaultOpen);
14000
+ const [open2, setOpen] = React71.useState(defaultOpen);
13911
14001
  if (!text) return null;
13912
- return /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("div", { className: "fdc-think" + (open2 ? " is-open" : ""), children: [
13913
- /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open2, children: [
13914
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("i", { className: "ph ph-brain", "aria-hidden": "true" }),
13915
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { children: streaming ? "Thinking" : durationMs ? "Thought for " + formatDuration(durationMs) : "Thought process" }),
13916
- streaming ? /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("span", { className: "fdc-dots", "aria-hidden": "true", children: [
13917
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", {}),
13918
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", {}),
13919
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", {})
14002
+ return /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fdc-think" + (open2 ? " is-open" : ""), children: [
14003
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open2, children: [
14004
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("i", { className: "ph ph-brain", "aria-hidden": "true" }),
14005
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { children: streaming ? "Thinking" : durationMs ? "Thought for " + formatDuration(durationMs) : "Thought process" }),
14006
+ streaming ? /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("span", { className: "fdc-dots", "aria-hidden": "true", children: [
14007
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", {}),
14008
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", {}),
14009
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", {})
13920
14010
  ] }) : null,
13921
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("i", { className: "ph ph-caret-" + (open2 ? "up" : "down"), "aria-hidden": "true" })
14011
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("i", { className: "ph ph-caret-" + (open2 ? "up" : "down"), "aria-hidden": "true" })
13922
14012
  ] }),
13923
- open2 ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("div", { className: "fdc-think-body", children: text }) : null
14013
+ open2 ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("div", { className: "fdc-think-body", children: text }) : null
13924
14014
  ] });
13925
14015
  }
13926
14016
  function Citations({ items = [], onOpen }) {
13927
- const [open2, setOpen] = React70.useState(false);
14017
+ const [open2, setOpen] = React71.useState(false);
13928
14018
  if (!items.length) return null;
13929
- return /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("div", { className: "fdc-cites", children: [
13930
- /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open2, children: [
13931
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("i", { className: "ph ph-quotes", "aria-hidden": "true" }),
13932
- /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("span", { children: [
14019
+ return /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fdc-cites", children: [
14020
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open2, children: [
14021
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("i", { className: "ph ph-quotes", "aria-hidden": "true" }),
14022
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("span", { children: [
13933
14023
  items.length,
13934
14024
  " source",
13935
14025
  items.length === 1 ? "" : "s"
13936
14026
  ] }),
13937
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("i", { className: "ph ph-caret-" + (open2 ? "up" : "down"), "aria-hidden": "true" })
14027
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("i", { className: "ph ph-caret-" + (open2 ? "up" : "down"), "aria-hidden": "true" })
13938
14028
  ] }),
13939
- open2 ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("ol", { className: "fdc-cites-list", children: items.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("li", { children: [
13940
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "fdc-cite-n fd-tabular", children: c.marker || i + 1 }),
13941
- c.url ? /* @__PURE__ */ (0, import_jsx_runtime99.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_runtime99.jsx)("span", { children: c.title || "Source" }),
13942
- c.detail ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "fdc-cite-detail", children: c.detail }) : null
14029
+ open2 ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("ol", { className: "fdc-cites-list", children: items.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("li", { children: [
14030
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fdc-cite-n fd-tabular", children: c.marker || i + 1 }),
14031
+ c.url ? /* @__PURE__ */ (0, import_jsx_runtime101.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_runtime101.jsx)("span", { children: c.title || "Source" }),
14032
+ c.detail ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fdc-cite-detail", children: c.detail }) : null
13943
14033
  ] }, c.id || i)) }) : null
13944
14034
  ] });
13945
14035
  }
@@ -13950,29 +14040,29 @@ function clampText(text, max) {
13950
14040
  return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
13951
14041
  }
13952
14042
  function MessageBody({ message: m, ctx }) {
13953
- const [expanded, setExpanded] = React70.useState(false);
14043
+ const [expanded, setExpanded] = React71.useState(false);
13954
14044
  const isUser = m.role === "user";
13955
14045
  const raw = m.text || "";
13956
14046
  const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
13957
14047
  const body = clamped != null ? clamped : raw;
13958
14048
  const showMd = ctx.markdown && !isUser;
13959
- return /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("div", { className: "fdc-body", children: [
13960
- m.thinking && ctx.showThinking ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(ThinkingBlock, { text: m.thinking, durationMs: m.thinkingMs, streaming: m.streaming && !m.text }) : null,
13961
- m.steps && m.steps.length && ctx.showSteps ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(StepList, { steps: m.steps, defaultOpen: m.steps.some((s) => s.status === "running"), dense: true }) : null,
13962
- body ? /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("div", { className: "fdc-text" + (isUser ? " is-user" : ""), children: [
13963
- showMd ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(Markdown, { source: body, headingOffset: 2, codeProps: { collapseAfter: 22 }, renderCitation: ctx.renderCitation }) : /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("div", { className: "fdc-plain", children: body }),
13964
- m.streaming ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "fdc-caret", "aria-hidden": "true" }) : null
14049
+ return /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fdc-body", children: [
14050
+ m.thinking && ctx.showThinking ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(ThinkingBlock, { text: m.thinking, durationMs: m.thinkingMs, streaming: m.streaming && !m.text }) : null,
14051
+ m.steps && m.steps.length && ctx.showSteps ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(StepList, { steps: m.steps, defaultOpen: m.steps.some((s) => s.status === "running"), dense: true }) : null,
14052
+ body ? /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fdc-text" + (isUser ? " is-user" : ""), children: [
14053
+ showMd ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Markdown, { source: body, headingOffset: 2, codeProps: { collapseAfter: 22 }, renderCitation: ctx.renderCitation }) : /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("div", { className: "fdc-plain", children: body }),
14054
+ m.streaming ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fdc-caret", "aria-hidden": "true" }) : null
13965
14055
  ] }) : null,
13966
- clamped != null ? /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(true), children: [
13967
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("i", { className: "ph ph-caret-down", "aria-hidden": "true" }),
14056
+ clamped != null ? /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(true), children: [
14057
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("i", { className: "ph ph-caret-down", "aria-hidden": "true" }),
13968
14058
  "Show more",
13969
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "fdc-more-len fd-tabular", children: raw.length < 2e3 ? raw.length.toLocaleString() + " characters" : Math.round(raw.length / 100) / 10 + "k characters" })
13970
- ] }) : expanded && ctx.maxVisibleChars && raw.length > ctx.maxVisibleChars ? /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(false), children: [
13971
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("i", { className: "ph ph-caret-up", "aria-hidden": "true" }),
14059
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fdc-more-len fd-tabular", children: raw.length < 2e3 ? raw.length.toLocaleString() + " characters" : Math.round(raw.length / 100) / 10 + "k characters" })
14060
+ ] }) : expanded && ctx.maxVisibleChars && raw.length > ctx.maxVisibleChars ? /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(false), children: [
14061
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("i", { className: "ph ph-caret-up", "aria-hidden": "true" }),
13972
14062
  "Show less"
13973
14063
  ] }) : null,
13974
- m.attachments && m.attachments.length ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(FileGrid, { files: m.attachments, onOpen: ctx.onOpenAttachment, tiles: true, maxHeight: ctx.attachmentHeight || 220, compact: ctx.narrow }) : null,
13975
- m.packet ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
14064
+ m.attachments && m.attachments.length ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(FileGrid, { files: m.attachments, onOpen: ctx.onOpenAttachment, tiles: true, maxHeight: ctx.attachmentHeight || 220, compact: ctx.narrow }) : null,
14065
+ m.packet ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
13976
14066
  PacketCard,
13977
14067
  {
13978
14068
  packet: m.packet,
@@ -13982,35 +14072,35 @@ function MessageBody({ message: m, ctx }) {
13982
14072
  applied: ctx.appliedPackets && ctx.appliedPackets[m.id]
13983
14073
  }
13984
14074
  ) : null,
13985
- m.citations && m.citations.length ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(Citations, { items: m.citations, onOpen: ctx.onOpenCitation }) : null,
13986
- m.working ? /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("div", { className: "fdc-working", role: "status", children: [
13987
- /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("span", { className: "fdc-dots", "aria-hidden": "true", children: [
13988
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", {}),
13989
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", {}),
13990
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", {})
14075
+ m.citations && m.citations.length ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Citations, { items: m.citations, onOpen: ctx.onOpenCitation }) : null,
14076
+ m.working ? /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fdc-working", role: "status", children: [
14077
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("span", { className: "fdc-dots", "aria-hidden": "true", children: [
14078
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", {}),
14079
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", {}),
14080
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", {})
13991
14081
  ] }),
13992
- /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("span", { className: "fdc-working-label", children: [
14082
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("span", { className: "fdc-working-label", children: [
13993
14083
  m.resumed ? "Resuming" : "Working",
13994
- m.job && m.job.status ? /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("span", { className: "fdc-working-job", children: [
14084
+ m.job && m.job.status ? /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("span", { className: "fdc-working-job", children: [
13995
14085
  " \xB7 ",
13996
14086
  m.job.status
13997
14087
  ] }) : null,
13998
- m.job && m.job.detail ? /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("span", { className: "fdc-working-job", children: [
14088
+ m.job && m.job.detail ? /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("span", { className: "fdc-working-job", children: [
13999
14089
  " \xB7 ",
14000
14090
  m.job.detail
14001
14091
  ] }) : null
14002
14092
  ] }),
14003
- m.jobId ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "fdc-working-id fd-mono", children: String(m.jobId).slice(0, 12) }) : null
14093
+ m.jobId ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fdc-working-id fd-mono", children: String(m.jobId).slice(0, 12) }) : null
14004
14094
  ] }) : null,
14005
- m.stopped ? /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("div", { className: "fdc-stopped", children: [
14006
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
14095
+ m.stopped ? /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fdc-stopped", children: [
14096
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
14007
14097
  "Stopped"
14008
14098
  ] }) : null,
14009
- m.error ? /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("div", { className: "fdc-error", role: "alert", children: [
14010
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
14011
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "fdc-error-text", children: ctx.errorCopy ? ctx.errorCopy(m.error) : m.error }),
14012
- m.retryable && ctx.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("button", { type: "button", className: "fdc-error-retry", onClick: ctx.onRetry, children: [
14013
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
14099
+ m.error ? /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fdc-error", role: "alert", children: [
14100
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
14101
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fdc-error-text", children: ctx.errorCopy ? ctx.errorCopy(m.error) : m.error }),
14102
+ m.retryable && ctx.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("button", { type: "button", className: "fdc-error-retry", onClick: ctx.onRetry, children: [
14103
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
14014
14104
  "Retry"
14015
14105
  ] }) : null
14016
14106
  ] }) : null
@@ -14023,16 +14113,16 @@ function RunActions({ group, ctx }) {
14023
14113
  const isAssistant = group.role === "assistant";
14024
14114
  const fb = last.feedback;
14025
14115
  if (!ctx.messageActions) return null;
14026
- return /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("div", { className: "fdc-actions", role: "group", "aria-label": "Message actions", children: [
14027
- /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("button", { type: "button", className: "fdc-act" + (copied ? " is-done" : ""), onClick: () => copy(markdownToText(text)), "aria-label": "Copy message", children: [
14028
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("i", { className: "ph ph-" + (copied ? "check" : "copy"), "aria-hidden": "true" }),
14029
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "fdc-act-label", children: copied ? "Copied" : "Copy" })
14116
+ return /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fdc-actions", role: "group", "aria-label": "Message actions", children: [
14117
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("button", { type: "button", className: "fdc-act" + (copied ? " is-done" : ""), onClick: () => copy(markdownToText(text)), "aria-label": "Copy message", children: [
14118
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("i", { className: "ph ph-" + (copied ? "check" : "copy"), "aria-hidden": "true" }),
14119
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fdc-act-label", children: copied ? "Copied" : "Copy" })
14030
14120
  ] }),
14031
- isAssistant && ctx.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("button", { type: "button", className: "fdc-act", onClick: ctx.onRetry, "aria-label": "Retry this turn", children: /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
14032
- group.role === "user" && ctx.onEdit ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("button", { type: "button", className: "fdc-act", onClick: () => ctx.onEdit(last), "aria-label": "Edit and resend", children: /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("i", { className: "ph ph-pencil-simple", "aria-hidden": "true" }) }) : null,
14033
- isAssistant && ctx.onFeedback ? /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)(React70.Fragment, { children: [
14034
- /* @__PURE__ */ (0, import_jsx_runtime99.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_runtime99.jsx)("i", { className: "ph ph-thumbs-up", "aria-hidden": "true" }) }),
14035
- /* @__PURE__ */ (0, import_jsx_runtime99.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_runtime99.jsx)("i", { className: "ph ph-thumbs-down", "aria-hidden": "true" }) })
14121
+ isAssistant && ctx.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("button", { type: "button", className: "fdc-act", onClick: ctx.onRetry, "aria-label": "Retry this turn", children: /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
14122
+ group.role === "user" && ctx.onEdit ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("button", { type: "button", className: "fdc-act", onClick: () => ctx.onEdit(last), "aria-label": "Edit and resend", children: /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("i", { className: "ph ph-pencil-simple", "aria-hidden": "true" }) }) : null,
14123
+ isAssistant && ctx.onFeedback ? /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)(React71.Fragment, { children: [
14124
+ /* @__PURE__ */ (0, import_jsx_runtime101.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_runtime101.jsx)("i", { className: "ph ph-thumbs-up", "aria-hidden": "true" }) }),
14125
+ /* @__PURE__ */ (0, import_jsx_runtime101.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_runtime101.jsx)("i", { className: "ph ph-thumbs-down", "aria-hidden": "true" }) })
14036
14126
  ] }) : null,
14037
14127
  ctx.extraActions ? ctx.extraActions(group) : null
14038
14128
  ] });
@@ -14042,22 +14132,22 @@ function ChatTurn({ group, ctx }) {
14042
14132
  const name = isUser ? ctx.userName : group.author || ctx.assistantName;
14043
14133
  const avatar = isUser ? ctx.userAvatar : ctx.assistantAvatar;
14044
14134
  const stamp = group.messages[0].timestamp;
14045
- return /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("article", { className: "fdc-turn is-" + group.role, "aria-label": String(name) + (stamp ? " at " + formatClock(stamp) : ""), children: [
14046
- /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("div", { className: "fdc-turn-head", children: [
14047
- ctx.showAvatars ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "fdc-avatar is-" + group.role, "aria-hidden": "true", children: avatar ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("img", { src: avatar, alt: "" }) : isUser ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "fdc-avatar-txt", children: (name || "You").slice(0, 1).toUpperCase() }) : /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("i", { className: "ph ph-" + (ctx.assistantIcon || "sparkle") }) }) : null,
14048
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "fdc-who", children: name }),
14049
- stamp ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(RelativeTime, { className: "fdc-when", value: stamp }) : null,
14050
- group.messages.some((m) => m.model) ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "fdc-turn-model", children: group.messages.find((m) => m.model).model }) : null
14135
+ return /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("article", { className: "fdc-turn is-" + group.role, "aria-label": String(name) + (stamp ? " at " + formatClock(stamp) : ""), children: [
14136
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fdc-turn-head", children: [
14137
+ ctx.showAvatars ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fdc-avatar is-" + group.role, "aria-hidden": "true", children: avatar ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("img", { src: avatar, alt: "" }) : isUser ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fdc-avatar-txt", children: (name || "You").slice(0, 1).toUpperCase() }) : /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("i", { className: "ph ph-" + (ctx.assistantIcon || "sparkle") }) }) : null,
14138
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fdc-who", children: name }),
14139
+ stamp ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(RelativeTime, { className: "fdc-when", value: stamp }) : null,
14140
+ group.messages.some((m) => m.model) ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fdc-turn-model", children: group.messages.find((m) => m.model).model }) : null
14051
14141
  ] }),
14052
- /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("div", { className: "fdc-turn-body", children: [
14053
- group.messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("div", { className: "fdc-msg" + (m.pending ? " is-pending" : ""), children: /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(MessageBody, { message: m, ctx }) }, m.id)),
14054
- /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(RunActions, { group, ctx })
14142
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fdc-turn-body", children: [
14143
+ group.messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("div", { className: "fdc-msg" + (m.pending ? " is-pending" : ""), children: /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(MessageBody, { message: m, ctx }) }, m.id)),
14144
+ /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(RunActions, { group, ctx })
14055
14145
  ] })
14056
14146
  ] });
14057
14147
  }
14058
14148
 
14059
14149
  // src/components/chat/ChatTranscript.tsx
14060
- var import_jsx_runtime100 = require("react/jsx-runtime");
14150
+ var import_jsx_runtime102 = require("react/jsx-runtime");
14061
14151
  var GROUP_WINDOW = 6e4;
14062
14152
  var STICK_PX = 100;
14063
14153
  function groupMessages(list) {
@@ -14090,25 +14180,25 @@ function dayLabel(key) {
14090
14180
  }
14091
14181
  function Suggestions({ items = [], onPick }) {
14092
14182
  if (!items.length) return null;
14093
- return /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("div", { className: "fdc-suggest", children: items.map((s, i) => {
14183
+ return /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("div", { className: "fdc-suggest", children: items.map((s, i) => {
14094
14184
  const it = typeof s === "string" ? { label: s, text: s } : s;
14095
- return /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("button", { type: "button", className: "fdc-suggest-item", onClick: () => onPick && onPick(it.text || it.label), children: [
14096
- it.icon ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("i", { className: "ph ph-" + it.icon, "aria-hidden": "true" }) : null,
14097
- /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("span", { className: "fdc-suggest-text", children: [
14098
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "fdc-suggest-label", children: it.label }),
14099
- it.description ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "fdc-suggest-desc", children: it.description }) : null
14185
+ return /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)("button", { type: "button", className: "fdc-suggest-item", onClick: () => onPick && onPick(it.text || it.label), children: [
14186
+ it.icon ? /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("i", { className: "ph ph-" + it.icon, "aria-hidden": "true" }) : null,
14187
+ /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)("span", { className: "fdc-suggest-text", children: [
14188
+ /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("span", { className: "fdc-suggest-label", children: it.label }),
14189
+ it.description ? /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("span", { className: "fdc-suggest-desc", children: it.description }) : null
14100
14190
  ] }),
14101
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("i", { className: "ph ph-arrow-up-right fdc-suggest-go", "aria-hidden": "true" })
14191
+ /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("i", { className: "ph ph-arrow-up-right fdc-suggest-go", "aria-hidden": "true" })
14102
14192
  ] }, it.id || i);
14103
14193
  }) });
14104
14194
  }
14105
14195
  function LoadingTurns() {
14106
- return /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("div", { className: "fdc-skel", "aria-hidden": "true", children: [0, 1].map((i) => /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: "fdc-skel-turn", children: [
14107
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("div", { className: "fd-skel fd-skel-circle", style: { width: 22, height: 22 } }),
14108
- /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: "fdc-skel-lines", children: [
14109
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("div", { className: "fd-skel", style: { width: i ? "62%" : "44%", height: 11 } }),
14110
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("div", { className: "fd-skel", style: { width: i ? "94%" : "78%", height: 11 } }),
14111
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("div", { className: "fd-skel", style: { width: i ? "71%" : "56%", height: 11 } })
14196
+ return /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("div", { className: "fdc-skel", "aria-hidden": "true", children: [0, 1].map((i) => /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)("div", { className: "fdc-skel-turn", children: [
14197
+ /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("div", { className: "fd-skel fd-skel-circle", style: { width: 22, height: 22 } }),
14198
+ /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)("div", { className: "fdc-skel-lines", children: [
14199
+ /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("div", { className: "fd-skel", style: { width: i ? "62%" : "44%", height: 11 } }),
14200
+ /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("div", { className: "fd-skel", style: { width: i ? "94%" : "78%", height: 11 } }),
14201
+ /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("div", { className: "fd-skel", style: { width: i ? "71%" : "56%", height: 11 } })
14112
14202
  ] })
14113
14203
  ] }, i)) });
14114
14204
  }
@@ -14125,10 +14215,10 @@ function ChatTranscript({
14125
14215
  renderEmpty,
14126
14216
  className = ""
14127
14217
  }) {
14128
- const scroller = React71.useRef(null);
14129
- const stick = React71.useRef(true);
14130
- const [pill, setPill] = React71.useState(0);
14131
- const seen = React71.useRef(0);
14218
+ const scroller = React72.useRef(null);
14219
+ const stick = React72.useRef(true);
14220
+ const [pill, setPill] = React72.useState(0);
14221
+ const seen = React72.useRef(0);
14132
14222
  const toBottom = (smooth) => {
14133
14223
  const el = scroller.current;
14134
14224
  if (!el) return;
@@ -14147,7 +14237,7 @@ function ChatTranscript({
14147
14237
  seen.current = messages.length;
14148
14238
  }
14149
14239
  };
14150
- React71.useLayoutEffect(() => {
14240
+ React72.useLayoutEffect(() => {
14151
14241
  const el = scroller.current;
14152
14242
  if (!el) return;
14153
14243
  if (stick.current) {
@@ -14155,7 +14245,7 @@ function ChatTranscript({
14155
14245
  seen.current = messages.length;
14156
14246
  } else setPill(Math.max(0, messages.length - seen.current));
14157
14247
  }, [messages]);
14158
- React71.useEffect(() => {
14248
+ React72.useEffect(() => {
14159
14249
  const el = scroller.current;
14160
14250
  const inner = el && el.firstChild;
14161
14251
  if (!el || !inner || typeof ResizeObserver === "undefined") return;
@@ -14165,38 +14255,38 @@ function ChatTranscript({
14165
14255
  ro.observe(inner);
14166
14256
  return () => ro.disconnect();
14167
14257
  }, []);
14168
- const groups = React71.useMemo(() => groupMessages(messages), [messages]);
14258
+ const groups = React72.useMemo(() => groupMessages(messages), [messages]);
14169
14259
  const empty = !messages.length && status === "ready";
14170
- return /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
14171
- /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
14172
- status === "loading" || status === "resolving" ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(LoadingTurns, {}) : null,
14173
- status === "disconnected" ? /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: "fdc-dead", children: [
14174
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "fdc-dead-icon", children: /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("i", { className: "ph ph-plugs", "aria-hidden": "true" }) }),
14175
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("h3", { className: "fdc-dead-title", children: ctx.deadTitle || "The assistant isn\u2019t reachable" }),
14176
- /* @__PURE__ */ (0, import_jsx_runtime100.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." }),
14177
- ctx.onReconnect ? /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("button", { type: "button", className: "fd-btn fd-btn-secondary fd-btn-sm", onClick: ctx.onReconnect, children: [
14178
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
14260
+ return /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
14261
+ /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
14262
+ status === "loading" || status === "resolving" ? /* @__PURE__ */ (0, import_jsx_runtime102.jsx)(LoadingTurns, {}) : null,
14263
+ status === "disconnected" ? /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)("div", { className: "fdc-dead", children: [
14264
+ /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("span", { className: "fdc-dead-icon", children: /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("i", { className: "ph ph-plugs", "aria-hidden": "true" }) }),
14265
+ /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("h3", { className: "fdc-dead-title", children: ctx.deadTitle || "The assistant isn\u2019t reachable" }),
14266
+ /* @__PURE__ */ (0, import_jsx_runtime102.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." }),
14267
+ ctx.onReconnect ? /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)("button", { type: "button", className: "fd-btn fd-btn-secondary fd-btn-sm", onClick: ctx.onReconnect, children: [
14268
+ /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
14179
14269
  "Try again"
14180
14270
  ] }) : null
14181
14271
  ] }) : null,
14182
- empty ? renderEmpty ? renderEmpty() : /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: "fdc-empty", children: [
14183
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "fdc-empty-icon", children: /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("i", { className: "ph ph-" + emptyIcon, "aria-hidden": "true" }) }),
14184
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("h3", { className: "fdc-empty-title", children: emptyTitle }),
14185
- emptyDescription ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("p", { className: "fdc-empty-body", children: emptyDescription }) : null,
14186
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Suggestions, { items: suggestions, onPick })
14272
+ empty ? renderEmpty ? renderEmpty() : /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)("div", { className: "fdc-empty", children: [
14273
+ /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("span", { className: "fdc-empty-icon", children: /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("i", { className: "ph ph-" + emptyIcon, "aria-hidden": "true" }) }),
14274
+ /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("h3", { className: "fdc-empty-title", children: emptyTitle }),
14275
+ emptyDescription ? /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("p", { className: "fdc-empty-body", children: emptyDescription }) : null,
14276
+ /* @__PURE__ */ (0, import_jsx_runtime102.jsx)(Suggestions, { items: suggestions, onPick })
14187
14277
  ] }) : null,
14188
14278
  groups.map((g, i) => {
14189
14279
  const prev = groups[i - 1];
14190
14280
  const k = dayKey(g.messages[0].timestamp);
14191
14281
  const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
14192
- return /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)(React71.Fragment, { children: [
14193
- showDay ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("div", { className: "fdc-day", children: /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { children: dayLabel(k) }) }) : null,
14194
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(ChatTurn, { group: g, ctx })
14282
+ return /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)(React72.Fragment, { children: [
14283
+ showDay ? /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("div", { className: "fdc-day", children: /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("span", { children: dayLabel(k) }) }) : null,
14284
+ /* @__PURE__ */ (0, import_jsx_runtime102.jsx)(ChatTurn, { group: g, ctx })
14195
14285
  ] }, g.key || i);
14196
14286
  })
14197
14287
  ] }),
14198
- pill ? /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("button", { type: "button", className: "fdc-pill", onClick: () => toBottom(true), children: [
14199
- /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("i", { className: "ph ph-arrow-down", "aria-hidden": "true" }),
14288
+ pill ? /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)("button", { type: "button", className: "fdc-pill", onClick: () => toBottom(true), children: [
14289
+ /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("i", { className: "ph ph-arrow-down", "aria-hidden": "true" }),
14200
14290
  pill,
14201
14291
  " new message",
14202
14292
  pill === 1 ? "" : "s"
@@ -14206,8 +14296,8 @@ function ChatTranscript({
14206
14296
  var TranscriptKit = { groupMessages };
14207
14297
 
14208
14298
  // src/components/chat/ChatComposer.tsx
14209
- var React72 = __toESM(require("react"), 1);
14210
- var import_jsx_runtime101 = require("react/jsx-runtime");
14299
+ var React73 = __toESM(require("react"), 1);
14300
+ var import_jsx_runtime103 = require("react/jsx-runtime");
14211
14301
  function ChatComposer({
14212
14302
  onSubmit,
14213
14303
  onStop,
@@ -14234,17 +14324,17 @@ function ChatComposer({
14234
14324
  onReject,
14235
14325
  onOpenAttachment
14236
14326
  }) {
14237
- const [text, setText] = React72.useState(draft || "");
14238
- const [trigger, setTrigger] = React72.useState(null);
14239
- const [mentionItems, setMentionItems] = React72.useState([]);
14240
- const [listening, setListening] = React72.useState(false);
14241
- const [notice, setNotice] = React72.useState(null);
14242
- const editor = React72.useRef(null);
14243
- const wrap = React72.useRef(null);
14244
- const stopVoice = React72.useRef(null);
14327
+ const [text, setText] = React73.useState(draft || "");
14328
+ const [trigger, setTrigger] = React73.useState(null);
14329
+ const [mentionItems, setMentionItems] = React73.useState([]);
14330
+ const [listening, setListening] = React73.useState(false);
14331
+ const [notice, setNotice] = React73.useState(null);
14332
+ const editor = React73.useRef(null);
14333
+ const wrap = React73.useRef(null);
14334
+ const stopVoice = React73.useRef(null);
14245
14335
  const staged = useStagedFiles(fileUploadHandler, { onError: () => {
14246
14336
  } });
14247
- React72.useEffect(() => {
14337
+ React73.useEffect(() => {
14248
14338
  if (draft != null && draft !== text) setText(draft);
14249
14339
  }, [draft]);
14250
14340
  const change = (v) => {
@@ -14280,7 +14370,7 @@ function ChatComposer({
14280
14370
  e.preventDefault();
14281
14371
  staged.add(found.files);
14282
14372
  };
14283
- React72.useEffect(() => {
14373
+ React73.useEffect(() => {
14284
14374
  if (!trigger || trigger.type !== "mention" || !mentionSources) {
14285
14375
  setMentionItems([]);
14286
14376
  return;
@@ -14298,7 +14388,7 @@ function ChatComposer({
14298
14388
  const q = (trigger.query || "").toLowerCase();
14299
14389
  setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
14300
14390
  }, [trigger, mentionSources]);
14301
- const slashItems = React72.useMemo(() => {
14391
+ const slashItems = React73.useMemo(() => {
14302
14392
  if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
14303
14393
  const q = (trigger.query || "").toLowerCase();
14304
14394
  return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
@@ -14312,7 +14402,7 @@ function ChatComposer({
14312
14402
  description: it.description,
14313
14403
  icon: it.icon,
14314
14404
  meta: mention.meta,
14315
- shortcut: slash.shortcut ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(KeyHint, { keys: slash.shortcut, size: "sm" }) : void 0,
14405
+ shortcut: slash.shortcut ? /* @__PURE__ */ (0, import_jsx_runtime103.jsx)(KeyHint, { keys: slash.shortcut, size: "sm" }) : void 0,
14316
14406
  onSelect: () => {
14317
14407
  const insert = trigger.type === "slash" ? slash.immediate ? "/" + slash.id : "/" + slash.id + " " : "@" + (mention.value || mention.label) + " ";
14318
14408
  editor.current && editor.current.replaceRange(trigger.from, trigger.to, insert);
@@ -14371,14 +14461,14 @@ function ChatComposer({
14371
14461
  stopVoice.current = typeof res === "function" ? res : () => {
14372
14462
  };
14373
14463
  };
14374
- return /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fdc-composer" + (disabled ? " is-disabled" : "") + (narrow ? " is-narrow" : ""), children: [
14375
- queue.length ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("div", { className: "fdc-queue", "aria-label": "Queued messages", children: queue.map((q) => /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fdc-queue-row", children: [
14376
- /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("i", { className: "ph ph-clock-countdown", "aria-hidden": "true" }),
14377
- /* @__PURE__ */ (0, import_jsx_runtime101.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)" : "") }),
14378
- onRemoveQueued ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("button", { type: "button", className: "fdc-queue-x", onClick: () => onRemoveQueued(q.id), "aria-label": "Remove queued message", children: /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
14464
+ return /* @__PURE__ */ (0, import_jsx_runtime103.jsxs)("div", { className: "fdc-composer" + (disabled ? " is-disabled" : "") + (narrow ? " is-narrow" : ""), children: [
14465
+ queue.length ? /* @__PURE__ */ (0, import_jsx_runtime103.jsx)("div", { className: "fdc-queue", "aria-label": "Queued messages", children: queue.map((q) => /* @__PURE__ */ (0, import_jsx_runtime103.jsxs)("div", { className: "fdc-queue-row", children: [
14466
+ /* @__PURE__ */ (0, import_jsx_runtime103.jsx)("i", { className: "ph ph-clock-countdown", "aria-hidden": "true" }),
14467
+ /* @__PURE__ */ (0, import_jsx_runtime103.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)" : "") }),
14468
+ onRemoveQueued ? /* @__PURE__ */ (0, import_jsx_runtime103.jsx)("button", { type: "button", className: "fdc-queue-x", onClick: () => onRemoveQueued(q.id), "aria-label": "Remove queued message", children: /* @__PURE__ */ (0, import_jsx_runtime103.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
14379
14469
  ] }, q.id)) }) : null,
14380
14470
  sessionBar,
14381
- /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
14471
+ /* @__PURE__ */ (0, import_jsx_runtime103.jsx)(
14382
14472
  Dropzone,
14383
14473
  {
14384
14474
  className: "fdc-field",
@@ -14392,9 +14482,9 @@ function ChatComposer({
14392
14482
  disabled: !fileUploadHandler || disabled,
14393
14483
  label: "Drop to attach",
14394
14484
  hint: acceptFiles ? acceptFiles.replace(/,/g, " \xB7 ") : void 0,
14395
- children: /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { ref: wrap, className: "fdc-field-inner", children: [
14396
- staged.items.length ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("div", { className: "fdc-staged", children: /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(FileStrip, { files: staged.items, size: narrow ? 60 : 68, onRemove: staged.remove, onRetry: staged.retry, onOpen: onOpenAttachment }) }) : null,
14397
- /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
14485
+ children: /* @__PURE__ */ (0, import_jsx_runtime103.jsxs)("div", { ref: wrap, className: "fdc-field-inner", children: [
14486
+ staged.items.length ? /* @__PURE__ */ (0, import_jsx_runtime103.jsx)("div", { className: "fdc-staged", children: /* @__PURE__ */ (0, import_jsx_runtime103.jsx)(FileStrip, { files: staged.items, size: narrow ? 60 : 68, onRemove: staged.remove, onRetry: staged.retry, onOpen: onOpenAttachment }) }) : null,
14487
+ /* @__PURE__ */ (0, import_jsx_runtime103.jsx)(
14398
14488
  MarkdownEditor,
14399
14489
  {
14400
14490
  ref: editor,
@@ -14413,33 +14503,33 @@ function ChatComposer({
14413
14503
  ariaLabel: "Message"
14414
14504
  }
14415
14505
  ),
14416
- /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fdc-tools", children: [
14417
- fileUploadHandler ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(FilePickButton, { onFiles: staged.add, onReject: (r) => flash(r[0].message), accept: acceptFiles, maxFileSize, label: "Attach files", icon: "plus" }) : null,
14418
- voiceHandler ? /* @__PURE__ */ (0, import_jsx_runtime101.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_runtime101.jsx)("i", { className: "ph ph-" + (listening ? "waveform" : "microphone"), "aria-hidden": "true" }) }) : null,
14506
+ /* @__PURE__ */ (0, import_jsx_runtime103.jsxs)("div", { className: "fdc-tools", children: [
14507
+ fileUploadHandler ? /* @__PURE__ */ (0, import_jsx_runtime103.jsx)(FilePickButton, { onFiles: staged.add, onReject: (r) => flash(r[0].message), accept: acceptFiles, maxFileSize, label: "Attach files", icon: "plus" }) : null,
14508
+ voiceHandler ? /* @__PURE__ */ (0, import_jsx_runtime103.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_runtime103.jsx)("i", { className: "ph ph-" + (listening ? "waveform" : "microphone"), "aria-hidden": "true" }) }) : null,
14419
14509
  toolbarExtras,
14420
- /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fdc-tools-gap" }),
14421
- maxLength && text.length > maxLength * 0.6 ? /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("span", { className: "fdc-count fd-tabular" + (text.length > maxLength * 0.95 ? " is-hot" : ""), children: [
14510
+ /* @__PURE__ */ (0, import_jsx_runtime103.jsx)("span", { className: "fdc-tools-gap" }),
14511
+ maxLength && text.length > maxLength * 0.6 ? /* @__PURE__ */ (0, import_jsx_runtime103.jsxs)("span", { className: "fdc-count fd-tabular" + (text.length > maxLength * 0.95 ? " is-hot" : ""), children: [
14422
14512
  text.length,
14423
14513
  "/",
14424
14514
  maxLength
14425
14515
  ] }) : null,
14426
- busy ? /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("button", { type: "button", className: "fdc-stop", onClick: onStop, "aria-label": "Stop generating", children: [
14427
- /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
14428
- /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { children: "Stop" })
14429
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("button", { type: "button", className: "fdc-send", onClick: submit, disabled: !canSend, "aria-label": "Send message", children: [
14430
- /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("i", { className: "ph ph-paper-plane-right", "aria-hidden": "true" }),
14431
- /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fdc-send-label", children: "Send" })
14516
+ busy ? /* @__PURE__ */ (0, import_jsx_runtime103.jsxs)("button", { type: "button", className: "fdc-stop", onClick: onStop, "aria-label": "Stop generating", children: [
14517
+ /* @__PURE__ */ (0, import_jsx_runtime103.jsx)("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
14518
+ /* @__PURE__ */ (0, import_jsx_runtime103.jsx)("span", { children: "Stop" })
14519
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime103.jsxs)("button", { type: "button", className: "fdc-send", onClick: submit, disabled: !canSend, "aria-label": "Send message", children: [
14520
+ /* @__PURE__ */ (0, import_jsx_runtime103.jsx)("i", { className: "ph ph-paper-plane-right", "aria-hidden": "true" }),
14521
+ /* @__PURE__ */ (0, import_jsx_runtime103.jsx)("span", { className: "fdc-send-label", children: "Send" })
14432
14522
  ] })
14433
14523
  ] })
14434
14524
  ] })
14435
14525
  }
14436
14526
  ),
14437
- notice ? /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fdc-notice", role: "status", children: [
14438
- /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
14527
+ notice ? /* @__PURE__ */ (0, import_jsx_runtime103.jsxs)("div", { className: "fdc-notice", role: "status", children: [
14528
+ /* @__PURE__ */ (0, import_jsx_runtime103.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
14439
14529
  notice
14440
14530
  ] }) : null,
14441
- hint && !notice ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("div", { className: "fdc-hint", children: hint }) : null,
14442
- /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
14531
+ hint && !notice ? /* @__PURE__ */ (0, import_jsx_runtime103.jsx)("div", { className: "fdc-hint", children: hint }) : null,
14532
+ /* @__PURE__ */ (0, import_jsx_runtime103.jsx)(
14443
14533
  Popover,
14444
14534
  {
14445
14535
  open: menuOpen,
@@ -14453,12 +14543,12 @@ function ChatComposer({
14453
14543
  returnFocus: false,
14454
14544
  closeOnOutside: true,
14455
14545
  label: trigger && trigger.type === "slash" ? "Commands" : "Mentions",
14456
- children: /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
14546
+ children: /* @__PURE__ */ (0, import_jsx_runtime103.jsx)(
14457
14547
  Menu,
14458
14548
  {
14459
14549
  items: menuItems,
14460
14550
  autoFocus: false,
14461
- header: /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("div", { className: "fd-pop-group", children: trigger && trigger.type === "slash" ? "Commands" : "Attach context" }),
14551
+ header: /* @__PURE__ */ (0, import_jsx_runtime103.jsx)("div", { className: "fd-pop-group", children: trigger && trigger.type === "slash" ? "Commands" : "Attach context" }),
14462
14552
  onClose: () => setTrigger(null)
14463
14553
  }
14464
14554
  )
@@ -14468,12 +14558,12 @@ function ChatComposer({
14468
14558
  }
14469
14559
 
14470
14560
  // src/components/chat/ChatSessionBar.tsx
14471
- var React73 = __toESM(require("react"), 1);
14472
- var import_jsx_runtime102 = require("react/jsx-runtime");
14561
+ var React74 = __toESM(require("react"), 1);
14562
+ var import_jsx_runtime104 = require("react/jsx-runtime");
14473
14563
  var compact2 = meterFormats.compact;
14474
14564
  function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
14475
- const [open2, setOpen] = React73.useState(false);
14476
- const anchor = React73.useRef(null);
14565
+ const [open2, setOpen] = React74.useState(false);
14566
+ const anchor = React74.useRef(null);
14477
14567
  const stats = sessionStats || null;
14478
14568
  const cu = contextUsage || null;
14479
14569
  const limits = usageLimits || null;
@@ -14488,9 +14578,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
14488
14578
  if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
14489
14579
  if (cu) bits.push(pct + "% context");
14490
14580
  const expandable = !!(cu || limits);
14491
- return /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)(React73.Fragment, { children: [
14492
- /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)("div", { className: "fdc-bar", children: [
14493
- /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)(
14581
+ return /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)(React74.Fragment, { children: [
14582
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: "fdc-bar", children: [
14583
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)(
14494
14584
  "button",
14495
14585
  {
14496
14586
  type: "button",
@@ -14501,15 +14591,15 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
14501
14591
  "aria-expanded": expandable ? open2 : void 0,
14502
14592
  "aria-label": expandable ? "Usage details" : void 0,
14503
14593
  children: [
14504
- cu ? /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("span", { className: "fdc-bar-mini", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime102.jsx)(SegmentedMeter, { total, segments: cu.segments, height: 4, showTotal: false }) }) : null,
14505
- /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("span", { className: "fdc-bar-text", title: truncationTitle(bits.join(" \xB7 ")), children: bits.join(" \xB7 ") }),
14506
- expandable ? /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("i", { className: "ph ph-caret-right fdc-bar-caret", "aria-hidden": "true" }) : null
14594
+ cu ? /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("span", { className: "fdc-bar-mini", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(SegmentedMeter, { total, segments: cu.segments, height: 4, showTotal: false }) }) : null,
14595
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("span", { className: "fdc-bar-text", title: truncationTitle(bits.join(" \xB7 ")), children: bits.join(" \xB7 ") }),
14596
+ expandable ? /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("i", { className: "ph ph-caret-right fdc-bar-caret", "aria-hidden": "true" }) : null
14507
14597
  ]
14508
14598
  }
14509
14599
  ),
14510
14600
  extras
14511
14601
  ] }),
14512
- /* @__PURE__ */ (0, import_jsx_runtime102.jsx)(
14602
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(
14513
14603
  Popover,
14514
14604
  {
14515
14605
  open: open2,
@@ -14520,15 +14610,15 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
14520
14610
  maxHeight: 460,
14521
14611
  padded: true,
14522
14612
  label: "Usage",
14523
- footer: onClear ? /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)("button", { type: "button", className: "fdc-usage-clear", onClick: () => {
14613
+ footer: onClear ? /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("button", { type: "button", className: "fdc-usage-clear", onClick: () => {
14524
14614
  setOpen(false);
14525
14615
  onClear();
14526
14616
  }, children: [
14527
- /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("i", { className: "ph ph-trash", "aria-hidden": "true" }),
14617
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("i", { className: "ph ph-trash", "aria-hidden": "true" }),
14528
14618
  "Clear conversation"
14529
14619
  ] }) : void 0,
14530
- children: /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)("div", { className: "fdc-usage", children: [
14531
- cu ? /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("section", { className: "fdc-usage-sec", children: /* @__PURE__ */ (0, import_jsx_runtime102.jsx)(
14620
+ children: /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: "fdc-usage", children: [
14621
+ cu ? /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("section", { className: "fdc-usage-sec", children: /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(
14532
14622
  SegmentedMeter,
14533
14623
  {
14534
14624
  total,
@@ -14540,9 +14630,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
14540
14630
  remainderLabel: "Free"
14541
14631
  }
14542
14632
  ) }) : null,
14543
- limits && limits.length ? /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)("section", { className: "fdc-usage-sec", children: [
14544
- /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("h4", { className: "fdc-usage-h", children: "Usage limits" }),
14545
- /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("div", { className: "fdc-usage-rows", children: limits.map((l) => /* @__PURE__ */ (0, import_jsx_runtime102.jsx)(
14633
+ limits && limits.length ? /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("section", { className: "fdc-usage-sec", children: [
14634
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("h4", { className: "fdc-usage-h", children: "Usage limits" }),
14635
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("div", { className: "fdc-usage-rows", children: limits.map((l) => /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(
14546
14636
  QuotaRow,
14547
14637
  {
14548
14638
  label: l.label,
@@ -14552,25 +14642,25 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
14552
14642
  l.id
14553
14643
  )) })
14554
14644
  ] }) : null,
14555
- stats ? /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)("section", { className: "fdc-usage-sec fdc-usage-stats", children: [
14556
- stats.elapsedMs ? /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)("div", { children: [
14557
- /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("span", { children: "Session" }),
14558
- /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("b", { className: "fd-tabular", children: formatDuration(stats.elapsedMs) })
14645
+ stats ? /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("section", { className: "fdc-usage-sec fdc-usage-stats", children: [
14646
+ stats.elapsedMs ? /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { children: [
14647
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("span", { children: "Session" }),
14648
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("b", { className: "fd-tabular", children: formatDuration(stats.elapsedMs) })
14559
14649
  ] }) : null,
14560
- stats.tokens ? /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)("div", { children: [
14561
- /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("span", { children: "Tokens" }),
14562
- /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("b", { className: "fd-tabular", children: stats.tokens.toLocaleString() })
14650
+ stats.tokens ? /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { children: [
14651
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("span", { children: "Tokens" }),
14652
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("b", { className: "fd-tabular", children: stats.tokens.toLocaleString() })
14563
14653
  ] }) : null,
14564
- stats.costUsd != null ? /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)("div", { children: [
14565
- /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("span", { children: "Cost" }),
14566
- /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)("b", { className: "fd-tabular", children: [
14654
+ stats.costUsd != null ? /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { children: [
14655
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("span", { children: "Cost" }),
14656
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("b", { className: "fd-tabular", children: [
14567
14657
  "$",
14568
14658
  Number(stats.costUsd).toFixed(3)
14569
14659
  ] })
14570
14660
  ] }) : null,
14571
- stats.turns ? /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)("div", { children: [
14572
- /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("span", { children: "Turns" }),
14573
- /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("b", { className: "fd-tabular", children: stats.turns })
14661
+ stats.turns ? /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { children: [
14662
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("span", { children: "Turns" }),
14663
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("b", { className: "fd-tabular", children: stats.turns })
14574
14664
  ] }) : null
14575
14665
  ] }) : null
14576
14666
  ] })
@@ -14609,7 +14699,7 @@ function ModelControls({
14609
14699
  disabled: m.disabled,
14610
14700
  checked: m.id === (current2 && current2.id),
14611
14701
  meta: m.meta,
14612
- shortcut: m.shortcut ? /* @__PURE__ */ (0, import_jsx_runtime102.jsx)(KeyHint, { keys: m.shortcut, size: "sm" }) : void 0,
14702
+ shortcut: m.shortcut ? /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(KeyHint, { keys: m.shortcut, size: "sm" }) : void 0,
14613
14703
  onSelect: () => onModelChange && onModelChange(m.id)
14614
14704
  });
14615
14705
  const items = [{ kind: "section", label: "Models" }].concat(flat.map(item));
@@ -14622,15 +14712,15 @@ function ModelControls({
14622
14712
  items.push({ kind: "section", label: "Fast mode" });
14623
14713
  items.push({
14624
14714
  kind: "custom",
14625
- render: () => /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)("label", { className: "fdc-switchrow", children: [
14626
- /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("span", { children: fastModeLabel }),
14627
- /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("input", { type: "checkbox", className: "fd-sr", checked: !!fastMode, onChange: (e) => onFastModeChange(e.target.checked) }),
14628
- /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("span", { className: "fd-switch-track" + (fastMode ? " is-on" : ""), "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("span", { className: "fd-switch-thumb" }) })
14715
+ render: () => /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("label", { className: "fdc-switchrow", children: [
14716
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("span", { children: fastModeLabel }),
14717
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("input", { type: "checkbox", className: "fd-sr", checked: !!fastMode, onChange: (e) => onFastModeChange(e.target.checked) }),
14718
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("span", { className: "fd-switch-track" + (fastMode ? " is-on" : ""), "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("span", { className: "fd-switch-thumb" }) })
14629
14719
  ] })
14630
14720
  });
14631
14721
  }
14632
- return /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)(React73.Fragment, { children: [
14633
- /* @__PURE__ */ (0, import_jsx_runtime102.jsx)(
14722
+ return /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)(React74.Fragment, { children: [
14723
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(
14634
14724
  MenuButton,
14635
14725
  {
14636
14726
  items,
@@ -14641,7 +14731,7 @@ function ModelControls({
14641
14731
  title: "Choose a model"
14642
14732
  }
14643
14733
  ),
14644
- effortLevels && effortLevels.length ? /* @__PURE__ */ (0, import_jsx_runtime102.jsx)(
14734
+ effortLevels && effortLevels.length ? /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(
14645
14735
  MenuButton,
14646
14736
  {
14647
14737
  placement: "top-end",
@@ -14662,7 +14752,7 @@ function ModelControls({
14662
14752
  }
14663
14753
 
14664
14754
  // src/components/chat/AgentChatPanel.tsx
14665
- var import_jsx_runtime103 = require("react/jsx-runtime");
14755
+ var import_jsx_runtime105 = require("react/jsx-runtime");
14666
14756
  var SURFACES = { sidebar: "is-sidebar", inline: "is-inline", page: "is-page", modal: "is-modal", sheet: "is-sheet" };
14667
14757
  function AgentChatPanel({
14668
14758
  /* required */
@@ -14696,6 +14786,7 @@ function AgentChatPanel({
14696
14786
  packetSchemas,
14697
14787
  packetRenderers,
14698
14788
  onApplyPacket,
14789
+ pendingTimeoutMs,
14699
14790
  onOpenAttachment,
14700
14791
  errorCopy,
14701
14792
  /* composer */
@@ -14746,17 +14837,18 @@ function AgentChatPanel({
14746
14837
  onFeedback,
14747
14838
  onEditMessage
14748
14839
  }) {
14749
- const [panelWidth, setPanelWidth] = React74.useState(width);
14750
- const [applied, setApplied] = React74.useState({});
14751
- const [draft, setDraft] = React74.useState("");
14752
- const dragging = React74.useRef(null);
14753
- React74.useEffect(() => setPanelWidth(width), [width]);
14840
+ const [panelWidth, setPanelWidth] = React75.useState(width);
14841
+ const [applied, setApplied] = React75.useState({});
14842
+ const [draft, setDraft] = React75.useState("");
14843
+ const dragging = React75.useRef(null);
14844
+ React75.useEffect(() => setPanelWidth(width), [width]);
14754
14845
  const engine = useChatEngine({
14755
14846
  contextType,
14756
14847
  contextId,
14757
14848
  apiAdapter,
14758
14849
  initialMessage,
14759
14850
  threadId,
14851
+ pendingTimeoutMs,
14760
14852
  onPacket,
14761
14853
  onThreadReady,
14762
14854
  onError,
@@ -14816,7 +14908,7 @@ function AgentChatPanel({
14816
14908
  onReconnect: engine.reload,
14817
14909
  deadTitle: "The assistant isn\u2019t reachable"
14818
14910
  };
14819
- const sessionBar = /* @__PURE__ */ (0, import_jsx_runtime103.jsx)(
14911
+ const sessionBar = /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
14820
14912
  ChatSessionBar,
14821
14913
  {
14822
14914
  sessionStats,
@@ -14825,7 +14917,7 @@ function AgentChatPanel({
14825
14917
  onClear: engine.visible.length ? engine.clear : void 0
14826
14918
  }
14827
14919
  );
14828
- const modelControls = /* @__PURE__ */ (0, import_jsx_runtime103.jsx)(
14920
+ const modelControls = /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
14829
14921
  ModelControls,
14830
14922
  {
14831
14923
  models,
@@ -14840,7 +14932,7 @@ function AgentChatPanel({
14840
14932
  narrow
14841
14933
  }
14842
14934
  );
14843
- const threadMenu = threads && threads.length ? /* @__PURE__ */ (0, import_jsx_runtime103.jsx)(
14935
+ const threadMenu = threads && threads.length ? /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
14844
14936
  MenuButton,
14845
14937
  {
14846
14938
  variant: "ghost",
@@ -14867,7 +14959,7 @@ function AgentChatPanel({
14867
14959
  })))
14868
14960
  }
14869
14961
  ) : null;
14870
- return /* @__PURE__ */ (0, import_jsx_runtime103.jsxs)(
14962
+ return /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)(
14871
14963
  "aside",
14872
14964
  {
14873
14965
  className: ["fdc-panel", SURFACES[surface] || SURFACES.sidebar, narrow ? "is-narrow" : "", className].filter(Boolean).join(" "),
@@ -14878,7 +14970,7 @@ function AgentChatPanel({
14878
14970
  },
14879
14971
  "aria-label": title,
14880
14972
  children: [
14881
- surface === "sidebar" && resizable ? /* @__PURE__ */ (0, import_jsx_runtime103.jsx)(
14973
+ surface === "sidebar" && resizable ? /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
14882
14974
  "div",
14883
14975
  {
14884
14976
  className: "fdc-grip",
@@ -14893,20 +14985,20 @@ function AgentChatPanel({
14893
14985
  }
14894
14986
  }
14895
14987
  ) : null,
14896
- showHeader ? /* @__PURE__ */ (0, import_jsx_runtime103.jsxs)("header", { className: "fdc-head", children: [
14897
- /* @__PURE__ */ (0, import_jsx_runtime103.jsx)("span", { className: "fdc-head-mark", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime103.jsx)("i", { className: "ph ph-" + assistantIcon }) }),
14898
- /* @__PURE__ */ (0, import_jsx_runtime103.jsxs)("span", { className: "fdc-head-titles", children: [
14899
- /* @__PURE__ */ (0, import_jsx_runtime103.jsx)("span", { className: "fdc-head-title", title: truncationTitle(title), children: title }),
14900
- subtitle ? /* @__PURE__ */ (0, import_jsx_runtime103.jsx)("span", { className: "fdc-head-sub", title: truncationTitle(subtitle), children: subtitle }) : null
14988
+ showHeader ? /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)("header", { className: "fdc-head", children: [
14989
+ /* @__PURE__ */ (0, import_jsx_runtime105.jsx)("span", { className: "fdc-head-mark", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime105.jsx)("i", { className: "ph ph-" + assistantIcon }) }),
14990
+ /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)("span", { className: "fdc-head-titles", children: [
14991
+ /* @__PURE__ */ (0, import_jsx_runtime105.jsx)("span", { className: "fdc-head-title", title: truncationTitle(title), children: title }),
14992
+ subtitle ? /* @__PURE__ */ (0, import_jsx_runtime105.jsx)("span", { className: "fdc-head-sub", title: truncationTitle(subtitle), children: subtitle }) : null
14901
14993
  ] }),
14902
- /* @__PURE__ */ (0, import_jsx_runtime103.jsxs)("span", { className: "fdc-head-acts", children: [
14994
+ /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)("span", { className: "fdc-head-acts", children: [
14903
14995
  headerActions,
14904
14996
  threadMenu,
14905
- onNewThread ? /* @__PURE__ */ (0, import_jsx_runtime103.jsx)("button", { type: "button", className: "fdc-iconbtn", onClick: onNewThread, "aria-label": "New conversation", title: "New conversation", children: /* @__PURE__ */ (0, import_jsx_runtime103.jsx)("i", { className: "ph ph-plus", "aria-hidden": "true" }) }) : null,
14906
- onClose ? /* @__PURE__ */ (0, import_jsx_runtime103.jsx)("button", { type: "button", className: "fdc-iconbtn", onClick: onClose, "aria-label": "Close panel", title: "Close", children: /* @__PURE__ */ (0, import_jsx_runtime103.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
14997
+ onNewThread ? /* @__PURE__ */ (0, import_jsx_runtime105.jsx)("button", { type: "button", className: "fdc-iconbtn", onClick: onNewThread, "aria-label": "New conversation", title: "New conversation", children: /* @__PURE__ */ (0, import_jsx_runtime105.jsx)("i", { className: "ph ph-plus", "aria-hidden": "true" }) }) : null,
14998
+ onClose ? /* @__PURE__ */ (0, import_jsx_runtime105.jsx)("button", { type: "button", className: "fdc-iconbtn", onClick: onClose, "aria-label": "Close panel", title: "Close", children: /* @__PURE__ */ (0, import_jsx_runtime105.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
14907
14999
  ] })
14908
15000
  ] }) : null,
14909
- /* @__PURE__ */ (0, import_jsx_runtime103.jsx)(
15001
+ /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
14910
15002
  ChatTranscript,
14911
15003
  {
14912
15004
  messages: engine.visible,
@@ -14921,7 +15013,7 @@ function AgentChatPanel({
14921
15013
  renderEmpty
14922
15014
  }
14923
15015
  ),
14924
- /* @__PURE__ */ (0, import_jsx_runtime103.jsx)(
15016
+ /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
14925
15017
  ChatComposer,
14926
15018
  {
14927
15019
  onSubmit: (text, atts) => engine.send(text, atts),
@@ -14954,8 +15046,8 @@ function AgentChatPanel({
14954
15046
  }
14955
15047
 
14956
15048
  // src/components/files/FileViewer.tsx
14957
- var React75 = __toESM(require("react"), 1);
14958
- var import_jsx_runtime104 = require("react/jsx-runtime");
15049
+ var React76 = __toESM(require("react"), 1);
15050
+ var import_jsx_runtime106 = require("react/jsx-runtime");
14959
15051
  function previewKindOf(file) {
14960
15052
  const mime = (file.mime || "").toLowerCase();
14961
15053
  const ext = extensionOf(file.name || "");
@@ -15011,13 +15103,13 @@ function parseDelimited(text, delimiter) {
15011
15103
  return rows;
15012
15104
  }
15013
15105
  function usePreview(file, kind, resolveUrl) {
15014
- const [state, setState] = React75.useState({ status: "loading" });
15015
- const [attempt, setAttempt] = React75.useState(0);
15016
- const resolveRef = React75.useRef(resolveUrl);
15017
- React75.useEffect(() => {
15106
+ const [state, setState] = React76.useState({ status: "loading" });
15107
+ const [attempt, setAttempt] = React76.useState(0);
15108
+ const resolveRef = React76.useRef(resolveUrl);
15109
+ React76.useEffect(() => {
15018
15110
  resolveRef.current = resolveUrl;
15019
15111
  }, [resolveUrl]);
15020
- React75.useEffect(() => {
15112
+ React76.useEffect(() => {
15021
15113
  if (kind === "none") {
15022
15114
  setState({ status: "ready" });
15023
15115
  return;
@@ -15047,19 +15139,19 @@ function usePreview(file, kind, resolveUrl) {
15047
15139
  if (ac) ac.abort();
15048
15140
  };
15049
15141
  }, [file.id, kind, attempt]);
15050
- return { ...state, retry: React75.useCallback(() => setAttempt((a) => a + 1), []) };
15142
+ return { ...state, retry: React76.useCallback(() => setAttempt((a) => a + 1), []) };
15051
15143
  }
15052
15144
  function PreviewBody({ file, kind, state }) {
15053
- if (kind === "image") return /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("img", { className: "fd-fv-image", src: state.url, alt: file.name || "Preview" });
15054
- if (kind === "pdf") return /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("iframe", { className: "fd-fv-pdf", src: state.url, title: file.name || "PDF preview" });
15055
- if (kind === "markdown") return /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(Markdown, { className: "fd-fv-markdown", source: state.text || "" });
15145
+ if (kind === "image") return /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("img", { className: "fd-fv-image", src: state.url, alt: file.name || "Preview" });
15146
+ if (kind === "pdf") return /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("iframe", { className: "fd-fv-pdf", src: state.url, title: file.name || "PDF preview" });
15147
+ if (kind === "markdown") return /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(Markdown, { className: "fd-fv-markdown", source: state.text || "" });
15056
15148
  if (kind === "json") {
15057
15149
  let pretty = state.text || "";
15058
15150
  try {
15059
15151
  pretty = JSON.stringify(JSON.parse(pretty), null, 2);
15060
15152
  } catch {
15061
15153
  }
15062
- return /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(CodeBlock, { code: pretty, language: "json" });
15154
+ return /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(CodeBlock, { code: pretty, language: "json" });
15063
15155
  }
15064
15156
  if (kind === "csv") {
15065
15157
  const tsv = extensionOf(file.name || "") === "tsv" || (file.mime || "").toLowerCase().includes("tab-separated");
@@ -15067,12 +15159,12 @@ function PreviewBody({ file, kind, state }) {
15067
15159
  const head = rows[0] || [];
15068
15160
  const dataRows = rows.slice(1);
15069
15161
  const shown = dataRows.slice(0, FILE_VIEWER_CSV_ROW_LIMIT);
15070
- return /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: "fd-fv-csv", children: [
15071
- /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("table", { className: "fd-fv-csv-table", children: [
15072
- /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("tr", { children: head.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("th", { children: c }, i)) }) }),
15073
- /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("tbody", { children: shown.map((r, ri) => /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("tr", { children: head.map((_, ci) => /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("td", { children: r[ci] ?? "" }, ci)) }, ri)) })
15162
+ return /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)("div", { className: "fd-fv-csv", children: [
15163
+ /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)("table", { className: "fd-fv-csv-table", children: [
15164
+ /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("tr", { children: head.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("th", { children: c }, i)) }) }),
15165
+ /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("tbody", { children: shown.map((r, ri) => /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("tr", { children: head.map((_, ci) => /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("td", { children: r[ci] ?? "" }, ci)) }, ri)) })
15074
15166
  ] }),
15075
- dataRows.length > FILE_VIEWER_CSV_ROW_LIMIT ? /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("p", { className: "fd-fv-csv-note fd-body-sm fd-muted", children: [
15167
+ dataRows.length > FILE_VIEWER_CSV_ROW_LIMIT ? /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)("p", { className: "fd-fv-csv-note fd-body-sm fd-muted", children: [
15076
15168
  "Showing the first ",
15077
15169
  FILE_VIEWER_CSV_ROW_LIMIT.toLocaleString(),
15078
15170
  " of ",
@@ -15081,24 +15173,24 @@ function PreviewBody({ file, kind, state }) {
15081
15173
  ] }) : null
15082
15174
  ] });
15083
15175
  }
15084
- if (kind === "text") return /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(CodeBlock, { code: state.text || "", language: extensionOf(file.name || "") || void 0 });
15085
- return /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: "fd-fv-fallback", children: [
15086
- /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("span", { className: "fd-fv-fallback-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("i", { className: "ph ph-" + iconForMime(file.mime, file.name) }) }),
15087
- /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("span", { className: "fd-fv-fallback-title", children: "No preview available" }),
15088
- /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("span", { className: "fd-fv-fallback-meta", children: [
15176
+ if (kind === "text") return /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(CodeBlock, { code: state.text || "", language: extensionOf(file.name || "") || void 0 });
15177
+ return /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)("div", { className: "fd-fv-fallback", children: [
15178
+ /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("span", { className: "fd-fv-fallback-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("i", { className: "ph ph-" + iconForMime(file.mime, file.name) }) }),
15179
+ /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("span", { className: "fd-fv-fallback-title", children: "No preview available" }),
15180
+ /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)("span", { className: "fd-fv-fallback-meta", children: [
15089
15181
  file.mime || "Unknown type",
15090
15182
  file.size ? " \xB7 " + formatBytes(file.size) : ""
15091
15183
  ] })
15092
15184
  ] });
15093
15185
  }
15094
15186
  function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", onClose, actions, className = "" }) {
15095
- const kind = React75.useMemo(() => previewKindOf(file), [file]);
15187
+ const kind = React76.useMemo(() => previewKindOf(file), [file]);
15096
15188
  const preview = usePreview(file, kind, resolveUrl);
15097
- const [tab, setTab] = React75.useState("preview");
15098
- const [downloading, setDownloading] = React75.useState(false);
15099
- const [downloadError, setDownloadError] = React75.useState(null);
15189
+ const [tab, setTab] = React76.useState("preview");
15190
+ const [downloading, setDownloading] = React76.useState(false);
15191
+ const [downloadError, setDownloadError] = React76.useState(null);
15100
15192
  const hasSide = sidePanel != null;
15101
- React75.useEffect(() => {
15193
+ React76.useEffect(() => {
15102
15194
  setTab("preview");
15103
15195
  }, [file.id]);
15104
15196
  const download = () => {
@@ -15114,29 +15206,29 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
15114
15206
  a.remove();
15115
15207
  }).catch((err) => setDownloadError(err && err.message || "Download failed.")).finally(() => setDownloading(false));
15116
15208
  };
15117
- return /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)(
15209
+ return /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)(
15118
15210
  "section",
15119
15211
  {
15120
15212
  className: ["fd-fv", hasSide && tab === "side" ? "is-tab-side" : "is-tab-preview", className].filter(Boolean).join(" "),
15121
15213
  "aria-label": file.name || "File",
15122
15214
  children: [
15123
- /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("header", { className: "fd-fv-head", children: [
15124
- /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("span", { className: "fd-fv-head-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("i", { className: "ph ph-" + iconForMime(file.mime, file.name) }) }),
15125
- /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("span", { className: "fd-fv-head-titles", children: [
15126
- /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("span", { className: "fd-fv-head-title", title: file.name, children: file.name }),
15127
- /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("span", { className: "fd-fv-head-meta", children: [
15215
+ /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)("header", { className: "fd-fv-head", children: [
15216
+ /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("span", { className: "fd-fv-head-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("i", { className: "ph ph-" + iconForMime(file.mime, file.name) }) }),
15217
+ /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)("span", { className: "fd-fv-head-titles", children: [
15218
+ /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("span", { className: "fd-fv-head-title", title: file.name, children: file.name }),
15219
+ /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)("span", { className: "fd-fv-head-meta", children: [
15128
15220
  file.mime || "Unknown type",
15129
15221
  file.size ? " \xB7 " + formatBytes(file.size) : ""
15130
15222
  ] })
15131
15223
  ] }),
15132
- /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("span", { className: "fd-fv-head-actions", children: [
15224
+ /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)("span", { className: "fd-fv-head-actions", children: [
15133
15225
  actions,
15134
- /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(Button, { variant: "secondary", size: "sm", icon: "download-simple", loading: downloading, onClick: download, children: "Download" }),
15135
- onClose ? /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(IconButton, { icon: "x", label: "Close", onClick: onClose }) : null
15226
+ /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(Button, { variant: "secondary", size: "sm", icon: "download-simple", loading: downloading, onClick: download, children: "Download" }),
15227
+ onClose ? /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(IconButton, { icon: "x", label: "Close", onClick: onClose }) : null
15136
15228
  ] })
15137
15229
  ] }),
15138
- downloadError ? /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("div", { className: "fd-fv-download-error", role: "alert", children: downloadError }) : null,
15139
- hasSide ? /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(
15230
+ downloadError ? /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("div", { className: "fd-fv-download-error", role: "alert", children: downloadError }) : null,
15231
+ hasSide ? /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(
15140
15232
  Tabs,
15141
15233
  {
15142
15234
  className: "fd-fv-tabs",
@@ -15145,19 +15237,19 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
15145
15237
  onChange: (v) => setTab(v)
15146
15238
  }
15147
15239
  ) : null,
15148
- /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: "fd-fv-body", children: [
15149
- /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("div", { className: "fd-fv-preview", role: "region", "aria-label": "Preview of " + (file.name || "file"), children: /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(
15240
+ /* @__PURE__ */ (0, import_jsx_runtime106.jsxs)("div", { className: "fd-fv-body", children: [
15241
+ /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("div", { className: "fd-fv-preview", role: "region", "aria-label": "Preview of " + (file.name || "file"), children: /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(
15150
15242
  LoadingRegion,
15151
15243
  {
15152
15244
  state: preview.status === "loading" ? "loading" : preview.status === "error" ? "error" : "ready",
15153
15245
  error: preview.error,
15154
15246
  label: "Loading preview of " + (file.name || "file"),
15155
15247
  onRetry: preview.status === "error" ? preview.retry : void 0,
15156
- skeleton: /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(Skeleton, { shape: "card", h: 220 }),
15157
- children: /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(PreviewBody, { file, kind, state: preview })
15248
+ skeleton: /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(Skeleton, { shape: "card", h: 220 }),
15249
+ children: /* @__PURE__ */ (0, import_jsx_runtime106.jsx)(PreviewBody, { file, kind, state: preview })
15158
15250
  }
15159
15251
  ) }),
15160
- hasSide ? /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("div", { className: "fd-fv-side", role: "region", "aria-label": sidePanelLabel, children: sidePanel }) : null
15252
+ hasSide ? /* @__PURE__ */ (0, import_jsx_runtime106.jsx)("div", { className: "fd-fv-side", role: "region", "aria-label": sidePanelLabel, children: sidePanel }) : null
15161
15253
  ] })
15162
15254
  ]
15163
15255
  }
@@ -15165,8 +15257,8 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
15165
15257
  }
15166
15258
 
15167
15259
  // src/components/files/FileBrowser.tsx
15168
- var React76 = __toESM(require("react"), 1);
15169
- var import_jsx_runtime105 = require("react/jsx-runtime");
15260
+ var React77 = __toESM(require("react"), 1);
15261
+ var import_jsx_runtime107 = require("react/jsx-runtime");
15170
15262
  function childrenOf(folders, parentId) {
15171
15263
  return folders.filter((f) => f.parentId === parentId).sort((a, b) => a.name.localeCompare(b.name));
15172
15264
  }
@@ -15238,8 +15330,8 @@ function FolderPickerMenu({
15238
15330
  }) {
15239
15331
  const panel = useInlinePanel();
15240
15332
  const { open: open2, setOpen, ref } = panel;
15241
- return /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)("span", { className: "fd-fb-menu-anchor", ref, children: [
15242
- /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
15333
+ return /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)("span", { className: "fd-fb-menu-anchor", ref, children: [
15334
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
15243
15335
  IconButton,
15244
15336
  {
15245
15337
  icon: "arrows-out-cardinal",
@@ -15251,9 +15343,9 @@ function FolderPickerMenu({
15251
15343
  onClick: () => setOpen((v) => !v)
15252
15344
  }
15253
15345
  ),
15254
- /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(InlinePanelSurface, { panel, align: "right", offset: 4, width: 220, maxHeight: 280, role: "menu", label, children: /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)("div", { className: "fd-fb-menu", children: [
15255
- /* @__PURE__ */ (0, import_jsx_runtime105.jsx)("span", { className: "fd-overline fd-muted fd-fb-menu-title", children: "Move to\u2026" }),
15256
- destinations.map((d) => /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)(
15346
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(InlinePanelSurface, { panel, align: "right", offset: 4, width: 220, maxHeight: 280, role: "menu", label, children: /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)("div", { className: "fd-fb-menu", children: [
15347
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)("span", { className: "fd-overline fd-muted fd-fb-menu-title", children: "Move to\u2026" }),
15348
+ destinations.map((d) => /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)(
15257
15349
  "button",
15258
15350
  {
15259
15351
  type: "button",
@@ -15265,7 +15357,7 @@ function FolderPickerMenu({
15265
15357
  setOpen(false);
15266
15358
  },
15267
15359
  children: [
15268
- /* @__PURE__ */ (0, import_jsx_runtime105.jsx)("i", { className: "ph ph-" + (d.id == null ? "house-simple" : "folder-simple"), "aria-hidden": "true" }),
15360
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)("i", { className: "ph ph-" + (d.id == null ? "house-simple" : "folder-simple"), "aria-hidden": "true" }),
15269
15361
  d.name
15270
15362
  ]
15271
15363
  },
@@ -15275,8 +15367,8 @@ function FolderPickerMenu({
15275
15367
  ] });
15276
15368
  }
15277
15369
  function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropPayload, actions, className = "" }) {
15278
- const [over, setOver] = React76.useState(false);
15279
- const dragCounter = React76.useRef(0);
15370
+ const [over, setOver] = React77.useState(false);
15371
+ const dragCounter = React77.useRef(0);
15280
15372
  const dropHandlers = isDropTarget ? {
15281
15373
  onDragEnter: (e) => {
15282
15374
  if (!hasInternalPayload(e)) return;
@@ -15301,8 +15393,8 @@ function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropP
15301
15393
  if (payload && onDropPayload) onDropPayload(payload);
15302
15394
  }
15303
15395
  } : {};
15304
- return /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)("div", { className: ["fd-fb-row", over ? "is-drop-target" : "", className].filter(Boolean).join(" "), ...dropHandlers, children: [
15305
- /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)(
15396
+ return /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)("div", { className: ["fd-fb-row", over ? "is-drop-target" : "", className].filter(Boolean).join(" "), ...dropHandlers, children: [
15397
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)(
15306
15398
  "button",
15307
15399
  {
15308
15400
  type: "button",
@@ -15311,26 +15403,26 @@ function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropP
15311
15403
  draggable: !!draggableId,
15312
15404
  onDragStart: draggableId ? (e) => writeDragPayload(e, draggableId) : void 0,
15313
15405
  children: [
15314
- /* @__PURE__ */ (0, import_jsx_runtime105.jsx)("span", { className: "fd-fb-row-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime105.jsx)("i", { className: "ph ph-" + icon }) }),
15315
- /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)("span", { className: "fd-fb-row-text", children: [
15316
- /* @__PURE__ */ (0, import_jsx_runtime105.jsx)("span", { className: "fd-fb-row-name", title: name, children: name }),
15317
- meta ? /* @__PURE__ */ (0, import_jsx_runtime105.jsx)("span", { className: "fd-fb-row-meta", children: meta }) : null
15406
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)("span", { className: "fd-fb-row-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime107.jsx)("i", { className: "ph ph-" + icon }) }),
15407
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)("span", { className: "fd-fb-row-text", children: [
15408
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)("span", { className: "fd-fb-row-name", title: name, children: name }),
15409
+ meta ? /* @__PURE__ */ (0, import_jsx_runtime107.jsx)("span", { className: "fd-fb-row-meta", children: meta }) : null
15318
15410
  ] })
15319
15411
  ]
15320
15412
  }
15321
15413
  ),
15322
- actions ? /* @__PURE__ */ (0, import_jsx_runtime105.jsx)("span", { className: "fd-fb-row-actions", children: actions }) : null
15414
+ actions ? /* @__PURE__ */ (0, import_jsx_runtime107.jsx)("span", { className: "fd-fb-row-actions", children: actions }) : null
15323
15415
  ] });
15324
15416
  }
15325
15417
  function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveInto, canMove }) {
15326
15418
  const kids = childrenOf(folders, folder.id);
15327
- const [expanded, setExpanded] = React76.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
15328
- React76.useEffect(() => {
15419
+ const [expanded, setExpanded] = React77.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
15420
+ React77.useEffect(() => {
15329
15421
  if (currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId)) setExpanded(true);
15330
15422
  }, [currentFolderId, folder.id, folders]);
15331
15423
  const isCurrent = folder.id === currentFolderId;
15332
- return /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)("div", { className: "fd-fb-tree-node", children: [
15333
- /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
15424
+ return /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)("div", { className: "fd-fb-tree-node", children: [
15425
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
15334
15426
  RowShell,
15335
15427
  {
15336
15428
  icon: folder.id === currentFolderId ? "folder-open" : "folder-simple",
@@ -15340,7 +15432,7 @@ function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveI
15340
15432
  isDropTarget: canMove,
15341
15433
  onDropPayload: (payload) => onMoveInto(payload, folder.id),
15342
15434
  className: ["fd-fb-tree-row", isCurrent ? "is-current" : ""].filter(Boolean).join(" "),
15343
- actions: kids.length ? /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
15435
+ actions: kids.length ? /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
15344
15436
  IconButton,
15345
15437
  {
15346
15438
  icon: expanded ? "caret-down" : "caret-right",
@@ -15352,7 +15444,7 @@ function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveI
15352
15444
  ) : void 0
15353
15445
  }
15354
15446
  ),
15355
- expanded && kids.length ? /* @__PURE__ */ (0, import_jsx_runtime105.jsx)("div", { className: "fd-fb-tree-children", style: { paddingLeft: 14 }, children: kids.map((k) => /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
15447
+ expanded && kids.length ? /* @__PURE__ */ (0, import_jsx_runtime107.jsx)("div", { className: "fd-fb-tree-children", style: { paddingLeft: 14 }, children: kids.map((k) => /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
15356
15448
  TreeNode,
15357
15449
  {
15358
15450
  folder: k,
@@ -15391,15 +15483,15 @@ function FileBrowser({
15391
15483
  const canUpload = perm.canUpload !== false && !!onUpload;
15392
15484
  const canRemoveFile = perm.canRemoveFile !== false && !!onRemoveFile;
15393
15485
  const canDeleteFolder = perm.canDeleteFolder !== false && !!onDeleteFolder;
15394
- const [createOpen, setCreateOpen] = React76.useState(false);
15395
- const [createName, setCreateName] = React76.useState("");
15396
- const [renameTarget, setRenameTarget] = React76.useState(null);
15397
- const [renameValue, setRenameValue] = React76.useState("");
15398
- const [deleteTarget, setDeleteTarget] = React76.useState(null);
15399
- const uploadInputRef = React76.useRef(null);
15400
- const crumbFolders = React76.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
15401
- const subfolders = React76.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
15402
- const currentFiles = React76.useMemo(
15486
+ const [createOpen, setCreateOpen] = React77.useState(false);
15487
+ const [createName, setCreateName] = React77.useState("");
15488
+ const [renameTarget, setRenameTarget] = React77.useState(null);
15489
+ const [renameValue, setRenameValue] = React77.useState("");
15490
+ const [deleteTarget, setDeleteTarget] = React77.useState(null);
15491
+ const uploadInputRef = React77.useRef(null);
15492
+ const crumbFolders = React77.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
15493
+ const subfolders = React77.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
15494
+ const currentFiles = React77.useMemo(
15403
15495
  () => files.filter((f) => f.folderId === currentFolderId).sort((a, b) => a.name.localeCompare(b.name)),
15404
15496
  [files, currentFolderId]
15405
15497
  );
@@ -15438,10 +15530,10 @@ function FileBrowser({
15438
15530
  if (deleteTarget && onDeleteFolder) onDeleteFolder(deleteTarget);
15439
15531
  setDeleteTarget(null);
15440
15532
  };
15441
- const content = /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)("div", { className: ["fd-fb", className].filter(Boolean).join(" "), children: [
15442
- /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)("div", { className: "fd-fb-head", children: [
15443
- /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)("nav", { className: "fd-fb-crumbs", "aria-label": "Folder path", children: [
15444
- /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
15533
+ const content = /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)("div", { className: ["fd-fb", className].filter(Boolean).join(" "), children: [
15534
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)("div", { className: "fd-fb-head", children: [
15535
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)("nav", { className: "fd-fb-crumbs", "aria-label": "Folder path", children: [
15536
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
15445
15537
  BreadcrumbCrumb,
15446
15538
  {
15447
15539
  label: "Home",
@@ -15451,7 +15543,7 @@ function FileBrowser({
15451
15543
  onDropPayload: (p) => moveIntoFolder(p, null)
15452
15544
  }
15453
15545
  ),
15454
- crumbFolders.map((f, i) => /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
15546
+ crumbFolders.map((f, i) => /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
15455
15547
  BreadcrumbCrumb,
15456
15548
  {
15457
15549
  label: f.name,
@@ -15463,11 +15555,11 @@ function FileBrowser({
15463
15555
  f.id
15464
15556
  ))
15465
15557
  ] }),
15466
- /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)("span", { className: "fd-fb-actions", children: [
15467
- canCreateFolder ? /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(Button, { variant: "secondary", size: "sm", icon: "folder-simple-plus", onClick: openCreate, children: "New folder" }) : null,
15468
- canUpload ? /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)(import_jsx_runtime105.Fragment, { children: [
15469
- /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(Button, { variant: "secondary", size: "sm", icon: "upload-simple", onClick: () => uploadInputRef.current && uploadInputRef.current.click(), children: "Upload" }),
15470
- /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
15558
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)("span", { className: "fd-fb-actions", children: [
15559
+ canCreateFolder ? /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(Button, { variant: "secondary", size: "sm", icon: "folder-simple-plus", onClick: openCreate, children: "New folder" }) : null,
15560
+ canUpload ? /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)(import_jsx_runtime107.Fragment, { children: [
15561
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(Button, { variant: "secondary", size: "sm", icon: "upload-simple", onClick: () => uploadInputRef.current && uploadInputRef.current.click(), children: "Upload" }),
15562
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
15471
15563
  "input",
15472
15564
  {
15473
15565
  ref: uploadInputRef,
@@ -15485,9 +15577,9 @@ function FileBrowser({
15485
15577
  ] }) : null
15486
15578
  ] })
15487
15579
  ] }),
15488
- /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)("div", { className: "fd-fb-body", children: [
15489
- /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)("div", { className: "fd-fb-tree", role: "region", "aria-label": "Folder tree", children: [
15490
- /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
15580
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)("div", { className: "fd-fb-body", children: [
15581
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)("div", { className: "fd-fb-tree", role: "region", "aria-label": "Folder tree", children: [
15582
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
15491
15583
  RowShell,
15492
15584
  {
15493
15585
  icon: "house-simple",
@@ -15498,7 +15590,7 @@ function FileBrowser({
15498
15590
  className: ["fd-fb-tree-row", currentFolderId == null ? "is-current" : ""].filter(Boolean).join(" ")
15499
15591
  }
15500
15592
  ),
15501
- childrenOf(folders, null).map((f) => /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
15593
+ childrenOf(folders, null).map((f) => /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
15502
15594
  TreeNode,
15503
15595
  {
15504
15596
  folder: f,
@@ -15512,18 +15604,18 @@ function FileBrowser({
15512
15604
  f.id
15513
15605
  ))
15514
15606
  ] }),
15515
- /* @__PURE__ */ (0, import_jsx_runtime105.jsx)("div", { className: "fd-fb-main", role: "region", "aria-label": "Folder contents", children: /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
15607
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)("div", { className: "fd-fb-main", role: "region", "aria-label": "Folder contents", children: /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
15516
15608
  LoadingRegion,
15517
15609
  {
15518
15610
  state: loading ? "loading" : "ready",
15519
15611
  label: "Loading folder contents",
15520
- skeleton: /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)("div", { className: "fd-stack", style: { gap: 8, padding: 12 }, children: [
15521
- /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(Skeleton, { h: 44, radius: "10px" }),
15522
- /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(Skeleton, { h: 44, radius: "10px" }),
15523
- /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(Skeleton, { h: 44, radius: "10px" })
15612
+ skeleton: /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)("div", { className: "fd-stack", style: { gap: 8, padding: 12 }, children: [
15613
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(Skeleton, { h: 44, radius: "10px" }),
15614
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(Skeleton, { h: 44, radius: "10px" }),
15615
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(Skeleton, { h: 44, radius: "10px" })
15524
15616
  ] }),
15525
- children: isEmpty ? /* @__PURE__ */ (0, import_jsx_runtime105.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_runtime105.jsxs)("div", { className: "fd-fb-list", children: [
15526
- subfolders.map((f) => /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
15617
+ children: isEmpty ? /* @__PURE__ */ (0, import_jsx_runtime107.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_runtime107.jsxs)("div", { className: "fd-fb-list", children: [
15618
+ subfolders.map((f) => /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
15527
15619
  RowShell,
15528
15620
  {
15529
15621
  icon: "folder-simple",
@@ -15532,9 +15624,9 @@ function FileBrowser({
15532
15624
  draggableId: canMove ? { kind: "folder", id: f.id } : void 0,
15533
15625
  isDropTarget: canMove,
15534
15626
  onDropPayload: (p) => moveIntoFolder(p, f.id),
15535
- actions: /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)(import_jsx_runtime105.Fragment, { children: [
15536
- canRenameFolder ? /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(IconButton, { icon: "pencil-simple", label: "Rename " + f.name, size: "sm", variant: "ghost", onClick: () => openRename(f) }) : null,
15537
- canMove ? /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
15627
+ actions: /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)(import_jsx_runtime107.Fragment, { children: [
15628
+ canRenameFolder ? /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(IconButton, { icon: "pencil-simple", label: "Rename " + f.name, size: "sm", variant: "ghost", onClick: () => openRename(f) }) : null,
15629
+ canMove ? /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
15538
15630
  FolderPickerMenu,
15539
15631
  {
15540
15632
  label: "Move " + f.name,
@@ -15542,12 +15634,12 @@ function FileBrowser({
15542
15634
  onPick: (target) => moveIntoFolder({ kind: "folder", id: f.id }, target)
15543
15635
  }
15544
15636
  ) : null,
15545
- canDeleteFolder ? /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(IconButton, { icon: "trash-simple", label: "Delete " + f.name, size: "sm", variant: "ghost", onClick: () => openDelete(f) }) : null
15637
+ canDeleteFolder ? /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(IconButton, { icon: "trash-simple", label: "Delete " + f.name, size: "sm", variant: "ghost", onClick: () => openDelete(f) }) : null
15546
15638
  ] })
15547
15639
  },
15548
15640
  f.id
15549
15641
  )),
15550
- currentFiles.map((file) => /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
15642
+ currentFiles.map((file) => /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
15551
15643
  RowShell,
15552
15644
  {
15553
15645
  icon: iconForMime(file.mime, file.name),
@@ -15555,8 +15647,8 @@ function FileBrowser({
15555
15647
  meta: file.size ? formatBytes(file.size) : void 0,
15556
15648
  onOpen: onOpenFile ? () => onOpenFile(file) : void 0,
15557
15649
  draggableId: canMove ? { kind: "file", id: file.id } : void 0,
15558
- actions: /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)(import_jsx_runtime105.Fragment, { children: [
15559
- canMove ? /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
15650
+ actions: /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)(import_jsx_runtime107.Fragment, { children: [
15651
+ canMove ? /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
15560
15652
  FolderPickerMenu,
15561
15653
  {
15562
15654
  label: "Move " + file.name,
@@ -15564,7 +15656,7 @@ function FileBrowser({
15564
15656
  onPick: (target) => onMoveFile && onMoveFile(file.id, target)
15565
15657
  }
15566
15658
  ) : null,
15567
- canRemoveFile ? /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(IconButton, { icon: "trash-simple", label: "Remove " + file.name, size: "sm", variant: "ghost", onClick: () => onRemoveFile && onRemoveFile(file) }) : null
15659
+ canRemoveFile ? /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(IconButton, { icon: "trash-simple", label: "Remove " + file.name, size: "sm", variant: "ghost", onClick: () => onRemoveFile && onRemoveFile(file) }) : null
15568
15660
  ] })
15569
15661
  },
15570
15662
  file.id
@@ -15573,10 +15665,10 @@ function FileBrowser({
15573
15665
  }
15574
15666
  ) })
15575
15667
  ] }),
15576
- /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(Modal, { open: createOpen, title: "New folder", onClose: () => setCreateOpen(false), footer: /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)(import_jsx_runtime105.Fragment, { children: [
15577
- /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(Button, { variant: "secondary", onClick: () => setCreateOpen(false), children: "Cancel" }),
15578
- /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(Button, { onClick: submitCreate, disabled: !createName.trim(), children: "Create" })
15579
- ] }), children: /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
15668
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(Modal, { open: createOpen, title: "New folder", onClose: () => setCreateOpen(false), footer: /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)(import_jsx_runtime107.Fragment, { children: [
15669
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(Button, { variant: "secondary", onClick: () => setCreateOpen(false), children: "Cancel" }),
15670
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(Button, { onClick: submitCreate, disabled: !createName.trim(), children: "Create" })
15671
+ ] }), children: /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
15580
15672
  "input",
15581
15673
  {
15582
15674
  className: "fd-fb-input",
@@ -15590,10 +15682,10 @@ function FileBrowser({
15590
15682
  autoFocus: true
15591
15683
  }
15592
15684
  ) }),
15593
- /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(Modal, { open: renameTarget != null, title: "Rename folder", onClose: () => setRenameTarget(null), footer: /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)(import_jsx_runtime105.Fragment, { children: [
15594
- /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(Button, { variant: "secondary", onClick: () => setRenameTarget(null), children: "Cancel" }),
15595
- /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(Button, { onClick: submitRename, disabled: !renameValue.trim(), children: "Save" })
15596
- ] }), children: /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
15685
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(Modal, { open: renameTarget != null, title: "Rename folder", onClose: () => setRenameTarget(null), footer: /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)(import_jsx_runtime107.Fragment, { children: [
15686
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(Button, { variant: "secondary", onClick: () => setRenameTarget(null), children: "Cancel" }),
15687
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(Button, { onClick: submitRename, disabled: !renameValue.trim(), children: "Save" })
15688
+ ] }), children: /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
15597
15689
  "input",
15598
15690
  {
15599
15691
  className: "fd-fb-input",
@@ -15607,22 +15699,22 @@ function FileBrowser({
15607
15699
  autoFocus: true
15608
15700
  }
15609
15701
  ) }),
15610
- /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
15702
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(
15611
15703
  Modal,
15612
15704
  {
15613
15705
  open: deleteTarget != null,
15614
15706
  title: deleteTarget ? "Delete \u201C" + deleteTarget.name + "\u201D?" : "Delete folder?",
15615
15707
  description: "This can't be undone. The folder must be empty.",
15616
15708
  onClose: () => setDeleteTarget(null),
15617
- footer: /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)(import_jsx_runtime105.Fragment, { children: [
15618
- /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(Button, { variant: "secondary", onClick: () => setDeleteTarget(null), children: "Cancel" }),
15619
- /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(Button, { variant: "danger", onClick: confirmDelete, children: "Delete" })
15709
+ footer: /* @__PURE__ */ (0, import_jsx_runtime107.jsxs)(import_jsx_runtime107.Fragment, { children: [
15710
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(Button, { variant: "secondary", onClick: () => setDeleteTarget(null), children: "Cancel" }),
15711
+ /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(Button, { variant: "danger", onClick: confirmDelete, children: "Delete" })
15620
15712
  ] })
15621
15713
  }
15622
15714
  )
15623
15715
  ] });
15624
15716
  if (!canUpload) return content;
15625
- return /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(Dropzone, { className: "fd-fb-dropzone", onFiles: (picked) => onUpload && onUpload(picked, currentFolderId), label: "Drop files to upload", children: content });
15717
+ return /* @__PURE__ */ (0, import_jsx_runtime107.jsx)(Dropzone, { className: "fd-fb-dropzone", onFiles: (picked) => onUpload && onUpload(picked, currentFolderId), label: "Drop files to upload", children: content });
15626
15718
  }
15627
15719
  function BreadcrumbCrumb({
15628
15720
  label,
@@ -15631,8 +15723,8 @@ function BreadcrumbCrumb({
15631
15723
  isDropTarget,
15632
15724
  onDropPayload
15633
15725
  }) {
15634
- const [over, setOver] = React76.useState(false);
15635
- const dragCounter = React76.useRef(0);
15726
+ const [over, setOver] = React77.useState(false);
15727
+ const dragCounter = React77.useRef(0);
15636
15728
  const dropHandlers = isDropTarget ? {
15637
15729
  onDragEnter: (e) => {
15638
15730
  if (!hasInternalPayload(e)) return;
@@ -15657,11 +15749,11 @@ function BreadcrumbCrumb({
15657
15749
  if (payload && onDropPayload) onDropPayload(payload);
15658
15750
  }
15659
15751
  } : {};
15660
- return /* @__PURE__ */ (0, import_jsx_runtime105.jsx)("span", { className: ["fd-fb-crumb", over ? "is-drop-target" : ""].filter(Boolean).join(" "), ...dropHandlers, children: isCurrent ? /* @__PURE__ */ (0, import_jsx_runtime105.jsx)("span", { className: "fd-fb-crumb-current", "aria-current": "page", children: label }) : /* @__PURE__ */ (0, import_jsx_runtime105.jsx)("button", { type: "button", className: "fd-fb-crumb-link", onClick, children: label }) });
15752
+ return /* @__PURE__ */ (0, import_jsx_runtime107.jsx)("span", { className: ["fd-fb-crumb", over ? "is-drop-target" : ""].filter(Boolean).join(" "), ...dropHandlers, children: isCurrent ? /* @__PURE__ */ (0, import_jsx_runtime107.jsx)("span", { className: "fd-fb-crumb-current", "aria-current": "page", children: label }) : /* @__PURE__ */ (0, import_jsx_runtime107.jsx)("button", { type: "button", className: "fd-fb-crumb-link", onClick, children: label }) });
15661
15753
  }
15662
15754
 
15663
15755
  // src/kits/query.ts
15664
- var React77 = __toESM(require("react"), 1);
15756
+ var React78 = __toESM(require("react"), 1);
15665
15757
 
15666
15758
  // src/kits/queryUrl.ts
15667
15759
  var historyUrlAdapter = {
@@ -15799,38 +15891,38 @@ function requestFor(params, query, paging, after) {
15799
15891
  }
15800
15892
  var toError = (e) => e instanceof Error ? e : new Error(String(e));
15801
15893
  function useServerTable({ endpoint, params, defaults, deps, prefsKey, paging = "page", url }) {
15802
- const [base] = React77.useState(() => {
15894
+ const [base] = React78.useState(() => {
15803
15895
  const store = PREFS || window.PlannerPrefs;
15804
15896
  const saved = prefsKey && store ? store.getTable(prefsKey) : {};
15805
15897
  return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
15806
15898
  });
15807
- const [mountParams] = React77.useState(() => url ? (url.adapter ?? historyUrlAdapter).read() : null);
15808
- const address = React77.useRef(mountParams);
15809
- const [query, setQuery] = React77.useState(() => url && mountParams ? readQueryFromUrl(mountParams, url.scope, base, paging) : base);
15810
- const savePref = React77.useCallback((patch2) => {
15899
+ const [mountParams] = React78.useState(() => url ? (url.adapter ?? historyUrlAdapter).read() : null);
15900
+ const address = React78.useRef(mountParams);
15901
+ const [query, setQuery] = React78.useState(() => url && mountParams ? readQueryFromUrl(mountParams, url.scope, base, paging) : base);
15902
+ const savePref = React78.useCallback((patch2) => {
15811
15903
  const store = PREFS || window.PlannerPrefs;
15812
15904
  if (prefsKey && store) store.setTable(prefsKey, patch2);
15813
15905
  }, [prefsKey]);
15814
- const [res, setRes] = React77.useState(null);
15815
- const [loading, setLoading] = React77.useState(true);
15816
- const [loadingMore, setLoadingMore] = React77.useState(false);
15817
- const [failure, setFailure] = React77.useState(null);
15818
- const [reloadToken, setReloadToken] = React77.useState(0);
15819
- const moreController = React77.useRef(null);
15906
+ const [res, setRes] = React78.useState(null);
15907
+ const [loading, setLoading] = React78.useState(true);
15908
+ const [loadingMore, setLoadingMore] = React78.useState(false);
15909
+ const [failure, setFailure] = React78.useState(null);
15910
+ const [reloadToken, setReloadToken] = React78.useState(0);
15911
+ const moreController = React78.useRef(null);
15820
15912
  const depKey = (deps || []).join("|");
15821
15913
  const paramKey = JSON.stringify(params || {});
15822
15914
  const queryKey = JSON.stringify(query);
15823
- const lifetime = React77.useRef(null);
15824
- React77.useEffect(() => {
15915
+ const lifetime = React78.useRef(null);
15916
+ React78.useEffect(() => {
15825
15917
  const controller = new AbortController();
15826
15918
  lifetime.current = controller;
15827
15919
  return () => controller.abort();
15828
15920
  }, []);
15829
- const latest = React77.useRef({ res, loading, query, params, endpoint, url, base });
15830
- React77.useEffect(() => {
15921
+ const latest = React78.useRef({ res, loading, query, params, endpoint, url, base });
15922
+ React78.useLayoutEffect(() => {
15831
15923
  latest.current = { res, loading, query, params, endpoint, url, base };
15832
15924
  });
15833
- React77.useEffect(() => {
15925
+ React78.useEffect(() => {
15834
15926
  const controller = new AbortController();
15835
15927
  const { signal } = controller;
15836
15928
  setLoading(true);
@@ -15866,7 +15958,7 @@ function useServerTable({ endpoint, params, defaults, deps, prefsKey, paging = "
15866
15958
  };
15867
15959
  }, [endpoint, queryKey, paramKey, depKey, paging, reloadToken]);
15868
15960
  const adapter = url ? url.adapter ?? historyUrlAdapter : null;
15869
- React77.useEffect(() => {
15961
+ React78.useEffect(() => {
15870
15962
  if (!adapter) return;
15871
15963
  return adapter.subscribe((params2) => {
15872
15964
  const { url: u, base: b } = latest.current;
@@ -16216,12 +16308,12 @@ function createVersionStore(initialState, options) {
16216
16308
  }
16217
16309
 
16218
16310
  // src/kits/documentTitle.ts
16219
- var React78 = __toESM(require("react"), 1);
16311
+ var React79 = __toESM(require("react"), 1);
16220
16312
  function formatDocumentTitle(routeTitle, appName) {
16221
16313
  return [routeTitle, appName, "Flytedesk"].filter((part) => !!part && part.length > 0).join(" \xB7 ");
16222
16314
  }
16223
16315
  function useDocumentTitle(routeTitle, appName) {
16224
- React78.useEffect(() => {
16316
+ React79.useEffect(() => {
16225
16317
  if (typeof document === "undefined") return;
16226
16318
  document.title = formatDocumentTitle(routeTitle, appName);
16227
16319
  }, [routeTitle, appName]);
@@ -16293,6 +16385,7 @@ function useDocumentTitle(routeTitle, appName) {
16293
16385
  FILE_VIEWER_TEXT_LIMIT,
16294
16386
  FactList,
16295
16387
  FeatureGate,
16388
+ Fieldset,
16296
16389
  FileBrowser,
16297
16390
  FileChip,
16298
16391
  FileGrid,
@@ -16346,6 +16439,7 @@ function useDocumentTitle(routeTitle, appName) {
16346
16439
  QuotaRow,
16347
16440
  ROOT_STEP,
16348
16441
  Radio,
16442
+ RadioGroup,
16349
16443
  RangeSlider,
16350
16444
  RelativeTime,
16351
16445
  RoadmapTimeline,