@flytedan/flytebot-design-system 0.16.0 → 0.17.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.js CHANGED
@@ -885,37 +885,48 @@ function Spinner({ size = "md", label = "Loading", className = "", style, ...res
885
885
  }
886
886
 
887
887
  // src/components/navigation/SidebarNav.tsx
888
+ import * as React6 from "react";
888
889
  import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
889
890
  function Tip({ label, children }) {
890
891
  return /* @__PURE__ */ jsx13("span", { title: label, style: { display: "inline-flex", flex: "none" }, children });
891
892
  }
892
- function SidebarNav({ brand, groups = [], current: current2, onNavigate, footer, open = false, className = "", ...rest }) {
893
- return /* @__PURE__ */ jsxs10("nav", { className: ["fd-side", className].filter(Boolean).join(" "), "data-open": open ? "true" : "false", ...rest, children: [
894
- brand ? /* @__PURE__ */ jsx13("div", { style: { height: "var(--topbar-h)", display: "flex", alignItems: "center", padding: "0 18px", borderBottom: "1px solid var(--border)", flex: "none", overflow: "hidden" }, children: brand }) : null,
895
- /* @__PURE__ */ jsx13("div", { style: { flex: 1, overflow: "auto", padding: "4px 10px 18px" }, children: groups.map((g, gi) => /* @__PURE__ */ jsxs10("div", { children: [
896
- g.label ? /* @__PURE__ */ jsx13("div", { className: "fd-side-group", children: g.label }) : null,
897
- /* @__PURE__ */ jsx13("div", { className: "fd-stack", style: { gap: 2 }, children: g.items.map((it) => /* @__PURE__ */ jsxs10(
898
- "button",
899
- {
900
- type: "button",
901
- className: "fd-side-item",
902
- "aria-current": current2 === it.value ? "page" : void 0,
903
- onClick: onNavigate ? () => onNavigate(it.value) : void 0,
904
- children: [
905
- /* @__PURE__ */ jsx13("span", { className: "fd-side-item-icon", children: /* @__PURE__ */ jsx13("i", { className: "ph ph-" + it.icon, "aria-hidden": "true" }) }),
906
- /* @__PURE__ */ jsx13("span", { style: { flex: 1, minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, title: truncationTitle(it.label), children: it.label }),
907
- it.preview ? /* @__PURE__ */ jsx13(Tip, { label: "Designed, backend not wired yet", children: /* @__PURE__ */ jsx13("i", { className: "ph ph-traffic-cone", style: { fontSize: 13, color: "var(--warn-solid)", flex: "none" } }) }) : null,
908
- it.locked ? /* @__PURE__ */ jsx13(Tip, { label: "You do not have permission for this", children: /* @__PURE__ */ jsx13("i", { className: "ph ph-lock-simple", style: { fontSize: 13, color: "var(--text-muted)", flex: "none" } }) }) : null,
909
- it.count !== void 0 ? /* @__PURE__ */ jsx13("span", { className: "fd-side-item-count", children: it.count }) : null,
910
- it.loading ? /* @__PURE__ */ jsx13("span", { className: "fd-skel fd-skel-text", style: { width: 22, height: 11, marginLeft: "auto" } }) : null
911
- ]
912
- },
913
- it.value
914
- )) })
915
- ] }, gi)) }),
916
- footer ? /* @__PURE__ */ jsx13("div", { style: { borderTop: "1px solid var(--border)", padding: 14, flex: "none" }, children: footer }) : null
917
- ] });
918
- }
893
+ var SidebarNav = React6.forwardRef(function SidebarNav2({ brand, groups = [], current: current2, onNavigate, footer, open = false, className = "", ...rest }, ref) {
894
+ return /* @__PURE__ */ jsxs10(
895
+ "nav",
896
+ {
897
+ ref,
898
+ tabIndex: -1,
899
+ className: ["fd-side", className].filter(Boolean).join(" "),
900
+ "data-open": open ? "true" : "false",
901
+ ...rest,
902
+ children: [
903
+ brand ? /* @__PURE__ */ jsx13("div", { style: { height: "var(--topbar-h)", display: "flex", alignItems: "center", padding: "0 18px", borderBottom: "1px solid var(--border)", flex: "none", overflow: "hidden" }, children: brand }) : null,
904
+ /* @__PURE__ */ jsx13("div", { style: { flex: 1, overflow: "auto", padding: "4px 10px 18px" }, children: groups.map((g, gi) => /* @__PURE__ */ jsxs10("div", { children: [
905
+ g.label ? /* @__PURE__ */ jsx13("div", { className: "fd-side-group", children: g.label }) : null,
906
+ /* @__PURE__ */ jsx13("div", { className: "fd-stack", style: { gap: 2 }, children: g.items.map((it) => /* @__PURE__ */ jsxs10(
907
+ "button",
908
+ {
909
+ type: "button",
910
+ className: "fd-side-item",
911
+ "aria-current": current2 === it.value ? "page" : void 0,
912
+ onClick: onNavigate ? () => onNavigate(it.value) : void 0,
913
+ children: [
914
+ /* @__PURE__ */ jsx13("span", { className: "fd-side-item-icon", children: /* @__PURE__ */ jsx13("i", { className: "ph ph-" + it.icon, "aria-hidden": "true" }) }),
915
+ /* @__PURE__ */ jsx13("span", { style: { flex: 1, minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, title: truncationTitle(it.label), children: it.label }),
916
+ it.preview ? /* @__PURE__ */ jsx13(Tip, { label: "Designed, backend not wired yet", children: /* @__PURE__ */ jsx13("i", { className: "ph ph-traffic-cone", style: { fontSize: 13, color: "var(--warn-solid)", flex: "none" } }) }) : null,
917
+ it.locked ? /* @__PURE__ */ jsx13(Tip, { label: "You do not have permission for this", children: /* @__PURE__ */ jsx13("i", { className: "ph ph-lock-simple", style: { fontSize: 13, color: "var(--text-muted)", flex: "none" } }) }) : null,
918
+ it.count !== void 0 ? /* @__PURE__ */ jsx13("span", { className: "fd-side-item-count", children: it.count }) : null,
919
+ it.loading ? /* @__PURE__ */ jsx13("span", { className: "fd-skel fd-skel-text", style: { width: 22, height: 11, marginLeft: "auto" } }) : null
920
+ ]
921
+ },
922
+ it.value
923
+ )) })
924
+ ] }, gi)) }),
925
+ footer ? /* @__PURE__ */ jsx13("div", { style: { borderTop: "1px solid var(--border)", padding: 14, flex: "none" }, children: footer }) : null
926
+ ]
927
+ }
928
+ );
929
+ });
919
930
 
920
931
  // src/components/navigation/FlytedeskBrand.tsx
921
932
  import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
@@ -956,13 +967,13 @@ function Tabs({ tabs = [], value, onChange, className = "", ...rest }) {
956
967
  }
957
968
 
958
969
  // src/components/navigation/Topbar.tsx
959
- import * as React6 from "react";
970
+ import * as React7 from "react";
960
971
  import { Fragment as Fragment3, jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
961
972
  function useIsNarrow(breakpoint) {
962
- const [narrow, setNarrow] = React6.useState(
973
+ const [narrow, setNarrow] = React7.useState(
963
974
  () => typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia(`(max-width: ${breakpoint}px)`).matches
964
975
  );
965
- React6.useEffect(() => {
976
+ React7.useEffect(() => {
966
977
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
967
978
  const mq = window.matchMedia(`(max-width: ${breakpoint}px)`);
968
979
  const apply = () => setNarrow(mq.matches);
@@ -983,11 +994,11 @@ function Topbar({
983
994
  ...rest
984
995
  }) {
985
996
  const narrow = useIsNarrow(overflowBreakpoint);
986
- const [moreOpen, setMoreOpen] = React6.useState(false);
987
- const moreRef = React6.useRef(null);
997
+ const [moreOpen, setMoreOpen] = React7.useState(false);
998
+ const moreRef = React7.useRef(null);
988
999
  return /* @__PURE__ */ jsxs13("header", { className: ["fd-topbar", narrow ? "is-narrow" : "", className].filter(Boolean).join(" "), ...rest, children: [
989
1000
  onMenu ? /* @__PURE__ */ jsx16("button", { type: "button", className: "fd-btn-icon", "aria-label": "Menu", onClick: onMenu, children: /* @__PURE__ */ jsx16("i", { className: "ph ph-list" }) }) : null,
990
- /* @__PURE__ */ jsx16("nav", { className: "fd-crumb", "aria-label": "Breadcrumb", children: crumbs.map((c, i) => /* @__PURE__ */ jsxs13(React6.Fragment, { children: [
1001
+ /* @__PURE__ */ jsx16("nav", { className: "fd-crumb", "aria-label": "Breadcrumb", children: crumbs.map((c, i) => /* @__PURE__ */ jsxs13(React7.Fragment, { children: [
991
1002
  i > 0 ? /* @__PURE__ */ jsx16("i", { className: "ph ph-caret-right", style: { fontSize: 11, opacity: 0.6 }, "aria-hidden": "true" }) : null,
992
1003
  i === crumbs.length - 1 ? (
993
1004
  // MP-141: the current crumb mixes a static route label with (usually) a
@@ -1196,18 +1207,18 @@ function Toast({ title, children, tone = "success", onUndo, onDismiss, className
1196
1207
  }
1197
1208
 
1198
1209
  // src/components/feedback/Tooltip.tsx
1199
- import * as React7 from "react";
1210
+ import * as React8 from "react";
1200
1211
  import { jsx as jsx24, jsxs as jsxs20 } from "react/jsx-runtime";
1201
1212
  var CLOSE_DELAY_MS = 120;
1202
1213
  function Tooltip({ label, placement = "top", children, className = "" }) {
1203
- const anchorRef = React7.useRef(null);
1204
- const bubbleRef = React7.useRef(null);
1205
- const [reason, setReason] = React7.useState(null);
1206
- const closeTimer = React7.useRef(null);
1207
- const id = React7.useId();
1214
+ const anchorRef = React8.useRef(null);
1215
+ const bubbleRef = React8.useRef(null);
1216
+ const [reason, setReason] = React8.useState(null);
1217
+ const closeTimer = React8.useRef(null);
1218
+ const id = React8.useId();
1208
1219
  const descId = id + "-desc";
1209
1220
  const open = reason != null;
1210
- const cancelClose = React7.useCallback(() => {
1221
+ const cancelClose = React8.useCallback(() => {
1211
1222
  if (closeTimer.current) {
1212
1223
  clearTimeout(closeTimer.current);
1213
1224
  closeTimer.current = null;
@@ -1217,7 +1228,7 @@ function Tooltip({ label, placement = "top", children, className = "" }) {
1217
1228
  cancelClose();
1218
1229
  setReason(why);
1219
1230
  };
1220
- const hide = React7.useCallback(() => {
1231
+ const hide = React8.useCallback(() => {
1221
1232
  cancelClose();
1222
1233
  setReason(null);
1223
1234
  }, [cancelClose]);
@@ -1232,7 +1243,7 @@ function Tooltip({ label, placement = "top", children, className = "" }) {
1232
1243
  setReason((r) => r === "hover" ? null : r);
1233
1244
  }, CLOSE_DELAY_MS);
1234
1245
  };
1235
- React7.useEffect(() => cancelClose, [cancelClose]);
1246
+ React8.useEffect(() => cancelClose, [cancelClose]);
1236
1247
  const pos = usePopoverPosition(open, anchorRef, {
1237
1248
  placement: placement === "bottom" ? "bottom-center" : "top-center",
1238
1249
  offset: 8,
@@ -1242,7 +1253,7 @@ function Tooltip({ label, placement = "top", children, className = "" }) {
1242
1253
  onDetach: hide
1243
1254
  });
1244
1255
  const zIndex = useOverlayLayer(open);
1245
- React7.useEffect(() => {
1256
+ React8.useEffect(() => {
1246
1257
  if (!open) return;
1247
1258
  const key = (e) => {
1248
1259
  if (e.key === "Escape") hide();
@@ -1270,7 +1281,7 @@ function Tooltip({ label, placement = "top", children, className = "" }) {
1270
1281
  }
1271
1282
  if (keyboard) show("focus");
1272
1283
  };
1273
- const described = React7.isValidElement(children) ? React7.cloneElement(children, {
1284
+ const described = React8.isValidElement(children) ? React8.cloneElement(children, {
1274
1285
  "aria-describedby": [children.props["aria-describedby"], descId].filter(Boolean).join(" ")
1275
1286
  }) : children;
1276
1287
  return /* @__PURE__ */ jsxs20(
@@ -1278,7 +1289,7 @@ function Tooltip({ label, placement = "top", children, className = "" }) {
1278
1289
  {
1279
1290
  ref: anchorRef,
1280
1291
  className: "fd-tooltip-anchor",
1281
- "aria-describedby": React7.isValidElement(children) ? void 0 : descId,
1292
+ "aria-describedby": React8.isValidElement(children) ? void 0 : descId,
1282
1293
  onPointerEnter: (e) => {
1283
1294
  if (isMouse(e)) hover();
1284
1295
  },
@@ -1322,7 +1333,7 @@ function Tooltip({ label, placement = "top", children, className = "" }) {
1322
1333
  }
1323
1334
 
1324
1335
  // src/components/data/Clamp.tsx
1325
- import * as React8 from "react";
1336
+ import * as React9 from "react";
1326
1337
  import { jsx as jsx25, jsxs as jsxs21 } from "react/jsx-runtime";
1327
1338
  function Clamp({
1328
1339
  children,
@@ -1334,16 +1345,16 @@ function Clamp({
1334
1345
  onToggle,
1335
1346
  className = ""
1336
1347
  }) {
1337
- const [open, setOpen] = React8.useState(false);
1338
- const [overflows, setOverflows] = React8.useState(false);
1339
- const bodyRef = React8.useRef(null);
1340
- const charClamped = React8.useMemo(() => {
1348
+ const [open, setOpen] = React9.useState(false);
1349
+ const [overflows, setOverflows] = React9.useState(false);
1350
+ const bodyRef = React9.useRef(null);
1351
+ const charClamped = React9.useMemo(() => {
1341
1352
  if (open || !maxChars || typeof text !== "string" || text.length <= maxChars) return null;
1342
1353
  const cut = text.slice(0, maxChars);
1343
1354
  const at = cut.lastIndexOf(" ");
1344
1355
  return (at > maxChars * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
1345
1356
  }, [text, maxChars, open]);
1346
- React8.useLayoutEffect(() => {
1357
+ React9.useLayoutEffect(() => {
1347
1358
  const node = bodyRef.current;
1348
1359
  if (maxChars || !node || !maxHeight) return;
1349
1360
  const measure = () => {
@@ -1482,18 +1493,18 @@ function DataTable({
1482
1493
  }
1483
1494
 
1484
1495
  // src/components/data/FilterBar.tsx
1485
- import * as React9 from "react";
1496
+ import * as React10 from "react";
1486
1497
  import { jsx as jsx28, jsxs as jsxs24 } from "react/jsx-runtime";
1487
1498
  var isSet = (v) => !(v == null || v === "" || v === false);
1488
1499
  function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align = "left", className = "", ...rest }) {
1489
- const [panel, setPanel] = React9.useState(null);
1500
+ const [panel, setPanel] = React10.useState(null);
1490
1501
  const zIndex = useOverlayLayer(!!panel);
1491
- const rootRef = React9.useRef(null);
1492
- const textInputRef = React9.useRef(null);
1493
- const optionsRef = React9.useRef(null);
1502
+ const rootRef = React10.useRef(null);
1503
+ const textInputRef = React10.useRef(null);
1504
+ const optionsRef = React10.useRef(null);
1494
1505
  const editingField = panel && panel.kind === "edit" ? fields.find((f) => f.key === panel.key) : void 0;
1495
1506
  const dismissible = !!panel && (panel.kind === "add" || panel.kind === "edit" && editingField?.type === "select");
1496
- React9.useEffect(() => {
1507
+ React10.useEffect(() => {
1497
1508
  if (!dismissible) return;
1498
1509
  const away = (e) => {
1499
1510
  if (rootRef.current && !rootRef.current.contains(e.target)) setPanel(null);
@@ -1508,7 +1519,7 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
1508
1519
  document.removeEventListener("keydown", esc);
1509
1520
  };
1510
1521
  }, [dismissible]);
1511
- React9.useEffect(() => {
1522
+ React10.useEffect(() => {
1512
1523
  if (!panel || panel.kind !== "edit") return;
1513
1524
  if (editingField?.type === "text") {
1514
1525
  textInputRef.current?.focus();
@@ -1674,7 +1685,7 @@ function StatTile({ label, value, sub, delta, loading = false, compact: compact3
1674
1685
  }
1675
1686
 
1676
1687
  // src/components/data/CodeBlock.tsx
1677
- import * as React10 from "react";
1688
+ import * as React11 from "react";
1678
1689
  import { Fragment as Fragment5, jsx as jsx30, jsxs as jsxs26 } from "react/jsx-runtime";
1679
1690
  var JS_KW = /^(?:const|let|var|function|return|if|else|for|while|do|new|class|extends|import|from|export|default|await|async|try|catch|finally|throw|typeof|instanceof|of|in|switch|case|break|continue|delete|void|yield|static|get|set|this|super|interface|type|enum|implements|public|private|protected|readonly|abstract|as|satisfies|declare|namespace)$/;
1680
1691
  var RULES = {
@@ -1830,13 +1841,13 @@ function tokenize(src, lang) {
1830
1841
  return out;
1831
1842
  }
1832
1843
  function Highlighted({ code, lang }) {
1833
- const toks = React10.useMemo(() => tokenize(code, lang), [code, lang]);
1844
+ const toks = React11.useMemo(() => tokenize(code, lang), [code, lang]);
1834
1845
  return /* @__PURE__ */ jsx30(Fragment5, { children: toks.map((tk, i) => tk.c ? /* @__PURE__ */ jsx30("span", { className: "tok-" + tk.c, children: tk.t }, i) : tk.t) });
1835
1846
  }
1836
1847
  function useCopy() {
1837
- const [done, setDone] = React10.useState(false);
1838
- const timer = React10.useRef(null);
1839
- React10.useEffect(() => () => {
1848
+ const [done, setDone] = React11.useState(false);
1849
+ const timer = React11.useRef(null);
1850
+ React11.useEffect(() => () => {
1840
1851
  if (timer.current) clearTimeout(timer.current);
1841
1852
  }, []);
1842
1853
  const copy = (text) => {
@@ -1872,8 +1883,8 @@ function CodeBlock({
1872
1883
  actions,
1873
1884
  className = ""
1874
1885
  }) {
1875
- const [wrap, setWrap] = React10.useState(!!wrapDefault);
1876
- const [open, setOpen] = React10.useState(false);
1886
+ const [wrap, setWrap] = React11.useState(!!wrapDefault);
1887
+ const [open, setOpen] = React11.useState(false);
1877
1888
  const [copied, copy] = useCopy();
1878
1889
  const body = String(code).replace(/\n$/, "");
1879
1890
  const lines = body.split("\n");
@@ -1902,7 +1913,7 @@ function CodeBlock({
1902
1913
  ] });
1903
1914
  }
1904
1915
  function DiffBlock({ diff = "", filename, collapseAfter = 34, className = "" }) {
1905
- const [open, setOpen] = React10.useState(false);
1916
+ const [open, setOpen] = React11.useState(false);
1906
1917
  const [copied, copy] = useCopy();
1907
1918
  const raw = String(diff).replace(/\n$/, "");
1908
1919
  const all = raw.split("\n").map((line) => {
@@ -1948,7 +1959,7 @@ function DiffBlock({ diff = "", filename, collapseAfter = 34, className = "" })
1948
1959
  }
1949
1960
 
1950
1961
  // src/components/data/Markdown.tsx
1951
- import * as React11 from "react";
1962
+ import * as React12 from "react";
1952
1963
  import { jsx as jsx31, jsxs as jsxs27 } from "react/jsx-runtime";
1953
1964
  var SAFE = /^(?:https?:|mailto:|tel:|#|\/|\.{1,2}\/)/i;
1954
1965
  var safeHref = (h) => SAFE.test(String(h || "").trim()) ? String(h).trim() : null;
@@ -1987,7 +1998,7 @@ function inlineNodes(src, ctx, keyBase) {
1987
1998
  const href = safeHref(g(2));
1988
1999
  out.push(href ? /* @__PURE__ */ jsx31("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__ */ jsx31("span", { children: g(1) }, key()));
1989
2000
  } else if (kind === "cite") {
1990
- out.push(ctx.renderCitation ? /* @__PURE__ */ jsx31(React11.Fragment, { children: ctx.renderCitation(g(1)) }, key()) : /* @__PURE__ */ jsx31("sup", { className: "fd-md-cite", children: g(1) }, key()));
2001
+ out.push(ctx.renderCitation ? /* @__PURE__ */ jsx31(React12.Fragment, { children: ctx.renderCitation(g(1)) }, key()) : /* @__PURE__ */ jsx31("sup", { className: "fd-md-cite", children: g(1) }, key()));
1991
2002
  } else if (kind === "strongem") out.push(/* @__PURE__ */ jsx31("strong", { children: /* @__PURE__ */ jsx31("em", { children: inlineNodes(g(1), ctx, key()) }) }, key()));
1992
2003
  else if (kind === "strong") out.push(/* @__PURE__ */ jsx31("strong", { children: inlineNodes(g(1) || g(2), ctx, key()) }, key()));
1993
2004
  else if (kind === "em") out.push(/* @__PURE__ */ jsx31("em", { children: inlineNodes(g(1) || g(2), ctx, key()) }, key()));
@@ -2152,7 +2163,7 @@ function Markdown({
2152
2163
  onLinkClick
2153
2164
  }) {
2154
2165
  const ctx = { allowImages, headingOffset, renderCitation, onLinkClick, codeProps };
2155
- const blocks = React11.useMemo(() => parseBlocks(source), [source]);
2166
+ const blocks = React12.useMemo(() => parseBlocks(source), [source]);
2156
2167
  return /* @__PURE__ */ jsx31("div", { className: ["fd-md", className].filter(Boolean).join(" "), children: renderBlocks(blocks, ctx, "b") });
2157
2168
  }
2158
2169
  function MarkdownInline({ source = "", className = "", onLinkClick }) {
@@ -2266,7 +2277,7 @@ function Pagination({
2266
2277
  }
2267
2278
 
2268
2279
  // src/components/data/RelativeTime.tsx
2269
- import * as React12 from "react";
2280
+ import * as React13 from "react";
2270
2281
  import { jsxs as jsxs30 } from "react/jsx-runtime";
2271
2282
  var MIN = 6e4;
2272
2283
  var HOUR = 36e5;
@@ -2318,9 +2329,9 @@ function formatDuration(ms) {
2318
2329
  return h + "h" + (m % 60 ? " " + m % 60 + "m" : "");
2319
2330
  }
2320
2331
  function RelativeTime({ value, prefix, className = "", refresh: refresh2 = true, ...rest }) {
2321
- const [, force] = React12.useState(0);
2332
+ const [, force] = React13.useState(0);
2322
2333
  const t = value instanceof Date ? value.getTime() : Date.parse(value);
2323
- React12.useEffect(() => {
2334
+ React13.useEffect(() => {
2324
2335
  if (!refresh2 || !t || isNaN(t)) return;
2325
2336
  const abs = Math.abs(t - Date.now());
2326
2337
  if (abs > DAY) return;
@@ -2336,10 +2347,10 @@ function RelativeTime({ value, prefix, className = "", refresh: refresh2 = true,
2336
2347
  }
2337
2348
 
2338
2349
  // src/components/data/ScoreMeter.tsx
2339
- import * as React14 from "react";
2350
+ import * as React15 from "react";
2340
2351
 
2341
2352
  // src/components/data/SegmentedMeter.tsx
2342
- import * as React13 from "react";
2353
+ import * as React14 from "react";
2343
2354
 
2344
2355
  // src/kits/files.ts
2345
2356
  function formatBytes(n) {
@@ -2544,7 +2555,7 @@ function SegmentedMeter({
2544
2555
  const pct = safeTotal ? Math.min(100, Math.round(used / safeTotal * 100)) : 0;
2545
2556
  const w = (v) => safeTotal ? Math.max(0, Math.min(100, Number(v) / safeTotal * 100)) : 0;
2546
2557
  const fill = (s, i) => s.color || (s.variant ? VARIANT_FILL[s.variant] : void 0) || CHART[i % CHART.length];
2547
- const generatedId = React13.useId();
2558
+ const generatedId = React14.useId();
2548
2559
  const uid2 = id || generatedId;
2549
2560
  return /* @__PURE__ */ jsxs31("div", { className: ["fd-segmeter", className].filter(Boolean).join(" "), onClick, children: [
2550
2561
  label || showTotal ? /* @__PURE__ */ jsxs31("div", { className: "fd-segmeter-head", children: [
@@ -2628,10 +2639,10 @@ function ScoreMeter({
2628
2639
  breakdownWidth = 280,
2629
2640
  className = ""
2630
2641
  }) {
2631
- const [open, setOpen] = React14.useState(false);
2632
- const ref = React14.useRef(null);
2642
+ const [open, setOpen] = React15.useState(false);
2643
+ const ref = React15.useRef(null);
2633
2644
  const value = Math.max(0, Math.min(100, Math.round(Number(score) || 0)));
2634
- const body = /* @__PURE__ */ jsxs32(React14.Fragment, { children: [
2645
+ const body = /* @__PURE__ */ jsxs32(React15.Fragment, { children: [
2635
2646
  /* @__PURE__ */ jsx35("span", { className: "fd-scoremeter-rail", style: { width }, "aria-hidden": "true", children: /* @__PURE__ */ jsx35(SegmentedMeter, { total: 100, segments, height, showTotal: false, showPercent: false, legend: false }) }),
2636
2647
  showScore ? /* @__PURE__ */ jsx35("span", { className: "fd-scoremeter-value fd-tabular", "aria-hidden": "true", children: value }) : null
2637
2648
  ] });
@@ -2650,7 +2661,7 @@ function ScoreMeter({
2650
2661
  }
2651
2662
  );
2652
2663
  }
2653
- return /* @__PURE__ */ jsxs32(React14.Fragment, { children: [
2664
+ return /* @__PURE__ */ jsxs32(React15.Fragment, { children: [
2654
2665
  /* @__PURE__ */ jsx35(
2655
2666
  "button",
2656
2667
  {
@@ -2681,13 +2692,13 @@ function ScoreMeter({
2681
2692
  }
2682
2693
 
2683
2694
  // src/components/data/SortMenu.tsx
2684
- import * as React15 from "react";
2695
+ import * as React16 from "react";
2685
2696
  import { jsx as jsx36, jsxs as jsxs33 } from "react/jsx-runtime";
2686
2697
  function SortMenu({ fields = [], sort, onSort, align = "right", size = "md", className = "", ...rest }) {
2687
- const [open, setOpen] = React15.useState(false);
2698
+ const [open, setOpen] = React16.useState(false);
2688
2699
  const zIndex = useOverlayLayer(open);
2689
- const ref = React15.useRef(null);
2690
- React15.useEffect(() => {
2700
+ const ref = React16.useRef(null);
2701
+ React16.useEffect(() => {
2691
2702
  if (!open) return;
2692
2703
  const away = (e) => {
2693
2704
  if (ref.current && !ref.current.contains(e.target)) setOpen(false);
@@ -2749,7 +2760,7 @@ function SortMenu({ fields = [], sort, onSort, align = "right", size = "md", cla
2749
2760
  }
2750
2761
 
2751
2762
  // src/components/data/StepList.tsx
2752
- import * as React16 from "react";
2763
+ import * as React17 from "react";
2753
2764
  import { jsx as jsx37, jsxs as jsxs34 } from "react/jsx-runtime";
2754
2765
  var KIND_ICON = { tool: "wrench", search: "magnifying-glass", read: "file-text", write: "pencil-simple", reasoning: "brain", run: "terminal", fetch: "cloud-arrow-down" };
2755
2766
  function StepList({
@@ -2762,9 +2773,9 @@ function StepList({
2762
2773
  dense = false,
2763
2774
  className = ""
2764
2775
  }) {
2765
- const [openState, setOpenState] = React16.useState(defaultOpen);
2776
+ const [openState, setOpenState] = React17.useState(defaultOpen);
2766
2777
  const open = openProp == null ? openState : openProp;
2767
- const [expanded, setExpanded] = React16.useState({});
2778
+ const [expanded, setExpanded] = React17.useState({});
2768
2779
  if (!steps.length) return null;
2769
2780
  const running = steps.some((s) => s.status === "running");
2770
2781
  const failed = steps.filter((s) => s.status === "error").length;
@@ -2822,7 +2833,7 @@ function StepList({
2822
2833
  }
2823
2834
 
2824
2835
  // src/components/data/VirtualList.tsx
2825
- import * as React17 from "react";
2836
+ import * as React18 from "react";
2826
2837
  import { jsx as jsx38, jsxs as jsxs35 } from "react/jsx-runtime";
2827
2838
  var VIRTUAL_LIST_BUFFER_ROWS = 20;
2828
2839
  var VIRTUAL_LIST_ROW_GAP = 6;
@@ -2874,35 +2885,35 @@ function VirtualList({
2874
2885
  className = "",
2875
2886
  style
2876
2887
  }) {
2877
- const [scrollTop, setScrollTop] = React17.useState(0);
2878
- const loaded = React17.useMemo(
2888
+ const [scrollTop, setScrollTop] = React18.useState(0);
2889
+ const loaded = React18.useMemo(
2879
2890
  () => ({ firstItemIndex, count: items.length }),
2880
2891
  [firstItemIndex, items.length]
2881
2892
  );
2882
2893
  const total = Math.max(totalCount == null ? 0 : totalCount, firstItemIndex + items.length);
2883
2894
  const bandKey = firstItemIndex + ":" + items.length;
2884
- const win = React17.useMemo(
2895
+ const win = React18.useMemo(
2885
2896
  () => computeVirtualWindow({ scrollTop, viewportHeight: height, itemHeight, itemCount: total, loaded }),
2886
2897
  [scrollTop, height, itemHeight, total, loaded]
2887
2898
  );
2888
- const need = React17.useMemo(() => computeNeedMore(win, loaded), [win, loaded]);
2899
+ const need = React18.useMemo(() => computeNeedMore(win, loaded), [win, loaded]);
2889
2900
  const wantStart = need.start && hasMore?.start !== false;
2890
2901
  const wantEnd = need.end && hasMore?.end !== false;
2891
2902
  const bucket2 = Math.floor(win.visibleStart / VIRTUAL_LIST_BUFFER_ROWS);
2892
2903
  const askKey = bandKey + "@" + bucket2;
2893
- const asked = React17.useRef({ start: null, end: null });
2894
- React17.useEffect(() => {
2904
+ const asked = React18.useRef({ start: null, end: null });
2905
+ React18.useEffect(() => {
2895
2906
  if (loading || !wantStart || asked.current.start === askKey) return;
2896
2907
  asked.current.start = askKey;
2897
2908
  onNeedMore("start", win);
2898
2909
  }, [wantStart, loading, askKey, onNeedMore, win]);
2899
- React17.useEffect(() => {
2910
+ React18.useEffect(() => {
2900
2911
  if (loading || !wantEnd || asked.current.end === askKey) return;
2901
2912
  asked.current.end = askKey;
2902
2913
  onNeedMore("end", win);
2903
2914
  }, [wantEnd, loading, askKey, onNeedMore, win]);
2904
- const lastKeysRef = React17.useRef(null);
2905
- const newKeys = React17.useMemo(() => {
2915
+ const lastKeysRef = React18.useRef(null);
2916
+ const newKeys = React18.useMemo(() => {
2906
2917
  const prev = lastKeysRef.current;
2907
2918
  if (!prev) return /* @__PURE__ */ new Set();
2908
2919
  const fresh = /* @__PURE__ */ new Set();
@@ -2912,7 +2923,7 @@ function VirtualList({
2912
2923
  }
2913
2924
  return fresh;
2914
2925
  }, [items]);
2915
- React17.useEffect(() => {
2926
+ React18.useEffect(() => {
2916
2927
  lastKeysRef.current = new Set(items.map(keyOf));
2917
2928
  }, [items]);
2918
2929
  const gapStyle = { "--fd-vlist-gap": rowGap + "px" };
@@ -2957,7 +2968,7 @@ function VirtualList({
2957
2968
  }
2958
2969
 
2959
2970
  // src/components/data/EntityRow.tsx
2960
- import * as React18 from "react";
2971
+ import * as React19 from "react";
2961
2972
  import { jsx as jsx39, jsxs as jsxs36 } from "react/jsx-runtime";
2962
2973
  var ENTITY_ROW_METRIC_WIDTH = 74;
2963
2974
  var METRIC_TONE_COLOR = {
@@ -2970,7 +2981,7 @@ function EntityRowMetrics({ metrics, className = "", style }) {
2970
2981
  const key = m.id || m.label || i;
2971
2982
  const className2 = ["fd-erow-metric", m.tone && m.tone !== "default" ? "is-" + m.tone : "", m.tooltip != null ? "is-described" : ""].filter(Boolean).join(" ");
2972
2983
  const tone = { color: METRIC_TONE_COLOR[m.tone || "default"] };
2973
- const content = /* @__PURE__ */ jsxs36(React18.Fragment, { children: [
2984
+ const content = /* @__PURE__ */ jsxs36(React19.Fragment, { children: [
2974
2985
  m.icon ? /* @__PURE__ */ jsx39("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }) : null,
2975
2986
  /* @__PURE__ */ jsx39("span", { className: "fd-erow-metric-value fd-tabular", children: m.value }),
2976
2987
  /* @__PURE__ */ jsx39("span", { className: "fd-sr", children: " " + m.label })
@@ -3062,14 +3073,14 @@ function EntityRow({
3062
3073
  }
3063
3074
 
3064
3075
  // src/components/data/TransferList.tsx
3065
- import * as React20 from "react";
3076
+ import * as React21 from "react";
3066
3077
  import { createPortal as createPortal4 } from "react-dom";
3067
3078
 
3068
3079
  // src/components/forms/field.tsx
3069
- import * as React19 from "react";
3080
+ import * as React20 from "react";
3070
3081
  import { jsx as jsx40, jsxs as jsxs37 } from "react/jsx-runtime";
3071
3082
  function useFieldId(id) {
3072
- const generated = React19.useId();
3083
+ const generated = React20.useId();
3073
3084
  return id || generated;
3074
3085
  }
3075
3086
  function FieldLabel({ htmlFor, id, required = false, onClick, children }) {
@@ -3187,12 +3198,12 @@ function TransferList({
3187
3198
  listHeight = 440,
3188
3199
  className = ""
3189
3200
  }) {
3190
- const [drag, setDrag] = React20.useState(null);
3191
- const [dragOverSide, setDragOverSide] = React20.useState(null);
3192
- const dragRef = React20.useRef(null);
3193
- const armedRef = React20.useRef(null);
3194
- const sideRefs = React20.useRef({ left: null, right: null });
3195
- const hitTestSide = React20.useCallback((x, y) => {
3201
+ const [drag, setDrag] = React21.useState(null);
3202
+ const [dragOverSide, setDragOverSide] = React21.useState(null);
3203
+ const dragRef = React21.useRef(null);
3204
+ const armedRef = React21.useRef(null);
3205
+ const sideRefs = React21.useRef({ left: null, right: null });
3206
+ const hitTestSide = React21.useCallback((x, y) => {
3196
3207
  for (const side of ["left", "right"]) {
3197
3208
  const el = sideRefs.current[side];
3198
3209
  if (!el) continue;
@@ -3201,7 +3212,7 @@ function TransferList({
3201
3212
  }
3202
3213
  return null;
3203
3214
  }, []);
3204
- const findItem = React20.useCallback(
3215
+ const findItem = React21.useCallback(
3205
3216
  (side, key) => (side === "left" ? left.items : right.items).find((it) => keyOf(it) === key),
3206
3217
  [left.items, right.items, keyOf]
3207
3218
  );
@@ -3223,7 +3234,7 @@ function TransferList({
3223
3234
  height: rect.height
3224
3235
  };
3225
3236
  };
3226
- React20.useEffect(() => {
3237
+ React21.useEffect(() => {
3227
3238
  const onMovePointer = (e) => {
3228
3239
  const armed = armedRef.current;
3229
3240
  if (!armed || e.pointerId !== armed.pointerId) return;
@@ -3276,7 +3287,7 @@ function TransferList({
3276
3287
  window.removeEventListener("pointercancel", endDrag);
3277
3288
  };
3278
3289
  }, [hitTestSide, findItem, onMove]);
3279
- React20.useEffect(() => {
3290
+ React21.useEffect(() => {
3280
3291
  if (!drag || typeof document === "undefined") return;
3281
3292
  const prev = document.body.style.userSelect;
3282
3293
  document.body.style.userSelect = "none";
@@ -3384,11 +3395,11 @@ function TransferList({
3384
3395
  }
3385
3396
 
3386
3397
  // src/components/forms/Checkbox.tsx
3387
- import * as React21 from "react";
3398
+ import * as React22 from "react";
3388
3399
  import { jsx as jsx44, jsxs as jsxs40 } from "react/jsx-runtime";
3389
3400
  function Checkbox({ label, description, card = false, indeterminate = false, className = "", ...rest }) {
3390
- const ref = React21.useRef(null);
3391
- React21.useEffect(() => {
3401
+ const ref = React22.useRef(null);
3402
+ React22.useEffect(() => {
3392
3403
  if (ref.current) ref.current.indeterminate = indeterminate;
3393
3404
  }, [indeterminate]);
3394
3405
  return /* @__PURE__ */ jsxs40("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
@@ -3447,7 +3458,7 @@ function Textarea({ label, help, error, required = false, rows = 4, disabled = f
3447
3458
  }
3448
3459
 
3449
3460
  // src/components/forms/NumberInput.tsx
3450
- import * as React22 from "react";
3461
+ import * as React23 from "react";
3451
3462
  import { jsx as jsx48, jsxs as jsxs44 } from "react/jsx-runtime";
3452
3463
  function NumberInput({
3453
3464
  label,
@@ -3475,10 +3486,10 @@ function NumberInput({
3475
3486
  const n = Number(String(v == null ? "" : v).replace(/[^0-9.-]/g, ""));
3476
3487
  return isNaN(n) ? null : n;
3477
3488
  };
3478
- const [text, setText] = React22.useState(value == null || value === "" ? "" : String(value));
3479
- const [editing, setEditing] = React22.useState(false);
3480
- const timer = React22.useRef(null);
3481
- React22.useEffect(() => {
3489
+ const [text, setText] = React23.useState(value == null || value === "" ? "" : String(value));
3490
+ const [editing, setEditing] = React23.useState(false);
3491
+ const timer = React23.useRef(null);
3492
+ React23.useEffect(() => {
3482
3493
  if (!editing) setText(value == null || value === "" ? "" : String(value));
3483
3494
  }, [value, editing]);
3484
3495
  const clamp = (n) => Math.min(max, Math.max(min, n));
@@ -3502,7 +3513,7 @@ function NumberInput({
3502
3513
  const release = () => {
3503
3514
  if (timer.current) clearTimeout(timer.current);
3504
3515
  };
3505
- React22.useEffect(() => () => {
3516
+ React23.useEffect(() => () => {
3506
3517
  if (timer.current) clearTimeout(timer.current);
3507
3518
  }, []);
3508
3519
  const shown = editing ? text : (() => {
@@ -3589,7 +3600,7 @@ function NumberInput({
3589
3600
  }
3590
3601
 
3591
3602
  // src/components/forms/Select.tsx
3592
- import * as React23 from "react";
3603
+ import * as React24 from "react";
3593
3604
  import { jsx as jsx49, jsxs as jsxs45 } from "react/jsx-runtime";
3594
3605
  var norm = (o) => typeof o === "string" ? { value: o, label: o } : o;
3595
3606
  function Select({
@@ -3616,13 +3627,13 @@ function Select({
3616
3627
  const isOn = (v) => multiple ? vals.includes(v) : v === value;
3617
3628
  const hasSearch = searchable === void 0 ? opts.length > 8 : searchable;
3618
3629
  const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
3619
- const [open, setOpen] = React23.useState(false);
3620
- const [q, setQ] = React23.useState("");
3621
- const [active, setActive] = React23.useState(-1);
3622
- const rootRef = React23.useRef(null);
3623
- const boxRef = React23.useRef(null);
3624
- const listRef = React23.useRef(null);
3625
- const typeBuf = React23.useRef({ s: "", t: 0 });
3630
+ const [open, setOpen] = React24.useState(false);
3631
+ const [q, setQ] = React24.useState("");
3632
+ const [active, setActive] = React24.useState(-1);
3633
+ const rootRef = React24.useRef(null);
3634
+ const boxRef = React24.useRef(null);
3635
+ const listRef = React24.useRef(null);
3636
+ const typeBuf = React24.useRef({ s: "", t: 0 });
3626
3637
  const selected = multiple ? null : opts.find((o) => o.value === value);
3627
3638
  const chosen = multiple ? opts.filter((o) => vals.includes(o.value)) : [];
3628
3639
  const boxText = multiple ? chosen.length === 0 ? placeholder : chosen.length === 1 ? chosen[0].label : summary ? summary(chosen.map((o) => o.value)) : chosen.length + " selected" : selected ? selected.label : placeholder;
@@ -3647,7 +3658,7 @@ function Select({
3647
3658
  }
3648
3659
  setOpen(!open);
3649
3660
  };
3650
- React23.useEffect(() => {
3661
+ React24.useEffect(() => {
3651
3662
  if (!open || active < 0 || !listRef.current) return;
3652
3663
  const el = listRef.current.querySelector('[data-i="' + active + '"]');
3653
3664
  if (el) {
@@ -3768,7 +3779,7 @@ function Select({
3768
3779
  ),
3769
3780
  q ? /* @__PURE__ */ jsx49("span", { className: "fd-body-sm fd-muted", children: visible.length }) : null
3770
3781
  ] }) : void 0,
3771
- footer: multiple ? /* @__PURE__ */ jsxs45(React23.Fragment, { children: [
3782
+ footer: multiple ? /* @__PURE__ */ jsxs45(React24.Fragment, { children: [
3772
3783
  /* @__PURE__ */ jsx49(
3773
3784
  "button",
3774
3785
  {
@@ -3799,7 +3810,7 @@ function Select({
3799
3810
  'Nothing matches "',
3800
3811
  q,
3801
3812
  '".'
3802
- ] }) : groups.map((grp) => /* @__PURE__ */ jsxs45(React23.Fragment, { children: [
3813
+ ] }) : groups.map((grp) => /* @__PURE__ */ jsxs45(React24.Fragment, { children: [
3803
3814
  grp.g ? /* @__PURE__ */ jsx49("div", { className: "fd-pop-group", children: grp.g }) : null,
3804
3815
  grp.items.map(({ o, i }) => /* @__PURE__ */ jsxs45(
3805
3816
  "button",
@@ -3836,7 +3847,7 @@ function Select({
3836
3847
  }
3837
3848
 
3838
3849
  // src/components/forms/DatePicker.tsx
3839
- import * as React24 from "react";
3850
+ import * as React25 from "react";
3840
3851
  import { jsx as jsx50, jsxs as jsxs46 } from "react/jsx-runtime";
3841
3852
  var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
3842
3853
  var DOW = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
@@ -3854,10 +3865,10 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3854
3865
  const today = /* @__PURE__ */ new Date();
3855
3866
  const sel = range ? value || {} : { start: value, end: value };
3856
3867
  const anchor = parse(sel.start) || parse(initialMonth) || today;
3857
- const [vy, setVy] = React24.useState(anchor.getFullYear());
3858
- const [vm, setVm] = React24.useState(anchor.getMonth());
3859
- const [mode2, setMode] = React24.useState("days");
3860
- const [hover, setHover] = React24.useState(null);
3868
+ const [vy, setVy] = React25.useState(anchor.getFullYear());
3869
+ const [vm, setVm] = React25.useState(anchor.getMonth());
3870
+ const [mode2, setMode] = React25.useState("days");
3871
+ const [hover, setHover] = React25.useState(null);
3861
3872
  const s = parse(sel.start), e = parse(sel.end);
3862
3873
  const hoverEnd = range && s && !e && hover ? parse(hover) : null;
3863
3874
  const inRange = (d) => {
@@ -3973,9 +3984,9 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3973
3984
  }
3974
3985
  function DatePicker({ label, help, error, required = false, disabled = false, range = false, value, onChange, placeholder, id, className = "", style, ...rest }) {
3975
3986
  const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
3976
- const [open, setOpen] = React24.useState(false);
3977
- const rootRef = React24.useRef(null);
3978
- const boxRef = React24.useRef(null);
3987
+ const [open, setOpen] = React25.useState(false);
3988
+ const rootRef = React25.useRef(null);
3989
+ const boxRef = React25.useRef(null);
3979
3990
  const display = range ? value && value.start ? fmt(value.start) + (value.end ? " \u2192 " + fmt(value.end) : " \u2192 \u2026") : "" : fmt(value);
3980
3991
  const toggle = () => {
3981
3992
  if (!disabled) setOpen(!open);
@@ -4038,7 +4049,7 @@ function DatePicker({ label, help, error, required = false, disabled = false, ra
4038
4049
  }
4039
4050
 
4040
4051
  // src/components/forms/TimePicker.tsx
4041
- import * as React25 from "react";
4052
+ import * as React26 from "react";
4042
4053
  import { jsx as jsx51, jsxs as jsxs47 } from "react/jsx-runtime";
4043
4054
  var pad = (n) => String(n).padStart(2, "0");
4044
4055
  function ClockFace({ value = "09:00", onChange }) {
@@ -4047,9 +4058,9 @@ function ClockFace({ value = "09:00", onChange }) {
4047
4058
  if (isNaN(m)) m = 0;
4048
4059
  const pm = h24 >= 12;
4049
4060
  const h12 = h24 % 12 === 0 ? 12 : h24 % 12;
4050
- const [mode2, setMode] = React25.useState("h");
4051
- const faceRef = React25.useRef(null);
4052
- const dragging = React25.useRef(false);
4061
+ const [mode2, setMode] = React26.useState("h");
4062
+ const faceRef = React26.useRef(null);
4063
+ const dragging = React26.useRef(false);
4053
4064
  const set = (h, mm, isPm) => onChange((isPm ? h % 12 + 12 : h % 12) + ":" + pad(mm));
4054
4065
  const R = 108, NR = 80;
4055
4066
  const nums = mode2 === "h" ? Array.from({ length: 12 }, (_, i) => i + 1) : Array.from({ length: 12 }, (_, i) => i * 5);
@@ -4122,9 +4133,9 @@ function ClockFace({ value = "09:00", onChange }) {
4122
4133
  }
4123
4134
  function TimePicker({ label, help, error, required = false, disabled = false, value = "", onChange, placeholder = "Pick a time", id, className = "", style }) {
4124
4135
  const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
4125
- const [open, setOpen] = React25.useState(false);
4126
- const rootRef = React25.useRef(null);
4127
- const boxRef = React25.useRef(null);
4136
+ const [open, setOpen] = React26.useState(false);
4137
+ const rootRef = React26.useRef(null);
4138
+ const boxRef = React26.useRef(null);
4128
4139
  const disp = () => {
4129
4140
  if (!value) return "";
4130
4141
  const [h, m] = value.split(":").map(Number);
@@ -4167,7 +4178,7 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
4167
4178
  offset: 6,
4168
4179
  width: 262,
4169
4180
  role: "presentation",
4170
- footer: /* @__PURE__ */ jsxs47(React25.Fragment, { children: [
4181
+ footer: /* @__PURE__ */ jsxs47(React26.Fragment, { children: [
4171
4182
  /* @__PURE__ */ jsx51(
4172
4183
  "button",
4173
4184
  {
@@ -4195,7 +4206,7 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
4195
4206
  }
4196
4207
 
4197
4208
  // src/components/forms/Slider.tsx
4198
- import * as React26 from "react";
4209
+ import * as React27 from "react";
4199
4210
  import { jsx as jsx52, jsxs as jsxs48 } from "react/jsx-runtime";
4200
4211
  function Slider({
4201
4212
  label,
@@ -4213,7 +4224,7 @@ function Slider({
4213
4224
  ...rest
4214
4225
  }) {
4215
4226
  const fieldId = useFieldId(id);
4216
- const [dragging, setDragging] = React26.useState(false);
4227
+ const [dragging, setDragging] = React27.useState(false);
4217
4228
  const v = value === void 0 ? min : Number(value);
4218
4229
  const pct = max === min ? 0 : (v - min) / (max - min) * 100;
4219
4230
  return /* @__PURE__ */ jsxs48("div", { className: ["fd-field", className].filter(Boolean).join(" "), children: [
@@ -4247,7 +4258,7 @@ function Slider({
4247
4258
  }
4248
4259
 
4249
4260
  // src/components/forms/RangeSlider.tsx
4250
- import * as React27 from "react";
4261
+ import * as React28 from "react";
4251
4262
  import { jsx as jsx53, jsxs as jsxs49 } from "react/jsx-runtime";
4252
4263
  function RangeSlider({
4253
4264
  label,
@@ -4267,9 +4278,9 @@ function RangeSlider({
4267
4278
  }) {
4268
4279
  const fmt2 = format || ((v) => String(v));
4269
4280
  const [a, b] = value || [min, max];
4270
- const [drag, setDrag] = React27.useState(null);
4271
- const [focus, setFocus] = React27.useState(null);
4272
- const railRef = React27.useRef(null);
4281
+ const [drag, setDrag] = React28.useState(null);
4282
+ const [focus, setFocus] = React28.useState(null);
4283
+ const railRef = React28.useRef(null);
4273
4284
  const pct = (v) => max === min ? 0 : (v - min) / (max - min) * 100;
4274
4285
  const clampPair = (i, v) => {
4275
4286
  v = Math.min(max, Math.max(min, Math.round(v / step) * step));
@@ -4284,7 +4295,7 @@ function RangeSlider({
4284
4295
  const r = railRef.current.getBoundingClientRect();
4285
4296
  return min + Math.min(1, Math.max(0, (e.clientX - r.left) / r.width)) * (max - min);
4286
4297
  };
4287
- React27.useEffect(() => {
4298
+ React28.useEffect(() => {
4288
4299
  if (drag === null) return;
4289
4300
  const mv = (e) => onChange && onChange(clampPair(drag, fromEvent(e)));
4290
4301
  const upH = () => setDrag(null);
@@ -4365,7 +4376,7 @@ function RangeSlider({
4365
4376
  /* @__PURE__ */ jsxs49("div", { className: "fd-range" + (hasLabels ? " has-labels" : ""), onPointerDown: onRailDown, children: [
4366
4377
  /* @__PURE__ */ jsx53("span", { className: "fd-range-rail", ref: railRef }),
4367
4378
  /* @__PURE__ */ jsx53("span", { className: "fd-range-fill", style: { left: pct(a) + "%", width: pct(b) - pct(a) + "%" } }),
4368
- marks.map((m) => /* @__PURE__ */ jsxs49(React27.Fragment, { children: [
4379
+ marks.map((m) => /* @__PURE__ */ jsxs49(React28.Fragment, { children: [
4369
4380
  /* @__PURE__ */ jsx53("span", { className: "fd-range-mark" + (m.value >= a && m.value <= b ? " is-in" : ""), style: { left: pct(m.value) + "%" } }),
4370
4381
  m.label ? /* @__PURE__ */ jsx53("span", { className: "fd-range-mark-label", style: { left: pct(m.value) + "%" }, children: m.label }) : null
4371
4382
  ] }, m.value)),
@@ -4394,7 +4405,7 @@ function RangeSlider({
4394
4405
  }
4395
4406
 
4396
4407
  // src/components/forms/Dropzone.tsx
4397
- import * as React28 from "react";
4408
+ import * as React29 from "react";
4398
4409
  import { jsx as jsx54, jsxs as jsxs50 } from "react/jsx-runtime";
4399
4410
  function Dropzone({
4400
4411
  onFiles,
@@ -4409,8 +4420,8 @@ function Dropzone({
4409
4420
  className = "",
4410
4421
  style
4411
4422
  }) {
4412
- const [over, setOver] = React28.useState(false);
4413
- const depth = React28.useRef(0);
4423
+ const [over, setOver] = React29.useState(false);
4424
+ const depth = React29.useRef(0);
4414
4425
  const has = (e) => {
4415
4426
  const dt = e.dataTransfer;
4416
4427
  if (!dt) return false;
@@ -4472,8 +4483,8 @@ function FilePickButton({
4472
4483
  className = "",
4473
4484
  children
4474
4485
  }) {
4475
- const ref = React28.useRef(null);
4476
- return /* @__PURE__ */ jsxs50(React28.Fragment, { children: [
4486
+ const ref = React29.useRef(null);
4487
+ return /* @__PURE__ */ jsxs50(React29.Fragment, { children: [
4477
4488
  /* @__PURE__ */ jsx54(
4478
4489
  "button",
4479
4490
  {
@@ -4506,10 +4517,10 @@ function FilePickButton({
4506
4517
  }
4507
4518
  function useStagedFiles(upload, opts) {
4508
4519
  const o = opts || {};
4509
- const [items, setItems] = React28.useState([]);
4510
- const controllers = React28.useRef({});
4520
+ const [items, setItems] = React29.useState([]);
4521
+ const controllers = React29.useRef({});
4511
4522
  const patch = (id, next) => setItems((list) => list.map((f) => f.id === id ? Object.assign({}, f, next) : f));
4512
- const run = React28.useCallback((att) => {
4523
+ const run = React29.useCallback((att) => {
4513
4524
  if (!upload) return;
4514
4525
  const ac = typeof AbortController !== "undefined" ? new AbortController() : null;
4515
4526
  controllers.current[att.id] = ac;
@@ -4526,14 +4537,14 @@ function useStagedFiles(upload, opts) {
4526
4537
  delete controllers.current[att.id];
4527
4538
  });
4528
4539
  }, [upload]);
4529
- const add = React28.useCallback((files) => {
4540
+ const add = React29.useCallback((files) => {
4530
4541
  if (!upload) return [];
4531
4542
  const atts = Array.from(files).map((f) => toAttachment(f));
4532
4543
  setItems((list) => list.concat(atts));
4533
4544
  atts.forEach(run);
4534
4545
  return atts;
4535
4546
  }, [upload, run]);
4536
- const remove = React28.useCallback((att) => {
4547
+ const remove = React29.useCallback((att) => {
4537
4548
  const ac = controllers.current[att.id];
4538
4549
  if (ac) {
4539
4550
  try {
@@ -4544,10 +4555,10 @@ function useStagedFiles(upload, opts) {
4544
4555
  }
4545
4556
  setItems((list) => list.filter((f) => f.id !== att.id));
4546
4557
  }, []);
4547
- const retry = React28.useCallback((att) => {
4558
+ const retry = React29.useCallback((att) => {
4548
4559
  run(att);
4549
4560
  }, [run]);
4550
- const clear = React28.useCallback(() => {
4561
+ const clear = React29.useCallback(() => {
4551
4562
  Object.values(controllers.current).forEach((ac) => {
4552
4563
  try {
4553
4564
  ac && ac.abort();
@@ -4671,7 +4682,7 @@ function FileGrid({ files = [], onOpen, onRemove, onRetry, tiles = true, maxHeig
4671
4682
  }
4672
4683
 
4673
4684
  // src/components/forms/MarkdownEditor.tsx
4674
- import * as React29 from "react";
4685
+ import * as React30 from "react";
4675
4686
  import { jsx as jsx56, jsxs as jsxs52 } from "react/jsx-runtime";
4676
4687
  var isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent || "");
4677
4688
  var INLINE_RE = /(\*\*\*[^*\n]+\*\*\*|\*\*[^*\n]+\*\*|__[^_\n]+__|~~[^~\n]+~~|`[^`\n]+`|\*[^*\s][^*\n]*\*|(?<![A-Za-z0-9_])_[^_\s][^_\n]*_|\[[^\]\n]*\]\([^)\s\n]*\)|https?:\/\/\S+)/g;
@@ -4885,7 +4896,7 @@ function syncDom(root, value) {
4885
4896
  while (root.children.length > lines.length) root.removeChild(root.lastChild);
4886
4897
  }
4887
4898
  var LIST_CONT = RE_LI;
4888
- var MarkdownEditor = React29.forwardRef(function MarkdownEditor2({
4899
+ var MarkdownEditor = React30.forwardRef(function MarkdownEditor2({
4889
4900
  value = "",
4890
4901
  onChange,
4891
4902
  onSubmit,
@@ -4904,10 +4915,10 @@ var MarkdownEditor = React29.forwardRef(function MarkdownEditor2({
4904
4915
  className = "",
4905
4916
  id
4906
4917
  }, ref) {
4907
- const boxRef = React29.useRef(null);
4908
- const composing = React29.useRef(false);
4909
- const pendingCaret = React29.useRef(null);
4910
- React29.useLayoutEffect(() => {
4918
+ const boxRef = React30.useRef(null);
4919
+ const composing = React30.useRef(false);
4920
+ const pendingCaret = React30.useRef(null);
4921
+ React30.useLayoutEffect(() => {
4911
4922
  const root = boxRef.current;
4912
4923
  if (!root || composing.current) return;
4913
4924
  const active = document.activeElement === root || root.contains(document.activeElement);
@@ -4916,7 +4927,7 @@ var MarkdownEditor = React29.forwardRef(function MarkdownEditor2({
4916
4927
  pendingCaret.current = null;
4917
4928
  if (active && caret != null) placeCaret(root, caret);
4918
4929
  }, [value]);
4919
- React29.useEffect(() => {
4930
+ React30.useEffect(() => {
4920
4931
  if (autoFocus && boxRef.current) boxRef.current.focus();
4921
4932
  }, [autoFocus]);
4922
4933
  const caretNow = () => {
@@ -4983,7 +4994,7 @@ var MarkdownEditor = React29.forwardRef(function MarkdownEditor2({
4983
4994
  api.replaceRange(from, to, next, from + next.length);
4984
4995
  }
4985
4996
  };
4986
- React29.useImperativeHandle(ref, () => api);
4997
+ React30.useImperativeHandle(ref, () => api);
4987
4998
  function detect(text, caret) {
4988
4999
  if (!onTrigger) return;
4989
5000
  const upto = text.slice(0, caret);
@@ -5135,16 +5146,16 @@ var MarkdownEditor = React29.forwardRef(function MarkdownEditor2({
5135
5146
  });
5136
5147
 
5137
5148
  // src/components/platform/AccountMenu.tsx
5138
- import * as React31 from "react";
5149
+ import * as React32 from "react";
5139
5150
 
5140
5151
  // src/kits/sessionContext.tsx
5141
- import * as React30 from "react";
5142
- var SessionContext = React30.createContext(null);
5152
+ import * as React31 from "react";
5153
+ var SessionContext = React31.createContext(null);
5143
5154
  function SessionProvider({ value, children }) {
5144
- return React30.createElement(SessionContext.Provider, { value }, children);
5155
+ return React31.createElement(SessionContext.Provider, { value }, children);
5145
5156
  }
5146
5157
  function useSessionContext() {
5147
- const ctx = React30.useContext(SessionContext);
5158
+ const ctx = React31.useContext(SessionContext);
5148
5159
  if (!ctx) {
5149
5160
  throw new Error(
5150
5161
  "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."
@@ -5155,20 +5166,8 @@ function useSessionContext() {
5155
5166
 
5156
5167
  // src/components/platform/AccountMenu.tsx
5157
5168
  import { Fragment as Fragment14, jsx as jsx57, jsxs as jsxs53 } from "react/jsx-runtime";
5158
- var DEFAULT_LINKS = [
5159
- { id: "profile", label: "Your profile", icon: "user-circle", href: "../admin/index.html#profile" },
5160
- { id: "preferences", label: "Preferences", icon: "sliders-horizontal", href: "../admin/index.html#preferences" }
5161
- ];
5162
- var DEFAULT_GROUPS = [
5163
- {
5164
- label: "Administration",
5165
- links: [
5166
- { id: "users", label: "Users", icon: "users-three", href: "../admin/index.html#users", perm: "users.view" },
5167
- { id: "roles", label: "Roles & permissions", icon: "shield-check", href: "../admin/index.html#roles", perm: "roles.manage" },
5168
- { id: "flags", label: "Feature flags", icon: "toggle-right", href: "../admin/index.html#flags", perm: "flags.manage" }
5169
- ]
5170
- }
5171
- ];
5169
+ var DEFAULT_LINKS = [];
5170
+ var DEFAULT_GROUPS = [];
5172
5171
  function Item({ item, onPick }) {
5173
5172
  return /* @__PURE__ */ jsxs53(
5174
5173
  "button",
@@ -5196,10 +5195,10 @@ function AccountMenu({
5196
5195
  ...rest
5197
5196
  }) {
5198
5197
  const { user, roles, can: can2, signOut: ctxSignOut, demo } = useSessionContext();
5199
- const [open, setOpen] = React31.useState(false);
5200
- const [switching, setSwitching] = React31.useState(false);
5201
- const [signingOut, setSigningOut] = React31.useState(false);
5202
- const ref = React31.useRef(null);
5198
+ const [open, setOpen] = React32.useState(false);
5199
+ const [switching, setSwitching] = React32.useState(false);
5200
+ const [signingOut, setSigningOut] = React32.useState(false);
5201
+ const ref = React32.useRef(null);
5203
5202
  const visibleLinks = links.filter((l) => !l.perm || can2(l.perm));
5204
5203
  const visibleGroups = groups.map((g) => ({ label: g.label, links: g.links.filter((l) => !l.perm || can2(l.perm)) })).filter((g) => g.links.length);
5205
5204
  const pick = (item) => {
@@ -5302,13 +5301,13 @@ function AccountMenu({
5302
5301
  }
5303
5302
 
5304
5303
  // src/components/platform/AppSwitcher.tsx
5305
- import * as React32 from "react";
5304
+ import * as React33 from "react";
5306
5305
  import { jsx as jsx58, jsxs as jsxs54 } from "react/jsx-runtime";
5307
5306
  function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
5308
5307
  const { apps: contextApps } = useSessionContext();
5309
5308
  const apps = appsProp ?? contextApps ?? [];
5310
- const [open, setOpen] = React32.useState(false);
5311
- const anchorRef = React32.useRef(null);
5309
+ const [open, setOpen] = React33.useState(false);
5310
+ const anchorRef = React33.useRef(null);
5312
5311
  if (!apps.length) return null;
5313
5312
  const items = apps.map((app) => ({
5314
5313
  id: app.key,
@@ -5322,7 +5321,7 @@ function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
5322
5321
  window.location.href = app.url;
5323
5322
  }
5324
5323
  }));
5325
- return /* @__PURE__ */ jsxs54(React32.Fragment, { children: [
5324
+ return /* @__PURE__ */ jsxs54(React33.Fragment, { children: [
5326
5325
  /* @__PURE__ */ jsx58("span", { ref: anchorRef, className: ["fd-appswitch-anchor", className].filter(Boolean).join(" "), style: { display: "inline-flex" }, children: /* @__PURE__ */ jsx58(
5327
5326
  IconButton,
5328
5327
  {
@@ -5351,10 +5350,10 @@ function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
5351
5350
  }
5352
5351
 
5353
5352
  // src/components/platform/AppearanceMenu.tsx
5354
- import * as React34 from "react";
5353
+ import * as React35 from "react";
5355
5354
 
5356
5355
  // src/kits/appearance.ts
5357
- import * as React33 from "react";
5356
+ import * as React34 from "react";
5358
5357
  var DEFAULT_STORAGE_KEY = "fd-appearance";
5359
5358
  var DEFAULT_PREFS = {
5360
5359
  theme: "system",
@@ -5449,11 +5448,11 @@ function applyPrefs(prefs, root = document.documentElement) {
5449
5448
  else root.removeAttribute("data-motion");
5450
5449
  }
5451
5450
  function useAppearancePrefs(store) {
5452
- const prefs = React33.useSyncExternalStore(store.subscribe, store.getSnapshot);
5453
- React33.useEffect(() => {
5451
+ const prefs = React34.useSyncExternalStore(store.subscribe, store.getSnapshot);
5452
+ React34.useEffect(() => {
5454
5453
  applyPrefs(prefs);
5455
5454
  }, [prefs]);
5456
- React33.useEffect(() => {
5455
+ React34.useEffect(() => {
5457
5456
  if (prefs.theme !== "system" || typeof window === "undefined" || typeof window.matchMedia !== "function") {
5458
5457
  return;
5459
5458
  }
@@ -5462,7 +5461,7 @@ function useAppearancePrefs(store) {
5462
5461
  mq.addEventListener("change", onChange);
5463
5462
  return () => mq.removeEventListener("change", onChange);
5464
5463
  }, [prefs]);
5465
- const update = React33.useCallback(
5464
+ const update = React34.useCallback(
5466
5465
  (patch) => {
5467
5466
  store.write({ ...store.getSnapshot(), ...patch });
5468
5467
  },
@@ -5485,15 +5484,15 @@ var TEXT_SCALE_OPTIONS = [
5485
5484
  { value: "xl", label: "XL" }
5486
5485
  ];
5487
5486
  function AppearanceMenu({ className = "", store: storeProp, storageKey, storage, defaults }) {
5488
- const store = React34.useMemo(
5487
+ const store = React35.useMemo(
5489
5488
  () => storeProp ?? createLocalStorageAppearanceStore({ storageKey, storage, defaults }),
5490
5489
  [storeProp, storageKey, storage, defaults]
5491
5490
  );
5492
5491
  const [prefs, update] = useAppearancePrefs(store);
5493
- const [open, setOpen] = React34.useState(false);
5494
- const anchorRef = React34.useRef(null);
5492
+ const [open, setOpen] = React35.useState(false);
5493
+ const anchorRef = React35.useRef(null);
5495
5494
  const patch = (p) => update(p);
5496
- return /* @__PURE__ */ jsxs55(React34.Fragment, { children: [
5495
+ return /* @__PURE__ */ jsxs55(React35.Fragment, { children: [
5497
5496
  /* @__PURE__ */ jsx59("span", { ref: anchorRef, className: ["fd-appearance-anchor", className].filter(Boolean).join(" "), style: { display: "inline-flex" }, children: /* @__PURE__ */ jsx59(
5498
5497
  IconButton,
5499
5498
  {
@@ -5562,14 +5561,14 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
5562
5561
  }
5563
5562
 
5564
5563
  // src/components/platform/ApiSpecBrowser.tsx
5565
- import * as React35 from "react";
5564
+ import * as React36 from "react";
5566
5565
  import { jsx as jsx60, jsxs as jsxs56 } from "react/jsx-runtime";
5567
5566
  var METHOD_TONE = { GET: "success", POST: "info", PATCH: "warning", PUT: "warning", DELETE: "danger" };
5568
5567
  function Json({ obj }) {
5569
5568
  return /* @__PURE__ */ jsx60("pre", { className: "fd-json", children: JSON.stringify(obj, null, 2) });
5570
5569
  }
5571
5570
  function Endpoint({ s, onRequest }) {
5572
- const [tried, setTried] = React35.useState(null);
5571
+ const [tried, setTried] = React36.useState(null);
5573
5572
  const run = async () => {
5574
5573
  setTried("busy");
5575
5574
  const t0 = (window.performance || Date).now();
@@ -5642,10 +5641,10 @@ function ApiSpecBrowser({
5642
5641
  className = "",
5643
5642
  ...rest
5644
5643
  }) {
5645
- const [q, setQ] = React35.useState("");
5646
- const [method, setMethod] = React35.useState(null);
5647
- const [mod, setMod] = React35.useState(null);
5648
- const [listOnly, setListOnly] = React35.useState(false);
5644
+ const [q, setQ] = React36.useState("");
5645
+ const [method, setMethod] = React36.useState(null);
5646
+ const [mod, setMod] = React36.useState(null);
5647
+ const [listOnly, setListOnly] = React36.useState(false);
5649
5648
  const activeModule = modules && modules.find((m) => m.id === mod);
5650
5649
  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())));
5651
5650
  const effGroups = groups && groups.length ? groups : [["All endpoints", spec.map((s) => s.id)]];
@@ -5724,7 +5723,7 @@ function ApiSpecBrowser({
5724
5723
  }
5725
5724
 
5726
5725
  // src/components/platform/ProfilePage.tsx
5727
- import * as React36 from "react";
5726
+ import * as React37 from "react";
5728
5727
  import { jsx as jsx61, jsxs as jsxs57 } from "react/jsx-runtime";
5729
5728
  function fieldInitialValue(field, user) {
5730
5729
  if (field.value) return field.value(user);
@@ -5760,21 +5759,21 @@ function ProfilePage({
5760
5759
  }) {
5761
5760
  const { user: sessionUser, roles, permissions, saveProfile: saveProfile2 } = useSessionContext();
5762
5761
  const user = userProp || sessionUser;
5763
- const initialFieldValues = React36.useMemo(() => {
5762
+ const initialFieldValues = React37.useMemo(() => {
5764
5763
  const values2 = {};
5765
5764
  for (const field of fields) values2[field.key] = fieldInitialValue(field, user);
5766
5765
  return values2;
5767
5766
  }, [user.id, fields]);
5768
- const initialNotify = React36.useMemo(() => {
5767
+ const initialNotify = React37.useMemo(() => {
5769
5768
  const values2 = {};
5770
5769
  for (const n of notifications) values2[n.key] = !!user.notify?.[n.key];
5771
5770
  return values2;
5772
5771
  }, [user.id, notifications]);
5773
- const [values, setValues] = React36.useState(initialFieldValues);
5774
- const [notify, setNotify] = React36.useState(initialNotify);
5775
- const [saving, setSaving] = React36.useState(false);
5776
- const [saved, setSaved] = React36.useState(false);
5777
- const [prevUserId, setPrevUserId] = React36.useState(user.id);
5772
+ const [values, setValues] = React37.useState(initialFieldValues);
5773
+ const [notify, setNotify] = React37.useState(initialNotify);
5774
+ const [saving, setSaving] = React37.useState(false);
5775
+ const [saved, setSaved] = React37.useState(false);
5776
+ const [prevUserId, setPrevUserId] = React37.useState(user.id);
5778
5777
  if (user.id !== prevUserId) {
5779
5778
  setPrevUserId(user.id);
5780
5779
  setValues(initialFieldValues);
@@ -5962,10 +5961,10 @@ function ProfilePage({
5962
5961
  }
5963
5962
 
5964
5963
  // src/components/platform/RoadmapTimeline.tsx
5965
- import * as React39 from "react";
5964
+ import * as React40 from "react";
5966
5965
 
5967
5966
  // src/kits/session.ts
5968
- import * as React37 from "react";
5967
+ import * as React38 from "react";
5969
5968
  var PERMISSION_CATALOG = [
5970
5969
  { group: "Plans", items: [
5971
5970
  { key: "plan.view", label: "View plans", detail: "Read any plan in the workspace." },
@@ -7532,8 +7531,8 @@ function roadmap(overrides) {
7532
7531
  };
7533
7532
  }
7534
7533
  function useSession() {
7535
- const [s, setS] = React37.useState(getSession);
7536
- React37.useEffect(() => subscribe(setS), []);
7534
+ const [s, setS] = React38.useState(getSession);
7535
+ React38.useEffect(() => subscribe(setS), []);
7537
7536
  return s;
7538
7537
  }
7539
7538
  var SessionKit = {
@@ -7566,7 +7565,7 @@ var SessionKit = {
7566
7565
  };
7567
7566
  function DemoSessionProvider({ children }) {
7568
7567
  const session = useSession();
7569
- const value = React37.useMemo(
7568
+ const value = React38.useMemo(
7570
7569
  () => ({
7571
7570
  user: session.user,
7572
7571
  roles: session.roles,
@@ -7582,11 +7581,11 @@ function DemoSessionProvider({ children }) {
7582
7581
  }),
7583
7582
  [session]
7584
7583
  );
7585
- return React37.createElement(SessionProvider, { value }, children);
7584
+ return React38.createElement(SessionProvider, { value }, children);
7586
7585
  }
7587
7586
 
7588
7587
  // src/kits/runtime.ts
7589
- import * as React38 from "react";
7588
+ import * as React39 from "react";
7590
7589
  var WIRED_ENDPOINTS = [
7591
7590
  // Nothing yet. Every id below would come from a real service:
7592
7591
  // "plan.get", "placements.list", …
@@ -7757,8 +7756,8 @@ var RuntimeKit = {
7757
7756
  };
7758
7757
  RuntimeKit.declare(FEATURE_NEEDS);
7759
7758
  function useRuntimeMode() {
7760
- const [m, setM] = React38.useState(RuntimeKit.getMode());
7761
- React38.useEffect(() => RuntimeKit.subscribe(setM), []);
7759
+ const [m, setM] = React39.useState(RuntimeKit.getMode());
7760
+ React39.useEffect(() => RuntimeKit.subscribe(setM), []);
7762
7761
  return m;
7763
7762
  }
7764
7763
  function useFeatureStatus(key) {
@@ -7841,12 +7840,12 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
7841
7840
  }
7842
7841
  function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
7843
7842
  const session = SessionKit.useSession();
7844
- const [project, setProject] = React39.useState("");
7845
- const [q, setQ] = React39.useState("");
7846
- const scrollRef = React39.useRef(null);
7847
- const nowRef = React39.useRef(null);
7848
- const rm = React39.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
7849
- const byKey = React39.useMemo(() => {
7843
+ const [project, setProject] = React40.useState("");
7844
+ const [q, setQ] = React40.useState("");
7845
+ const scrollRef = React40.useRef(null);
7846
+ const nowRef = React40.useRef(null);
7847
+ const rm = React40.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
7848
+ const byKey = React40.useMemo(() => {
7850
7849
  const m = {};
7851
7850
  rm.items.forEach((i) => {
7852
7851
  m[i.key] = i;
@@ -7855,7 +7854,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
7855
7854
  }, [rm]);
7856
7855
  const items = rm.items.filter((i) => (!project || i.project === project) && (!q || (i.label + " " + i.description + " " + (i.backend || "") + " " + i.key).toLowerCase().includes(q.toLowerCase())));
7857
7856
  const projects = [...new Set(rm.items.map((i) => i.project))];
7858
- React39.useEffect(() => {
7857
+ React40.useEffect(() => {
7859
7858
  let raf1 = 0, raf2 = 0;
7860
7859
  const place = () => {
7861
7860
  const box = scrollRef.current, mark = nowRef.current;
@@ -7929,7 +7928,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
7929
7928
  lastPhase = item.phase;
7930
7929
  const inPhase = items.filter((i) => i.phase === item.phase).length;
7931
7930
  const isBoundary = n === firstPending;
7932
- return /* @__PURE__ */ jsxs58(React39.Fragment, { children: [
7931
+ return /* @__PURE__ */ jsxs58(React40.Fragment, { children: [
7933
7932
  showPhase ? /* @__PURE__ */ jsxs58("div", { className: "fd-rm-era", children: [
7934
7933
  /* @__PURE__ */ jsxs58("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
7935
7934
  /* @__PURE__ */ jsx62("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
@@ -7973,7 +7972,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
7973
7972
  }
7974
7973
 
7975
7974
  // src/components/platform/ComingSoon.tsx
7976
- import * as React40 from "react";
7975
+ import * as React41 from "react";
7977
7976
  import { createPortal as createPortal5 } from "react-dom";
7978
7977
  import { Fragment as Fragment18, jsx as jsx63, jsxs as jsxs59 } from "react/jsx-runtime";
7979
7978
  var BYPASS_STORE = "fd.soon.bypass.v1";
@@ -7991,8 +7990,8 @@ function writeBypassed(list) {
7991
7990
  }
7992
7991
  }
7993
7992
  function useBypass(key) {
7994
- const [on, setOn] = React40.useState(() => !!key && readBypassed().indexOf(key) >= 0);
7995
- React40.useEffect(() => {
7993
+ const [on, setOn] = React41.useState(() => !!key && readBypassed().indexOf(key) >= 0);
7994
+ React41.useEffect(() => {
7996
7995
  setOn(!!key && readBypassed().indexOf(key) >= 0);
7997
7996
  }, [key]);
7998
7997
  const set = (next) => {
@@ -8039,9 +8038,9 @@ function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onB
8039
8038
  ] });
8040
8039
  }
8041
8040
  function useHoverCard(open) {
8042
- const anchor = React40.useRef(null);
8043
- const [pos, setPos] = React40.useState(null);
8044
- React40.useLayoutEffect(() => {
8041
+ const anchor = React41.useRef(null);
8042
+ const [pos, setPos] = React41.useState(null);
8043
+ React41.useLayoutEffect(() => {
8045
8044
  if (!open || !anchor.current) {
8046
8045
  setPos(null);
8047
8046
  return;
@@ -8168,10 +8167,10 @@ function ComingSoon({
8168
8167
  ] });
8169
8168
  }
8170
8169
  function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass, blur, tip, className, rest, children }) {
8171
- const [open, setOpen] = React40.useState(false);
8170
+ const [open, setOpen] = React41.useState(false);
8172
8171
  const [anchor, pos] = useHoverCard(open);
8173
8172
  const zIndex = useOverlayLayer(open);
8174
- const close = React40.useRef(null);
8173
+ const close = React41.useRef(null);
8175
8174
  const show = () => {
8176
8175
  if (close.current) {
8177
8176
  clearTimeout(close.current);
@@ -8187,7 +8186,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
8187
8186
  setOpen(false);
8188
8187
  }, 140);
8189
8188
  };
8190
- React40.useEffect(() => () => {
8189
+ React41.useEffect(() => () => {
8191
8190
  if (close.current) clearTimeout(close.current);
8192
8191
  }, []);
8193
8192
  return /* @__PURE__ */ jsxs59(
@@ -8358,14 +8357,14 @@ function PermissionHint({ perm, children }) {
8358
8357
  }
8359
8358
 
8360
8359
  // src/components/platform/ModeSwitch.tsx
8361
- import * as React41 from "react";
8360
+ import * as React42 from "react";
8362
8361
  import { Fragment as Fragment19, jsx as jsx65, jsxs as jsxs61 } from "react/jsx-runtime";
8363
8362
  function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
8364
8363
  const mode2 = useRuntimeMode();
8365
- const [open, setOpen] = React41.useState(false);
8364
+ const [open, setOpen] = React42.useState(false);
8366
8365
  const zIndex = useOverlayLayer(open);
8367
- const ref = React41.useRef(null);
8368
- React41.useEffect(() => {
8366
+ const ref = React42.useRef(null);
8367
+ React42.useEffect(() => {
8369
8368
  if (!open) return;
8370
8369
  const away = (e) => {
8371
8370
  if (ref.current && !ref.current.contains(e.target)) setOpen(false);
@@ -8621,7 +8620,7 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
8621
8620
  }
8622
8621
 
8623
8622
  // src/components/planner/MixGap.tsx
8624
- import * as React42 from "react";
8623
+ import * as React43 from "react";
8625
8624
  import { Fragment as Fragment20, jsx as jsx68, jsxs as jsxs64 } from "react/jsx-runtime";
8626
8625
  var MIX_GAP_LAYOUT = {
8627
8626
  trackHeight: 30,
@@ -8636,7 +8635,7 @@ function mixGapOffset(value, max) {
8636
8635
  }
8637
8636
  function MixGap({ rows = [], loading = false, className = "" }) {
8638
8637
  const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
8639
- const [hover, setHover] = React42.useState(null);
8638
+ const [hover, setHover] = React43.useState(null);
8640
8639
  const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
8641
8640
  const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
8642
8641
  const { trackHeight, barHeight, targetWidth, labelGap } = MIX_GAP_LAYOUT;
@@ -8779,7 +8778,7 @@ function ChannelContribution({
8779
8778
  }
8780
8779
 
8781
8780
  // src/components/planner/BudgetReallocator.tsx
8782
- import * as React43 from "react";
8781
+ import * as React44 from "react";
8783
8782
  import { Fragment as Fragment21, jsx as jsx70, jsxs as jsxs66 } from "react/jsx-runtime";
8784
8783
  var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
8785
8784
  function BudgetReallocator({
@@ -8795,8 +8794,8 @@ function BudgetReallocator({
8795
8794
  onCancel,
8796
8795
  className = ""
8797
8796
  }) {
8798
- const [draft, setDraft] = React43.useState(spend);
8799
- React43.useEffect(() => setDraft(spend), [spend]);
8797
+ const [draft, setDraft] = React44.useState(spend);
8798
+ React44.useEffect(() => setDraft(spend), [spend]);
8800
8799
  const dirty = draft !== spend;
8801
8800
  const nextCrp = scoreFor ? scoreFor(draft) : crp;
8802
8801
  const nextBand = bandFor(nextCrp);
@@ -8811,10 +8810,10 @@ function BudgetReallocator({
8811
8810
  setDraft(spend);
8812
8811
  if (onCancel) onCancel();
8813
8812
  };
8814
- const trackRef = React43.useRef(null);
8815
- const chipRef = React43.useRef(null);
8816
- const [chipLeft, setChipLeft] = React43.useState(null);
8817
- React43.useLayoutEffect(() => {
8813
+ const trackRef = React44.useRef(null);
8814
+ const chipRef = React44.useRef(null);
8815
+ const [chipLeft, setChipLeft] = React44.useState(null);
8816
+ React44.useLayoutEffect(() => {
8818
8817
  const track = trackRef.current;
8819
8818
  if (!dirty || !track) {
8820
8819
  setChipLeft(null);
@@ -9001,7 +9000,7 @@ function ImportanceTag({ level, showLabel = true, size = "sm", className = "" })
9001
9000
  }
9002
9001
 
9003
9002
  // src/components/planner/PreferenceMeter.tsx
9004
- import * as React44 from "react";
9003
+ import * as React45 from "react";
9005
9004
  import { jsx as jsx73, jsxs as jsxs69 } from "react/jsx-runtime";
9006
9005
  function preferenceScore(criteria) {
9007
9006
  const earned = criteria.reduce((n, c) => n + (Number(c.earned) || 0), 0);
@@ -9031,7 +9030,7 @@ function PreferenceMeter({
9031
9030
  className = ""
9032
9031
  }) {
9033
9032
  const value = score == null ? preferenceScore(criteria) : score;
9034
- const segments = React44.useMemo(() => preferenceSegments(criteria), [criteria]);
9033
+ const segments = React45.useMemo(() => preferenceSegments(criteria), [criteria]);
9035
9034
  return /* @__PURE__ */ jsx73(
9036
9035
  ScoreMeter,
9037
9036
  {
@@ -9070,10 +9069,10 @@ function PreferenceMeter({
9070
9069
  }
9071
9070
 
9072
9071
  // src/components/chat/AgentChatPanel.tsx
9073
- import * as React50 from "react";
9072
+ import * as React51 from "react";
9074
9073
 
9075
9074
  // src/components/chat/chatEngine.ts
9076
- import * as React45 from "react";
9075
+ import * as React46 from "react";
9077
9076
  var CHAT_UNAVAILABLE = "chat_unavailable";
9078
9077
  var JOB_PENDING = ["queued", "running"];
9079
9078
  var JOB_SUCCESS = ["completed", "recovered"];
@@ -9127,22 +9126,22 @@ function useChatEngine(opts) {
9127
9126
  onClear,
9128
9127
  onFeedback
9129
9128
  } = opts || {};
9130
- const [status, setStatus] = React45.useState("idle");
9131
- const [threadId, setThreadId] = React45.useState(null);
9132
- const [messages, setMessages] = React45.useState([]);
9133
- const [queue, setQueue] = React45.useState([]);
9134
- const [fatal, setFatal] = React45.useState(null);
9135
- const [busy, setBusy] = React45.useState(false);
9136
- const [turnStartedAt, setTurnStartedAt] = React45.useState(null);
9137
- const listRef = React45.useRef([]);
9138
- const queueRef = React45.useRef([]);
9139
- const busyRef = React45.useRef(false);
9140
- const stoppedRef = React45.useRef(false);
9141
- const abortRef = React45.useRef(null);
9142
- const serverCount = React45.useRef(0);
9143
- const threadRef = React45.useRef(null);
9144
- const mounted = React45.useRef(true);
9145
- React45.useEffect(() => {
9129
+ const [status, setStatus] = React46.useState("idle");
9130
+ const [threadId, setThreadId] = React46.useState(null);
9131
+ const [messages, setMessages] = React46.useState([]);
9132
+ const [queue, setQueue] = React46.useState([]);
9133
+ const [fatal, setFatal] = React46.useState(null);
9134
+ const [busy, setBusy] = React46.useState(false);
9135
+ const [turnStartedAt, setTurnStartedAt] = React46.useState(null);
9136
+ const listRef = React46.useRef([]);
9137
+ const queueRef = React46.useRef([]);
9138
+ const busyRef = React46.useRef(false);
9139
+ const stoppedRef = React46.useRef(false);
9140
+ const abortRef = React46.useRef(null);
9141
+ const serverCount = React46.useRef(0);
9142
+ const threadRef = React46.useRef(null);
9143
+ const mounted = React46.useRef(true);
9144
+ React46.useEffect(() => {
9146
9145
  mounted.current = true;
9147
9146
  return () => {
9148
9147
  mounted.current = false;
@@ -9164,14 +9163,14 @@ function useChatEngine(opts) {
9164
9163
  }
9165
9164
  return false;
9166
9165
  };
9167
- const loadThread = React45.useCallback(async (id) => {
9166
+ const loadThread = React46.useCallback(async (id) => {
9168
9167
  const data = await apiAdapter.getThread(id);
9169
9168
  const list = [...data && data.messages || []];
9170
9169
  serverCount.current = list.length;
9171
9170
  commit(list);
9172
9171
  return list;
9173
9172
  }, [apiAdapter]);
9174
- React45.useEffect(() => {
9173
+ React46.useEffect(() => {
9175
9174
  if (!apiAdapter) {
9176
9175
  setStatus("idle");
9177
9176
  setFatal(null);
@@ -9384,7 +9383,7 @@ function useChatEngine(opts) {
9384
9383
  await dispatchTurn(turn);
9385
9384
  }
9386
9385
  }
9387
- const send = React45.useCallback((text, attachments) => {
9386
+ const send = React46.useCallback((text, attachments) => {
9388
9387
  const body = (text || "").trim();
9389
9388
  if (!body && !(attachments && attachments.length)) return;
9390
9389
  if (status === "disconnected") return;
@@ -9394,7 +9393,7 @@ function useChatEngine(opts) {
9394
9393
  stoppedRef.current = false;
9395
9394
  drain();
9396
9395
  }, [status]);
9397
- const stop = React45.useCallback(() => {
9396
+ const stop = React46.useCallback(() => {
9398
9397
  stoppedRef.current = true;
9399
9398
  const ac = abortRef.current;
9400
9399
  if (ac) {
@@ -9413,11 +9412,11 @@ function useChatEngine(opts) {
9413
9412
  store.del(STORAGE_PREFIX + threadRef.current);
9414
9413
  }
9415
9414
  }, [apiAdapter]);
9416
- const removeQueued = React45.useCallback((id) => {
9415
+ const removeQueued = React46.useCallback((id) => {
9417
9416
  queueRef.current = queueRef.current.filter((t) => t.id !== id);
9418
9417
  setQueue(queueRef.current.slice());
9419
9418
  }, []);
9420
- const retry = React45.useCallback(() => {
9419
+ const retry = React46.useCallback(() => {
9421
9420
  const list = listRef.current;
9422
9421
  let at = -1;
9423
9422
  for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
@@ -9433,19 +9432,19 @@ function useChatEngine(opts) {
9433
9432
  setQueue(queueRef.current.slice());
9434
9433
  drain();
9435
9434
  }, []);
9436
- const clear = React45.useCallback(() => {
9435
+ const clear = React46.useCallback(() => {
9437
9436
  commit([]);
9438
9437
  serverCount.current = 0;
9439
9438
  queueRef.current = [];
9440
9439
  setQueue([]);
9441
9440
  onClear && onClear();
9442
9441
  }, [onClear]);
9443
- const setFeedback = React45.useCallback((id, value) => {
9442
+ const setFeedback = React46.useCallback((id, value) => {
9444
9443
  patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
9445
9444
  const msg = listRef.current.find((m) => m.id === id);
9446
9445
  onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
9447
9446
  }, [onFeedback]);
9448
- const reload = React45.useCallback(async () => {
9447
+ const reload = React46.useCallback(async () => {
9449
9448
  if (!threadRef.current) return;
9450
9449
  setStatus("loading");
9451
9450
  try {
@@ -9483,10 +9482,10 @@ var ChatKit = {
9483
9482
  };
9484
9483
 
9485
9484
  // src/components/chat/ChatTranscript.tsx
9486
- import * as React47 from "react";
9485
+ import * as React48 from "react";
9487
9486
 
9488
9487
  // src/components/chat/ChatTurn.tsx
9489
- import * as React46 from "react";
9488
+ import * as React47 from "react";
9490
9489
  import { jsx as jsx74, jsxs as jsxs70 } from "react/jsx-runtime";
9491
9490
  function JsonView({ value }) {
9492
9491
  let text;
@@ -9523,7 +9522,7 @@ function PacketCard({ packet, schema, render, onApply, applied }) {
9523
9522
  ] });
9524
9523
  }
9525
9524
  function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
9526
- const [open, setOpen] = React46.useState(defaultOpen);
9525
+ const [open, setOpen] = React47.useState(defaultOpen);
9527
9526
  if (!text) return null;
9528
9527
  return /* @__PURE__ */ jsxs70("div", { className: "fdc-think" + (open ? " is-open" : ""), children: [
9529
9528
  /* @__PURE__ */ jsxs70("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
@@ -9540,7 +9539,7 @@ function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
9540
9539
  ] });
9541
9540
  }
9542
9541
  function Citations({ items = [], onOpen }) {
9543
- const [open, setOpen] = React46.useState(false);
9542
+ const [open, setOpen] = React47.useState(false);
9544
9543
  if (!items.length) return null;
9545
9544
  return /* @__PURE__ */ jsxs70("div", { className: "fdc-cites", children: [
9546
9545
  /* @__PURE__ */ jsxs70("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
@@ -9566,7 +9565,7 @@ function clampText(text, max) {
9566
9565
  return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
9567
9566
  }
9568
9567
  function MessageBody({ message: m, ctx }) {
9569
- const [expanded, setExpanded] = React46.useState(false);
9568
+ const [expanded, setExpanded] = React47.useState(false);
9570
9569
  const isUser = m.role === "user";
9571
9570
  const raw = m.text || "";
9572
9571
  const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
@@ -9633,9 +9632,9 @@ function MessageBody({ message: m, ctx }) {
9633
9632
  ] });
9634
9633
  }
9635
9634
  function useCopyRun() {
9636
- const [done, setDone] = React46.useState(false);
9637
- const t = React46.useRef(null);
9638
- React46.useEffect(() => () => {
9635
+ const [done, setDone] = React47.useState(false);
9636
+ const t = React47.useRef(null);
9637
+ React47.useEffect(() => () => {
9639
9638
  if (t.current) clearTimeout(t.current);
9640
9639
  }, []);
9641
9640
  return [done, (text) => {
@@ -9662,7 +9661,7 @@ function RunActions({ group, ctx }) {
9662
9661
  ] }),
9663
9662
  isAssistant && ctx.onRetry ? /* @__PURE__ */ jsx74("button", { type: "button", className: "fdc-act", onClick: ctx.onRetry, "aria-label": "Retry this turn", children: /* @__PURE__ */ jsx74("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
9664
9663
  group.role === "user" && ctx.onEdit ? /* @__PURE__ */ jsx74("button", { type: "button", className: "fdc-act", onClick: () => ctx.onEdit(last), "aria-label": "Edit and resend", children: /* @__PURE__ */ jsx74("i", { className: "ph ph-pencil-simple", "aria-hidden": "true" }) }) : null,
9665
- isAssistant && ctx.onFeedback ? /* @__PURE__ */ jsxs70(React46.Fragment, { children: [
9664
+ isAssistant && ctx.onFeedback ? /* @__PURE__ */ jsxs70(React47.Fragment, { children: [
9666
9665
  /* @__PURE__ */ jsx74("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__ */ jsx74("i", { className: "ph ph-thumbs-up", "aria-hidden": "true" }) }),
9667
9666
  /* @__PURE__ */ jsx74("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__ */ jsx74("i", { className: "ph ph-thumbs-down", "aria-hidden": "true" }) })
9668
9667
  ] }) : null,
@@ -9757,10 +9756,10 @@ function ChatTranscript({
9757
9756
  renderEmpty,
9758
9757
  className = ""
9759
9758
  }) {
9760
- const scroller = React47.useRef(null);
9761
- const stick = React47.useRef(true);
9762
- const [pill, setPill] = React47.useState(0);
9763
- const seen = React47.useRef(0);
9759
+ const scroller = React48.useRef(null);
9760
+ const stick = React48.useRef(true);
9761
+ const [pill, setPill] = React48.useState(0);
9762
+ const seen = React48.useRef(0);
9764
9763
  const toBottom = (smooth) => {
9765
9764
  const el = scroller.current;
9766
9765
  if (!el) return;
@@ -9779,7 +9778,7 @@ function ChatTranscript({
9779
9778
  seen.current = messages.length;
9780
9779
  }
9781
9780
  };
9782
- React47.useLayoutEffect(() => {
9781
+ React48.useLayoutEffect(() => {
9783
9782
  const el = scroller.current;
9784
9783
  if (!el) return;
9785
9784
  if (stick.current) {
@@ -9787,7 +9786,7 @@ function ChatTranscript({
9787
9786
  seen.current = messages.length;
9788
9787
  } else setPill(Math.max(0, messages.length - seen.current));
9789
9788
  }, [messages]);
9790
- React47.useEffect(() => {
9789
+ React48.useEffect(() => {
9791
9790
  const el = scroller.current;
9792
9791
  const inner = el && el.firstChild;
9793
9792
  if (!el || !inner || typeof ResizeObserver === "undefined") return;
@@ -9797,7 +9796,7 @@ function ChatTranscript({
9797
9796
  ro.observe(inner);
9798
9797
  return () => ro.disconnect();
9799
9798
  }, []);
9800
- const groups = React47.useMemo(() => groupMessages(messages), [messages]);
9799
+ const groups = React48.useMemo(() => groupMessages(messages), [messages]);
9801
9800
  const empty = !messages.length && status === "ready";
9802
9801
  return /* @__PURE__ */ jsxs71("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
9803
9802
  /* @__PURE__ */ jsxs71("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
@@ -9821,7 +9820,7 @@ function ChatTranscript({
9821
9820
  const prev = groups[i - 1];
9822
9821
  const k = dayKey(g.messages[0].timestamp);
9823
9822
  const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
9824
- return /* @__PURE__ */ jsxs71(React47.Fragment, { children: [
9823
+ return /* @__PURE__ */ jsxs71(React48.Fragment, { children: [
9825
9824
  showDay ? /* @__PURE__ */ jsx75("div", { className: "fdc-day", children: /* @__PURE__ */ jsx75("span", { children: dayLabel(k) }) }) : null,
9826
9825
  /* @__PURE__ */ jsx75(ChatTurn, { group: g, ctx })
9827
9826
  ] }, g.key || i);
@@ -9838,7 +9837,7 @@ function ChatTranscript({
9838
9837
  var TranscriptKit = { groupMessages };
9839
9838
 
9840
9839
  // src/components/chat/ChatComposer.tsx
9841
- import * as React48 from "react";
9840
+ import * as React49 from "react";
9842
9841
  import { jsx as jsx76, jsxs as jsxs72 } from "react/jsx-runtime";
9843
9842
  function ChatComposer({
9844
9843
  onSubmit,
@@ -9866,17 +9865,17 @@ function ChatComposer({
9866
9865
  onReject,
9867
9866
  onOpenAttachment
9868
9867
  }) {
9869
- const [text, setText] = React48.useState(draft || "");
9870
- const [trigger, setTrigger] = React48.useState(null);
9871
- const [mentionItems, setMentionItems] = React48.useState([]);
9872
- const [listening, setListening] = React48.useState(false);
9873
- const [notice, setNotice] = React48.useState(null);
9874
- const editor = React48.useRef(null);
9875
- const wrap = React48.useRef(null);
9876
- const stopVoice = React48.useRef(null);
9868
+ const [text, setText] = React49.useState(draft || "");
9869
+ const [trigger, setTrigger] = React49.useState(null);
9870
+ const [mentionItems, setMentionItems] = React49.useState([]);
9871
+ const [listening, setListening] = React49.useState(false);
9872
+ const [notice, setNotice] = React49.useState(null);
9873
+ const editor = React49.useRef(null);
9874
+ const wrap = React49.useRef(null);
9875
+ const stopVoice = React49.useRef(null);
9877
9876
  const staged = useStagedFiles(fileUploadHandler, { onError: () => {
9878
9877
  } });
9879
- React48.useEffect(() => {
9878
+ React49.useEffect(() => {
9880
9879
  if (draft != null && draft !== text) setText(draft);
9881
9880
  }, [draft]);
9882
9881
  const change = (v) => {
@@ -9912,7 +9911,7 @@ function ChatComposer({
9912
9911
  e.preventDefault();
9913
9912
  staged.add(found.files);
9914
9913
  };
9915
- React48.useEffect(() => {
9914
+ React49.useEffect(() => {
9916
9915
  if (!trigger || trigger.type !== "mention" || !mentionSources) {
9917
9916
  setMentionItems([]);
9918
9917
  return;
@@ -9930,7 +9929,7 @@ function ChatComposer({
9930
9929
  const q = (trigger.query || "").toLowerCase();
9931
9930
  setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
9932
9931
  }, [trigger, mentionSources]);
9933
- const slashItems = React48.useMemo(() => {
9932
+ const slashItems = React49.useMemo(() => {
9934
9933
  if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
9935
9934
  const q = (trigger.query || "").toLowerCase();
9936
9935
  return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
@@ -10104,12 +10103,12 @@ function ChatComposer({
10104
10103
  }
10105
10104
 
10106
10105
  // src/components/chat/ChatSessionBar.tsx
10107
- import * as React49 from "react";
10106
+ import * as React50 from "react";
10108
10107
  import { jsx as jsx77, jsxs as jsxs73 } from "react/jsx-runtime";
10109
10108
  var compact2 = meterFormats.compact;
10110
10109
  function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
10111
- const [open, setOpen] = React49.useState(false);
10112
- const anchor = React49.useRef(null);
10110
+ const [open, setOpen] = React50.useState(false);
10111
+ const anchor = React50.useRef(null);
10113
10112
  const stats = sessionStats || null;
10114
10113
  const cu = contextUsage || null;
10115
10114
  const limits = usageLimits || null;
@@ -10124,7 +10123,7 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
10124
10123
  if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
10125
10124
  if (cu) bits.push(pct + "% context");
10126
10125
  const expandable = !!(cu || limits);
10127
- return /* @__PURE__ */ jsxs73(React49.Fragment, { children: [
10126
+ return /* @__PURE__ */ jsxs73(React50.Fragment, { children: [
10128
10127
  /* @__PURE__ */ jsxs73("div", { className: "fdc-bar", children: [
10129
10128
  /* @__PURE__ */ jsxs73(
10130
10129
  "button",
@@ -10265,7 +10264,7 @@ function ModelControls({
10265
10264
  ] })
10266
10265
  });
10267
10266
  }
10268
- return /* @__PURE__ */ jsxs73(React49.Fragment, { children: [
10267
+ return /* @__PURE__ */ jsxs73(React50.Fragment, { children: [
10269
10268
  /* @__PURE__ */ jsx77(
10270
10269
  MenuButton,
10271
10270
  {
@@ -10382,11 +10381,11 @@ function AgentChatPanel({
10382
10381
  onFeedback,
10383
10382
  onEditMessage
10384
10383
  }) {
10385
- const [panelWidth, setPanelWidth] = React50.useState(width);
10386
- const [applied, setApplied] = React50.useState({});
10387
- const [draft, setDraft] = React50.useState("");
10388
- const dragging = React50.useRef(null);
10389
- React50.useEffect(() => setPanelWidth(width), [width]);
10384
+ const [panelWidth, setPanelWidth] = React51.useState(width);
10385
+ const [applied, setApplied] = React51.useState({});
10386
+ const [draft, setDraft] = React51.useState("");
10387
+ const dragging = React51.useRef(null);
10388
+ React51.useEffect(() => setPanelWidth(width), [width]);
10390
10389
  const engine = useChatEngine({
10391
10390
  contextType,
10392
10391
  contextId,
@@ -10590,7 +10589,7 @@ function AgentChatPanel({
10590
10589
  }
10591
10590
 
10592
10591
  // src/components/files/FileViewer.tsx
10593
- import * as React51 from "react";
10592
+ import * as React52 from "react";
10594
10593
  import { jsx as jsx79, jsxs as jsxs75 } from "react/jsx-runtime";
10595
10594
  function previewKindOf(file) {
10596
10595
  const mime = (file.mime || "").toLowerCase();
@@ -10647,13 +10646,13 @@ function parseDelimited(text, delimiter) {
10647
10646
  return rows;
10648
10647
  }
10649
10648
  function usePreview(file, kind, resolveUrl) {
10650
- const [state, setState] = React51.useState({ status: "loading" });
10651
- const [attempt, setAttempt] = React51.useState(0);
10652
- const resolveRef = React51.useRef(resolveUrl);
10653
- React51.useEffect(() => {
10649
+ const [state, setState] = React52.useState({ status: "loading" });
10650
+ const [attempt, setAttempt] = React52.useState(0);
10651
+ const resolveRef = React52.useRef(resolveUrl);
10652
+ React52.useEffect(() => {
10654
10653
  resolveRef.current = resolveUrl;
10655
10654
  }, [resolveUrl]);
10656
- React51.useEffect(() => {
10655
+ React52.useEffect(() => {
10657
10656
  if (kind === "none") {
10658
10657
  setState({ status: "ready" });
10659
10658
  return;
@@ -10683,7 +10682,7 @@ function usePreview(file, kind, resolveUrl) {
10683
10682
  if (ac) ac.abort();
10684
10683
  };
10685
10684
  }, [file.id, kind, attempt]);
10686
- return { ...state, retry: React51.useCallback(() => setAttempt((a) => a + 1), []) };
10685
+ return { ...state, retry: React52.useCallback(() => setAttempt((a) => a + 1), []) };
10687
10686
  }
10688
10687
  function PreviewBody({ file, kind, state }) {
10689
10688
  if (kind === "image") return /* @__PURE__ */ jsx79("img", { className: "fd-fv-image", src: state.url, alt: file.name || "Preview" });
@@ -10728,13 +10727,13 @@ function PreviewBody({ file, kind, state }) {
10728
10727
  ] });
10729
10728
  }
10730
10729
  function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", onClose, actions, className = "" }) {
10731
- const kind = React51.useMemo(() => previewKindOf(file), [file]);
10730
+ const kind = React52.useMemo(() => previewKindOf(file), [file]);
10732
10731
  const preview = usePreview(file, kind, resolveUrl);
10733
- const [tab, setTab] = React51.useState("preview");
10734
- const [downloading, setDownloading] = React51.useState(false);
10735
- const [downloadError, setDownloadError] = React51.useState(null);
10732
+ const [tab, setTab] = React52.useState("preview");
10733
+ const [downloading, setDownloading] = React52.useState(false);
10734
+ const [downloadError, setDownloadError] = React52.useState(null);
10736
10735
  const hasSide = sidePanel != null;
10737
- React51.useEffect(() => {
10736
+ React52.useEffect(() => {
10738
10737
  setTab("preview");
10739
10738
  }, [file.id]);
10740
10739
  const download = () => {
@@ -10801,7 +10800,7 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
10801
10800
  }
10802
10801
 
10803
10802
  // src/components/files/FileBrowser.tsx
10804
- import * as React52 from "react";
10803
+ import * as React53 from "react";
10805
10804
  import { Fragment as Fragment25, jsx as jsx80, jsxs as jsxs76 } from "react/jsx-runtime";
10806
10805
  function childrenOf(folders, parentId) {
10807
10806
  return folders.filter((f) => f.parentId === parentId).sort((a, b) => a.name.localeCompare(b.name));
@@ -10872,10 +10871,10 @@ function FolderPickerMenu({
10872
10871
  destinations,
10873
10872
  onPick
10874
10873
  }) {
10875
- const [open, setOpen] = React52.useState(false);
10874
+ const [open, setOpen] = React53.useState(false);
10876
10875
  const zIndex = useOverlayLayer(open);
10877
- const ref = React52.useRef(null);
10878
- React52.useEffect(() => {
10876
+ const ref = React53.useRef(null);
10877
+ React53.useEffect(() => {
10879
10878
  if (!open) return;
10880
10879
  const away = (e) => {
10881
10880
  if (ref.current && !ref.current.contains(e.target)) setOpen(false);
@@ -10927,8 +10926,8 @@ function FolderPickerMenu({
10927
10926
  ] });
10928
10927
  }
10929
10928
  function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropPayload, actions, className = "" }) {
10930
- const [over, setOver] = React52.useState(false);
10931
- const dragCounter = React52.useRef(0);
10929
+ const [over, setOver] = React53.useState(false);
10930
+ const dragCounter = React53.useRef(0);
10932
10931
  const dropHandlers = isDropTarget ? {
10933
10932
  onDragEnter: (e) => {
10934
10933
  if (!hasInternalPayload(e)) return;
@@ -10976,8 +10975,8 @@ function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropP
10976
10975
  }
10977
10976
  function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveInto, canMove }) {
10978
10977
  const kids = childrenOf(folders, folder.id);
10979
- const [expanded, setExpanded] = React52.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
10980
- React52.useEffect(() => {
10978
+ const [expanded, setExpanded] = React53.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
10979
+ React53.useEffect(() => {
10981
10980
  if (currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId)) setExpanded(true);
10982
10981
  }, [currentFolderId, folder.id, folders]);
10983
10982
  const isCurrent = folder.id === currentFolderId;
@@ -11043,15 +11042,15 @@ function FileBrowser({
11043
11042
  const canUpload = perm.canUpload !== false && !!onUpload;
11044
11043
  const canRemoveFile = perm.canRemoveFile !== false && !!onRemoveFile;
11045
11044
  const canDeleteFolder = perm.canDeleteFolder !== false && !!onDeleteFolder;
11046
- const [createOpen, setCreateOpen] = React52.useState(false);
11047
- const [createName, setCreateName] = React52.useState("");
11048
- const [renameTarget, setRenameTarget] = React52.useState(null);
11049
- const [renameValue, setRenameValue] = React52.useState("");
11050
- const [deleteTarget, setDeleteTarget] = React52.useState(null);
11051
- const uploadInputRef = React52.useRef(null);
11052
- const crumbFolders = React52.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
11053
- const subfolders = React52.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
11054
- const currentFiles = React52.useMemo(
11045
+ const [createOpen, setCreateOpen] = React53.useState(false);
11046
+ const [createName, setCreateName] = React53.useState("");
11047
+ const [renameTarget, setRenameTarget] = React53.useState(null);
11048
+ const [renameValue, setRenameValue] = React53.useState("");
11049
+ const [deleteTarget, setDeleteTarget] = React53.useState(null);
11050
+ const uploadInputRef = React53.useRef(null);
11051
+ const crumbFolders = React53.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
11052
+ const subfolders = React53.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
11053
+ const currentFiles = React53.useMemo(
11055
11054
  () => files.filter((f) => f.folderId === currentFolderId).sort((a, b) => a.name.localeCompare(b.name)),
11056
11055
  [files, currentFolderId]
11057
11056
  );
@@ -11283,8 +11282,8 @@ function BreadcrumbCrumb({
11283
11282
  isDropTarget,
11284
11283
  onDropPayload
11285
11284
  }) {
11286
- const [over, setOver] = React52.useState(false);
11287
- const dragCounter = React52.useRef(0);
11285
+ const [over, setOver] = React53.useState(false);
11286
+ const dragCounter = React53.useRef(0);
11288
11287
  const dropHandlers = isDropTarget ? {
11289
11288
  onDragEnter: (e) => {
11290
11289
  if (!hasInternalPayload(e)) return;
@@ -11313,7 +11312,7 @@ function BreadcrumbCrumb({
11313
11312
  }
11314
11313
 
11315
11314
  // src/kits/query.ts
11316
- import * as React53 from "react";
11315
+ import * as React54 from "react";
11317
11316
  function eqFilter(get2) {
11318
11317
  return (row, value) => Array.isArray(value) ? value.includes(get2(row)) : get2(row) === value;
11319
11318
  }
@@ -11345,22 +11344,22 @@ function compare(a, b, dir) {
11345
11344
  var API = null;
11346
11345
  var PREFS = null;
11347
11346
  function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
11348
- const [query, setQuery] = React53.useState(() => {
11347
+ const [query, setQuery] = React54.useState(() => {
11349
11348
  const store = PREFS || window.PlannerPrefs;
11350
11349
  const saved = prefsKey && store ? store.getTable(prefsKey) : {};
11351
11350
  return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
11352
11351
  });
11353
- const savePref = React53.useCallback((patch2) => {
11352
+ const savePref = React54.useCallback((patch2) => {
11354
11353
  const store = PREFS || window.PlannerPrefs;
11355
11354
  if (prefsKey && store) store.setTable(prefsKey, patch2);
11356
11355
  }, [prefsKey]);
11357
- const [res, setRes] = React53.useState(null);
11358
- const [loading, setLoading] = React53.useState(true);
11359
- const seq2 = React53.useRef(0);
11356
+ const [res, setRes] = React54.useState(null);
11357
+ const [loading, setLoading] = React54.useState(true);
11358
+ const seq2 = React54.useRef(0);
11360
11359
  const depKey = (deps || []).join("|");
11361
11360
  const paramKey = JSON.stringify(params || {});
11362
11361
  const queryKey = JSON.stringify(query);
11363
- React53.useEffect(() => {
11362
+ React54.useEffect(() => {
11364
11363
  const id = ++seq2.current;
11365
11364
  setLoading(true);
11366
11365
  const t = setTimeout(() => {
@@ -11657,6 +11656,92 @@ function createVersionStore(initialState, options) {
11657
11656
  }
11658
11657
  };
11659
11658
  }
11659
+
11660
+ // src/kits/useResponsiveRail.ts
11661
+ import * as React55 from "react";
11662
+ function matchesBreakpoint(breakpoint) {
11663
+ return typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia(`(max-width: ${breakpoint}px)`).matches;
11664
+ }
11665
+ var FOCUSABLE_SELECTOR = 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';
11666
+ function getFocusable(container) {
11667
+ return Array.from(container.querySelectorAll(FOCUSABLE_SELECTOR));
11668
+ }
11669
+ function useResponsiveRail(options = {}) {
11670
+ const { breakpoint = 1024, initialOpen = true, onPersist } = options;
11671
+ const navRef = React55.useRef(null);
11672
+ const [overlay, setOverlay] = React55.useState(() => matchesBreakpoint(breakpoint));
11673
+ const [open, setOpenRaw] = React55.useState(() => matchesBreakpoint(breakpoint) ? false : initialOpen);
11674
+ const setOpen = React55.useCallback(
11675
+ (value) => {
11676
+ setOpenRaw(value);
11677
+ if (!matchesBreakpoint(breakpoint)) onPersist?.(value);
11678
+ },
11679
+ [breakpoint, onPersist]
11680
+ );
11681
+ const toggle = React55.useCallback(() => setOpen(!open), [open, setOpen]);
11682
+ const close = React55.useCallback(() => setOpenRaw(false), []);
11683
+ React55.useEffect(() => {
11684
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
11685
+ const mq = window.matchMedia(`(max-width: ${breakpoint}px)`);
11686
+ const handler = (e) => {
11687
+ setOverlay(e.matches);
11688
+ setOpenRaw(!e.matches);
11689
+ };
11690
+ mq.addEventListener("change", handler);
11691
+ return () => mq.removeEventListener("change", handler);
11692
+ }, [breakpoint]);
11693
+ React55.useEffect(() => {
11694
+ if (!overlay || !open) return;
11695
+ const handler = (e) => {
11696
+ if (e.key === "Escape") close();
11697
+ };
11698
+ document.addEventListener("keydown", handler);
11699
+ return () => document.removeEventListener("keydown", handler);
11700
+ }, [overlay, open, close]);
11701
+ React55.useEffect(() => {
11702
+ if (!overlay || !open) return;
11703
+ const previousOverflow = document.body.style.overflow;
11704
+ document.body.style.overflow = "hidden";
11705
+ return () => {
11706
+ document.body.style.overflow = previousOverflow;
11707
+ };
11708
+ }, [overlay, open]);
11709
+ React55.useEffect(() => {
11710
+ if (!overlay || !open) return;
11711
+ const container = navRef.current;
11712
+ if (!container) return;
11713
+ const previouslyFocused = document.activeElement;
11714
+ const focusable = getFocusable(container);
11715
+ (focusable[0] ?? container).focus();
11716
+ const handler = (e) => {
11717
+ if (e.key !== "Tab") return;
11718
+ const items = getFocusable(container);
11719
+ if (items.length === 0) {
11720
+ e.preventDefault();
11721
+ return;
11722
+ }
11723
+ const first = items[0];
11724
+ const last = items[items.length - 1];
11725
+ const active = document.activeElement;
11726
+ const outside = !(active instanceof Node) || !container.contains(active);
11727
+ if (e.shiftKey) {
11728
+ if (outside || active === first) {
11729
+ e.preventDefault();
11730
+ last.focus();
11731
+ }
11732
+ } else if (outside || active === last) {
11733
+ e.preventDefault();
11734
+ first.focus();
11735
+ }
11736
+ };
11737
+ document.addEventListener("keydown", handler);
11738
+ return () => {
11739
+ document.removeEventListener("keydown", handler);
11740
+ previouslyFocused?.focus?.();
11741
+ };
11742
+ }, [overlay, open]);
11743
+ return { open, overlay, navRef, toggle, close, setOpen };
11744
+ }
11660
11745
  export {
11661
11746
  AccountMenu,
11662
11747
  AgentChatPanel,
@@ -11840,6 +11925,7 @@ export {
11840
11925
  useChatEngine,
11841
11926
  useFeatureStatus,
11842
11927
  usePopoverPosition,
11928
+ useResponsiveRail,
11843
11929
  useRuntimeMode,
11844
11930
  useServerTable,
11845
11931
  useSessionContext,