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