@flytedan/flytebot-design-system 0.12.5 → 0.12.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -185,6 +185,7 @@ __export(index_exports, {
185
185
  meterFormats: () => meterFormats,
186
186
  modifierLabel: () => modifierLabel,
187
187
  pastedTextName: () => pastedTextName,
188
+ pluralizeUnit: () => pluralizeUnit,
188
189
  preferenceScore: () => preferenceScore,
189
190
  preferenceSegments: () => preferenceSegments,
190
191
  rangeFilter: () => rangeFilter,
@@ -253,6 +254,11 @@ function Button({
253
254
  );
254
255
  }
255
256
 
257
+ // src/components/actions/overflowRowContext.ts
258
+ var React = __toESM(require("react"), 1);
259
+ var OverflowRowContext = React.createContext(false);
260
+ var useOverflowRow = () => React.useContext(OverflowRowContext);
261
+
256
262
  // src/components/actions/IconButton.tsx
257
263
  var import_jsx_runtime2 = require("react/jsx-runtime");
258
264
  function IconButton({
@@ -266,19 +272,24 @@ function IconButton({
266
272
  className = "",
267
273
  ...rest
268
274
  }) {
275
+ const overflowRow = useOverflowRow();
269
276
  const cls = [
270
277
  "fd-btn-icon",
271
278
  variant === "outline" ? "fd-btn-icon-outline" : variant === "solid" ? "fd-btn-icon-solid" : "",
272
279
  tone !== "neutral" ? "is-" + tone : "",
273
280
  size === "sm" ? "fd-btn-icon-sm" : size === "lg" ? "fd-btn-icon-lg" : "",
274
281
  round ? "fd-btn-icon-round" : "",
282
+ overflowRow ? "fd-btn-icon-row" : "",
275
283
  className
276
284
  ].filter(Boolean).join(" ");
277
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: cls, "aria-label": label, title: label, disabled, ...rest, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", { className: "ph ph-" + icon, "aria-hidden": "true" }) });
285
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { type: "button", className: cls, "aria-label": label, title: label, disabled, ...rest, children: [
286
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", { className: "ph ph-" + icon, "aria-hidden": "true" }),
287
+ overflowRow ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "fd-btn-icon-row-label", children: label }) : null
288
+ ] });
278
289
  }
279
290
 
280
291
  // src/components/actions/Popover.tsx
281
- var React = __toESM(require("react"), 1);
292
+ var React2 = __toESM(require("react"), 1);
282
293
  var import_react_dom = require("react-dom");
283
294
  var import_jsx_runtime3 = require("react/jsx-runtime");
284
295
  var MARGIN = 8;
@@ -310,12 +321,12 @@ function measureLayer(el) {
310
321
  function usePopoverPosition(open, anchorRef, opts) {
311
322
  const o = opts || {};
312
323
  const { side: wantSide, align } = parsePlacement(o.placement);
313
- const [pos, setPos] = React.useState(null);
314
- const posRef = React.useRef(null);
315
- const detachRef = React.useRef(o.onDetach);
324
+ const [pos, setPos] = React2.useState(null);
325
+ const posRef = React2.useRef(null);
326
+ const detachRef = React2.useRef(o.onDetach);
316
327
  detachRef.current = o.onDetach;
317
328
  const layerRef = o.layerRef;
318
- React.useLayoutEffect(() => {
329
+ React2.useLayoutEffect(() => {
319
330
  if (!open || !anchorRef || !anchorRef.current) {
320
331
  posRef.current = null;
321
332
  setPos(null);
@@ -390,8 +401,8 @@ var portal = (node) => {
390
401
  };
391
402
  var ROOT_LAYER = 0;
392
403
  var LAYER_STEP = 10;
393
- var LayerContext = React.createContext(ROOT_LAYER);
394
- var useLayer = () => React.useContext(LayerContext);
404
+ var LayerContext = React2.createContext(ROOT_LAYER);
405
+ var useLayer = () => React2.useContext(LayerContext);
395
406
  var useOverlayLayer = (base) => {
396
407
  const parent = useLayer();
397
408
  return parent === ROOT_LAYER ? base : parent + LAYER_STEP;
@@ -421,7 +432,7 @@ function Popover({
421
432
  footer,
422
433
  children
423
434
  }) {
424
- const ref = React.useRef(null);
435
+ const ref = React2.useRef(null);
425
436
  const pos = usePopoverPosition(!!open, anchorRef, {
426
437
  placement,
427
438
  offset,
@@ -433,9 +444,9 @@ function Popover({
433
444
  onDetach: onClose,
434
445
  layerRef: ref
435
446
  });
436
- const restore = React.useRef(null);
447
+ const restore = React2.useRef(null);
437
448
  const zIndex = useOverlayLayer(POPOVER_BASE);
438
- React.useEffect(() => {
449
+ React2.useEffect(() => {
439
450
  if (!open) return;
440
451
  restore.current = typeof document !== "undefined" ? document.activeElement : null;
441
452
  return () => {
@@ -447,7 +458,7 @@ function Popover({
447
458
  }
448
459
  };
449
460
  }, [open, returnFocus]);
450
- React.useEffect(() => {
461
+ React2.useEffect(() => {
451
462
  if (!open) return;
452
463
  const away = (e) => {
453
464
  if (!closeOnOutside) return;
@@ -521,12 +532,12 @@ function Popover({
521
532
  }
522
533
  var isItem = (it) => !!it && it.kind !== "separator" && it.kind !== "section" && it.kind !== "custom" && !it.disabled;
523
534
  function Menu({ items = [], onSelect, onClose, autoFocus = true, className = "", footer, header }) {
524
- const listRef = React.useRef(null);
525
- const [active, setActive] = React.useState(() => items.findIndex(isItem));
526
- const [openSub, setOpenSub] = React.useState(null);
527
- const subAnchor = React.useRef(null);
528
- const typed = React.useRef({ s: "", t: 0 });
529
- React.useEffect(() => {
535
+ const listRef = React2.useRef(null);
536
+ const [active, setActive] = React2.useState(() => items.findIndex(isItem));
537
+ const [openSub, setOpenSub] = React2.useState(null);
538
+ const subAnchor = React2.useRef(null);
539
+ const typed = React2.useRef({ s: "", t: 0 });
540
+ React2.useEffect(() => {
530
541
  if (autoFocus && listRef.current) listRef.current.focus({ preventScroll: true });
531
542
  }, [autoFocus]);
532
543
  const move = (dir) => {
@@ -588,7 +599,7 @@ function Menu({ items = [], onSelect, onClose, autoFocus = true, className = "",
588
599
  }
589
600
  };
590
601
  const sub = openSub != null ? items[openSub] : null;
591
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(React.Fragment, { children: [
602
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(React2.Fragment, { children: [
592
603
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "fd-menu-frame", children: [
593
604
  header != null ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "fd-menu-header", children: header }) : null,
594
605
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
@@ -702,9 +713,9 @@ function MenuButton({
702
713
  header,
703
714
  footer
704
715
  }) {
705
- const [open, setOpen] = React.useState(false);
706
- const ref = React.useRef(null);
707
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(React.Fragment, { children: [
716
+ const [open, setOpen] = React2.useState(false);
717
+ const ref = React2.useRef(null);
718
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(React2.Fragment, { children: [
708
719
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
709
720
  "button",
710
721
  {
@@ -797,7 +808,7 @@ function CardRow({ label, children, className = "" }) {
797
808
  }
798
809
 
799
810
  // src/components/surfaces/Collapsible.tsx
800
- var React2 = __toESM(require("react"), 1);
811
+ var React3 = __toESM(require("react"), 1);
801
812
  var import_jsx_runtime6 = require("react/jsx-runtime");
802
813
  function Collapsible({
803
814
  title,
@@ -811,7 +822,7 @@ function Collapsible({
811
822
  className = "",
812
823
  ...rest
813
824
  }) {
814
- const [internal, setInternal] = React2.useState(defaultOpen);
825
+ const [internal, setInternal] = React3.useState(defaultOpen);
815
826
  const isOpen = open === void 0 ? internal : open;
816
827
  const toggle = () => {
817
828
  if (open === void 0) setInternal(!isOpen);
@@ -832,19 +843,19 @@ function Collapsible({
832
843
  }
833
844
 
834
845
  // src/components/surfaces/Drawer.tsx
835
- var React3 = __toESM(require("react"), 1);
846
+ var React4 = __toESM(require("react"), 1);
836
847
  var import_react_dom2 = require("react-dom");
837
848
  var import_jsx_runtime7 = require("react/jsx-runtime");
838
849
  var DRAWER_BASE = 90;
839
850
  function Drawer({ open = true, title, onClose, footer, children, className = "", ...rest }) {
840
851
  const zIndex = useOverlayLayer(DRAWER_BASE);
841
- const [closing, setClosing] = React3.useState(false);
842
- const close = React3.useCallback(() => {
852
+ const [closing, setClosing] = React4.useState(false);
853
+ const close = React4.useCallback(() => {
843
854
  if (!onClose) return;
844
855
  setClosing(true);
845
856
  setTimeout(onClose, 210);
846
857
  }, [onClose]);
847
- React3.useEffect(() => {
858
+ React4.useEffect(() => {
848
859
  if (!open || !onClose) return;
849
860
  const h = (e) => {
850
861
  if (e.key === "Escape") close();
@@ -870,17 +881,17 @@ function Drawer({ open = true, title, onClose, footer, children, className = "",
870
881
  }
871
882
 
872
883
  // src/components/surfaces/Modal.tsx
873
- var React4 = __toESM(require("react"), 1);
884
+ var React5 = __toESM(require("react"), 1);
874
885
  var import_react_dom3 = require("react-dom");
875
886
  var import_jsx_runtime8 = require("react/jsx-runtime");
876
887
  function Modal({ open = true, title, description, onClose, footer, wide = false, children, className = "", ...rest }) {
877
- const [closing, setClosing] = React4.useState(false);
878
- const close = React4.useCallback(() => {
888
+ const [closing, setClosing] = React5.useState(false);
889
+ const close = React5.useCallback(() => {
879
890
  if (!onClose) return;
880
891
  setClosing(true);
881
892
  setTimeout(onClose, 190);
882
893
  }, [onClose]);
883
- React4.useEffect(() => {
894
+ React5.useEffect(() => {
884
895
  if (!open || !onClose) return;
885
896
  const h = (e) => {
886
897
  if (e.key === "Escape") close();
@@ -1107,13 +1118,13 @@ function Tabs({ tabs = [], value, onChange, className = "", ...rest }) {
1107
1118
  }
1108
1119
 
1109
1120
  // src/components/navigation/Topbar.tsx
1110
- var React5 = __toESM(require("react"), 1);
1121
+ var React6 = __toESM(require("react"), 1);
1111
1122
  var import_jsx_runtime16 = require("react/jsx-runtime");
1112
1123
  function useIsNarrow(breakpoint) {
1113
- const [narrow, setNarrow] = React5.useState(
1124
+ const [narrow, setNarrow] = React6.useState(
1114
1125
  () => typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia(`(max-width: ${breakpoint}px)`).matches
1115
1126
  );
1116
- React5.useEffect(() => {
1127
+ React6.useEffect(() => {
1117
1128
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
1118
1129
  const mq = window.matchMedia(`(max-width: ${breakpoint}px)`);
1119
1130
  const apply = () => setNarrow(mq.matches);
@@ -1134,11 +1145,11 @@ function Topbar({
1134
1145
  ...rest
1135
1146
  }) {
1136
1147
  const narrow = useIsNarrow(overflowBreakpoint);
1137
- const [moreOpen, setMoreOpen] = React5.useState(false);
1138
- const moreRef = React5.useRef(null);
1148
+ const [moreOpen, setMoreOpen] = React6.useState(false);
1149
+ const moreRef = React6.useRef(null);
1139
1150
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("header", { className: ["fd-topbar", narrow ? "is-narrow" : "", className].filter(Boolean).join(" "), ...rest, children: [
1140
1151
  onMenu ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", className: "fd-btn-icon", "aria-label": "Menu", onClick: onMenu, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("i", { className: "ph ph-list" }) }) : null,
1141
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("nav", { className: "fd-crumb", "aria-label": "Breadcrumb", children: crumbs.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(React5.Fragment, { children: [
1152
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("nav", { className: "fd-crumb", "aria-label": "Breadcrumb", children: crumbs.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(React6.Fragment, { children: [
1142
1153
  i > 0 ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("i", { className: "ph ph-caret-right", style: { fontSize: 11, opacity: 0.6 }, "aria-hidden": "true" }) : null,
1143
1154
  i === crumbs.length - 1 ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "fd-crumb-current", children: c.label }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1144
1155
  "a",
@@ -1177,7 +1188,7 @@ function Topbar({
1177
1188
  padded: true,
1178
1189
  label: "More actions",
1179
1190
  className: "fd-topbar-overflow",
1180
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "fd-stack fd-topbar-overflow-list", children: overflowActions })
1191
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "fd-stack fd-topbar-overflow-list", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(OverflowRowContext.Provider, { value: true, children: overflowActions }) })
1181
1192
  }
1182
1193
  )
1183
1194
  ] }) : overflowActions : null,
@@ -1343,19 +1354,19 @@ function Toast({ title, children, tone = "success", onUndo, onDismiss, className
1343
1354
  }
1344
1355
 
1345
1356
  // src/components/feedback/Tooltip.tsx
1346
- var React6 = __toESM(require("react"), 1);
1357
+ var React7 = __toESM(require("react"), 1);
1347
1358
  var import_jsx_runtime24 = require("react/jsx-runtime");
1348
1359
  var TOOLTIP_BASE = 150;
1349
1360
  var CLOSE_DELAY_MS = 120;
1350
1361
  function Tooltip({ label, placement = "top", children, className = "" }) {
1351
- const anchorRef = React6.useRef(null);
1352
- const bubbleRef = React6.useRef(null);
1353
- const [reason, setReason] = React6.useState(null);
1354
- const closeTimer = React6.useRef(null);
1355
- const id = React6.useId();
1362
+ const anchorRef = React7.useRef(null);
1363
+ const bubbleRef = React7.useRef(null);
1364
+ const [reason, setReason] = React7.useState(null);
1365
+ const closeTimer = React7.useRef(null);
1366
+ const id = React7.useId();
1356
1367
  const descId = id + "-desc";
1357
1368
  const open = reason != null;
1358
- const cancelClose = React6.useCallback(() => {
1369
+ const cancelClose = React7.useCallback(() => {
1359
1370
  if (closeTimer.current) {
1360
1371
  clearTimeout(closeTimer.current);
1361
1372
  closeTimer.current = null;
@@ -1365,7 +1376,7 @@ function Tooltip({ label, placement = "top", children, className = "" }) {
1365
1376
  cancelClose();
1366
1377
  setReason(why);
1367
1378
  };
1368
- const hide = React6.useCallback(() => {
1379
+ const hide = React7.useCallback(() => {
1369
1380
  cancelClose();
1370
1381
  setReason(null);
1371
1382
  }, [cancelClose]);
@@ -1380,7 +1391,7 @@ function Tooltip({ label, placement = "top", children, className = "" }) {
1380
1391
  setReason((r) => r === "hover" ? null : r);
1381
1392
  }, CLOSE_DELAY_MS);
1382
1393
  };
1383
- React6.useEffect(() => cancelClose, [cancelClose]);
1394
+ React7.useEffect(() => cancelClose, [cancelClose]);
1384
1395
  const pos = usePopoverPosition(open, anchorRef, {
1385
1396
  placement: placement === "bottom" ? "bottom-center" : "top-center",
1386
1397
  offset: 8,
@@ -1390,7 +1401,7 @@ function Tooltip({ label, placement = "top", children, className = "" }) {
1390
1401
  onDetach: hide
1391
1402
  });
1392
1403
  const zIndex = useOverlayLayer(TOOLTIP_BASE);
1393
- React6.useEffect(() => {
1404
+ React7.useEffect(() => {
1394
1405
  if (!open) return;
1395
1406
  const key = (e) => {
1396
1407
  if (e.key === "Escape") hide();
@@ -1418,7 +1429,7 @@ function Tooltip({ label, placement = "top", children, className = "" }) {
1418
1429
  }
1419
1430
  if (keyboard) show("focus");
1420
1431
  };
1421
- const described = React6.isValidElement(children) ? React6.cloneElement(children, {
1432
+ const described = React7.isValidElement(children) ? React7.cloneElement(children, {
1422
1433
  "aria-describedby": [children.props["aria-describedby"], descId].filter(Boolean).join(" ")
1423
1434
  }) : children;
1424
1435
  return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
@@ -1426,7 +1437,7 @@ function Tooltip({ label, placement = "top", children, className = "" }) {
1426
1437
  {
1427
1438
  ref: anchorRef,
1428
1439
  className: "fd-tooltip-anchor",
1429
- "aria-describedby": React6.isValidElement(children) ? void 0 : descId,
1440
+ "aria-describedby": React7.isValidElement(children) ? void 0 : descId,
1430
1441
  onPointerEnter: (e) => {
1431
1442
  if (isMouse(e)) hover();
1432
1443
  },
@@ -1470,7 +1481,7 @@ function Tooltip({ label, placement = "top", children, className = "" }) {
1470
1481
  }
1471
1482
 
1472
1483
  // src/components/data/Clamp.tsx
1473
- var React7 = __toESM(require("react"), 1);
1484
+ var React8 = __toESM(require("react"), 1);
1474
1485
  var import_jsx_runtime25 = require("react/jsx-runtime");
1475
1486
  function Clamp({
1476
1487
  children,
@@ -1482,16 +1493,16 @@ function Clamp({
1482
1493
  onToggle,
1483
1494
  className = ""
1484
1495
  }) {
1485
- const [open, setOpen] = React7.useState(false);
1486
- const [overflows, setOverflows] = React7.useState(false);
1487
- const bodyRef = React7.useRef(null);
1488
- const charClamped = React7.useMemo(() => {
1496
+ const [open, setOpen] = React8.useState(false);
1497
+ const [overflows, setOverflows] = React8.useState(false);
1498
+ const bodyRef = React8.useRef(null);
1499
+ const charClamped = React8.useMemo(() => {
1489
1500
  if (open || !maxChars || typeof text !== "string" || text.length <= maxChars) return null;
1490
1501
  const cut = text.slice(0, maxChars);
1491
1502
  const at = cut.lastIndexOf(" ");
1492
1503
  return (at > maxChars * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
1493
1504
  }, [text, maxChars, open]);
1494
- React7.useLayoutEffect(() => {
1505
+ React8.useLayoutEffect(() => {
1495
1506
  const node = bodyRef.current;
1496
1507
  if (maxChars || !node || !maxHeight) return;
1497
1508
  const measure = () => {
@@ -1630,19 +1641,19 @@ function DataTable({
1630
1641
  }
1631
1642
 
1632
1643
  // src/components/data/FilterBar.tsx
1633
- var React8 = __toESM(require("react"), 1);
1644
+ var React9 = __toESM(require("react"), 1);
1634
1645
  var import_jsx_runtime28 = require("react/jsx-runtime");
1635
1646
  var FILTER_BAR_BASE = 120;
1636
1647
  var isSet = (v) => !(v == null || v === "" || v === false);
1637
1648
  function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align = "left", className = "", ...rest }) {
1638
- const [panel, setPanel] = React8.useState(null);
1649
+ const [panel, setPanel] = React9.useState(null);
1639
1650
  const zIndex = useOverlayLayer(FILTER_BAR_BASE);
1640
- const rootRef = React8.useRef(null);
1641
- const textInputRef = React8.useRef(null);
1642
- const optionsRef = React8.useRef(null);
1651
+ const rootRef = React9.useRef(null);
1652
+ const textInputRef = React9.useRef(null);
1653
+ const optionsRef = React9.useRef(null);
1643
1654
  const editingField = panel && panel.kind === "edit" ? fields.find((f) => f.key === panel.key) : void 0;
1644
1655
  const dismissible = !!panel && (panel.kind === "add" || panel.kind === "edit" && editingField?.type === "select");
1645
- React8.useEffect(() => {
1656
+ React9.useEffect(() => {
1646
1657
  if (!dismissible) return;
1647
1658
  const away = (e) => {
1648
1659
  if (rootRef.current && !rootRef.current.contains(e.target)) setPanel(null);
@@ -1657,7 +1668,7 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
1657
1668
  document.removeEventListener("keydown", esc);
1658
1669
  };
1659
1670
  }, [dismissible]);
1660
- React8.useEffect(() => {
1671
+ React9.useEffect(() => {
1661
1672
  if (!panel || panel.kind !== "edit") return;
1662
1673
  if (editingField?.type === "text") {
1663
1674
  textInputRef.current?.focus();
@@ -1823,7 +1834,7 @@ function StatTile({ label, value, sub, delta, loading = false, compact: compact3
1823
1834
  }
1824
1835
 
1825
1836
  // src/components/data/CodeBlock.tsx
1826
- var React9 = __toESM(require("react"), 1);
1837
+ var React10 = __toESM(require("react"), 1);
1827
1838
  var import_jsx_runtime30 = require("react/jsx-runtime");
1828
1839
  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)$/;
1829
1840
  var RULES = {
@@ -1979,13 +1990,13 @@ function tokenize(src, lang) {
1979
1990
  return out;
1980
1991
  }
1981
1992
  function Highlighted({ code, lang }) {
1982
- const toks = React9.useMemo(() => tokenize(code, lang), [code, lang]);
1993
+ const toks = React10.useMemo(() => tokenize(code, lang), [code, lang]);
1983
1994
  return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_jsx_runtime30.Fragment, { children: toks.map((tk, i) => tk.c ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "tok-" + tk.c, children: tk.t }, i) : tk.t) });
1984
1995
  }
1985
1996
  function useCopy() {
1986
- const [done, setDone] = React9.useState(false);
1987
- const timer = React9.useRef(null);
1988
- React9.useEffect(() => () => {
1997
+ const [done, setDone] = React10.useState(false);
1998
+ const timer = React10.useRef(null);
1999
+ React10.useEffect(() => () => {
1989
2000
  if (timer.current) clearTimeout(timer.current);
1990
2001
  }, []);
1991
2002
  const copy = (text) => {
@@ -2021,8 +2032,8 @@ function CodeBlock({
2021
2032
  actions,
2022
2033
  className = ""
2023
2034
  }) {
2024
- const [wrap, setWrap] = React9.useState(!!wrapDefault);
2025
- const [open, setOpen] = React9.useState(false);
2035
+ const [wrap, setWrap] = React10.useState(!!wrapDefault);
2036
+ const [open, setOpen] = React10.useState(false);
2026
2037
  const [copied, copy] = useCopy();
2027
2038
  const body = String(code).replace(/\n$/, "");
2028
2039
  const lines = body.split("\n");
@@ -2051,7 +2062,7 @@ function CodeBlock({
2051
2062
  ] });
2052
2063
  }
2053
2064
  function DiffBlock({ diff = "", filename, collapseAfter = 34, className = "" }) {
2054
- const [open, setOpen] = React9.useState(false);
2065
+ const [open, setOpen] = React10.useState(false);
2055
2066
  const [copied, copy] = useCopy();
2056
2067
  const raw = String(diff).replace(/\n$/, "");
2057
2068
  const all = raw.split("\n").map((line) => {
@@ -2097,7 +2108,7 @@ function DiffBlock({ diff = "", filename, collapseAfter = 34, className = "" })
2097
2108
  }
2098
2109
 
2099
2110
  // src/components/data/Markdown.tsx
2100
- var React10 = __toESM(require("react"), 1);
2111
+ var React11 = __toESM(require("react"), 1);
2101
2112
  var import_jsx_runtime31 = require("react/jsx-runtime");
2102
2113
  var SAFE = /^(?:https?:|mailto:|tel:|#|\/|\.{1,2}\/)/i;
2103
2114
  var safeHref = (h) => SAFE.test(String(h || "").trim()) ? String(h).trim() : null;
@@ -2136,7 +2147,7 @@ function inlineNodes(src, ctx, keyBase) {
2136
2147
  const href = safeHref(g(2));
2137
2148
  out.push(href ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("a", { href, title: g(3) || void 0, target: /^https?:/i.test(href) ? "_blank" : void 0, rel: "noopener noreferrer", onClick: ctx.onLinkClick, children: inlineNodes(g(1), ctx, key()) }, key()) : /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { children: g(1) }, key()));
2138
2149
  } else if (kind === "cite") {
2139
- out.push(ctx.renderCitation ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(React10.Fragment, { children: ctx.renderCitation(g(1)) }, key()) : /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("sup", { className: "fd-md-cite", children: g(1) }, key()));
2150
+ out.push(ctx.renderCitation ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(React11.Fragment, { children: ctx.renderCitation(g(1)) }, key()) : /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("sup", { className: "fd-md-cite", children: g(1) }, key()));
2140
2151
  } else if (kind === "strongem") out.push(/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("strong", { children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("em", { children: inlineNodes(g(1), ctx, key()) }) }, key()));
2141
2152
  else if (kind === "strong") out.push(/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("strong", { children: inlineNodes(g(1) || g(2), ctx, key()) }, key()));
2142
2153
  else if (kind === "em") out.push(/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("em", { children: inlineNodes(g(1) || g(2), ctx, key()) }, key()));
@@ -2301,7 +2312,7 @@ function Markdown({
2301
2312
  onLinkClick
2302
2313
  }) {
2303
2314
  const ctx = { allowImages, headingOffset, renderCitation, onLinkClick, codeProps };
2304
- const blocks = React10.useMemo(() => parseBlocks(source), [source]);
2315
+ const blocks = React11.useMemo(() => parseBlocks(source), [source]);
2305
2316
  return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: ["fd-md", className].filter(Boolean).join(" "), children: renderBlocks(blocks, ctx, "b") });
2306
2317
  }
2307
2318
  function MarkdownInline({ source = "", className = "", onLinkClick }) {
@@ -2345,6 +2356,10 @@ function Meter({ segments = [], unallocated = 0, height = 8, label, legend = fal
2345
2356
 
2346
2357
  // src/components/data/Pagination.tsx
2347
2358
  var import_jsx_runtime33 = require("react/jsx-runtime");
2359
+ var unitPluralRules = new Intl.PluralRules("en-US");
2360
+ function pluralizeUnit(n, singular, irregularPlural) {
2361
+ return unitPluralRules.select(n) === "one" ? singular : irregularPlural ?? `${singular}s`;
2362
+ }
2348
2363
  function Pagination({
2349
2364
  page = 1,
2350
2365
  pageSize = 25,
@@ -2353,7 +2368,8 @@ function Pagination({
2353
2368
  onPageChange,
2354
2369
  onPageSizeChange,
2355
2370
  loading = false,
2356
- unit = "rows",
2371
+ unit = "row",
2372
+ unitPlural,
2357
2373
  className = "",
2358
2374
  ...rest
2359
2375
  }) {
@@ -2363,6 +2379,7 @@ function Pagination({
2363
2379
  const go = (p) => {
2364
2380
  if (onPageChange && p >= 1 && p <= totalPages && p !== page) onPageChange(p);
2365
2381
  };
2382
+ const unitLabel = pluralizeUnit(total, unit, unitPlural);
2366
2383
  const nums = [];
2367
2384
  const span = 1;
2368
2385
  for (let i = 1; i <= totalPages; i++) {
@@ -2372,7 +2389,7 @@ function Pagination({
2372
2389
  return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: ["fd-pag", className].filter(Boolean).join(" "), ...rest, children: [
2373
2390
  /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "fd-pag-count", children: loading ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "fd-skel fd-skel-text", style: { display: "inline-block", height: 12, width: 108 } }) : total === 0 ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
2374
2391
  "No ",
2375
- unit
2392
+ unitLabel
2376
2393
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
2377
2394
  /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("strong", { children: [
2378
2395
  from.toLocaleString(),
@@ -2382,7 +2399,7 @@ function Pagination({
2382
2399
  " of ",
2383
2400
  total.toLocaleString(),
2384
2401
  " ",
2385
- unit
2402
+ unitLabel
2386
2403
  ] }) }),
2387
2404
  onPageSizeChange ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("label", { className: "fd-pag-size", children: [
2388
2405
  /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { children: "Rows" }),
@@ -2409,7 +2426,7 @@ function Pagination({
2409
2426
  }
2410
2427
 
2411
2428
  // src/components/data/RelativeTime.tsx
2412
- var React11 = __toESM(require("react"), 1);
2429
+ var React12 = __toESM(require("react"), 1);
2413
2430
  var import_jsx_runtime34 = require("react/jsx-runtime");
2414
2431
  var MIN = 6e4;
2415
2432
  var HOUR = 36e5;
@@ -2461,9 +2478,9 @@ function formatDuration(ms) {
2461
2478
  return h + "h" + (m % 60 ? " " + m % 60 + "m" : "");
2462
2479
  }
2463
2480
  function RelativeTime({ value, prefix, className = "", refresh: refresh2 = true, ...rest }) {
2464
- const [, force] = React11.useState(0);
2481
+ const [, force] = React12.useState(0);
2465
2482
  const t = value instanceof Date ? value.getTime() : Date.parse(value);
2466
- React11.useEffect(() => {
2483
+ React12.useEffect(() => {
2467
2484
  if (!refresh2 || !t || isNaN(t)) return;
2468
2485
  const abs = Math.abs(t - Date.now());
2469
2486
  if (abs > DAY) return;
@@ -2479,10 +2496,10 @@ function RelativeTime({ value, prefix, className = "", refresh: refresh2 = true,
2479
2496
  }
2480
2497
 
2481
2498
  // src/components/data/ScoreMeter.tsx
2482
- var React13 = __toESM(require("react"), 1);
2499
+ var React14 = __toESM(require("react"), 1);
2483
2500
 
2484
2501
  // src/components/data/SegmentedMeter.tsx
2485
- var React12 = __toESM(require("react"), 1);
2502
+ var React13 = __toESM(require("react"), 1);
2486
2503
 
2487
2504
  // src/kits/files.ts
2488
2505
  function formatBytes(n) {
@@ -2687,7 +2704,7 @@ function SegmentedMeter({
2687
2704
  const pct = safeTotal ? Math.min(100, Math.round(used / safeTotal * 100)) : 0;
2688
2705
  const w = (v) => safeTotal ? Math.max(0, Math.min(100, Number(v) / safeTotal * 100)) : 0;
2689
2706
  const fill = (s, i) => s.color || (s.variant ? VARIANT_FILL[s.variant] : void 0) || CHART[i % CHART.length];
2690
- const generatedId = React12.useId();
2707
+ const generatedId = React13.useId();
2691
2708
  const uid2 = id || generatedId;
2692
2709
  return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: ["fd-segmeter", className].filter(Boolean).join(" "), onClick, children: [
2693
2710
  label || showTotal ? /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "fd-segmeter-head", children: [
@@ -2771,10 +2788,10 @@ function ScoreMeter({
2771
2788
  breakdownWidth = 280,
2772
2789
  className = ""
2773
2790
  }) {
2774
- const [open, setOpen] = React13.useState(false);
2775
- const ref = React13.useRef(null);
2791
+ const [open, setOpen] = React14.useState(false);
2792
+ const ref = React14.useRef(null);
2776
2793
  const value = Math.max(0, Math.min(100, Math.round(Number(score) || 0)));
2777
- const body = /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(React13.Fragment, { children: [
2794
+ const body = /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(React14.Fragment, { children: [
2778
2795
  /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "fd-scoremeter-rail", style: { width }, "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(SegmentedMeter, { total: 100, segments, height, showTotal: false, showPercent: false, legend: false }) }),
2779
2796
  showScore ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "fd-scoremeter-value fd-tabular", "aria-hidden": "true", children: value }) : null
2780
2797
  ] });
@@ -2793,7 +2810,7 @@ function ScoreMeter({
2793
2810
  }
2794
2811
  );
2795
2812
  }
2796
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(React13.Fragment, { children: [
2813
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(React14.Fragment, { children: [
2797
2814
  /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
2798
2815
  "button",
2799
2816
  {
@@ -2824,14 +2841,14 @@ function ScoreMeter({
2824
2841
  }
2825
2842
 
2826
2843
  // src/components/data/SortMenu.tsx
2827
- var React14 = __toESM(require("react"), 1);
2844
+ var React15 = __toESM(require("react"), 1);
2828
2845
  var import_jsx_runtime37 = require("react/jsx-runtime");
2829
2846
  var SORT_MENU_BASE = 120;
2830
2847
  function SortMenu({ fields = [], sort, onSort, align = "right", size = "md", className = "", ...rest }) {
2831
- const [open, setOpen] = React14.useState(false);
2848
+ const [open, setOpen] = React15.useState(false);
2832
2849
  const zIndex = useOverlayLayer(SORT_MENU_BASE);
2833
- const ref = React14.useRef(null);
2834
- React14.useEffect(() => {
2850
+ const ref = React15.useRef(null);
2851
+ React15.useEffect(() => {
2835
2852
  if (!open) return;
2836
2853
  const away = (e) => {
2837
2854
  if (ref.current && !ref.current.contains(e.target)) setOpen(false);
@@ -2893,7 +2910,7 @@ function SortMenu({ fields = [], sort, onSort, align = "right", size = "md", cla
2893
2910
  }
2894
2911
 
2895
2912
  // src/components/data/StepList.tsx
2896
- var React15 = __toESM(require("react"), 1);
2913
+ var React16 = __toESM(require("react"), 1);
2897
2914
  var import_jsx_runtime38 = require("react/jsx-runtime");
2898
2915
  var KIND_ICON = { tool: "wrench", search: "magnifying-glass", read: "file-text", write: "pencil-simple", reasoning: "brain", run: "terminal", fetch: "cloud-arrow-down" };
2899
2916
  function StepList({
@@ -2906,9 +2923,9 @@ function StepList({
2906
2923
  dense = false,
2907
2924
  className = ""
2908
2925
  }) {
2909
- const [openState, setOpenState] = React15.useState(defaultOpen);
2926
+ const [openState, setOpenState] = React16.useState(defaultOpen);
2910
2927
  const open = openProp == null ? openState : openProp;
2911
- const [expanded, setExpanded] = React15.useState({});
2928
+ const [expanded, setExpanded] = React16.useState({});
2912
2929
  if (!steps.length) return null;
2913
2930
  const running = steps.some((s) => s.status === "running");
2914
2931
  const failed = steps.filter((s) => s.status === "error").length;
@@ -2966,7 +2983,7 @@ function StepList({
2966
2983
  }
2967
2984
 
2968
2985
  // src/components/data/VirtualList.tsx
2969
- var React16 = __toESM(require("react"), 1);
2986
+ var React17 = __toESM(require("react"), 1);
2970
2987
  var import_jsx_runtime39 = require("react/jsx-runtime");
2971
2988
  var VIRTUAL_LIST_BUFFER_ROWS = 20;
2972
2989
  var VIRTUAL_LIST_ROW_GAP = 6;
@@ -3018,35 +3035,35 @@ function VirtualList({
3018
3035
  className = "",
3019
3036
  style
3020
3037
  }) {
3021
- const [scrollTop, setScrollTop] = React16.useState(0);
3022
- const loaded = React16.useMemo(
3038
+ const [scrollTop, setScrollTop] = React17.useState(0);
3039
+ const loaded = React17.useMemo(
3023
3040
  () => ({ firstItemIndex, count: items.length }),
3024
3041
  [firstItemIndex, items.length]
3025
3042
  );
3026
3043
  const total = Math.max(totalCount == null ? 0 : totalCount, firstItemIndex + items.length);
3027
3044
  const bandKey = firstItemIndex + ":" + items.length;
3028
- const win = React16.useMemo(
3045
+ const win = React17.useMemo(
3029
3046
  () => computeVirtualWindow({ scrollTop, viewportHeight: height, itemHeight, itemCount: total, loaded }),
3030
3047
  [scrollTop, height, itemHeight, total, loaded]
3031
3048
  );
3032
- const need = React16.useMemo(() => computeNeedMore(win, loaded), [win, loaded]);
3049
+ const need = React17.useMemo(() => computeNeedMore(win, loaded), [win, loaded]);
3033
3050
  const wantStart = need.start && hasMore?.start !== false;
3034
3051
  const wantEnd = need.end && hasMore?.end !== false;
3035
3052
  const bucket2 = Math.floor(win.visibleStart / VIRTUAL_LIST_BUFFER_ROWS);
3036
3053
  const askKey = bandKey + "@" + bucket2;
3037
- const asked = React16.useRef({ start: null, end: null });
3038
- React16.useEffect(() => {
3054
+ const asked = React17.useRef({ start: null, end: null });
3055
+ React17.useEffect(() => {
3039
3056
  if (loading || !wantStart || asked.current.start === askKey) return;
3040
3057
  asked.current.start = askKey;
3041
3058
  onNeedMore("start", win);
3042
3059
  }, [wantStart, loading, askKey, onNeedMore, win]);
3043
- React16.useEffect(() => {
3060
+ React17.useEffect(() => {
3044
3061
  if (loading || !wantEnd || asked.current.end === askKey) return;
3045
3062
  asked.current.end = askKey;
3046
3063
  onNeedMore("end", win);
3047
3064
  }, [wantEnd, loading, askKey, onNeedMore, win]);
3048
- const lastKeysRef = React16.useRef(null);
3049
- const newKeys = React16.useMemo(() => {
3065
+ const lastKeysRef = React17.useRef(null);
3066
+ const newKeys = React17.useMemo(() => {
3050
3067
  const prev = lastKeysRef.current;
3051
3068
  if (!prev) return /* @__PURE__ */ new Set();
3052
3069
  const fresh = /* @__PURE__ */ new Set();
@@ -3056,7 +3073,7 @@ function VirtualList({
3056
3073
  }
3057
3074
  return fresh;
3058
3075
  }, [items]);
3059
- React16.useEffect(() => {
3076
+ React17.useEffect(() => {
3060
3077
  lastKeysRef.current = new Set(items.map(keyOf));
3061
3078
  }, [items]);
3062
3079
  const gapStyle = { "--fd-vlist-gap": rowGap + "px" };
@@ -3101,7 +3118,7 @@ function VirtualList({
3101
3118
  }
3102
3119
 
3103
3120
  // src/components/data/EntityRow.tsx
3104
- var React17 = __toESM(require("react"), 1);
3121
+ var React18 = __toESM(require("react"), 1);
3105
3122
  var import_jsx_runtime40 = require("react/jsx-runtime");
3106
3123
  var ENTITY_ROW_METRIC_WIDTH = 74;
3107
3124
  var METRIC_TONE_COLOR = {
@@ -3114,7 +3131,7 @@ function EntityRowMetrics({ metrics, className = "", style }) {
3114
3131
  const key = m.id || m.label || i;
3115
3132
  const className2 = ["fd-erow-metric", m.tone && m.tone !== "default" ? "is-" + m.tone : "", m.tooltip != null ? "is-described" : ""].filter(Boolean).join(" ");
3116
3133
  const tone = { color: METRIC_TONE_COLOR[m.tone || "default"] };
3117
- const content = /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(React17.Fragment, { children: [
3134
+ const content = /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(React18.Fragment, { children: [
3118
3135
  m.icon ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }) : null,
3119
3136
  /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "fd-erow-metric-value fd-tabular", children: m.value }),
3120
3137
  /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "fd-sr", children: " " + m.label })
@@ -3182,14 +3199,14 @@ function EntityRow({
3182
3199
  }
3183
3200
 
3184
3201
  // src/components/data/TransferList.tsx
3185
- var React19 = __toESM(require("react"), 1);
3202
+ var React20 = __toESM(require("react"), 1);
3186
3203
  var import_react_dom4 = require("react-dom");
3187
3204
 
3188
3205
  // src/components/forms/field.tsx
3189
- var React18 = __toESM(require("react"), 1);
3206
+ var React19 = __toESM(require("react"), 1);
3190
3207
  var import_jsx_runtime41 = require("react/jsx-runtime");
3191
3208
  function useFieldId(id) {
3192
- const generated = React18.useId();
3209
+ const generated = React19.useId();
3193
3210
  return id || generated;
3194
3211
  }
3195
3212
  function FieldLabel({ htmlFor, id, required = false, onClick, children }) {
@@ -3307,12 +3324,12 @@ function TransferList({
3307
3324
  listHeight = 440,
3308
3325
  className = ""
3309
3326
  }) {
3310
- const [drag, setDrag] = React19.useState(null);
3311
- const [dragOverSide, setDragOverSide] = React19.useState(null);
3312
- const dragRef = React19.useRef(null);
3313
- const armedRef = React19.useRef(null);
3314
- const sideRefs = React19.useRef({ left: null, right: null });
3315
- const hitTestSide = React19.useCallback((x, y) => {
3327
+ const [drag, setDrag] = React20.useState(null);
3328
+ const [dragOverSide, setDragOverSide] = React20.useState(null);
3329
+ const dragRef = React20.useRef(null);
3330
+ const armedRef = React20.useRef(null);
3331
+ const sideRefs = React20.useRef({ left: null, right: null });
3332
+ const hitTestSide = React20.useCallback((x, y) => {
3316
3333
  for (const side of ["left", "right"]) {
3317
3334
  const el = sideRefs.current[side];
3318
3335
  if (!el) continue;
@@ -3321,7 +3338,7 @@ function TransferList({
3321
3338
  }
3322
3339
  return null;
3323
3340
  }, []);
3324
- const findItem = React19.useCallback(
3341
+ const findItem = React20.useCallback(
3325
3342
  (side, key) => (side === "left" ? left.items : right.items).find((it) => keyOf(it) === key),
3326
3343
  [left.items, right.items, keyOf]
3327
3344
  );
@@ -3343,7 +3360,7 @@ function TransferList({
3343
3360
  height: rect.height
3344
3361
  };
3345
3362
  };
3346
- React19.useEffect(() => {
3363
+ React20.useEffect(() => {
3347
3364
  const onMovePointer = (e) => {
3348
3365
  const armed = armedRef.current;
3349
3366
  if (!armed || e.pointerId !== armed.pointerId) return;
@@ -3396,7 +3413,7 @@ function TransferList({
3396
3413
  window.removeEventListener("pointercancel", endDrag);
3397
3414
  };
3398
3415
  }, [hitTestSide, findItem, onMove]);
3399
- React19.useEffect(() => {
3416
+ React20.useEffect(() => {
3400
3417
  if (!drag || typeof document === "undefined") return;
3401
3418
  const prev = document.body.style.userSelect;
3402
3419
  document.body.style.userSelect = "none";
@@ -3504,11 +3521,11 @@ function TransferList({
3504
3521
  }
3505
3522
 
3506
3523
  // src/components/forms/Checkbox.tsx
3507
- var React20 = __toESM(require("react"), 1);
3524
+ var React21 = __toESM(require("react"), 1);
3508
3525
  var import_jsx_runtime45 = require("react/jsx-runtime");
3509
3526
  function Checkbox({ label, description, card = false, indeterminate = false, className = "", ...rest }) {
3510
- const ref = React20.useRef(null);
3511
- React20.useEffect(() => {
3527
+ const ref = React21.useRef(null);
3528
+ React21.useEffect(() => {
3512
3529
  if (ref.current) ref.current.indeterminate = indeterminate;
3513
3530
  }, [indeterminate]);
3514
3531
  return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
@@ -3567,7 +3584,7 @@ function Textarea({ label, help, error, required = false, rows = 4, disabled = f
3567
3584
  }
3568
3585
 
3569
3586
  // src/components/forms/NumberInput.tsx
3570
- var React21 = __toESM(require("react"), 1);
3587
+ var React22 = __toESM(require("react"), 1);
3571
3588
  var import_jsx_runtime49 = require("react/jsx-runtime");
3572
3589
  function NumberInput({
3573
3590
  label,
@@ -3595,10 +3612,10 @@ function NumberInput({
3595
3612
  const n = Number(String(v == null ? "" : v).replace(/[^0-9.-]/g, ""));
3596
3613
  return isNaN(n) ? null : n;
3597
3614
  };
3598
- const [text, setText] = React21.useState(value == null || value === "" ? "" : String(value));
3599
- const [editing, setEditing] = React21.useState(false);
3600
- const timer = React21.useRef(null);
3601
- React21.useEffect(() => {
3615
+ const [text, setText] = React22.useState(value == null || value === "" ? "" : String(value));
3616
+ const [editing, setEditing] = React22.useState(false);
3617
+ const timer = React22.useRef(null);
3618
+ React22.useEffect(() => {
3602
3619
  if (!editing) setText(value == null || value === "" ? "" : String(value));
3603
3620
  }, [value, editing]);
3604
3621
  const clamp = (n) => Math.min(max, Math.max(min, n));
@@ -3622,7 +3639,7 @@ function NumberInput({
3622
3639
  const release = () => {
3623
3640
  if (timer.current) clearTimeout(timer.current);
3624
3641
  };
3625
- React21.useEffect(() => () => {
3642
+ React22.useEffect(() => () => {
3626
3643
  if (timer.current) clearTimeout(timer.current);
3627
3644
  }, []);
3628
3645
  const shown = editing ? text : (() => {
@@ -3709,7 +3726,7 @@ function NumberInput({
3709
3726
  }
3710
3727
 
3711
3728
  // src/components/forms/Select.tsx
3712
- var React22 = __toESM(require("react"), 1);
3729
+ var React23 = __toESM(require("react"), 1);
3713
3730
  var import_jsx_runtime50 = require("react/jsx-runtime");
3714
3731
  var norm = (o) => typeof o === "string" ? { value: o, label: o } : o;
3715
3732
  function Select({
@@ -3736,13 +3753,13 @@ function Select({
3736
3753
  const isOn = (v) => multiple ? vals.includes(v) : v === value;
3737
3754
  const hasSearch = searchable === void 0 ? opts.length > 8 : searchable;
3738
3755
  const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
3739
- const [open, setOpen] = React22.useState(false);
3740
- const [q, setQ] = React22.useState("");
3741
- const [active, setActive] = React22.useState(-1);
3742
- const rootRef = React22.useRef(null);
3743
- const boxRef = React22.useRef(null);
3744
- const listRef = React22.useRef(null);
3745
- const typeBuf = React22.useRef({ s: "", t: 0 });
3756
+ const [open, setOpen] = React23.useState(false);
3757
+ const [q, setQ] = React23.useState("");
3758
+ const [active, setActive] = React23.useState(-1);
3759
+ const rootRef = React23.useRef(null);
3760
+ const boxRef = React23.useRef(null);
3761
+ const listRef = React23.useRef(null);
3762
+ const typeBuf = React23.useRef({ s: "", t: 0 });
3746
3763
  const selected = multiple ? null : opts.find((o) => o.value === value);
3747
3764
  const chosen = multiple ? opts.filter((o) => vals.includes(o.value)) : [];
3748
3765
  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;
@@ -3767,7 +3784,7 @@ function Select({
3767
3784
  }
3768
3785
  setOpen(!open);
3769
3786
  };
3770
- React22.useEffect(() => {
3787
+ React23.useEffect(() => {
3771
3788
  if (!open || active < 0 || !listRef.current) return;
3772
3789
  const el = listRef.current.querySelector('[data-i="' + active + '"]');
3773
3790
  if (el) {
@@ -3888,7 +3905,7 @@ function Select({
3888
3905
  ),
3889
3906
  q ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "fd-body-sm fd-muted", children: visible.length }) : null
3890
3907
  ] }) : void 0,
3891
- footer: multiple ? /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(React22.Fragment, { children: [
3908
+ footer: multiple ? /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(React23.Fragment, { children: [
3892
3909
  /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
3893
3910
  "button",
3894
3911
  {
@@ -3919,7 +3936,7 @@ function Select({
3919
3936
  'Nothing matches "',
3920
3937
  q,
3921
3938
  '".'
3922
- ] }) : groups.map((grp) => /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(React22.Fragment, { children: [
3939
+ ] }) : groups.map((grp) => /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(React23.Fragment, { children: [
3923
3940
  grp.g ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "fd-pop-group", children: grp.g }) : null,
3924
3941
  grp.items.map(({ o, i }) => /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
3925
3942
  "button",
@@ -3956,7 +3973,7 @@ function Select({
3956
3973
  }
3957
3974
 
3958
3975
  // src/components/forms/DatePicker.tsx
3959
- var React23 = __toESM(require("react"), 1);
3976
+ var React24 = __toESM(require("react"), 1);
3960
3977
  var import_jsx_runtime51 = require("react/jsx-runtime");
3961
3978
  var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
3962
3979
  var DOW = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
@@ -3974,10 +3991,10 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3974
3991
  const today = /* @__PURE__ */ new Date();
3975
3992
  const sel = range ? value || {} : { start: value, end: value };
3976
3993
  const anchor = parse(sel.start) || parse(initialMonth) || today;
3977
- const [vy, setVy] = React23.useState(anchor.getFullYear());
3978
- const [vm, setVm] = React23.useState(anchor.getMonth());
3979
- const [mode2, setMode] = React23.useState("days");
3980
- const [hover, setHover] = React23.useState(null);
3994
+ const [vy, setVy] = React24.useState(anchor.getFullYear());
3995
+ const [vm, setVm] = React24.useState(anchor.getMonth());
3996
+ const [mode2, setMode] = React24.useState("days");
3997
+ const [hover, setHover] = React24.useState(null);
3981
3998
  const s = parse(sel.start), e = parse(sel.end);
3982
3999
  const hoverEnd = range && s && !e && hover ? parse(hover) : null;
3983
4000
  const inRange = (d) => {
@@ -4093,9 +4110,9 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
4093
4110
  }
4094
4111
  function DatePicker({ label, help, error, required = false, disabled = false, range = false, value, onChange, placeholder, id, className = "", style, ...rest }) {
4095
4112
  const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
4096
- const [open, setOpen] = React23.useState(false);
4097
- const rootRef = React23.useRef(null);
4098
- const boxRef = React23.useRef(null);
4113
+ const [open, setOpen] = React24.useState(false);
4114
+ const rootRef = React24.useRef(null);
4115
+ const boxRef = React24.useRef(null);
4099
4116
  const display = range ? value && value.start ? fmt(value.start) + (value.end ? " \u2192 " + fmt(value.end) : " \u2192 \u2026") : "" : fmt(value);
4100
4117
  const toggle = () => {
4101
4118
  if (!disabled) setOpen(!open);
@@ -4157,7 +4174,7 @@ function DatePicker({ label, help, error, required = false, disabled = false, ra
4157
4174
  }
4158
4175
 
4159
4176
  // src/components/forms/TimePicker.tsx
4160
- var React24 = __toESM(require("react"), 1);
4177
+ var React25 = __toESM(require("react"), 1);
4161
4178
  var import_jsx_runtime52 = require("react/jsx-runtime");
4162
4179
  var pad = (n) => String(n).padStart(2, "0");
4163
4180
  function ClockFace({ value = "09:00", onChange }) {
@@ -4166,9 +4183,9 @@ function ClockFace({ value = "09:00", onChange }) {
4166
4183
  if (isNaN(m)) m = 0;
4167
4184
  const pm = h24 >= 12;
4168
4185
  const h12 = h24 % 12 === 0 ? 12 : h24 % 12;
4169
- const [mode2, setMode] = React24.useState("h");
4170
- const faceRef = React24.useRef(null);
4171
- const dragging = React24.useRef(false);
4186
+ const [mode2, setMode] = React25.useState("h");
4187
+ const faceRef = React25.useRef(null);
4188
+ const dragging = React25.useRef(false);
4172
4189
  const set = (h, mm, isPm) => onChange((isPm ? h % 12 + 12 : h % 12) + ":" + pad(mm));
4173
4190
  const R = 108, NR = 80;
4174
4191
  const nums = mode2 === "h" ? Array.from({ length: 12 }, (_, i) => i + 1) : Array.from({ length: 12 }, (_, i) => i * 5);
@@ -4241,9 +4258,9 @@ function ClockFace({ value = "09:00", onChange }) {
4241
4258
  }
4242
4259
  function TimePicker({ label, help, error, required = false, disabled = false, value = "", onChange, placeholder = "Pick a time", id, className = "", style }) {
4243
4260
  const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
4244
- const [open, setOpen] = React24.useState(false);
4245
- const rootRef = React24.useRef(null);
4246
- const boxRef = React24.useRef(null);
4261
+ const [open, setOpen] = React25.useState(false);
4262
+ const rootRef = React25.useRef(null);
4263
+ const boxRef = React25.useRef(null);
4247
4264
  const disp = () => {
4248
4265
  if (!value) return "";
4249
4266
  const [h, m] = value.split(":").map(Number);
@@ -4286,7 +4303,7 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
4286
4303
  offset: 6,
4287
4304
  width: 262,
4288
4305
  role: "presentation",
4289
- footer: /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(React24.Fragment, { children: [
4306
+ footer: /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(React25.Fragment, { children: [
4290
4307
  /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
4291
4308
  "button",
4292
4309
  {
@@ -4314,7 +4331,7 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
4314
4331
  }
4315
4332
 
4316
4333
  // src/components/forms/Slider.tsx
4317
- var React25 = __toESM(require("react"), 1);
4334
+ var React26 = __toESM(require("react"), 1);
4318
4335
  var import_jsx_runtime53 = require("react/jsx-runtime");
4319
4336
  function Slider({
4320
4337
  label,
@@ -4332,7 +4349,7 @@ function Slider({
4332
4349
  ...rest
4333
4350
  }) {
4334
4351
  const fieldId = useFieldId(id);
4335
- const [dragging, setDragging] = React25.useState(false);
4352
+ const [dragging, setDragging] = React26.useState(false);
4336
4353
  const v = value === void 0 ? min : Number(value);
4337
4354
  const pct = max === min ? 0 : (v - min) / (max - min) * 100;
4338
4355
  return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: ["fd-field", className].filter(Boolean).join(" "), children: [
@@ -4366,7 +4383,7 @@ function Slider({
4366
4383
  }
4367
4384
 
4368
4385
  // src/components/forms/RangeSlider.tsx
4369
- var React26 = __toESM(require("react"), 1);
4386
+ var React27 = __toESM(require("react"), 1);
4370
4387
  var import_jsx_runtime54 = require("react/jsx-runtime");
4371
4388
  function RangeSlider({
4372
4389
  label,
@@ -4386,9 +4403,9 @@ function RangeSlider({
4386
4403
  }) {
4387
4404
  const fmt2 = format || ((v) => String(v));
4388
4405
  const [a, b] = value || [min, max];
4389
- const [drag, setDrag] = React26.useState(null);
4390
- const [focus, setFocus] = React26.useState(null);
4391
- const railRef = React26.useRef(null);
4406
+ const [drag, setDrag] = React27.useState(null);
4407
+ const [focus, setFocus] = React27.useState(null);
4408
+ const railRef = React27.useRef(null);
4392
4409
  const pct = (v) => max === min ? 0 : (v - min) / (max - min) * 100;
4393
4410
  const clampPair = (i, v) => {
4394
4411
  v = Math.min(max, Math.max(min, Math.round(v / step) * step));
@@ -4403,7 +4420,7 @@ function RangeSlider({
4403
4420
  const r = railRef.current.getBoundingClientRect();
4404
4421
  return min + Math.min(1, Math.max(0, (e.clientX - r.left) / r.width)) * (max - min);
4405
4422
  };
4406
- React26.useEffect(() => {
4423
+ React27.useEffect(() => {
4407
4424
  if (drag === null) return;
4408
4425
  const mv = (e) => onChange && onChange(clampPair(drag, fromEvent(e)));
4409
4426
  const upH = () => setDrag(null);
@@ -4484,7 +4501,7 @@ function RangeSlider({
4484
4501
  /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "fd-range" + (hasLabels ? " has-labels" : ""), onPointerDown: onRailDown, children: [
4485
4502
  /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "fd-range-rail", ref: railRef }),
4486
4503
  /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "fd-range-fill", style: { left: pct(a) + "%", width: pct(b) - pct(a) + "%" } }),
4487
- marks.map((m) => /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(React26.Fragment, { children: [
4504
+ marks.map((m) => /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(React27.Fragment, { children: [
4488
4505
  /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "fd-range-mark" + (m.value >= a && m.value <= b ? " is-in" : ""), style: { left: pct(m.value) + "%" } }),
4489
4506
  m.label ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "fd-range-mark-label", style: { left: pct(m.value) + "%" }, children: m.label }) : null
4490
4507
  ] }, m.value)),
@@ -4513,7 +4530,7 @@ function RangeSlider({
4513
4530
  }
4514
4531
 
4515
4532
  // src/components/forms/Dropzone.tsx
4516
- var React27 = __toESM(require("react"), 1);
4533
+ var React28 = __toESM(require("react"), 1);
4517
4534
  var import_jsx_runtime55 = require("react/jsx-runtime");
4518
4535
  function Dropzone({
4519
4536
  onFiles,
@@ -4528,8 +4545,8 @@ function Dropzone({
4528
4545
  className = "",
4529
4546
  style
4530
4547
  }) {
4531
- const [over, setOver] = React27.useState(false);
4532
- const depth = React27.useRef(0);
4548
+ const [over, setOver] = React28.useState(false);
4549
+ const depth = React28.useRef(0);
4533
4550
  const has = (e) => {
4534
4551
  const dt = e.dataTransfer;
4535
4552
  if (!dt) return false;
@@ -4591,8 +4608,8 @@ function FilePickButton({
4591
4608
  className = "",
4592
4609
  children
4593
4610
  }) {
4594
- const ref = React27.useRef(null);
4595
- return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(React27.Fragment, { children: [
4611
+ const ref = React28.useRef(null);
4612
+ return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(React28.Fragment, { children: [
4596
4613
  /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
4597
4614
  "button",
4598
4615
  {
@@ -4625,10 +4642,10 @@ function FilePickButton({
4625
4642
  }
4626
4643
  function useStagedFiles(upload, opts) {
4627
4644
  const o = opts || {};
4628
- const [items, setItems] = React27.useState([]);
4629
- const controllers = React27.useRef({});
4645
+ const [items, setItems] = React28.useState([]);
4646
+ const controllers = React28.useRef({});
4630
4647
  const patch = (id, next) => setItems((list) => list.map((f) => f.id === id ? Object.assign({}, f, next) : f));
4631
- const run = React27.useCallback((att) => {
4648
+ const run = React28.useCallback((att) => {
4632
4649
  if (!upload) return;
4633
4650
  const ac = typeof AbortController !== "undefined" ? new AbortController() : null;
4634
4651
  controllers.current[att.id] = ac;
@@ -4645,14 +4662,14 @@ function useStagedFiles(upload, opts) {
4645
4662
  delete controllers.current[att.id];
4646
4663
  });
4647
4664
  }, [upload]);
4648
- const add = React27.useCallback((files) => {
4665
+ const add = React28.useCallback((files) => {
4649
4666
  if (!upload) return [];
4650
4667
  const atts = Array.from(files).map((f) => toAttachment(f));
4651
4668
  setItems((list) => list.concat(atts));
4652
4669
  atts.forEach(run);
4653
4670
  return atts;
4654
4671
  }, [upload, run]);
4655
- const remove = React27.useCallback((att) => {
4672
+ const remove = React28.useCallback((att) => {
4656
4673
  const ac = controllers.current[att.id];
4657
4674
  if (ac) {
4658
4675
  try {
@@ -4663,10 +4680,10 @@ function useStagedFiles(upload, opts) {
4663
4680
  }
4664
4681
  setItems((list) => list.filter((f) => f.id !== att.id));
4665
4682
  }, []);
4666
- const retry = React27.useCallback((att) => {
4683
+ const retry = React28.useCallback((att) => {
4667
4684
  run(att);
4668
4685
  }, [run]);
4669
- const clear = React27.useCallback(() => {
4686
+ const clear = React28.useCallback(() => {
4670
4687
  Object.values(controllers.current).forEach((ac) => {
4671
4688
  try {
4672
4689
  ac && ac.abort();
@@ -4790,7 +4807,7 @@ function FileGrid({ files = [], onOpen, onRemove, onRetry, tiles = true, maxHeig
4790
4807
  }
4791
4808
 
4792
4809
  // src/components/forms/MarkdownEditor.tsx
4793
- var React28 = __toESM(require("react"), 1);
4810
+ var React29 = __toESM(require("react"), 1);
4794
4811
  var import_jsx_runtime57 = require("react/jsx-runtime");
4795
4812
  var isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent || "");
4796
4813
  var INLINE_RE = /(\*\*\*[^*\n]+\*\*\*|\*\*[^*\n]+\*\*|__[^_\n]+__|~~[^~\n]+~~|`[^`\n]+`|\*[^*\s][^*\n]*\*|(?<![A-Za-z0-9_])_[^_\s][^_\n]*_|\[[^\]\n]*\]\([^)\s\n]*\)|https?:\/\/\S+)/g;
@@ -5004,7 +5021,7 @@ function syncDom(root, value) {
5004
5021
  while (root.children.length > lines.length) root.removeChild(root.lastChild);
5005
5022
  }
5006
5023
  var LIST_CONT = RE_LI;
5007
- var MarkdownEditor = React28.forwardRef(function MarkdownEditor2({
5024
+ var MarkdownEditor = React29.forwardRef(function MarkdownEditor2({
5008
5025
  value = "",
5009
5026
  onChange,
5010
5027
  onSubmit,
@@ -5023,10 +5040,10 @@ var MarkdownEditor = React28.forwardRef(function MarkdownEditor2({
5023
5040
  className = "",
5024
5041
  id
5025
5042
  }, ref) {
5026
- const boxRef = React28.useRef(null);
5027
- const composing = React28.useRef(false);
5028
- const pendingCaret = React28.useRef(null);
5029
- React28.useLayoutEffect(() => {
5043
+ const boxRef = React29.useRef(null);
5044
+ const composing = React29.useRef(false);
5045
+ const pendingCaret = React29.useRef(null);
5046
+ React29.useLayoutEffect(() => {
5030
5047
  const root = boxRef.current;
5031
5048
  if (!root || composing.current) return;
5032
5049
  const active = document.activeElement === root || root.contains(document.activeElement);
@@ -5035,7 +5052,7 @@ var MarkdownEditor = React28.forwardRef(function MarkdownEditor2({
5035
5052
  pendingCaret.current = null;
5036
5053
  if (active && caret != null) placeCaret(root, caret);
5037
5054
  }, [value]);
5038
- React28.useEffect(() => {
5055
+ React29.useEffect(() => {
5039
5056
  if (autoFocus && boxRef.current) boxRef.current.focus();
5040
5057
  }, [autoFocus]);
5041
5058
  const caretNow = () => {
@@ -5102,7 +5119,7 @@ var MarkdownEditor = React28.forwardRef(function MarkdownEditor2({
5102
5119
  api.replaceRange(from, to, next, from + next.length);
5103
5120
  }
5104
5121
  };
5105
- React28.useImperativeHandle(ref, () => api);
5122
+ React29.useImperativeHandle(ref, () => api);
5106
5123
  function detect(text, caret) {
5107
5124
  if (!onTrigger) return;
5108
5125
  const upto = text.slice(0, caret);
@@ -5254,10 +5271,10 @@ var MarkdownEditor = React28.forwardRef(function MarkdownEditor2({
5254
5271
  });
5255
5272
 
5256
5273
  // src/components/platform/AccountMenu.tsx
5257
- var React30 = __toESM(require("react"), 1);
5274
+ var React31 = __toESM(require("react"), 1);
5258
5275
 
5259
5276
  // src/kits/session.ts
5260
- var React29 = __toESM(require("react"), 1);
5277
+ var React30 = __toESM(require("react"), 1);
5261
5278
  var PERMISSION_CATALOG = [
5262
5279
  { group: "Plans", items: [
5263
5280
  { key: "plan.view", label: "View plans", detail: "Read any plan in the workspace." },
@@ -6824,8 +6841,8 @@ function roadmap(overrides) {
6824
6841
  };
6825
6842
  }
6826
6843
  function useSession() {
6827
- const [s, setS] = React29.useState(getSession);
6828
- React29.useEffect(() => subscribe(setS), []);
6844
+ const [s, setS] = React30.useState(getSession);
6845
+ React30.useEffect(() => subscribe(setS), []);
6829
6846
  return s;
6830
6847
  }
6831
6848
  var SessionKit = {
@@ -6895,9 +6912,9 @@ function AccountMenu({
6895
6912
  ...rest
6896
6913
  }) {
6897
6914
  const session = SessionKit.useSession();
6898
- const [open, setOpen] = React30.useState(false);
6899
- const [switching, setSwitching] = React30.useState(false);
6900
- const ref = React30.useRef(null);
6915
+ const [open, setOpen] = React31.useState(false);
6916
+ const [switching, setSwitching] = React31.useState(false);
6917
+ const ref = React31.useRef(null);
6901
6918
  const user = session.user;
6902
6919
  const visibleAdmin = adminLinks.filter((l) => !l.perm || SessionKit.can(l.perm));
6903
6920
  const pick = (item) => {
@@ -6981,14 +6998,14 @@ function AccountMenu({
6981
6998
  }
6982
6999
 
6983
7000
  // src/components/platform/ApiSpecBrowser.tsx
6984
- var React31 = __toESM(require("react"), 1);
7001
+ var React32 = __toESM(require("react"), 1);
6985
7002
  var import_jsx_runtime59 = require("react/jsx-runtime");
6986
7003
  var METHOD_TONE = { GET: "success", POST: "info", PATCH: "warning", PUT: "warning", DELETE: "danger" };
6987
7004
  function Json({ obj }) {
6988
7005
  return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("pre", { className: "fd-json", children: JSON.stringify(obj, null, 2) });
6989
7006
  }
6990
7007
  function Endpoint({ s, onRequest }) {
6991
- const [tried, setTried] = React31.useState(null);
7008
+ const [tried, setTried] = React32.useState(null);
6992
7009
  const run = async () => {
6993
7010
  setTried("busy");
6994
7011
  const t0 = (window.performance || Date).now();
@@ -7061,10 +7078,10 @@ function ApiSpecBrowser({
7061
7078
  className = "",
7062
7079
  ...rest
7063
7080
  }) {
7064
- const [q, setQ] = React31.useState("");
7065
- const [method, setMethod] = React31.useState(null);
7066
- const [mod, setMod] = React31.useState(null);
7067
- const [listOnly, setListOnly] = React31.useState(false);
7081
+ const [q, setQ] = React32.useState("");
7082
+ const [method, setMethod] = React32.useState(null);
7083
+ const [mod, setMod] = React32.useState(null);
7084
+ const [listOnly, setListOnly] = React32.useState(false);
7068
7085
  const activeModule = modules && modules.find((m) => m.id === mod);
7069
7086
  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())));
7070
7087
  const effGroups = groups && groups.length ? groups : [["All endpoints", spec.map((s) => s.id)]];
@@ -7143,7 +7160,7 @@ function ApiSpecBrowser({
7143
7160
  }
7144
7161
 
7145
7162
  // src/components/platform/ProfilePage.tsx
7146
- var React32 = __toESM(require("react"), 1);
7163
+ var React33 = __toESM(require("react"), 1);
7147
7164
  var import_jsx_runtime60 = require("react/jsx-runtime");
7148
7165
  var TIMEZONES = ["America/New_York", "America/Chicago", "America/Denver", "America/Los_Angeles", "America/Anchorage", "Pacific/Honolulu", "Europe/London", "Europe/Berlin"];
7149
7166
  var NOTIFY = [
@@ -7156,7 +7173,7 @@ var NOTIFY = [
7156
7173
  function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSessions = true, className = "", ...rest }) {
7157
7174
  const session = SessionKit.useSession();
7158
7175
  const user = userProp || session.user;
7159
- const [draft, setDraft] = React32.useState(() => ({
7176
+ const [draft, setDraft] = React33.useState(() => ({
7160
7177
  name: user.name || "",
7161
7178
  title: user.title || "",
7162
7179
  email: user.email || "",
@@ -7165,8 +7182,8 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
7165
7182
  bio: user.bio || "",
7166
7183
  notify: user.notify || { planShared: true, planChanged: true, goalMissed: true, flagChanged: false, weekly: true }
7167
7184
  }));
7168
- const [saving, setSaving] = React32.useState(false);
7169
- const [saved, setSaved] = React32.useState(false);
7185
+ const [saving, setSaving] = React33.useState(false);
7186
+ const [saved, setSaved] = React33.useState(false);
7170
7187
  const set = (k, v) => {
7171
7188
  setDraft((d) => Object.assign({}, d, { [k]: v }));
7172
7189
  setSaved(false);
@@ -7356,10 +7373,10 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
7356
7373
  }
7357
7374
 
7358
7375
  // src/components/platform/RoadmapTimeline.tsx
7359
- var React34 = __toESM(require("react"), 1);
7376
+ var React35 = __toESM(require("react"), 1);
7360
7377
 
7361
7378
  // src/kits/runtime.ts
7362
- var React33 = __toESM(require("react"), 1);
7379
+ var React34 = __toESM(require("react"), 1);
7363
7380
  var WIRED_ENDPOINTS = [
7364
7381
  // Nothing yet. Every id below would come from a real service:
7365
7382
  // "plan.get", "placements.list", …
@@ -7530,8 +7547,8 @@ var RuntimeKit = {
7530
7547
  };
7531
7548
  RuntimeKit.declare(FEATURE_NEEDS);
7532
7549
  function useRuntimeMode() {
7533
- const [m, setM] = React33.useState(RuntimeKit.getMode());
7534
- React33.useEffect(() => RuntimeKit.subscribe(setM), []);
7550
+ const [m, setM] = React34.useState(RuntimeKit.getMode());
7551
+ React34.useEffect(() => RuntimeKit.subscribe(setM), []);
7535
7552
  return m;
7536
7553
  }
7537
7554
  function useFeatureStatus(key) {
@@ -7614,12 +7631,12 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
7614
7631
  }
7615
7632
  function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
7616
7633
  const session = SessionKit.useSession();
7617
- const [project, setProject] = React34.useState("");
7618
- const [q, setQ] = React34.useState("");
7619
- const scrollRef = React34.useRef(null);
7620
- const nowRef = React34.useRef(null);
7621
- const rm = React34.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
7622
- const byKey = React34.useMemo(() => {
7634
+ const [project, setProject] = React35.useState("");
7635
+ const [q, setQ] = React35.useState("");
7636
+ const scrollRef = React35.useRef(null);
7637
+ const nowRef = React35.useRef(null);
7638
+ const rm = React35.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
7639
+ const byKey = React35.useMemo(() => {
7623
7640
  const m = {};
7624
7641
  rm.items.forEach((i) => {
7625
7642
  m[i.key] = i;
@@ -7628,7 +7645,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
7628
7645
  }, [rm]);
7629
7646
  const items = rm.items.filter((i) => (!project || i.project === project) && (!q || (i.label + " " + i.description + " " + (i.backend || "") + " " + i.key).toLowerCase().includes(q.toLowerCase())));
7630
7647
  const projects = [...new Set(rm.items.map((i) => i.project))];
7631
- React34.useEffect(() => {
7648
+ React35.useEffect(() => {
7632
7649
  let raf1 = 0, raf2 = 0;
7633
7650
  const place = () => {
7634
7651
  const box = scrollRef.current, mark = nowRef.current;
@@ -7702,7 +7719,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
7702
7719
  lastPhase = item.phase;
7703
7720
  const inPhase = items.filter((i) => i.phase === item.phase).length;
7704
7721
  const isBoundary = n === firstPending;
7705
- return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(React34.Fragment, { children: [
7722
+ return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(React35.Fragment, { children: [
7706
7723
  showPhase ? /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "fd-rm-era", children: [
7707
7724
  /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
7708
7725
  /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
@@ -7746,7 +7763,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
7746
7763
  }
7747
7764
 
7748
7765
  // src/components/platform/ComingSoon.tsx
7749
- var React35 = __toESM(require("react"), 1);
7766
+ var React36 = __toESM(require("react"), 1);
7750
7767
  var import_react_dom5 = require("react-dom");
7751
7768
  var import_jsx_runtime62 = require("react/jsx-runtime");
7752
7769
  var SOON_HOVERCARD_BASE = 220;
@@ -7765,8 +7782,8 @@ function writeBypassed(list) {
7765
7782
  }
7766
7783
  }
7767
7784
  function useBypass(key) {
7768
- const [on, setOn] = React35.useState(() => !!key && readBypassed().indexOf(key) >= 0);
7769
- React35.useEffect(() => {
7785
+ const [on, setOn] = React36.useState(() => !!key && readBypassed().indexOf(key) >= 0);
7786
+ React36.useEffect(() => {
7770
7787
  setOn(!!key && readBypassed().indexOf(key) >= 0);
7771
7788
  }, [key]);
7772
7789
  const set = (next) => {
@@ -7813,9 +7830,9 @@ function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onB
7813
7830
  ] });
7814
7831
  }
7815
7832
  function useHoverCard(open) {
7816
- const anchor = React35.useRef(null);
7817
- const [pos, setPos] = React35.useState(null);
7818
- React35.useLayoutEffect(() => {
7833
+ const anchor = React36.useRef(null);
7834
+ const [pos, setPos] = React36.useState(null);
7835
+ React36.useLayoutEffect(() => {
7819
7836
  if (!open || !anchor.current) {
7820
7837
  setPos(null);
7821
7838
  return;
@@ -7942,10 +7959,10 @@ function ComingSoon({
7942
7959
  ] });
7943
7960
  }
7944
7961
  function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass, blur, tip, className, rest, children }) {
7945
- const [open, setOpen] = React35.useState(false);
7962
+ const [open, setOpen] = React36.useState(false);
7946
7963
  const [anchor, pos] = useHoverCard(open);
7947
7964
  const zIndex = useOverlayLayer(SOON_HOVERCARD_BASE);
7948
- const close = React35.useRef(null);
7965
+ const close = React36.useRef(null);
7949
7966
  const show = () => {
7950
7967
  if (close.current) {
7951
7968
  clearTimeout(close.current);
@@ -7961,7 +7978,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
7961
7978
  setOpen(false);
7962
7979
  }, 140);
7963
7980
  };
7964
- React35.useEffect(() => () => {
7981
+ React36.useEffect(() => () => {
7965
7982
  if (close.current) clearTimeout(close.current);
7966
7983
  }, []);
7967
7984
  return /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(
@@ -8130,15 +8147,15 @@ function PermissionHint({ perm, children }) {
8130
8147
  }
8131
8148
 
8132
8149
  // src/components/platform/ModeSwitch.tsx
8133
- var React36 = __toESM(require("react"), 1);
8150
+ var React37 = __toESM(require("react"), 1);
8134
8151
  var import_jsx_runtime64 = require("react/jsx-runtime");
8135
8152
  var MODE_SWITCH_BASE = 140;
8136
8153
  function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
8137
8154
  const mode2 = useRuntimeMode();
8138
- const [open, setOpen] = React36.useState(false);
8155
+ const [open, setOpen] = React37.useState(false);
8139
8156
  const zIndex = useOverlayLayer(MODE_SWITCH_BASE);
8140
- const ref = React36.useRef(null);
8141
- React36.useEffect(() => {
8157
+ const ref = React37.useRef(null);
8158
+ React37.useEffect(() => {
8142
8159
  if (!open) return;
8143
8160
  const away = (e) => {
8144
8161
  if (ref.current && !ref.current.contains(e.target)) setOpen(false);
@@ -8387,7 +8404,7 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
8387
8404
  }
8388
8405
 
8389
8406
  // src/components/planner/MixGap.tsx
8390
- var React37 = __toESM(require("react"), 1);
8407
+ var React38 = __toESM(require("react"), 1);
8391
8408
  var import_jsx_runtime67 = require("react/jsx-runtime");
8392
8409
  var MIX_GAP_LAYOUT = {
8393
8410
  trackHeight: 30,
@@ -8402,7 +8419,7 @@ function mixGapOffset(value, max) {
8402
8419
  }
8403
8420
  function MixGap({ rows = [], loading = false, className = "" }) {
8404
8421
  const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
8405
- const [hover, setHover] = React37.useState(null);
8422
+ const [hover, setHover] = React38.useState(null);
8406
8423
  const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
8407
8424
  const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
8408
8425
  const { trackHeight, barHeight, targetWidth, labelGap } = MIX_GAP_LAYOUT;
@@ -8545,7 +8562,7 @@ function ChannelContribution({
8545
8562
  }
8546
8563
 
8547
8564
  // src/components/planner/BudgetReallocator.tsx
8548
- var React38 = __toESM(require("react"), 1);
8565
+ var React39 = __toESM(require("react"), 1);
8549
8566
  var import_jsx_runtime69 = require("react/jsx-runtime");
8550
8567
  var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
8551
8568
  function BudgetReallocator({
@@ -8561,8 +8578,8 @@ function BudgetReallocator({
8561
8578
  onCancel,
8562
8579
  className = ""
8563
8580
  }) {
8564
- const [draft, setDraft] = React38.useState(spend);
8565
- React38.useEffect(() => setDraft(spend), [spend]);
8581
+ const [draft, setDraft] = React39.useState(spend);
8582
+ React39.useEffect(() => setDraft(spend), [spend]);
8566
8583
  const dirty = draft !== spend;
8567
8584
  const nextCrp = scoreFor ? scoreFor(draft) : crp;
8568
8585
  const nextBand = bandFor(nextCrp);
@@ -8732,7 +8749,7 @@ function ImportanceTag({ level, showLabel = true, size = "sm", className = "" })
8732
8749
  }
8733
8750
 
8734
8751
  // src/components/planner/PreferenceMeter.tsx
8735
- var React39 = __toESM(require("react"), 1);
8752
+ var React40 = __toESM(require("react"), 1);
8736
8753
  var import_jsx_runtime72 = require("react/jsx-runtime");
8737
8754
  function preferenceScore(criteria) {
8738
8755
  const earned = criteria.reduce((n, c) => n + (Number(c.earned) || 0), 0);
@@ -8762,7 +8779,7 @@ function PreferenceMeter({
8762
8779
  className = ""
8763
8780
  }) {
8764
8781
  const value = score == null ? preferenceScore(criteria) : score;
8765
- const segments = React39.useMemo(() => preferenceSegments(criteria), [criteria]);
8782
+ const segments = React40.useMemo(() => preferenceSegments(criteria), [criteria]);
8766
8783
  return /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(
8767
8784
  ScoreMeter,
8768
8785
  {
@@ -8801,10 +8818,10 @@ function PreferenceMeter({
8801
8818
  }
8802
8819
 
8803
8820
  // src/components/chat/AgentChatPanel.tsx
8804
- var React45 = __toESM(require("react"), 1);
8821
+ var React46 = __toESM(require("react"), 1);
8805
8822
 
8806
8823
  // src/components/chat/chatEngine.ts
8807
- var React40 = __toESM(require("react"), 1);
8824
+ var React41 = __toESM(require("react"), 1);
8808
8825
  var CHAT_UNAVAILABLE = "chat_unavailable";
8809
8826
  var JOB_PENDING = ["queued", "running"];
8810
8827
  var JOB_SUCCESS = ["completed", "recovered"];
@@ -8858,22 +8875,22 @@ function useChatEngine(opts) {
8858
8875
  onClear,
8859
8876
  onFeedback
8860
8877
  } = opts || {};
8861
- const [status, setStatus] = React40.useState("idle");
8862
- const [threadId, setThreadId] = React40.useState(null);
8863
- const [messages, setMessages] = React40.useState([]);
8864
- const [queue, setQueue] = React40.useState([]);
8865
- const [fatal, setFatal] = React40.useState(null);
8866
- const [busy, setBusy] = React40.useState(false);
8867
- const [turnStartedAt, setTurnStartedAt] = React40.useState(null);
8868
- const listRef = React40.useRef([]);
8869
- const queueRef = React40.useRef([]);
8870
- const busyRef = React40.useRef(false);
8871
- const stoppedRef = React40.useRef(false);
8872
- const abortRef = React40.useRef(null);
8873
- const serverCount = React40.useRef(0);
8874
- const threadRef = React40.useRef(null);
8875
- const mounted = React40.useRef(true);
8876
- React40.useEffect(() => {
8878
+ const [status, setStatus] = React41.useState("idle");
8879
+ const [threadId, setThreadId] = React41.useState(null);
8880
+ const [messages, setMessages] = React41.useState([]);
8881
+ const [queue, setQueue] = React41.useState([]);
8882
+ const [fatal, setFatal] = React41.useState(null);
8883
+ const [busy, setBusy] = React41.useState(false);
8884
+ const [turnStartedAt, setTurnStartedAt] = React41.useState(null);
8885
+ const listRef = React41.useRef([]);
8886
+ const queueRef = React41.useRef([]);
8887
+ const busyRef = React41.useRef(false);
8888
+ const stoppedRef = React41.useRef(false);
8889
+ const abortRef = React41.useRef(null);
8890
+ const serverCount = React41.useRef(0);
8891
+ const threadRef = React41.useRef(null);
8892
+ const mounted = React41.useRef(true);
8893
+ React41.useEffect(() => {
8877
8894
  mounted.current = true;
8878
8895
  return () => {
8879
8896
  mounted.current = false;
@@ -8895,14 +8912,14 @@ function useChatEngine(opts) {
8895
8912
  }
8896
8913
  return false;
8897
8914
  };
8898
- const loadThread = React40.useCallback(async (id) => {
8915
+ const loadThread = React41.useCallback(async (id) => {
8899
8916
  const data = await apiAdapter.getThread(id);
8900
8917
  const list = [...data && data.messages || []];
8901
8918
  serverCount.current = list.length;
8902
8919
  commit(list);
8903
8920
  return list;
8904
8921
  }, [apiAdapter]);
8905
- React40.useEffect(() => {
8922
+ React41.useEffect(() => {
8906
8923
  if (!apiAdapter) {
8907
8924
  setStatus("idle");
8908
8925
  setFatal(null);
@@ -9115,7 +9132,7 @@ function useChatEngine(opts) {
9115
9132
  await dispatchTurn(turn);
9116
9133
  }
9117
9134
  }
9118
- const send = React40.useCallback((text, attachments) => {
9135
+ const send = React41.useCallback((text, attachments) => {
9119
9136
  const body = (text || "").trim();
9120
9137
  if (!body && !(attachments && attachments.length)) return;
9121
9138
  if (status === "disconnected") return;
@@ -9125,7 +9142,7 @@ function useChatEngine(opts) {
9125
9142
  stoppedRef.current = false;
9126
9143
  drain();
9127
9144
  }, [status]);
9128
- const stop = React40.useCallback(() => {
9145
+ const stop = React41.useCallback(() => {
9129
9146
  stoppedRef.current = true;
9130
9147
  const ac = abortRef.current;
9131
9148
  if (ac) {
@@ -9144,11 +9161,11 @@ function useChatEngine(opts) {
9144
9161
  store.del(STORAGE_PREFIX + threadRef.current);
9145
9162
  }
9146
9163
  }, [apiAdapter]);
9147
- const removeQueued = React40.useCallback((id) => {
9164
+ const removeQueued = React41.useCallback((id) => {
9148
9165
  queueRef.current = queueRef.current.filter((t) => t.id !== id);
9149
9166
  setQueue(queueRef.current.slice());
9150
9167
  }, []);
9151
- const retry = React40.useCallback(() => {
9168
+ const retry = React41.useCallback(() => {
9152
9169
  const list = listRef.current;
9153
9170
  let at = -1;
9154
9171
  for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
@@ -9164,19 +9181,19 @@ function useChatEngine(opts) {
9164
9181
  setQueue(queueRef.current.slice());
9165
9182
  drain();
9166
9183
  }, []);
9167
- const clear = React40.useCallback(() => {
9184
+ const clear = React41.useCallback(() => {
9168
9185
  commit([]);
9169
9186
  serverCount.current = 0;
9170
9187
  queueRef.current = [];
9171
9188
  setQueue([]);
9172
9189
  onClear && onClear();
9173
9190
  }, [onClear]);
9174
- const setFeedback = React40.useCallback((id, value) => {
9191
+ const setFeedback = React41.useCallback((id, value) => {
9175
9192
  patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
9176
9193
  const msg = listRef.current.find((m) => m.id === id);
9177
9194
  onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
9178
9195
  }, [onFeedback]);
9179
- const reload = React40.useCallback(async () => {
9196
+ const reload = React41.useCallback(async () => {
9180
9197
  if (!threadRef.current) return;
9181
9198
  setStatus("loading");
9182
9199
  try {
@@ -9214,10 +9231,10 @@ var ChatKit = {
9214
9231
  };
9215
9232
 
9216
9233
  // src/components/chat/ChatTranscript.tsx
9217
- var React42 = __toESM(require("react"), 1);
9234
+ var React43 = __toESM(require("react"), 1);
9218
9235
 
9219
9236
  // src/components/chat/ChatTurn.tsx
9220
- var React41 = __toESM(require("react"), 1);
9237
+ var React42 = __toESM(require("react"), 1);
9221
9238
  var import_jsx_runtime73 = require("react/jsx-runtime");
9222
9239
  function JsonView({ value }) {
9223
9240
  let text;
@@ -9254,7 +9271,7 @@ function PacketCard({ packet, schema, render, onApply, applied }) {
9254
9271
  ] });
9255
9272
  }
9256
9273
  function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
9257
- const [open, setOpen] = React41.useState(defaultOpen);
9274
+ const [open, setOpen] = React42.useState(defaultOpen);
9258
9275
  if (!text) return null;
9259
9276
  return /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("div", { className: "fdc-think" + (open ? " is-open" : ""), children: [
9260
9277
  /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
@@ -9271,7 +9288,7 @@ function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
9271
9288
  ] });
9272
9289
  }
9273
9290
  function Citations({ items = [], onOpen }) {
9274
- const [open, setOpen] = React41.useState(false);
9291
+ const [open, setOpen] = React42.useState(false);
9275
9292
  if (!items.length) return null;
9276
9293
  return /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("div", { className: "fdc-cites", children: [
9277
9294
  /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
@@ -9297,7 +9314,7 @@ function clampText(text, max) {
9297
9314
  return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
9298
9315
  }
9299
9316
  function MessageBody({ message: m, ctx }) {
9300
- const [expanded, setExpanded] = React41.useState(false);
9317
+ const [expanded, setExpanded] = React42.useState(false);
9301
9318
  const isUser = m.role === "user";
9302
9319
  const raw = m.text || "";
9303
9320
  const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
@@ -9364,9 +9381,9 @@ function MessageBody({ message: m, ctx }) {
9364
9381
  ] });
9365
9382
  }
9366
9383
  function useCopyRun() {
9367
- const [done, setDone] = React41.useState(false);
9368
- const t = React41.useRef(null);
9369
- React41.useEffect(() => () => {
9384
+ const [done, setDone] = React42.useState(false);
9385
+ const t = React42.useRef(null);
9386
+ React42.useEffect(() => () => {
9370
9387
  if (t.current) clearTimeout(t.current);
9371
9388
  }, []);
9372
9389
  return [done, (text) => {
@@ -9393,7 +9410,7 @@ function RunActions({ group, ctx }) {
9393
9410
  ] }),
9394
9411
  isAssistant && ctx.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("button", { type: "button", className: "fdc-act", onClick: ctx.onRetry, "aria-label": "Retry this turn", children: /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
9395
9412
  group.role === "user" && ctx.onEdit ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("button", { type: "button", className: "fdc-act", onClick: () => ctx.onEdit(last), "aria-label": "Edit and resend", children: /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-pencil-simple", "aria-hidden": "true" }) }) : null,
9396
- isAssistant && ctx.onFeedback ? /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)(React41.Fragment, { children: [
9413
+ isAssistant && ctx.onFeedback ? /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)(React42.Fragment, { children: [
9397
9414
  /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("button", { type: "button", className: "fdc-act" + (fb === "up" ? " is-on" : ""), onClick: () => ctx.onFeedback(last.id, "up"), "aria-pressed": fb === "up", "aria-label": "Good response", children: /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-thumbs-up", "aria-hidden": "true" }) }),
9398
9415
  /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("button", { type: "button", className: "fdc-act" + (fb === "down" ? " is-on" : ""), onClick: () => ctx.onFeedback(last.id, "down"), "aria-pressed": fb === "down", "aria-label": "Bad response", children: /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-thumbs-down", "aria-hidden": "true" }) })
9399
9416
  ] }) : null,
@@ -9488,10 +9505,10 @@ function ChatTranscript({
9488
9505
  renderEmpty,
9489
9506
  className = ""
9490
9507
  }) {
9491
- const scroller = React42.useRef(null);
9492
- const stick = React42.useRef(true);
9493
- const [pill, setPill] = React42.useState(0);
9494
- const seen = React42.useRef(0);
9508
+ const scroller = React43.useRef(null);
9509
+ const stick = React43.useRef(true);
9510
+ const [pill, setPill] = React43.useState(0);
9511
+ const seen = React43.useRef(0);
9495
9512
  const toBottom = (smooth) => {
9496
9513
  const el = scroller.current;
9497
9514
  if (!el) return;
@@ -9510,7 +9527,7 @@ function ChatTranscript({
9510
9527
  seen.current = messages.length;
9511
9528
  }
9512
9529
  };
9513
- React42.useLayoutEffect(() => {
9530
+ React43.useLayoutEffect(() => {
9514
9531
  const el = scroller.current;
9515
9532
  if (!el) return;
9516
9533
  if (stick.current) {
@@ -9518,7 +9535,7 @@ function ChatTranscript({
9518
9535
  seen.current = messages.length;
9519
9536
  } else setPill(Math.max(0, messages.length - seen.current));
9520
9537
  }, [messages]);
9521
- React42.useEffect(() => {
9538
+ React43.useEffect(() => {
9522
9539
  const el = scroller.current;
9523
9540
  const inner = el && el.firstChild;
9524
9541
  if (!el || !inner || typeof ResizeObserver === "undefined") return;
@@ -9528,7 +9545,7 @@ function ChatTranscript({
9528
9545
  ro.observe(inner);
9529
9546
  return () => ro.disconnect();
9530
9547
  }, []);
9531
- const groups = React42.useMemo(() => groupMessages(messages), [messages]);
9548
+ const groups = React43.useMemo(() => groupMessages(messages), [messages]);
9532
9549
  const empty = !messages.length && status === "ready";
9533
9550
  return /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
9534
9551
  /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
@@ -9552,7 +9569,7 @@ function ChatTranscript({
9552
9569
  const prev = groups[i - 1];
9553
9570
  const k = dayKey(g.messages[0].timestamp);
9554
9571
  const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
9555
- return /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)(React42.Fragment, { children: [
9572
+ return /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)(React43.Fragment, { children: [
9556
9573
  showDay ? /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("div", { className: "fdc-day", children: /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { children: dayLabel(k) }) }) : null,
9557
9574
  /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(ChatTurn, { group: g, ctx })
9558
9575
  ] }, g.key || i);
@@ -9569,7 +9586,7 @@ function ChatTranscript({
9569
9586
  var TranscriptKit = { groupMessages };
9570
9587
 
9571
9588
  // src/components/chat/ChatComposer.tsx
9572
- var React43 = __toESM(require("react"), 1);
9589
+ var React44 = __toESM(require("react"), 1);
9573
9590
  var import_jsx_runtime75 = require("react/jsx-runtime");
9574
9591
  function ChatComposer({
9575
9592
  onSubmit,
@@ -9597,17 +9614,17 @@ function ChatComposer({
9597
9614
  onReject,
9598
9615
  onOpenAttachment
9599
9616
  }) {
9600
- const [text, setText] = React43.useState(draft || "");
9601
- const [trigger, setTrigger] = React43.useState(null);
9602
- const [mentionItems, setMentionItems] = React43.useState([]);
9603
- const [listening, setListening] = React43.useState(false);
9604
- const [notice, setNotice] = React43.useState(null);
9605
- const editor = React43.useRef(null);
9606
- const wrap = React43.useRef(null);
9607
- const stopVoice = React43.useRef(null);
9617
+ const [text, setText] = React44.useState(draft || "");
9618
+ const [trigger, setTrigger] = React44.useState(null);
9619
+ const [mentionItems, setMentionItems] = React44.useState([]);
9620
+ const [listening, setListening] = React44.useState(false);
9621
+ const [notice, setNotice] = React44.useState(null);
9622
+ const editor = React44.useRef(null);
9623
+ const wrap = React44.useRef(null);
9624
+ const stopVoice = React44.useRef(null);
9608
9625
  const staged = useStagedFiles(fileUploadHandler, { onError: () => {
9609
9626
  } });
9610
- React43.useEffect(() => {
9627
+ React44.useEffect(() => {
9611
9628
  if (draft != null && draft !== text) setText(draft);
9612
9629
  }, [draft]);
9613
9630
  const change = (v) => {
@@ -9641,7 +9658,7 @@ function ChatComposer({
9641
9658
  e.preventDefault();
9642
9659
  staged.add(found.files);
9643
9660
  };
9644
- React43.useEffect(() => {
9661
+ React44.useEffect(() => {
9645
9662
  if (!trigger || trigger.type !== "mention" || !mentionSources) {
9646
9663
  setMentionItems([]);
9647
9664
  return;
@@ -9659,7 +9676,7 @@ function ChatComposer({
9659
9676
  const q = (trigger.query || "").toLowerCase();
9660
9677
  setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
9661
9678
  }, [trigger, mentionSources]);
9662
- const slashItems = React43.useMemo(() => {
9679
+ const slashItems = React44.useMemo(() => {
9663
9680
  if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
9664
9681
  const q = (trigger.query || "").toLowerCase();
9665
9682
  return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
@@ -9833,12 +9850,12 @@ function ChatComposer({
9833
9850
  }
9834
9851
 
9835
9852
  // src/components/chat/ChatSessionBar.tsx
9836
- var React44 = __toESM(require("react"), 1);
9853
+ var React45 = __toESM(require("react"), 1);
9837
9854
  var import_jsx_runtime76 = require("react/jsx-runtime");
9838
9855
  var compact2 = meterFormats.compact;
9839
9856
  function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
9840
- const [open, setOpen] = React44.useState(false);
9841
- const anchor = React44.useRef(null);
9857
+ const [open, setOpen] = React45.useState(false);
9858
+ const anchor = React45.useRef(null);
9842
9859
  const stats = sessionStats || null;
9843
9860
  const cu = contextUsage || null;
9844
9861
  const limits = usageLimits || null;
@@ -9853,7 +9870,7 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
9853
9870
  if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
9854
9871
  if (cu) bits.push(pct + "% context");
9855
9872
  const expandable = !!(cu || limits);
9856
- return /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(React44.Fragment, { children: [
9873
+ return /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(React45.Fragment, { children: [
9857
9874
  /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "fdc-bar", children: [
9858
9875
  /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(
9859
9876
  "button",
@@ -9994,7 +10011,7 @@ function ModelControls({
9994
10011
  ] })
9995
10012
  });
9996
10013
  }
9997
- return /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(React44.Fragment, { children: [
10014
+ return /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(React45.Fragment, { children: [
9998
10015
  /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
9999
10016
  MenuButton,
10000
10017
  {
@@ -10111,11 +10128,11 @@ function AgentChatPanel({
10111
10128
  onFeedback,
10112
10129
  onEditMessage
10113
10130
  }) {
10114
- const [panelWidth, setPanelWidth] = React45.useState(width);
10115
- const [applied, setApplied] = React45.useState({});
10116
- const [draft, setDraft] = React45.useState("");
10117
- const dragging = React45.useRef(null);
10118
- React45.useEffect(() => setPanelWidth(width), [width]);
10131
+ const [panelWidth, setPanelWidth] = React46.useState(width);
10132
+ const [applied, setApplied] = React46.useState({});
10133
+ const [draft, setDraft] = React46.useState("");
10134
+ const dragging = React46.useRef(null);
10135
+ React46.useEffect(() => setPanelWidth(width), [width]);
10119
10136
  const engine = useChatEngine({
10120
10137
  contextType,
10121
10138
  contextId,
@@ -10319,7 +10336,7 @@ function AgentChatPanel({
10319
10336
  }
10320
10337
 
10321
10338
  // src/kits/query.ts
10322
- var React46 = __toESM(require("react"), 1);
10339
+ var React47 = __toESM(require("react"), 1);
10323
10340
  function eqFilter(get2) {
10324
10341
  return (row, value) => Array.isArray(value) ? value.includes(get2(row)) : get2(row) === value;
10325
10342
  }
@@ -10351,22 +10368,22 @@ function compare(a, b, dir) {
10351
10368
  var API = null;
10352
10369
  var PREFS = null;
10353
10370
  function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
10354
- const [query, setQuery] = React46.useState(() => {
10371
+ const [query, setQuery] = React47.useState(() => {
10355
10372
  const store = PREFS || window.PlannerPrefs;
10356
10373
  const saved = prefsKey && store ? store.getTable(prefsKey) : {};
10357
10374
  return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
10358
10375
  });
10359
- const savePref = React46.useCallback((patch2) => {
10376
+ const savePref = React47.useCallback((patch2) => {
10360
10377
  const store = PREFS || window.PlannerPrefs;
10361
10378
  if (prefsKey && store) store.setTable(prefsKey, patch2);
10362
10379
  }, [prefsKey]);
10363
- const [res, setRes] = React46.useState(null);
10364
- const [loading, setLoading] = React46.useState(true);
10365
- const seq2 = React46.useRef(0);
10380
+ const [res, setRes] = React47.useState(null);
10381
+ const [loading, setLoading] = React47.useState(true);
10382
+ const seq2 = React47.useRef(0);
10366
10383
  const depKey = (deps || []).join("|");
10367
10384
  const paramKey = JSON.stringify(params || {});
10368
10385
  const queryKey = JSON.stringify(query);
10369
- React46.useEffect(() => {
10386
+ React47.useEffect(() => {
10370
10387
  const id = ++seq2.current;
10371
10388
  setLoading(true);
10372
10389
  const t = setTimeout(() => {
@@ -10820,6 +10837,7 @@ function createVersionStore(initialState, options) {
10820
10837
  meterFormats,
10821
10838
  modifierLabel,
10822
10839
  pastedTextName,
10840
+ pluralizeUnit,
10823
10841
  preferenceScore,
10824
10842
  preferenceSegments,
10825
10843
  rangeFilter,