@flytedan/flytebot-design-system 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -205,7 +205,14 @@ function Popover({
205
205
  bottom: pos.bottom == null ? "auto" : pos.bottom,
206
206
  width: matchWidth ? pos.width : width,
207
207
  minWidth: minWidth || (matchWidth ? void 0 : 200),
208
- maxHeight: Math.min(maxHeight || 420, pos.maxH),
208
+ // Size to content by default — cap only at real available room between the
209
+ // anchor and the viewport edge (pos.maxH, computed by usePopoverPosition).
210
+ // A caller-supplied `maxHeight` narrows that further (e.g. a long menu that
211
+ // should scroll well before it reaches the viewport edge); it must never
212
+ // widen past pos.maxH, which is why it's still Math.min'd against it. There
213
+ // is intentionally no arbitrary default here — an unrequested cap would clip
214
+ // ordinary content that simply happens to be taller than some fixed number.
215
+ maxHeight: maxHeight != null ? Math.min(maxHeight, pos.maxH) : pos.maxH,
209
216
  transformOrigin: pos.side === "top" ? "bottom center" : "top center",
210
217
  zIndex: 140,
211
218
  ...style
@@ -2421,56 +2428,140 @@ function StepList({
2421
2428
  ] });
2422
2429
  }
2423
2430
 
2424
- // src/components/forms/Checkbox.tsx
2431
+ // src/components/data/VirtualList.tsx
2425
2432
  import * as React15 from "react";
2426
2433
  import { jsx as jsx37, jsxs as jsxs33 } from "react/jsx-runtime";
2427
- function Checkbox({ label, description, card = false, indeterminate = false, className = "", ...rest }) {
2428
- const ref = React15.useRef(null);
2434
+ var VIRTUAL_LIST_BUFFER_ROWS = 20;
2435
+ function computeVirtualWindow(opts) {
2436
+ const { scrollTop, viewportHeight, itemHeight, itemCount, bufferRows = VIRTUAL_LIST_BUFFER_ROWS } = opts;
2437
+ if (itemCount <= 0 || itemHeight <= 0) {
2438
+ return { visibleStart: 0, visibleEnd: -1, startIndex: 0, endIndex: -1, totalHeight: 0, offsetY: 0 };
2439
+ }
2440
+ const lastPossible = itemCount - 1;
2441
+ const visibleStart = Math.min(lastPossible, Math.max(0, Math.floor(scrollTop / itemHeight)));
2442
+ const visibleRows = Math.max(1, Math.ceil(viewportHeight / itemHeight));
2443
+ const visibleEnd = Math.min(lastPossible, visibleStart + visibleRows - 1);
2444
+ const startIndex = Math.max(0, visibleStart - bufferRows);
2445
+ const endIndex = Math.min(lastPossible, visibleEnd + bufferRows);
2446
+ return {
2447
+ visibleStart,
2448
+ visibleEnd,
2449
+ startIndex,
2450
+ endIndex,
2451
+ totalHeight: itemCount * itemHeight,
2452
+ offsetY: startIndex * itemHeight
2453
+ };
2454
+ }
2455
+ function computeNeedMore(win, itemCount, bufferRows = VIRTUAL_LIST_BUFFER_ROWS) {
2456
+ if (itemCount <= 0) return { start: true, end: true };
2457
+ return {
2458
+ start: win.visibleStart <= bufferRows,
2459
+ end: itemCount - 1 - win.visibleEnd <= bufferRows
2460
+ };
2461
+ }
2462
+ function VirtualList({
2463
+ items,
2464
+ itemHeight,
2465
+ renderItem,
2466
+ onNeedMore,
2467
+ hasMore,
2468
+ loading = false,
2469
+ keyOf,
2470
+ height = 400,
2471
+ emptyState,
2472
+ className = "",
2473
+ style
2474
+ }) {
2475
+ const [scrollTop, setScrollTop] = React15.useState(0);
2476
+ const requested = React15.useRef({ start: null, end: null });
2477
+ const win = React15.useMemo(
2478
+ () => computeVirtualWindow({ scrollTop, viewportHeight: height, itemHeight, itemCount: items.length }),
2479
+ [scrollTop, height, itemHeight, items.length]
2480
+ );
2481
+ const need = React15.useMemo(() => computeNeedMore(win, items.length), [win, items.length]);
2482
+ const wantStart = need.start && hasMore?.start !== false;
2483
+ const wantEnd = need.end && hasMore?.end !== false;
2429
2484
  React15.useEffect(() => {
2430
- if (ref.current) ref.current.indeterminate = indeterminate;
2431
- }, [indeterminate]);
2432
- return /* @__PURE__ */ jsxs33("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
2433
- /* @__PURE__ */ jsxs33("span", { className: "fd-choice-input", children: [
2434
- /* @__PURE__ */ jsx37("input", { ref, type: "checkbox", ...rest }),
2435
- /* @__PURE__ */ jsx37("span", { className: "fd-choice-box", "aria-hidden": "true", children: /* @__PURE__ */ jsx37("i", { className: indeterminate ? "ph ph-minus" : "ph ph-check" }) })
2436
- ] }),
2437
- /* @__PURE__ */ jsxs33("span", { className: "fd-choice-text", children: [
2438
- /* @__PURE__ */ jsx37("span", { className: "fd-choice-title", children: label }),
2439
- description ? /* @__PURE__ */ jsx37("span", { className: "fd-choice-desc", children: description }) : null
2440
- ] })
2441
- ] });
2485
+ if (loading || !wantStart || requested.current.start === items.length) return;
2486
+ requested.current.start = items.length;
2487
+ onNeedMore("start");
2488
+ }, [wantStart, loading, items.length, onNeedMore]);
2489
+ React15.useEffect(() => {
2490
+ if (loading || !wantEnd || requested.current.end === items.length) return;
2491
+ requested.current.end = items.length;
2492
+ onNeedMore("end");
2493
+ }, [wantEnd, loading, items.length, onNeedMore]);
2494
+ if (!items.length && !loading && emptyState) {
2495
+ return /* @__PURE__ */ jsx37("div", { className: ["fd-vlist", className].filter(Boolean).join(" "), style: { height, overflow: "auto", ...style }, children: emptyState });
2496
+ }
2497
+ const rows = [];
2498
+ for (let i = win.startIndex; i <= win.endIndex; i++) {
2499
+ const item = items[i];
2500
+ if (item === void 0) continue;
2501
+ rows.push(
2502
+ /* @__PURE__ */ jsx37("div", { style: { height: itemHeight, boxSizing: "border-box" }, children: renderItem(item, i) }, keyOf(item))
2503
+ );
2504
+ }
2505
+ return /* @__PURE__ */ jsxs33(
2506
+ "div",
2507
+ {
2508
+ className: ["fd-vlist", className].filter(Boolean).join(" "),
2509
+ style: { height, overflowY: "auto", overflowX: "hidden", position: "relative", ...style },
2510
+ onScroll: (e) => setScrollTop(e.currentTarget.scrollTop),
2511
+ children: [
2512
+ /* @__PURE__ */ jsx37("div", { style: { height: win.totalHeight, position: "relative" }, children: /* @__PURE__ */ jsx37("div", { style: { position: "absolute", top: win.offsetY, left: 0, right: 0 }, children: rows }) }),
2513
+ loading ? /* @__PURE__ */ jsx37("div", { style: { position: "sticky", bottom: 0, left: 0, right: 0, display: "grid", placeItems: "center", padding: "8px 0", background: "var(--surface)" }, children: /* @__PURE__ */ jsx37("span", { className: "fd-spinner", "aria-hidden": "true" }) }) : null
2514
+ ]
2515
+ }
2516
+ );
2442
2517
  }
2443
2518
 
2444
- // src/components/forms/Radio.tsx
2519
+ // src/components/data/EntityRow.tsx
2445
2520
  import { jsx as jsx38, jsxs as jsxs34 } from "react/jsx-runtime";
2446
- function Radio({ label, description, card = false, className = "", ...rest }) {
2447
- return /* @__PURE__ */ jsxs34("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
2448
- /* @__PURE__ */ jsxs34("span", { className: "fd-choice-input", children: [
2449
- /* @__PURE__ */ jsx38("input", { type: "radio", ...rest }),
2450
- /* @__PURE__ */ jsx38("span", { className: "fd-choice-box fd-choice-box-round", "aria-hidden": "true", children: /* @__PURE__ */ jsx38("span", { className: "fd-choice-dot" }) })
2451
- ] }),
2452
- /* @__PURE__ */ jsxs34("span", { className: "fd-choice-text", children: [
2453
- /* @__PURE__ */ jsx38("span", { className: "fd-choice-title", children: label }),
2454
- description ? /* @__PURE__ */ jsx38("span", { className: "fd-choice-desc", children: description }) : null
2455
- ] })
2456
- ] });
2521
+ function EntityRow({ title, meta, action, draggable = false, onDragStart, onDragEnd, style, className = "" }) {
2522
+ return /* @__PURE__ */ jsxs34(
2523
+ "div",
2524
+ {
2525
+ draggable,
2526
+ onDragStart,
2527
+ onDragEnd,
2528
+ className: ["fd-erow", className].filter(Boolean).join(" "),
2529
+ style: {
2530
+ display: "flex",
2531
+ alignItems: "center",
2532
+ gap: 8,
2533
+ height: "100%",
2534
+ padding: "0 8px",
2535
+ borderRadius: 6,
2536
+ cursor: draggable ? "grab" : void 0,
2537
+ ...style
2538
+ },
2539
+ children: [
2540
+ draggable ? /* @__PURE__ */ jsx38("i", { className: "ph ph-dots-six-vertical", "aria-hidden": "true", style: { fontSize: 13, flex: "none", color: "var(--text-muted)" } }) : null,
2541
+ /* @__PURE__ */ jsxs34("span", { style: { flex: 1, minWidth: 0, display: "flex", flexDirection: "column", gap: 1 }, children: [
2542
+ /* @__PURE__ */ jsx38("span", { className: "fd-body-sm", style: { fontWeight: 600, color: "var(--text)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }, children: title }),
2543
+ meta ? /* @__PURE__ */ jsx38("span", { style: { fontSize: "var(--overline-size)", color: "var(--text-muted)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }, children: meta }) : null
2544
+ ] }),
2545
+ action ? /* @__PURE__ */ jsx38(
2546
+ IconButton,
2547
+ {
2548
+ icon: action.icon,
2549
+ label: action.label,
2550
+ size: "sm",
2551
+ onClick: action.onClick,
2552
+ style: { color: action.tone === "add" ? "var(--ok-text)" : action.tone === "remove" ? "var(--danger-text)" : void 0 }
2553
+ }
2554
+ ) : null
2555
+ ]
2556
+ }
2557
+ );
2457
2558
  }
2458
2559
 
2459
- // src/components/forms/Switch.tsx
2460
- import { jsx as jsx39, jsxs as jsxs35 } from "react/jsx-runtime";
2461
- function Switch({ label, description, className = "", ...rest }) {
2462
- return /* @__PURE__ */ jsxs35("label", { className: ["fd-switch", className].filter(Boolean).join(" "), children: [
2463
- /* @__PURE__ */ jsx39("input", { type: "checkbox", role: "switch", ...rest }),
2464
- /* @__PURE__ */ jsx39("span", { className: "fd-switch-track", children: /* @__PURE__ */ jsx39("span", { className: "fd-switch-thumb" }) }),
2465
- label ? /* @__PURE__ */ jsxs35("span", { className: "fd-choice-text", children: [
2466
- /* @__PURE__ */ jsx39("span", { className: "fd-switch-label", children: label }),
2467
- description ? /* @__PURE__ */ jsx39("span", { className: "fd-choice-desc", children: description }) : null
2468
- ] }) : null
2469
- ] });
2470
- }
2560
+ // src/components/data/TransferList.tsx
2561
+ import * as React16 from "react";
2471
2562
 
2472
2563
  // src/components/forms/Input.tsx
2473
- import { jsx as jsx40, jsxs as jsxs36 } from "react/jsx-runtime";
2564
+ import { jsx as jsx39, jsxs as jsxs35 } from "react/jsx-runtime";
2474
2565
  function Input({
2475
2566
  label,
2476
2567
  help,
@@ -2498,27 +2589,27 @@ function Input({
2498
2589
  size === "lg" ? "fd-input-lg" : "",
2499
2590
  className
2500
2591
  ].filter(Boolean).join(" ");
2501
- return /* @__PURE__ */ jsxs36("div", { className: "fd-field", style, children: [
2502
- label ? /* @__PURE__ */ jsxs36("label", { className: "fd-field-label", htmlFor: fieldId, children: [
2592
+ return /* @__PURE__ */ jsxs35("div", { className: "fd-field", style, children: [
2593
+ label ? /* @__PURE__ */ jsxs35("label", { className: "fd-field-label", htmlFor: fieldId, children: [
2503
2594
  label,
2504
- required ? /* @__PURE__ */ jsx40("span", { className: "fd-field-req", "aria-hidden": "true", children: "*" }) : null
2595
+ required ? /* @__PURE__ */ jsx39("span", { className: "fd-field-req", "aria-hidden": "true", children: "*" }) : null
2505
2596
  ] }) : null,
2506
- /* @__PURE__ */ jsxs36("div", { className: box, children: [
2507
- icon ? /* @__PURE__ */ jsx40("span", { className: "fd-input-icon", children: /* @__PURE__ */ jsx40("i", { className: "ph ph-" + icon, "aria-hidden": "true" }) }) : null,
2508
- prefix ? /* @__PURE__ */ jsx40("span", { className: "fd-input-affix", children: prefix }) : null,
2509
- /* @__PURE__ */ jsx40("input", { id: fieldId, disabled, style: inputStyle, "aria-invalid": error ? "true" : void 0, ...rest }),
2510
- loading ? /* @__PURE__ */ jsx40("span", { className: "fd-spinner", style: { color: "var(--text-muted)" }, "aria-label": "Loading" }) : null,
2511
- suffix && !loading ? /* @__PURE__ */ jsx40("span", { className: "fd-input-affix", children: suffix }) : null
2597
+ /* @__PURE__ */ jsxs35("div", { className: box, children: [
2598
+ icon ? /* @__PURE__ */ jsx39("span", { className: "fd-input-icon", children: /* @__PURE__ */ jsx39("i", { className: "ph ph-" + icon, "aria-hidden": "true" }) }) : null,
2599
+ prefix ? /* @__PURE__ */ jsx39("span", { className: "fd-input-affix", children: prefix }) : null,
2600
+ /* @__PURE__ */ jsx39("input", { id: fieldId, disabled, style: inputStyle, "aria-invalid": error ? "true" : void 0, ...rest }),
2601
+ loading ? /* @__PURE__ */ jsx39("span", { className: "fd-spinner", style: { color: "var(--text-muted)" }, "aria-label": "Loading" }) : null,
2602
+ suffix && !loading ? /* @__PURE__ */ jsx39("span", { className: "fd-input-affix", children: suffix }) : null
2512
2603
  ] }),
2513
- error ? /* @__PURE__ */ jsxs36("span", { className: "fd-field-error", children: [
2514
- /* @__PURE__ */ jsx40("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
2604
+ error ? /* @__PURE__ */ jsxs35("span", { className: "fd-field-error", children: [
2605
+ /* @__PURE__ */ jsx39("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
2515
2606
  error
2516
- ] }) : help ? /* @__PURE__ */ jsx40("span", { className: "fd-field-help", children: help }) : null
2607
+ ] }) : help ? /* @__PURE__ */ jsx39("span", { className: "fd-field-help", children: help }) : null
2517
2608
  ] });
2518
2609
  }
2519
2610
 
2520
2611
  // src/components/forms/SearchField.tsx
2521
- import { jsx as jsx41 } from "react/jsx-runtime";
2612
+ import { jsx as jsx40 } from "react/jsx-runtime";
2522
2613
  function SearchField({
2523
2614
  value,
2524
2615
  onChange,
@@ -2533,7 +2624,7 @@ function SearchField({
2533
2624
  ...rest
2534
2625
  }) {
2535
2626
  const clear = onClear || (() => onChange(""));
2536
- return /* @__PURE__ */ jsx41(
2627
+ return /* @__PURE__ */ jsx40(
2537
2628
  Input,
2538
2629
  {
2539
2630
  id,
@@ -2546,14 +2637,14 @@ function SearchField({
2546
2637
  style,
2547
2638
  className,
2548
2639
  onChange: (e) => onChange(e.target.value),
2549
- suffix: value ? /* @__PURE__ */ jsx41(
2640
+ suffix: value ? /* @__PURE__ */ jsx40(
2550
2641
  "button",
2551
2642
  {
2552
2643
  type: "button",
2553
2644
  "aria-label": "Clear search",
2554
2645
  onClick: clear,
2555
2646
  style: { all: "unset", cursor: "pointer", color: "var(--text-muted)", display: "grid", placeItems: "center", padding: 2 },
2556
- children: /* @__PURE__ */ jsx41("i", { className: "ph ph-x-circle", style: { fontSize: 15 }, "aria-hidden": "true" })
2647
+ children: /* @__PURE__ */ jsx40("i", { className: "ph ph-x-circle", style: { fontSize: 15 }, "aria-hidden": "true" })
2557
2648
  }
2558
2649
  ) : void 0,
2559
2650
  ...rest
@@ -2561,27 +2652,183 @@ function SearchField({
2561
2652
  );
2562
2653
  }
2563
2654
 
2564
- // src/components/forms/Textarea.tsx
2655
+ // src/components/data/TransferList.tsx
2656
+ import { jsx as jsx41, jsxs as jsxs36 } from "react/jsx-runtime";
2657
+ var emptyHasMore = {};
2658
+ function TransferList({
2659
+ left,
2660
+ right,
2661
+ keyOf,
2662
+ renderLabel,
2663
+ renderMeta,
2664
+ onMove,
2665
+ itemHeight = 44,
2666
+ listHeight = 440,
2667
+ className = ""
2668
+ }) {
2669
+ const [dragging, setDragging] = React16.useState(null);
2670
+ const [dragOverSide, setDragOverSide] = React16.useState(null);
2671
+ const startDrag = (e, item, from) => {
2672
+ const key = keyOf(item);
2673
+ setDragging({ key, from });
2674
+ e.dataTransfer.effectAllowed = "move";
2675
+ e.dataTransfer.setData("text/plain", String(key));
2676
+ };
2677
+ const endDrag = () => {
2678
+ setDragging(null);
2679
+ setDragOverSide(null);
2680
+ };
2681
+ const findItem = (side, key) => (side === "left" ? left.items : right.items).find((it) => keyOf(it) === key);
2682
+ const dropOnSide = (e, side) => {
2683
+ e.preventDefault();
2684
+ setDragOverSide(null);
2685
+ if (!dragging || dragging.from === side) return;
2686
+ const item = findItem(dragging.from, dragging.key);
2687
+ if (item !== void 0) onMove(item, dragging.from, side);
2688
+ setDragging(null);
2689
+ };
2690
+ const renderSide = (side, cfg, opposite) => /* @__PURE__ */ jsxs36(
2691
+ "div",
2692
+ {
2693
+ style: {
2694
+ flex: 1,
2695
+ minWidth: 0,
2696
+ display: "flex",
2697
+ flexDirection: "column",
2698
+ gap: 8,
2699
+ padding: 10,
2700
+ borderRadius: 10,
2701
+ border: "1px solid " + (dragOverSide === side ? "var(--brand)" : "var(--border)"),
2702
+ background: "var(--surface)"
2703
+ },
2704
+ onDragOver: (e) => {
2705
+ if (!dragging || dragging.from === side) return;
2706
+ e.preventDefault();
2707
+ e.dataTransfer.dropEffect = "move";
2708
+ if (dragOverSide !== side) setDragOverSide(side);
2709
+ },
2710
+ onDragLeave: (e) => {
2711
+ if (e.currentTarget.contains(e.relatedTarget)) return;
2712
+ setDragOverSide((s) => s === side ? null : s);
2713
+ },
2714
+ onDrop: (e) => dropOnSide(e, side),
2715
+ children: [
2716
+ cfg.label ? /* @__PURE__ */ jsxs36("span", { className: "fd-overline fd-muted", children: [
2717
+ cfg.label,
2718
+ cfg.total != null ? " (" + cfg.total.toLocaleString() + ")" : ""
2719
+ ] }) : null,
2720
+ /* @__PURE__ */ jsxs36("span", { className: "fd-row", style: { gap: 8 }, children: [
2721
+ /* @__PURE__ */ jsx41(SearchField, { value: cfg.search, onChange: cfg.onSearchChange, placeholder: "Search", "aria-label": (cfg.label || side) + " search", style: { flex: 1 } }),
2722
+ /* @__PURE__ */ jsx41(SortMenu, { fields: cfg.sortFields, sort: cfg.sort, onSort: cfg.onSort })
2723
+ ] }),
2724
+ /* @__PURE__ */ jsx41(
2725
+ VirtualList,
2726
+ {
2727
+ items: cfg.items,
2728
+ itemHeight,
2729
+ height: listHeight,
2730
+ keyOf,
2731
+ loading: cfg.loading,
2732
+ hasMore: cfg.hasMore || emptyHasMore,
2733
+ onNeedMore: cfg.onNeedMore,
2734
+ emptyState: /* @__PURE__ */ jsx41(EmptyState, { icon: "tray", title: "Nothing here" }),
2735
+ renderItem: (item) => /* @__PURE__ */ jsx41(
2736
+ EntityRow,
2737
+ {
2738
+ title: renderLabel(item),
2739
+ meta: renderMeta ? renderMeta(item) : void 0,
2740
+ draggable: true,
2741
+ onDragStart: (e) => startDrag(e, item, side),
2742
+ onDragEnd: endDrag,
2743
+ style: { opacity: dragging && dragging.from === side && dragging.key === keyOf(item) ? 0.4 : 1 },
2744
+ action: {
2745
+ icon: side === "left" ? "plus" : "minus",
2746
+ label: (side === "left" ? "Move to " : "Move from ") + (side === "left" ? right.label || "the other list" : left.label || "the other list"),
2747
+ tone: side === "left" ? "add" : "remove",
2748
+ onClick: () => onMove(item, side, opposite)
2749
+ }
2750
+ }
2751
+ )
2752
+ }
2753
+ )
2754
+ ]
2755
+ }
2756
+ );
2757
+ return /* @__PURE__ */ jsxs36("div", { className: ["fd-tlist", className].filter(Boolean).join(" "), style: { display: "flex", gap: 16, alignItems: "flex-start" }, children: [
2758
+ renderSide("left", left, "right"),
2759
+ renderSide("right", right, "left")
2760
+ ] });
2761
+ }
2762
+
2763
+ // src/components/forms/Checkbox.tsx
2764
+ import * as React17 from "react";
2565
2765
  import { jsx as jsx42, jsxs as jsxs37 } from "react/jsx-runtime";
2766
+ function Checkbox({ label, description, card = false, indeterminate = false, className = "", ...rest }) {
2767
+ const ref = React17.useRef(null);
2768
+ React17.useEffect(() => {
2769
+ if (ref.current) ref.current.indeterminate = indeterminate;
2770
+ }, [indeterminate]);
2771
+ return /* @__PURE__ */ jsxs37("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
2772
+ /* @__PURE__ */ jsxs37("span", { className: "fd-choice-input", children: [
2773
+ /* @__PURE__ */ jsx42("input", { ref, type: "checkbox", ...rest }),
2774
+ /* @__PURE__ */ jsx42("span", { className: "fd-choice-box", "aria-hidden": "true", children: /* @__PURE__ */ jsx42("i", { className: indeterminate ? "ph ph-minus" : "ph ph-check" }) })
2775
+ ] }),
2776
+ /* @__PURE__ */ jsxs37("span", { className: "fd-choice-text", children: [
2777
+ /* @__PURE__ */ jsx42("span", { className: "fd-choice-title", children: label }),
2778
+ description ? /* @__PURE__ */ jsx42("span", { className: "fd-choice-desc", children: description }) : null
2779
+ ] })
2780
+ ] });
2781
+ }
2782
+
2783
+ // src/components/forms/Radio.tsx
2784
+ import { jsx as jsx43, jsxs as jsxs38 } from "react/jsx-runtime";
2785
+ function Radio({ label, description, card = false, className = "", ...rest }) {
2786
+ return /* @__PURE__ */ jsxs38("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
2787
+ /* @__PURE__ */ jsxs38("span", { className: "fd-choice-input", children: [
2788
+ /* @__PURE__ */ jsx43("input", { type: "radio", ...rest }),
2789
+ /* @__PURE__ */ jsx43("span", { className: "fd-choice-box fd-choice-box-round", "aria-hidden": "true", children: /* @__PURE__ */ jsx43("span", { className: "fd-choice-dot" }) })
2790
+ ] }),
2791
+ /* @__PURE__ */ jsxs38("span", { className: "fd-choice-text", children: [
2792
+ /* @__PURE__ */ jsx43("span", { className: "fd-choice-title", children: label }),
2793
+ description ? /* @__PURE__ */ jsx43("span", { className: "fd-choice-desc", children: description }) : null
2794
+ ] })
2795
+ ] });
2796
+ }
2797
+
2798
+ // src/components/forms/Switch.tsx
2799
+ import { jsx as jsx44, jsxs as jsxs39 } from "react/jsx-runtime";
2800
+ function Switch({ label, description, className = "", ...rest }) {
2801
+ return /* @__PURE__ */ jsxs39("label", { className: ["fd-switch", className].filter(Boolean).join(" "), children: [
2802
+ /* @__PURE__ */ jsx44("input", { type: "checkbox", role: "switch", ...rest }),
2803
+ /* @__PURE__ */ jsx44("span", { className: "fd-switch-track", children: /* @__PURE__ */ jsx44("span", { className: "fd-switch-thumb" }) }),
2804
+ label ? /* @__PURE__ */ jsxs39("span", { className: "fd-choice-text", children: [
2805
+ /* @__PURE__ */ jsx44("span", { className: "fd-switch-label", children: label }),
2806
+ description ? /* @__PURE__ */ jsx44("span", { className: "fd-choice-desc", children: description }) : null
2807
+ ] }) : null
2808
+ ] });
2809
+ }
2810
+
2811
+ // src/components/forms/Textarea.tsx
2812
+ import { jsx as jsx45, jsxs as jsxs40 } from "react/jsx-runtime";
2566
2813
  function Textarea({ label, help, error, required = false, rows = 4, disabled = false, id, className = "", style, ...rest }) {
2567
2814
  const fieldId = id || (rest.name ? "fd-" + rest.name : void 0);
2568
2815
  const box = ["fd-input", "fd-input-textarea", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : "", className].filter(Boolean).join(" ");
2569
- return /* @__PURE__ */ jsxs37("div", { className: "fd-field", style, children: [
2570
- label ? /* @__PURE__ */ jsxs37("label", { className: "fd-field-label", htmlFor: fieldId, children: [
2816
+ return /* @__PURE__ */ jsxs40("div", { className: "fd-field", style, children: [
2817
+ label ? /* @__PURE__ */ jsxs40("label", { className: "fd-field-label", htmlFor: fieldId, children: [
2571
2818
  label,
2572
- required ? /* @__PURE__ */ jsx42("span", { className: "fd-field-req", children: "*" }) : null
2819
+ required ? /* @__PURE__ */ jsx45("span", { className: "fd-field-req", children: "*" }) : null
2573
2820
  ] }) : null,
2574
- /* @__PURE__ */ jsx42("div", { className: box, children: /* @__PURE__ */ jsx42("textarea", { id: fieldId, rows, disabled, "aria-invalid": error ? "true" : void 0, ...rest }) }),
2575
- error ? /* @__PURE__ */ jsxs37("span", { className: "fd-field-error", children: [
2576
- /* @__PURE__ */ jsx42("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
2821
+ /* @__PURE__ */ jsx45("div", { className: box, children: /* @__PURE__ */ jsx45("textarea", { id: fieldId, rows, disabled, "aria-invalid": error ? "true" : void 0, ...rest }) }),
2822
+ error ? /* @__PURE__ */ jsxs40("span", { className: "fd-field-error", children: [
2823
+ /* @__PURE__ */ jsx45("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
2577
2824
  error
2578
- ] }) : help ? /* @__PURE__ */ jsx42("span", { className: "fd-field-help", children: help }) : null
2825
+ ] }) : help ? /* @__PURE__ */ jsx45("span", { className: "fd-field-help", children: help }) : null
2579
2826
  ] });
2580
2827
  }
2581
2828
 
2582
2829
  // src/components/forms/NumberInput.tsx
2583
- import * as React16 from "react";
2584
- import { jsx as jsx43, jsxs as jsxs38 } from "react/jsx-runtime";
2830
+ import * as React18 from "react";
2831
+ import { jsx as jsx46, jsxs as jsxs41 } from "react/jsx-runtime";
2585
2832
  function NumberInput({
2586
2833
  label,
2587
2834
  help,
@@ -2605,10 +2852,10 @@ function NumberInput({
2605
2852
  const n = Number(String(v == null ? "" : v).replace(/[^0-9.-]/g, ""));
2606
2853
  return isNaN(n) ? null : n;
2607
2854
  };
2608
- const [text, setText] = React16.useState(value == null || value === "" ? "" : String(value));
2609
- const [editing, setEditing] = React16.useState(false);
2610
- const timer = React16.useRef(null);
2611
- React16.useEffect(() => {
2855
+ const [text, setText] = React18.useState(value == null || value === "" ? "" : String(value));
2856
+ const [editing, setEditing] = React18.useState(false);
2857
+ const timer = React18.useRef(null);
2858
+ React18.useEffect(() => {
2612
2859
  if (!editing) setText(value == null || value === "" ? "" : String(value));
2613
2860
  }, [value, editing]);
2614
2861
  const clamp = (n) => Math.min(max, Math.max(min, n));
@@ -2632,7 +2879,7 @@ function NumberInput({
2632
2879
  const release = () => {
2633
2880
  if (timer.current) clearTimeout(timer.current);
2634
2881
  };
2635
- React16.useEffect(() => () => {
2882
+ React18.useEffect(() => () => {
2636
2883
  if (timer.current) clearTimeout(timer.current);
2637
2884
  }, []);
2638
2885
  const shown = editing ? text : (() => {
@@ -2640,14 +2887,14 @@ function NumberInput({
2640
2887
  return n == null ? "" : format ? n.toLocaleString() : String(n);
2641
2888
  })();
2642
2889
  const box = ["fd-input", "fd-input-num", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" ");
2643
- return /* @__PURE__ */ jsxs38("div", { className: ["fd-field", className].filter(Boolean).join(" "), style, children: [
2644
- label ? /* @__PURE__ */ jsxs38("label", { className: "fd-field-label", children: [
2890
+ return /* @__PURE__ */ jsxs41("div", { className: ["fd-field", className].filter(Boolean).join(" "), style, children: [
2891
+ label ? /* @__PURE__ */ jsxs41("label", { className: "fd-field-label", children: [
2645
2892
  label,
2646
- required ? /* @__PURE__ */ jsx43("span", { className: "fd-field-req", children: "*" }) : null
2893
+ required ? /* @__PURE__ */ jsx46("span", { className: "fd-field-req", children: "*" }) : null
2647
2894
  ] }) : null,
2648
- /* @__PURE__ */ jsxs38("div", { className: box, style: { gap: 8 }, children: [
2649
- prefix ? /* @__PURE__ */ jsx43("span", { className: "fd-input-affix", children: prefix }) : null,
2650
- /* @__PURE__ */ jsx43(
2895
+ /* @__PURE__ */ jsxs41("div", { className: box, style: { gap: 8 }, children: [
2896
+ prefix ? /* @__PURE__ */ jsx46("span", { className: "fd-input-affix", children: prefix }) : null,
2897
+ /* @__PURE__ */ jsx46(
2651
2898
  "input",
2652
2899
  {
2653
2900
  inputMode: "numeric",
@@ -2680,9 +2927,9 @@ function NumberInput({
2680
2927
  }
2681
2928
  }
2682
2929
  ),
2683
- suffix ? /* @__PURE__ */ jsx43("span", { className: "fd-input-affix", children: suffix }) : null,
2684
- /* @__PURE__ */ jsxs38("span", { className: "fd-row", style: { gap: 4, flex: "none" }, children: [
2685
- /* @__PURE__ */ jsx43(
2930
+ suffix ? /* @__PURE__ */ jsx46("span", { className: "fd-input-affix", children: suffix }) : null,
2931
+ /* @__PURE__ */ jsxs41("span", { className: "fd-row", style: { gap: 4, flex: "none" }, children: [
2932
+ /* @__PURE__ */ jsx46(
2686
2933
  "button",
2687
2934
  {
2688
2935
  type: "button",
@@ -2692,10 +2939,10 @@ function NumberInput({
2692
2939
  onPointerDown: () => hold(-1),
2693
2940
  onPointerUp: release,
2694
2941
  onPointerLeave: release,
2695
- children: /* @__PURE__ */ jsx43("i", { className: "ph ph-minus" })
2942
+ children: /* @__PURE__ */ jsx46("i", { className: "ph ph-minus" })
2696
2943
  }
2697
2944
  ),
2698
- /* @__PURE__ */ jsx43(
2945
+ /* @__PURE__ */ jsx46(
2699
2946
  "button",
2700
2947
  {
2701
2948
  type: "button",
@@ -2705,26 +2952,26 @@ function NumberInput({
2705
2952
  onPointerDown: () => hold(1),
2706
2953
  onPointerUp: release,
2707
2954
  onPointerLeave: release,
2708
- children: /* @__PURE__ */ jsx43("i", { className: "ph ph-plus" })
2955
+ children: /* @__PURE__ */ jsx46("i", { className: "ph ph-plus" })
2709
2956
  }
2710
2957
  )
2711
2958
  ] })
2712
2959
  ] }),
2713
- error ? /* @__PURE__ */ jsxs38("span", { className: "fd-field-error", children: [
2714
- /* @__PURE__ */ jsx43("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
2960
+ error ? /* @__PURE__ */ jsxs41("span", { className: "fd-field-error", children: [
2961
+ /* @__PURE__ */ jsx46("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
2715
2962
  error
2716
- ] }) : help ? /* @__PURE__ */ jsx43("span", { className: "fd-field-help", children: help }) : null
2963
+ ] }) : help ? /* @__PURE__ */ jsx46("span", { className: "fd-field-help", children: help }) : null
2717
2964
  ] });
2718
2965
  }
2719
2966
 
2720
2967
  // src/components/forms/Select.tsx
2721
- import * as React17 from "react";
2968
+ import * as React19 from "react";
2722
2969
  import { createPortal as createPortal4 } from "react-dom";
2723
- import { jsx as jsx44, jsxs as jsxs39 } from "react/jsx-runtime";
2970
+ import { jsx as jsx47, jsxs as jsxs42 } from "react/jsx-runtime";
2724
2971
  var norm = (o) => typeof o === "string" ? { value: o, label: o } : o;
2725
2972
  function usePopPos(open, ref, estH, estW) {
2726
- const [pos, setPos] = React17.useState(null);
2727
- React17.useLayoutEffect(() => {
2973
+ const [pos, setPos] = React19.useState(null);
2974
+ React19.useLayoutEffect(() => {
2728
2975
  if (!open || !ref.current) {
2729
2976
  setPos(null);
2730
2977
  return;
@@ -2788,14 +3035,14 @@ function Select({
2788
3035
  const vals = multiple ? Array.isArray(value) ? value : value ? [value] : [] : [];
2789
3036
  const isOn = (v) => multiple ? vals.includes(v) : v === value;
2790
3037
  const hasSearch = searchable === void 0 ? opts.length > 8 : searchable;
2791
- const [open, setOpen] = React17.useState(false);
2792
- const [q, setQ] = React17.useState("");
2793
- const [active, setActive] = React17.useState(-1);
2794
- const rootRef = React17.useRef(null);
2795
- const boxRef = React17.useRef(null);
2796
- const popRef = React17.useRef(null);
2797
- const listRef = React17.useRef(null);
2798
- const typeBuf = React17.useRef({ s: "", t: 0 });
3038
+ const [open, setOpen] = React19.useState(false);
3039
+ const [q, setQ] = React19.useState("");
3040
+ const [active, setActive] = React19.useState(-1);
3041
+ const rootRef = React19.useRef(null);
3042
+ const boxRef = React19.useRef(null);
3043
+ const popRef = React19.useRef(null);
3044
+ const listRef = React19.useRef(null);
3045
+ const typeBuf = React19.useRef({ s: "", t: 0 });
2799
3046
  const selected = multiple ? null : opts.find((o) => o.value === value);
2800
3047
  const chosen = multiple ? opts.filter((o) => vals.includes(o.value)) : [];
2801
3048
  const pos = usePopPos(open, boxRef, hasSearch ? 390 : 340, 260);
@@ -2821,7 +3068,7 @@ function Select({
2821
3068
  }
2822
3069
  setOpen(!open);
2823
3070
  };
2824
- React17.useEffect(() => {
3071
+ React19.useEffect(() => {
2825
3072
  if (!open) return;
2826
3073
  const away = (e) => {
2827
3074
  if (rootRef.current && rootRef.current.contains(e.target)) return;
@@ -2831,7 +3078,7 @@ function Select({
2831
3078
  document.addEventListener("pointerdown", away);
2832
3079
  return () => document.removeEventListener("pointerdown", away);
2833
3080
  }, [open]);
2834
- React17.useEffect(() => {
3081
+ React19.useEffect(() => {
2835
3082
  if (!open || active < 0 || !listRef.current) return;
2836
3083
  const el = listRef.current.querySelector('[data-i="' + active + '"]');
2837
3084
  if (el) {
@@ -2885,13 +3132,13 @@ function Select({
2885
3132
  });
2886
3133
  const fieldId = id || (rest.name ? "fd-" + rest.name : void 0);
2887
3134
  const box = ["fd-input", "fd-select", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" ");
2888
- return /* @__PURE__ */ jsxs39("div", { className: ["fd-field", "fd-popfield", open ? "is-open" : "", className].filter(Boolean).join(" "), style, ref: rootRef, children: [
2889
- label ? /* @__PURE__ */ jsxs39("label", { className: "fd-field-label", htmlFor: fieldId, onClick: toggle, children: [
3135
+ return /* @__PURE__ */ jsxs42("div", { className: ["fd-field", "fd-popfield", open ? "is-open" : "", className].filter(Boolean).join(" "), style, ref: rootRef, children: [
3136
+ label ? /* @__PURE__ */ jsxs42("label", { className: "fd-field-label", htmlFor: fieldId, onClick: toggle, children: [
2890
3137
  label,
2891
- required ? /* @__PURE__ */ jsx44("span", { className: "fd-field-req", children: "*" }) : null
3138
+ required ? /* @__PURE__ */ jsx47("span", { className: "fd-field-req", children: "*" }) : null
2892
3139
  ] }) : null,
2893
- /* @__PURE__ */ jsxs39("div", { className: box, style: { cursor: disabled ? "not-allowed" : "pointer" }, ref: boxRef, children: [
2894
- /* @__PURE__ */ jsxs39(
3140
+ /* @__PURE__ */ jsxs42("div", { className: box, style: { cursor: disabled ? "not-allowed" : "pointer" }, ref: boxRef, children: [
3141
+ /* @__PURE__ */ jsxs42(
2895
3142
  "button",
2896
3143
  {
2897
3144
  type: "button",
@@ -2904,13 +3151,13 @@ function Select({
2904
3151
  "aria-haspopup": "listbox",
2905
3152
  style: { all: "unset", flex: 1, minWidth: 0, display: "flex", alignItems: "center", gap: 8, cursor: "inherit", overflow: "hidden" },
2906
3153
  children: [
2907
- selected && selected.icon ? /* @__PURE__ */ jsx44("i", { className: "ph ph-" + selected.icon, style: { flex: "none", color: "var(--text-2)" } }) : null,
2908
- /* @__PURE__ */ jsx44("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", color: (multiple ? chosen.length : selected) ? "var(--text)" : "var(--text-muted)" }, children: boxText }),
2909
- multiple && chosen.length > 1 ? /* @__PURE__ */ jsx44("span", { className: "fd-mono", style: { flex: "none", fontSize: 11, fontWeight: 700, padding: "1px 6px", borderRadius: 99, background: "var(--brand)", color: "#fff" }, children: chosen.length }) : null
3154
+ selected && selected.icon ? /* @__PURE__ */ jsx47("i", { className: "ph ph-" + selected.icon, style: { flex: "none", color: "var(--text-2)" } }) : null,
3155
+ /* @__PURE__ */ jsx47("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", color: (multiple ? chosen.length : selected) ? "var(--text)" : "var(--text-muted)" }, children: boxText }),
3156
+ multiple && chosen.length > 1 ? /* @__PURE__ */ jsx47("span", { className: "fd-mono", style: { flex: "none", fontSize: 11, fontWeight: 700, padding: "1px 6px", borderRadius: 99, background: "var(--brand)", color: "#fff" }, children: chosen.length }) : null
2910
3157
  ]
2911
3158
  }
2912
3159
  ),
2913
- clearable && (multiple ? chosen.length > 0 : selected) && !loading ? /* @__PURE__ */ jsx44(
3160
+ clearable && (multiple ? chosen.length > 0 : selected) && !loading ? /* @__PURE__ */ jsx47(
2914
3161
  "button",
2915
3162
  {
2916
3163
  type: "button",
@@ -2920,22 +3167,22 @@ function Select({
2920
3167
  fire(multiple ? [] : "");
2921
3168
  },
2922
3169
  style: { all: "unset", cursor: "pointer", color: "var(--text-muted)", display: "grid", placeItems: "center", padding: 2 },
2923
- children: /* @__PURE__ */ jsx44("i", { className: "ph ph-x-circle", style: { fontSize: 15 } })
3170
+ children: /* @__PURE__ */ jsx47("i", { className: "ph ph-x-circle", style: { fontSize: 15 } })
2924
3171
  }
2925
3172
  ) : null,
2926
- loading ? /* @__PURE__ */ jsx44("span", { className: "fd-spinner", style: { color: "var(--text-muted)" }, "aria-label": "Loading options" }) : /* @__PURE__ */ jsx44("span", { className: "fd-select-caret", onClick: toggle, children: /* @__PURE__ */ jsx44("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
3173
+ loading ? /* @__PURE__ */ jsx47("span", { className: "fd-spinner", style: { color: "var(--text-muted)" }, "aria-label": "Loading options" }) : /* @__PURE__ */ jsx47("span", { className: "fd-select-caret", onClick: toggle, children: /* @__PURE__ */ jsx47("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
2927
3174
  ] }),
2928
3175
  open && pos ? createPortal4(
2929
- /* @__PURE__ */ jsxs39(
3176
+ /* @__PURE__ */ jsxs42(
2930
3177
  "div",
2931
3178
  {
2932
3179
  className: "fd-pop" + (pos.up ? " is-up" : ""),
2933
3180
  ref: popRef,
2934
3181
  style: popStyle(pos, { minWidth: Math.max(pos.width, 260), maxWidth: 380, zIndex: 130, overflowY: "hidden" }),
2935
3182
  children: [
2936
- hasSearch ? /* @__PURE__ */ jsxs39("div", { className: "fd-pop-search", children: [
2937
- /* @__PURE__ */ jsx44("i", { className: "ph ph-magnifying-glass", style: { color: "var(--text-muted)", fontSize: 14 } }),
2938
- /* @__PURE__ */ jsx44(
3183
+ hasSearch ? /* @__PURE__ */ jsxs42("div", { className: "fd-pop-search", children: [
3184
+ /* @__PURE__ */ jsx47("i", { className: "ph ph-magnifying-glass", style: { color: "var(--text-muted)", fontSize: 14 } }),
3185
+ /* @__PURE__ */ jsx47(
2939
3186
  "input",
2940
3187
  {
2941
3188
  autoFocus: true,
@@ -2948,15 +3195,15 @@ function Select({
2948
3195
  }
2949
3196
  }
2950
3197
  ),
2951
- q ? /* @__PURE__ */ jsx44("span", { className: "fd-body-sm fd-muted", children: visible.length }) : null
3198
+ q ? /* @__PURE__ */ jsx47("span", { className: "fd-body-sm fd-muted", children: visible.length }) : null
2952
3199
  ] }) : null,
2953
- /* @__PURE__ */ jsx44("div", { className: "fd-pop-list", role: "listbox", "aria-multiselectable": multiple || void 0, ref: listRef, style: { maxHeight: Math.max(120, pos.maxH - (hasSearch ? 64 : 12) - (multiple ? 42 : 0)) }, children: visible.length === 0 ? /* @__PURE__ */ jsxs39("div", { className: "fd-pop-empty", children: [
3200
+ /* @__PURE__ */ jsx47("div", { className: "fd-pop-list", role: "listbox", "aria-multiselectable": multiple || void 0, ref: listRef, style: { maxHeight: Math.max(120, pos.maxH - (hasSearch ? 64 : 12) - (multiple ? 42 : 0)) }, children: visible.length === 0 ? /* @__PURE__ */ jsxs42("div", { className: "fd-pop-empty", children: [
2954
3201
  'Nothing matches "',
2955
3202
  q,
2956
3203
  '".'
2957
- ] }) : groups.map((grp) => /* @__PURE__ */ jsxs39(React17.Fragment, { children: [
2958
- grp.g ? /* @__PURE__ */ jsx44("div", { className: "fd-pop-group", children: grp.g }) : null,
2959
- grp.items.map(({ o, i }) => /* @__PURE__ */ jsxs39(
3204
+ ] }) : groups.map((grp) => /* @__PURE__ */ jsxs42(React19.Fragment, { children: [
3205
+ grp.g ? /* @__PURE__ */ jsx47("div", { className: "fd-pop-group", children: grp.g }) : null,
3206
+ grp.items.map(({ o, i }) => /* @__PURE__ */ jsxs42(
2960
3207
  "button",
2961
3208
  {
2962
3209
  type: "button",
@@ -2968,21 +3215,21 @@ function Select({
2968
3215
  onMouseEnter: () => setActive(i),
2969
3216
  onClick: () => pick(o),
2970
3217
  children: [
2971
- multiple ? /* @__PURE__ */ jsx44("span", { "aria-hidden": "true", style: { flex: "none", display: "grid", placeItems: "center", width: 16, height: 16, borderRadius: 4, border: "1.5px solid " + (isOn(o.value) ? "var(--brand)" : "var(--border-strong, var(--border))"), background: isOn(o.value) ? "var(--brand)" : "var(--surface)", color: "#fff" }, children: isOn(o.value) ? /* @__PURE__ */ jsx44("i", { className: "ph ph-check", style: { fontSize: 11 } }) : null }) : null,
2972
- o.icon ? /* @__PURE__ */ jsx44("span", { className: "fd-opt-icon", children: /* @__PURE__ */ jsx44("i", { className: "ph ph-" + o.icon }) }) : null,
2973
- /* @__PURE__ */ jsxs39("span", { style: { flex: 1, minWidth: 0 }, children: [
2974
- /* @__PURE__ */ jsx44("span", { className: "fd-opt-label", children: o.label }),
2975
- o.description ? /* @__PURE__ */ jsx44("span", { className: "fd-opt-desc", children: o.description }) : null
3218
+ multiple ? /* @__PURE__ */ jsx47("span", { "aria-hidden": "true", style: { flex: "none", display: "grid", placeItems: "center", width: 16, height: 16, borderRadius: 4, border: "1.5px solid " + (isOn(o.value) ? "var(--brand)" : "var(--border-strong, var(--border))"), background: isOn(o.value) ? "var(--brand)" : "var(--surface)", color: "#fff" }, children: isOn(o.value) ? /* @__PURE__ */ jsx47("i", { className: "ph ph-check", style: { fontSize: 11 } }) : null }) : null,
3219
+ o.icon ? /* @__PURE__ */ jsx47("span", { className: "fd-opt-icon", children: /* @__PURE__ */ jsx47("i", { className: "ph ph-" + o.icon }) }) : null,
3220
+ /* @__PURE__ */ jsxs42("span", { style: { flex: 1, minWidth: 0 }, children: [
3221
+ /* @__PURE__ */ jsx47("span", { className: "fd-opt-label", children: o.label }),
3222
+ o.description ? /* @__PURE__ */ jsx47("span", { className: "fd-opt-desc", children: o.description }) : null
2976
3223
  ] }),
2977
- o.meta ? /* @__PURE__ */ jsx44("span", { className: "fd-opt-meta", children: o.meta }) : null,
2978
- multiple ? null : /* @__PURE__ */ jsx44("span", { className: "fd-opt-check", children: o.value === value ? /* @__PURE__ */ jsx44("i", { className: "ph ph-check" }) : null })
3224
+ o.meta ? /* @__PURE__ */ jsx47("span", { className: "fd-opt-meta", children: o.meta }) : null,
3225
+ multiple ? null : /* @__PURE__ */ jsx47("span", { className: "fd-opt-check", children: o.value === value ? /* @__PURE__ */ jsx47("i", { className: "ph ph-check" }) : null })
2979
3226
  ]
2980
3227
  },
2981
3228
  String(o.value)
2982
3229
  ))
2983
3230
  ] }, grp.g || "_")) }),
2984
- multiple ? /* @__PURE__ */ jsxs39("div", { className: "fd-row", style: { gap: 10, padding: "8px 12px", borderTop: "1px solid var(--border)" }, children: [
2985
- /* @__PURE__ */ jsx44(
3231
+ multiple ? /* @__PURE__ */ jsxs42("div", { className: "fd-row", style: { gap: 10, padding: "8px 12px", borderTop: "1px solid var(--border)" }, children: [
3232
+ /* @__PURE__ */ jsx47(
2986
3233
  "button",
2987
3234
  {
2988
3235
  type: "button",
@@ -2991,13 +3238,13 @@ function Select({
2991
3238
  children: "Select all"
2992
3239
  }
2993
3240
  ),
2994
- /* @__PURE__ */ jsx44("span", { style: { flex: 1 } }),
2995
- /* @__PURE__ */ jsxs39("span", { className: "fd-body-sm fd-muted", children: [
3241
+ /* @__PURE__ */ jsx47("span", { style: { flex: 1 } }),
3242
+ /* @__PURE__ */ jsxs42("span", { className: "fd-body-sm fd-muted", children: [
2996
3243
  vals.length,
2997
3244
  " of ",
2998
3245
  opts.length
2999
3246
  ] }),
3000
- /* @__PURE__ */ jsx44(
3247
+ /* @__PURE__ */ jsx47(
3001
3248
  "button",
3002
3249
  {
3003
3250
  type: "button",
@@ -3013,17 +3260,17 @@ function Select({
3013
3260
  ),
3014
3261
  document.body
3015
3262
  ) : null,
3016
- error ? /* @__PURE__ */ jsxs39("span", { className: "fd-field-error", children: [
3017
- /* @__PURE__ */ jsx44("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
3263
+ error ? /* @__PURE__ */ jsxs42("span", { className: "fd-field-error", children: [
3264
+ /* @__PURE__ */ jsx47("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
3018
3265
  error
3019
- ] }) : help ? /* @__PURE__ */ jsx44("span", { className: "fd-field-help", children: help }) : null
3266
+ ] }) : help ? /* @__PURE__ */ jsx47("span", { className: "fd-field-help", children: help }) : null
3020
3267
  ] });
3021
3268
  }
3022
3269
 
3023
3270
  // src/components/forms/DatePicker.tsx
3024
- import * as React18 from "react";
3271
+ import * as React20 from "react";
3025
3272
  import { createPortal as createPortal5 } from "react-dom";
3026
- import { jsx as jsx45, jsxs as jsxs40 } from "react/jsx-runtime";
3273
+ import { jsx as jsx48, jsxs as jsxs43 } from "react/jsx-runtime";
3027
3274
  var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
3028
3275
  var DOW = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
3029
3276
  var iso = (d) => d.getFullYear() + "-" + String(d.getMonth() + 1).padStart(2, "0") + "-" + String(d.getDate()).padStart(2, "0");
@@ -3037,8 +3284,8 @@ var fmt = (s) => {
3037
3284
  return d ? MONTHS[d.getMonth()].slice(0, 3) + " " + d.getDate() + ", " + d.getFullYear() : "";
3038
3285
  };
3039
3286
  function usePopPos2(open, ref, estH, estW) {
3040
- const [pos, setPos] = React18.useState(null);
3041
- React18.useLayoutEffect(() => {
3287
+ const [pos, setPos] = React20.useState(null);
3288
+ React20.useLayoutEffect(() => {
3042
3289
  if (!open || !ref.current) {
3043
3290
  setPos(null);
3044
3291
  return;
@@ -3082,10 +3329,10 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3082
3329
  const today = /* @__PURE__ */ new Date();
3083
3330
  const sel = range ? value || {} : { start: value, end: value };
3084
3331
  const anchor = parse(sel.start) || parse(initialMonth) || today;
3085
- const [vy, setVy] = React18.useState(anchor.getFullYear());
3086
- const [vm, setVm] = React18.useState(anchor.getMonth());
3087
- const [mode2, setMode] = React18.useState("days");
3088
- const [hover, setHover] = React18.useState(null);
3332
+ const [vy, setVy] = React20.useState(anchor.getFullYear());
3333
+ const [vm, setVm] = React20.useState(anchor.getMonth());
3334
+ const [mode2, setMode] = React20.useState("days");
3335
+ const [hover, setHover] = React20.useState(null);
3089
3336
  const s = parse(sel.start), e = parse(sel.end);
3090
3337
  const hoverEnd = range && s && !e && hover ? parse(hover) : null;
3091
3338
  const inRange = (d) => {
@@ -3122,9 +3369,9 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3122
3369
  const startPad = new Date(y, m, 1).getDay();
3123
3370
  const cells = [];
3124
3371
  for (let i = 0; i < 42; i++) cells.push(new Date(y, m, i - startPad + 1));
3125
- return /* @__PURE__ */ jsxs40("div", { className: "fd-cal-grid", style: { width: months > 1 ? 252 : "auto", flex: "none" }, onMouseLeave: () => setHover(null), children: [
3126
- DOW.map((d) => /* @__PURE__ */ jsx45("span", { className: "fd-cal-dow", children: d }, d)),
3127
- cells.map((d, i) => /* @__PURE__ */ jsx45(
3372
+ return /* @__PURE__ */ jsxs43("div", { className: "fd-cal-grid", style: { width: months > 1 ? 252 : "auto", flex: "none" }, onMouseLeave: () => setHover(null), children: [
3373
+ DOW.map((d) => /* @__PURE__ */ jsx48("span", { className: "fd-cal-dow", children: d }, d)),
3374
+ cells.map((d, i) => /* @__PURE__ */ jsx48(
3128
3375
  "button",
3129
3376
  {
3130
3377
  type: "button",
@@ -3138,20 +3385,20 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3138
3385
  ] });
3139
3386
  };
3140
3387
  const nextY = vm === 11 ? vy + 1 : vy, nextM = (vm + 1) % 12;
3141
- return /* @__PURE__ */ jsxs40("div", { className: "fd-cal", style: { width: months > 1 && mode2 === "days" ? "auto" : void 0 }, children: [
3142
- /* @__PURE__ */ jsxs40("div", { className: "fd-cal-head", children: [
3143
- /* @__PURE__ */ jsx45("button", { type: "button", className: "fd-btn-icon", "aria-label": "Previous", onClick: () => mode2 === "years" ? setVy(vy - 12) : mode2 === "months" ? setVy(vy - 1) : nav(-1), children: /* @__PURE__ */ jsx45("i", { className: "ph ph-caret-left" }) }),
3144
- /* @__PURE__ */ jsxs40("button", { type: "button", className: "fd-cal-title", onClick: () => setMode(mode2 === "days" ? "months" : mode2 === "months" ? "years" : "days"), children: [
3388
+ return /* @__PURE__ */ jsxs43("div", { className: "fd-cal", style: { width: months > 1 && mode2 === "days" ? "auto" : void 0 }, children: [
3389
+ /* @__PURE__ */ jsxs43("div", { className: "fd-cal-head", children: [
3390
+ /* @__PURE__ */ jsx48("button", { type: "button", className: "fd-btn-icon", "aria-label": "Previous", onClick: () => mode2 === "years" ? setVy(vy - 12) : mode2 === "months" ? setVy(vy - 1) : nav(-1), children: /* @__PURE__ */ jsx48("i", { className: "ph ph-caret-left" }) }),
3391
+ /* @__PURE__ */ jsxs43("button", { type: "button", className: "fd-cal-title", onClick: () => setMode(mode2 === "days" ? "months" : mode2 === "months" ? "years" : "days"), children: [
3145
3392
  mode2 === "days" ? MONTHS[vm] + " " + vy : mode2 === "months" ? vy : vy - 5 + " \u2013 " + (vy + 6),
3146
- /* @__PURE__ */ jsx45("i", { className: "ph ph-caret-down", style: { fontSize: 10, marginLeft: 6, color: "var(--text-muted)" } })
3393
+ /* @__PURE__ */ jsx48("i", { className: "ph ph-caret-down", style: { fontSize: 10, marginLeft: 6, color: "var(--text-muted)" } })
3147
3394
  ] }),
3148
- months > 1 && mode2 === "days" ? /* @__PURE__ */ jsx45("span", { className: "fd-cal-title", style: { cursor: "default", background: "none" }, children: MONTHS[nextM] + " " + nextY }) : null,
3149
- /* @__PURE__ */ jsx45("button", { type: "button", className: "fd-btn-icon", "aria-label": "Next", onClick: () => mode2 === "years" ? setVy(vy + 12) : mode2 === "months" ? setVy(vy + 1) : nav(1), children: /* @__PURE__ */ jsx45("i", { className: "ph ph-caret-right" }) })
3395
+ months > 1 && mode2 === "days" ? /* @__PURE__ */ jsx48("span", { className: "fd-cal-title", style: { cursor: "default", background: "none" }, children: MONTHS[nextM] + " " + nextY }) : null,
3396
+ /* @__PURE__ */ jsx48("button", { type: "button", className: "fd-btn-icon", "aria-label": "Next", onClick: () => mode2 === "years" ? setVy(vy + 12) : mode2 === "months" ? setVy(vy + 1) : nav(1), children: /* @__PURE__ */ jsx48("i", { className: "ph ph-caret-right" }) })
3150
3397
  ] }),
3151
- mode2 === "days" ? /* @__PURE__ */ jsxs40("div", { style: { display: "flex", gap: 18 }, children: [
3398
+ mode2 === "days" ? /* @__PURE__ */ jsxs43("div", { style: { display: "flex", gap: 18 }, children: [
3152
3399
  monthGrid(vy, vm),
3153
3400
  months > 1 ? monthGrid(nextY, nextM) : null
3154
- ] }) : mode2 === "months" ? /* @__PURE__ */ jsx45("div", { className: "fd-cal-grid-months", children: MONTHS.map((m, i) => /* @__PURE__ */ jsx45(
3401
+ ] }) : mode2 === "months" ? /* @__PURE__ */ jsx48("div", { className: "fd-cal-grid-months", children: MONTHS.map((m, i) => /* @__PURE__ */ jsx48(
3155
3402
  "button",
3156
3403
  {
3157
3404
  type: "button",
@@ -3163,7 +3410,7 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3163
3410
  children: m.slice(0, 3)
3164
3411
  },
3165
3412
  m
3166
- )) }) : /* @__PURE__ */ jsx45("div", { className: "fd-cal-grid-months", children: Array.from({ length: 12 }, (_, i) => vy - 5 + i).map((y) => /* @__PURE__ */ jsx45(
3413
+ )) }) : /* @__PURE__ */ jsx48("div", { className: "fd-cal-grid-months", children: Array.from({ length: 12 }, (_, i) => vy - 5 + i).map((y) => /* @__PURE__ */ jsx48(
3167
3414
  "button",
3168
3415
  {
3169
3416
  type: "button",
@@ -3176,8 +3423,8 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3176
3423
  },
3177
3424
  y
3178
3425
  )) }),
3179
- /* @__PURE__ */ jsxs40("div", { className: "fd-cal-foot", children: [
3180
- /* @__PURE__ */ jsx45(
3426
+ /* @__PURE__ */ jsxs43("div", { className: "fd-cal-foot", children: [
3427
+ /* @__PURE__ */ jsx48(
3181
3428
  "button",
3182
3429
  {
3183
3430
  type: "button",
@@ -3191,8 +3438,8 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3191
3438
  children: "Today"
3192
3439
  }
3193
3440
  ),
3194
- /* @__PURE__ */ jsx45("span", { style: { flex: 1 } }),
3195
- range && sel.start ? /* @__PURE__ */ jsxs40("span", { className: "fd-body-sm fd-muted", children: [
3441
+ /* @__PURE__ */ jsx48("span", { style: { flex: 1 } }),
3442
+ range && sel.start ? /* @__PURE__ */ jsxs43("span", { className: "fd-body-sm fd-muted", children: [
3196
3443
  fmt(sel.start),
3197
3444
  sel.end ? " \u2192 " + fmt(sel.end) : " \u2192 pick an end"
3198
3445
  ] }) : null
@@ -3200,12 +3447,12 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3200
3447
  ] });
3201
3448
  }
3202
3449
  function DatePicker({ label, help, error, required = false, disabled = false, range = false, value, onChange, placeholder, className = "", style, ...rest }) {
3203
- const [open, setOpen] = React18.useState(false);
3204
- const rootRef = React18.useRef(null);
3205
- const boxRef = React18.useRef(null);
3206
- const popRef = React18.useRef(null);
3450
+ const [open, setOpen] = React20.useState(false);
3451
+ const rootRef = React20.useRef(null);
3452
+ const boxRef = React20.useRef(null);
3453
+ const popRef = React20.useRef(null);
3207
3454
  const pos = usePopPos2(open, boxRef, 430, range ? 600 : 316);
3208
- React18.useEffect(() => {
3455
+ React20.useEffect(() => {
3209
3456
  if (!open) return;
3210
3457
  const away = (e) => {
3211
3458
  if (rootRef.current && rootRef.current.contains(e.target)) return;
@@ -3226,14 +3473,14 @@ function DatePicker({ label, help, error, required = false, disabled = false, ra
3226
3473
  const toggle = () => {
3227
3474
  if (!disabled) setOpen(!open);
3228
3475
  };
3229
- return /* @__PURE__ */ jsxs40("div", { className: ["fd-field", "fd-popfield", open ? "is-open" : "", className].filter(Boolean).join(" "), style, ref: rootRef, children: [
3230
- label ? /* @__PURE__ */ jsxs40("label", { className: "fd-field-label", onClick: toggle, children: [
3476
+ return /* @__PURE__ */ jsxs43("div", { className: ["fd-field", "fd-popfield", open ? "is-open" : "", className].filter(Boolean).join(" "), style, ref: rootRef, children: [
3477
+ label ? /* @__PURE__ */ jsxs43("label", { className: "fd-field-label", onClick: toggle, children: [
3231
3478
  label,
3232
- required ? /* @__PURE__ */ jsx45("span", { className: "fd-field-req", children: "*" }) : null
3479
+ required ? /* @__PURE__ */ jsx48("span", { className: "fd-field-req", children: "*" }) : null
3233
3480
  ] }) : null,
3234
- /* @__PURE__ */ jsxs40("div", { className: ["fd-input", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" "), style: { cursor: disabled ? "not-allowed" : "pointer" }, onClick: toggle, ref: boxRef, children: [
3235
- /* @__PURE__ */ jsx45("span", { className: "fd-input-icon", children: /* @__PURE__ */ jsx45("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }) }),
3236
- /* @__PURE__ */ jsx45(
3481
+ /* @__PURE__ */ jsxs43("div", { className: ["fd-input", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" "), style: { cursor: disabled ? "not-allowed" : "pointer" }, onClick: toggle, ref: boxRef, children: [
3482
+ /* @__PURE__ */ jsx48("span", { className: "fd-input-icon", children: /* @__PURE__ */ jsx48("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }) }),
3483
+ /* @__PURE__ */ jsx48(
3237
3484
  "button",
3238
3485
  {
3239
3486
  type: "button",
@@ -3249,10 +3496,10 @@ function DatePicker({ label, help, error, required = false, disabled = false, ra
3249
3496
  children: display || placeholder || (range ? "Pick a date range" : "Pick a date")
3250
3497
  }
3251
3498
  ),
3252
- /* @__PURE__ */ jsx45("span", { className: "fd-select-caret", children: /* @__PURE__ */ jsx45("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
3499
+ /* @__PURE__ */ jsx48("span", { className: "fd-select-caret", children: /* @__PURE__ */ jsx48("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
3253
3500
  ] }),
3254
3501
  open && pos ? createPortal5(
3255
- /* @__PURE__ */ jsx45("div", { className: "fd-pop" + (pos.up ? " is-up" : ""), ref: popRef, style: popStyle2(pos, { width: "max-content", minWidth: 0, zIndex: 130 }), children: /* @__PURE__ */ jsx45(
3502
+ /* @__PURE__ */ jsx48("div", { className: "fd-pop" + (pos.up ? " is-up" : ""), ref: popRef, style: popStyle2(pos, { width: "max-content", minWidth: 0, zIndex: 130 }), children: /* @__PURE__ */ jsx48(
3256
3503
  Calendar,
3257
3504
  {
3258
3505
  range,
@@ -3266,21 +3513,21 @@ function DatePicker({ label, help, error, required = false, disabled = false, ra
3266
3513
  ) }),
3267
3514
  document.body
3268
3515
  ) : null,
3269
- error ? /* @__PURE__ */ jsxs40("span", { className: "fd-field-error", children: [
3270
- /* @__PURE__ */ jsx45("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
3516
+ error ? /* @__PURE__ */ jsxs43("span", { className: "fd-field-error", children: [
3517
+ /* @__PURE__ */ jsx48("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
3271
3518
  error
3272
- ] }) : help ? /* @__PURE__ */ jsx45("span", { className: "fd-field-help", children: help }) : null
3519
+ ] }) : help ? /* @__PURE__ */ jsx48("span", { className: "fd-field-help", children: help }) : null
3273
3520
  ] });
3274
3521
  }
3275
3522
 
3276
3523
  // src/components/forms/TimePicker.tsx
3277
- import * as React19 from "react";
3524
+ import * as React21 from "react";
3278
3525
  import { createPortal as createPortal6 } from "react-dom";
3279
- import { jsx as jsx46, jsxs as jsxs41 } from "react/jsx-runtime";
3526
+ import { jsx as jsx49, jsxs as jsxs44 } from "react/jsx-runtime";
3280
3527
  var pad = (n) => String(n).padStart(2, "0");
3281
3528
  function usePopPos3(open, ref, estH, estW) {
3282
- const [pos, setPos] = React19.useState(null);
3283
- React19.useLayoutEffect(() => {
3529
+ const [pos, setPos] = React21.useState(null);
3530
+ React21.useLayoutEffect(() => {
3284
3531
  if (!open || !ref.current) {
3285
3532
  setPos(null);
3286
3533
  return;
@@ -3326,9 +3573,9 @@ function ClockFace({ value = "09:00", onChange }) {
3326
3573
  if (isNaN(m)) m = 0;
3327
3574
  const pm = h24 >= 12;
3328
3575
  const h12 = h24 % 12 === 0 ? 12 : h24 % 12;
3329
- const [mode2, setMode] = React19.useState("h");
3330
- const faceRef = React19.useRef(null);
3331
- const dragging = React19.useRef(false);
3576
+ const [mode2, setMode] = React21.useState("h");
3577
+ const faceRef = React21.useRef(null);
3578
+ const dragging = React21.useRef(false);
3332
3579
  const set = (h, mm, isPm) => onChange((isPm ? h % 12 + 12 : h % 12) + ":" + pad(mm));
3333
3580
  const R = 108, NR = 80;
3334
3581
  const nums = mode2 === "h" ? Array.from({ length: 12 }, (_, i) => i + 1) : Array.from({ length: 12 }, (_, i) => i * 5);
@@ -3363,12 +3610,12 @@ function ClockFace({ value = "09:00", onChange }) {
3363
3610
  };
3364
3611
  const handAngle = mode2 === "h" ? h12 % 12 * 30 : m * 6;
3365
3612
  const minuteOff = mode2 === "m" && m % 5 !== 0;
3366
- return /* @__PURE__ */ jsxs41("div", { style: { padding: "4px 14px 14px" }, children: [
3367
- /* @__PURE__ */ jsxs41("div", { className: "fd-clock-digits", children: [
3368
- /* @__PURE__ */ jsx46("button", { type: "button", className: "fd-clock-digit" + (mode2 === "h" ? " is-active" : ""), onClick: () => setMode("h"), children: pad(h12) }),
3369
- /* @__PURE__ */ jsx46("span", { style: { fontSize: 24, fontWeight: 700, color: "var(--text-muted)" }, children: ":" }),
3370
- /* @__PURE__ */ jsx46("button", { type: "button", className: "fd-clock-digit" + (mode2 === "m" ? " is-active" : ""), onClick: () => setMode("m"), children: pad(m) }),
3371
- /* @__PURE__ */ jsx46("span", { className: "fd-stack", style: { gap: 3, marginLeft: 8 }, children: ["AM", "PM"].map((ap) => /* @__PURE__ */ jsx46(
3613
+ return /* @__PURE__ */ jsxs44("div", { style: { padding: "4px 14px 14px" }, children: [
3614
+ /* @__PURE__ */ jsxs44("div", { className: "fd-clock-digits", children: [
3615
+ /* @__PURE__ */ jsx49("button", { type: "button", className: "fd-clock-digit" + (mode2 === "h" ? " is-active" : ""), onClick: () => setMode("h"), children: pad(h12) }),
3616
+ /* @__PURE__ */ jsx49("span", { style: { fontSize: 24, fontWeight: 700, color: "var(--text-muted)" }, children: ":" }),
3617
+ /* @__PURE__ */ jsx49("button", { type: "button", className: "fd-clock-digit" + (mode2 === "m" ? " is-active" : ""), onClick: () => setMode("m"), children: pad(m) }),
3618
+ /* @__PURE__ */ jsx49("span", { className: "fd-stack", style: { gap: 3, marginLeft: 8 }, children: ["AM", "PM"].map((ap) => /* @__PURE__ */ jsx49(
3372
3619
  "button",
3373
3620
  {
3374
3621
  type: "button",
@@ -3379,13 +3626,13 @@ function ClockFace({ value = "09:00", onChange }) {
3379
3626
  ap
3380
3627
  )) })
3381
3628
  ] }),
3382
- /* @__PURE__ */ jsxs41("div", { className: "fd-clock", ref: faceRef, onPointerDown: down, onPointerMove: move, onPointerUp: upH, children: [
3383
- /* @__PURE__ */ jsx46("span", { className: "fd-clock-hand", style: { height: NR - (minuteOff ? 14 : 16), transform: "translateX(-50%) rotate(" + handAngle + "deg)", bottom: "50%" } }),
3384
- /* @__PURE__ */ jsx46("span", { className: "fd-clock-pivot" }),
3385
- minuteOff ? /* @__PURE__ */ jsx46("span", { style: { position: "absolute", left: "50%", top: "50%", width: 10, height: 10, margin: -5, borderRadius: "50%", border: "2px solid var(--brand)", background: "var(--surface)", transform: "rotate(" + handAngle + "deg) translateY(-" + (NR - 6) + "px)", transformOrigin: "center", pointerEvents: "none" } }) : null,
3629
+ /* @__PURE__ */ jsxs44("div", { className: "fd-clock", ref: faceRef, onPointerDown: down, onPointerMove: move, onPointerUp: upH, children: [
3630
+ /* @__PURE__ */ jsx49("span", { className: "fd-clock-hand", style: { height: NR - (minuteOff ? 14 : 16), transform: "translateX(-50%) rotate(" + handAngle + "deg)", bottom: "50%" } }),
3631
+ /* @__PURE__ */ jsx49("span", { className: "fd-clock-pivot" }),
3632
+ minuteOff ? /* @__PURE__ */ jsx49("span", { style: { position: "absolute", left: "50%", top: "50%", width: 10, height: 10, margin: -5, borderRadius: "50%", border: "2px solid var(--brand)", background: "var(--surface)", transform: "rotate(" + handAngle + "deg) translateY(-" + (NR - 6) + "px)", transformOrigin: "center", pointerEvents: "none" } }) : null,
3386
3633
  nums.map((n) => {
3387
3634
  const a = angleOf(n) * Math.PI / 180;
3388
- return /* @__PURE__ */ jsx46(
3635
+ return /* @__PURE__ */ jsx49(
3389
3636
  "span",
3390
3637
  {
3391
3638
  className: "fd-clock-num" + (n === selNum || mode2 === "m" && n === Math.round(m / 5) * 5 % 60 && m % 5 === 0 ? " is-sel" : ""),
@@ -3396,16 +3643,16 @@ function ClockFace({ value = "09:00", onChange }) {
3396
3643
  );
3397
3644
  })
3398
3645
  ] }),
3399
- /* @__PURE__ */ jsx46("div", { className: "fd-row", style: { justifyContent: "center", gap: 6 }, children: /* @__PURE__ */ jsx46("span", { className: "fd-body-sm fd-muted", children: mode2 === "h" ? "Pick the hour \u2014 drag or tap" : "Now the minutes" }) })
3646
+ /* @__PURE__ */ jsx49("div", { className: "fd-row", style: { justifyContent: "center", gap: 6 }, children: /* @__PURE__ */ jsx49("span", { className: "fd-body-sm fd-muted", children: mode2 === "h" ? "Pick the hour \u2014 drag or tap" : "Now the minutes" }) })
3400
3647
  ] });
3401
3648
  }
3402
3649
  function TimePicker({ label, help, error, required = false, disabled = false, value = "", onChange, placeholder = "Pick a time", className = "", style }) {
3403
- const [open, setOpen] = React19.useState(false);
3404
- const rootRef = React19.useRef(null);
3405
- const boxRef = React19.useRef(null);
3406
- const popRef = React19.useRef(null);
3650
+ const [open, setOpen] = React21.useState(false);
3651
+ const rootRef = React21.useRef(null);
3652
+ const boxRef = React21.useRef(null);
3653
+ const popRef = React21.useRef(null);
3407
3654
  const pos = usePopPos3(open, boxRef, 420, 262);
3408
- React19.useEffect(() => {
3655
+ React21.useEffect(() => {
3409
3656
  if (!open) return;
3410
3657
  const away = (e) => {
3411
3658
  if (rootRef.current && rootRef.current.contains(e.target)) return;
@@ -3430,14 +3677,14 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
3430
3677
  const toggle = () => {
3431
3678
  if (!disabled) setOpen(!open);
3432
3679
  };
3433
- return /* @__PURE__ */ jsxs41("div", { className: ["fd-field", "fd-popfield", open ? "is-open" : "", className].filter(Boolean).join(" "), style, ref: rootRef, children: [
3434
- label ? /* @__PURE__ */ jsxs41("label", { className: "fd-field-label", onClick: toggle, children: [
3680
+ return /* @__PURE__ */ jsxs44("div", { className: ["fd-field", "fd-popfield", open ? "is-open" : "", className].filter(Boolean).join(" "), style, ref: rootRef, children: [
3681
+ label ? /* @__PURE__ */ jsxs44("label", { className: "fd-field-label", onClick: toggle, children: [
3435
3682
  label,
3436
- required ? /* @__PURE__ */ jsx46("span", { className: "fd-field-req", children: "*" }) : null
3683
+ required ? /* @__PURE__ */ jsx49("span", { className: "fd-field-req", children: "*" }) : null
3437
3684
  ] }) : null,
3438
- /* @__PURE__ */ jsxs41("div", { className: ["fd-input", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" "), style: { cursor: disabled ? "not-allowed" : "pointer" }, onClick: toggle, ref: boxRef, children: [
3439
- /* @__PURE__ */ jsx46("span", { className: "fd-input-icon", children: /* @__PURE__ */ jsx46("i", { className: "ph ph-clock", "aria-hidden": "true" }) }),
3440
- /* @__PURE__ */ jsx46(
3685
+ /* @__PURE__ */ jsxs44("div", { className: ["fd-input", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" "), style: { cursor: disabled ? "not-allowed" : "pointer" }, onClick: toggle, ref: boxRef, children: [
3686
+ /* @__PURE__ */ jsx49("span", { className: "fd-input-icon", children: /* @__PURE__ */ jsx49("i", { className: "ph ph-clock", "aria-hidden": "true" }) }),
3687
+ /* @__PURE__ */ jsx49(
3441
3688
  "button",
3442
3689
  {
3443
3690
  type: "button",
@@ -3452,13 +3699,13 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
3452
3699
  children: disp() || placeholder
3453
3700
  }
3454
3701
  ),
3455
- /* @__PURE__ */ jsx46("span", { className: "fd-select-caret", children: /* @__PURE__ */ jsx46("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
3702
+ /* @__PURE__ */ jsx49("span", { className: "fd-select-caret", children: /* @__PURE__ */ jsx49("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
3456
3703
  ] }),
3457
3704
  open && pos ? createPortal6(
3458
- /* @__PURE__ */ jsxs41("div", { className: "fd-pop" + (pos.up ? " is-up" : ""), ref: popRef, style: popStyle3(pos, { width: 262, minWidth: 0, zIndex: 130 }), children: [
3459
- /* @__PURE__ */ jsx46(ClockFace, { value: value || "09:00", onChange: (v) => onChange && onChange({ target: { value: v } }) }),
3460
- /* @__PURE__ */ jsxs41("div", { className: "fd-cal-foot", style: { margin: "0 14px 12px", paddingTop: 10 }, children: [
3461
- /* @__PURE__ */ jsx46(
3705
+ /* @__PURE__ */ jsxs44("div", { className: "fd-pop" + (pos.up ? " is-up" : ""), ref: popRef, style: popStyle3(pos, { width: 262, minWidth: 0, zIndex: 130 }), children: [
3706
+ /* @__PURE__ */ jsx49(ClockFace, { value: value || "09:00", onChange: (v) => onChange && onChange({ target: { value: v } }) }),
3707
+ /* @__PURE__ */ jsxs44("div", { className: "fd-cal-foot", style: { margin: "0 14px 12px", paddingTop: 10 }, children: [
3708
+ /* @__PURE__ */ jsx49(
3462
3709
  "button",
3463
3710
  {
3464
3711
  type: "button",
@@ -3471,22 +3718,22 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
3471
3718
  children: "Now"
3472
3719
  }
3473
3720
  ),
3474
- /* @__PURE__ */ jsx46("span", { style: { flex: 1 } }),
3475
- /* @__PURE__ */ jsx46("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", onClick: () => setOpen(false), children: "Done" })
3721
+ /* @__PURE__ */ jsx49("span", { style: { flex: 1 } }),
3722
+ /* @__PURE__ */ jsx49("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", onClick: () => setOpen(false), children: "Done" })
3476
3723
  ] })
3477
3724
  ] }),
3478
3725
  document.body
3479
3726
  ) : null,
3480
- error ? /* @__PURE__ */ jsxs41("span", { className: "fd-field-error", children: [
3481
- /* @__PURE__ */ jsx46("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
3727
+ error ? /* @__PURE__ */ jsxs44("span", { className: "fd-field-error", children: [
3728
+ /* @__PURE__ */ jsx49("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
3482
3729
  error
3483
- ] }) : help ? /* @__PURE__ */ jsx46("span", { className: "fd-field-help", children: help }) : null
3730
+ ] }) : help ? /* @__PURE__ */ jsx49("span", { className: "fd-field-help", children: help }) : null
3484
3731
  ] });
3485
3732
  }
3486
3733
 
3487
3734
  // src/components/forms/Slider.tsx
3488
- import * as React20 from "react";
3489
- import { jsx as jsx47, jsxs as jsxs42 } from "react/jsx-runtime";
3735
+ import * as React22 from "react";
3736
+ import { jsx as jsx50, jsxs as jsxs45 } from "react/jsx-runtime";
3490
3737
  function Slider({
3491
3738
  label,
3492
3739
  min = 0,
@@ -3500,18 +3747,18 @@ function Slider({
3500
3747
  className = "",
3501
3748
  ...rest
3502
3749
  }) {
3503
- const [dragging, setDragging] = React20.useState(false);
3750
+ const [dragging, setDragging] = React22.useState(false);
3504
3751
  const v = value === void 0 ? min : Number(value);
3505
3752
  const pct = max === min ? 0 : (v - min) / (max - min) * 100;
3506
- return /* @__PURE__ */ jsxs42("div", { className: ["fd-field", className].filter(Boolean).join(" "), children: [
3507
- label ? /* @__PURE__ */ jsxs42("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
3508
- /* @__PURE__ */ jsx47("span", { className: "fd-field-label", children: label }),
3509
- /* @__PURE__ */ jsx47("span", { className: "fd-num", style: { color: "var(--text-2)" }, children: format(v) })
3753
+ return /* @__PURE__ */ jsxs45("div", { className: ["fd-field", className].filter(Boolean).join(" "), children: [
3754
+ label ? /* @__PURE__ */ jsxs45("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
3755
+ /* @__PURE__ */ jsx50("span", { className: "fd-field-label", children: label }),
3756
+ /* @__PURE__ */ jsx50("span", { className: "fd-num", style: { color: "var(--text-2)" }, children: format(v) })
3510
3757
  ] }) : null,
3511
- /* @__PURE__ */ jsxs42("div", { className: "fd-slider", children: [
3512
- /* @__PURE__ */ jsx47("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
3513
- showChip && dragging ? /* @__PURE__ */ jsx47("span", { className: "fd-slider-chip", style: { left: pct + "%" }, children: format(v) }) : null,
3514
- /* @__PURE__ */ jsx47(
3758
+ /* @__PURE__ */ jsxs45("div", { className: "fd-slider", children: [
3759
+ /* @__PURE__ */ jsx50("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
3760
+ showChip && dragging ? /* @__PURE__ */ jsx50("span", { className: "fd-slider-chip", style: { left: pct + "%" }, children: format(v) }) : null,
3761
+ /* @__PURE__ */ jsx50(
3515
3762
  "input",
3516
3763
  {
3517
3764
  type: "range",
@@ -3528,13 +3775,13 @@ function Slider({
3528
3775
  }
3529
3776
  )
3530
3777
  ] }),
3531
- help ? /* @__PURE__ */ jsx47("span", { className: "fd-field-help", children: help }) : null
3778
+ help ? /* @__PURE__ */ jsx50("span", { className: "fd-field-help", children: help }) : null
3532
3779
  ] });
3533
3780
  }
3534
3781
 
3535
3782
  // src/components/forms/RangeSlider.tsx
3536
- import * as React21 from "react";
3537
- import { jsx as jsx48, jsxs as jsxs43 } from "react/jsx-runtime";
3783
+ import * as React23 from "react";
3784
+ import { jsx as jsx51, jsxs as jsxs46 } from "react/jsx-runtime";
3538
3785
  function RangeSlider({
3539
3786
  label,
3540
3787
  min = 0,
@@ -3553,9 +3800,9 @@ function RangeSlider({
3553
3800
  }) {
3554
3801
  const fmt2 = format || ((v) => String(v));
3555
3802
  const [a, b] = value || [min, max];
3556
- const [drag, setDrag] = React21.useState(null);
3557
- const [focus, setFocus] = React21.useState(null);
3558
- const railRef = React21.useRef(null);
3803
+ const [drag, setDrag] = React23.useState(null);
3804
+ const [focus, setFocus] = React23.useState(null);
3805
+ const railRef = React23.useRef(null);
3559
3806
  const pct = (v) => max === min ? 0 : (v - min) / (max - min) * 100;
3560
3807
  const clampPair = (i, v) => {
3561
3808
  v = Math.min(max, Math.max(min, Math.round(v / step) * step));
@@ -3570,7 +3817,7 @@ function RangeSlider({
3570
3817
  const r = railRef.current.getBoundingClientRect();
3571
3818
  return min + Math.min(1, Math.max(0, (e.clientX - r.left) / r.width)) * (max - min);
3572
3819
  };
3573
- React21.useEffect(() => {
3820
+ React23.useEffect(() => {
3574
3821
  if (drag === null) return;
3575
3822
  const mv = (e) => onChange && onChange(clampPair(drag, fromEvent(e)));
3576
3823
  const upH = () => setDrag(null);
@@ -3591,7 +3838,7 @@ function RangeSlider({
3591
3838
  };
3592
3839
  const thin = S.length > 7 ? Math.ceil(S.length / 5) : 1;
3593
3840
  const pair = value || [S[0].value, S[S.length - 1].value];
3594
- return /* @__PURE__ */ jsx48(
3841
+ return /* @__PURE__ */ jsx51(
3595
3842
  RangeSlider,
3596
3843
  {
3597
3844
  ...rest,
@@ -3639,23 +3886,23 @@ function RangeSlider({
3639
3886
  };
3640
3887
  const showChip = (i) => drag === i || focus === i;
3641
3888
  const hasLabels = marks.some((m) => m.label);
3642
- return /* @__PURE__ */ jsxs43("div", { className: ["fd-field", className].filter(Boolean).join(" "), ...rest, children: [
3643
- label ? /* @__PURE__ */ jsxs43("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
3644
- /* @__PURE__ */ jsx48("span", { className: "fd-field-label", children: label }),
3645
- /* @__PURE__ */ jsxs43("span", { className: "fd-num", style: { color: "var(--text-2)" }, children: [
3889
+ return /* @__PURE__ */ jsxs46("div", { className: ["fd-field", className].filter(Boolean).join(" "), ...rest, children: [
3890
+ label ? /* @__PURE__ */ jsxs46("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
3891
+ /* @__PURE__ */ jsx51("span", { className: "fd-field-label", children: label }),
3892
+ /* @__PURE__ */ jsxs46("span", { className: "fd-num", style: { color: "var(--text-2)" }, children: [
3646
3893
  fmt2(a),
3647
3894
  " \u2013 ",
3648
3895
  fmt2(b)
3649
3896
  ] })
3650
3897
  ] }) : null,
3651
- /* @__PURE__ */ jsxs43("div", { className: "fd-range" + (hasLabels ? " has-labels" : ""), onPointerDown: onRailDown, children: [
3652
- /* @__PURE__ */ jsx48("span", { className: "fd-range-rail", ref: railRef }),
3653
- /* @__PURE__ */ jsx48("span", { className: "fd-range-fill", style: { left: pct(a) + "%", width: pct(b) - pct(a) + "%" } }),
3654
- marks.map((m) => /* @__PURE__ */ jsxs43(React21.Fragment, { children: [
3655
- /* @__PURE__ */ jsx48("span", { className: "fd-range-mark" + (m.value >= a && m.value <= b ? " is-in" : ""), style: { left: pct(m.value) + "%" } }),
3656
- m.label ? /* @__PURE__ */ jsx48("span", { className: "fd-range-mark-label", style: { left: pct(m.value) + "%" }, children: m.label }) : null
3898
+ /* @__PURE__ */ jsxs46("div", { className: "fd-range" + (hasLabels ? " has-labels" : ""), onPointerDown: onRailDown, children: [
3899
+ /* @__PURE__ */ jsx51("span", { className: "fd-range-rail", ref: railRef }),
3900
+ /* @__PURE__ */ jsx51("span", { className: "fd-range-fill", style: { left: pct(a) + "%", width: pct(b) - pct(a) + "%" } }),
3901
+ marks.map((m) => /* @__PURE__ */ jsxs46(React23.Fragment, { children: [
3902
+ /* @__PURE__ */ jsx51("span", { className: "fd-range-mark" + (m.value >= a && m.value <= b ? " is-in" : ""), style: { left: pct(m.value) + "%" } }),
3903
+ m.label ? /* @__PURE__ */ jsx51("span", { className: "fd-range-mark-label", style: { left: pct(m.value) + "%" }, children: m.label }) : null
3657
3904
  ] }, m.value)),
3658
- [a, b].map((v, i) => /* @__PURE__ */ jsx48(
3905
+ [a, b].map((v, i) => /* @__PURE__ */ jsx51(
3659
3906
  "span",
3660
3907
  {
3661
3908
  className: "fd-range-thumb" + (drag === i ? " is-drag" : ""),
@@ -3670,18 +3917,18 @@ function RangeSlider({
3670
3917
  onKeyDown: key(i),
3671
3918
  onFocus: () => setFocus(i),
3672
3919
  onBlur: () => setFocus(null),
3673
- children: /* @__PURE__ */ jsx48("span", { className: "fd-range-chip", style: { opacity: showChip(i) ? 1 : void 0 }, children: fmt2(v) })
3920
+ children: /* @__PURE__ */ jsx51("span", { className: "fd-range-chip", style: { opacity: showChip(i) ? 1 : void 0 }, children: fmt2(v) })
3674
3921
  },
3675
3922
  i
3676
3923
  ))
3677
3924
  ] }),
3678
- help ? /* @__PURE__ */ jsx48("span", { className: "fd-field-help", children: help }) : null
3925
+ help ? /* @__PURE__ */ jsx51("span", { className: "fd-field-help", children: help }) : null
3679
3926
  ] });
3680
3927
  }
3681
3928
 
3682
3929
  // src/components/forms/Dropzone.tsx
3683
- import * as React22 from "react";
3684
- import { jsx as jsx49, jsxs as jsxs44 } from "react/jsx-runtime";
3930
+ import * as React24 from "react";
3931
+ import { jsx as jsx52, jsxs as jsxs47 } from "react/jsx-runtime";
3685
3932
  function Dropzone({
3686
3933
  onFiles,
3687
3934
  onReject,
@@ -3695,8 +3942,8 @@ function Dropzone({
3695
3942
  className = "",
3696
3943
  style
3697
3944
  }) {
3698
- const [over, setOver] = React22.useState(false);
3699
- const depth = React22.useRef(0);
3945
+ const [over, setOver] = React24.useState(false);
3946
+ const depth = React24.useRef(0);
3700
3947
  const has = (e) => {
3701
3948
  const dt = e.dataTransfer;
3702
3949
  if (!dt) return false;
@@ -3726,7 +3973,7 @@ function Dropzone({
3726
3973
  if (rejected.length && onReject) onReject(rejected);
3727
3974
  if (accepted.length && onFiles) onFiles(accepted);
3728
3975
  };
3729
- return /* @__PURE__ */ jsxs44(
3976
+ return /* @__PURE__ */ jsxs47(
3730
3977
  "div",
3731
3978
  {
3732
3979
  className: ["fd-dropzone", over ? "is-over" : "", className].filter(Boolean).join(" "),
@@ -3737,10 +3984,10 @@ function Dropzone({
3737
3984
  onDrop: drop,
3738
3985
  children: [
3739
3986
  children,
3740
- over ? /* @__PURE__ */ jsx49("div", { className: "fd-dropzone-veil", "aria-hidden": "true", children: /* @__PURE__ */ jsxs44("div", { className: "fd-dropzone-card", children: [
3741
- /* @__PURE__ */ jsx49("i", { className: "ph ph-tray-arrow-down" }),
3742
- /* @__PURE__ */ jsx49("span", { className: "fd-dropzone-label", children: label }),
3743
- hint ? /* @__PURE__ */ jsx49("span", { className: "fd-dropzone-hint", children: hint }) : null
3987
+ over ? /* @__PURE__ */ jsx52("div", { className: "fd-dropzone-veil", "aria-hidden": "true", children: /* @__PURE__ */ jsxs47("div", { className: "fd-dropzone-card", children: [
3988
+ /* @__PURE__ */ jsx52("i", { className: "ph ph-tray-arrow-down" }),
3989
+ /* @__PURE__ */ jsx52("span", { className: "fd-dropzone-label", children: label }),
3990
+ hint ? /* @__PURE__ */ jsx52("span", { className: "fd-dropzone-hint", children: hint }) : null
3744
3991
  ] }) }) : null
3745
3992
  ]
3746
3993
  }
@@ -3758,9 +4005,9 @@ function FilePickButton({
3758
4005
  className = "",
3759
4006
  children
3760
4007
  }) {
3761
- const ref = React22.useRef(null);
3762
- return /* @__PURE__ */ jsxs44(React22.Fragment, { children: [
3763
- /* @__PURE__ */ jsx49(
4008
+ const ref = React24.useRef(null);
4009
+ return /* @__PURE__ */ jsxs47(React24.Fragment, { children: [
4010
+ /* @__PURE__ */ jsx52(
3764
4011
  "button",
3765
4012
  {
3766
4013
  type: "button",
@@ -3769,10 +4016,10 @@ function FilePickButton({
3769
4016
  "aria-label": label,
3770
4017
  title: label,
3771
4018
  onClick: () => ref.current && ref.current.click(),
3772
- children: children != null ? children : /* @__PURE__ */ jsx49("i", { className: "ph ph-" + icon, "aria-hidden": "true" })
4019
+ children: children != null ? children : /* @__PURE__ */ jsx52("i", { className: "ph ph-" + icon, "aria-hidden": "true" })
3773
4020
  }
3774
4021
  ),
3775
- /* @__PURE__ */ jsx49(
4022
+ /* @__PURE__ */ jsx52(
3776
4023
  "input",
3777
4024
  {
3778
4025
  ref,
@@ -3792,10 +4039,10 @@ function FilePickButton({
3792
4039
  }
3793
4040
  function useStagedFiles(upload, opts) {
3794
4041
  const o = opts || {};
3795
- const [items, setItems] = React22.useState([]);
3796
- const controllers = React22.useRef({});
4042
+ const [items, setItems] = React24.useState([]);
4043
+ const controllers = React24.useRef({});
3797
4044
  const patch = (id, next) => setItems((list) => list.map((f) => f.id === id ? Object.assign({}, f, next) : f));
3798
- const run = React22.useCallback((att) => {
4045
+ const run = React24.useCallback((att) => {
3799
4046
  if (!upload) return;
3800
4047
  const ac = typeof AbortController !== "undefined" ? new AbortController() : null;
3801
4048
  controllers.current[att.id] = ac;
@@ -3812,14 +4059,14 @@ function useStagedFiles(upload, opts) {
3812
4059
  delete controllers.current[att.id];
3813
4060
  });
3814
4061
  }, [upload]);
3815
- const add = React22.useCallback((files) => {
4062
+ const add = React24.useCallback((files) => {
3816
4063
  if (!upload) return [];
3817
4064
  const atts = Array.from(files).map((f) => toAttachment(f));
3818
4065
  setItems((list) => list.concat(atts));
3819
4066
  atts.forEach(run);
3820
4067
  return atts;
3821
4068
  }, [upload, run]);
3822
- const remove = React22.useCallback((att) => {
4069
+ const remove = React24.useCallback((att) => {
3823
4070
  const ac = controllers.current[att.id];
3824
4071
  if (ac) {
3825
4072
  try {
@@ -3830,10 +4077,10 @@ function useStagedFiles(upload, opts) {
3830
4077
  }
3831
4078
  setItems((list) => list.filter((f) => f.id !== att.id));
3832
4079
  }, []);
3833
- const retry = React22.useCallback((att) => {
4080
+ const retry = React24.useCallback((att) => {
3834
4081
  run(att);
3835
4082
  }, [run]);
3836
- const clear = React22.useCallback(() => {
4083
+ const clear = React24.useCallback(() => {
3837
4084
  Object.values(controllers.current).forEach((ac) => {
3838
4085
  try {
3839
4086
  ac && ac.abort();
@@ -3849,7 +4096,7 @@ function useStagedFiles(upload, opts) {
3849
4096
  var DropzoneKit = { useStagedFiles };
3850
4097
 
3851
4098
  // src/components/forms/FileGrid.tsx
3852
- import { jsx as jsx50, jsxs as jsxs45 } from "react/jsx-runtime";
4099
+ import { jsx as jsx53, jsxs as jsxs48 } from "react/jsx-runtime";
3853
4100
  var truncateMiddle = (name, max = 34) => {
3854
4101
  if (!name || name.length <= max) return name;
3855
4102
  const ext = /\.[A-Za-z0-9]+$/.exec(name);
@@ -3858,7 +4105,7 @@ var truncateMiddle = (name, max = 34) => {
3858
4105
  return head + "\u2026" + tail;
3859
4106
  };
3860
4107
  function Progress({ value }) {
3861
- return /* @__PURE__ */ jsx50("span", { className: "fd-file-prog", role: "progressbar", "aria-valuenow": Math.round(value), "aria-valuemin": 0, "aria-valuemax": 100, children: /* @__PURE__ */ jsx50("span", { className: "fd-file-prog-fill", style: { width: Math.max(4, Math.min(100, value)) + "%" } }) });
4108
+ return /* @__PURE__ */ jsx53("span", { className: "fd-file-prog", role: "progressbar", "aria-valuenow": Math.round(value), "aria-valuemin": 0, "aria-valuemax": 100, children: /* @__PURE__ */ jsx53("span", { className: "fd-file-prog-fill", style: { width: Math.max(4, Math.min(100, value)) + "%" } }) });
3862
4109
  }
3863
4110
  function FileChip({ file, onOpen, onRemove, onRetry, compact: compact3 = false, className = "" }) {
3864
4111
  if (!file) return null;
@@ -3867,8 +4114,8 @@ function FileChip({ file, onOpen, onRemove, onRetry, compact: compact3 = false,
3867
4114
  const thumb = file.thumb && file.thumb.url || (image ? file.blobUrl || file.url : null);
3868
4115
  const meta = file.meta || (file.size ? formatBytes(file.size) : "");
3869
4116
  const clickable = !!onOpen && !uploading;
3870
- return /* @__PURE__ */ jsxs45("div", { className: ["fd-file", compact3 ? "is-compact" : "", file.error ? "is-error" : "", uploading ? "is-uploading" : "", className].filter(Boolean).join(" "), children: [
3871
- /* @__PURE__ */ jsxs45(
4117
+ return /* @__PURE__ */ jsxs48("div", { className: ["fd-file", compact3 ? "is-compact" : "", file.error ? "is-error" : "", uploading ? "is-uploading" : "", className].filter(Boolean).join(" "), children: [
4118
+ /* @__PURE__ */ jsxs48(
3872
4119
  "button",
3873
4120
  {
3874
4121
  type: "button",
@@ -3877,16 +4124,16 @@ function FileChip({ file, onOpen, onRemove, onRetry, compact: compact3 = false,
3877
4124
  onClick: clickable ? () => onOpen(file) : void 0,
3878
4125
  title: file.name + (meta ? " \xB7 " + meta : ""),
3879
4126
  children: [
3880
- /* @__PURE__ */ jsxs45("span", { className: "fd-file-icon", children: [
3881
- thumb ? /* @__PURE__ */ jsx50("img", { src: thumb, alt: "" }) : /* @__PURE__ */ jsx50("i", { className: "ph ph-" + iconForMime(file.mime, file.name), "aria-hidden": "true" }),
3882
- (file.mime || "").startsWith("video/") ? /* @__PURE__ */ jsx50("i", { className: "ph ph-play fd-file-play", "aria-hidden": "true" }) : null
4127
+ /* @__PURE__ */ jsxs48("span", { className: "fd-file-icon", children: [
4128
+ thumb ? /* @__PURE__ */ jsx53("img", { src: thumb, alt: "" }) : /* @__PURE__ */ jsx53("i", { className: "ph ph-" + iconForMime(file.mime, file.name), "aria-hidden": "true" }),
4129
+ (file.mime || "").startsWith("video/") ? /* @__PURE__ */ jsx53("i", { className: "ph ph-play fd-file-play", "aria-hidden": "true" }) : null
3883
4130
  ] }),
3884
- /* @__PURE__ */ jsxs45("span", { className: "fd-file-text", children: [
3885
- /* @__PURE__ */ jsx50("span", { className: "fd-file-name", children: truncateMiddle(file.name, compact3 ? 26 : 40) }),
3886
- /* @__PURE__ */ jsx50("span", { className: "fd-file-meta", children: file.error ? /* @__PURE__ */ jsxs45("span", { className: "fd-file-err", children: [
3887
- /* @__PURE__ */ jsx50("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
4131
+ /* @__PURE__ */ jsxs48("span", { className: "fd-file-text", children: [
4132
+ /* @__PURE__ */ jsx53("span", { className: "fd-file-name", children: truncateMiddle(file.name, compact3 ? 26 : 40) }),
4133
+ /* @__PURE__ */ jsx53("span", { className: "fd-file-meta", children: file.error ? /* @__PURE__ */ jsxs48("span", { className: "fd-file-err", children: [
4134
+ /* @__PURE__ */ jsx53("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
3888
4135
  file.error
3889
- ] }) : uploading ? /* @__PURE__ */ jsxs45("span", { className: "fd-tabular", children: [
4136
+ ] }) : uploading ? /* @__PURE__ */ jsxs48("span", { className: "fd-tabular", children: [
3890
4137
  Math.round(file.progress),
3891
4138
  "% uploaded"
3892
4139
  ] }) : meta })
@@ -3894,29 +4141,29 @@ function FileChip({ file, onOpen, onRemove, onRetry, compact: compact3 = false,
3894
4141
  ]
3895
4142
  }
3896
4143
  ),
3897
- uploading ? /* @__PURE__ */ jsx50(Progress, { value: file.progress }) : null,
3898
- file.error && onRetry ? /* @__PURE__ */ jsx50("button", { type: "button", className: "fd-file-act", onClick: () => onRetry(file), "aria-label": "Retry upload of " + file.name, children: /* @__PURE__ */ jsx50("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
3899
- onRemove ? /* @__PURE__ */ jsx50("button", { type: "button", className: "fd-file-act", onClick: () => onRemove(file), "aria-label": "Remove " + file.name, children: /* @__PURE__ */ jsx50("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
4144
+ uploading ? /* @__PURE__ */ jsx53(Progress, { value: file.progress }) : null,
4145
+ file.error && onRetry ? /* @__PURE__ */ jsx53("button", { type: "button", className: "fd-file-act", onClick: () => onRetry(file), "aria-label": "Retry upload of " + file.name, children: /* @__PURE__ */ jsx53("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
4146
+ onRemove ? /* @__PURE__ */ jsx53("button", { type: "button", className: "fd-file-act", onClick: () => onRemove(file), "aria-label": "Remove " + file.name, children: /* @__PURE__ */ jsx53("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
3900
4147
  ] });
3901
4148
  }
3902
4149
  function FileTile({ file, onOpen, onRemove, maxHeight = 200, className = "" }) {
3903
4150
  if (!file) return null;
3904
4151
  const src = file.thumb && file.thumb.url || file.blobUrl || file.url;
3905
4152
  const uploading = file.progress != null && file.progress < 100 && !file.error;
3906
- return /* @__PURE__ */ jsxs45("figure", { className: ["fd-tile", uploading ? "is-uploading" : "", file.error ? "is-error" : "", className].filter(Boolean).join(" "), children: [
3907
- /* @__PURE__ */ jsx50("button", { type: "button", className: "fd-tile-btn", onClick: onOpen ? () => onOpen(file) : void 0, disabled: !onOpen, children: src ? /* @__PURE__ */ jsx50("img", { src, alt: file.name || "", style: { maxHeight }, loading: "lazy" }) : /* @__PURE__ */ jsx50("span", { className: "fd-tile-fallback", children: /* @__PURE__ */ jsx50("i", { className: "ph ph-" + iconForMime(file.mime, file.name), "aria-hidden": "true" }) }) }),
3908
- uploading ? /* @__PURE__ */ jsx50(Progress, { value: file.progress }) : null,
3909
- file.error ? /* @__PURE__ */ jsxs45("figcaption", { className: "fd-tile-err", children: [
3910
- /* @__PURE__ */ jsx50("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
4153
+ return /* @__PURE__ */ jsxs48("figure", { className: ["fd-tile", uploading ? "is-uploading" : "", file.error ? "is-error" : "", className].filter(Boolean).join(" "), children: [
4154
+ /* @__PURE__ */ jsx53("button", { type: "button", className: "fd-tile-btn", onClick: onOpen ? () => onOpen(file) : void 0, disabled: !onOpen, children: src ? /* @__PURE__ */ jsx53("img", { src, alt: file.name || "", style: { maxHeight }, loading: "lazy" }) : /* @__PURE__ */ jsx53("span", { className: "fd-tile-fallback", children: /* @__PURE__ */ jsx53("i", { className: "ph ph-" + iconForMime(file.mime, file.name), "aria-hidden": "true" }) }) }),
4155
+ uploading ? /* @__PURE__ */ jsx53(Progress, { value: file.progress }) : null,
4156
+ file.error ? /* @__PURE__ */ jsxs48("figcaption", { className: "fd-tile-err", children: [
4157
+ /* @__PURE__ */ jsx53("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
3911
4158
  file.error
3912
4159
  ] }) : null,
3913
- onRemove ? /* @__PURE__ */ jsx50("button", { type: "button", className: "fd-tile-x", onClick: () => onRemove(file), "aria-label": "Remove " + file.name, children: /* @__PURE__ */ jsx50("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
4160
+ onRemove ? /* @__PURE__ */ jsx53("button", { type: "button", className: "fd-tile-x", onClick: () => onRemove(file), "aria-label": "Remove " + file.name, children: /* @__PURE__ */ jsx53("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
3914
4161
  ] });
3915
4162
  }
3916
4163
  function FileStrip({ files = [], size = 68, onOpen, onRemove, onRetry, className = "" }) {
3917
4164
  const list = files.filter(Boolean);
3918
4165
  if (!list.length) return null;
3919
- return /* @__PURE__ */ jsx50("div", { className: ["fd-filestrip", className].filter(Boolean).join(" "), style: { "--fd-cell": size + "px" }, children: list.map((f) => /* @__PURE__ */ jsx50(FileCell, { file: f, onOpen, onRemove, onRetry }, f.id || f.name)) });
4166
+ return /* @__PURE__ */ jsx53("div", { className: ["fd-filestrip", className].filter(Boolean).join(" "), style: { "--fd-cell": size + "px" }, children: list.map((f) => /* @__PURE__ */ jsx53(FileCell, { file: f, onOpen, onRemove, onRetry }, f.id || f.name)) });
3920
4167
  }
3921
4168
  var shortName = (name, keep = 5) => {
3922
4169
  const s = String(name || "file");
@@ -3930,19 +4177,19 @@ function FileCell({ file, onOpen, onRemove, onRetry }) {
3930
4177
  const image = isImage(file.mime, file.name);
3931
4178
  const thumb = file.thumb && file.thumb.url || (image ? file.blobUrl || file.url : null);
3932
4179
  const label = file.name + (file.size ? " \xB7 " + formatBytes(file.size) : "");
3933
- return /* @__PURE__ */ jsxs45("div", { className: ["fd-cell", file.error ? "is-error" : "", uploading ? "is-uploading" : ""].filter(Boolean).join(" "), title: file.error ? file.name + " \u2014 " + file.error : label, children: [
3934
- /* @__PURE__ */ jsxs45("button", { type: "button", className: "fd-cell-main", onClick: onOpen ? () => onOpen(file) : void 0, disabled: !onOpen || uploading, "aria-label": "Open " + file.name, children: [
3935
- thumb ? /* @__PURE__ */ jsx50("img", { src: thumb, alt: "" }) : /* @__PURE__ */ jsxs45("span", { className: "fd-cell-doc", children: [
3936
- /* @__PURE__ */ jsx50("i", { className: "ph ph-" + iconForMime(file.mime, file.name), "aria-hidden": "true" }),
3937
- /* @__PURE__ */ jsx50("span", { className: "fd-cell-name", children: shortName(file.name) }),
3938
- /* @__PURE__ */ jsx50("span", { className: "fd-cell-size", children: file.meta || formatBytes(file.size) })
4180
+ return /* @__PURE__ */ jsxs48("div", { className: ["fd-cell", file.error ? "is-error" : "", uploading ? "is-uploading" : ""].filter(Boolean).join(" "), title: file.error ? file.name + " \u2014 " + file.error : label, children: [
4181
+ /* @__PURE__ */ jsxs48("button", { type: "button", className: "fd-cell-main", onClick: onOpen ? () => onOpen(file) : void 0, disabled: !onOpen || uploading, "aria-label": "Open " + file.name, children: [
4182
+ thumb ? /* @__PURE__ */ jsx53("img", { src: thumb, alt: "" }) : /* @__PURE__ */ jsxs48("span", { className: "fd-cell-doc", children: [
4183
+ /* @__PURE__ */ jsx53("i", { className: "ph ph-" + iconForMime(file.mime, file.name), "aria-hidden": "true" }),
4184
+ /* @__PURE__ */ jsx53("span", { className: "fd-cell-name", children: shortName(file.name) }),
4185
+ /* @__PURE__ */ jsx53("span", { className: "fd-cell-size", children: file.meta || formatBytes(file.size) })
3939
4186
  ] }),
3940
- (file.mime || "").startsWith("video/") ? /* @__PURE__ */ jsx50("i", { className: "ph ph-play fd-cell-play", "aria-hidden": "true" }) : null
4187
+ (file.mime || "").startsWith("video/") ? /* @__PURE__ */ jsx53("i", { className: "ph ph-play fd-cell-play", "aria-hidden": "true" }) : null
3941
4188
  ] }),
3942
- uploading ? /* @__PURE__ */ jsx50(Progress, { value: file.progress }) : null,
3943
- file.error ? /* @__PURE__ */ jsx50("span", { className: "fd-cell-err", "aria-hidden": "true", children: /* @__PURE__ */ jsx50("i", { className: "ph ph-warning-circle" }) }) : null,
3944
- file.error && onRetry ? /* @__PURE__ */ jsx50("button", { type: "button", className: "fd-cell-x is-retry", onClick: () => onRetry(file), "aria-label": "Retry upload of " + file.name, children: /* @__PURE__ */ jsx50("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
3945
- onRemove ? /* @__PURE__ */ jsx50("button", { type: "button", className: "fd-cell-x", onClick: () => onRemove(file), "aria-label": "Remove " + file.name, children: /* @__PURE__ */ jsx50("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
4189
+ uploading ? /* @__PURE__ */ jsx53(Progress, { value: file.progress }) : null,
4190
+ file.error ? /* @__PURE__ */ jsx53("span", { className: "fd-cell-err", "aria-hidden": "true", children: /* @__PURE__ */ jsx53("i", { className: "ph ph-warning-circle" }) }) : null,
4191
+ file.error && onRetry ? /* @__PURE__ */ jsx53("button", { type: "button", className: "fd-cell-x is-retry", onClick: () => onRetry(file), "aria-label": "Retry upload of " + file.name, children: /* @__PURE__ */ jsx53("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
4192
+ onRemove ? /* @__PURE__ */ jsx53("button", { type: "button", className: "fd-cell-x", onClick: () => onRemove(file), "aria-label": "Remove " + file.name, children: /* @__PURE__ */ jsx53("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
3946
4193
  ] });
3947
4194
  }
3948
4195
  function FileGrid({ files = [], onOpen, onRemove, onRetry, tiles = true, maxHeight = 200, compact: compact3 = false, className = "" }) {
@@ -3950,15 +4197,15 @@ function FileGrid({ files = [], onOpen, onRemove, onRetry, tiles = true, maxHeig
3950
4197
  if (!list.length) return null;
3951
4198
  const pics = tiles ? list.filter((f) => isImage(f.mime, f.name)) : [];
3952
4199
  const rest = list.filter((f) => pics.indexOf(f) === -1);
3953
- return /* @__PURE__ */ jsxs45("div", { className: ["fd-filegrid", className].filter(Boolean).join(" "), children: [
3954
- pics.length ? /* @__PURE__ */ jsx50("div", { className: "fd-filegrid-tiles", children: pics.map((f) => /* @__PURE__ */ jsx50(FileTile, { file: f, onOpen, onRemove, maxHeight }, f.id || f.name)) }) : null,
3955
- rest.length ? /* @__PURE__ */ jsx50("div", { className: "fd-filegrid-chips", children: rest.map((f) => /* @__PURE__ */ jsx50(FileChip, { file: f, onOpen, onRemove, onRetry, compact: compact3 }, f.id || f.name)) }) : null
4200
+ return /* @__PURE__ */ jsxs48("div", { className: ["fd-filegrid", className].filter(Boolean).join(" "), children: [
4201
+ pics.length ? /* @__PURE__ */ jsx53("div", { className: "fd-filegrid-tiles", children: pics.map((f) => /* @__PURE__ */ jsx53(FileTile, { file: f, onOpen, onRemove, maxHeight }, f.id || f.name)) }) : null,
4202
+ rest.length ? /* @__PURE__ */ jsx53("div", { className: "fd-filegrid-chips", children: rest.map((f) => /* @__PURE__ */ jsx53(FileChip, { file: f, onOpen, onRemove, onRetry, compact: compact3 }, f.id || f.name)) }) : null
3956
4203
  ] });
3957
4204
  }
3958
4205
 
3959
4206
  // src/components/forms/MarkdownEditor.tsx
3960
- import * as React23 from "react";
3961
- import { jsx as jsx51, jsxs as jsxs46 } from "react/jsx-runtime";
4207
+ import * as React25 from "react";
4208
+ import { jsx as jsx54, jsxs as jsxs49 } from "react/jsx-runtime";
3962
4209
  var isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent || "");
3963
4210
  var INLINE_RE = /(\*\*\*[^*\n]+\*\*\*|\*\*[^*\n]+\*\*|__[^_\n]+__|~~[^~\n]+~~|`[^`\n]+`|\*[^*\s][^*\n]*\*|(?<![A-Za-z0-9_])_[^_\s][^_\n]*_|\[[^\]\n]*\]\([^)\s\n]*\)|https?:\/\/\S+)/g;
3964
4211
  function inlineParts(text) {
@@ -4171,7 +4418,7 @@ function syncDom(root, value) {
4171
4418
  while (root.children.length > lines.length) root.removeChild(root.lastChild);
4172
4419
  }
4173
4420
  var LIST_CONT = RE_LI;
4174
- var MarkdownEditor = React23.forwardRef(function MarkdownEditor2({
4421
+ var MarkdownEditor = React25.forwardRef(function MarkdownEditor2({
4175
4422
  value = "",
4176
4423
  onChange,
4177
4424
  onSubmit,
@@ -4190,10 +4437,10 @@ var MarkdownEditor = React23.forwardRef(function MarkdownEditor2({
4190
4437
  className = "",
4191
4438
  id
4192
4439
  }, ref) {
4193
- const boxRef = React23.useRef(null);
4194
- const composing = React23.useRef(false);
4195
- const pendingCaret = React23.useRef(null);
4196
- React23.useLayoutEffect(() => {
4440
+ const boxRef = React25.useRef(null);
4441
+ const composing = React25.useRef(false);
4442
+ const pendingCaret = React25.useRef(null);
4443
+ React25.useLayoutEffect(() => {
4197
4444
  const root = boxRef.current;
4198
4445
  if (!root || composing.current) return;
4199
4446
  const active = document.activeElement === root || root.contains(document.activeElement);
@@ -4202,7 +4449,7 @@ var MarkdownEditor = React23.forwardRef(function MarkdownEditor2({
4202
4449
  pendingCaret.current = null;
4203
4450
  if (active && caret != null) placeCaret(root, caret);
4204
4451
  }, [value]);
4205
- React23.useEffect(() => {
4452
+ React25.useEffect(() => {
4206
4453
  if (autoFocus && boxRef.current) boxRef.current.focus();
4207
4454
  }, [autoFocus]);
4208
4455
  const caretNow = () => {
@@ -4269,7 +4516,7 @@ var MarkdownEditor = React23.forwardRef(function MarkdownEditor2({
4269
4516
  api.replaceRange(from, to, next, from + next.length);
4270
4517
  }
4271
4518
  };
4272
- React23.useImperativeHandle(ref, () => api);
4519
+ React25.useImperativeHandle(ref, () => api);
4273
4520
  function detect(text, caret) {
4274
4521
  if (!onTrigger) return;
4275
4522
  const upto = text.slice(0, caret);
@@ -4382,8 +4629,8 @@ var MarkdownEditor = React23.forwardRef(function MarkdownEditor2({
4382
4629
  api.replaceRange(s.start, s.end, text.replace(/\r\n?/g, "\n"));
4383
4630
  };
4384
4631
  const lh = 1.55;
4385
- return /* @__PURE__ */ jsxs46("div", { className: ["fd-rme-wrap", disabled ? "is-disabled" : "", className].filter(Boolean).join(" "), children: [
4386
- /* @__PURE__ */ jsx51(
4632
+ return /* @__PURE__ */ jsxs49("div", { className: ["fd-rme-wrap", disabled ? "is-disabled" : "", className].filter(Boolean).join(" "), children: [
4633
+ /* @__PURE__ */ jsx54(
4387
4634
  "div",
4388
4635
  {
4389
4636
  ref: boxRef,
@@ -4416,15 +4663,15 @@ var MarkdownEditor = React23.forwardRef(function MarkdownEditor2({
4416
4663
  }
4417
4664
  }
4418
4665
  ),
4419
- !value ? /* @__PURE__ */ jsx51("span", { className: "fd-rme-ph", "aria-hidden": "true", children: placeholder }) : null
4666
+ !value ? /* @__PURE__ */ jsx54("span", { className: "fd-rme-ph", "aria-hidden": "true", children: placeholder }) : null
4420
4667
  ] });
4421
4668
  });
4422
4669
 
4423
4670
  // src/components/platform/AccountMenu.tsx
4424
- import * as React25 from "react";
4671
+ import * as React27 from "react";
4425
4672
 
4426
4673
  // src/kits/session.ts
4427
- import * as React24 from "react";
4674
+ import * as React26 from "react";
4428
4675
  var PERMISSION_CATALOG = [
4429
4676
  { group: "Plans", items: [
4430
4677
  { key: "plan.view", label: "View plans", detail: "Read any plan in the workspace." },
@@ -5991,8 +6238,8 @@ function roadmap(overrides) {
5991
6238
  };
5992
6239
  }
5993
6240
  function useSession() {
5994
- const [s, setS] = React24.useState(getSession);
5995
- React24.useEffect(() => subscribe(setS), []);
6241
+ const [s, setS] = React26.useState(getSession);
6242
+ React26.useEffect(() => subscribe(setS), []);
5996
6243
  return s;
5997
6244
  }
5998
6245
  var SessionKit = {
@@ -6025,7 +6272,7 @@ var SessionKit = {
6025
6272
  };
6026
6273
 
6027
6274
  // src/components/platform/AccountMenu.tsx
6028
- import { Fragment as Fragment11, jsx as jsx52, jsxs as jsxs47 } from "react/jsx-runtime";
6275
+ import { Fragment as Fragment11, jsx as jsx55, jsxs as jsxs50 } from "react/jsx-runtime";
6029
6276
  var DEFAULT_LINKS = [
6030
6277
  { id: "profile", label: "Your profile", icon: "user-circle", href: "../admin/index.html#profile" },
6031
6278
  { id: "preferences", label: "Preferences", icon: "sliders-horizontal", href: "../admin/index.html#preferences" }
@@ -6036,7 +6283,7 @@ var DEFAULT_ADMIN_LINKS = [
6036
6283
  { id: "flags", label: "Feature flags", icon: "toggle-right", href: "../admin/index.html#flags", perm: "flags.manage" }
6037
6284
  ];
6038
6285
  function Item({ item, onPick }) {
6039
- return /* @__PURE__ */ jsxs47(
6286
+ return /* @__PURE__ */ jsxs50(
6040
6287
  "button",
6041
6288
  {
6042
6289
  type: "button",
@@ -6044,9 +6291,9 @@ function Item({ item, onPick }) {
6044
6291
  className: "fd-acct-item",
6045
6292
  onClick: () => onPick(item),
6046
6293
  children: [
6047
- /* @__PURE__ */ jsx52("i", { className: "ph ph-" + item.icon, "aria-hidden": "true" }),
6048
- /* @__PURE__ */ jsx52("span", { style: { flex: 1 }, children: item.label }),
6049
- item.badge ? /* @__PURE__ */ jsx52(Badge, { tone: "neutral", children: item.badge }) : null
6294
+ /* @__PURE__ */ jsx55("i", { className: "ph ph-" + item.icon, "aria-hidden": "true" }),
6295
+ /* @__PURE__ */ jsx55("span", { style: { flex: 1 }, children: item.label }),
6296
+ item.badge ? /* @__PURE__ */ jsx55(Badge, { tone: "neutral", children: item.badge }) : null
6050
6297
  ]
6051
6298
  }
6052
6299
  );
@@ -6062,9 +6309,9 @@ function AccountMenu({
6062
6309
  ...rest
6063
6310
  }) {
6064
6311
  const session = SessionKit.useSession();
6065
- const [open, setOpen] = React25.useState(false);
6066
- const [switching, setSwitching] = React25.useState(false);
6067
- const ref = React25.useRef(null);
6312
+ const [open, setOpen] = React27.useState(false);
6313
+ const [switching, setSwitching] = React27.useState(false);
6314
+ const ref = React27.useRef(null);
6068
6315
  const user = session.user;
6069
6316
  const visibleAdmin = adminLinks.filter((l) => !l.perm || SessionKit.can(l.perm));
6070
6317
  const pick = (item) => {
@@ -6078,8 +6325,8 @@ function AccountMenu({
6078
6325
  if (onSignOut) return onSignOut();
6079
6326
  window.alert("Signed out. (Simulated \u2014 no auth provider is wired up.)");
6080
6327
  };
6081
- return /* @__PURE__ */ jsxs47(Fragment11, { children: [
6082
- /* @__PURE__ */ jsxs47(
6328
+ return /* @__PURE__ */ jsxs50(Fragment11, { children: [
6329
+ /* @__PURE__ */ jsxs50(
6083
6330
  "button",
6084
6331
  {
6085
6332
  type: "button",
@@ -6091,32 +6338,32 @@ function AccountMenu({
6091
6338
  onClick: () => setOpen((o) => !o),
6092
6339
  ...rest,
6093
6340
  children: [
6094
- /* @__PURE__ */ jsx52(Avatar, { name: user.name, size: "sm" }),
6095
- /* @__PURE__ */ jsx52("i", { className: "ph ph-caret-down", "aria-hidden": "true", style: { fontSize: 11, color: "var(--text-muted)" } })
6341
+ /* @__PURE__ */ jsx55(Avatar, { name: user.name, size: "sm" }),
6342
+ /* @__PURE__ */ jsx55("i", { className: "ph ph-caret-down", "aria-hidden": "true", style: { fontSize: 11, color: "var(--text-muted)" } })
6096
6343
  ]
6097
6344
  }
6098
6345
  ),
6099
- /* @__PURE__ */ jsx52(Popover, { open, anchorRef: ref, onClose: () => setOpen(false), placement: "bottom-end", width: 272, children: /* @__PURE__ */ jsxs47("div", { role: "menu", className: "fd-stack", style: { gap: 0 }, children: [
6100
- /* @__PURE__ */ jsxs47("div", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
6101
- /* @__PURE__ */ jsx52(Avatar, { name: user.name }),
6102
- /* @__PURE__ */ jsxs47("span", { className: "fd-stack", style: { gap: 1, minWidth: 0, flex: 1 }, children: [
6103
- /* @__PURE__ */ jsx52("span", { className: "fd-body-sm", style: { fontWeight: 700 }, children: user.name }),
6104
- /* @__PURE__ */ jsx52("span", { className: "fd-body-sm fd-muted fd-table-trunc", children: user.email })
6346
+ /* @__PURE__ */ jsx55(Popover, { open, anchorRef: ref, onClose: () => setOpen(false), placement: "bottom-end", width: 272, children: /* @__PURE__ */ jsxs50("div", { role: "menu", className: "fd-stack", style: { gap: 0 }, children: [
6347
+ /* @__PURE__ */ jsxs50("div", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
6348
+ /* @__PURE__ */ jsx55(Avatar, { name: user.name }),
6349
+ /* @__PURE__ */ jsxs50("span", { className: "fd-stack", style: { gap: 1, minWidth: 0, flex: 1 }, children: [
6350
+ /* @__PURE__ */ jsx55("span", { className: "fd-body-sm", style: { fontWeight: 700 }, children: user.name }),
6351
+ /* @__PURE__ */ jsx55("span", { className: "fd-body-sm fd-muted fd-table-trunc", children: user.email })
6105
6352
  ] })
6106
6353
  ] }),
6107
- showRoles && session.roles.length ? /* @__PURE__ */ jsx52("div", { className: "fd-row", style: { gap: 6, padding: "10px 14px", flexWrap: "wrap", borderBottom: "1px solid var(--border)" }, children: session.roles.map((r) => /* @__PURE__ */ jsx52(Badge, { tone: r.id === "owner" ? "success" : "neutral", children: r.name }, r.id)) }) : null,
6108
- /* @__PURE__ */ jsx52("div", { className: "fd-acct-group", children: links.map((l) => /* @__PURE__ */ jsx52(Item, { item: l, onPick: pick }, l.id)) }),
6109
- visibleAdmin.length ? /* @__PURE__ */ jsxs47("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: [
6110
- /* @__PURE__ */ jsx52("span", { className: "fd-overline fd-muted", style: { padding: "8px 14px 4px", display: "block" }, children: "Administration" }),
6111
- visibleAdmin.map((l) => /* @__PURE__ */ jsx52(Item, { item: l, onPick: pick }, l.id))
6354
+ showRoles && session.roles.length ? /* @__PURE__ */ jsx55("div", { className: "fd-row", style: { gap: 6, padding: "10px 14px", flexWrap: "wrap", borderBottom: "1px solid var(--border)" }, children: session.roles.map((r) => /* @__PURE__ */ jsx55(Badge, { tone: r.id === "owner" ? "success" : "neutral", children: r.name }, r.id)) }) : null,
6355
+ /* @__PURE__ */ jsx55("div", { className: "fd-acct-group", children: links.map((l) => /* @__PURE__ */ jsx55(Item, { item: l, onPick: pick }, l.id)) }),
6356
+ visibleAdmin.length ? /* @__PURE__ */ jsxs50("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: [
6357
+ /* @__PURE__ */ jsx55("span", { className: "fd-overline fd-muted", style: { padding: "8px 14px 4px", display: "block" }, children: "Administration" }),
6358
+ visibleAdmin.map((l) => /* @__PURE__ */ jsx55(Item, { item: l, onPick: pick }, l.id))
6112
6359
  ] }) : null,
6113
- allowUserSwitch ? /* @__PURE__ */ jsxs47("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: [
6114
- /* @__PURE__ */ jsxs47("button", { type: "button", role: "menuitem", className: "fd-acct-item", onClick: () => setSwitching((s) => !s), children: [
6115
- /* @__PURE__ */ jsx52("i", { className: "ph ph-user-switch", "aria-hidden": "true" }),
6116
- /* @__PURE__ */ jsx52("span", { style: { flex: 1 }, children: "View as another member" }),
6117
- /* @__PURE__ */ jsx52("i", { className: "ph ph-caret-" + (switching ? "up" : "down"), "aria-hidden": "true", style: { fontSize: 11 } })
6360
+ allowUserSwitch ? /* @__PURE__ */ jsxs50("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: [
6361
+ /* @__PURE__ */ jsxs50("button", { type: "button", role: "menuitem", className: "fd-acct-item", onClick: () => setSwitching((s) => !s), children: [
6362
+ /* @__PURE__ */ jsx55("i", { className: "ph ph-user-switch", "aria-hidden": "true" }),
6363
+ /* @__PURE__ */ jsx55("span", { style: { flex: 1 }, children: "View as another member" }),
6364
+ /* @__PURE__ */ jsx55("i", { className: "ph ph-caret-" + (switching ? "up" : "down"), "aria-hidden": "true", style: { fontSize: 11 } })
6118
6365
  ] }),
6119
- switching ? /* @__PURE__ */ jsx52("div", { className: "fd-stack", style: { gap: 0, maxHeight: 208, overflowY: "auto" }, children: session.allUsers.filter((u) => u.status === "active").map((u) => /* @__PURE__ */ jsxs47(
6366
+ switching ? /* @__PURE__ */ jsx55("div", { className: "fd-stack", style: { gap: 0, maxHeight: 208, overflowY: "auto" }, children: session.allUsers.filter((u) => u.status === "active").map((u) => /* @__PURE__ */ jsxs50(
6120
6367
  "button",
6121
6368
  {
6122
6369
  type: "button",
@@ -6128,34 +6375,34 @@ function AccountMenu({
6128
6375
  setSwitching(false);
6129
6376
  },
6130
6377
  children: [
6131
- /* @__PURE__ */ jsx52(Avatar, { name: u.name, size: "sm" }),
6132
- /* @__PURE__ */ jsxs47("span", { className: "fd-stack", style: { gap: 0, flex: 1, minWidth: 0, alignItems: "flex-start" }, children: [
6133
- /* @__PURE__ */ jsx52("span", { style: { fontWeight: u.id === user.id ? 700 : 500 }, children: u.name }),
6134
- /* @__PURE__ */ jsx52("span", { className: "fd-muted", style: { fontSize: 11.5 }, children: u.roles.join(", ") })
6378
+ /* @__PURE__ */ jsx55(Avatar, { name: u.name, size: "sm" }),
6379
+ /* @__PURE__ */ jsxs50("span", { className: "fd-stack", style: { gap: 0, flex: 1, minWidth: 0, alignItems: "flex-start" }, children: [
6380
+ /* @__PURE__ */ jsx55("span", { style: { fontWeight: u.id === user.id ? 700 : 500 }, children: u.name }),
6381
+ /* @__PURE__ */ jsx55("span", { className: "fd-muted", style: { fontSize: 11.5 }, children: u.roles.join(", ") })
6135
6382
  ] }),
6136
- u.id === user.id ? /* @__PURE__ */ jsx52("i", { className: "ph ph-check", "aria-hidden": "true", style: { color: "var(--ok-text)" } }) : null
6383
+ u.id === user.id ? /* @__PURE__ */ jsx55("i", { className: "ph ph-check", "aria-hidden": "true", style: { color: "var(--ok-text)" } }) : null
6137
6384
  ]
6138
6385
  },
6139
6386
  u.id
6140
6387
  )) }) : null
6141
6388
  ] }) : null,
6142
- /* @__PURE__ */ jsx52("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: /* @__PURE__ */ jsxs47("button", { type: "button", role: "menuitem", className: "fd-acct-item", "data-danger": "true", onClick: signOut, children: [
6143
- /* @__PURE__ */ jsx52("i", { className: "ph ph-sign-out", "aria-hidden": "true" }),
6144
- /* @__PURE__ */ jsx52("span", { style: { flex: 1 }, children: "Sign out" })
6389
+ /* @__PURE__ */ jsx55("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: /* @__PURE__ */ jsxs50("button", { type: "button", role: "menuitem", className: "fd-acct-item", "data-danger": "true", onClick: signOut, children: [
6390
+ /* @__PURE__ */ jsx55("i", { className: "ph ph-sign-out", "aria-hidden": "true" }),
6391
+ /* @__PURE__ */ jsx55("span", { style: { flex: 1 }, children: "Sign out" })
6145
6392
  ] }) })
6146
6393
  ] }) })
6147
6394
  ] });
6148
6395
  }
6149
6396
 
6150
6397
  // src/components/platform/ApiSpecBrowser.tsx
6151
- import * as React26 from "react";
6152
- import { jsx as jsx53, jsxs as jsxs48 } from "react/jsx-runtime";
6398
+ import * as React28 from "react";
6399
+ import { jsx as jsx56, jsxs as jsxs51 } from "react/jsx-runtime";
6153
6400
  var METHOD_TONE = { GET: "success", POST: "info", PATCH: "warning", PUT: "warning", DELETE: "danger" };
6154
6401
  function Json({ obj }) {
6155
- return /* @__PURE__ */ jsx53("pre", { className: "fd-json", children: JSON.stringify(obj, null, 2) });
6402
+ return /* @__PURE__ */ jsx56("pre", { className: "fd-json", children: JSON.stringify(obj, null, 2) });
6156
6403
  }
6157
6404
  function Endpoint({ s, onRequest }) {
6158
- const [tried, setTried] = React26.useState(null);
6405
+ const [tried, setTried] = React28.useState(null);
6159
6406
  const run = async () => {
6160
6407
  setTried("busy");
6161
6408
  const t0 = (window.performance || Date).now();
@@ -6166,50 +6413,50 @@ function Endpoint({ s, onRequest }) {
6166
6413
  setTried({ ms: Math.round((window.performance || Date).now() - t0), error: String(e && e.message || e) });
6167
6414
  }
6168
6415
  };
6169
- return /* @__PURE__ */ jsx53(Card, { elevation: "flat", padded: false, children: /* @__PURE__ */ jsxs48("div", { className: "fd-stack", style: { gap: 0 }, children: [
6170
- /* @__PURE__ */ jsxs48("div", { className: "fd-row", style: { gap: 10, padding: "14px 18px", flexWrap: "wrap" }, children: [
6171
- /* @__PURE__ */ jsx53(Badge, { tone: METHOD_TONE[s.method] || "neutral", children: s.method }),
6172
- /* @__PURE__ */ jsx53("code", { className: "fd-mono", style: { fontSize: 12.5, fontWeight: 600, color: "var(--text)", wordBreak: "break-all" }, children: s.path }),
6173
- s.isList ? /* @__PURE__ */ jsx53(Badge, { tone: "neutral", icon: "rows", children: "Paged list" }) : null,
6174
- /* @__PURE__ */ jsx53("span", { style: { flex: 1 } }),
6175
- /* @__PURE__ */ jsxs48("span", { className: "fd-body-sm fd-muted fd-mono", children: [
6416
+ return /* @__PURE__ */ jsx56(Card, { elevation: "flat", padded: false, children: /* @__PURE__ */ jsxs51("div", { className: "fd-stack", style: { gap: 0 }, children: [
6417
+ /* @__PURE__ */ jsxs51("div", { className: "fd-row", style: { gap: 10, padding: "14px 18px", flexWrap: "wrap" }, children: [
6418
+ /* @__PURE__ */ jsx56(Badge, { tone: METHOD_TONE[s.method] || "neutral", children: s.method }),
6419
+ /* @__PURE__ */ jsx56("code", { className: "fd-mono", style: { fontSize: 12.5, fontWeight: 600, color: "var(--text)", wordBreak: "break-all" }, children: s.path }),
6420
+ s.isList ? /* @__PURE__ */ jsx56(Badge, { tone: "neutral", icon: "rows", children: "Paged list" }) : null,
6421
+ /* @__PURE__ */ jsx56("span", { style: { flex: 1 } }),
6422
+ /* @__PURE__ */ jsxs51("span", { className: "fd-body-sm fd-muted fd-mono", children: [
6176
6423
  s.latency[0],
6177
6424
  "\u2013",
6178
6425
  s.latency[1],
6179
6426
  "ms"
6180
6427
  ] }),
6181
- /* @__PURE__ */ jsx53(Button, { size: "sm", variant: "secondary", icon: "play", loading: tried === "busy", onClick: run, children: "Try it" })
6428
+ /* @__PURE__ */ jsx56(Button, { size: "sm", variant: "secondary", icon: "play", loading: tried === "busy", onClick: run, children: "Try it" })
6182
6429
  ] }),
6183
- /* @__PURE__ */ jsxs48("div", { className: "fd-stack", style: { gap: 14, padding: "0 18px 16px" }, children: [
6184
- /* @__PURE__ */ jsxs48("div", { className: "fd-stack", style: { gap: 6 }, children: [
6185
- /* @__PURE__ */ jsx53("span", { className: "fd-body-sm", style: { fontWeight: 700 }, children: s.title }),
6186
- /* @__PURE__ */ jsx53("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: s.purpose }),
6187
- s.usedBy && s.usedBy.length ? /* @__PURE__ */ jsx53("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: s.usedBy.map((u) => /* @__PURE__ */ jsx53(Tag, { children: u }, u)) }) : null
6430
+ /* @__PURE__ */ jsxs51("div", { className: "fd-stack", style: { gap: 14, padding: "0 18px 16px" }, children: [
6431
+ /* @__PURE__ */ jsxs51("div", { className: "fd-stack", style: { gap: 6 }, children: [
6432
+ /* @__PURE__ */ jsx56("span", { className: "fd-body-sm", style: { fontWeight: 700 }, children: s.title }),
6433
+ /* @__PURE__ */ jsx56("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: s.purpose }),
6434
+ s.usedBy && s.usedBy.length ? /* @__PURE__ */ jsx56("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: s.usedBy.map((u) => /* @__PURE__ */ jsx56(Tag, { children: u }, u)) }) : null
6188
6435
  ] }),
6189
- /* @__PURE__ */ jsxs48("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(280px,1fr))", gap: 12, alignItems: "start" }, children: [
6190
- s.request ? /* @__PURE__ */ jsxs48("div", { className: "fd-stack", style: { gap: 6 }, children: [
6191
- /* @__PURE__ */ jsx53("span", { className: "fd-overline fd-muted", children: "Request body" }),
6192
- /* @__PURE__ */ jsx53(Json, { obj: s.request })
6436
+ /* @__PURE__ */ jsxs51("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(280px,1fr))", gap: 12, alignItems: "start" }, children: [
6437
+ s.request ? /* @__PURE__ */ jsxs51("div", { className: "fd-stack", style: { gap: 6 }, children: [
6438
+ /* @__PURE__ */ jsx56("span", { className: "fd-overline fd-muted", children: "Request body" }),
6439
+ /* @__PURE__ */ jsx56(Json, { obj: s.request })
6193
6440
  ] }) : null,
6194
- s.query ? /* @__PURE__ */ jsxs48("div", { className: "fd-stack", style: { gap: 6 }, children: [
6195
- /* @__PURE__ */ jsx53("span", { className: "fd-overline fd-muted", children: "Query" }),
6196
- /* @__PURE__ */ jsx53(Json, { obj: s.query })
6441
+ s.query ? /* @__PURE__ */ jsxs51("div", { className: "fd-stack", style: { gap: 6 }, children: [
6442
+ /* @__PURE__ */ jsx56("span", { className: "fd-overline fd-muted", children: "Query" }),
6443
+ /* @__PURE__ */ jsx56(Json, { obj: s.query })
6197
6444
  ] }) : null,
6198
- /* @__PURE__ */ jsxs48("div", { className: "fd-stack", style: { gap: 6 }, children: [
6199
- /* @__PURE__ */ jsx53("span", { className: "fd-overline fd-muted", children: "Response 200" }),
6200
- /* @__PURE__ */ jsx53(Json, { obj: s.response })
6445
+ /* @__PURE__ */ jsxs51("div", { className: "fd-stack", style: { gap: 6 }, children: [
6446
+ /* @__PURE__ */ jsx56("span", { className: "fd-overline fd-muted", children: "Response 200" }),
6447
+ /* @__PURE__ */ jsx56(Json, { obj: s.response })
6201
6448
  ] })
6202
6449
  ] }),
6203
- s.notes ? /* @__PURE__ */ jsx53(Flag, { tone: "info", statement: "Implementation note", cost: s.notes, actions: null }) : null,
6204
- tried && tried !== "busy" ? /* @__PURE__ */ jsxs48("div", { className: "fd-stack", style: { gap: 6 }, children: [
6205
- /* @__PURE__ */ jsxs48("span", { className: "fd-row", style: { gap: 8 }, children: [
6206
- /* @__PURE__ */ jsx53("span", { className: "fd-overline fd-muted", children: "Simulated response" }),
6207
- /* @__PURE__ */ jsxs48(Badge, { tone: tried.error ? "danger" : "success", icon: "timer", children: [
6450
+ s.notes ? /* @__PURE__ */ jsx56(Flag, { tone: "info", statement: "Implementation note", cost: s.notes, actions: null }) : null,
6451
+ tried && tried !== "busy" ? /* @__PURE__ */ jsxs51("div", { className: "fd-stack", style: { gap: 6 }, children: [
6452
+ /* @__PURE__ */ jsxs51("span", { className: "fd-row", style: { gap: 8 }, children: [
6453
+ /* @__PURE__ */ jsx56("span", { className: "fd-overline fd-muted", children: "Simulated response" }),
6454
+ /* @__PURE__ */ jsxs51(Badge, { tone: tried.error ? "danger" : "success", icon: "timer", children: [
6208
6455
  tried.ms,
6209
6456
  "ms"
6210
6457
  ] })
6211
6458
  ] }),
6212
- /* @__PURE__ */ jsx53(Json, { obj: tried.error ? { error: tried.error } : tried.data })
6459
+ /* @__PURE__ */ jsx56(Json, { obj: tried.error ? { error: tried.error } : tried.data })
6213
6460
  ] }) : null
6214
6461
  ] })
6215
6462
  ] }) });
@@ -6228,58 +6475,58 @@ function ApiSpecBrowser({
6228
6475
  className = "",
6229
6476
  ...rest
6230
6477
  }) {
6231
- const [q, setQ] = React26.useState("");
6232
- const [method, setMethod] = React26.useState(null);
6233
- const [mod, setMod] = React26.useState(null);
6234
- const [listOnly, setListOnly] = React26.useState(false);
6478
+ const [q, setQ] = React28.useState("");
6479
+ const [method, setMethod] = React28.useState(null);
6480
+ const [mod, setMod] = React28.useState(null);
6481
+ const [listOnly, setListOnly] = React28.useState(false);
6235
6482
  const activeModule = modules && modules.find((m) => m.id === mod);
6236
6483
  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())));
6237
6484
  const effGroups = groups && groups.length ? groups : [["All endpoints", spec.map((s) => s.id)]];
6238
6485
  const methods = [...new Set(spec.map((s) => s.method))];
6239
6486
  const listCount = spec.filter((s) => s.isList).length;
6240
- return /* @__PURE__ */ jsxs48("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 1100 }, ...rest, children: [
6241
- /* @__PURE__ */ jsxs48("div", { className: "fd-stack", style: { gap: 10 }, children: [
6242
- kicker ? /* @__PURE__ */ jsx53("span", { className: "fd-overline fd-muted", children: kicker }) : null,
6243
- /* @__PURE__ */ jsx53("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
6244
- lede ? /* @__PURE__ */ jsx53("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: lede }) : null
6487
+ return /* @__PURE__ */ jsxs51("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 1100 }, ...rest, children: [
6488
+ /* @__PURE__ */ jsxs51("div", { className: "fd-stack", style: { gap: 10 }, children: [
6489
+ kicker ? /* @__PURE__ */ jsx56("span", { className: "fd-overline fd-muted", children: kicker }) : null,
6490
+ /* @__PURE__ */ jsx56("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
6491
+ lede ? /* @__PURE__ */ jsx56("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: lede }) : null
6245
6492
  ] }),
6246
- modules && modules.length ? /* @__PURE__ */ jsxs48("div", { className: "fd-stack", style: { gap: 8 }, children: [
6247
- /* @__PURE__ */ jsx53("span", { className: "fd-overline fd-muted", children: "Filter by screen \u2014 every endpoint that screen depends on" }),
6248
- /* @__PURE__ */ jsxs48("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
6249
- /* @__PURE__ */ jsxs48(Tag, { icon: "stack", selected: !mod, onClick: () => setMod(null), children: [
6493
+ modules && modules.length ? /* @__PURE__ */ jsxs51("div", { className: "fd-stack", style: { gap: 8 }, children: [
6494
+ /* @__PURE__ */ jsx56("span", { className: "fd-overline fd-muted", children: "Filter by screen \u2014 every endpoint that screen depends on" }),
6495
+ /* @__PURE__ */ jsxs51("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
6496
+ /* @__PURE__ */ jsxs51(Tag, { icon: "stack", selected: !mod, onClick: () => setMod(null), children: [
6250
6497
  "All screens ",
6251
- /* @__PURE__ */ jsx53("span", { className: "fd-mono", children: spec.length })
6498
+ /* @__PURE__ */ jsx56("span", { className: "fd-mono", children: spec.length })
6252
6499
  ] }),
6253
- modules.map((m) => /* @__PURE__ */ jsxs48(Tag, { icon: m.icon, selected: mod === m.id, onClick: () => setMod(mod === m.id ? null : m.id), children: [
6500
+ modules.map((m) => /* @__PURE__ */ jsxs51(Tag, { icon: m.icon, selected: mod === m.id, onClick: () => setMod(mod === m.id ? null : m.id), children: [
6254
6501
  m.label,
6255
6502
  " ",
6256
- /* @__PURE__ */ jsx53("span", { className: "fd-mono", children: m.endpoints.length })
6503
+ /* @__PURE__ */ jsx56("span", { className: "fd-mono", children: m.endpoints.length })
6257
6504
  ] }, m.id))
6258
6505
  ] }),
6259
- activeModule ? /* @__PURE__ */ jsx53(
6506
+ activeModule ? /* @__PURE__ */ jsx56(
6260
6507
  Flag,
6261
6508
  {
6262
6509
  tone: "info",
6263
6510
  statement: activeModule.label + " calls " + activeModule.endpoints.length + " endpoints.",
6264
6511
  cost: "Integration checklist for this screen: " + activeModule.endpoints.join(", ") + ". Wire these and the screen is done.",
6265
- actions: /* @__PURE__ */ jsx53(Button, { size: "sm", variant: "ghost", icon: "x", onClick: () => setMod(null), children: "Show all screens" })
6512
+ actions: /* @__PURE__ */ jsx56(Button, { size: "sm", variant: "ghost", icon: "x", onClick: () => setMod(null), children: "Show all screens" })
6266
6513
  }
6267
6514
  ) : null
6268
6515
  ] }) : null,
6269
- sourceNote ? /* @__PURE__ */ jsx53(Flag, { tone: "info", statement: "Design-first: this page is the spec.", cost: sourceNote, actions: null }) : null,
6270
- /* @__PURE__ */ jsxs48("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
6271
- /* @__PURE__ */ jsx53(Input, { icon: "magnifying-glass", placeholder: "Find an endpoint, screen, or behavior", value: q, onChange: (e) => setQ(e.target.value), style: { width: 300 } }),
6272
- methods.map((m) => /* @__PURE__ */ jsxs48(Tag, { selected: method === m, onClick: () => setMethod(method === m ? null : m), children: [
6516
+ sourceNote ? /* @__PURE__ */ jsx56(Flag, { tone: "info", statement: "Design-first: this page is the spec.", cost: sourceNote, actions: null }) : null,
6517
+ /* @__PURE__ */ jsxs51("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
6518
+ /* @__PURE__ */ jsx56(Input, { icon: "magnifying-glass", placeholder: "Find an endpoint, screen, or behavior", value: q, onChange: (e) => setQ(e.target.value), style: { width: 300 } }),
6519
+ methods.map((m) => /* @__PURE__ */ jsxs51(Tag, { selected: method === m, onClick: () => setMethod(method === m ? null : m), children: [
6273
6520
  m,
6274
6521
  " ",
6275
- /* @__PURE__ */ jsx53("span", { className: "fd-mono", children: spec.filter((s) => s.method === m).length })
6522
+ /* @__PURE__ */ jsx56("span", { className: "fd-mono", children: spec.filter((s) => s.method === m).length })
6276
6523
  ] }, m)),
6277
- listCount ? /* @__PURE__ */ jsxs48(Tag, { icon: "rows", selected: listOnly, onClick: () => setListOnly(!listOnly), children: [
6524
+ listCount ? /* @__PURE__ */ jsxs51(Tag, { icon: "rows", selected: listOnly, onClick: () => setListOnly(!listOnly), children: [
6278
6525
  "Paged lists ",
6279
- /* @__PURE__ */ jsx53("span", { className: "fd-mono", children: listCount })
6526
+ /* @__PURE__ */ jsx56("span", { className: "fd-mono", children: listCount })
6280
6527
  ] }) : null,
6281
- /* @__PURE__ */ jsx53("span", { style: { flex: 1 } }),
6282
- /* @__PURE__ */ jsxs48("span", { className: "fd-body-sm fd-muted", children: [
6528
+ /* @__PURE__ */ jsx56("span", { style: { flex: 1 } }),
6529
+ /* @__PURE__ */ jsxs51("span", { className: "fd-body-sm fd-muted", children: [
6283
6530
  hits.length,
6284
6531
  " of ",
6285
6532
  spec.length,
@@ -6287,31 +6534,31 @@ function ApiSpecBrowser({
6287
6534
  listCount ? " \xB7 " + listCount + " paged" : ""
6288
6535
  ] })
6289
6536
  ] }),
6290
- hits.length === 0 ? /* @__PURE__ */ jsx53(Card, { elevation: "flat", children: /* @__PURE__ */ jsx53("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: "No endpoint matches those filters." }) }) : effGroups.map(([g, ids]) => {
6537
+ hits.length === 0 ? /* @__PURE__ */ jsx56(Card, { elevation: "flat", children: /* @__PURE__ */ jsx56("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: "No endpoint matches those filters." }) }) : effGroups.map(([g, ids]) => {
6291
6538
  const items = hits.filter((s) => ids.indexOf(s.id) >= 0);
6292
6539
  if (!items.length) return null;
6293
- return /* @__PURE__ */ jsxs48("div", { className: "fd-stack", style: { gap: 12 }, children: [
6294
- /* @__PURE__ */ jsx53("span", { className: "fd-label-lg", children: g }),
6295
- items.map((s) => /* @__PURE__ */ jsx53(Endpoint, { s, onRequest }, s.id))
6540
+ return /* @__PURE__ */ jsxs51("div", { className: "fd-stack", style: { gap: 12 }, children: [
6541
+ /* @__PURE__ */ jsx56("span", { className: "fd-label-lg", children: g }),
6542
+ items.map((s) => /* @__PURE__ */ jsx56(Endpoint, { s, onRequest }, s.id))
6296
6543
  ] }, g);
6297
6544
  }),
6298
- conventions && conventions.length ? /* @__PURE__ */ jsx53(Card, { title: "Cross-cutting conventions", elevation: "flat", children: /* @__PURE__ */ jsx53("div", { className: "fd-stack", style: { gap: 10 }, children: conventions.map(([k, v]) => /* @__PURE__ */ jsxs48("div", { className: "fd-row", style: { gap: 12, alignItems: "flex-start" }, children: [
6299
- /* @__PURE__ */ jsx53("span", { className: "fd-overline fd-muted", style: { width: 110, flex: "none", paddingTop: 2 }, children: k }),
6300
- /* @__PURE__ */ jsx53("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: v })
6545
+ conventions && conventions.length ? /* @__PURE__ */ jsx56(Card, { title: "Cross-cutting conventions", elevation: "flat", children: /* @__PURE__ */ jsx56("div", { className: "fd-stack", style: { gap: 10 }, children: conventions.map(([k, v]) => /* @__PURE__ */ jsxs51("div", { className: "fd-row", style: { gap: 12, alignItems: "flex-start" }, children: [
6546
+ /* @__PURE__ */ jsx56("span", { className: "fd-overline fd-muted", style: { width: 110, flex: "none", paddingTop: 2 }, children: k }),
6547
+ /* @__PURE__ */ jsx56("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: v })
6301
6548
  ] }, k)) }) }) : null,
6302
- openQuestions && openQuestions.length ? /* @__PURE__ */ jsx53(Collapsible, { icon: "list-checks", title: "Open questions before implementation", subtitle: openQuestions.length + " unresolved", children: /* @__PURE__ */ jsx53("div", { className: "fd-stack", style: { gap: 8 }, children: openQuestions.map(([id, question, why]) => /* @__PURE__ */ jsxs48("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start", padding: "8px 0", borderTop: "1px solid var(--border)" }, children: [
6303
- /* @__PURE__ */ jsx53(Badge, { tone: "danger", children: id }),
6304
- /* @__PURE__ */ jsxs48("span", { className: "fd-stack", style: { gap: 2, flex: 1 }, children: [
6305
- /* @__PURE__ */ jsx53("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: question }),
6306
- /* @__PURE__ */ jsx53("span", { className: "fd-body-sm fd-muted", children: why })
6549
+ openQuestions && openQuestions.length ? /* @__PURE__ */ jsx56(Collapsible, { icon: "list-checks", title: "Open questions before implementation", subtitle: openQuestions.length + " unresolved", children: /* @__PURE__ */ jsx56("div", { className: "fd-stack", style: { gap: 8 }, children: openQuestions.map(([id, question, why]) => /* @__PURE__ */ jsxs51("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start", padding: "8px 0", borderTop: "1px solid var(--border)" }, children: [
6550
+ /* @__PURE__ */ jsx56(Badge, { tone: "danger", children: id }),
6551
+ /* @__PURE__ */ jsxs51("span", { className: "fd-stack", style: { gap: 2, flex: 1 }, children: [
6552
+ /* @__PURE__ */ jsx56("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: question }),
6553
+ /* @__PURE__ */ jsx56("span", { className: "fd-body-sm fd-muted", children: why })
6307
6554
  ] })
6308
6555
  ] }, id)) }) }) : null
6309
6556
  ] });
6310
6557
  }
6311
6558
 
6312
6559
  // src/components/platform/ProfilePage.tsx
6313
- import * as React27 from "react";
6314
- import { jsx as jsx54, jsxs as jsxs49 } from "react/jsx-runtime";
6560
+ import * as React29 from "react";
6561
+ import { jsx as jsx57, jsxs as jsxs52 } from "react/jsx-runtime";
6315
6562
  var TIMEZONES = ["America/New_York", "America/Chicago", "America/Denver", "America/Los_Angeles", "America/Anchorage", "Pacific/Honolulu", "Europe/London", "Europe/Berlin"];
6316
6563
  var NOTIFY = [
6317
6564
  { key: "planShared", label: "A plan is shared with me", detail: "Someone sends you a plan or a client link." },
@@ -6323,7 +6570,7 @@ var NOTIFY = [
6323
6570
  function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSessions = true, className = "", ...rest }) {
6324
6571
  const session = SessionKit.useSession();
6325
6572
  const user = userProp || session.user;
6326
- const [draft, setDraft] = React27.useState(() => ({
6573
+ const [draft, setDraft] = React29.useState(() => ({
6327
6574
  name: user.name || "",
6328
6575
  title: user.title || "",
6329
6576
  email: user.email || "",
@@ -6332,8 +6579,8 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
6332
6579
  bio: user.bio || "",
6333
6580
  notify: user.notify || { planShared: true, planChanged: true, goalMissed: true, flagChanged: false, weekly: true }
6334
6581
  }));
6335
- const [saving, setSaving] = React27.useState(false);
6336
- const [saved, setSaved] = React27.useState(false);
6582
+ const [saving, setSaving] = React29.useState(false);
6583
+ const [saved, setSaved] = React29.useState(false);
6337
6584
  const set = (k, v) => {
6338
6585
  setDraft((d) => Object.assign({}, d, { [k]: v }));
6339
6586
  setSaved(false);
@@ -6355,43 +6602,43 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
6355
6602
  { id: "s2", device: "iPhone 15 \xB7 Safari", where: "Denver, CO", when: "2 hours ago" },
6356
6603
  { id: "s3", device: "Windows \xB7 Edge", where: "Chicago, IL", when: "Aug 12" }
6357
6604
  ];
6358
- return /* @__PURE__ */ jsxs49("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 860 }, ...rest, children: [
6359
- /* @__PURE__ */ jsxs49("div", { className: "fd-stack", style: { gap: 10 }, children: [
6360
- /* @__PURE__ */ jsx54("span", { className: "fd-overline fd-muted", children: "Account" }),
6361
- /* @__PURE__ */ jsx54("h1", { className: "fd-h1", style: { margin: 0 }, children: "Your profile" }),
6362
- /* @__PURE__ */ jsx54("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: "How you appear to colleagues and clients across every flytedesk app, and what we send you." })
6605
+ return /* @__PURE__ */ jsxs52("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 860 }, ...rest, children: [
6606
+ /* @__PURE__ */ jsxs52("div", { className: "fd-stack", style: { gap: 10 }, children: [
6607
+ /* @__PURE__ */ jsx57("span", { className: "fd-overline fd-muted", children: "Account" }),
6608
+ /* @__PURE__ */ jsx57("h1", { className: "fd-h1", style: { margin: 0 }, children: "Your profile" }),
6609
+ /* @__PURE__ */ jsx57("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: "How you appear to colleagues and clients across every flytedesk app, and what we send you." })
6363
6610
  ] }),
6364
- /* @__PURE__ */ jsx54(Card, { elevation: "flat", children: /* @__PURE__ */ jsxs49("div", { className: "fd-row", style: { gap: 16, flexWrap: "wrap", alignItems: "flex-start" }, children: [
6365
- /* @__PURE__ */ jsx54(Avatar, { name: draft.name || user.name, size: "lg" }),
6366
- /* @__PURE__ */ jsxs49("div", { className: "fd-stack", style: { gap: 4, flex: 1, minWidth: 200 }, children: [
6367
- /* @__PURE__ */ jsx54("span", { className: "fd-h3", style: { margin: 0 }, children: draft.name || user.name }),
6368
- /* @__PURE__ */ jsxs49("span", { className: "fd-body-sm fd-muted", children: [
6611
+ /* @__PURE__ */ jsx57(Card, { elevation: "flat", children: /* @__PURE__ */ jsxs52("div", { className: "fd-row", style: { gap: 16, flexWrap: "wrap", alignItems: "flex-start" }, children: [
6612
+ /* @__PURE__ */ jsx57(Avatar, { name: draft.name || user.name, size: "lg" }),
6613
+ /* @__PURE__ */ jsxs52("div", { className: "fd-stack", style: { gap: 4, flex: 1, minWidth: 200 }, children: [
6614
+ /* @__PURE__ */ jsx57("span", { className: "fd-h3", style: { margin: 0 }, children: draft.name || user.name }),
6615
+ /* @__PURE__ */ jsxs52("span", { className: "fd-body-sm fd-muted", children: [
6369
6616
  draft.title || "No title set",
6370
6617
  " \xB7 ",
6371
6618
  user.team || "No team"
6372
6619
  ] }),
6373
- /* @__PURE__ */ jsxs49("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 4 }, children: [
6374
- session.roles.map((r) => /* @__PURE__ */ jsx54(Badge, { tone: r.id === "owner" ? "success" : "neutral", children: r.name }, r.id)),
6375
- user.sso ? /* @__PURE__ */ jsx54(Badge, { tone: "info", icon: "shield-check", children: "SSO" }) : null
6620
+ /* @__PURE__ */ jsxs52("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 4 }, children: [
6621
+ session.roles.map((r) => /* @__PURE__ */ jsx57(Badge, { tone: r.id === "owner" ? "success" : "neutral", children: r.name }, r.id)),
6622
+ user.sso ? /* @__PURE__ */ jsx57(Badge, { tone: "info", icon: "shield-check", children: "SSO" }) : null
6376
6623
  ] })
6377
6624
  ] }),
6378
- /* @__PURE__ */ jsx54(Button, { variant: "secondary", size: "sm", icon: "image", children: "Change photo" })
6625
+ /* @__PURE__ */ jsx57(Button, { variant: "secondary", size: "sm", icon: "image", children: "Change photo" })
6379
6626
  ] }) }),
6380
- /* @__PURE__ */ jsx54(
6627
+ /* @__PURE__ */ jsx57(
6381
6628
  Card,
6382
6629
  {
6383
- title: /* @__PURE__ */ jsxs49("span", { className: "fd-stack", style: { gap: 2 }, children: [
6384
- /* @__PURE__ */ jsx54("span", { children: "Identity" }),
6385
- /* @__PURE__ */ jsx54("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "Name and title appear on plans you share" })
6630
+ title: /* @__PURE__ */ jsxs52("span", { className: "fd-stack", style: { gap: 2 }, children: [
6631
+ /* @__PURE__ */ jsx57("span", { children: "Identity" }),
6632
+ /* @__PURE__ */ jsx57("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "Name and title appear on plans you share" })
6386
6633
  ] }),
6387
6634
  elevation: "flat",
6388
- children: /* @__PURE__ */ jsxs49("div", { className: "fd-stack", style: { gap: 14 }, children: [
6389
- /* @__PURE__ */ jsxs49("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: [
6390
- /* @__PURE__ */ jsx54(Input, { label: "Full name", value: draft.name, onChange: (e) => set("name", e.target.value) }),
6391
- /* @__PURE__ */ jsx54(Input, { label: "Job title", value: draft.title, onChange: (e) => set("title", e.target.value), placeholder: "e.g. Senior media planner" })
6635
+ children: /* @__PURE__ */ jsxs52("div", { className: "fd-stack", style: { gap: 14 }, children: [
6636
+ /* @__PURE__ */ jsxs52("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: [
6637
+ /* @__PURE__ */ jsx57(Input, { label: "Full name", value: draft.name, onChange: (e) => set("name", e.target.value) }),
6638
+ /* @__PURE__ */ jsx57(Input, { label: "Job title", value: draft.title, onChange: (e) => set("title", e.target.value), placeholder: "e.g. Senior media planner" })
6392
6639
  ] }),
6393
- /* @__PURE__ */ jsxs49("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: [
6394
- /* @__PURE__ */ jsx54(
6640
+ /* @__PURE__ */ jsxs52("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: [
6641
+ /* @__PURE__ */ jsx57(
6395
6642
  Input,
6396
6643
  {
6397
6644
  label: "Work email",
@@ -6401,9 +6648,9 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
6401
6648
  help: user.sso ? "Managed by your identity provider \u2014 change it there." : "Contact an administrator to change this."
6402
6649
  }
6403
6650
  ),
6404
- /* @__PURE__ */ jsx54(Input, { label: "Phone", value: draft.phone, onChange: (e) => set("phone", e.target.value), placeholder: "Optional" })
6651
+ /* @__PURE__ */ jsx57(Input, { label: "Phone", value: draft.phone, onChange: (e) => set("phone", e.target.value), placeholder: "Optional" })
6405
6652
  ] }),
6406
- /* @__PURE__ */ jsx54(
6653
+ /* @__PURE__ */ jsx57(
6407
6654
  Textarea,
6408
6655
  {
6409
6656
  label: "Short bio",
@@ -6417,8 +6664,8 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
6417
6664
  ] })
6418
6665
  }
6419
6666
  ),
6420
- /* @__PURE__ */ jsx54(Card, { title: "Working preferences", elevation: "flat", children: /* @__PURE__ */ jsxs49("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: [
6421
- /* @__PURE__ */ jsx54(
6667
+ /* @__PURE__ */ jsx57(Card, { title: "Working preferences", elevation: "flat", children: /* @__PURE__ */ jsxs52("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: [
6668
+ /* @__PURE__ */ jsx57(
6422
6669
  Select,
6423
6670
  {
6424
6671
  label: "Time zone",
@@ -6428,28 +6675,28 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
6428
6675
  help: "Flight dates and schedules render in this zone."
6429
6676
  }
6430
6677
  ),
6431
- /* @__PURE__ */ jsx54(Select, { label: "Start of week", options: ["Monday", "Sunday"], placeholder: "Monday" })
6678
+ /* @__PURE__ */ jsx57(Select, { label: "Start of week", options: ["Monday", "Sunday"], placeholder: "Monday" })
6432
6679
  ] }) }),
6433
- /* @__PURE__ */ jsx54(
6680
+ /* @__PURE__ */ jsx57(
6434
6681
  Card,
6435
6682
  {
6436
- title: /* @__PURE__ */ jsxs49("span", { className: "fd-stack", style: { gap: 2 }, children: [
6437
- /* @__PURE__ */ jsx54("span", { children: "Notifications" }),
6438
- /* @__PURE__ */ jsx54("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "Email only for now \u2014 in-app notifications are on the roadmap" })
6683
+ title: /* @__PURE__ */ jsxs52("span", { className: "fd-stack", style: { gap: 2 }, children: [
6684
+ /* @__PURE__ */ jsx57("span", { children: "Notifications" }),
6685
+ /* @__PURE__ */ jsx57("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "Email only for now \u2014 in-app notifications are on the roadmap" })
6439
6686
  ] }),
6440
6687
  elevation: "flat",
6441
- children: /* @__PURE__ */ jsx54("div", { className: "fd-stack", style: { gap: 14 }, children: NOTIFY.map((n) => /* @__PURE__ */ jsx54(Switch, { checked: !!draft.notify[n.key], onChange: () => setNotify(n.key), label: n.label, description: n.detail }, n.key)) })
6688
+ children: /* @__PURE__ */ jsx57("div", { className: "fd-stack", style: { gap: 14 }, children: NOTIFY.map((n) => /* @__PURE__ */ jsx57(Switch, { checked: !!draft.notify[n.key], onChange: () => setNotify(n.key), label: n.label, description: n.detail }, n.key)) })
6442
6689
  }
6443
6690
  ),
6444
- /* @__PURE__ */ jsxs49(
6691
+ /* @__PURE__ */ jsxs52(
6445
6692
  Card,
6446
6693
  {
6447
- title: /* @__PURE__ */ jsxs49("span", { className: "fd-stack", style: { gap: 2 }, children: [
6448
- /* @__PURE__ */ jsx54("span", { children: "Access" }),
6449
- /* @__PURE__ */ jsx54("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "What your roles grant you" })
6694
+ title: /* @__PURE__ */ jsxs52("span", { className: "fd-stack", style: { gap: 2 }, children: [
6695
+ /* @__PURE__ */ jsx57("span", { children: "Access" }),
6696
+ /* @__PURE__ */ jsx57("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "What your roles grant you" })
6450
6697
  ] }),
6451
6698
  elevation: "flat",
6452
- action: /* @__PURE__ */ jsx54(
6699
+ action: /* @__PURE__ */ jsx57(
6453
6700
  Button,
6454
6701
  {
6455
6702
  size: "sm",
@@ -6460,39 +6707,39 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
6460
6707
  }
6461
6708
  ),
6462
6709
  children: [
6463
- /* @__PURE__ */ jsxs49("div", { className: "fd-stack", style: { gap: 0 }, children: [
6464
- /* @__PURE__ */ jsx54(CardRow, { label: "Roles", children: session.roles.map((r) => r.name).join(", ") || "None" }),
6465
- /* @__PURE__ */ jsxs49(CardRow, { label: "Permissions", children: [
6710
+ /* @__PURE__ */ jsxs52("div", { className: "fd-stack", style: { gap: 0 }, children: [
6711
+ /* @__PURE__ */ jsx57(CardRow, { label: "Roles", children: session.roles.map((r) => r.name).join(", ") || "None" }),
6712
+ /* @__PURE__ */ jsxs52(CardRow, { label: "Permissions", children: [
6466
6713
  session.permissions.length,
6467
6714
  " granted"
6468
6715
  ] }),
6469
- /* @__PURE__ */ jsx54(CardRow, { label: "Member since", children: user.joined || "\u2014" })
6716
+ /* @__PURE__ */ jsx57(CardRow, { label: "Member since", children: user.joined || "\u2014" })
6470
6717
  ] }),
6471
- /* @__PURE__ */ jsx54("p", { className: "fd-body-sm fd-muted", style: { margin: "12px 0 0" }, children: "You cannot change your own roles \u2014 that is the point of them. An administrator manages roles from Admin \u2192 Users." })
6718
+ /* @__PURE__ */ jsx57("p", { className: "fd-body-sm fd-muted", style: { margin: "12px 0 0" }, children: "You cannot change your own roles \u2014 that is the point of them. An administrator manages roles from Admin \u2192 Users." })
6472
6719
  ]
6473
6720
  }
6474
6721
  ),
6475
- showSessions ? /* @__PURE__ */ jsx54(
6722
+ showSessions ? /* @__PURE__ */ jsx57(
6476
6723
  Card,
6477
6724
  {
6478
6725
  title: "Signed-in devices",
6479
6726
  elevation: "flat",
6480
- action: /* @__PURE__ */ jsx54(Button, { size: "sm", variant: "ghost", icon: "sign-out", children: "Sign out everywhere" }),
6481
- children: /* @__PURE__ */ jsx54("div", { className: "fd-stack", style: { gap: 0 }, children: liveSessions.map((s) => /* @__PURE__ */ jsxs49("div", { className: "fd-row", style: { gap: 12, padding: "10px 0", borderTop: "1px solid var(--border)", flexWrap: "wrap" }, children: [
6482
- /* @__PURE__ */ jsx54("i", { className: "ph ph-device-mobile", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
6483
- /* @__PURE__ */ jsxs49("span", { className: "fd-stack", style: { gap: 1, flex: 1, minWidth: 160 }, children: [
6484
- /* @__PURE__ */ jsx54("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: s.device }),
6485
- /* @__PURE__ */ jsxs49("span", { className: "fd-body-sm fd-muted", children: [
6727
+ action: /* @__PURE__ */ jsx57(Button, { size: "sm", variant: "ghost", icon: "sign-out", children: "Sign out everywhere" }),
6728
+ children: /* @__PURE__ */ jsx57("div", { className: "fd-stack", style: { gap: 0 }, children: liveSessions.map((s) => /* @__PURE__ */ jsxs52("div", { className: "fd-row", style: { gap: 12, padding: "10px 0", borderTop: "1px solid var(--border)", flexWrap: "wrap" }, children: [
6729
+ /* @__PURE__ */ jsx57("i", { className: "ph ph-device-mobile", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
6730
+ /* @__PURE__ */ jsxs52("span", { className: "fd-stack", style: { gap: 1, flex: 1, minWidth: 160 }, children: [
6731
+ /* @__PURE__ */ jsx57("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: s.device }),
6732
+ /* @__PURE__ */ jsxs52("span", { className: "fd-body-sm fd-muted", children: [
6486
6733
  s.where,
6487
6734
  " \xB7 ",
6488
6735
  s.when
6489
6736
  ] })
6490
6737
  ] }),
6491
- s.current ? /* @__PURE__ */ jsx54(Badge, { tone: "success", dot: true, children: "This device" }) : /* @__PURE__ */ jsx54(Button, { size: "sm", variant: "ghost", children: "Revoke" })
6738
+ s.current ? /* @__PURE__ */ jsx57(Badge, { tone: "success", dot: true, children: "This device" }) : /* @__PURE__ */ jsx57(Button, { size: "sm", variant: "ghost", children: "Revoke" })
6492
6739
  ] }, s.id)) })
6493
6740
  }
6494
6741
  ) : null,
6495
- /* @__PURE__ */ jsxs49("div", { className: "fd-row", style: {
6742
+ /* @__PURE__ */ jsxs52("div", { className: "fd-row", style: {
6496
6743
  gap: 10,
6497
6744
  flexWrap: "wrap",
6498
6745
  position: "sticky",
@@ -6503,8 +6750,8 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
6503
6750
  border: "1px solid var(--border)",
6504
6751
  boxShadow: "0 -4px 16px rgba(11,13,17,.06)"
6505
6752
  }, children: [
6506
- /* @__PURE__ */ jsx54("span", { className: "fd-body-sm", style: { fontWeight: 600, flex: 1 }, children: saved ? "Saved." : dirty ? "Unsaved changes" : "No pending changes" }),
6507
- /* @__PURE__ */ jsx54(
6753
+ /* @__PURE__ */ jsx57("span", { className: "fd-body-sm", style: { fontWeight: 600, flex: 1 }, children: saved ? "Saved." : dirty ? "Unsaved changes" : "No pending changes" }),
6754
+ /* @__PURE__ */ jsx57(
6508
6755
  Button,
6509
6756
  {
6510
6757
  size: "sm",
@@ -6517,16 +6764,16 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
6517
6764
  children: "Discard"
6518
6765
  }
6519
6766
  ),
6520
- /* @__PURE__ */ jsx54(Button, { size: "sm", icon: "check", disabled: !dirty, loading: saving, onClick: save, children: "Save changes" })
6767
+ /* @__PURE__ */ jsx57(Button, { size: "sm", icon: "check", disabled: !dirty, loading: saving, onClick: save, children: "Save changes" })
6521
6768
  ] })
6522
6769
  ] });
6523
6770
  }
6524
6771
 
6525
6772
  // src/components/platform/RoadmapTimeline.tsx
6526
- import * as React29 from "react";
6773
+ import * as React31 from "react";
6527
6774
 
6528
6775
  // src/kits/runtime.ts
6529
- import * as React28 from "react";
6776
+ import * as React30 from "react";
6530
6777
  var WIRED_ENDPOINTS = [
6531
6778
  // Nothing yet. Every id below would come from a real service:
6532
6779
  // "plan.get", "placements.list", …
@@ -6697,8 +6944,8 @@ var RuntimeKit = {
6697
6944
  };
6698
6945
  RuntimeKit.declare(FEATURE_NEEDS);
6699
6946
  function useRuntimeMode() {
6700
- const [m, setM] = React28.useState(RuntimeKit.getMode());
6701
- React28.useEffect(() => RuntimeKit.subscribe(setM), []);
6947
+ const [m, setM] = React30.useState(RuntimeKit.getMode());
6948
+ React30.useEffect(() => RuntimeKit.subscribe(setM), []);
6702
6949
  return m;
6703
6950
  }
6704
6951
  function useFeatureStatus(key) {
@@ -6717,7 +6964,7 @@ var UseRuntimeMode = useRuntimeMode;
6717
6964
  var UseFeatureStatus = useFeatureStatus;
6718
6965
 
6719
6966
  // src/components/platform/RoadmapTimeline.tsx
6720
- import { jsx as jsx55, jsxs as jsxs50 } from "react/jsx-runtime";
6967
+ import { jsx as jsx58, jsxs as jsxs53 } from "react/jsx-runtime";
6721
6968
  var STATUS = {
6722
6969
  shipped: { tone: "success", icon: "check-circle", label: "Wired" },
6723
6970
  next: { tone: "warning", icon: "traffic-cone", label: "Not wired" },
@@ -6732,45 +6979,45 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
6732
6979
  const s = STATUS[item.status] || STATUS.planned;
6733
6980
  const deps = (item.dependsOn || []).map((k) => byKey[k]).filter(Boolean);
6734
6981
  const blocking = deps.filter((d) => !d.implemented);
6735
- return /* @__PURE__ */ jsx55(Card, { elevation: "flat", children: /* @__PURE__ */ jsxs50("div", { className: "fd-stack", style: { gap: 10 }, children: [
6736
- /* @__PURE__ */ jsxs50("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
6737
- /* @__PURE__ */ jsx55("span", { className: "fd-body", style: { fontWeight: 700, flex: 1, minWidth: 140 }, children: item.label }),
6738
- /* @__PURE__ */ jsx55(Badge, { tone: "neutral", icon: PROJECT_ICON[item.project] || "squares-four", children: item.project }),
6739
- /* @__PURE__ */ jsx55(Badge, { tone: s.tone, icon: s.icon, children: s.label })
6982
+ return /* @__PURE__ */ jsx58(Card, { elevation: "flat", children: /* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 10 }, children: [
6983
+ /* @__PURE__ */ jsxs53("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
6984
+ /* @__PURE__ */ jsx58("span", { className: "fd-body", style: { fontWeight: 700, flex: 1, minWidth: 140 }, children: item.label }),
6985
+ /* @__PURE__ */ jsx58(Badge, { tone: "neutral", icon: PROJECT_ICON[item.project] || "squares-four", children: item.project }),
6986
+ /* @__PURE__ */ jsx58(Badge, { tone: s.tone, icon: s.icon, children: s.label })
6740
6987
  ] }),
6741
- /* @__PURE__ */ jsx55("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: item.description }),
6742
- item.backend ? /* @__PURE__ */ jsxs50("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start" }, children: [
6743
- /* @__PURE__ */ jsx55("span", { className: "fd-overline fd-muted", style: { width: 62, flex: "none", paddingTop: 2 }, children: "Backend" }),
6744
- /* @__PURE__ */ jsx55("span", { className: "fd-body-sm", style: { flex: 1, textWrap: "pretty" }, children: item.backend })
6988
+ /* @__PURE__ */ jsx58("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: item.description }),
6989
+ item.backend ? /* @__PURE__ */ jsxs53("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start" }, children: [
6990
+ /* @__PURE__ */ jsx58("span", { className: "fd-overline fd-muted", style: { width: 62, flex: "none", paddingTop: 2 }, children: "Backend" }),
6991
+ /* @__PURE__ */ jsx58("span", { className: "fd-body-sm", style: { flex: 1, textWrap: "pretty" }, children: item.backend })
6745
6992
  ] }) : null,
6746
- /* @__PURE__ */ jsxs50("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
6747
- item.effort ? /* @__PURE__ */ jsxs50("span", { className: "fd-body-sm fd-muted", children: [
6748
- /* @__PURE__ */ jsx55("i", { className: "ph ph-hourglass-medium" }),
6993
+ /* @__PURE__ */ jsxs53("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
6994
+ item.effort ? /* @__PURE__ */ jsxs53("span", { className: "fd-body-sm fd-muted", children: [
6995
+ /* @__PURE__ */ jsx58("i", { className: "ph ph-hourglass-medium" }),
6749
6996
  " ",
6750
6997
  item.effort
6751
6998
  ] }) : null,
6752
- /* @__PURE__ */ jsxs50("span", { className: "fd-body-sm fd-muted", children: [
6753
- /* @__PURE__ */ jsx55("i", { className: "ph ph-user" }),
6999
+ /* @__PURE__ */ jsxs53("span", { className: "fd-body-sm fd-muted", children: [
7000
+ /* @__PURE__ */ jsx58("i", { className: "ph ph-user" }),
6754
7001
  " ",
6755
7002
  item.owner
6756
7003
  ] }),
6757
- item.screen ? /* @__PURE__ */ jsx55(Badge, { tone: "neutral", icon: "browser", children: "screen" }) : null,
6758
- /* @__PURE__ */ jsx55("span", { style: { flex: 1 } }),
6759
- /* @__PURE__ */ jsx55(
7004
+ item.screen ? /* @__PURE__ */ jsx58(Badge, { tone: "neutral", icon: "browser", children: "screen" }) : null,
7005
+ /* @__PURE__ */ jsx58("span", { style: { flex: 1 } }),
7006
+ /* @__PURE__ */ jsx58(
6760
7007
  "button",
6761
7008
  {
6762
7009
  type: "button",
6763
7010
  onClick: () => onOpenFlag && onOpenFlag(item.key),
6764
7011
  style: { all: "unset", cursor: "pointer", display: "inline-flex", alignItems: "center", gap: 5 },
6765
- children: /* @__PURE__ */ jsx55("code", { className: "fd-mono", style: { fontSize: 11, color: "var(--brand)" }, children: item.key })
7012
+ children: /* @__PURE__ */ jsx58("code", { className: "fd-mono", style: { fontSize: 11, color: "var(--brand)" }, children: item.key })
6766
7013
  }
6767
7014
  )
6768
7015
  ] }),
6769
- deps.length ? /* @__PURE__ */ jsxs50("div", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 6, borderTop: "1px solid var(--border)" }, children: [
6770
- /* @__PURE__ */ jsx55("span", { className: "fd-overline fd-muted", style: { paddingTop: 3 }, children: "After" }),
6771
- deps.map((d) => /* @__PURE__ */ jsx55(Tag, { icon: d.implemented ? "check" : "clock", children: d.label }, d.key))
7016
+ deps.length ? /* @__PURE__ */ jsxs53("div", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 6, borderTop: "1px solid var(--border)" }, children: [
7017
+ /* @__PURE__ */ jsx58("span", { className: "fd-overline fd-muted", style: { paddingTop: 3 }, children: "After" }),
7018
+ deps.map((d) => /* @__PURE__ */ jsx58(Tag, { icon: d.implemented ? "check" : "clock", children: d.label }, d.key))
6772
7019
  ] }) : null,
6773
- blocking.length && !item.implemented ? /* @__PURE__ */ jsxs50("span", { className: "fd-body-sm", style: { color: "var(--warn-text)" }, children: [
7020
+ blocking.length && !item.implemented ? /* @__PURE__ */ jsxs53("span", { className: "fd-body-sm", style: { color: "var(--warn-text)" }, children: [
6774
7021
  "Blocked until ",
6775
7022
  blocking.map((d) => d.label).join(" and "),
6776
7023
  " ",
@@ -6781,12 +7028,12 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
6781
7028
  }
6782
7029
  function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
6783
7030
  const session = SessionKit.useSession();
6784
- const [project, setProject] = React29.useState("");
6785
- const [q, setQ] = React29.useState("");
6786
- const scrollRef = React29.useRef(null);
6787
- const nowRef = React29.useRef(null);
6788
- const rm = React29.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
6789
- const byKey = React29.useMemo(() => {
7031
+ const [project, setProject] = React31.useState("");
7032
+ const [q, setQ] = React31.useState("");
7033
+ const scrollRef = React31.useRef(null);
7034
+ const nowRef = React31.useRef(null);
7035
+ const rm = React31.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
7036
+ const byKey = React31.useMemo(() => {
6790
7037
  const m = {};
6791
7038
  rm.items.forEach((i) => {
6792
7039
  m[i.key] = i;
@@ -6795,7 +7042,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
6795
7042
  }, [rm]);
6796
7043
  const items = rm.items.filter((i) => (!project || i.project === project) && (!q || (i.label + " " + i.description + " " + (i.backend || "") + " " + i.key).toLowerCase().includes(q.toLowerCase())));
6797
7044
  const projects = [...new Set(rm.items.map((i) => i.project))];
6798
- React29.useEffect(() => {
7045
+ React31.useEffect(() => {
6799
7046
  let raf1 = 0, raf2 = 0;
6800
7047
  const place = () => {
6801
7048
  const box = scrollRef.current, mark = nowRef.current;
@@ -6823,23 +7070,23 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
6823
7070
  }, 0);
6824
7071
  const nextPhase = items.find((i) => !i.implemented);
6825
7072
  let lastPhase = null;
6826
- return /* @__PURE__ */ jsxs50("div", { className: "fd-stack", style: { gap: 16, maxWidth: 1e3 }, children: [
6827
- /* @__PURE__ */ jsxs50("div", { className: "fd-stack", style: { gap: 10 }, children: [
6828
- /* @__PURE__ */ jsx55("span", { className: "fd-overline fd-muted", children: "Architecture" }),
6829
- /* @__PURE__ */ jsx55("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
6830
- /* @__PURE__ */ jsx55("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: lede || "Every screen and feature in these tools is already designed and working against a simulated backend. This is the plan for connecting them to the real one \u2014 so the only work described here is server work." })
7073
+ return /* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 16, maxWidth: 1e3 }, children: [
7074
+ /* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 10 }, children: [
7075
+ /* @__PURE__ */ jsx58("span", { className: "fd-overline fd-muted", children: "Architecture" }),
7076
+ /* @__PURE__ */ jsx58("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
7077
+ /* @__PURE__ */ jsx58("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: lede || "Every screen and feature in these tools is already designed and working against a simulated backend. This is the plan for connecting them to the real one \u2014 so the only work described here is server work." })
6831
7078
  ] }),
6832
- /* @__PURE__ */ jsxs50("div", { className: "fd-grid-stats is-thin", children: [
6833
- /* @__PURE__ */ jsx55(StatTile, { compact: true, label: "Wired", value: String(rm.shipped), sub: "of " + rm.items.length + " features" }),
6834
- /* @__PURE__ */ jsx55(StatTile, { compact: true, label: "Remaining", value: String(rm.remaining), sub: "backend work" }),
6835
- /* @__PURE__ */ jsx55(StatTile, { compact: true, label: "Est. effort", value: days ? days + " days" : "\u2014", sub: "sum of estimates, not calendar" }),
6836
- /* @__PURE__ */ jsx55(StatTile, { compact: true, label: "Up next", value: nextPhase ? "Phase " + nextPhase.phase : "\u2014", sub: nextPhase ? nextPhase.phaseName : "all wired" })
7079
+ /* @__PURE__ */ jsxs53("div", { className: "fd-grid-stats is-thin", children: [
7080
+ /* @__PURE__ */ jsx58(StatTile, { compact: true, label: "Wired", value: String(rm.shipped), sub: "of " + rm.items.length + " features" }),
7081
+ /* @__PURE__ */ jsx58(StatTile, { compact: true, label: "Remaining", value: String(rm.remaining), sub: "backend work" }),
7082
+ /* @__PURE__ */ jsx58(StatTile, { compact: true, label: "Est. effort", value: days ? days + " days" : "\u2014", sub: "sum of estimates, not calendar" }),
7083
+ /* @__PURE__ */ jsx58(StatTile, { compact: true, label: "Up next", value: nextPhase ? "Phase " + nextPhase.phase : "\u2014", sub: nextPhase ? nextPhase.phaseName : "all wired" })
6837
7084
  ] }),
6838
- /* @__PURE__ */ jsxs50("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
6839
- /* @__PURE__ */ jsx55(Input, { icon: "magnifying-glass", placeholder: "Find a feature or a piece of backend work", value: q, onChange: (e) => setQ(e.target.value), style: { width: 300 } }),
6840
- /* @__PURE__ */ jsx55(Select, { placeholder: "All projects", value: project, onChange: (e) => setProject(e.target.value), options: projects, style: { width: 190 } }),
6841
- /* @__PURE__ */ jsx55("span", { style: { flex: 1 } }),
6842
- /* @__PURE__ */ jsx55(
7085
+ /* @__PURE__ */ jsxs53("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
7086
+ /* @__PURE__ */ jsx58(Input, { icon: "magnifying-glass", placeholder: "Find a feature or a piece of backend work", value: q, onChange: (e) => setQ(e.target.value), style: { width: 300 } }),
7087
+ /* @__PURE__ */ jsx58(Select, { placeholder: "All projects", value: project, onChange: (e) => setProject(e.target.value), options: projects, style: { width: 190 } }),
7088
+ /* @__PURE__ */ jsx58("span", { style: { flex: 1 } }),
7089
+ /* @__PURE__ */ jsx58(
6843
7090
  Button,
6844
7091
  {
6845
7092
  size: "sm",
@@ -6853,7 +7100,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
6853
7100
  }
6854
7101
  )
6855
7102
  ] }),
6856
- /* @__PURE__ */ jsx55(
7103
+ /* @__PURE__ */ jsx58(
6857
7104
  Flag,
6858
7105
  {
6859
7106
  tone: "info",
@@ -6862,60 +7109,60 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
6862
7109
  actions: null
6863
7110
  }
6864
7111
  ),
6865
- /* @__PURE__ */ jsx55("div", { className: "fd-rm", children: /* @__PURE__ */ jsx55("div", { className: "fd-rm-scroll", ref: scrollRef, children: /* @__PURE__ */ jsxs50("div", { className: "fd-rm-track", children: [
6866
- /* @__PURE__ */ jsx55("span", { className: "fd-rm-spine", children: /* @__PURE__ */ jsx55("span", { className: "fd-rm-spine-done", style: { height: items.length ? 100 * shippedShown / items.length + "%" : "0%" } }) }),
7112
+ /* @__PURE__ */ jsx58("div", { className: "fd-rm", children: /* @__PURE__ */ jsx58("div", { className: "fd-rm-scroll", ref: scrollRef, children: /* @__PURE__ */ jsxs53("div", { className: "fd-rm-track", children: [
7113
+ /* @__PURE__ */ jsx58("span", { className: "fd-rm-spine", children: /* @__PURE__ */ jsx58("span", { className: "fd-rm-spine-done", style: { height: items.length ? 100 * shippedShown / items.length + "%" : "0%" } }) }),
6867
7114
  items.map((item, n) => {
6868
7115
  const showPhase = item.phase !== lastPhase;
6869
7116
  lastPhase = item.phase;
6870
7117
  const inPhase = items.filter((i) => i.phase === item.phase).length;
6871
7118
  const isBoundary = n === firstPending;
6872
- return /* @__PURE__ */ jsxs50(React29.Fragment, { children: [
6873
- showPhase ? /* @__PURE__ */ jsxs50("div", { className: "fd-rm-era", children: [
6874
- /* @__PURE__ */ jsxs50("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
6875
- /* @__PURE__ */ jsx55("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
6876
- item.phase === 0 ? null : /* @__PURE__ */ jsxs50("span", { className: "fd-mono", style: { opacity: 0.7, fontWeight: 400 }, children: [
7119
+ return /* @__PURE__ */ jsxs53(React31.Fragment, { children: [
7120
+ showPhase ? /* @__PURE__ */ jsxs53("div", { className: "fd-rm-era", children: [
7121
+ /* @__PURE__ */ jsxs53("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
7122
+ /* @__PURE__ */ jsx58("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
7123
+ item.phase === 0 ? null : /* @__PURE__ */ jsxs53("span", { className: "fd-mono", style: { opacity: 0.7, fontWeight: 400 }, children: [
6877
7124
  fmtDate(item.phaseStart),
6878
7125
  " \u2013 ",
6879
7126
  fmtDate(item.date)
6880
7127
  ] }),
6881
- /* @__PURE__ */ jsxs50("span", { style: { opacity: 0.7, fontWeight: 400 }, children: [
7128
+ /* @__PURE__ */ jsxs53("span", { style: { opacity: 0.7, fontWeight: 400 }, children: [
6882
7129
  "\xB7 ",
6883
7130
  inPhase,
6884
7131
  " feature",
6885
7132
  inPhase === 1 ? "" : "s"
6886
7133
  ] })
6887
7134
  ] }),
6888
- item.phaseWhy ? /* @__PURE__ */ jsx55("p", { className: "fd-rm-era-why", children: item.phaseWhy }) : null
7135
+ item.phaseWhy ? /* @__PURE__ */ jsx58("p", { className: "fd-rm-era-why", children: item.phaseWhy }) : null
6889
7136
  ] }) : null,
6890
- isBoundary ? /* @__PURE__ */ jsx55("div", { className: "fd-rm-now", ref: nowRef, children: /* @__PURE__ */ jsxs50("span", { className: "fd-rm-now-pill", children: [
6891
- /* @__PURE__ */ jsx55("i", { className: "ph ph-map-pin" }),
7137
+ isBoundary ? /* @__PURE__ */ jsx58("div", { className: "fd-rm-now", ref: nowRef, children: /* @__PURE__ */ jsxs53("span", { className: "fd-rm-now-pill", children: [
7138
+ /* @__PURE__ */ jsx58("i", { className: "ph ph-map-pin" }),
6892
7139
  " You are here \u2014 everything above is wired"
6893
7140
  ] }) }) : null,
6894
- /* @__PURE__ */ jsxs50("div", { className: "fd-rm-row", children: [
6895
- /* @__PURE__ */ jsx55("span", { className: "fd-rm-dot " + (item.implemented ? "is-shipped" : item.status === "next" ? "is-next" : "") }),
6896
- /* @__PURE__ */ jsxs50("div", { className: "fd-rm-date", children: [
7141
+ /* @__PURE__ */ jsxs53("div", { className: "fd-rm-row", children: [
7142
+ /* @__PURE__ */ jsx58("span", { className: "fd-rm-dot " + (item.implemented ? "is-shipped" : item.status === "next" ? "is-next" : "") }),
7143
+ /* @__PURE__ */ jsxs53("div", { className: "fd-rm-date", children: [
6897
7144
  fmtDate(item.date),
6898
- /* @__PURE__ */ jsx55("br", {}),
6899
- /* @__PURE__ */ jsx55("span", { style: { opacity: 0.75 }, children: item.implemented ? "shipped" : "phase " + item.phase })
7145
+ /* @__PURE__ */ jsx58("br", {}),
7146
+ /* @__PURE__ */ jsx58("span", { style: { opacity: 0.75 }, children: item.implemented ? "shipped" : "phase " + item.phase })
6900
7147
  ] }),
6901
- /* @__PURE__ */ jsx55(RoadmapCard, { item, byKey, onOpenFlag })
7148
+ /* @__PURE__ */ jsx58(RoadmapCard, { item, byKey, onOpenFlag })
6902
7149
  ] })
6903
7150
  ] }, item.key);
6904
7151
  }),
6905
- !items.length ? /* @__PURE__ */ jsx55("p", { className: "fd-body-sm fd-muted", children: "Nothing matches that filter." }) : null
7152
+ !items.length ? /* @__PURE__ */ jsx58("p", { className: "fd-body-sm fd-muted", children: "Nothing matches that filter." }) : null
6906
7153
  ] }) }) }),
6907
- /* @__PURE__ */ jsxs50("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: [
7154
+ /* @__PURE__ */ jsxs53("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: [
6908
7155
  "Derived from the feature-flag registry \u2014 each entry's status is its flag's ",
6909
- /* @__PURE__ */ jsx55("code", { className: "fd-mono", children: "implemented" }),
7156
+ /* @__PURE__ */ jsx58("code", { className: "fd-mono", children: "implemented" }),
6910
7157
  " field, so this page cannot drift from what the apps actually do."
6911
7158
  ] })
6912
7159
  ] });
6913
7160
  }
6914
7161
 
6915
7162
  // src/components/platform/ComingSoon.tsx
6916
- import * as React30 from "react";
7163
+ import * as React32 from "react";
6917
7164
  import { createPortal as createPortal7 } from "react-dom";
6918
- import { Fragment as Fragment13, jsx as jsx56, jsxs as jsxs51 } from "react/jsx-runtime";
7165
+ import { Fragment as Fragment13, jsx as jsx59, jsxs as jsxs54 } from "react/jsx-runtime";
6919
7166
  var BYPASS_STORE = "fd.soon.bypass.v1";
6920
7167
  function readBypassed() {
6921
7168
  try {
@@ -6931,8 +7178,8 @@ function writeBypassed(list) {
6931
7178
  }
6932
7179
  }
6933
7180
  function useBypass(key) {
6934
- const [on, setOn] = React30.useState(() => !!key && readBypassed().indexOf(key) >= 0);
6935
- React30.useEffect(() => {
7181
+ const [on, setOn] = React32.useState(() => !!key && readBypassed().indexOf(key) >= 0);
7182
+ React32.useEffect(() => {
6936
7183
  setOn(!!key && readBypassed().indexOf(key) >= 0);
6937
7184
  }, [key]);
6938
7185
  const set = (next) => {
@@ -6945,43 +7192,43 @@ function useBypass(key) {
6945
7192
  return [on, set];
6946
7193
  }
6947
7194
  function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass }) {
6948
- return /* @__PURE__ */ jsxs51(Fragment13, { children: [
6949
- /* @__PURE__ */ jsxs51("span", { className: "fd-soon-badge", children: [
6950
- /* @__PURE__ */ jsx56("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
7195
+ return /* @__PURE__ */ jsxs54(Fragment13, { children: [
7196
+ /* @__PURE__ */ jsxs54("span", { className: "fd-soon-badge", children: [
7197
+ /* @__PURE__ */ jsx59("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
6951
7198
  label
6952
7199
  ] }),
6953
- detail ? /* @__PURE__ */ jsx56("span", { className: "fd-soon-detail", children: detail }) : null,
6954
- backend ? /* @__PURE__ */ jsxs51("span", { className: "fd-soon-backend", children: [
6955
- /* @__PURE__ */ jsx56("span", { className: "fd-overline", children: "Needs" }),
7200
+ detail ? /* @__PURE__ */ jsx59("span", { className: "fd-soon-detail", children: detail }) : null,
7201
+ backend ? /* @__PURE__ */ jsxs54("span", { className: "fd-soon-backend", children: [
7202
+ /* @__PURE__ */ jsx59("span", { className: "fd-overline", children: "Needs" }),
6956
7203
  " ",
6957
7204
  backend
6958
7205
  ] }) : null,
6959
- eta || effort || onRoadmap ? /* @__PURE__ */ jsxs51("span", { className: "fd-soon-meta", children: [
6960
- eta ? /* @__PURE__ */ jsxs51("span", { children: [
6961
- /* @__PURE__ */ jsx56("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }),
7206
+ eta || effort || onRoadmap ? /* @__PURE__ */ jsxs54("span", { className: "fd-soon-meta", children: [
7207
+ eta ? /* @__PURE__ */ jsxs54("span", { children: [
7208
+ /* @__PURE__ */ jsx59("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }),
6962
7209
  " ",
6963
7210
  eta
6964
7211
  ] }) : null,
6965
- effort ? /* @__PURE__ */ jsxs51("span", { children: [
6966
- /* @__PURE__ */ jsx56("i", { className: "ph ph-hourglass-medium", "aria-hidden": "true" }),
7212
+ effort ? /* @__PURE__ */ jsxs54("span", { children: [
7213
+ /* @__PURE__ */ jsx59("i", { className: "ph ph-hourglass-medium", "aria-hidden": "true" }),
6967
7214
  " ",
6968
7215
  effort
6969
7216
  ] }) : null,
6970
- onRoadmap ? /* @__PURE__ */ jsxs51("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
7217
+ onRoadmap ? /* @__PURE__ */ jsxs54("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
6971
7218
  "See the roadmap ",
6972
- /* @__PURE__ */ jsx56("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
7219
+ /* @__PURE__ */ jsx59("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
6973
7220
  ] }) : null
6974
7221
  ] }) : null,
6975
- allowed ? /* @__PURE__ */ jsxs51("button", { type: "button", className: "fd-soon-view", onClick: onBypass, children: [
6976
- /* @__PURE__ */ jsx56("i", { className: "ph ph-eye", "aria-hidden": "true" }),
7222
+ allowed ? /* @__PURE__ */ jsxs54("button", { type: "button", className: "fd-soon-view", onClick: onBypass, children: [
7223
+ /* @__PURE__ */ jsx59("i", { className: "ph ph-eye", "aria-hidden": "true" }),
6977
7224
  " View and use it anyway"
6978
7225
  ] }) : null
6979
7226
  ] });
6980
7227
  }
6981
7228
  function useHoverCard(open) {
6982
- const anchor = React30.useRef(null);
6983
- const [pos, setPos] = React30.useState(null);
6984
- React30.useLayoutEffect(() => {
7229
+ const anchor = React32.useRef(null);
7230
+ const [pos, setPos] = React32.useState(null);
7231
+ React32.useLayoutEffect(() => {
6985
7232
  if (!open || !anchor.current) {
6986
7233
  setPos(null);
6987
7234
  return;
@@ -7033,9 +7280,9 @@ function ComingSoon({
7033
7280
  const tip = [label, detail, backend ? "Needs " + backend : null, eta ? "ETA " + eta : null, effort].filter(Boolean).join(" \xB7 ");
7034
7281
  if (inline) {
7035
7282
  if (allowed && bypassed) {
7036
- return /* @__PURE__ */ jsxs51("span", { className: ["fd-soon-inline-on", className].filter(Boolean).join(" "), ...rest, children: [
7283
+ return /* @__PURE__ */ jsxs54("span", { className: ["fd-soon-inline-on", className].filter(Boolean).join(" "), ...rest, children: [
7037
7284
  children,
7038
- /* @__PURE__ */ jsx56(
7285
+ /* @__PURE__ */ jsx59(
7039
7286
  "button",
7040
7287
  {
7041
7288
  type: "button",
@@ -7043,12 +7290,12 @@ function ComingSoon({
7043
7290
  title: "Unwired \u2014 writes go to the simulated backend. " + tip + " Click to re-blur.",
7044
7291
  onClick: () => setBypassed(false),
7045
7292
  "aria-label": "Re-blur this unwired feature",
7046
- children: /* @__PURE__ */ jsx56("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
7293
+ children: /* @__PURE__ */ jsx59("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
7047
7294
  }
7048
7295
  )
7049
7296
  ] });
7050
7297
  }
7051
- return /* @__PURE__ */ jsx56(
7298
+ return /* @__PURE__ */ jsx59(
7052
7299
  InlineSoon,
7053
7300
  {
7054
7301
  label,
@@ -7068,20 +7315,20 @@ function ComingSoon({
7068
7315
  );
7069
7316
  }
7070
7317
  if (allowed && bypassed) {
7071
- return /* @__PURE__ */ jsxs51("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, ...rest, children: [
7072
- /* @__PURE__ */ jsxs51("div", { className: "fd-soon-bar", role: "status", children: [
7073
- /* @__PURE__ */ jsxs51("span", { className: "fd-soon-badge", children: [
7074
- /* @__PURE__ */ jsx56("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
7318
+ return /* @__PURE__ */ jsxs54("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, ...rest, children: [
7319
+ /* @__PURE__ */ jsxs54("div", { className: "fd-soon-bar", role: "status", children: [
7320
+ /* @__PURE__ */ jsxs54("span", { className: "fd-soon-badge", children: [
7321
+ /* @__PURE__ */ jsx59("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
7075
7322
  "Unwired feature \u2014 you are using it anyway"
7076
7323
  ] }),
7077
- /* @__PURE__ */ jsx56("span", { className: "fd-soon-bar-detail", children: "Every action here writes to the simulated backend, so nothing you do persists beyond this session." }),
7078
- /* @__PURE__ */ jsxs51("span", { className: "fd-soon-bar-actions", children: [
7079
- onRoadmap ? /* @__PURE__ */ jsxs51("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
7324
+ /* @__PURE__ */ jsx59("span", { className: "fd-soon-bar-detail", children: "Every action here writes to the simulated backend, so nothing you do persists beyond this session." }),
7325
+ /* @__PURE__ */ jsxs54("span", { className: "fd-soon-bar-actions", children: [
7326
+ onRoadmap ? /* @__PURE__ */ jsxs54("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
7080
7327
  "Roadmap ",
7081
- /* @__PURE__ */ jsx56("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
7328
+ /* @__PURE__ */ jsx59("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
7082
7329
  ] }) : null,
7083
- /* @__PURE__ */ jsxs51("button", { type: "button", className: "fd-soon-link", onClick: () => setBypassed(false), children: [
7084
- /* @__PURE__ */ jsx56("i", { className: "ph ph-eye-slash", "aria-hidden": "true" }),
7330
+ /* @__PURE__ */ jsxs54("button", { type: "button", className: "fd-soon-link", onClick: () => setBypassed(false), children: [
7331
+ /* @__PURE__ */ jsx59("i", { className: "ph ph-eye-slash", "aria-hidden": "true" }),
7085
7332
  " Re-blur"
7086
7333
  ] })
7087
7334
  ] })
@@ -7089,10 +7336,10 @@ function ComingSoon({
7089
7336
  children
7090
7337
  ] });
7091
7338
  }
7092
- return /* @__PURE__ */ jsxs51("div", { className: ["fd-soon", className].filter(Boolean).join(" "), style: minHeight ? { minHeight } : void 0, ...rest, children: [
7093
- /* @__PURE__ */ jsx56("div", { className: "fd-soon-under", style: { filter: "blur(" + blur + "px) saturate(.62)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
7094
- /* @__PURE__ */ jsx56("div", { className: "fd-soon-veil" }),
7095
- /* @__PURE__ */ jsx56("div", { className: "fd-soon-note", role: "note", children: /* @__PURE__ */ jsx56(
7339
+ return /* @__PURE__ */ jsxs54("div", { className: ["fd-soon", className].filter(Boolean).join(" "), style: minHeight ? { minHeight } : void 0, ...rest, children: [
7340
+ /* @__PURE__ */ jsx59("div", { className: "fd-soon-under", style: { filter: "blur(" + blur + "px) saturate(.62)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
7341
+ /* @__PURE__ */ jsx59("div", { className: "fd-soon-veil" }),
7342
+ /* @__PURE__ */ jsx59("div", { className: "fd-soon-note", role: "note", children: /* @__PURE__ */ jsx59(
7096
7343
  SoonCard,
7097
7344
  {
7098
7345
  label,
@@ -7108,9 +7355,9 @@ function ComingSoon({
7108
7355
  ] });
7109
7356
  }
7110
7357
  function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass, blur, tip, className, rest, children }) {
7111
- const [open, setOpen] = React30.useState(false);
7358
+ const [open, setOpen] = React32.useState(false);
7112
7359
  const [anchor, pos] = useHoverCard(open);
7113
- const close = React30.useRef(null);
7360
+ const close = React32.useRef(null);
7114
7361
  const show = () => {
7115
7362
  if (close.current) {
7116
7363
  clearTimeout(close.current);
@@ -7126,10 +7373,10 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
7126
7373
  setOpen(false);
7127
7374
  }, 140);
7128
7375
  };
7129
- React30.useEffect(() => () => {
7376
+ React32.useEffect(() => () => {
7130
7377
  if (close.current) clearTimeout(close.current);
7131
7378
  }, []);
7132
- return /* @__PURE__ */ jsxs51(
7379
+ return /* @__PURE__ */ jsxs54(
7133
7380
  "span",
7134
7381
  {
7135
7382
  ref: anchor,
@@ -7140,8 +7387,8 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
7140
7387
  onBlur: hide,
7141
7388
  ...rest,
7142
7389
  children: [
7143
- /* @__PURE__ */ jsx56("span", { className: "fd-soon-under", style: { filter: "blur(" + Math.min(blur, 1.1) + "px) saturate(.66)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
7144
- /* @__PURE__ */ jsx56(
7390
+ /* @__PURE__ */ jsx59("span", { className: "fd-soon-under", style: { filter: "blur(" + Math.min(blur, 1.1) + "px) saturate(.66)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
7391
+ /* @__PURE__ */ jsx59(
7145
7392
  "button",
7146
7393
  {
7147
7394
  type: "button",
@@ -7152,11 +7399,11 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
7152
7399
  onFocus: show,
7153
7400
  onBlur: hide,
7154
7401
  onClick: () => open ? setOpen(false) : show(),
7155
- children: /* @__PURE__ */ jsx56("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
7402
+ children: /* @__PURE__ */ jsx59("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
7156
7403
  }
7157
7404
  ),
7158
7405
  open && pos ? createPortal7(
7159
- /* @__PURE__ */ jsx56(
7406
+ /* @__PURE__ */ jsx59(
7160
7407
  "div",
7161
7408
  {
7162
7409
  className: "fd-soon-note fd-soon-hovercard",
@@ -7164,7 +7411,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
7164
7411
  style: { position: "fixed", left: pos.left, top: pos.top, bottom: pos.bottom, width: pos.width },
7165
7412
  onMouseEnter: show,
7166
7413
  onMouseLeave: hide,
7167
- children: /* @__PURE__ */ jsx56(
7414
+ children: /* @__PURE__ */ jsx59(
7168
7415
  SoonCard,
7169
7416
  {
7170
7417
  label,
@@ -7194,10 +7441,10 @@ function formatEta(iso2) {
7194
7441
  var FormatEta = formatEta;
7195
7442
 
7196
7443
  // src/components/platform/Gate.tsx
7197
- import { jsx as jsx57, jsxs as jsxs52 } from "react/jsx-runtime";
7444
+ import { jsx as jsx60, jsxs as jsxs55 } from "react/jsx-runtime";
7198
7445
  function PermissionDenied({ permission, title, detail, compact: compact3 = false, className = "", ...rest }) {
7199
7446
  const need = Array.isArray(permission) ? permission : [permission].filter(Boolean);
7200
- return /* @__PURE__ */ jsxs52(
7447
+ return /* @__PURE__ */ jsxs55(
7201
7448
  "div",
7202
7449
  {
7203
7450
  className: ["fd-stack", className].filter(Boolean).join(" "),
@@ -7213,14 +7460,14 @@ function PermissionDenied({ permission, title, detail, compact: compact3 = false
7213
7460
  },
7214
7461
  ...rest,
7215
7462
  children: [
7216
- /* @__PURE__ */ jsxs52("span", { className: "fd-row", style: { gap: 8 }, children: [
7217
- /* @__PURE__ */ jsx57("i", { className: "ph ph-lock-simple", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
7218
- /* @__PURE__ */ jsx57("span", { className: compact3 ? "fd-label-lg" : "fd-h3", children: title || "You do not have access to this" })
7463
+ /* @__PURE__ */ jsxs55("span", { className: "fd-row", style: { gap: 8 }, children: [
7464
+ /* @__PURE__ */ jsx60("i", { className: "ph ph-lock-simple", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
7465
+ /* @__PURE__ */ jsx60("span", { className: compact3 ? "fd-label-lg" : "fd-h3", children: title || "You do not have access to this" })
7219
7466
  ] }),
7220
- /* @__PURE__ */ jsx57("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: detail || "Your roles do not grant this. An administrator can change that from Admin \u2192 Users." }),
7221
- need.length ? /* @__PURE__ */ jsxs52("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: [
7222
- /* @__PURE__ */ jsx57("span", { className: "fd-overline fd-muted", children: "Requires" }),
7223
- need.map((p) => /* @__PURE__ */ jsx57("code", { className: "fd-mono", style: {
7467
+ /* @__PURE__ */ jsx60("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: detail || "Your roles do not grant this. An administrator can change that from Admin \u2192 Users." }),
7468
+ need.length ? /* @__PURE__ */ jsxs55("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: [
7469
+ /* @__PURE__ */ jsx60("span", { className: "fd-overline fd-muted", children: "Requires" }),
7470
+ need.map((p) => /* @__PURE__ */ jsx60("code", { className: "fd-mono", style: {
7224
7471
  fontSize: 11.5,
7225
7472
  padding: "2px 7px",
7226
7473
  borderRadius: 5,
@@ -7241,7 +7488,7 @@ function Gate({ perm, anyOf, role, silent = false, fallback, compact: compact3 =
7241
7488
  if (ok) return children;
7242
7489
  if (fallback !== void 0) return fallback;
7243
7490
  if (silent) return null;
7244
- return /* @__PURE__ */ jsx57(PermissionDenied, { permission: perm || anyOf, compact: compact3 });
7491
+ return /* @__PURE__ */ jsx60(PermissionDenied, { permission: perm || anyOf, compact: compact3 });
7245
7492
  }
7246
7493
  function FeatureGate({
7247
7494
  flag,
@@ -7262,7 +7509,7 @@ function FeatureGate({
7262
7509
  if (!preview) return fallback;
7263
7510
  const f = SessionKit.findFlag(flag) || {};
7264
7511
  const missing = rt.missing || [];
7265
- return /* @__PURE__ */ jsx57(
7512
+ return /* @__PURE__ */ jsx60(
7266
7513
  ComingSoon,
7267
7514
  {
7268
7515
  label: label || (variant === "inline" ? f.label || "Not wired yet" : "Designed \u2014 backend not wired yet"),
@@ -7283,25 +7530,25 @@ function FeatureGate({
7283
7530
  function PermissionHint({ perm, children }) {
7284
7531
  SessionKit.useSession();
7285
7532
  if (SessionKit.can(perm)) return children;
7286
- return /* @__PURE__ */ jsx57(
7533
+ return /* @__PURE__ */ jsx60(
7287
7534
  "span",
7288
7535
  {
7289
7536
  title: "Requires " + (Array.isArray(perm) ? perm.join(", ") : perm),
7290
7537
  style: { display: "inline-flex", opacity: 0.45, cursor: "not-allowed" },
7291
7538
  "aria-disabled": "true",
7292
- children: /* @__PURE__ */ jsx57("span", { style: { pointerEvents: "none" }, children })
7539
+ children: /* @__PURE__ */ jsx60("span", { style: { pointerEvents: "none" }, children })
7293
7540
  }
7294
7541
  );
7295
7542
  }
7296
7543
 
7297
7544
  // src/components/platform/ModeSwitch.tsx
7298
- import * as React31 from "react";
7299
- import { Fragment as Fragment14, jsx as jsx58, jsxs as jsxs53 } from "react/jsx-runtime";
7545
+ import * as React33 from "react";
7546
+ import { Fragment as Fragment14, jsx as jsx61, jsxs as jsxs56 } from "react/jsx-runtime";
7300
7547
  function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
7301
7548
  const mode2 = useRuntimeMode();
7302
- const [open, setOpen] = React31.useState(false);
7303
- const ref = React31.useRef(null);
7304
- React31.useEffect(() => {
7549
+ const [open, setOpen] = React33.useState(false);
7550
+ const ref = React33.useRef(null);
7551
+ React33.useEffect(() => {
7305
7552
  if (!open) return;
7306
7553
  const away = (e) => {
7307
7554
  if (ref.current && !ref.current.contains(e.target)) setOpen(false);
@@ -7323,8 +7570,8 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
7323
7570
  RuntimeKit.setMode(next);
7324
7571
  setOpen(false);
7325
7572
  };
7326
- return /* @__PURE__ */ jsxs53("span", { style: { position: "relative", display: "inline-flex" }, ref, children: [
7327
- /* @__PURE__ */ jsxs53(
7573
+ return /* @__PURE__ */ jsxs56("span", { style: { position: "relative", display: "inline-flex" }, ref, children: [
7574
+ /* @__PURE__ */ jsxs56(
7328
7575
  "button",
7329
7576
  {
7330
7577
  type: "button",
@@ -7334,29 +7581,29 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
7334
7581
  title: test ? "Test mode \u2014 every response is simulated. Click to inspect requests or return to live mode." : "Live mode \u2014 incomplete features are shown under construction. Click for test mode.",
7335
7582
  className: "fd-mode-btn" + (test ? " is-test" : "") + (open ? " is-open" : ""),
7336
7583
  children: [
7337
- /* @__PURE__ */ jsx58("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), style: { fontSize: 17 } }),
7338
- test && requestCount ? /* @__PURE__ */ jsx58("span", { className: "fd-mono fd-mode-count", children: requestCount > 99 ? "99+" : requestCount }, requestCount) : null
7584
+ /* @__PURE__ */ jsx61("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), style: { fontSize: 17 } }),
7585
+ test && requestCount ? /* @__PURE__ */ jsx61("span", { className: "fd-mono fd-mode-count", children: requestCount > 99 ? "99+" : requestCount }, requestCount) : null
7339
7586
  ]
7340
7587
  }
7341
7588
  ),
7342
- open ? /* @__PURE__ */ jsxs53("span", { className: "fd-view-enter fd-mode-pop", children: [
7343
- /* @__PURE__ */ jsxs53("span", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
7344
- /* @__PURE__ */ jsxs53("span", { className: "fd-badge " + (test ? "fd-badge-warning" : "fd-badge-neutral"), children: [
7345
- /* @__PURE__ */ jsx58("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), "aria-hidden": "true" }),
7589
+ open ? /* @__PURE__ */ jsxs56("span", { className: "fd-view-enter fd-mode-pop", children: [
7590
+ /* @__PURE__ */ jsxs56("span", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
7591
+ /* @__PURE__ */ jsxs56("span", { className: "fd-badge " + (test ? "fd-badge-warning" : "fd-badge-neutral"), children: [
7592
+ /* @__PURE__ */ jsx61("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), "aria-hidden": "true" }),
7346
7593
  test ? "Test mode" : "Live mode"
7347
7594
  ] }),
7348
- test ? /* @__PURE__ */ jsxs53("span", { className: "fd-body-sm fd-muted fd-mono", children: [
7595
+ test ? /* @__PURE__ */ jsxs56("span", { className: "fd-body-sm fd-muted fd-mono", children: [
7349
7596
  requestCount,
7350
7597
  " simulated request",
7351
7598
  requestCount === 1 ? "" : "s"
7352
7599
  ] }) : null,
7353
- /* @__PURE__ */ jsx58("span", { style: { flex: 1 } }),
7354
- test && onClearLog ? /* @__PURE__ */ jsx58("button", { type: "button", className: "fd-soon-link", onClick: onClearLog, children: "Clear" }) : null
7600
+ /* @__PURE__ */ jsx61("span", { style: { flex: 1 } }),
7601
+ test && onClearLog ? /* @__PURE__ */ jsx61("button", { type: "button", className: "fd-soon-link", onClick: onClearLog, children: "Clear" }) : null
7355
7602
  ] }),
7356
- /* @__PURE__ */ jsxs53("span", { style: { display: "block", padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
7357
- /* @__PURE__ */ jsx58("span", { className: "fd-body-sm fd-secondary", style: { display: "block", textWrap: "pretty" }, children: test ? "Every feature is usable and nothing is obstructed, but no response comes from a real service \u2014 nothing you do here persists. Use this to review and demo the design." : "This is what a user would see today. " + s.incomplete + " of " + s.total + " features depend on backend work that is not wired yet, so they render under construction." }),
7358
- /* @__PURE__ */ jsxs53("span", { className: "fd-row", style: { gap: 8, marginTop: 10, flexWrap: "wrap" }, children: [
7359
- /* @__PURE__ */ jsxs53("span", { className: "fd-body-sm fd-muted fd-mono", children: [
7603
+ /* @__PURE__ */ jsxs56("span", { style: { display: "block", padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
7604
+ /* @__PURE__ */ jsx61("span", { className: "fd-body-sm fd-secondary", style: { display: "block", textWrap: "pretty" }, children: test ? "Every feature is usable and nothing is obstructed, but no response comes from a real service \u2014 nothing you do here persists. Use this to review and demo the design." : "This is what a user would see today. " + s.incomplete + " of " + s.total + " features depend on backend work that is not wired yet, so they render under construction." }),
7605
+ /* @__PURE__ */ jsxs56("span", { className: "fd-row", style: { gap: 8, marginTop: 10, flexWrap: "wrap" }, children: [
7606
+ /* @__PURE__ */ jsxs56("span", { className: "fd-body-sm fd-muted fd-mono", children: [
7360
7607
  s.endpointsWired,
7361
7608
  " endpoint",
7362
7609
  s.endpointsWired === 1 ? "" : "s",
@@ -7366,58 +7613,58 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
7366
7613
  s.total,
7367
7614
  " features complete"
7368
7615
  ] }),
7369
- onOpenSpec ? /* @__PURE__ */ jsxs53(Fragment14, { children: [
7370
- /* @__PURE__ */ jsx58("span", { style: { flex: 1 } }),
7371
- /* @__PURE__ */ jsxs53("button", { type: "button", className: "fd-soon-link", onClick: () => {
7616
+ onOpenSpec ? /* @__PURE__ */ jsxs56(Fragment14, { children: [
7617
+ /* @__PURE__ */ jsx61("span", { style: { flex: 1 } }),
7618
+ /* @__PURE__ */ jsxs56("button", { type: "button", className: "fd-soon-link", onClick: () => {
7372
7619
  setOpen(false);
7373
7620
  onOpenSpec();
7374
7621
  }, children: [
7375
7622
  "API spec ",
7376
- /* @__PURE__ */ jsx58("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
7623
+ /* @__PURE__ */ jsx61("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
7377
7624
  ] })
7378
7625
  ] }) : null
7379
7626
  ] })
7380
7627
  ] }),
7381
- /* @__PURE__ */ jsxs53("span", { className: "fd-mode-choice", children: [
7382
- /* @__PURE__ */ jsxs53("button", { type: "button", className: "fd-mode-opt" + (!test ? " is-on" : ""), onClick: () => go("live"), children: [
7383
- /* @__PURE__ */ jsx58("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
7384
- /* @__PURE__ */ jsxs53("span", { className: "fd-mode-opt-text", children: [
7385
- /* @__PURE__ */ jsx58("span", { className: "fd-mode-opt-title", children: "Live mode" }),
7386
- /* @__PURE__ */ jsx58("span", { className: "fd-mode-opt-desc", children: "Incomplete features under construction" })
7628
+ /* @__PURE__ */ jsxs56("span", { className: "fd-mode-choice", children: [
7629
+ /* @__PURE__ */ jsxs56("button", { type: "button", className: "fd-mode-opt" + (!test ? " is-on" : ""), onClick: () => go("live"), children: [
7630
+ /* @__PURE__ */ jsx61("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
7631
+ /* @__PURE__ */ jsxs56("span", { className: "fd-mode-opt-text", children: [
7632
+ /* @__PURE__ */ jsx61("span", { className: "fd-mode-opt-title", children: "Live mode" }),
7633
+ /* @__PURE__ */ jsx61("span", { className: "fd-mode-opt-desc", children: "Incomplete features under construction" })
7387
7634
  ] }),
7388
- !test ? /* @__PURE__ */ jsx58("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
7635
+ !test ? /* @__PURE__ */ jsx61("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
7389
7636
  ] }),
7390
- /* @__PURE__ */ jsxs53("button", { type: "button", className: "fd-mode-opt" + (test ? " is-on" : ""), onClick: () => go("test"), children: [
7391
- /* @__PURE__ */ jsx58("i", { className: "ph ph-flask", "aria-hidden": "true" }),
7392
- /* @__PURE__ */ jsxs53("span", { className: "fd-mode-opt-text", children: [
7393
- /* @__PURE__ */ jsx58("span", { className: "fd-mode-opt-title", children: "Test mode" }),
7394
- /* @__PURE__ */ jsx58("span", { className: "fd-mode-opt-desc", children: "Everything usable, all data simulated" })
7637
+ /* @__PURE__ */ jsxs56("button", { type: "button", className: "fd-mode-opt" + (test ? " is-on" : ""), onClick: () => go("test"), children: [
7638
+ /* @__PURE__ */ jsx61("i", { className: "ph ph-flask", "aria-hidden": "true" }),
7639
+ /* @__PURE__ */ jsxs56("span", { className: "fd-mode-opt-text", children: [
7640
+ /* @__PURE__ */ jsx61("span", { className: "fd-mode-opt-title", children: "Test mode" }),
7641
+ /* @__PURE__ */ jsx61("span", { className: "fd-mode-opt-desc", children: "Everything usable, all data simulated" })
7395
7642
  ] }),
7396
- test ? /* @__PURE__ */ jsx58("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
7643
+ test ? /* @__PURE__ */ jsx61("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
7397
7644
  ] })
7398
7645
  ] }),
7399
- test && renderLog ? /* @__PURE__ */ jsx58("span", { style: { display: "block", maxHeight: 340, overflowY: "auto", borderTop: "1px solid var(--border)" }, children: renderLog() }) : null
7646
+ test && renderLog ? /* @__PURE__ */ jsx61("span", { style: { display: "block", maxHeight: 340, overflowY: "auto", borderTop: "1px solid var(--border)" }, children: renderLog() }) : null
7400
7647
  ] }) : null
7401
7648
  ] });
7402
7649
  }
7403
7650
  function TestModeBar({ onExit }) {
7404
7651
  const mode2 = useRuntimeMode();
7405
7652
  if (mode2 !== "test") return null;
7406
- return /* @__PURE__ */ jsxs53("div", { className: "fd-testbar", role: "status", children: [
7407
- /* @__PURE__ */ jsxs53("span", { className: "fd-badge fd-badge-warning", children: [
7408
- /* @__PURE__ */ jsx58("i", { className: "ph ph-flask", "aria-hidden": "true" }),
7653
+ return /* @__PURE__ */ jsxs56("div", { className: "fd-testbar", role: "status", children: [
7654
+ /* @__PURE__ */ jsxs56("span", { className: "fd-badge fd-badge-warning", children: [
7655
+ /* @__PURE__ */ jsx61("i", { className: "ph ph-flask", "aria-hidden": "true" }),
7409
7656
  "Test mode"
7410
7657
  ] }),
7411
- /* @__PURE__ */ jsx58("span", { className: "fd-testbar-detail", children: "Every feature is unlocked and every response is simulated \u2014 nothing here persists." }),
7412
- /* @__PURE__ */ jsxs53("button", { type: "button", className: "fd-soon-link", onClick: () => onExit ? onExit() : RuntimeKit.setMode("live"), children: [
7413
- /* @__PURE__ */ jsx58("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
7658
+ /* @__PURE__ */ jsx61("span", { className: "fd-testbar-detail", children: "Every feature is unlocked and every response is simulated \u2014 nothing here persists." }),
7659
+ /* @__PURE__ */ jsxs56("button", { type: "button", className: "fd-soon-link", onClick: () => onExit ? onExit() : RuntimeKit.setMode("live"), children: [
7660
+ /* @__PURE__ */ jsx61("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
7414
7661
  " Back to live mode"
7415
7662
  ] })
7416
7663
  ] });
7417
7664
  }
7418
7665
 
7419
7666
  // src/components/planner/ChannelMeta.tsx
7420
- import { jsx as jsx59, jsxs as jsxs54 } from "react/jsx-runtime";
7667
+ import { jsx as jsx62, jsxs as jsxs57 } from "react/jsx-runtime";
7421
7668
  var CHANNEL_WEIGHTS = {
7422
7669
  "OOH": 50,
7423
7670
  "DOOH": 50,
@@ -7470,9 +7717,9 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
7470
7717
  const m = ChannelMeta(channel);
7471
7718
  const wt = channelWeightOf(channel || "");
7472
7719
  if (dot) {
7473
- return /* @__PURE__ */ jsx59("span", { className: ["fd-chan-dot", className].filter(Boolean).join(" "), title: m.name, style: { background: m.color }, ...rest });
7720
+ return /* @__PURE__ */ jsx62("span", { className: ["fd-chan-dot", className].filter(Boolean).join(" "), title: m.name, style: { background: m.color }, ...rest });
7474
7721
  }
7475
- return /* @__PURE__ */ jsxs54(
7722
+ return /* @__PURE__ */ jsxs57(
7476
7723
  "span",
7477
7724
  {
7478
7725
  className: ["fd-chan", size === "sm" ? "fd-chan-sm" : "", className].filter(Boolean).join(" "),
@@ -7480,16 +7727,16 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
7480
7727
  style: { "--chan": m.color },
7481
7728
  ...rest,
7482
7729
  children: [
7483
- /* @__PURE__ */ jsx59("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }),
7484
- showLabel ? /* @__PURE__ */ jsx59("span", { className: "fd-chan-label", children: m.label }) : null,
7485
- weight ? /* @__PURE__ */ jsx59("span", { className: "fd-chan-weight", children: wt || 0 }) : null
7730
+ /* @__PURE__ */ jsx62("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }),
7731
+ showLabel ? /* @__PURE__ */ jsx62("span", { className: "fd-chan-label", children: m.label }) : null,
7732
+ weight ? /* @__PURE__ */ jsx62("span", { className: "fd-chan-weight", children: wt || 0 }) : null
7486
7733
  ]
7487
7734
  }
7488
7735
  );
7489
7736
  }
7490
7737
 
7491
7738
  // src/components/planner/SaturationDistribution.tsx
7492
- import { jsx as jsx60, jsxs as jsxs55 } from "react/jsx-runtime";
7739
+ import { jsx as jsx63, jsxs as jsxs58 } from "react/jsx-runtime";
7493
7740
  var BANDS2 = [
7494
7741
  { key: "weak", label: "Weak", n: 1, range: "< 50" },
7495
7742
  { key: "adequate", label: "Adequate", n: 2, range: "50\u2013100" },
@@ -7500,18 +7747,18 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
7500
7747
  const grouped = BANDS2.map((b) => ({ ...b, items: campuses.filter((c) => c.band === b.key) }));
7501
7748
  const tallest = Math.max(1, ...grouped.map((g) => g.items.length));
7502
7749
  const floor = BANDS2.find((b) => b.key === floorBand) || BANDS2[0];
7503
- return /* @__PURE__ */ jsxs55("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
7504
- /* @__PURE__ */ jsx60("div", { style: { display: "grid", gridTemplateColumns: "repeat(4,1fr)", gap: 12, alignItems: "end" }, children: grouped.map((g) => {
7750
+ return /* @__PURE__ */ jsxs58("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
7751
+ /* @__PURE__ */ jsx63("div", { style: { display: "grid", gridTemplateColumns: "repeat(4,1fr)", gap: 12, alignItems: "end" }, children: grouped.map((g) => {
7505
7752
  const mark = "var(--csi-" + g.n + "-mark)";
7506
7753
  const active = selectedBand === g.key;
7507
- return /* @__PURE__ */ jsxs55(
7754
+ return /* @__PURE__ */ jsxs58(
7508
7755
  "button",
7509
7756
  {
7510
7757
  type: "button",
7511
7758
  onClick: onSelectBand ? () => onSelectBand(active ? null : g.key) : void 0,
7512
7759
  style: { display: "flex", flexDirection: "column", justifyContent: "flex-end", gap: 10, padding: 12, border: "1px solid " + (active ? "var(--border-strong)" : "var(--border)"), borderRadius: "var(--r-lg)", background: active ? "var(--surface-2)" : "var(--surface)", cursor: onSelectBand ? "pointer" : "default", textAlign: "left", minHeight: 190, transition: "background var(--dur-fast) var(--ease),border-color var(--dur-fast) var(--ease)" },
7513
7760
  children: [
7514
- /* @__PURE__ */ jsx60("span", { style: { display: "flex", flexDirection: "column-reverse", gap: 4, minHeight: tallest * 24 }, children: loading ? Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ jsx60("span", { className: "fd-skel", style: { height: 16, borderRadius: 4 } }, i)) : g.items.map((c) => /* @__PURE__ */ jsx60(
7761
+ /* @__PURE__ */ jsx63("span", { style: { display: "flex", flexDirection: "column-reverse", gap: 4, minHeight: tallest * 24 }, children: loading ? Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ jsx63("span", { className: "fd-skel", style: { height: 16, borderRadius: 4 } }, i)) : g.items.map((c) => /* @__PURE__ */ jsx63(
7515
7762
  "span",
7516
7763
  {
7517
7764
  title: c.name + " \xB7 " + c.crp,
@@ -7520,13 +7767,13 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
7520
7767
  },
7521
7768
  c.name
7522
7769
  )) }),
7523
- /* @__PURE__ */ jsxs55("span", { className: "fd-row", style: { gap: 8, alignItems: "baseline" }, children: [
7524
- /* @__PURE__ */ jsx60("span", { className: "fd-num-hero", style: { fontSize: 30, color: g.items.length ? "var(--text)" : "var(--text-disabled)" }, children: loading ? "\u2013" : g.items.length }),
7525
- /* @__PURE__ */ jsx60("span", { className: "fd-meter", style: { gap: 2, color: mark }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx60("span", { className: "fd-meter-seg" + (i <= g.n ? " is-on" : ""), style: { width: 4, height: 9 } }, i)) })
7770
+ /* @__PURE__ */ jsxs58("span", { className: "fd-row", style: { gap: 8, alignItems: "baseline" }, children: [
7771
+ /* @__PURE__ */ jsx63("span", { className: "fd-num-hero", style: { fontSize: 30, color: g.items.length ? "var(--text)" : "var(--text-disabled)" }, children: loading ? "\u2013" : g.items.length }),
7772
+ /* @__PURE__ */ jsx63("span", { className: "fd-meter", style: { gap: 2, color: mark }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx63("span", { className: "fd-meter-seg" + (i <= g.n ? " is-on" : ""), style: { width: 4, height: 9 } }, i)) })
7526
7773
  ] }),
7527
- /* @__PURE__ */ jsxs55("span", { className: "fd-stack", style: { gap: 1 }, children: [
7528
- /* @__PURE__ */ jsx60("span", { className: "fd-label-lg", children: g.label }),
7529
- /* @__PURE__ */ jsxs55("span", { className: "fd-body-sm fd-muted", style: { fontSize: 11.5 }, children: [
7774
+ /* @__PURE__ */ jsxs58("span", { className: "fd-stack", style: { gap: 1 }, children: [
7775
+ /* @__PURE__ */ jsx63("span", { className: "fd-label-lg", children: g.label }),
7776
+ /* @__PURE__ */ jsxs58("span", { className: "fd-body-sm fd-muted", style: { fontSize: 11.5 }, children: [
7530
7777
  "CRP ",
7531
7778
  g.range
7532
7779
  ] })
@@ -7536,10 +7783,10 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
7536
7783
  g.key
7537
7784
  );
7538
7785
  }) }),
7539
- floorBand ? /* @__PURE__ */ jsxs55("div", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderRadius: "var(--r-md)", background: "var(--surface-2)", border: "1px solid var(--border)", flexWrap: "wrap" }, children: [
7540
- /* @__PURE__ */ jsx60("span", { className: "fd-meter", style: { gap: 2, color: "var(--csi-" + floor.n + "-mark)" }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx60("span", { className: "fd-meter-seg" + (i <= floor.n ? " is-on" : ""), style: { width: 5, height: 12 } }, i)) }),
7541
- /* @__PURE__ */ jsxs55("span", { className: "fd-body-sm fd-secondary", style: { flex: 1, minWidth: 240 }, children: [
7542
- /* @__PURE__ */ jsxs55("strong", { style: { color: "var(--text)" }, children: [
7786
+ floorBand ? /* @__PURE__ */ jsxs58("div", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderRadius: "var(--r-md)", background: "var(--surface-2)", border: "1px solid var(--border)", flexWrap: "wrap" }, children: [
7787
+ /* @__PURE__ */ jsx63("span", { className: "fd-meter", style: { gap: 2, color: "var(--csi-" + floor.n + "-mark)" }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx63("span", { className: "fd-meter-seg" + (i <= floor.n ? " is-on" : ""), style: { width: 5, height: 12 } }, i)) }),
7788
+ /* @__PURE__ */ jsxs58("span", { className: "fd-body-sm fd-secondary", style: { flex: 1, minWidth: 240 }, children: [
7789
+ /* @__PURE__ */ jsxs58("strong", { style: { color: "var(--text)" }, children: [
7543
7790
  "Plan floor ",
7544
7791
  floorScore
7545
7792
  ] }),
@@ -7550,21 +7797,21 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
7550
7797
  }
7551
7798
 
7552
7799
  // src/components/planner/MixGap.tsx
7553
- import * as React32 from "react";
7554
- import { Fragment as Fragment15, jsx as jsx61, jsxs as jsxs56 } from "react/jsx-runtime";
7800
+ import * as React34 from "react";
7801
+ import { Fragment as Fragment15, jsx as jsx64, jsxs as jsxs59 } from "react/jsx-runtime";
7555
7802
  function MixGap({ rows = [], loading = false, className = "" }) {
7556
7803
  const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
7557
- const [hover, setHover] = React32.useState(null);
7804
+ const [hover, setHover] = React34.useState(null);
7558
7805
  const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
7559
7806
  const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
7560
- return /* @__PURE__ */ jsxs56("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 4 }, children: [
7561
- /* @__PURE__ */ jsxs56("div", { className: "fd-row", style: { gap: 16, justifyContent: "flex-end", paddingBottom: 6, flexWrap: "wrap" }, children: [
7562
- [["On target", TONE.ok], ["Close", TONE.warn], ["Short", TONE.danger]].map(([l, c]) => /* @__PURE__ */ jsxs56("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
7563
- /* @__PURE__ */ jsx61("span", { style: { width: 14, height: 9, borderRadius: 2, background: c } }),
7807
+ return /* @__PURE__ */ jsxs59("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 4 }, children: [
7808
+ /* @__PURE__ */ jsxs59("div", { className: "fd-row", style: { gap: 16, justifyContent: "flex-end", paddingBottom: 6, flexWrap: "wrap" }, children: [
7809
+ [["On target", TONE.ok], ["Close", TONE.warn], ["Short", TONE.danger]].map(([l, c]) => /* @__PURE__ */ jsxs59("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
7810
+ /* @__PURE__ */ jsx64("span", { style: { width: 14, height: 9, borderRadius: 2, background: c } }),
7564
7811
  l
7565
7812
  ] }, l)),
7566
- /* @__PURE__ */ jsxs56("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
7567
- /* @__PURE__ */ jsx61("span", { style: { width: 3, height: 14, background: "var(--n-500)" } }),
7813
+ /* @__PURE__ */ jsxs59("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
7814
+ /* @__PURE__ */ jsx64("span", { style: { width: 3, height: 14, background: "var(--n-500)" } }),
7568
7815
  "Target"
7569
7816
  ] })
7570
7817
  ] }),
@@ -7572,7 +7819,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
7572
7819
  const gap = r.realized - r.target;
7573
7820
  const tone = toneOf(gap);
7574
7821
  const tip = "Realized " + r.realized + "% vs " + r.target + "% target" + (gap < -1 ? " \xB7 " + Math.abs(gap).toFixed(0) + " pts short" : gap > 1 ? " \xB7 " + gap.toFixed(0) + " pts over" : " \xB7 on target") + (r.note ? " \u2014 " + r.note : "");
7575
- return /* @__PURE__ */ jsxs56(
7822
+ return /* @__PURE__ */ jsxs59(
7576
7823
  "div",
7577
7824
  {
7578
7825
  className: "fd-row",
@@ -7580,15 +7827,15 @@ function MixGap({ rows = [], loading = false, className = "" }) {
7580
7827
  onMouseEnter: () => setHover(r.channel),
7581
7828
  onMouseLeave: () => setHover(null),
7582
7829
  children: [
7583
- /* @__PURE__ */ jsx61("span", { style: { width: 128, flex: "none" }, children: /* @__PURE__ */ jsx61(ChannelTag, { channel: r.channel, size: "sm" }) }),
7584
- /* @__PURE__ */ jsx61("span", { style: { position: "relative", flex: 1, height: 22, minWidth: 120 }, children: loading ? /* @__PURE__ */ jsx61("span", { className: "fd-skel", style: { position: "absolute", inset: "5px 0", borderRadius: 3 } }) : /* @__PURE__ */ jsxs56(Fragment15, { children: [
7585
- /* @__PURE__ */ jsx61("span", { style: { position: "absolute", left: 0, top: 5, height: 12, width: r.realized / max * 100 + "%", background: TONE[tone], borderRadius: "2px 3px 3px 2px", transition: "width var(--dur-slow) var(--ease), background var(--dur-base) var(--ease)" } }),
7586
- /* @__PURE__ */ jsx61("span", { style: { position: "absolute", left: r.target / max * 100 + "%", top: 0, width: 3, height: 22, background: "var(--n-500)", borderRadius: 1 } }),
7587
- /* @__PURE__ */ jsxs56("span", { className: "fd-num", style: { position: "absolute", right: Math.max(r.realized, r.target) / max > 0.82 ? 0 : "auto", left: Math.max(r.realized, r.target) / max > 0.82 ? "auto" : "calc(" + Math.max(r.realized, r.target) / max * 100 + "% + 10px)", top: 2, fontSize: 12, color: "var(--text-muted)", whiteSpace: "nowrap", background: Math.max(r.realized, r.target) / max > 0.82 ? "var(--surface)" : "none", paddingLeft: 3 }, children: [
7830
+ /* @__PURE__ */ jsx64("span", { style: { width: 128, flex: "none" }, children: /* @__PURE__ */ jsx64(ChannelTag, { channel: r.channel, size: "sm" }) }),
7831
+ /* @__PURE__ */ jsx64("span", { style: { position: "relative", flex: 1, height: 22, minWidth: 120 }, children: loading ? /* @__PURE__ */ jsx64("span", { className: "fd-skel", style: { position: "absolute", inset: "5px 0", borderRadius: 3 } }) : /* @__PURE__ */ jsxs59(Fragment15, { children: [
7832
+ /* @__PURE__ */ jsx64("span", { style: { position: "absolute", left: 0, top: 5, height: 12, width: r.realized / max * 100 + "%", background: TONE[tone], borderRadius: "2px 3px 3px 2px", transition: "width var(--dur-slow) var(--ease), background var(--dur-base) var(--ease)" } }),
7833
+ /* @__PURE__ */ jsx64("span", { style: { position: "absolute", left: r.target / max * 100 + "%", top: 0, width: 3, height: 22, background: "var(--n-500)", borderRadius: 1 } }),
7834
+ /* @__PURE__ */ jsxs59("span", { className: "fd-num", style: { position: "absolute", right: Math.max(r.realized, r.target) / max > 0.82 ? 0 : "auto", left: Math.max(r.realized, r.target) / max > 0.82 ? "auto" : "calc(" + Math.max(r.realized, r.target) / max * 100 + "% + 10px)", top: 2, fontSize: 12, color: "var(--text-muted)", whiteSpace: "nowrap", background: Math.max(r.realized, r.target) / max > 0.82 ? "var(--surface)" : "none", paddingLeft: 3 }, children: [
7588
7835
  r.realized,
7589
7836
  "%"
7590
7837
  ] }),
7591
- hover === r.channel ? /* @__PURE__ */ jsx61("span", { className: "fd-tooltip", role: "tooltip", style: { position: "absolute", left: 0, right: "auto", bottom: 26, maxWidth: "min(340px, 100%)", whiteSpace: "normal", textAlign: "left", width: "max-content" }, children: tip }) : null
7838
+ hover === r.channel ? /* @__PURE__ */ jsx64("span", { className: "fd-tooltip", role: "tooltip", style: { position: "absolute", left: 0, right: "auto", bottom: 26, maxWidth: "min(340px, 100%)", whiteSpace: "normal", textAlign: "left", width: "max-content" }, children: tip }) : null
7592
7839
  ] }) })
7593
7840
  ]
7594
7841
  },
@@ -7599,7 +7846,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
7599
7846
  }
7600
7847
 
7601
7848
  // src/components/planner/ChannelContribution.tsx
7602
- import { jsx as jsx62, jsxs as jsxs57 } from "react/jsx-runtime";
7849
+ import { jsx as jsx65, jsxs as jsxs60 } from "react/jsx-runtime";
7603
7850
  var money = (n) => "$" + Math.round(n).toLocaleString();
7604
7851
  function ChannelContribution({
7605
7852
  channels = [],
@@ -7615,9 +7862,9 @@ function ChannelContribution({
7615
7862
  const grand = total !== void 0 ? total : base + bonus;
7616
7863
  const pct = (v) => grand ? v / grand * 100 : 0;
7617
7864
  const spendTotal = channels.reduce((s, c) => s + Number(String(c.spend || 0).replace(/[^0-9.]/g, "")), 0);
7618
- return /* @__PURE__ */ jsxs57("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
7619
- loading ? /* @__PURE__ */ jsx62("span", { className: "fd-skel", style: { height: 34, borderRadius: "var(--r-sm)" } }) : /* @__PURE__ */ jsxs57("div", { className: "fd-row", style: { height: 34, borderRadius: "var(--r-sm)", overflow: "hidden", gap: 2, background: "var(--surface-3)" }, children: [
7620
- channels.map((c) => /* @__PURE__ */ jsx62(
7865
+ return /* @__PURE__ */ jsxs60("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
7866
+ loading ? /* @__PURE__ */ jsx65("span", { className: "fd-skel", style: { height: 34, borderRadius: "var(--r-sm)" } }) : /* @__PURE__ */ jsxs60("div", { className: "fd-row", style: { height: 34, borderRadius: "var(--r-sm)", overflow: "hidden", gap: 2, background: "var(--surface-3)" }, children: [
7867
+ channels.map((c) => /* @__PURE__ */ jsx65(
7621
7868
  "span",
7622
7869
  {
7623
7870
  title: c.name + " \xB7 " + c.crp.toFixed(1) + " CRP",
@@ -7626,7 +7873,7 @@ function ChannelContribution({
7626
7873
  },
7627
7874
  c.name
7628
7875
  )),
7629
- bonus > 0 ? /* @__PURE__ */ jsx62(
7876
+ bonus > 0 ? /* @__PURE__ */ jsx65(
7630
7877
  "span",
7631
7878
  {
7632
7879
  title: "Surround-sound bonus +" + bonusPct + "%",
@@ -7635,18 +7882,18 @@ function ChannelContribution({
7635
7882
  }
7636
7883
  ) : null
7637
7884
  ] }),
7638
- showTable ? /* @__PURE__ */ jsxs57("table", { className: "fd-table", style: { fontSize: "var(--body-sm-size)" }, children: [
7639
- /* @__PURE__ */ jsx62("thead", { children: /* @__PURE__ */ jsxs57("tr", { children: [
7640
- /* @__PURE__ */ jsx62("th", { style: { width: "34%" }, children: "Channel" }),
7641
- /* @__PURE__ */ jsx62("th", { style: { width: "16%" }, children: "Weight" }),
7642
- /* @__PURE__ */ jsx62("th", { className: "is-num", style: { width: "16%" }, children: "Spend" }),
7643
- /* @__PURE__ */ jsx62("th", { className: "is-num", style: { width: "17%" }, children: "CRP" }),
7644
- /* @__PURE__ */ jsx62("th", { className: "is-num", style: { width: "17%" }, children: "Share" })
7885
+ showTable ? /* @__PURE__ */ jsxs60("table", { className: "fd-table", style: { fontSize: "var(--body-sm-size)" }, children: [
7886
+ /* @__PURE__ */ jsx65("thead", { children: /* @__PURE__ */ jsxs60("tr", { children: [
7887
+ /* @__PURE__ */ jsx65("th", { style: { width: "34%" }, children: "Channel" }),
7888
+ /* @__PURE__ */ jsx65("th", { style: { width: "16%" }, children: "Weight" }),
7889
+ /* @__PURE__ */ jsx65("th", { className: "is-num", style: { width: "16%" }, children: "Spend" }),
7890
+ /* @__PURE__ */ jsx65("th", { className: "is-num", style: { width: "17%" }, children: "CRP" }),
7891
+ /* @__PURE__ */ jsx65("th", { className: "is-num", style: { width: "17%" }, children: "Share" })
7645
7892
  ] }) }),
7646
- /* @__PURE__ */ jsxs57("tbody", { children: [
7647
- channels.map((c) => /* @__PURE__ */ jsxs57("tr", { children: [
7648
- /* @__PURE__ */ jsx62("td", { children: /* @__PURE__ */ jsx62(ChannelTag, { channel: c.name, size: "sm" }) }),
7649
- /* @__PURE__ */ jsx62("td", { children: /* @__PURE__ */ jsx62(
7893
+ /* @__PURE__ */ jsxs60("tbody", { children: [
7894
+ channels.map((c) => /* @__PURE__ */ jsxs60("tr", { children: [
7895
+ /* @__PURE__ */ jsx65("td", { children: /* @__PURE__ */ jsx65(ChannelTag, { channel: c.name, size: "sm" }) }),
7896
+ /* @__PURE__ */ jsx65("td", { children: /* @__PURE__ */ jsx65(
7650
7897
  "span",
7651
7898
  {
7652
7899
  className: "fd-badge fd-badge-neutral",
@@ -7655,38 +7902,38 @@ function ChannelContribution({
7655
7902
  children: "weight " + (channelWeightOf(c.name) || 0)
7656
7903
  }
7657
7904
  ) }),
7658
- /* @__PURE__ */ jsx62("td", { className: "is-num", children: c.spend }),
7659
- /* @__PURE__ */ jsx62("td", { className: "is-num", children: c.crp.toFixed(1) }),
7660
- /* @__PURE__ */ jsxs57("td", { className: "is-num", children: [
7905
+ /* @__PURE__ */ jsx65("td", { className: "is-num", children: c.spend }),
7906
+ /* @__PURE__ */ jsx65("td", { className: "is-num", children: c.crp.toFixed(1) }),
7907
+ /* @__PURE__ */ jsxs60("td", { className: "is-num", children: [
7661
7908
  pct(c.crp).toFixed(0),
7662
7909
  "%"
7663
7910
  ] })
7664
7911
  ] }, c.name)),
7665
- bonus > 0 ? /* @__PURE__ */ jsxs57("tr", { children: [
7666
- /* @__PURE__ */ jsx62("td", { children: /* @__PURE__ */ jsxs57("span", { className: "fd-row", style: { gap: 9, fontWeight: 600 }, children: [
7667
- /* @__PURE__ */ jsx62("span", { style: { width: 9, height: 9, borderRadius: 2, background: "repeating-linear-gradient(135deg,var(--csi-3-mark) 0 3px,var(--csi-2-mark) 3px 6px)", flex: "none" } }),
7912
+ bonus > 0 ? /* @__PURE__ */ jsxs60("tr", { children: [
7913
+ /* @__PURE__ */ jsx65("td", { children: /* @__PURE__ */ jsxs60("span", { className: "fd-row", style: { gap: 9, fontWeight: 600 }, children: [
7914
+ /* @__PURE__ */ jsx65("span", { style: { width: 9, height: 9, borderRadius: 2, background: "repeating-linear-gradient(135deg,var(--csi-3-mark) 0 3px,var(--csi-2-mark) 3px 6px)", flex: "none" } }),
7668
7915
  "Surround-sound bonus"
7669
7916
  ] }) }),
7670
- /* @__PURE__ */ jsx62("td", { children: /* @__PURE__ */ jsxs57("span", { className: "fd-badge fd-badge-success", style: { height: 20, fontSize: 11 }, children: [
7917
+ /* @__PURE__ */ jsx65("td", { children: /* @__PURE__ */ jsxs60("span", { className: "fd-badge fd-badge-success", style: { height: 20, fontSize: 11 }, children: [
7671
7918
  "+",
7672
7919
  bonusPct,
7673
7920
  "% of +",
7674
7921
  bonusMax,
7675
7922
  "%"
7676
7923
  ] }) }),
7677
- /* @__PURE__ */ jsx62("td", { className: "is-num fd-muted", children: "\u2014" }),
7678
- /* @__PURE__ */ jsx62("td", { className: "is-num", children: bonus.toFixed(1) }),
7679
- /* @__PURE__ */ jsxs57("td", { className: "is-num", children: [
7924
+ /* @__PURE__ */ jsx65("td", { className: "is-num fd-muted", children: "\u2014" }),
7925
+ /* @__PURE__ */ jsx65("td", { className: "is-num", children: bonus.toFixed(1) }),
7926
+ /* @__PURE__ */ jsxs60("td", { className: "is-num", children: [
7680
7927
  pct(bonus).toFixed(0),
7681
7928
  "%"
7682
7929
  ] })
7683
7930
  ] }) : null,
7684
- /* @__PURE__ */ jsxs57("tr", { style: { background: "var(--surface-2)" }, children: [
7685
- /* @__PURE__ */ jsx62("td", { style: { fontWeight: 700 }, children: "Campus total" }),
7686
- /* @__PURE__ */ jsx62("td", {}),
7687
- /* @__PURE__ */ jsx62("td", { className: "is-num", style: { fontWeight: 700 }, children: money(spendTotal) }),
7688
- /* @__PURE__ */ jsx62("td", { className: "is-num", style: { fontWeight: 700 }, children: grand.toFixed(1) }),
7689
- /* @__PURE__ */ jsx62("td", { className: "is-num", style: { fontWeight: 700 }, children: "100%" })
7931
+ /* @__PURE__ */ jsxs60("tr", { style: { background: "var(--surface-2)" }, children: [
7932
+ /* @__PURE__ */ jsx65("td", { style: { fontWeight: 700 }, children: "Campus total" }),
7933
+ /* @__PURE__ */ jsx65("td", {}),
7934
+ /* @__PURE__ */ jsx65("td", { className: "is-num", style: { fontWeight: 700 }, children: money(spendTotal) }),
7935
+ /* @__PURE__ */ jsx65("td", { className: "is-num", style: { fontWeight: 700 }, children: grand.toFixed(1) }),
7936
+ /* @__PURE__ */ jsx65("td", { className: "is-num", style: { fontWeight: 700 }, children: "100%" })
7690
7937
  ] })
7691
7938
  ] })
7692
7939
  ] }) : null
@@ -7694,8 +7941,8 @@ function ChannelContribution({
7694
7941
  }
7695
7942
 
7696
7943
  // src/components/planner/BudgetReallocator.tsx
7697
- import * as React33 from "react";
7698
- import { Fragment as Fragment16, jsx as jsx63, jsxs as jsxs58 } from "react/jsx-runtime";
7944
+ import * as React35 from "react";
7945
+ import { Fragment as Fragment16, jsx as jsx66, jsxs as jsxs61 } from "react/jsx-runtime";
7699
7946
  var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
7700
7947
  function BudgetReallocator({
7701
7948
  campus,
@@ -7710,8 +7957,8 @@ function BudgetReallocator({
7710
7957
  onCancel,
7711
7958
  className = ""
7712
7959
  }) {
7713
- const [draft, setDraft] = React33.useState(spend);
7714
- React33.useEffect(() => setDraft(spend), [spend]);
7960
+ const [draft, setDraft] = React35.useState(spend);
7961
+ React35.useEffect(() => setDraft(spend), [spend]);
7715
7962
  const dirty = draft !== spend;
7716
7963
  const nextCrp = scoreFor ? scoreFor(draft) : crp;
7717
7964
  const nextBand = bandFor(nextCrp);
@@ -7726,24 +7973,24 @@ function BudgetReallocator({
7726
7973
  setDraft(spend);
7727
7974
  if (onCancel) onCancel();
7728
7975
  };
7729
- return /* @__PURE__ */ jsxs58(
7976
+ return /* @__PURE__ */ jsxs61(
7730
7977
  "div",
7731
7978
  {
7732
7979
  className: ["fd-stack", className].filter(Boolean).join(" "),
7733
7980
  style: { gap: 14, padding: 18, border: "1px solid " + (dirty ? "var(--border-brand)" : "var(--border)"), borderRadius: "var(--r-lg)", background: dirty ? "var(--surface-brand)" : "var(--surface)", color: "var(--text)", transition: "background var(--dur-base) var(--ease),border-color var(--dur-base) var(--ease)" },
7734
7981
  children: [
7735
- /* @__PURE__ */ jsxs58("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
7736
- /* @__PURE__ */ jsx63("span", { className: "fd-h4", style: { flex: 1, minWidth: 140 }, children: campus }),
7737
- /* @__PURE__ */ jsx63(CsiBadge, { band: nowBand, crp: Number(crp.toFixed(1)), size: "medium" }),
7738
- dirty ? /* @__PURE__ */ jsxs58(Fragment16, { children: [
7739
- /* @__PURE__ */ jsx63("i", { className: "ph ph-arrow-right fd-muted", "aria-hidden": "true" }),
7740
- /* @__PURE__ */ jsx63(CsiBadge, { band: nextBand, crp: Number(nextCrp.toFixed(1)), size: "medium", preview: true })
7982
+ /* @__PURE__ */ jsxs61("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
7983
+ /* @__PURE__ */ jsx66("span", { className: "fd-h4", style: { flex: 1, minWidth: 140 }, children: campus }),
7984
+ /* @__PURE__ */ jsx66(CsiBadge, { band: nowBand, crp: Number(crp.toFixed(1)), size: "medium" }),
7985
+ dirty ? /* @__PURE__ */ jsxs61(Fragment16, { children: [
7986
+ /* @__PURE__ */ jsx66("i", { className: "ph ph-arrow-right fd-muted", "aria-hidden": "true" }),
7987
+ /* @__PURE__ */ jsx66(CsiBadge, { band: nextBand, crp: Number(nextCrp.toFixed(1)), size: "medium", preview: true })
7741
7988
  ] }) : null
7742
7989
  ] }),
7743
- /* @__PURE__ */ jsxs58("div", { className: "fd-slider", children: [
7744
- /* @__PURE__ */ jsx63("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
7745
- dirty ? /* @__PURE__ */ jsx63("span", { className: "fd-slider-chip", style: { left: pct + "%", background: delta < 0 ? "var(--danger-solid)" : "var(--ok-solid)" }, children: (delta < 0 ? "\u2212$" : "+$") + Math.abs(delta).toLocaleString() }) : null,
7746
- /* @__PURE__ */ jsx63(
7990
+ /* @__PURE__ */ jsxs61("div", { className: "fd-slider", children: [
7991
+ /* @__PURE__ */ jsx66("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
7992
+ dirty ? /* @__PURE__ */ jsx66("span", { className: "fd-slider-chip", style: { left: pct + "%", background: delta < 0 ? "var(--danger-solid)" : "var(--ok-solid)" }, children: (delta < 0 ? "\u2212$" : "+$") + Math.abs(delta).toLocaleString() }) : null,
7993
+ /* @__PURE__ */ jsx66(
7747
7994
  "input",
7748
7995
  {
7749
7996
  type: "range",
@@ -7759,13 +8006,13 @@ function BudgetReallocator({
7759
8006
  }
7760
8007
  )
7761
8008
  ] }),
7762
- /* @__PURE__ */ jsxs58("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
7763
- /* @__PURE__ */ jsxs58("span", { className: "fd-stack", style: { gap: 2, flex: 1, minWidth: 150 }, children: [
7764
- /* @__PURE__ */ jsx63("span", { className: "fd-num", style: { fontSize: 19, fontWeight: 700 }, children: "$" + draft.toLocaleString() }),
7765
- /* @__PURE__ */ jsx63("span", { className: "fd-body-sm fd-muted", children: "Arrow keys step $100, shift+arrow $1,000. Escape reverts." })
8009
+ /* @__PURE__ */ jsxs61("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
8010
+ /* @__PURE__ */ jsxs61("span", { className: "fd-stack", style: { gap: 2, flex: 1, minWidth: 150 }, children: [
8011
+ /* @__PURE__ */ jsx66("span", { className: "fd-num", style: { fontSize: 19, fontWeight: 700 }, children: "$" + draft.toLocaleString() }),
8012
+ /* @__PURE__ */ jsx66("span", { className: "fd-body-sm fd-muted", children: "Arrow keys step $100, shift+arrow $1,000. Escape reverts." })
7766
8013
  ] }),
7767
- /* @__PURE__ */ jsx63("button", { type: "button", className: "fd-btn fd-btn-ghost", disabled: !dirty, onClick: revert, children: "Cancel" }),
7768
- /* @__PURE__ */ jsx63(
8014
+ /* @__PURE__ */ jsx66("button", { type: "button", className: "fd-btn fd-btn-ghost", disabled: !dirty, onClick: revert, children: "Cancel" }),
8015
+ /* @__PURE__ */ jsx66(
7769
8016
  "button",
7770
8017
  {
7771
8018
  type: "button",
@@ -7784,7 +8031,7 @@ function BudgetReallocator({
7784
8031
  }
7785
8032
 
7786
8033
  // src/components/planner/SurroundSound.tsx
7787
- import { jsx as jsx64, jsxs as jsxs59 } from "react/jsx-runtime";
8034
+ import { jsx as jsx67, jsxs as jsxs62 } from "react/jsx-runtime";
7788
8035
  var CATEGORIES = [
7789
8036
  { key: "ooh", label: "OOH", icon: "flag-banner", color: "var(--ch-ooh)" },
7790
8037
  { key: "transit", label: "Transit", icon: "bus", color: "var(--ch-transit)" },
@@ -7796,26 +8043,26 @@ var CATEGORIES = [
7796
8043
  function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost, className = "" }) {
7797
8044
  const earned = Math.max(0, Math.min(1, bonusPct / bonusMax));
7798
8045
  const single = present.length <= 2;
7799
- return /* @__PURE__ */ jsxs59("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, children: [
7800
- /* @__PURE__ */ jsx64("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: CATEGORIES.map((c) => {
8046
+ return /* @__PURE__ */ jsxs62("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, children: [
8047
+ /* @__PURE__ */ jsx67("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: CATEGORIES.map((c) => {
7801
8048
  const on = present.includes(c.key);
7802
- return /* @__PURE__ */ jsxs59(
8049
+ return /* @__PURE__ */ jsxs62(
7803
8050
  "span",
7804
8051
  {
7805
8052
  title: c.label + (on ? " \u2014 present" : " \u2014 not bought"),
7806
8053
  style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 5, width: 62, padding: "10px 0", borderRadius: "var(--r-md)", border: "1px solid " + (on ? "var(--csi-2-edge)" : "var(--border)"), background: on ? "var(--csi-2-fill)" : "var(--surface-2)", color: on ? "var(--csi-2-text)" : "var(--text-disabled)" },
7807
8054
  children: [
7808
- /* @__PURE__ */ jsx64("i", { className: "ph ph-" + c.icon, style: { fontSize: 19, color: on ? c.color : "var(--text-muted)" }, "aria-hidden": "true" }),
7809
- /* @__PURE__ */ jsx64("span", { style: { fontSize: 10.5, fontWeight: 700 }, children: c.label })
8055
+ /* @__PURE__ */ jsx67("i", { className: "ph ph-" + c.icon, style: { fontSize: 19, color: on ? c.color : "var(--text-muted)" }, "aria-hidden": "true" }),
8056
+ /* @__PURE__ */ jsx67("span", { style: { fontSize: 10.5, fontWeight: 700 }, children: c.label })
7810
8057
  ]
7811
8058
  },
7812
8059
  c.key
7813
8060
  );
7814
8061
  }) }),
7815
- /* @__PURE__ */ jsxs59("div", { className: "fd-stack", style: { gap: 8 }, children: [
7816
- /* @__PURE__ */ jsxs59("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
7817
- /* @__PURE__ */ jsx64("span", { className: "fd-label-lg", children: "Surround-sound bonus earned" }),
7818
- /* @__PURE__ */ jsxs59("span", { className: "fd-num", style: { color: single ? "var(--warn-text)" : "var(--csi-3-mark)", fontWeight: 700 }, children: [
8062
+ /* @__PURE__ */ jsxs62("div", { className: "fd-stack", style: { gap: 8 }, children: [
8063
+ /* @__PURE__ */ jsxs62("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
8064
+ /* @__PURE__ */ jsx67("span", { className: "fd-label-lg", children: "Surround-sound bonus earned" }),
8065
+ /* @__PURE__ */ jsxs62("span", { className: "fd-num", style: { color: single ? "var(--warn-text)" : "var(--csi-3-mark)", fontWeight: 700 }, children: [
7819
8066
  "+",
7820
8067
  bonusPct,
7821
8068
  "% of +",
@@ -7823,8 +8070,8 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
7823
8070
  "%"
7824
8071
  ] })
7825
8072
  ] }),
7826
- /* @__PURE__ */ jsx64("div", { style: { height: 8, borderRadius: "var(--r-xs)", background: "var(--surface-3)", overflow: "hidden" }, children: /* @__PURE__ */ jsx64("div", { style: { height: "100%", width: earned * 100 + "%", background: "var(--csi-3-mark)", borderRadius: "inherit", transition: "width var(--dur-slow) var(--ease)" } }) }),
7827
- /* @__PURE__ */ jsxs59("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: [
8073
+ /* @__PURE__ */ jsx67("div", { style: { height: 8, borderRadius: "var(--r-xs)", background: "var(--surface-3)", overflow: "hidden" }, children: /* @__PURE__ */ jsx67("div", { style: { height: "100%", width: earned * 100 + "%", background: "var(--csi-3-mark)", borderRadius: "inherit", transition: "width var(--dur-slow) var(--ease)" } }) }),
8074
+ /* @__PURE__ */ jsxs62("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: [
7828
8075
  present.length,
7829
8076
  " of 6 channel categories present.",
7830
8077
  " ",
@@ -7836,10 +8083,10 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
7836
8083
  }
7837
8084
 
7838
8085
  // src/components/chat/AgentChatPanel.tsx
7839
- import * as React39 from "react";
8086
+ import * as React41 from "react";
7840
8087
 
7841
8088
  // src/components/chat/chatEngine.ts
7842
- import * as React34 from "react";
8089
+ import * as React36 from "react";
7843
8090
  var CHAT_UNAVAILABLE = "chat_unavailable";
7844
8091
  var JOB_PENDING = ["queued", "running"];
7845
8092
  var JOB_SUCCESS = ["completed", "recovered"];
@@ -7893,22 +8140,22 @@ function useChatEngine(opts) {
7893
8140
  onClear,
7894
8141
  onFeedback
7895
8142
  } = opts || {};
7896
- const [status, setStatus] = React34.useState("idle");
7897
- const [threadId, setThreadId] = React34.useState(null);
7898
- const [messages, setMessages] = React34.useState([]);
7899
- const [queue, setQueue] = React34.useState([]);
7900
- const [fatal, setFatal] = React34.useState(null);
7901
- const [busy, setBusy] = React34.useState(false);
7902
- const [turnStartedAt, setTurnStartedAt] = React34.useState(null);
7903
- const listRef = React34.useRef([]);
7904
- const queueRef = React34.useRef([]);
7905
- const busyRef = React34.useRef(false);
7906
- const stoppedRef = React34.useRef(false);
7907
- const abortRef = React34.useRef(null);
7908
- const serverCount = React34.useRef(0);
7909
- const threadRef = React34.useRef(null);
7910
- const mounted = React34.useRef(true);
7911
- React34.useEffect(() => {
8143
+ const [status, setStatus] = React36.useState("idle");
8144
+ const [threadId, setThreadId] = React36.useState(null);
8145
+ const [messages, setMessages] = React36.useState([]);
8146
+ const [queue, setQueue] = React36.useState([]);
8147
+ const [fatal, setFatal] = React36.useState(null);
8148
+ const [busy, setBusy] = React36.useState(false);
8149
+ const [turnStartedAt, setTurnStartedAt] = React36.useState(null);
8150
+ const listRef = React36.useRef([]);
8151
+ const queueRef = React36.useRef([]);
8152
+ const busyRef = React36.useRef(false);
8153
+ const stoppedRef = React36.useRef(false);
8154
+ const abortRef = React36.useRef(null);
8155
+ const serverCount = React36.useRef(0);
8156
+ const threadRef = React36.useRef(null);
8157
+ const mounted = React36.useRef(true);
8158
+ React36.useEffect(() => {
7912
8159
  mounted.current = true;
7913
8160
  return () => {
7914
8161
  mounted.current = false;
@@ -7930,14 +8177,14 @@ function useChatEngine(opts) {
7930
8177
  }
7931
8178
  return false;
7932
8179
  };
7933
- const loadThread = React34.useCallback(async (id) => {
8180
+ const loadThread = React36.useCallback(async (id) => {
7934
8181
  const data = await apiAdapter.getThread(id);
7935
8182
  const list = [...data && data.messages || []];
7936
8183
  serverCount.current = list.length;
7937
8184
  commit(list);
7938
8185
  return list;
7939
8186
  }, [apiAdapter]);
7940
- React34.useEffect(() => {
8187
+ React36.useEffect(() => {
7941
8188
  if (!apiAdapter) {
7942
8189
  setStatus("idle");
7943
8190
  setFatal(null);
@@ -8150,7 +8397,7 @@ function useChatEngine(opts) {
8150
8397
  await dispatchTurn(turn);
8151
8398
  }
8152
8399
  }
8153
- const send = React34.useCallback((text, attachments) => {
8400
+ const send = React36.useCallback((text, attachments) => {
8154
8401
  const body = (text || "").trim();
8155
8402
  if (!body && !(attachments && attachments.length)) return;
8156
8403
  if (status === "disconnected") return;
@@ -8160,7 +8407,7 @@ function useChatEngine(opts) {
8160
8407
  stoppedRef.current = false;
8161
8408
  drain();
8162
8409
  }, [status]);
8163
- const stop = React34.useCallback(() => {
8410
+ const stop = React36.useCallback(() => {
8164
8411
  stoppedRef.current = true;
8165
8412
  const ac = abortRef.current;
8166
8413
  if (ac) {
@@ -8179,11 +8426,11 @@ function useChatEngine(opts) {
8179
8426
  store.del(STORAGE_PREFIX + threadRef.current);
8180
8427
  }
8181
8428
  }, [apiAdapter]);
8182
- const removeQueued = React34.useCallback((id) => {
8429
+ const removeQueued = React36.useCallback((id) => {
8183
8430
  queueRef.current = queueRef.current.filter((t) => t.id !== id);
8184
8431
  setQueue(queueRef.current.slice());
8185
8432
  }, []);
8186
- const retry = React34.useCallback(() => {
8433
+ const retry = React36.useCallback(() => {
8187
8434
  const list = listRef.current;
8188
8435
  let at = -1;
8189
8436
  for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
@@ -8199,19 +8446,19 @@ function useChatEngine(opts) {
8199
8446
  setQueue(queueRef.current.slice());
8200
8447
  drain();
8201
8448
  }, []);
8202
- const clear = React34.useCallback(() => {
8449
+ const clear = React36.useCallback(() => {
8203
8450
  commit([]);
8204
8451
  serverCount.current = 0;
8205
8452
  queueRef.current = [];
8206
8453
  setQueue([]);
8207
8454
  onClear && onClear();
8208
8455
  }, [onClear]);
8209
- const setFeedback = React34.useCallback((id, value) => {
8456
+ const setFeedback = React36.useCallback((id, value) => {
8210
8457
  patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
8211
8458
  const msg = listRef.current.find((m) => m.id === id);
8212
8459
  onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
8213
8460
  }, [onFeedback]);
8214
- const reload = React34.useCallback(async () => {
8461
+ const reload = React36.useCallback(async () => {
8215
8462
  if (!threadRef.current) return;
8216
8463
  setStatus("loading");
8217
8464
  try {
@@ -8249,11 +8496,11 @@ var ChatKit = {
8249
8496
  };
8250
8497
 
8251
8498
  // src/components/chat/ChatTranscript.tsx
8252
- import * as React36 from "react";
8499
+ import * as React38 from "react";
8253
8500
 
8254
8501
  // src/components/chat/ChatTurn.tsx
8255
- import * as React35 from "react";
8256
- import { jsx as jsx65, jsxs as jsxs60 } from "react/jsx-runtime";
8502
+ import * as React37 from "react";
8503
+ import { jsx as jsx68, jsxs as jsxs63 } from "react/jsx-runtime";
8257
8504
  function JsonView({ value }) {
8258
8505
  let text;
8259
8506
  try {
@@ -8261,67 +8508,67 @@ function JsonView({ value }) {
8261
8508
  } catch (e) {
8262
8509
  text = String(value);
8263
8510
  }
8264
- return /* @__PURE__ */ jsx65(CodeBlock, { code: text, language: "json", collapseAfter: 18 });
8511
+ return /* @__PURE__ */ jsx68(CodeBlock, { code: text, language: "json", collapseAfter: 18 });
8265
8512
  }
8266
8513
  function PacketCard({ packet, schema, render, onApply, applied }) {
8267
8514
  if (!packet) return null;
8268
8515
  const s = schema || {};
8269
8516
  const invalid = packet.valid === false;
8270
8517
  const title = s.heading || packet.type;
8271
- return /* @__PURE__ */ jsxs60("section", { className: "fdc-packet" + (invalid ? " is-invalid" : ""), "aria-label": title, children: [
8272
- /* @__PURE__ */ jsxs60("header", { className: "fdc-packet-head", children: [
8273
- /* @__PURE__ */ jsx65("i", { className: "ph ph-" + (s.icon || "package"), "aria-hidden": "true" }),
8274
- /* @__PURE__ */ jsx65("span", { className: "fdc-packet-title", children: title }),
8275
- packet.repaired ? /* @__PURE__ */ jsx65("span", { className: "fdc-packet-badge", children: "Repaired" }) : null,
8276
- invalid ? /* @__PURE__ */ jsx65("span", { className: "fdc-packet-badge is-danger", children: "Invalid" }) : null
8518
+ return /* @__PURE__ */ jsxs63("section", { className: "fdc-packet" + (invalid ? " is-invalid" : ""), "aria-label": title, children: [
8519
+ /* @__PURE__ */ jsxs63("header", { className: "fdc-packet-head", children: [
8520
+ /* @__PURE__ */ jsx68("i", { className: "ph ph-" + (s.icon || "package"), "aria-hidden": "true" }),
8521
+ /* @__PURE__ */ jsx68("span", { className: "fdc-packet-title", children: title }),
8522
+ packet.repaired ? /* @__PURE__ */ jsx68("span", { className: "fdc-packet-badge", children: "Repaired" }) : null,
8523
+ invalid ? /* @__PURE__ */ jsx68("span", { className: "fdc-packet-badge is-danger", children: "Invalid" }) : null
8277
8524
  ] }),
8278
- invalid ? /* @__PURE__ */ jsxs60("div", { className: "fdc-packet-alert", role: "alert", children: [
8279
- /* @__PURE__ */ jsx65("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
8280
- /* @__PURE__ */ jsx65("span", { children: packet.error || "This result failed validation and can\u2019t be applied." })
8281
- ] }) : /* @__PURE__ */ jsx65("div", { className: "fdc-packet-body", children: render ? render(packet) : /* @__PURE__ */ jsx65(JsonView, { value: packet.payload }) }),
8282
- !invalid && onApply ? /* @__PURE__ */ jsxs60("footer", { className: "fdc-packet-foot", children: [
8283
- packet.repaired ? /* @__PURE__ */ jsx65("span", { className: "fdc-packet-note", children: "Corrected by the backend after a first attempt." }) : /* @__PURE__ */ jsx65("span", {}),
8284
- /* @__PURE__ */ jsxs60("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", disabled: applied, onClick: () => onApply(packet), children: [
8285
- /* @__PURE__ */ jsx65("i", { className: "ph ph-" + (applied ? "check" : "arrow-square-in"), "aria-hidden": "true" }),
8525
+ invalid ? /* @__PURE__ */ jsxs63("div", { className: "fdc-packet-alert", role: "alert", children: [
8526
+ /* @__PURE__ */ jsx68("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
8527
+ /* @__PURE__ */ jsx68("span", { children: packet.error || "This result failed validation and can\u2019t be applied." })
8528
+ ] }) : /* @__PURE__ */ jsx68("div", { className: "fdc-packet-body", children: render ? render(packet) : /* @__PURE__ */ jsx68(JsonView, { value: packet.payload }) }),
8529
+ !invalid && onApply ? /* @__PURE__ */ jsxs63("footer", { className: "fdc-packet-foot", children: [
8530
+ packet.repaired ? /* @__PURE__ */ jsx68("span", { className: "fdc-packet-note", children: "Corrected by the backend after a first attempt." }) : /* @__PURE__ */ jsx68("span", {}),
8531
+ /* @__PURE__ */ jsxs63("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", disabled: applied, onClick: () => onApply(packet), children: [
8532
+ /* @__PURE__ */ jsx68("i", { className: "ph ph-" + (applied ? "check" : "arrow-square-in"), "aria-hidden": "true" }),
8286
8533
  applied ? "Applied" : s.applyLabel || "Apply"
8287
8534
  ] })
8288
8535
  ] }) : null
8289
8536
  ] });
8290
8537
  }
8291
8538
  function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
8292
- const [open, setOpen] = React35.useState(defaultOpen);
8539
+ const [open, setOpen] = React37.useState(defaultOpen);
8293
8540
  if (!text) return null;
8294
- return /* @__PURE__ */ jsxs60("div", { className: "fdc-think" + (open ? " is-open" : ""), children: [
8295
- /* @__PURE__ */ jsxs60("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
8296
- /* @__PURE__ */ jsx65("i", { className: "ph ph-brain", "aria-hidden": "true" }),
8297
- /* @__PURE__ */ jsx65("span", { children: streaming ? "Thinking" : durationMs ? "Thought for " + formatDuration(durationMs) : "Thought process" }),
8298
- streaming ? /* @__PURE__ */ jsxs60("span", { className: "fdc-dots", "aria-hidden": "true", children: [
8299
- /* @__PURE__ */ jsx65("span", {}),
8300
- /* @__PURE__ */ jsx65("span", {}),
8301
- /* @__PURE__ */ jsx65("span", {})
8541
+ return /* @__PURE__ */ jsxs63("div", { className: "fdc-think" + (open ? " is-open" : ""), children: [
8542
+ /* @__PURE__ */ jsxs63("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
8543
+ /* @__PURE__ */ jsx68("i", { className: "ph ph-brain", "aria-hidden": "true" }),
8544
+ /* @__PURE__ */ jsx68("span", { children: streaming ? "Thinking" : durationMs ? "Thought for " + formatDuration(durationMs) : "Thought process" }),
8545
+ streaming ? /* @__PURE__ */ jsxs63("span", { className: "fdc-dots", "aria-hidden": "true", children: [
8546
+ /* @__PURE__ */ jsx68("span", {}),
8547
+ /* @__PURE__ */ jsx68("span", {}),
8548
+ /* @__PURE__ */ jsx68("span", {})
8302
8549
  ] }) : null,
8303
- /* @__PURE__ */ jsx65("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" })
8550
+ /* @__PURE__ */ jsx68("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" })
8304
8551
  ] }),
8305
- open ? /* @__PURE__ */ jsx65("div", { className: "fdc-think-body", children: text }) : null
8552
+ open ? /* @__PURE__ */ jsx68("div", { className: "fdc-think-body", children: text }) : null
8306
8553
  ] });
8307
8554
  }
8308
8555
  function Citations({ items = [], onOpen }) {
8309
- const [open, setOpen] = React35.useState(false);
8556
+ const [open, setOpen] = React37.useState(false);
8310
8557
  if (!items.length) return null;
8311
- return /* @__PURE__ */ jsxs60("div", { className: "fdc-cites", children: [
8312
- /* @__PURE__ */ jsxs60("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
8313
- /* @__PURE__ */ jsx65("i", { className: "ph ph-quotes", "aria-hidden": "true" }),
8314
- /* @__PURE__ */ jsxs60("span", { children: [
8558
+ return /* @__PURE__ */ jsxs63("div", { className: "fdc-cites", children: [
8559
+ /* @__PURE__ */ jsxs63("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
8560
+ /* @__PURE__ */ jsx68("i", { className: "ph ph-quotes", "aria-hidden": "true" }),
8561
+ /* @__PURE__ */ jsxs63("span", { children: [
8315
8562
  items.length,
8316
8563
  " source",
8317
8564
  items.length === 1 ? "" : "s"
8318
8565
  ] }),
8319
- /* @__PURE__ */ jsx65("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" })
8566
+ /* @__PURE__ */ jsx68("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" })
8320
8567
  ] }),
8321
- open ? /* @__PURE__ */ jsx65("ol", { className: "fdc-cites-list", children: items.map((c, i) => /* @__PURE__ */ jsxs60("li", { children: [
8322
- /* @__PURE__ */ jsx65("span", { className: "fdc-cite-n fd-tabular", children: c.marker || i + 1 }),
8323
- c.url ? /* @__PURE__ */ jsx65("a", { href: c.url, target: "_blank", rel: "noopener noreferrer", onClick: onOpen ? (e) => onOpen(c, e) : void 0, children: c.title || c.url }) : /* @__PURE__ */ jsx65("span", { children: c.title || "Source" }),
8324
- c.detail ? /* @__PURE__ */ jsx65("span", { className: "fdc-cite-detail", children: c.detail }) : null
8568
+ open ? /* @__PURE__ */ jsx68("ol", { className: "fdc-cites-list", children: items.map((c, i) => /* @__PURE__ */ jsxs63("li", { children: [
8569
+ /* @__PURE__ */ jsx68("span", { className: "fdc-cite-n fd-tabular", children: c.marker || i + 1 }),
8570
+ c.url ? /* @__PURE__ */ jsx68("a", { href: c.url, target: "_blank", rel: "noopener noreferrer", onClick: onOpen ? (e) => onOpen(c, e) : void 0, children: c.title || c.url }) : /* @__PURE__ */ jsx68("span", { children: c.title || "Source" }),
8571
+ c.detail ? /* @__PURE__ */ jsx68("span", { className: "fdc-cite-detail", children: c.detail }) : null
8325
8572
  ] }, c.id || i)) }) : null
8326
8573
  ] });
8327
8574
  }
@@ -8332,29 +8579,29 @@ function clampText(text, max) {
8332
8579
  return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
8333
8580
  }
8334
8581
  function MessageBody({ message: m, ctx }) {
8335
- const [expanded, setExpanded] = React35.useState(false);
8582
+ const [expanded, setExpanded] = React37.useState(false);
8336
8583
  const isUser = m.role === "user";
8337
8584
  const raw = m.text || "";
8338
8585
  const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
8339
8586
  const body = clamped != null ? clamped : raw;
8340
8587
  const showMd = ctx.markdown && !isUser;
8341
- return /* @__PURE__ */ jsxs60("div", { className: "fdc-body", children: [
8342
- m.thinking && ctx.showThinking ? /* @__PURE__ */ jsx65(ThinkingBlock, { text: m.thinking, durationMs: m.thinkingMs, streaming: m.streaming && !m.text }) : null,
8343
- m.steps && m.steps.length && ctx.showSteps ? /* @__PURE__ */ jsx65(StepList, { steps: m.steps, defaultOpen: m.steps.some((s) => s.status === "running"), dense: true }) : null,
8344
- body ? /* @__PURE__ */ jsxs60("div", { className: "fdc-text" + (isUser ? " is-user" : ""), children: [
8345
- showMd ? /* @__PURE__ */ jsx65(Markdown, { source: body, headingOffset: 2, codeProps: { collapseAfter: 22 }, renderCitation: ctx.renderCitation }) : /* @__PURE__ */ jsx65("div", { className: "fdc-plain", children: body }),
8346
- m.streaming ? /* @__PURE__ */ jsx65("span", { className: "fdc-caret", "aria-hidden": "true" }) : null
8588
+ return /* @__PURE__ */ jsxs63("div", { className: "fdc-body", children: [
8589
+ m.thinking && ctx.showThinking ? /* @__PURE__ */ jsx68(ThinkingBlock, { text: m.thinking, durationMs: m.thinkingMs, streaming: m.streaming && !m.text }) : null,
8590
+ m.steps && m.steps.length && ctx.showSteps ? /* @__PURE__ */ jsx68(StepList, { steps: m.steps, defaultOpen: m.steps.some((s) => s.status === "running"), dense: true }) : null,
8591
+ body ? /* @__PURE__ */ jsxs63("div", { className: "fdc-text" + (isUser ? " is-user" : ""), children: [
8592
+ showMd ? /* @__PURE__ */ jsx68(Markdown, { source: body, headingOffset: 2, codeProps: { collapseAfter: 22 }, renderCitation: ctx.renderCitation }) : /* @__PURE__ */ jsx68("div", { className: "fdc-plain", children: body }),
8593
+ m.streaming ? /* @__PURE__ */ jsx68("span", { className: "fdc-caret", "aria-hidden": "true" }) : null
8347
8594
  ] }) : null,
8348
- clamped != null ? /* @__PURE__ */ jsxs60("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(true), children: [
8349
- /* @__PURE__ */ jsx65("i", { className: "ph ph-caret-down", "aria-hidden": "true" }),
8595
+ clamped != null ? /* @__PURE__ */ jsxs63("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(true), children: [
8596
+ /* @__PURE__ */ jsx68("i", { className: "ph ph-caret-down", "aria-hidden": "true" }),
8350
8597
  "Show more",
8351
- /* @__PURE__ */ jsx65("span", { className: "fdc-more-len fd-tabular", children: raw.length < 2e3 ? raw.length.toLocaleString() + " characters" : Math.round(raw.length / 100) / 10 + "k characters" })
8352
- ] }) : expanded && ctx.maxVisibleChars && raw.length > ctx.maxVisibleChars ? /* @__PURE__ */ jsxs60("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(false), children: [
8353
- /* @__PURE__ */ jsx65("i", { className: "ph ph-caret-up", "aria-hidden": "true" }),
8598
+ /* @__PURE__ */ jsx68("span", { className: "fdc-more-len fd-tabular", children: raw.length < 2e3 ? raw.length.toLocaleString() + " characters" : Math.round(raw.length / 100) / 10 + "k characters" })
8599
+ ] }) : expanded && ctx.maxVisibleChars && raw.length > ctx.maxVisibleChars ? /* @__PURE__ */ jsxs63("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(false), children: [
8600
+ /* @__PURE__ */ jsx68("i", { className: "ph ph-caret-up", "aria-hidden": "true" }),
8354
8601
  "Show less"
8355
8602
  ] }) : null,
8356
- m.attachments && m.attachments.length ? /* @__PURE__ */ jsx65(FileGrid, { files: m.attachments, onOpen: ctx.onOpenAttachment, tiles: true, maxHeight: ctx.attachmentHeight || 220, compact: ctx.narrow }) : null,
8357
- m.packet ? /* @__PURE__ */ jsx65(
8603
+ m.attachments && m.attachments.length ? /* @__PURE__ */ jsx68(FileGrid, { files: m.attachments, onOpen: ctx.onOpenAttachment, tiles: true, maxHeight: ctx.attachmentHeight || 220, compact: ctx.narrow }) : null,
8604
+ m.packet ? /* @__PURE__ */ jsx68(
8358
8605
  PacketCard,
8359
8606
  {
8360
8607
  packet: m.packet,
@@ -8364,44 +8611,44 @@ function MessageBody({ message: m, ctx }) {
8364
8611
  applied: ctx.appliedPackets && ctx.appliedPackets[m.id]
8365
8612
  }
8366
8613
  ) : null,
8367
- m.citations && m.citations.length ? /* @__PURE__ */ jsx65(Citations, { items: m.citations, onOpen: ctx.onOpenCitation }) : null,
8368
- m.working ? /* @__PURE__ */ jsxs60("div", { className: "fdc-working", role: "status", children: [
8369
- /* @__PURE__ */ jsxs60("span", { className: "fdc-dots", "aria-hidden": "true", children: [
8370
- /* @__PURE__ */ jsx65("span", {}),
8371
- /* @__PURE__ */ jsx65("span", {}),
8372
- /* @__PURE__ */ jsx65("span", {})
8614
+ m.citations && m.citations.length ? /* @__PURE__ */ jsx68(Citations, { items: m.citations, onOpen: ctx.onOpenCitation }) : null,
8615
+ m.working ? /* @__PURE__ */ jsxs63("div", { className: "fdc-working", role: "status", children: [
8616
+ /* @__PURE__ */ jsxs63("span", { className: "fdc-dots", "aria-hidden": "true", children: [
8617
+ /* @__PURE__ */ jsx68("span", {}),
8618
+ /* @__PURE__ */ jsx68("span", {}),
8619
+ /* @__PURE__ */ jsx68("span", {})
8373
8620
  ] }),
8374
- /* @__PURE__ */ jsxs60("span", { className: "fdc-working-label", children: [
8621
+ /* @__PURE__ */ jsxs63("span", { className: "fdc-working-label", children: [
8375
8622
  m.resumed ? "Resuming" : "Working",
8376
- m.job && m.job.status ? /* @__PURE__ */ jsxs60("span", { className: "fdc-working-job", children: [
8623
+ m.job && m.job.status ? /* @__PURE__ */ jsxs63("span", { className: "fdc-working-job", children: [
8377
8624
  " \xB7 ",
8378
8625
  m.job.status
8379
8626
  ] }) : null,
8380
- m.job && m.job.detail ? /* @__PURE__ */ jsxs60("span", { className: "fdc-working-job", children: [
8627
+ m.job && m.job.detail ? /* @__PURE__ */ jsxs63("span", { className: "fdc-working-job", children: [
8381
8628
  " \xB7 ",
8382
8629
  m.job.detail
8383
8630
  ] }) : null
8384
8631
  ] }),
8385
- m.jobId ? /* @__PURE__ */ jsx65("span", { className: "fdc-working-id fd-mono", children: String(m.jobId).slice(0, 12) }) : null
8632
+ m.jobId ? /* @__PURE__ */ jsx68("span", { className: "fdc-working-id fd-mono", children: String(m.jobId).slice(0, 12) }) : null
8386
8633
  ] }) : null,
8387
- m.stopped ? /* @__PURE__ */ jsxs60("div", { className: "fdc-stopped", children: [
8388
- /* @__PURE__ */ jsx65("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
8634
+ m.stopped ? /* @__PURE__ */ jsxs63("div", { className: "fdc-stopped", children: [
8635
+ /* @__PURE__ */ jsx68("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
8389
8636
  "Stopped"
8390
8637
  ] }) : null,
8391
- m.error ? /* @__PURE__ */ jsxs60("div", { className: "fdc-error", role: "alert", children: [
8392
- /* @__PURE__ */ jsx65("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
8393
- /* @__PURE__ */ jsx65("span", { className: "fdc-error-text", children: ctx.errorCopy ? ctx.errorCopy(m.error) : m.error }),
8394
- m.retryable && ctx.onRetry ? /* @__PURE__ */ jsxs60("button", { type: "button", className: "fdc-error-retry", onClick: ctx.onRetry, children: [
8395
- /* @__PURE__ */ jsx65("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
8638
+ m.error ? /* @__PURE__ */ jsxs63("div", { className: "fdc-error", role: "alert", children: [
8639
+ /* @__PURE__ */ jsx68("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
8640
+ /* @__PURE__ */ jsx68("span", { className: "fdc-error-text", children: ctx.errorCopy ? ctx.errorCopy(m.error) : m.error }),
8641
+ m.retryable && ctx.onRetry ? /* @__PURE__ */ jsxs63("button", { type: "button", className: "fdc-error-retry", onClick: ctx.onRetry, children: [
8642
+ /* @__PURE__ */ jsx68("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
8396
8643
  "Retry"
8397
8644
  ] }) : null
8398
8645
  ] }) : null
8399
8646
  ] });
8400
8647
  }
8401
8648
  function useCopyRun() {
8402
- const [done, setDone] = React35.useState(false);
8403
- const t = React35.useRef(null);
8404
- React35.useEffect(() => () => {
8649
+ const [done, setDone] = React37.useState(false);
8650
+ const t = React37.useRef(null);
8651
+ React37.useEffect(() => () => {
8405
8652
  if (t.current) clearTimeout(t.current);
8406
8653
  }, []);
8407
8654
  return [done, (text) => {
@@ -8421,16 +8668,16 @@ function RunActions({ group, ctx }) {
8421
8668
  const isAssistant = group.role === "assistant";
8422
8669
  const fb = last.feedback;
8423
8670
  if (!ctx.messageActions) return null;
8424
- return /* @__PURE__ */ jsxs60("div", { className: "fdc-actions", role: "group", "aria-label": "Message actions", children: [
8425
- /* @__PURE__ */ jsxs60("button", { type: "button", className: "fdc-act" + (copied ? " is-done" : ""), onClick: () => copy(markdownToText(text)), "aria-label": "Copy message", children: [
8426
- /* @__PURE__ */ jsx65("i", { className: "ph ph-" + (copied ? "check" : "copy"), "aria-hidden": "true" }),
8427
- /* @__PURE__ */ jsx65("span", { className: "fdc-act-label", children: copied ? "Copied" : "Copy" })
8671
+ return /* @__PURE__ */ jsxs63("div", { className: "fdc-actions", role: "group", "aria-label": "Message actions", children: [
8672
+ /* @__PURE__ */ jsxs63("button", { type: "button", className: "fdc-act" + (copied ? " is-done" : ""), onClick: () => copy(markdownToText(text)), "aria-label": "Copy message", children: [
8673
+ /* @__PURE__ */ jsx68("i", { className: "ph ph-" + (copied ? "check" : "copy"), "aria-hidden": "true" }),
8674
+ /* @__PURE__ */ jsx68("span", { className: "fdc-act-label", children: copied ? "Copied" : "Copy" })
8428
8675
  ] }),
8429
- isAssistant && ctx.onRetry ? /* @__PURE__ */ jsx65("button", { type: "button", className: "fdc-act", onClick: ctx.onRetry, "aria-label": "Retry this turn", children: /* @__PURE__ */ jsx65("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
8430
- group.role === "user" && ctx.onEdit ? /* @__PURE__ */ jsx65("button", { type: "button", className: "fdc-act", onClick: () => ctx.onEdit(last), "aria-label": "Edit and resend", children: /* @__PURE__ */ jsx65("i", { className: "ph ph-pencil-simple", "aria-hidden": "true" }) }) : null,
8431
- isAssistant && ctx.onFeedback ? /* @__PURE__ */ jsxs60(React35.Fragment, { children: [
8432
- /* @__PURE__ */ jsx65("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__ */ jsx65("i", { className: "ph ph-thumbs-up", "aria-hidden": "true" }) }),
8433
- /* @__PURE__ */ jsx65("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__ */ jsx65("i", { className: "ph ph-thumbs-down", "aria-hidden": "true" }) })
8676
+ isAssistant && ctx.onRetry ? /* @__PURE__ */ jsx68("button", { type: "button", className: "fdc-act", onClick: ctx.onRetry, "aria-label": "Retry this turn", children: /* @__PURE__ */ jsx68("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
8677
+ group.role === "user" && ctx.onEdit ? /* @__PURE__ */ jsx68("button", { type: "button", className: "fdc-act", onClick: () => ctx.onEdit(last), "aria-label": "Edit and resend", children: /* @__PURE__ */ jsx68("i", { className: "ph ph-pencil-simple", "aria-hidden": "true" }) }) : null,
8678
+ isAssistant && ctx.onFeedback ? /* @__PURE__ */ jsxs63(React37.Fragment, { children: [
8679
+ /* @__PURE__ */ jsx68("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__ */ jsx68("i", { className: "ph ph-thumbs-up", "aria-hidden": "true" }) }),
8680
+ /* @__PURE__ */ jsx68("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__ */ jsx68("i", { className: "ph ph-thumbs-down", "aria-hidden": "true" }) })
8434
8681
  ] }) : null,
8435
8682
  ctx.extraActions ? ctx.extraActions(group) : null
8436
8683
  ] });
@@ -8440,22 +8687,22 @@ function ChatTurn({ group, ctx }) {
8440
8687
  const name = isUser ? ctx.userName : group.author || ctx.assistantName;
8441
8688
  const avatar = isUser ? ctx.userAvatar : ctx.assistantAvatar;
8442
8689
  const stamp = group.messages[0].timestamp;
8443
- return /* @__PURE__ */ jsxs60("article", { className: "fdc-turn is-" + group.role, "aria-label": String(name) + (stamp ? " at " + formatClock(stamp) : ""), children: [
8444
- /* @__PURE__ */ jsxs60("div", { className: "fdc-turn-head", children: [
8445
- ctx.showAvatars ? /* @__PURE__ */ jsx65("span", { className: "fdc-avatar is-" + group.role, "aria-hidden": "true", children: avatar ? /* @__PURE__ */ jsx65("img", { src: avatar, alt: "" }) : isUser ? /* @__PURE__ */ jsx65("span", { className: "fdc-avatar-txt", children: (name || "You").slice(0, 1).toUpperCase() }) : /* @__PURE__ */ jsx65("i", { className: "ph ph-" + (ctx.assistantIcon || "sparkle") }) }) : null,
8446
- /* @__PURE__ */ jsx65("span", { className: "fdc-who", children: name }),
8447
- stamp ? /* @__PURE__ */ jsx65(RelativeTime, { className: "fdc-when", value: stamp }) : null,
8448
- group.messages.some((m) => m.model) ? /* @__PURE__ */ jsx65("span", { className: "fdc-turn-model", children: group.messages.find((m) => m.model).model }) : null
8690
+ return /* @__PURE__ */ jsxs63("article", { className: "fdc-turn is-" + group.role, "aria-label": String(name) + (stamp ? " at " + formatClock(stamp) : ""), children: [
8691
+ /* @__PURE__ */ jsxs63("div", { className: "fdc-turn-head", children: [
8692
+ ctx.showAvatars ? /* @__PURE__ */ jsx68("span", { className: "fdc-avatar is-" + group.role, "aria-hidden": "true", children: avatar ? /* @__PURE__ */ jsx68("img", { src: avatar, alt: "" }) : isUser ? /* @__PURE__ */ jsx68("span", { className: "fdc-avatar-txt", children: (name || "You").slice(0, 1).toUpperCase() }) : /* @__PURE__ */ jsx68("i", { className: "ph ph-" + (ctx.assistantIcon || "sparkle") }) }) : null,
8693
+ /* @__PURE__ */ jsx68("span", { className: "fdc-who", children: name }),
8694
+ stamp ? /* @__PURE__ */ jsx68(RelativeTime, { className: "fdc-when", value: stamp }) : null,
8695
+ group.messages.some((m) => m.model) ? /* @__PURE__ */ jsx68("span", { className: "fdc-turn-model", children: group.messages.find((m) => m.model).model }) : null
8449
8696
  ] }),
8450
- /* @__PURE__ */ jsxs60("div", { className: "fdc-turn-body", children: [
8451
- group.messages.map((m) => /* @__PURE__ */ jsx65("div", { className: "fdc-msg" + (m.pending ? " is-pending" : ""), children: /* @__PURE__ */ jsx65(MessageBody, { message: m, ctx }) }, m.id)),
8452
- /* @__PURE__ */ jsx65(RunActions, { group, ctx })
8697
+ /* @__PURE__ */ jsxs63("div", { className: "fdc-turn-body", children: [
8698
+ group.messages.map((m) => /* @__PURE__ */ jsx68("div", { className: "fdc-msg" + (m.pending ? " is-pending" : ""), children: /* @__PURE__ */ jsx68(MessageBody, { message: m, ctx }) }, m.id)),
8699
+ /* @__PURE__ */ jsx68(RunActions, { group, ctx })
8453
8700
  ] })
8454
8701
  ] });
8455
8702
  }
8456
8703
 
8457
8704
  // src/components/chat/ChatTranscript.tsx
8458
- import { jsx as jsx66, jsxs as jsxs61 } from "react/jsx-runtime";
8705
+ import { jsx as jsx69, jsxs as jsxs64 } from "react/jsx-runtime";
8459
8706
  var GROUP_WINDOW = 6e4;
8460
8707
  var STICK_PX = 100;
8461
8708
  function groupMessages(list) {
@@ -8488,25 +8735,25 @@ function dayLabel(key) {
8488
8735
  }
8489
8736
  function Suggestions({ items = [], onPick }) {
8490
8737
  if (!items.length) return null;
8491
- return /* @__PURE__ */ jsx66("div", { className: "fdc-suggest", children: items.map((s, i) => {
8738
+ return /* @__PURE__ */ jsx69("div", { className: "fdc-suggest", children: items.map((s, i) => {
8492
8739
  const it = typeof s === "string" ? { label: s, text: s } : s;
8493
- return /* @__PURE__ */ jsxs61("button", { type: "button", className: "fdc-suggest-item", onClick: () => onPick && onPick(it.text || it.label), children: [
8494
- it.icon ? /* @__PURE__ */ jsx66("i", { className: "ph ph-" + it.icon, "aria-hidden": "true" }) : null,
8495
- /* @__PURE__ */ jsxs61("span", { className: "fdc-suggest-text", children: [
8496
- /* @__PURE__ */ jsx66("span", { className: "fdc-suggest-label", children: it.label }),
8497
- it.description ? /* @__PURE__ */ jsx66("span", { className: "fdc-suggest-desc", children: it.description }) : null
8740
+ return /* @__PURE__ */ jsxs64("button", { type: "button", className: "fdc-suggest-item", onClick: () => onPick && onPick(it.text || it.label), children: [
8741
+ it.icon ? /* @__PURE__ */ jsx69("i", { className: "ph ph-" + it.icon, "aria-hidden": "true" }) : null,
8742
+ /* @__PURE__ */ jsxs64("span", { className: "fdc-suggest-text", children: [
8743
+ /* @__PURE__ */ jsx69("span", { className: "fdc-suggest-label", children: it.label }),
8744
+ it.description ? /* @__PURE__ */ jsx69("span", { className: "fdc-suggest-desc", children: it.description }) : null
8498
8745
  ] }),
8499
- /* @__PURE__ */ jsx66("i", { className: "ph ph-arrow-up-right fdc-suggest-go", "aria-hidden": "true" })
8746
+ /* @__PURE__ */ jsx69("i", { className: "ph ph-arrow-up-right fdc-suggest-go", "aria-hidden": "true" })
8500
8747
  ] }, it.id || i);
8501
8748
  }) });
8502
8749
  }
8503
8750
  function LoadingTurns() {
8504
- return /* @__PURE__ */ jsx66("div", { className: "fdc-skel", "aria-hidden": "true", children: [0, 1].map((i) => /* @__PURE__ */ jsxs61("div", { className: "fdc-skel-turn", children: [
8505
- /* @__PURE__ */ jsx66("div", { className: "fd-skel fd-skel-circle", style: { width: 22, height: 22 } }),
8506
- /* @__PURE__ */ jsxs61("div", { className: "fdc-skel-lines", children: [
8507
- /* @__PURE__ */ jsx66("div", { className: "fd-skel", style: { width: i ? "62%" : "44%", height: 11 } }),
8508
- /* @__PURE__ */ jsx66("div", { className: "fd-skel", style: { width: i ? "94%" : "78%", height: 11 } }),
8509
- /* @__PURE__ */ jsx66("div", { className: "fd-skel", style: { width: i ? "71%" : "56%", height: 11 } })
8751
+ return /* @__PURE__ */ jsx69("div", { className: "fdc-skel", "aria-hidden": "true", children: [0, 1].map((i) => /* @__PURE__ */ jsxs64("div", { className: "fdc-skel-turn", children: [
8752
+ /* @__PURE__ */ jsx69("div", { className: "fd-skel fd-skel-circle", style: { width: 22, height: 22 } }),
8753
+ /* @__PURE__ */ jsxs64("div", { className: "fdc-skel-lines", children: [
8754
+ /* @__PURE__ */ jsx69("div", { className: "fd-skel", style: { width: i ? "62%" : "44%", height: 11 } }),
8755
+ /* @__PURE__ */ jsx69("div", { className: "fd-skel", style: { width: i ? "94%" : "78%", height: 11 } }),
8756
+ /* @__PURE__ */ jsx69("div", { className: "fd-skel", style: { width: i ? "71%" : "56%", height: 11 } })
8510
8757
  ] })
8511
8758
  ] }, i)) });
8512
8759
  }
@@ -8523,10 +8770,10 @@ function ChatTranscript({
8523
8770
  renderEmpty,
8524
8771
  className = ""
8525
8772
  }) {
8526
- const scroller = React36.useRef(null);
8527
- const stick = React36.useRef(true);
8528
- const [pill, setPill] = React36.useState(0);
8529
- const seen = React36.useRef(0);
8773
+ const scroller = React38.useRef(null);
8774
+ const stick = React38.useRef(true);
8775
+ const [pill, setPill] = React38.useState(0);
8776
+ const seen = React38.useRef(0);
8530
8777
  const toBottom = (smooth) => {
8531
8778
  const el = scroller.current;
8532
8779
  if (!el) return;
@@ -8545,7 +8792,7 @@ function ChatTranscript({
8545
8792
  seen.current = messages.length;
8546
8793
  }
8547
8794
  };
8548
- React36.useLayoutEffect(() => {
8795
+ React38.useLayoutEffect(() => {
8549
8796
  const el = scroller.current;
8550
8797
  if (!el) return;
8551
8798
  if (stick.current) {
@@ -8553,7 +8800,7 @@ function ChatTranscript({
8553
8800
  seen.current = messages.length;
8554
8801
  } else setPill(Math.max(0, messages.length - seen.current));
8555
8802
  }, [messages]);
8556
- React36.useEffect(() => {
8803
+ React38.useEffect(() => {
8557
8804
  const el = scroller.current;
8558
8805
  const inner = el && el.firstChild;
8559
8806
  if (!el || !inner || typeof ResizeObserver === "undefined") return;
@@ -8563,38 +8810,38 @@ function ChatTranscript({
8563
8810
  ro.observe(inner);
8564
8811
  return () => ro.disconnect();
8565
8812
  }, []);
8566
- const groups = React36.useMemo(() => groupMessages(messages), [messages]);
8813
+ const groups = React38.useMemo(() => groupMessages(messages), [messages]);
8567
8814
  const empty = !messages.length && status === "ready";
8568
- return /* @__PURE__ */ jsxs61("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
8569
- /* @__PURE__ */ jsxs61("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
8570
- status === "loading" || status === "resolving" ? /* @__PURE__ */ jsx66(LoadingTurns, {}) : null,
8571
- status === "disconnected" ? /* @__PURE__ */ jsxs61("div", { className: "fdc-dead", children: [
8572
- /* @__PURE__ */ jsx66("span", { className: "fdc-dead-icon", children: /* @__PURE__ */ jsx66("i", { className: "ph ph-plugs", "aria-hidden": "true" }) }),
8573
- /* @__PURE__ */ jsx66("h3", { className: "fdc-dead-title", children: ctx.deadTitle || "The assistant isn\u2019t reachable" }),
8574
- /* @__PURE__ */ jsx66("p", { className: "fdc-dead-body", children: fatal === "chat_unavailable" ? "The service reported chat_unavailable. Nothing you type will be lost \u2014 reopen the panel once it\u2019s back." : "The thread couldn\u2019t be resolved" + (fatal ? " (" + fatal + ")" : "") + ". The composer stays disabled until it resolves." }),
8575
- ctx.onReconnect ? /* @__PURE__ */ jsxs61("button", { type: "button", className: "fd-btn fd-btn-secondary fd-btn-sm", onClick: ctx.onReconnect, children: [
8576
- /* @__PURE__ */ jsx66("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
8815
+ return /* @__PURE__ */ jsxs64("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
8816
+ /* @__PURE__ */ jsxs64("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
8817
+ status === "loading" || status === "resolving" ? /* @__PURE__ */ jsx69(LoadingTurns, {}) : null,
8818
+ status === "disconnected" ? /* @__PURE__ */ jsxs64("div", { className: "fdc-dead", children: [
8819
+ /* @__PURE__ */ jsx69("span", { className: "fdc-dead-icon", children: /* @__PURE__ */ jsx69("i", { className: "ph ph-plugs", "aria-hidden": "true" }) }),
8820
+ /* @__PURE__ */ jsx69("h3", { className: "fdc-dead-title", children: ctx.deadTitle || "The assistant isn\u2019t reachable" }),
8821
+ /* @__PURE__ */ jsx69("p", { className: "fdc-dead-body", children: fatal === "chat_unavailable" ? "The service reported chat_unavailable. Nothing you type will be lost \u2014 reopen the panel once it\u2019s back." : "The thread couldn\u2019t be resolved" + (fatal ? " (" + fatal + ")" : "") + ". The composer stays disabled until it resolves." }),
8822
+ ctx.onReconnect ? /* @__PURE__ */ jsxs64("button", { type: "button", className: "fd-btn fd-btn-secondary fd-btn-sm", onClick: ctx.onReconnect, children: [
8823
+ /* @__PURE__ */ jsx69("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
8577
8824
  "Try again"
8578
8825
  ] }) : null
8579
8826
  ] }) : null,
8580
- empty ? renderEmpty ? renderEmpty() : /* @__PURE__ */ jsxs61("div", { className: "fdc-empty", children: [
8581
- /* @__PURE__ */ jsx66("span", { className: "fdc-empty-icon", children: /* @__PURE__ */ jsx66("i", { className: "ph ph-" + emptyIcon, "aria-hidden": "true" }) }),
8582
- /* @__PURE__ */ jsx66("h3", { className: "fdc-empty-title", children: emptyTitle }),
8583
- emptyDescription ? /* @__PURE__ */ jsx66("p", { className: "fdc-empty-body", children: emptyDescription }) : null,
8584
- /* @__PURE__ */ jsx66(Suggestions, { items: suggestions, onPick })
8827
+ empty ? renderEmpty ? renderEmpty() : /* @__PURE__ */ jsxs64("div", { className: "fdc-empty", children: [
8828
+ /* @__PURE__ */ jsx69("span", { className: "fdc-empty-icon", children: /* @__PURE__ */ jsx69("i", { className: "ph ph-" + emptyIcon, "aria-hidden": "true" }) }),
8829
+ /* @__PURE__ */ jsx69("h3", { className: "fdc-empty-title", children: emptyTitle }),
8830
+ emptyDescription ? /* @__PURE__ */ jsx69("p", { className: "fdc-empty-body", children: emptyDescription }) : null,
8831
+ /* @__PURE__ */ jsx69(Suggestions, { items: suggestions, onPick })
8585
8832
  ] }) : null,
8586
8833
  groups.map((g, i) => {
8587
8834
  const prev = groups[i - 1];
8588
8835
  const k = dayKey(g.messages[0].timestamp);
8589
8836
  const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
8590
- return /* @__PURE__ */ jsxs61(React36.Fragment, { children: [
8591
- showDay ? /* @__PURE__ */ jsx66("div", { className: "fdc-day", children: /* @__PURE__ */ jsx66("span", { children: dayLabel(k) }) }) : null,
8592
- /* @__PURE__ */ jsx66(ChatTurn, { group: g, ctx })
8837
+ return /* @__PURE__ */ jsxs64(React38.Fragment, { children: [
8838
+ showDay ? /* @__PURE__ */ jsx69("div", { className: "fdc-day", children: /* @__PURE__ */ jsx69("span", { children: dayLabel(k) }) }) : null,
8839
+ /* @__PURE__ */ jsx69(ChatTurn, { group: g, ctx })
8593
8840
  ] }, g.key || i);
8594
8841
  })
8595
8842
  ] }),
8596
- pill ? /* @__PURE__ */ jsxs61("button", { type: "button", className: "fdc-pill", onClick: () => toBottom(true), children: [
8597
- /* @__PURE__ */ jsx66("i", { className: "ph ph-arrow-down", "aria-hidden": "true" }),
8843
+ pill ? /* @__PURE__ */ jsxs64("button", { type: "button", className: "fdc-pill", onClick: () => toBottom(true), children: [
8844
+ /* @__PURE__ */ jsx69("i", { className: "ph ph-arrow-down", "aria-hidden": "true" }),
8598
8845
  pill,
8599
8846
  " new message",
8600
8847
  pill === 1 ? "" : "s"
@@ -8604,8 +8851,8 @@ function ChatTranscript({
8604
8851
  var TranscriptKit = { groupMessages };
8605
8852
 
8606
8853
  // src/components/chat/ChatComposer.tsx
8607
- import * as React37 from "react";
8608
- import { jsx as jsx67, jsxs as jsxs62 } from "react/jsx-runtime";
8854
+ import * as React39 from "react";
8855
+ import { jsx as jsx70, jsxs as jsxs65 } from "react/jsx-runtime";
8609
8856
  function ChatComposer({
8610
8857
  onSubmit,
8611
8858
  onStop,
@@ -8632,17 +8879,17 @@ function ChatComposer({
8632
8879
  onReject,
8633
8880
  onOpenAttachment
8634
8881
  }) {
8635
- const [text, setText] = React37.useState(draft || "");
8636
- const [trigger, setTrigger] = React37.useState(null);
8637
- const [mentionItems, setMentionItems] = React37.useState([]);
8638
- const [listening, setListening] = React37.useState(false);
8639
- const [notice, setNotice] = React37.useState(null);
8640
- const editor = React37.useRef(null);
8641
- const wrap = React37.useRef(null);
8642
- const stopVoice = React37.useRef(null);
8882
+ const [text, setText] = React39.useState(draft || "");
8883
+ const [trigger, setTrigger] = React39.useState(null);
8884
+ const [mentionItems, setMentionItems] = React39.useState([]);
8885
+ const [listening, setListening] = React39.useState(false);
8886
+ const [notice, setNotice] = React39.useState(null);
8887
+ const editor = React39.useRef(null);
8888
+ const wrap = React39.useRef(null);
8889
+ const stopVoice = React39.useRef(null);
8643
8890
  const staged = useStagedFiles(fileUploadHandler, { onError: () => {
8644
8891
  } });
8645
- React37.useEffect(() => {
8892
+ React39.useEffect(() => {
8646
8893
  if (draft != null && draft !== text) setText(draft);
8647
8894
  }, [draft]);
8648
8895
  const change = (v) => {
@@ -8676,7 +8923,7 @@ function ChatComposer({
8676
8923
  e.preventDefault();
8677
8924
  staged.add(found.files);
8678
8925
  };
8679
- React37.useEffect(() => {
8926
+ React39.useEffect(() => {
8680
8927
  if (!trigger || trigger.type !== "mention" || !mentionSources) {
8681
8928
  setMentionItems([]);
8682
8929
  return;
@@ -8694,7 +8941,7 @@ function ChatComposer({
8694
8941
  const q = (trigger.query || "").toLowerCase();
8695
8942
  setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
8696
8943
  }, [trigger, mentionSources]);
8697
- const slashItems = React37.useMemo(() => {
8944
+ const slashItems = React39.useMemo(() => {
8698
8945
  if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
8699
8946
  const q = (trigger.query || "").toLowerCase();
8700
8947
  return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
@@ -8708,7 +8955,7 @@ function ChatComposer({
8708
8955
  description: it.description,
8709
8956
  icon: it.icon,
8710
8957
  meta: mention.meta,
8711
- shortcut: slash.shortcut ? /* @__PURE__ */ jsx67(KeyHint, { keys: slash.shortcut, size: "sm" }) : void 0,
8958
+ shortcut: slash.shortcut ? /* @__PURE__ */ jsx70(KeyHint, { keys: slash.shortcut, size: "sm" }) : void 0,
8712
8959
  onSelect: () => {
8713
8960
  const insert = trigger.type === "slash" ? slash.immediate ? "/" + slash.id : "/" + slash.id + " " : "@" + (mention.value || mention.label) + " ";
8714
8961
  editor.current && editor.current.replaceRange(trigger.from, trigger.to, insert);
@@ -8771,14 +9018,14 @@ function ChatComposer({
8771
9018
  stopVoice.current = typeof res === "function" ? res : () => {
8772
9019
  };
8773
9020
  };
8774
- return /* @__PURE__ */ jsxs62("div", { className: "fdc-composer" + (disabled ? " is-disabled" : "") + (narrow ? " is-narrow" : ""), children: [
8775
- queue.length ? /* @__PURE__ */ jsx67("div", { className: "fdc-queue", "aria-label": "Queued messages", children: queue.map((q) => /* @__PURE__ */ jsxs62("div", { className: "fdc-queue-row", children: [
8776
- /* @__PURE__ */ jsx67("i", { className: "ph ph-clock-countdown", "aria-hidden": "true" }),
8777
- /* @__PURE__ */ jsx67("span", { className: "fdc-queue-text", children: q.text || (q.attachments ? q.attachments.length + " file(s)" : "") }),
8778
- onRemoveQueued ? /* @__PURE__ */ jsx67("button", { type: "button", className: "fdc-queue-x", onClick: () => onRemoveQueued(q.id), "aria-label": "Remove queued message", children: /* @__PURE__ */ jsx67("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
9021
+ return /* @__PURE__ */ jsxs65("div", { className: "fdc-composer" + (disabled ? " is-disabled" : "") + (narrow ? " is-narrow" : ""), children: [
9022
+ queue.length ? /* @__PURE__ */ jsx70("div", { className: "fdc-queue", "aria-label": "Queued messages", children: queue.map((q) => /* @__PURE__ */ jsxs65("div", { className: "fdc-queue-row", children: [
9023
+ /* @__PURE__ */ jsx70("i", { className: "ph ph-clock-countdown", "aria-hidden": "true" }),
9024
+ /* @__PURE__ */ jsx70("span", { className: "fdc-queue-text", children: q.text || (q.attachments ? q.attachments.length + " file(s)" : "") }),
9025
+ onRemoveQueued ? /* @__PURE__ */ jsx70("button", { type: "button", className: "fdc-queue-x", onClick: () => onRemoveQueued(q.id), "aria-label": "Remove queued message", children: /* @__PURE__ */ jsx70("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
8779
9026
  ] }, q.id)) }) : null,
8780
9027
  sessionBar,
8781
- /* @__PURE__ */ jsx67(
9028
+ /* @__PURE__ */ jsx70(
8782
9029
  Dropzone,
8783
9030
  {
8784
9031
  className: "fdc-field",
@@ -8792,9 +9039,9 @@ function ChatComposer({
8792
9039
  disabled: !fileUploadHandler || disabled,
8793
9040
  label: "Drop to attach",
8794
9041
  hint: acceptFiles ? acceptFiles.replace(/,/g, " \xB7 ") : void 0,
8795
- children: /* @__PURE__ */ jsxs62("div", { ref: wrap, className: "fdc-field-inner", children: [
8796
- staged.items.length ? /* @__PURE__ */ jsx67("div", { className: "fdc-staged", children: /* @__PURE__ */ jsx67(FileStrip, { files: staged.items, size: narrow ? 60 : 68, onRemove: staged.remove, onRetry: staged.retry, onOpen: onOpenAttachment }) }) : null,
8797
- /* @__PURE__ */ jsx67(
9042
+ children: /* @__PURE__ */ jsxs65("div", { ref: wrap, className: "fdc-field-inner", children: [
9043
+ staged.items.length ? /* @__PURE__ */ jsx70("div", { className: "fdc-staged", children: /* @__PURE__ */ jsx70(FileStrip, { files: staged.items, size: narrow ? 60 : 68, onRemove: staged.remove, onRetry: staged.retry, onOpen: onOpenAttachment }) }) : null,
9044
+ /* @__PURE__ */ jsx70(
8798
9045
  MarkdownEditor,
8799
9046
  {
8800
9047
  ref: editor,
@@ -8813,33 +9060,33 @@ function ChatComposer({
8813
9060
  ariaLabel: "Message"
8814
9061
  }
8815
9062
  ),
8816
- /* @__PURE__ */ jsxs62("div", { className: "fdc-tools", children: [
8817
- fileUploadHandler ? /* @__PURE__ */ jsx67(FilePickButton, { onFiles: staged.add, onReject: (r) => flash(r[0].message), accept: acceptFiles, maxFileSize, label: "Attach files", icon: "plus" }) : null,
8818
- voiceHandler ? /* @__PURE__ */ jsx67("button", { type: "button", className: "fd-attachbtn" + (listening ? " is-live" : ""), onClick: voice, "aria-pressed": listening, "aria-label": listening ? "Stop dictation" : "Dictate", children: /* @__PURE__ */ jsx67("i", { className: "ph ph-" + (listening ? "waveform" : "microphone"), "aria-hidden": "true" }) }) : null,
9063
+ /* @__PURE__ */ jsxs65("div", { className: "fdc-tools", children: [
9064
+ fileUploadHandler ? /* @__PURE__ */ jsx70(FilePickButton, { onFiles: staged.add, onReject: (r) => flash(r[0].message), accept: acceptFiles, maxFileSize, label: "Attach files", icon: "plus" }) : null,
9065
+ voiceHandler ? /* @__PURE__ */ jsx70("button", { type: "button", className: "fd-attachbtn" + (listening ? " is-live" : ""), onClick: voice, "aria-pressed": listening, "aria-label": listening ? "Stop dictation" : "Dictate", children: /* @__PURE__ */ jsx70("i", { className: "ph ph-" + (listening ? "waveform" : "microphone"), "aria-hidden": "true" }) }) : null,
8819
9066
  toolbarExtras,
8820
- /* @__PURE__ */ jsx67("span", { className: "fdc-tools-gap" }),
8821
- maxLength && text.length > maxLength * 0.6 ? /* @__PURE__ */ jsxs62("span", { className: "fdc-count fd-tabular" + (text.length > maxLength * 0.95 ? " is-hot" : ""), children: [
9067
+ /* @__PURE__ */ jsx70("span", { className: "fdc-tools-gap" }),
9068
+ maxLength && text.length > maxLength * 0.6 ? /* @__PURE__ */ jsxs65("span", { className: "fdc-count fd-tabular" + (text.length > maxLength * 0.95 ? " is-hot" : ""), children: [
8822
9069
  text.length,
8823
9070
  "/",
8824
9071
  maxLength
8825
9072
  ] }) : null,
8826
- busy ? /* @__PURE__ */ jsxs62("button", { type: "button", className: "fdc-stop", onClick: onStop, "aria-label": "Stop generating", children: [
8827
- /* @__PURE__ */ jsx67("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
8828
- /* @__PURE__ */ jsx67("span", { children: "Stop" })
8829
- ] }) : /* @__PURE__ */ jsxs62("button", { type: "button", className: "fdc-send", onClick: submit, disabled: !canSend, "aria-label": "Send message", children: [
8830
- /* @__PURE__ */ jsx67("i", { className: "ph ph-paper-plane-right", "aria-hidden": "true" }),
8831
- /* @__PURE__ */ jsx67("span", { className: "fdc-send-label", children: "Send" })
9073
+ busy ? /* @__PURE__ */ jsxs65("button", { type: "button", className: "fdc-stop", onClick: onStop, "aria-label": "Stop generating", children: [
9074
+ /* @__PURE__ */ jsx70("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
9075
+ /* @__PURE__ */ jsx70("span", { children: "Stop" })
9076
+ ] }) : /* @__PURE__ */ jsxs65("button", { type: "button", className: "fdc-send", onClick: submit, disabled: !canSend, "aria-label": "Send message", children: [
9077
+ /* @__PURE__ */ jsx70("i", { className: "ph ph-paper-plane-right", "aria-hidden": "true" }),
9078
+ /* @__PURE__ */ jsx70("span", { className: "fdc-send-label", children: "Send" })
8832
9079
  ] })
8833
9080
  ] })
8834
9081
  ] })
8835
9082
  }
8836
9083
  ),
8837
- notice ? /* @__PURE__ */ jsxs62("div", { className: "fdc-notice", role: "status", children: [
8838
- /* @__PURE__ */ jsx67("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
9084
+ notice ? /* @__PURE__ */ jsxs65("div", { className: "fdc-notice", role: "status", children: [
9085
+ /* @__PURE__ */ jsx70("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
8839
9086
  notice
8840
9087
  ] }) : null,
8841
- hint && !notice ? /* @__PURE__ */ jsx67("div", { className: "fdc-hint", children: hint }) : null,
8842
- /* @__PURE__ */ jsx67(
9088
+ hint && !notice ? /* @__PURE__ */ jsx70("div", { className: "fdc-hint", children: hint }) : null,
9089
+ /* @__PURE__ */ jsx70(
8843
9090
  Popover,
8844
9091
  {
8845
9092
  open: menuOpen,
@@ -8853,12 +9100,12 @@ function ChatComposer({
8853
9100
  returnFocus: false,
8854
9101
  closeOnOutside: true,
8855
9102
  label: trigger && trigger.type === "slash" ? "Commands" : "Mentions",
8856
- children: /* @__PURE__ */ jsx67(
9103
+ children: /* @__PURE__ */ jsx70(
8857
9104
  Menu,
8858
9105
  {
8859
9106
  items: menuItems,
8860
9107
  autoFocus: false,
8861
- header: /* @__PURE__ */ jsx67("div", { className: "fd-pop-group", children: trigger && trigger.type === "slash" ? "Commands" : "Attach context" }),
9108
+ header: /* @__PURE__ */ jsx70("div", { className: "fd-pop-group", children: trigger && trigger.type === "slash" ? "Commands" : "Attach context" }),
8862
9109
  onClose: () => setTrigger(null)
8863
9110
  }
8864
9111
  )
@@ -8868,12 +9115,12 @@ function ChatComposer({
8868
9115
  }
8869
9116
 
8870
9117
  // src/components/chat/ChatSessionBar.tsx
8871
- import * as React38 from "react";
8872
- import { jsx as jsx68, jsxs as jsxs63 } from "react/jsx-runtime";
9118
+ import * as React40 from "react";
9119
+ import { jsx as jsx71, jsxs as jsxs66 } from "react/jsx-runtime";
8873
9120
  var compact2 = meterFormats.compact;
8874
9121
  function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
8875
- const [open, setOpen] = React38.useState(false);
8876
- const anchor = React38.useRef(null);
9122
+ const [open, setOpen] = React40.useState(false);
9123
+ const anchor = React40.useRef(null);
8877
9124
  const stats = sessionStats || null;
8878
9125
  const cu = contextUsage || null;
8879
9126
  const limits = usageLimits || null;
@@ -8888,9 +9135,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
8888
9135
  if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
8889
9136
  if (cu) bits.push(pct + "% context");
8890
9137
  const expandable = !!(cu || limits);
8891
- return /* @__PURE__ */ jsxs63(React38.Fragment, { children: [
8892
- /* @__PURE__ */ jsxs63("div", { className: "fdc-bar", children: [
8893
- /* @__PURE__ */ jsxs63(
9138
+ return /* @__PURE__ */ jsxs66(React40.Fragment, { children: [
9139
+ /* @__PURE__ */ jsxs66("div", { className: "fdc-bar", children: [
9140
+ /* @__PURE__ */ jsxs66(
8894
9141
  "button",
8895
9142
  {
8896
9143
  type: "button",
@@ -8901,16 +9148,16 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
8901
9148
  "aria-expanded": expandable ? open : void 0,
8902
9149
  "aria-label": expandable ? "Usage details" : void 0,
8903
9150
  children: [
8904
- cu ? /* @__PURE__ */ jsx68("span", { className: "fdc-bar-mini", "aria-hidden": "true", children: /* @__PURE__ */ jsx68(SegmentedMeter, { total, segments: cu.segments, height: 4, showTotal: false }) }) : null,
8905
- /* @__PURE__ */ jsx68("span", { className: "fdc-bar-text", children: bits.join(" \xB7 ") }),
8906
- expandable ? /* @__PURE__ */ jsx68("i", { className: "ph ph-caret-right fdc-bar-caret", "aria-hidden": "true" }) : null
9151
+ cu ? /* @__PURE__ */ jsx71("span", { className: "fdc-bar-mini", "aria-hidden": "true", children: /* @__PURE__ */ jsx71(SegmentedMeter, { total, segments: cu.segments, height: 4, showTotal: false }) }) : null,
9152
+ /* @__PURE__ */ jsx71("span", { className: "fdc-bar-text", children: bits.join(" \xB7 ") }),
9153
+ expandable ? /* @__PURE__ */ jsx71("i", { className: "ph ph-caret-right fdc-bar-caret", "aria-hidden": "true" }) : null
8907
9154
  ]
8908
9155
  }
8909
9156
  ),
8910
9157
  extras
8911
9158
  ] }),
8912
- /* @__PURE__ */ jsx68(Popover, { open, anchorRef: anchor, placement: "top-start", onClose: () => setOpen(false), minWidth: 330, maxHeight: 460, padded: true, label: "Usage", children: /* @__PURE__ */ jsxs63("div", { className: "fdc-usage", children: [
8913
- cu ? /* @__PURE__ */ jsx68("section", { className: "fdc-usage-sec", children: /* @__PURE__ */ jsx68(
9159
+ /* @__PURE__ */ jsx71(Popover, { open, anchorRef: anchor, placement: "top-start", onClose: () => setOpen(false), minWidth: 330, maxHeight: 460, padded: true, label: "Usage", children: /* @__PURE__ */ jsxs66("div", { className: "fdc-usage", children: [
9160
+ cu ? /* @__PURE__ */ jsx71("section", { className: "fdc-usage-sec", children: /* @__PURE__ */ jsx71(
8914
9161
  SegmentedMeter,
8915
9162
  {
8916
9163
  total,
@@ -8922,9 +9169,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
8922
9169
  remainderLabel: "Free"
8923
9170
  }
8924
9171
  ) }) : null,
8925
- limits && limits.length ? /* @__PURE__ */ jsxs63("section", { className: "fdc-usage-sec", children: [
8926
- /* @__PURE__ */ jsx68("h4", { className: "fdc-usage-h", children: "Usage limits" }),
8927
- /* @__PURE__ */ jsx68("div", { className: "fdc-usage-rows", children: limits.map((l) => /* @__PURE__ */ jsx68(
9172
+ limits && limits.length ? /* @__PURE__ */ jsxs66("section", { className: "fdc-usage-sec", children: [
9173
+ /* @__PURE__ */ jsx71("h4", { className: "fdc-usage-h", children: "Usage limits" }),
9174
+ /* @__PURE__ */ jsx71("div", { className: "fdc-usage-rows", children: limits.map((l) => /* @__PURE__ */ jsx71(
8928
9175
  QuotaRow,
8929
9176
  {
8930
9177
  label: l.label,
@@ -8934,32 +9181,32 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
8934
9181
  l.id
8935
9182
  )) })
8936
9183
  ] }) : null,
8937
- stats ? /* @__PURE__ */ jsxs63("section", { className: "fdc-usage-sec fdc-usage-stats", children: [
8938
- stats.elapsedMs ? /* @__PURE__ */ jsxs63("div", { children: [
8939
- /* @__PURE__ */ jsx68("span", { children: "Session" }),
8940
- /* @__PURE__ */ jsx68("b", { className: "fd-tabular", children: formatDuration(stats.elapsedMs) })
9184
+ stats ? /* @__PURE__ */ jsxs66("section", { className: "fdc-usage-sec fdc-usage-stats", children: [
9185
+ stats.elapsedMs ? /* @__PURE__ */ jsxs66("div", { children: [
9186
+ /* @__PURE__ */ jsx71("span", { children: "Session" }),
9187
+ /* @__PURE__ */ jsx71("b", { className: "fd-tabular", children: formatDuration(stats.elapsedMs) })
8941
9188
  ] }) : null,
8942
- stats.tokens ? /* @__PURE__ */ jsxs63("div", { children: [
8943
- /* @__PURE__ */ jsx68("span", { children: "Tokens" }),
8944
- /* @__PURE__ */ jsx68("b", { className: "fd-tabular", children: stats.tokens.toLocaleString() })
9189
+ stats.tokens ? /* @__PURE__ */ jsxs66("div", { children: [
9190
+ /* @__PURE__ */ jsx71("span", { children: "Tokens" }),
9191
+ /* @__PURE__ */ jsx71("b", { className: "fd-tabular", children: stats.tokens.toLocaleString() })
8945
9192
  ] }) : null,
8946
- stats.costUsd != null ? /* @__PURE__ */ jsxs63("div", { children: [
8947
- /* @__PURE__ */ jsx68("span", { children: "Cost" }),
8948
- /* @__PURE__ */ jsxs63("b", { className: "fd-tabular", children: [
9193
+ stats.costUsd != null ? /* @__PURE__ */ jsxs66("div", { children: [
9194
+ /* @__PURE__ */ jsx71("span", { children: "Cost" }),
9195
+ /* @__PURE__ */ jsxs66("b", { className: "fd-tabular", children: [
8949
9196
  "$",
8950
9197
  Number(stats.costUsd).toFixed(3)
8951
9198
  ] })
8952
9199
  ] }) : null,
8953
- stats.turns ? /* @__PURE__ */ jsxs63("div", { children: [
8954
- /* @__PURE__ */ jsx68("span", { children: "Turns" }),
8955
- /* @__PURE__ */ jsx68("b", { className: "fd-tabular", children: stats.turns })
9200
+ stats.turns ? /* @__PURE__ */ jsxs66("div", { children: [
9201
+ /* @__PURE__ */ jsx71("span", { children: "Turns" }),
9202
+ /* @__PURE__ */ jsx71("b", { className: "fd-tabular", children: stats.turns })
8956
9203
  ] }) : null
8957
9204
  ] }) : null,
8958
- onClear ? /* @__PURE__ */ jsx68("footer", { className: "fdc-usage-foot", children: /* @__PURE__ */ jsxs63("button", { type: "button", className: "fdc-usage-clear", onClick: () => {
9205
+ onClear ? /* @__PURE__ */ jsx71("footer", { className: "fdc-usage-foot", children: /* @__PURE__ */ jsxs66("button", { type: "button", className: "fdc-usage-clear", onClick: () => {
8959
9206
  setOpen(false);
8960
9207
  onClear();
8961
9208
  }, children: [
8962
- /* @__PURE__ */ jsx68("i", { className: "ph ph-trash", "aria-hidden": "true" }),
9209
+ /* @__PURE__ */ jsx71("i", { className: "ph ph-trash", "aria-hidden": "true" }),
8963
9210
  "Clear conversation"
8964
9211
  ] }) }) : null
8965
9212
  ] }) })
@@ -8996,7 +9243,7 @@ function ModelControls({
8996
9243
  disabled: m.disabled,
8997
9244
  checked: m.id === (current2 && current2.id),
8998
9245
  meta: m.meta,
8999
- shortcut: m.shortcut ? /* @__PURE__ */ jsx68(KeyHint, { keys: m.shortcut, size: "sm" }) : void 0,
9246
+ shortcut: m.shortcut ? /* @__PURE__ */ jsx71(KeyHint, { keys: m.shortcut, size: "sm" }) : void 0,
9000
9247
  onSelect: () => onModelChange && onModelChange(m.id)
9001
9248
  });
9002
9249
  const items = [{ kind: "section", label: "Models" }].concat(flat.map(item));
@@ -9009,15 +9256,15 @@ function ModelControls({
9009
9256
  items.push({ kind: "section", label: "Fast mode" });
9010
9257
  items.push({
9011
9258
  kind: "custom",
9012
- render: () => /* @__PURE__ */ jsxs63("label", { className: "fdc-switchrow", children: [
9013
- /* @__PURE__ */ jsx68("span", { children: fastModeLabel }),
9014
- /* @__PURE__ */ jsx68("input", { type: "checkbox", className: "fd-sr", checked: !!fastMode, onChange: (e) => onFastModeChange(e.target.checked) }),
9015
- /* @__PURE__ */ jsx68("span", { className: "fd-switch-track" + (fastMode ? " is-on" : ""), "aria-hidden": "true", children: /* @__PURE__ */ jsx68("span", { className: "fd-switch-thumb" }) })
9259
+ render: () => /* @__PURE__ */ jsxs66("label", { className: "fdc-switchrow", children: [
9260
+ /* @__PURE__ */ jsx71("span", { children: fastModeLabel }),
9261
+ /* @__PURE__ */ jsx71("input", { type: "checkbox", className: "fd-sr", checked: !!fastMode, onChange: (e) => onFastModeChange(e.target.checked) }),
9262
+ /* @__PURE__ */ jsx71("span", { className: "fd-switch-track" + (fastMode ? " is-on" : ""), "aria-hidden": "true", children: /* @__PURE__ */ jsx71("span", { className: "fd-switch-thumb" }) })
9016
9263
  ] })
9017
9264
  });
9018
9265
  }
9019
- return /* @__PURE__ */ jsxs63(React38.Fragment, { children: [
9020
- /* @__PURE__ */ jsx68(
9266
+ return /* @__PURE__ */ jsxs66(React40.Fragment, { children: [
9267
+ /* @__PURE__ */ jsx71(
9021
9268
  MenuButton,
9022
9269
  {
9023
9270
  items,
@@ -9028,7 +9275,7 @@ function ModelControls({
9028
9275
  title: "Choose a model"
9029
9276
  }
9030
9277
  ),
9031
- effortLevels && effortLevels.length ? /* @__PURE__ */ jsx68(
9278
+ effortLevels && effortLevels.length ? /* @__PURE__ */ jsx71(
9032
9279
  MenuButton,
9033
9280
  {
9034
9281
  placement: "top-end",
@@ -9049,7 +9296,7 @@ function ModelControls({
9049
9296
  }
9050
9297
 
9051
9298
  // src/components/chat/AgentChatPanel.tsx
9052
- import { jsx as jsx69, jsxs as jsxs64 } from "react/jsx-runtime";
9299
+ import { jsx as jsx72, jsxs as jsxs67 } from "react/jsx-runtime";
9053
9300
  var SURFACES = { sidebar: "is-sidebar", inline: "is-inline", page: "is-page", modal: "is-modal", sheet: "is-sheet" };
9054
9301
  function AgentChatPanel({
9055
9302
  /* required */
@@ -9133,11 +9380,11 @@ function AgentChatPanel({
9133
9380
  onFeedback,
9134
9381
  onEditMessage
9135
9382
  }) {
9136
- const [panelWidth, setPanelWidth] = React39.useState(width);
9137
- const [applied, setApplied] = React39.useState({});
9138
- const [draft, setDraft] = React39.useState("");
9139
- const dragging = React39.useRef(null);
9140
- React39.useEffect(() => setPanelWidth(width), [width]);
9383
+ const [panelWidth, setPanelWidth] = React41.useState(width);
9384
+ const [applied, setApplied] = React41.useState({});
9385
+ const [draft, setDraft] = React41.useState("");
9386
+ const dragging = React41.useRef(null);
9387
+ React41.useEffect(() => setPanelWidth(width), [width]);
9141
9388
  const engine = useChatEngine({
9142
9389
  contextType,
9143
9390
  contextId,
@@ -9203,7 +9450,7 @@ function AgentChatPanel({
9203
9450
  onReconnect: engine.reload,
9204
9451
  deadTitle: "The assistant isn\u2019t reachable"
9205
9452
  };
9206
- const sessionBar = /* @__PURE__ */ jsx69(
9453
+ const sessionBar = /* @__PURE__ */ jsx72(
9207
9454
  ChatSessionBar,
9208
9455
  {
9209
9456
  sessionStats,
@@ -9212,7 +9459,7 @@ function AgentChatPanel({
9212
9459
  onClear: engine.visible.length ? engine.clear : void 0
9213
9460
  }
9214
9461
  );
9215
- const modelControls = /* @__PURE__ */ jsx69(
9462
+ const modelControls = /* @__PURE__ */ jsx72(
9216
9463
  ModelControls,
9217
9464
  {
9218
9465
  models,
@@ -9227,7 +9474,7 @@ function AgentChatPanel({
9227
9474
  narrow
9228
9475
  }
9229
9476
  );
9230
- const threadMenu = threads && threads.length ? /* @__PURE__ */ jsx69(
9477
+ const threadMenu = threads && threads.length ? /* @__PURE__ */ jsx72(
9231
9478
  MenuButton,
9232
9479
  {
9233
9480
  variant: "ghost",
@@ -9254,7 +9501,7 @@ function AgentChatPanel({
9254
9501
  })))
9255
9502
  }
9256
9503
  ) : null;
9257
- return /* @__PURE__ */ jsxs64(
9504
+ return /* @__PURE__ */ jsxs67(
9258
9505
  "aside",
9259
9506
  {
9260
9507
  className: ["fdc-panel", SURFACES[surface] || SURFACES.sidebar, narrow ? "is-narrow" : "", className].filter(Boolean).join(" "),
@@ -9265,7 +9512,7 @@ function AgentChatPanel({
9265
9512
  },
9266
9513
  "aria-label": title,
9267
9514
  children: [
9268
- surface === "sidebar" && resizable ? /* @__PURE__ */ jsx69(
9515
+ surface === "sidebar" && resizable ? /* @__PURE__ */ jsx72(
9269
9516
  "div",
9270
9517
  {
9271
9518
  className: "fdc-grip",
@@ -9280,20 +9527,20 @@ function AgentChatPanel({
9280
9527
  }
9281
9528
  }
9282
9529
  ) : null,
9283
- showHeader ? /* @__PURE__ */ jsxs64("header", { className: "fdc-head", children: [
9284
- /* @__PURE__ */ jsx69("span", { className: "fdc-head-mark", "aria-hidden": "true", children: /* @__PURE__ */ jsx69("i", { className: "ph ph-" + assistantIcon }) }),
9285
- /* @__PURE__ */ jsxs64("span", { className: "fdc-head-titles", children: [
9286
- /* @__PURE__ */ jsx69("span", { className: "fdc-head-title", children: title }),
9287
- subtitle ? /* @__PURE__ */ jsx69("span", { className: "fdc-head-sub", children: subtitle }) : null
9530
+ showHeader ? /* @__PURE__ */ jsxs67("header", { className: "fdc-head", children: [
9531
+ /* @__PURE__ */ jsx72("span", { className: "fdc-head-mark", "aria-hidden": "true", children: /* @__PURE__ */ jsx72("i", { className: "ph ph-" + assistantIcon }) }),
9532
+ /* @__PURE__ */ jsxs67("span", { className: "fdc-head-titles", children: [
9533
+ /* @__PURE__ */ jsx72("span", { className: "fdc-head-title", children: title }),
9534
+ subtitle ? /* @__PURE__ */ jsx72("span", { className: "fdc-head-sub", children: subtitle }) : null
9288
9535
  ] }),
9289
- /* @__PURE__ */ jsxs64("span", { className: "fdc-head-acts", children: [
9536
+ /* @__PURE__ */ jsxs67("span", { className: "fdc-head-acts", children: [
9290
9537
  headerActions,
9291
9538
  threadMenu,
9292
- onNewThread ? /* @__PURE__ */ jsx69("button", { type: "button", className: "fdc-iconbtn", onClick: onNewThread, "aria-label": "New conversation", title: "New conversation", children: /* @__PURE__ */ jsx69("i", { className: "ph ph-plus", "aria-hidden": "true" }) }) : null,
9293
- onClose ? /* @__PURE__ */ jsx69("button", { type: "button", className: "fdc-iconbtn", onClick: onClose, "aria-label": "Close panel", title: "Close", children: /* @__PURE__ */ jsx69("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
9539
+ onNewThread ? /* @__PURE__ */ jsx72("button", { type: "button", className: "fdc-iconbtn", onClick: onNewThread, "aria-label": "New conversation", title: "New conversation", children: /* @__PURE__ */ jsx72("i", { className: "ph ph-plus", "aria-hidden": "true" }) }) : null,
9540
+ onClose ? /* @__PURE__ */ jsx72("button", { type: "button", className: "fdc-iconbtn", onClick: onClose, "aria-label": "Close panel", title: "Close", children: /* @__PURE__ */ jsx72("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
9294
9541
  ] })
9295
9542
  ] }) : null,
9296
- /* @__PURE__ */ jsx69(
9543
+ /* @__PURE__ */ jsx72(
9297
9544
  ChatTranscript,
9298
9545
  {
9299
9546
  messages: engine.visible,
@@ -9308,7 +9555,7 @@ function AgentChatPanel({
9308
9555
  renderEmpty
9309
9556
  }
9310
9557
  ),
9311
- /* @__PURE__ */ jsx69(
9558
+ /* @__PURE__ */ jsx72(
9312
9559
  ChatComposer,
9313
9560
  {
9314
9561
  onSubmit: (text, atts) => engine.send(text, atts),
@@ -9341,7 +9588,7 @@ function AgentChatPanel({
9341
9588
  }
9342
9589
 
9343
9590
  // src/kits/query.ts
9344
- import * as React40 from "react";
9591
+ import * as React42 from "react";
9345
9592
  function eqFilter(get2) {
9346
9593
  return (row, value) => Array.isArray(value) ? value.includes(get2(row)) : get2(row) === value;
9347
9594
  }
@@ -9373,22 +9620,22 @@ function compare(a, b, dir) {
9373
9620
  var API = null;
9374
9621
  var PREFS = null;
9375
9622
  function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
9376
- const [query, setQuery] = React40.useState(() => {
9623
+ const [query, setQuery] = React42.useState(() => {
9377
9624
  const store = PREFS || window.PlannerPrefs;
9378
9625
  const saved = prefsKey && store ? store.getTable(prefsKey) : {};
9379
9626
  return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
9380
9627
  });
9381
- const savePref = React40.useCallback((patch2) => {
9628
+ const savePref = React42.useCallback((patch2) => {
9382
9629
  const store = PREFS || window.PlannerPrefs;
9383
9630
  if (prefsKey && store) store.setTable(prefsKey, patch2);
9384
9631
  }, [prefsKey]);
9385
- const [res, setRes] = React40.useState(null);
9386
- const [loading, setLoading] = React40.useState(true);
9387
- const seq2 = React40.useRef(0);
9632
+ const [res, setRes] = React42.useState(null);
9633
+ const [loading, setLoading] = React42.useState(true);
9634
+ const seq2 = React42.useRef(0);
9388
9635
  const depKey = (deps || []).join("|");
9389
9636
  const paramKey = JSON.stringify(params || {});
9390
9637
  const queryKey = JSON.stringify(query);
9391
- React40.useEffect(() => {
9638
+ React42.useEffect(() => {
9392
9639
  const id = ++seq2.current;
9393
9640
  setLoading(true);
9394
9641
  const t = setTimeout(() => {
@@ -9726,6 +9973,7 @@ export {
9726
9973
  Dropzone,
9727
9974
  DropzoneKit,
9728
9975
  EmptyState,
9976
+ EntityRow,
9729
9977
  FeatureGate,
9730
9978
  FileChip,
9731
9979
  FileGrid,
@@ -9798,11 +10046,16 @@ export {
9798
10046
  Tooltip,
9799
10047
  Topbar,
9800
10048
  TranscriptKit,
10049
+ TransferList,
9801
10050
  UseFeatureStatus,
9802
10051
  UseRuntimeMode,
10052
+ VIRTUAL_LIST_BUFFER_ROWS,
10053
+ VirtualList,
9803
10054
  acceptMatches,
9804
10055
  anyOfFilter,
9805
10056
  channelWeightOf,
10057
+ computeNeedMore,
10058
+ computeVirtualWindow,
9806
10059
  createVersionStore,
9807
10060
  eqFilter,
9808
10061
  extensionOf,