@flytedan/flytebot-design-system 0.9.0 → 0.10.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
@@ -2744,11 +2744,30 @@ function EntityRow({
2744
2744
  }
2745
2745
 
2746
2746
  // src/components/data/TransferList.tsx
2747
- import * as React17 from "react";
2747
+ import * as React18 from "react";
2748
2748
  import { createPortal as createPortal4 } from "react-dom";
2749
2749
 
2750
- // src/components/forms/Input.tsx
2750
+ // src/components/forms/field.tsx
2751
+ import * as React17 from "react";
2751
2752
  import { jsx as jsx40, jsxs as jsxs36 } from "react/jsx-runtime";
2753
+ function useFieldId(id) {
2754
+ const generated = React17.useId();
2755
+ return id || generated;
2756
+ }
2757
+ function FieldLabel({ htmlFor, id, required = false, onClick, children }) {
2758
+ return /* @__PURE__ */ jsxs36("label", { className: "fd-field-label", htmlFor, id, onClick, children: [
2759
+ children,
2760
+ required ? /* @__PURE__ */ jsx40("span", { className: "fd-field-req", "aria-hidden": "true", children: "*" }) : null
2761
+ ] });
2762
+ }
2763
+ function useTriggerLabelling(label, id) {
2764
+ const fieldId = useFieldId(id);
2765
+ const labelId = fieldId + "-label";
2766
+ return { fieldId, labelId, ariaLabelledBy: label ? labelId + " " + fieldId : void 0 };
2767
+ }
2768
+
2769
+ // src/components/forms/Input.tsx
2770
+ import { jsx as jsx41, jsxs as jsxs37 } from "react/jsx-runtime";
2752
2771
  function Input({
2753
2772
  label,
2754
2773
  help,
@@ -2767,7 +2786,7 @@ function Input({
2767
2786
  inputStyle,
2768
2787
  ...rest
2769
2788
  }) {
2770
- const fieldId = id || (rest.name ? "fd-" + rest.name : void 0);
2789
+ const fieldId = useFieldId(id);
2771
2790
  const box = [
2772
2791
  "fd-input",
2773
2792
  numeric ? "fd-input-num" : "",
@@ -2776,27 +2795,24 @@ function Input({
2776
2795
  size === "lg" ? "fd-input-lg" : "",
2777
2796
  className
2778
2797
  ].filter(Boolean).join(" ");
2779
- return /* @__PURE__ */ jsxs36("div", { className: "fd-field", style, children: [
2780
- label ? /* @__PURE__ */ jsxs36("label", { className: "fd-field-label", htmlFor: fieldId, children: [
2781
- label,
2782
- required ? /* @__PURE__ */ jsx40("span", { className: "fd-field-req", "aria-hidden": "true", children: "*" }) : null
2783
- ] }) : null,
2784
- /* @__PURE__ */ jsxs36("div", { className: box, children: [
2785
- icon ? /* @__PURE__ */ jsx40("span", { className: "fd-input-icon", children: /* @__PURE__ */ jsx40("i", { className: "ph ph-" + icon, "aria-hidden": "true" }) }) : null,
2786
- prefix ? /* @__PURE__ */ jsx40("span", { className: "fd-input-affix", children: prefix }) : null,
2787
- /* @__PURE__ */ jsx40("input", { id: fieldId, disabled, style: inputStyle, "aria-invalid": error ? "true" : void 0, ...rest }),
2788
- loading ? /* @__PURE__ */ jsx40("span", { className: "fd-spinner", style: { color: "var(--text-muted)" }, "aria-label": "Loading" }) : null,
2789
- suffix && !loading ? /* @__PURE__ */ jsx40("span", { className: "fd-input-affix", children: suffix }) : null
2798
+ return /* @__PURE__ */ jsxs37("div", { className: "fd-field", style, children: [
2799
+ label ? /* @__PURE__ */ jsx41(FieldLabel, { htmlFor: fieldId, required, children: label }) : null,
2800
+ /* @__PURE__ */ jsxs37("div", { className: box, children: [
2801
+ icon ? /* @__PURE__ */ jsx41("span", { className: "fd-input-icon", children: /* @__PURE__ */ jsx41("i", { className: "ph ph-" + icon, "aria-hidden": "true" }) }) : null,
2802
+ prefix ? /* @__PURE__ */ jsx41("span", { className: "fd-input-affix", children: prefix }) : null,
2803
+ /* @__PURE__ */ jsx41("input", { id: fieldId, disabled, style: inputStyle, "aria-invalid": error ? "true" : void 0, ...rest }),
2804
+ loading ? /* @__PURE__ */ jsx41("span", { className: "fd-spinner", style: { color: "var(--text-muted)" }, "aria-label": "Loading" }) : null,
2805
+ suffix && !loading ? /* @__PURE__ */ jsx41("span", { className: "fd-input-affix", children: suffix }) : null
2790
2806
  ] }),
2791
- error ? /* @__PURE__ */ jsxs36("span", { className: "fd-field-error", children: [
2792
- /* @__PURE__ */ jsx40("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
2807
+ error ? /* @__PURE__ */ jsxs37("span", { className: "fd-field-error", children: [
2808
+ /* @__PURE__ */ jsx41("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
2793
2809
  error
2794
- ] }) : help ? /* @__PURE__ */ jsx40("span", { className: "fd-field-help", children: help }) : null
2810
+ ] }) : help ? /* @__PURE__ */ jsx41("span", { className: "fd-field-help", children: help }) : null
2795
2811
  ] });
2796
2812
  }
2797
2813
 
2798
2814
  // src/components/forms/SearchField.tsx
2799
- import { jsx as jsx41 } from "react/jsx-runtime";
2815
+ import { jsx as jsx42 } from "react/jsx-runtime";
2800
2816
  function SearchField({
2801
2817
  value,
2802
2818
  onChange,
@@ -2811,7 +2827,7 @@ function SearchField({
2811
2827
  ...rest
2812
2828
  }) {
2813
2829
  const clear = onClear || (() => onChange(""));
2814
- return /* @__PURE__ */ jsx41(
2830
+ return /* @__PURE__ */ jsx42(
2815
2831
  Input,
2816
2832
  {
2817
2833
  id,
@@ -2824,14 +2840,14 @@ function SearchField({
2824
2840
  style,
2825
2841
  className,
2826
2842
  onChange: (e) => onChange(e.target.value),
2827
- suffix: value ? /* @__PURE__ */ jsx41(
2843
+ suffix: value ? /* @__PURE__ */ jsx42(
2828
2844
  "button",
2829
2845
  {
2830
2846
  type: "button",
2831
2847
  "aria-label": "Clear search",
2832
2848
  onClick: clear,
2833
2849
  style: { all: "unset", cursor: "pointer", color: "var(--text-muted)", display: "grid", placeItems: "center", padding: 2 },
2834
- children: /* @__PURE__ */ jsx41("i", { className: "ph ph-x-circle", style: { fontSize: 15 }, "aria-hidden": "true" })
2850
+ children: /* @__PURE__ */ jsx42("i", { className: "ph ph-x-circle", style: { fontSize: 15 }, "aria-hidden": "true" })
2835
2851
  }
2836
2852
  ) : void 0,
2837
2853
  ...rest
@@ -2840,7 +2856,7 @@ function SearchField({
2840
2856
  }
2841
2857
 
2842
2858
  // src/components/data/TransferList.tsx
2843
- import { jsx as jsx42, jsxs as jsxs37 } from "react/jsx-runtime";
2859
+ import { jsx as jsx43, jsxs as jsxs38 } from "react/jsx-runtime";
2844
2860
  var emptyHasMore = {};
2845
2861
  var DRAG_THRESHOLD_PX = 5;
2846
2862
  function TransferList({
@@ -2854,12 +2870,12 @@ function TransferList({
2854
2870
  listHeight = 440,
2855
2871
  className = ""
2856
2872
  }) {
2857
- const [drag, setDrag] = React17.useState(null);
2858
- const [dragOverSide, setDragOverSide] = React17.useState(null);
2859
- const dragRef = React17.useRef(null);
2860
- const armedRef = React17.useRef(null);
2861
- const sideRefs = React17.useRef({ left: null, right: null });
2862
- const hitTestSide = React17.useCallback((x, y) => {
2873
+ const [drag, setDrag] = React18.useState(null);
2874
+ const [dragOverSide, setDragOverSide] = React18.useState(null);
2875
+ const dragRef = React18.useRef(null);
2876
+ const armedRef = React18.useRef(null);
2877
+ const sideRefs = React18.useRef({ left: null, right: null });
2878
+ const hitTestSide = React18.useCallback((x, y) => {
2863
2879
  for (const side of ["left", "right"]) {
2864
2880
  const el = sideRefs.current[side];
2865
2881
  if (!el) continue;
@@ -2868,7 +2884,7 @@ function TransferList({
2868
2884
  }
2869
2885
  return null;
2870
2886
  }, []);
2871
- const findItem = React17.useCallback(
2887
+ const findItem = React18.useCallback(
2872
2888
  (side, key) => (side === "left" ? left.items : right.items).find((it) => keyOf(it) === key),
2873
2889
  [left.items, right.items, keyOf]
2874
2890
  );
@@ -2890,7 +2906,7 @@ function TransferList({
2890
2906
  height: rect.height
2891
2907
  };
2892
2908
  };
2893
- React17.useEffect(() => {
2909
+ React18.useEffect(() => {
2894
2910
  const onMovePointer = (e) => {
2895
2911
  const armed = armedRef.current;
2896
2912
  if (!armed || e.pointerId !== armed.pointerId) return;
@@ -2943,7 +2959,7 @@ function TransferList({
2943
2959
  window.removeEventListener("pointercancel", endDrag);
2944
2960
  };
2945
2961
  }, [hitTestSide, findItem, onMove]);
2946
- React17.useEffect(() => {
2962
+ React18.useEffect(() => {
2947
2963
  if (!drag || typeof document === "undefined") return;
2948
2964
  const prev = document.body.style.userSelect;
2949
2965
  document.body.style.userSelect = "none";
@@ -2953,7 +2969,7 @@ function TransferList({
2953
2969
  }, [drag]);
2954
2970
  const renderSide = (side, cfg, opposite) => {
2955
2971
  const showOverlay = drag != null && dragOverSide === side;
2956
- return /* @__PURE__ */ jsxs37(
2972
+ return /* @__PURE__ */ jsxs38(
2957
2973
  "div",
2958
2974
  {
2959
2975
  ref: (el) => {
@@ -2972,16 +2988,16 @@ function TransferList({
2972
2988
  position: "relative"
2973
2989
  },
2974
2990
  children: [
2975
- cfg.label ? /* @__PURE__ */ jsxs37("span", { className: "fd-overline fd-muted", children: [
2991
+ cfg.label ? /* @__PURE__ */ jsxs38("span", { className: "fd-overline fd-muted", children: [
2976
2992
  cfg.label,
2977
2993
  cfg.total != null ? " (" + cfg.total.toLocaleString() + ")" : ""
2978
2994
  ] }) : null,
2979
- cfg.header ? /* @__PURE__ */ jsx42("div", { className: "fd-tlist-header", children: cfg.header }) : null,
2980
- /* @__PURE__ */ jsxs37("span", { className: "fd-row", style: { gap: 8 }, children: [
2981
- /* @__PURE__ */ jsx42(SearchField, { value: cfg.search, onChange: cfg.onSearchChange, placeholder: "Search", "aria-label": (cfg.label || side) + " search", style: { flex: 1 } }),
2982
- /* @__PURE__ */ jsx42(SortMenu, { fields: cfg.sortFields, sort: cfg.sort, onSort: cfg.onSort, align: side === "left" ? "left" : "right" })
2995
+ cfg.header ? /* @__PURE__ */ jsx43("div", { className: "fd-tlist-header", children: cfg.header }) : null,
2996
+ /* @__PURE__ */ jsxs38("span", { className: "fd-row", style: { gap: 8 }, children: [
2997
+ /* @__PURE__ */ jsx43(SearchField, { value: cfg.search, onChange: cfg.onSearchChange, placeholder: "Search", "aria-label": (cfg.label || side) + " search", style: { flex: 1 } }),
2998
+ /* @__PURE__ */ jsx43(SortMenu, { fields: cfg.sortFields, sort: cfg.sort, onSort: cfg.onSort, align: side === "left" ? "left" : "right" })
2983
2999
  ] }),
2984
- /* @__PURE__ */ jsx42(
3000
+ /* @__PURE__ */ jsx43(
2985
3001
  VirtualList,
2986
3002
  {
2987
3003
  items: cfg.items,
@@ -2995,13 +3011,13 @@ function TransferList({
2995
3011
  firstItemIndex: cfg.firstItemIndex,
2996
3012
  totalCount: cfg.totalCount,
2997
3013
  onNeedMore: cfg.onNeedMore,
2998
- emptyState: /* @__PURE__ */ jsx42(EmptyState, { icon: "tray", title: "Nothing here" }),
3014
+ emptyState: /* @__PURE__ */ jsx43(EmptyState, { icon: "tray", title: "Nothing here" }),
2999
3015
  renderItem: (item) => {
3000
3016
  const isBeingDragged = drag != null && drag.from === side && drag.key === keyOf(item);
3001
3017
  if (isBeingDragged) {
3002
- return /* @__PURE__ */ jsx42("div", { className: "fd-erow-placeholder", "aria-hidden": "true" });
3018
+ return /* @__PURE__ */ jsx43("div", { className: "fd-erow-placeholder", "aria-hidden": "true" });
3003
3019
  }
3004
- return /* @__PURE__ */ jsx42(
3020
+ return /* @__PURE__ */ jsx43(
3005
3021
  EntityRow,
3006
3022
  {
3007
3023
  ...renderRow(item),
@@ -3018,20 +3034,20 @@ function TransferList({
3018
3034
  }
3019
3035
  }
3020
3036
  ),
3021
- cfg.footer ? /* @__PURE__ */ jsx42("div", { className: "fd-tlist-footer", children: cfg.footer }) : null,
3022
- showOverlay ? /* @__PURE__ */ jsx42("div", { className: "fd-tlist-drop-overlay", "aria-hidden": "true", children: /* @__PURE__ */ jsxs37("span", { className: "fd-tlist-drop-card", children: [
3023
- /* @__PURE__ */ jsx42("i", { className: "ph ph-tray-arrow-down", style: { fontSize: 18 }, "aria-hidden": "true" }),
3024
- /* @__PURE__ */ jsx42("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: cfg.dropLabel || "Drop here" + (cfg.label ? " \u2014 " + cfg.label : "") })
3037
+ cfg.footer ? /* @__PURE__ */ jsx43("div", { className: "fd-tlist-footer", children: cfg.footer }) : null,
3038
+ showOverlay ? /* @__PURE__ */ jsx43("div", { className: "fd-tlist-drop-overlay", "aria-hidden": "true", children: /* @__PURE__ */ jsxs38("span", { className: "fd-tlist-drop-card", children: [
3039
+ /* @__PURE__ */ jsx43("i", { className: "ph ph-tray-arrow-down", style: { fontSize: 18 }, "aria-hidden": "true" }),
3040
+ /* @__PURE__ */ jsx43("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: cfg.dropLabel || "Drop here" + (cfg.label ? " \u2014 " + cfg.label : "") })
3025
3041
  ] }) }) : null
3026
3042
  ]
3027
3043
  }
3028
3044
  );
3029
3045
  };
3030
- return /* @__PURE__ */ jsxs37("div", { className: ["fd-tlist", className].filter(Boolean).join(" "), style: { display: "flex", gap: 16, alignItems: "flex-start" }, children: [
3046
+ return /* @__PURE__ */ jsxs38("div", { className: ["fd-tlist", className].filter(Boolean).join(" "), style: { display: "flex", gap: 16, alignItems: "flex-start" }, children: [
3031
3047
  renderSide("left", left, "right"),
3032
3048
  renderSide("right", right, "left"),
3033
3049
  drag ? createPortal4(
3034
- /* @__PURE__ */ jsx42(
3050
+ /* @__PURE__ */ jsx43(
3035
3051
  "div",
3036
3052
  {
3037
3053
  "aria-hidden": "true",
@@ -3046,7 +3062,7 @@ function TransferList({
3046
3062
  pointerEvents: "none",
3047
3063
  zIndex: 1e3
3048
3064
  },
3049
- children: /* @__PURE__ */ jsx42(EntityRow, { ...renderRow(drag.item), draggable: true, className: "fd-erow-dragging" })
3065
+ children: /* @__PURE__ */ jsx43(EntityRow, { ...renderRow(drag.item), draggable: true, className: "fd-erow-dragging" })
3050
3066
  }
3051
3067
  ),
3052
3068
  document.body
@@ -3055,74 +3071,71 @@ function TransferList({
3055
3071
  }
3056
3072
 
3057
3073
  // src/components/forms/Checkbox.tsx
3058
- import * as React18 from "react";
3059
- import { jsx as jsx43, jsxs as jsxs38 } from "react/jsx-runtime";
3074
+ import * as React19 from "react";
3075
+ import { jsx as jsx44, jsxs as jsxs39 } from "react/jsx-runtime";
3060
3076
  function Checkbox({ label, description, card = false, indeterminate = false, className = "", ...rest }) {
3061
- const ref = React18.useRef(null);
3062
- React18.useEffect(() => {
3077
+ const ref = React19.useRef(null);
3078
+ React19.useEffect(() => {
3063
3079
  if (ref.current) ref.current.indeterminate = indeterminate;
3064
3080
  }, [indeterminate]);
3065
- return /* @__PURE__ */ jsxs38("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
3066
- /* @__PURE__ */ jsxs38("span", { className: "fd-choice-input", children: [
3067
- /* @__PURE__ */ jsx43("input", { ref, type: "checkbox", ...rest }),
3068
- /* @__PURE__ */ jsx43("span", { className: "fd-choice-box", "aria-hidden": "true", children: /* @__PURE__ */ jsx43("i", { className: indeterminate ? "ph ph-minus" : "ph ph-check" }) })
3081
+ return /* @__PURE__ */ jsxs39("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
3082
+ /* @__PURE__ */ jsxs39("span", { className: "fd-choice-input", children: [
3083
+ /* @__PURE__ */ jsx44("input", { ref, type: "checkbox", ...rest }),
3084
+ /* @__PURE__ */ jsx44("span", { className: "fd-choice-box", "aria-hidden": "true", children: /* @__PURE__ */ jsx44("i", { className: indeterminate ? "ph ph-minus" : "ph ph-check" }) })
3069
3085
  ] }),
3070
- /* @__PURE__ */ jsxs38("span", { className: "fd-choice-text", children: [
3071
- /* @__PURE__ */ jsx43("span", { className: "fd-choice-title", children: label }),
3072
- description ? /* @__PURE__ */ jsx43("span", { className: "fd-choice-desc", children: description }) : null
3086
+ /* @__PURE__ */ jsxs39("span", { className: "fd-choice-text", children: [
3087
+ /* @__PURE__ */ jsx44("span", { className: "fd-choice-title", children: label }),
3088
+ description ? /* @__PURE__ */ jsx44("span", { className: "fd-choice-desc", children: description }) : null
3073
3089
  ] })
3074
3090
  ] });
3075
3091
  }
3076
3092
 
3077
3093
  // src/components/forms/Radio.tsx
3078
- import { jsx as jsx44, jsxs as jsxs39 } from "react/jsx-runtime";
3094
+ import { jsx as jsx45, jsxs as jsxs40 } from "react/jsx-runtime";
3079
3095
  function Radio({ label, description, card = false, className = "", ...rest }) {
3080
- return /* @__PURE__ */ jsxs39("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
3081
- /* @__PURE__ */ jsxs39("span", { className: "fd-choice-input", children: [
3082
- /* @__PURE__ */ jsx44("input", { type: "radio", ...rest }),
3083
- /* @__PURE__ */ jsx44("span", { className: "fd-choice-box fd-choice-box-round", "aria-hidden": "true", children: /* @__PURE__ */ jsx44("span", { className: "fd-choice-dot" }) })
3096
+ return /* @__PURE__ */ jsxs40("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
3097
+ /* @__PURE__ */ jsxs40("span", { className: "fd-choice-input", children: [
3098
+ /* @__PURE__ */ jsx45("input", { type: "radio", ...rest }),
3099
+ /* @__PURE__ */ jsx45("span", { className: "fd-choice-box fd-choice-box-round", "aria-hidden": "true", children: /* @__PURE__ */ jsx45("span", { className: "fd-choice-dot" }) })
3084
3100
  ] }),
3085
- /* @__PURE__ */ jsxs39("span", { className: "fd-choice-text", children: [
3086
- /* @__PURE__ */ jsx44("span", { className: "fd-choice-title", children: label }),
3087
- description ? /* @__PURE__ */ jsx44("span", { className: "fd-choice-desc", children: description }) : null
3101
+ /* @__PURE__ */ jsxs40("span", { className: "fd-choice-text", children: [
3102
+ /* @__PURE__ */ jsx45("span", { className: "fd-choice-title", children: label }),
3103
+ description ? /* @__PURE__ */ jsx45("span", { className: "fd-choice-desc", children: description }) : null
3088
3104
  ] })
3089
3105
  ] });
3090
3106
  }
3091
3107
 
3092
3108
  // src/components/forms/Switch.tsx
3093
- import { jsx as jsx45, jsxs as jsxs40 } from "react/jsx-runtime";
3109
+ import { jsx as jsx46, jsxs as jsxs41 } from "react/jsx-runtime";
3094
3110
  function Switch({ label, description, className = "", ...rest }) {
3095
- return /* @__PURE__ */ jsxs40("label", { className: ["fd-switch", className].filter(Boolean).join(" "), children: [
3096
- /* @__PURE__ */ jsx45("input", { type: "checkbox", role: "switch", ...rest }),
3097
- /* @__PURE__ */ jsx45("span", { className: "fd-switch-track", children: /* @__PURE__ */ jsx45("span", { className: "fd-switch-thumb" }) }),
3098
- label ? /* @__PURE__ */ jsxs40("span", { className: "fd-choice-text", children: [
3099
- /* @__PURE__ */ jsx45("span", { className: "fd-switch-label", children: label }),
3100
- description ? /* @__PURE__ */ jsx45("span", { className: "fd-choice-desc", children: description }) : null
3111
+ return /* @__PURE__ */ jsxs41("label", { className: ["fd-switch", className].filter(Boolean).join(" "), children: [
3112
+ /* @__PURE__ */ jsx46("input", { type: "checkbox", role: "switch", ...rest }),
3113
+ /* @__PURE__ */ jsx46("span", { className: "fd-switch-track", children: /* @__PURE__ */ jsx46("span", { className: "fd-switch-thumb" }) }),
3114
+ label ? /* @__PURE__ */ jsxs41("span", { className: "fd-choice-text", children: [
3115
+ /* @__PURE__ */ jsx46("span", { className: "fd-switch-label", children: label }),
3116
+ description ? /* @__PURE__ */ jsx46("span", { className: "fd-choice-desc", children: description }) : null
3101
3117
  ] }) : null
3102
3118
  ] });
3103
3119
  }
3104
3120
 
3105
3121
  // src/components/forms/Textarea.tsx
3106
- import { jsx as jsx46, jsxs as jsxs41 } from "react/jsx-runtime";
3122
+ import { jsx as jsx47, jsxs as jsxs42 } from "react/jsx-runtime";
3107
3123
  function Textarea({ label, help, error, required = false, rows = 4, disabled = false, id, className = "", style, ...rest }) {
3108
- const fieldId = id || (rest.name ? "fd-" + rest.name : void 0);
3124
+ const fieldId = useFieldId(id);
3109
3125
  const box = ["fd-input", "fd-input-textarea", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : "", className].filter(Boolean).join(" ");
3110
- return /* @__PURE__ */ jsxs41("div", { className: "fd-field", style, children: [
3111
- label ? /* @__PURE__ */ jsxs41("label", { className: "fd-field-label", htmlFor: fieldId, children: [
3112
- label,
3113
- required ? /* @__PURE__ */ jsx46("span", { className: "fd-field-req", children: "*" }) : null
3114
- ] }) : null,
3115
- /* @__PURE__ */ jsx46("div", { className: box, children: /* @__PURE__ */ jsx46("textarea", { id: fieldId, rows, disabled, "aria-invalid": error ? "true" : void 0, ...rest }) }),
3116
- error ? /* @__PURE__ */ jsxs41("span", { className: "fd-field-error", children: [
3117
- /* @__PURE__ */ jsx46("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
3126
+ return /* @__PURE__ */ jsxs42("div", { className: "fd-field", style, children: [
3127
+ label ? /* @__PURE__ */ jsx47(FieldLabel, { htmlFor: fieldId, required, children: label }) : null,
3128
+ /* @__PURE__ */ jsx47("div", { className: box, children: /* @__PURE__ */ jsx47("textarea", { id: fieldId, rows, disabled, "aria-invalid": error ? "true" : void 0, ...rest }) }),
3129
+ error ? /* @__PURE__ */ jsxs42("span", { className: "fd-field-error", children: [
3130
+ /* @__PURE__ */ jsx47("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
3118
3131
  error
3119
- ] }) : help ? /* @__PURE__ */ jsx46("span", { className: "fd-field-help", children: help }) : null
3132
+ ] }) : help ? /* @__PURE__ */ jsx47("span", { className: "fd-field-help", children: help }) : null
3120
3133
  ] });
3121
3134
  }
3122
3135
 
3123
3136
  // src/components/forms/NumberInput.tsx
3124
- import * as React19 from "react";
3125
- import { jsx as jsx47, jsxs as jsxs42 } from "react/jsx-runtime";
3137
+ import * as React20 from "react";
3138
+ import { jsx as jsx48, jsxs as jsxs43 } from "react/jsx-runtime";
3126
3139
  function NumberInput({
3127
3140
  label,
3128
3141
  help,
@@ -3140,16 +3153,19 @@ function NumberInput({
3140
3153
  format = true,
3141
3154
  className = "",
3142
3155
  style,
3143
- placeholder
3156
+ placeholder,
3157
+ id,
3158
+ "aria-label": ariaLabel
3144
3159
  }) {
3160
+ const fieldId = useFieldId(id);
3145
3161
  const num = (v) => {
3146
3162
  const n = Number(String(v == null ? "" : v).replace(/[^0-9.-]/g, ""));
3147
3163
  return isNaN(n) ? null : n;
3148
3164
  };
3149
- const [text, setText] = React19.useState(value == null || value === "" ? "" : String(value));
3150
- const [editing, setEditing] = React19.useState(false);
3151
- const timer = React19.useRef(null);
3152
- React19.useEffect(() => {
3165
+ const [text, setText] = React20.useState(value == null || value === "" ? "" : String(value));
3166
+ const [editing, setEditing] = React20.useState(false);
3167
+ const timer = React20.useRef(null);
3168
+ React20.useEffect(() => {
3153
3169
  if (!editing) setText(value == null || value === "" ? "" : String(value));
3154
3170
  }, [value, editing]);
3155
3171
  const clamp = (n) => Math.min(max, Math.max(min, n));
@@ -3173,7 +3189,7 @@ function NumberInput({
3173
3189
  const release = () => {
3174
3190
  if (timer.current) clearTimeout(timer.current);
3175
3191
  };
3176
- React19.useEffect(() => () => {
3192
+ React20.useEffect(() => () => {
3177
3193
  if (timer.current) clearTimeout(timer.current);
3178
3194
  }, []);
3179
3195
  const shown = editing ? text : (() => {
@@ -3181,16 +3197,17 @@ function NumberInput({
3181
3197
  return n == null ? "" : format ? n.toLocaleString() : String(n);
3182
3198
  })();
3183
3199
  const box = ["fd-input", "fd-input-num", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" ");
3184
- return /* @__PURE__ */ jsxs42("div", { className: ["fd-field", className].filter(Boolean).join(" "), style, children: [
3185
- label ? /* @__PURE__ */ jsxs42("label", { className: "fd-field-label", children: [
3186
- label,
3187
- required ? /* @__PURE__ */ jsx47("span", { className: "fd-field-req", children: "*" }) : null
3188
- ] }) : null,
3189
- /* @__PURE__ */ jsxs42("div", { className: box, style: { gap: 8 }, children: [
3190
- prefix ? /* @__PURE__ */ jsx47("span", { className: "fd-input-affix", children: prefix }) : null,
3191
- /* @__PURE__ */ jsx47(
3200
+ const fieldName = label || ariaLabel;
3201
+ const stepperName = (verb) => fieldName ? verb + " " + fieldName : verb;
3202
+ return /* @__PURE__ */ jsxs43("div", { className: ["fd-field", className].filter(Boolean).join(" "), style, children: [
3203
+ label ? /* @__PURE__ */ jsx48(FieldLabel, { htmlFor: fieldId, required, children: label }) : null,
3204
+ /* @__PURE__ */ jsxs43("div", { className: box, style: { gap: 8 }, children: [
3205
+ prefix ? /* @__PURE__ */ jsx48("span", { className: "fd-input-affix", children: prefix }) : null,
3206
+ /* @__PURE__ */ jsx48(
3192
3207
  "input",
3193
3208
  {
3209
+ id: fieldId,
3210
+ "aria-label": ariaLabel,
3194
3211
  inputMode: "numeric",
3195
3212
  disabled,
3196
3213
  placeholder,
@@ -3221,51 +3238,51 @@ function NumberInput({
3221
3238
  }
3222
3239
  }
3223
3240
  ),
3224
- suffix ? /* @__PURE__ */ jsx47("span", { className: "fd-input-affix", children: suffix }) : null,
3225
- /* @__PURE__ */ jsxs42("span", { className: "fd-row", style: { gap: 4, flex: "none" }, children: [
3226
- /* @__PURE__ */ jsx47(
3241
+ suffix ? /* @__PURE__ */ jsx48("span", { className: "fd-input-affix", children: suffix }) : null,
3242
+ /* @__PURE__ */ jsxs43("span", { className: "fd-row", style: { gap: 4, flex: "none" }, children: [
3243
+ /* @__PURE__ */ jsx48(
3227
3244
  "button",
3228
3245
  {
3229
3246
  type: "button",
3230
3247
  className: "fd-stepbtn",
3231
- "aria-label": "Decrease",
3248
+ "aria-label": stepperName("Decrease"),
3232
3249
  disabled: disabled || (num(text) ?? 0) <= min,
3233
3250
  onPointerDown: () => hold(-1),
3234
3251
  onPointerUp: release,
3235
3252
  onPointerLeave: release,
3236
- children: /* @__PURE__ */ jsx47("i", { className: "ph ph-minus" })
3253
+ children: /* @__PURE__ */ jsx48("i", { className: "ph ph-minus" })
3237
3254
  }
3238
3255
  ),
3239
- /* @__PURE__ */ jsx47(
3256
+ /* @__PURE__ */ jsx48(
3240
3257
  "button",
3241
3258
  {
3242
3259
  type: "button",
3243
3260
  className: "fd-stepbtn",
3244
- "aria-label": "Increase",
3261
+ "aria-label": stepperName("Increase"),
3245
3262
  disabled: disabled || (num(text) ?? 0) >= max,
3246
3263
  onPointerDown: () => hold(1),
3247
3264
  onPointerUp: release,
3248
3265
  onPointerLeave: release,
3249
- children: /* @__PURE__ */ jsx47("i", { className: "ph ph-plus" })
3266
+ children: /* @__PURE__ */ jsx48("i", { className: "ph ph-plus" })
3250
3267
  }
3251
3268
  )
3252
3269
  ] })
3253
3270
  ] }),
3254
- error ? /* @__PURE__ */ jsxs42("span", { className: "fd-field-error", children: [
3255
- /* @__PURE__ */ jsx47("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
3271
+ error ? /* @__PURE__ */ jsxs43("span", { className: "fd-field-error", children: [
3272
+ /* @__PURE__ */ jsx48("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
3256
3273
  error
3257
- ] }) : help ? /* @__PURE__ */ jsx47("span", { className: "fd-field-help", children: help }) : null
3274
+ ] }) : help ? /* @__PURE__ */ jsx48("span", { className: "fd-field-help", children: help }) : null
3258
3275
  ] });
3259
3276
  }
3260
3277
 
3261
3278
  // src/components/forms/Select.tsx
3262
- import * as React20 from "react";
3279
+ import * as React21 from "react";
3263
3280
  import { createPortal as createPortal5 } from "react-dom";
3264
- import { jsx as jsx48, jsxs as jsxs43 } from "react/jsx-runtime";
3281
+ import { jsx as jsx49, jsxs as jsxs44 } from "react/jsx-runtime";
3265
3282
  var norm = (o) => typeof o === "string" ? { value: o, label: o } : o;
3266
3283
  function usePopPos(open, ref, estH, estW) {
3267
- const [pos, setPos] = React20.useState(null);
3268
- React20.useLayoutEffect(() => {
3284
+ const [pos, setPos] = React21.useState(null);
3285
+ React21.useLayoutEffect(() => {
3269
3286
  if (!open || !ref.current) {
3270
3287
  setPos(null);
3271
3288
  return;
@@ -3322,21 +3339,21 @@ function Select({
3322
3339
  summary,
3323
3340
  id,
3324
3341
  className = "",
3325
- style,
3326
- ...rest
3342
+ style
3327
3343
  }) {
3328
3344
  const opts = options.map(norm);
3329
3345
  const vals = multiple ? Array.isArray(value) ? value : value ? [value] : [] : [];
3330
3346
  const isOn = (v) => multiple ? vals.includes(v) : v === value;
3331
3347
  const hasSearch = searchable === void 0 ? opts.length > 8 : searchable;
3332
- const [open, setOpen] = React20.useState(false);
3333
- const [q, setQ] = React20.useState("");
3334
- const [active, setActive] = React20.useState(-1);
3335
- const rootRef = React20.useRef(null);
3336
- const boxRef = React20.useRef(null);
3337
- const popRef = React20.useRef(null);
3338
- const listRef = React20.useRef(null);
3339
- const typeBuf = React20.useRef({ s: "", t: 0 });
3348
+ const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
3349
+ const [open, setOpen] = React21.useState(false);
3350
+ const [q, setQ] = React21.useState("");
3351
+ const [active, setActive] = React21.useState(-1);
3352
+ const rootRef = React21.useRef(null);
3353
+ const boxRef = React21.useRef(null);
3354
+ const popRef = React21.useRef(null);
3355
+ const listRef = React21.useRef(null);
3356
+ const typeBuf = React21.useRef({ s: "", t: 0 });
3340
3357
  const selected = multiple ? null : opts.find((o) => o.value === value);
3341
3358
  const chosen = multiple ? opts.filter((o) => vals.includes(o.value)) : [];
3342
3359
  const pos = usePopPos(open, boxRef, hasSearch ? 390 : 340, 260);
@@ -3362,7 +3379,7 @@ function Select({
3362
3379
  }
3363
3380
  setOpen(!open);
3364
3381
  };
3365
- React20.useEffect(() => {
3382
+ React21.useEffect(() => {
3366
3383
  if (!open) return;
3367
3384
  const away = (e) => {
3368
3385
  if (rootRef.current && rootRef.current.contains(e.target)) return;
@@ -3372,7 +3389,7 @@ function Select({
3372
3389
  document.addEventListener("pointerdown", away);
3373
3390
  return () => document.removeEventListener("pointerdown", away);
3374
3391
  }, [open]);
3375
- React20.useEffect(() => {
3392
+ React21.useEffect(() => {
3376
3393
  if (!open || active < 0 || !listRef.current) return;
3377
3394
  const el = listRef.current.querySelector('[data-i="' + active + '"]');
3378
3395
  if (el) {
@@ -3424,15 +3441,11 @@ function Select({
3424
3441
  if (!last || last.g !== g) groups.push({ g, items: [{ o, i }] });
3425
3442
  else last.items.push({ o, i });
3426
3443
  });
3427
- const fieldId = id || (rest.name ? "fd-" + rest.name : void 0);
3428
3444
  const box = ["fd-input", "fd-select", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" ");
3429
- return /* @__PURE__ */ jsxs43("div", { className: ["fd-field", "fd-popfield", open ? "is-open" : "", className].filter(Boolean).join(" "), style, ref: rootRef, children: [
3430
- label ? /* @__PURE__ */ jsxs43("label", { className: "fd-field-label", htmlFor: fieldId, onClick: toggle, children: [
3431
- label,
3432
- required ? /* @__PURE__ */ jsx48("span", { className: "fd-field-req", children: "*" }) : null
3433
- ] }) : null,
3434
- /* @__PURE__ */ jsxs43("div", { className: box, style: { cursor: disabled ? "not-allowed" : "pointer" }, ref: boxRef, children: [
3435
- /* @__PURE__ */ jsxs43(
3445
+ return /* @__PURE__ */ jsxs44("div", { className: ["fd-field", "fd-popfield", open ? "is-open" : "", className].filter(Boolean).join(" "), style, ref: rootRef, children: [
3446
+ label ? /* @__PURE__ */ jsx49(FieldLabel, { id: labelId, required, onClick: toggle, children: label }) : null,
3447
+ /* @__PURE__ */ jsxs44("div", { className: box, style: { cursor: disabled ? "not-allowed" : "pointer" }, ref: boxRef, children: [
3448
+ /* @__PURE__ */ jsxs44(
3436
3449
  "button",
3437
3450
  {
3438
3451
  type: "button",
@@ -3443,15 +3456,16 @@ function Select({
3443
3456
  role: "combobox",
3444
3457
  "aria-expanded": open,
3445
3458
  "aria-haspopup": "listbox",
3459
+ "aria-labelledby": ariaLabelledBy,
3446
3460
  style: { all: "unset", flex: 1, minWidth: 0, display: "flex", alignItems: "center", gap: 8, cursor: "inherit", overflow: "hidden" },
3447
3461
  children: [
3448
- selected && selected.icon ? /* @__PURE__ */ jsx48("i", { className: "ph ph-" + selected.icon, style: { flex: "none", color: "var(--text-2)" } }) : null,
3449
- /* @__PURE__ */ jsx48("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", color: (multiple ? chosen.length : selected) ? "var(--text)" : "var(--text-muted)" }, children: boxText }),
3450
- multiple && chosen.length > 1 ? /* @__PURE__ */ jsx48("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
3462
+ selected && selected.icon ? /* @__PURE__ */ jsx49("i", { className: "ph ph-" + selected.icon, style: { flex: "none", color: "var(--text-2)" } }) : null,
3463
+ /* @__PURE__ */ jsx49("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", color: (multiple ? chosen.length : selected) ? "var(--text)" : "var(--text-muted)" }, children: boxText }),
3464
+ multiple && chosen.length > 1 ? /* @__PURE__ */ jsx49("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
3451
3465
  ]
3452
3466
  }
3453
3467
  ),
3454
- clearable && (multiple ? chosen.length > 0 : selected) && !loading ? /* @__PURE__ */ jsx48(
3468
+ clearable && (multiple ? chosen.length > 0 : selected) && !loading ? /* @__PURE__ */ jsx49(
3455
3469
  "button",
3456
3470
  {
3457
3471
  type: "button",
@@ -3461,22 +3475,22 @@ function Select({
3461
3475
  fire(multiple ? [] : "");
3462
3476
  },
3463
3477
  style: { all: "unset", cursor: "pointer", color: "var(--text-muted)", display: "grid", placeItems: "center", padding: 2 },
3464
- children: /* @__PURE__ */ jsx48("i", { className: "ph ph-x-circle", style: { fontSize: 15 } })
3478
+ children: /* @__PURE__ */ jsx49("i", { className: "ph ph-x-circle", style: { fontSize: 15 } })
3465
3479
  }
3466
3480
  ) : null,
3467
- loading ? /* @__PURE__ */ jsx48("span", { className: "fd-spinner", style: { color: "var(--text-muted)" }, "aria-label": "Loading options" }) : /* @__PURE__ */ jsx48("span", { className: "fd-select-caret", onClick: toggle, children: /* @__PURE__ */ jsx48("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
3481
+ loading ? /* @__PURE__ */ jsx49("span", { className: "fd-spinner", style: { color: "var(--text-muted)" }, "aria-label": "Loading options" }) : /* @__PURE__ */ jsx49("span", { className: "fd-select-caret", onClick: toggle, children: /* @__PURE__ */ jsx49("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
3468
3482
  ] }),
3469
3483
  open && pos ? createPortal5(
3470
- /* @__PURE__ */ jsxs43(
3484
+ /* @__PURE__ */ jsxs44(
3471
3485
  "div",
3472
3486
  {
3473
3487
  className: "fd-pop" + (pos.up ? " is-up" : ""),
3474
3488
  ref: popRef,
3475
3489
  style: popStyle(pos, { minWidth: Math.max(pos.width, 260), maxWidth: 380, zIndex: 130, overflowY: "hidden" }),
3476
3490
  children: [
3477
- hasSearch ? /* @__PURE__ */ jsxs43("div", { className: "fd-pop-search", children: [
3478
- /* @__PURE__ */ jsx48("i", { className: "ph ph-magnifying-glass", style: { color: "var(--text-muted)", fontSize: 14 } }),
3479
- /* @__PURE__ */ jsx48(
3491
+ hasSearch ? /* @__PURE__ */ jsxs44("div", { className: "fd-pop-search", children: [
3492
+ /* @__PURE__ */ jsx49("i", { className: "ph ph-magnifying-glass", style: { color: "var(--text-muted)", fontSize: 14 } }),
3493
+ /* @__PURE__ */ jsx49(
3480
3494
  "input",
3481
3495
  {
3482
3496
  autoFocus: true,
@@ -3489,15 +3503,15 @@ function Select({
3489
3503
  }
3490
3504
  }
3491
3505
  ),
3492
- q ? /* @__PURE__ */ jsx48("span", { className: "fd-body-sm fd-muted", children: visible.length }) : null
3506
+ q ? /* @__PURE__ */ jsx49("span", { className: "fd-body-sm fd-muted", children: visible.length }) : null
3493
3507
  ] }) : null,
3494
- /* @__PURE__ */ jsx48("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__ */ jsxs43("div", { className: "fd-pop-empty", children: [
3508
+ /* @__PURE__ */ jsx49("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__ */ jsxs44("div", { className: "fd-pop-empty", children: [
3495
3509
  'Nothing matches "',
3496
3510
  q,
3497
3511
  '".'
3498
- ] }) : groups.map((grp) => /* @__PURE__ */ jsxs43(React20.Fragment, { children: [
3499
- grp.g ? /* @__PURE__ */ jsx48("div", { className: "fd-pop-group", children: grp.g }) : null,
3500
- grp.items.map(({ o, i }) => /* @__PURE__ */ jsxs43(
3512
+ ] }) : groups.map((grp) => /* @__PURE__ */ jsxs44(React21.Fragment, { children: [
3513
+ grp.g ? /* @__PURE__ */ jsx49("div", { className: "fd-pop-group", children: grp.g }) : null,
3514
+ grp.items.map(({ o, i }) => /* @__PURE__ */ jsxs44(
3501
3515
  "button",
3502
3516
  {
3503
3517
  type: "button",
@@ -3509,21 +3523,21 @@ function Select({
3509
3523
  onMouseEnter: () => setActive(i),
3510
3524
  onClick: () => pick(o),
3511
3525
  children: [
3512
- multiple ? /* @__PURE__ */ jsx48("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__ */ jsx48("i", { className: "ph ph-check", style: { fontSize: 11 } }) : null }) : null,
3513
- o.icon ? /* @__PURE__ */ jsx48("span", { className: "fd-opt-icon", children: /* @__PURE__ */ jsx48("i", { className: "ph ph-" + o.icon }) }) : null,
3514
- /* @__PURE__ */ jsxs43("span", { style: { flex: 1, minWidth: 0 }, children: [
3515
- /* @__PURE__ */ jsx48("span", { className: "fd-opt-label", children: o.label }),
3516
- o.description ? /* @__PURE__ */ jsx48("span", { className: "fd-opt-desc", children: o.description }) : null
3526
+ multiple ? /* @__PURE__ */ jsx49("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__ */ jsx49("i", { className: "ph ph-check", style: { fontSize: 11 } }) : null }) : null,
3527
+ o.icon ? /* @__PURE__ */ jsx49("span", { className: "fd-opt-icon", children: /* @__PURE__ */ jsx49("i", { className: "ph ph-" + o.icon }) }) : null,
3528
+ /* @__PURE__ */ jsxs44("span", { style: { flex: 1, minWidth: 0 }, children: [
3529
+ /* @__PURE__ */ jsx49("span", { className: "fd-opt-label", children: o.label }),
3530
+ o.description ? /* @__PURE__ */ jsx49("span", { className: "fd-opt-desc", children: o.description }) : null
3517
3531
  ] }),
3518
- o.meta ? /* @__PURE__ */ jsx48("span", { className: "fd-opt-meta", children: o.meta }) : null,
3519
- multiple ? null : /* @__PURE__ */ jsx48("span", { className: "fd-opt-check", children: o.value === value ? /* @__PURE__ */ jsx48("i", { className: "ph ph-check" }) : null })
3532
+ o.meta ? /* @__PURE__ */ jsx49("span", { className: "fd-opt-meta", children: o.meta }) : null,
3533
+ multiple ? null : /* @__PURE__ */ jsx49("span", { className: "fd-opt-check", children: o.value === value ? /* @__PURE__ */ jsx49("i", { className: "ph ph-check" }) : null })
3520
3534
  ]
3521
3535
  },
3522
3536
  String(o.value)
3523
3537
  ))
3524
3538
  ] }, grp.g || "_")) }),
3525
- multiple ? /* @__PURE__ */ jsxs43("div", { className: "fd-row", style: { gap: 10, padding: "8px 12px", borderTop: "1px solid var(--border)" }, children: [
3526
- /* @__PURE__ */ jsx48(
3539
+ multiple ? /* @__PURE__ */ jsxs44("div", { className: "fd-row", style: { gap: 10, padding: "8px 12px", borderTop: "1px solid var(--border)" }, children: [
3540
+ /* @__PURE__ */ jsx49(
3527
3541
  "button",
3528
3542
  {
3529
3543
  type: "button",
@@ -3532,13 +3546,13 @@ function Select({
3532
3546
  children: "Select all"
3533
3547
  }
3534
3548
  ),
3535
- /* @__PURE__ */ jsx48("span", { style: { flex: 1 } }),
3536
- /* @__PURE__ */ jsxs43("span", { className: "fd-body-sm fd-muted", children: [
3549
+ /* @__PURE__ */ jsx49("span", { style: { flex: 1 } }),
3550
+ /* @__PURE__ */ jsxs44("span", { className: "fd-body-sm fd-muted", children: [
3537
3551
  vals.length,
3538
3552
  " of ",
3539
3553
  opts.length
3540
3554
  ] }),
3541
- /* @__PURE__ */ jsx48(
3555
+ /* @__PURE__ */ jsx49(
3542
3556
  "button",
3543
3557
  {
3544
3558
  type: "button",
@@ -3554,17 +3568,17 @@ function Select({
3554
3568
  ),
3555
3569
  document.body
3556
3570
  ) : null,
3557
- error ? /* @__PURE__ */ jsxs43("span", { className: "fd-field-error", children: [
3558
- /* @__PURE__ */ jsx48("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
3571
+ error ? /* @__PURE__ */ jsxs44("span", { className: "fd-field-error", children: [
3572
+ /* @__PURE__ */ jsx49("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
3559
3573
  error
3560
- ] }) : help ? /* @__PURE__ */ jsx48("span", { className: "fd-field-help", children: help }) : null
3574
+ ] }) : help ? /* @__PURE__ */ jsx49("span", { className: "fd-field-help", children: help }) : null
3561
3575
  ] });
3562
3576
  }
3563
3577
 
3564
3578
  // src/components/forms/DatePicker.tsx
3565
- import * as React21 from "react";
3579
+ import * as React22 from "react";
3566
3580
  import { createPortal as createPortal6 } from "react-dom";
3567
- import { jsx as jsx49, jsxs as jsxs44 } from "react/jsx-runtime";
3581
+ import { jsx as jsx50, jsxs as jsxs45 } from "react/jsx-runtime";
3568
3582
  var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
3569
3583
  var DOW = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
3570
3584
  var iso = (d) => d.getFullYear() + "-" + String(d.getMonth() + 1).padStart(2, "0") + "-" + String(d.getDate()).padStart(2, "0");
@@ -3578,8 +3592,8 @@ var fmt = (s) => {
3578
3592
  return d ? MONTHS[d.getMonth()].slice(0, 3) + " " + d.getDate() + ", " + d.getFullYear() : "";
3579
3593
  };
3580
3594
  function usePopPos2(open, ref, estH, estW) {
3581
- const [pos, setPos] = React21.useState(null);
3582
- React21.useLayoutEffect(() => {
3595
+ const [pos, setPos] = React22.useState(null);
3596
+ React22.useLayoutEffect(() => {
3583
3597
  if (!open || !ref.current) {
3584
3598
  setPos(null);
3585
3599
  return;
@@ -3623,10 +3637,10 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3623
3637
  const today = /* @__PURE__ */ new Date();
3624
3638
  const sel = range ? value || {} : { start: value, end: value };
3625
3639
  const anchor = parse(sel.start) || parse(initialMonth) || today;
3626
- const [vy, setVy] = React21.useState(anchor.getFullYear());
3627
- const [vm, setVm] = React21.useState(anchor.getMonth());
3628
- const [mode2, setMode] = React21.useState("days");
3629
- const [hover, setHover] = React21.useState(null);
3640
+ const [vy, setVy] = React22.useState(anchor.getFullYear());
3641
+ const [vm, setVm] = React22.useState(anchor.getMonth());
3642
+ const [mode2, setMode] = React22.useState("days");
3643
+ const [hover, setHover] = React22.useState(null);
3630
3644
  const s = parse(sel.start), e = parse(sel.end);
3631
3645
  const hoverEnd = range && s && !e && hover ? parse(hover) : null;
3632
3646
  const inRange = (d) => {
@@ -3663,9 +3677,9 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3663
3677
  const startPad = new Date(y, m, 1).getDay();
3664
3678
  const cells = [];
3665
3679
  for (let i = 0; i < 42; i++) cells.push(new Date(y, m, i - startPad + 1));
3666
- return /* @__PURE__ */ jsxs44("div", { className: "fd-cal-grid", style: { width: months > 1 ? 252 : "auto", flex: "none" }, onMouseLeave: () => setHover(null), children: [
3667
- DOW.map((d) => /* @__PURE__ */ jsx49("span", { className: "fd-cal-dow", children: d }, d)),
3668
- cells.map((d, i) => /* @__PURE__ */ jsx49(
3680
+ return /* @__PURE__ */ jsxs45("div", { className: "fd-cal-grid", style: { width: months > 1 ? 252 : "auto", flex: "none" }, onMouseLeave: () => setHover(null), children: [
3681
+ DOW.map((d) => /* @__PURE__ */ jsx50("span", { className: "fd-cal-dow", children: d }, d)),
3682
+ cells.map((d, i) => /* @__PURE__ */ jsx50(
3669
3683
  "button",
3670
3684
  {
3671
3685
  type: "button",
@@ -3679,20 +3693,20 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3679
3693
  ] });
3680
3694
  };
3681
3695
  const nextY = vm === 11 ? vy + 1 : vy, nextM = (vm + 1) % 12;
3682
- return /* @__PURE__ */ jsxs44("div", { className: "fd-cal", style: { width: months > 1 && mode2 === "days" ? "auto" : void 0 }, children: [
3683
- /* @__PURE__ */ jsxs44("div", { className: "fd-cal-head", children: [
3684
- /* @__PURE__ */ jsx49("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__ */ jsx49("i", { className: "ph ph-caret-left" }) }),
3685
- /* @__PURE__ */ jsxs44("button", { type: "button", className: "fd-cal-title", onClick: () => setMode(mode2 === "days" ? "months" : mode2 === "months" ? "years" : "days"), children: [
3696
+ return /* @__PURE__ */ jsxs45("div", { className: "fd-cal", style: { width: months > 1 && mode2 === "days" ? "auto" : void 0 }, children: [
3697
+ /* @__PURE__ */ jsxs45("div", { className: "fd-cal-head", children: [
3698
+ /* @__PURE__ */ jsx50("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__ */ jsx50("i", { className: "ph ph-caret-left" }) }),
3699
+ /* @__PURE__ */ jsxs45("button", { type: "button", className: "fd-cal-title", onClick: () => setMode(mode2 === "days" ? "months" : mode2 === "months" ? "years" : "days"), children: [
3686
3700
  mode2 === "days" ? MONTHS[vm] + " " + vy : mode2 === "months" ? vy : vy - 5 + " \u2013 " + (vy + 6),
3687
- /* @__PURE__ */ jsx49("i", { className: "ph ph-caret-down", style: { fontSize: 10, marginLeft: 6, color: "var(--text-muted)" } })
3701
+ /* @__PURE__ */ jsx50("i", { className: "ph ph-caret-down", style: { fontSize: 10, marginLeft: 6, color: "var(--text-muted)" } })
3688
3702
  ] }),
3689
- months > 1 && mode2 === "days" ? /* @__PURE__ */ jsx49("span", { className: "fd-cal-title", style: { cursor: "default", background: "none" }, children: MONTHS[nextM] + " " + nextY }) : null,
3690
- /* @__PURE__ */ jsx49("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__ */ jsx49("i", { className: "ph ph-caret-right" }) })
3703
+ months > 1 && mode2 === "days" ? /* @__PURE__ */ jsx50("span", { className: "fd-cal-title", style: { cursor: "default", background: "none" }, children: MONTHS[nextM] + " " + nextY }) : null,
3704
+ /* @__PURE__ */ jsx50("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__ */ jsx50("i", { className: "ph ph-caret-right" }) })
3691
3705
  ] }),
3692
- mode2 === "days" ? /* @__PURE__ */ jsxs44("div", { style: { display: "flex", gap: 18 }, children: [
3706
+ mode2 === "days" ? /* @__PURE__ */ jsxs45("div", { style: { display: "flex", gap: 18 }, children: [
3693
3707
  monthGrid(vy, vm),
3694
3708
  months > 1 ? monthGrid(nextY, nextM) : null
3695
- ] }) : mode2 === "months" ? /* @__PURE__ */ jsx49("div", { className: "fd-cal-grid-months", children: MONTHS.map((m, i) => /* @__PURE__ */ jsx49(
3709
+ ] }) : mode2 === "months" ? /* @__PURE__ */ jsx50("div", { className: "fd-cal-grid-months", children: MONTHS.map((m, i) => /* @__PURE__ */ jsx50(
3696
3710
  "button",
3697
3711
  {
3698
3712
  type: "button",
@@ -3704,7 +3718,7 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3704
3718
  children: m.slice(0, 3)
3705
3719
  },
3706
3720
  m
3707
- )) }) : /* @__PURE__ */ jsx49("div", { className: "fd-cal-grid-months", children: Array.from({ length: 12 }, (_, i) => vy - 5 + i).map((y) => /* @__PURE__ */ jsx49(
3721
+ )) }) : /* @__PURE__ */ jsx50("div", { className: "fd-cal-grid-months", children: Array.from({ length: 12 }, (_, i) => vy - 5 + i).map((y) => /* @__PURE__ */ jsx50(
3708
3722
  "button",
3709
3723
  {
3710
3724
  type: "button",
@@ -3717,8 +3731,8 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3717
3731
  },
3718
3732
  y
3719
3733
  )) }),
3720
- /* @__PURE__ */ jsxs44("div", { className: "fd-cal-foot", children: [
3721
- /* @__PURE__ */ jsx49(
3734
+ /* @__PURE__ */ jsxs45("div", { className: "fd-cal-foot", children: [
3735
+ /* @__PURE__ */ jsx50(
3722
3736
  "button",
3723
3737
  {
3724
3738
  type: "button",
@@ -3732,21 +3746,22 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3732
3746
  children: "Today"
3733
3747
  }
3734
3748
  ),
3735
- /* @__PURE__ */ jsx49("span", { style: { flex: 1 } }),
3736
- range && sel.start ? /* @__PURE__ */ jsxs44("span", { className: "fd-body-sm fd-muted", children: [
3749
+ /* @__PURE__ */ jsx50("span", { style: { flex: 1 } }),
3750
+ range && sel.start ? /* @__PURE__ */ jsxs45("span", { className: "fd-body-sm fd-muted", children: [
3737
3751
  fmt(sel.start),
3738
3752
  sel.end ? " \u2192 " + fmt(sel.end) : " \u2192 pick an end"
3739
3753
  ] }) : null
3740
3754
  ] })
3741
3755
  ] });
3742
3756
  }
3743
- function DatePicker({ label, help, error, required = false, disabled = false, range = false, value, onChange, placeholder, className = "", style, ...rest }) {
3744
- const [open, setOpen] = React21.useState(false);
3745
- const rootRef = React21.useRef(null);
3746
- const boxRef = React21.useRef(null);
3747
- const popRef = React21.useRef(null);
3757
+ function DatePicker({ label, help, error, required = false, disabled = false, range = false, value, onChange, placeholder, id, className = "", style, ...rest }) {
3758
+ const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
3759
+ const [open, setOpen] = React22.useState(false);
3760
+ const rootRef = React22.useRef(null);
3761
+ const boxRef = React22.useRef(null);
3762
+ const popRef = React22.useRef(null);
3748
3763
  const pos = usePopPos2(open, boxRef, 430, range ? 600 : 316);
3749
- React21.useEffect(() => {
3764
+ React22.useEffect(() => {
3750
3765
  if (!open) return;
3751
3766
  const away = (e) => {
3752
3767
  if (rootRef.current && rootRef.current.contains(e.target)) return;
@@ -3767,17 +3782,16 @@ function DatePicker({ label, help, error, required = false, disabled = false, ra
3767
3782
  const toggle = () => {
3768
3783
  if (!disabled) setOpen(!open);
3769
3784
  };
3770
- return /* @__PURE__ */ jsxs44("div", { className: ["fd-field", "fd-popfield", open ? "is-open" : "", className].filter(Boolean).join(" "), style, ref: rootRef, children: [
3771
- label ? /* @__PURE__ */ jsxs44("label", { className: "fd-field-label", onClick: toggle, children: [
3772
- label,
3773
- required ? /* @__PURE__ */ jsx49("span", { className: "fd-field-req", children: "*" }) : null
3774
- ] }) : null,
3775
- /* @__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: [
3776
- /* @__PURE__ */ jsx49("span", { className: "fd-input-icon", children: /* @__PURE__ */ jsx49("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }) }),
3777
- /* @__PURE__ */ jsx49(
3785
+ return /* @__PURE__ */ jsxs45("div", { className: ["fd-field", "fd-popfield", open ? "is-open" : "", className].filter(Boolean).join(" "), style, ref: rootRef, children: [
3786
+ label ? /* @__PURE__ */ jsx50(FieldLabel, { id: labelId, required, onClick: toggle, children: label }) : null,
3787
+ /* @__PURE__ */ jsxs45("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: [
3788
+ /* @__PURE__ */ jsx50("span", { className: "fd-input-icon", children: /* @__PURE__ */ jsx50("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }) }),
3789
+ /* @__PURE__ */ jsx50(
3778
3790
  "button",
3779
3791
  {
3780
3792
  type: "button",
3793
+ id: fieldId,
3794
+ "aria-labelledby": ariaLabelledBy,
3781
3795
  disabled,
3782
3796
  onKeyDown: (e) => {
3783
3797
  if (e.key === "Enter" || e.key === " ") {
@@ -3790,10 +3804,10 @@ function DatePicker({ label, help, error, required = false, disabled = false, ra
3790
3804
  children: display || placeholder || (range ? "Pick a date range" : "Pick a date")
3791
3805
  }
3792
3806
  ),
3793
- /* @__PURE__ */ jsx49("span", { className: "fd-select-caret", children: /* @__PURE__ */ jsx49("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
3807
+ /* @__PURE__ */ jsx50("span", { className: "fd-select-caret", children: /* @__PURE__ */ jsx50("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
3794
3808
  ] }),
3795
3809
  open && pos ? createPortal6(
3796
- /* @__PURE__ */ jsx49("div", { className: "fd-pop" + (pos.up ? " is-up" : ""), ref: popRef, style: popStyle2(pos, { width: "max-content", minWidth: 0, zIndex: 130 }), children: /* @__PURE__ */ jsx49(
3810
+ /* @__PURE__ */ jsx50("div", { className: "fd-pop" + (pos.up ? " is-up" : ""), ref: popRef, style: popStyle2(pos, { width: "max-content", minWidth: 0, zIndex: 130 }), children: /* @__PURE__ */ jsx50(
3797
3811
  Calendar,
3798
3812
  {
3799
3813
  range,
@@ -3807,21 +3821,21 @@ function DatePicker({ label, help, error, required = false, disabled = false, ra
3807
3821
  ) }),
3808
3822
  document.body
3809
3823
  ) : null,
3810
- error ? /* @__PURE__ */ jsxs44("span", { className: "fd-field-error", children: [
3811
- /* @__PURE__ */ jsx49("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
3824
+ error ? /* @__PURE__ */ jsxs45("span", { className: "fd-field-error", children: [
3825
+ /* @__PURE__ */ jsx50("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
3812
3826
  error
3813
- ] }) : help ? /* @__PURE__ */ jsx49("span", { className: "fd-field-help", children: help }) : null
3827
+ ] }) : help ? /* @__PURE__ */ jsx50("span", { className: "fd-field-help", children: help }) : null
3814
3828
  ] });
3815
3829
  }
3816
3830
 
3817
3831
  // src/components/forms/TimePicker.tsx
3818
- import * as React22 from "react";
3832
+ import * as React23 from "react";
3819
3833
  import { createPortal as createPortal7 } from "react-dom";
3820
- import { jsx as jsx50, jsxs as jsxs45 } from "react/jsx-runtime";
3834
+ import { jsx as jsx51, jsxs as jsxs46 } from "react/jsx-runtime";
3821
3835
  var pad = (n) => String(n).padStart(2, "0");
3822
3836
  function usePopPos3(open, ref, estH, estW) {
3823
- const [pos, setPos] = React22.useState(null);
3824
- React22.useLayoutEffect(() => {
3837
+ const [pos, setPos] = React23.useState(null);
3838
+ React23.useLayoutEffect(() => {
3825
3839
  if (!open || !ref.current) {
3826
3840
  setPos(null);
3827
3841
  return;
@@ -3867,9 +3881,9 @@ function ClockFace({ value = "09:00", onChange }) {
3867
3881
  if (isNaN(m)) m = 0;
3868
3882
  const pm = h24 >= 12;
3869
3883
  const h12 = h24 % 12 === 0 ? 12 : h24 % 12;
3870
- const [mode2, setMode] = React22.useState("h");
3871
- const faceRef = React22.useRef(null);
3872
- const dragging = React22.useRef(false);
3884
+ const [mode2, setMode] = React23.useState("h");
3885
+ const faceRef = React23.useRef(null);
3886
+ const dragging = React23.useRef(false);
3873
3887
  const set = (h, mm, isPm) => onChange((isPm ? h % 12 + 12 : h % 12) + ":" + pad(mm));
3874
3888
  const R = 108, NR = 80;
3875
3889
  const nums = mode2 === "h" ? Array.from({ length: 12 }, (_, i) => i + 1) : Array.from({ length: 12 }, (_, i) => i * 5);
@@ -3904,12 +3918,12 @@ function ClockFace({ value = "09:00", onChange }) {
3904
3918
  };
3905
3919
  const handAngle = mode2 === "h" ? h12 % 12 * 30 : m * 6;
3906
3920
  const minuteOff = mode2 === "m" && m % 5 !== 0;
3907
- return /* @__PURE__ */ jsxs45("div", { style: { padding: "4px 14px 14px" }, children: [
3908
- /* @__PURE__ */ jsxs45("div", { className: "fd-clock-digits", children: [
3909
- /* @__PURE__ */ jsx50("button", { type: "button", className: "fd-clock-digit" + (mode2 === "h" ? " is-active" : ""), onClick: () => setMode("h"), children: pad(h12) }),
3910
- /* @__PURE__ */ jsx50("span", { style: { fontSize: 24, fontWeight: 700, color: "var(--text-muted)" }, children: ":" }),
3911
- /* @__PURE__ */ jsx50("button", { type: "button", className: "fd-clock-digit" + (mode2 === "m" ? " is-active" : ""), onClick: () => setMode("m"), children: pad(m) }),
3912
- /* @__PURE__ */ jsx50("span", { className: "fd-stack", style: { gap: 3, marginLeft: 8 }, children: ["AM", "PM"].map((ap) => /* @__PURE__ */ jsx50(
3921
+ return /* @__PURE__ */ jsxs46("div", { style: { padding: "4px 14px 14px" }, children: [
3922
+ /* @__PURE__ */ jsxs46("div", { className: "fd-clock-digits", children: [
3923
+ /* @__PURE__ */ jsx51("button", { type: "button", className: "fd-clock-digit" + (mode2 === "h" ? " is-active" : ""), onClick: () => setMode("h"), children: pad(h12) }),
3924
+ /* @__PURE__ */ jsx51("span", { style: { fontSize: 24, fontWeight: 700, color: "var(--text-muted)" }, children: ":" }),
3925
+ /* @__PURE__ */ jsx51("button", { type: "button", className: "fd-clock-digit" + (mode2 === "m" ? " is-active" : ""), onClick: () => setMode("m"), children: pad(m) }),
3926
+ /* @__PURE__ */ jsx51("span", { className: "fd-stack", style: { gap: 3, marginLeft: 8 }, children: ["AM", "PM"].map((ap) => /* @__PURE__ */ jsx51(
3913
3927
  "button",
3914
3928
  {
3915
3929
  type: "button",
@@ -3920,13 +3934,13 @@ function ClockFace({ value = "09:00", onChange }) {
3920
3934
  ap
3921
3935
  )) })
3922
3936
  ] }),
3923
- /* @__PURE__ */ jsxs45("div", { className: "fd-clock", ref: faceRef, onPointerDown: down, onPointerMove: move, onPointerUp: upH, children: [
3924
- /* @__PURE__ */ jsx50("span", { className: "fd-clock-hand", style: { height: NR - (minuteOff ? 14 : 16), transform: "translateX(-50%) rotate(" + handAngle + "deg)", bottom: "50%" } }),
3925
- /* @__PURE__ */ jsx50("span", { className: "fd-clock-pivot" }),
3926
- minuteOff ? /* @__PURE__ */ jsx50("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,
3937
+ /* @__PURE__ */ jsxs46("div", { className: "fd-clock", ref: faceRef, onPointerDown: down, onPointerMove: move, onPointerUp: upH, children: [
3938
+ /* @__PURE__ */ jsx51("span", { className: "fd-clock-hand", style: { height: NR - (minuteOff ? 14 : 16), transform: "translateX(-50%) rotate(" + handAngle + "deg)", bottom: "50%" } }),
3939
+ /* @__PURE__ */ jsx51("span", { className: "fd-clock-pivot" }),
3940
+ minuteOff ? /* @__PURE__ */ jsx51("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,
3927
3941
  nums.map((n) => {
3928
3942
  const a = angleOf(n) * Math.PI / 180;
3929
- return /* @__PURE__ */ jsx50(
3943
+ return /* @__PURE__ */ jsx51(
3930
3944
  "span",
3931
3945
  {
3932
3946
  className: "fd-clock-num" + (n === selNum || mode2 === "m" && n === Math.round(m / 5) * 5 % 60 && m % 5 === 0 ? " is-sel" : ""),
@@ -3937,16 +3951,17 @@ function ClockFace({ value = "09:00", onChange }) {
3937
3951
  );
3938
3952
  })
3939
3953
  ] }),
3940
- /* @__PURE__ */ jsx50("div", { className: "fd-row", style: { justifyContent: "center", gap: 6 }, children: /* @__PURE__ */ jsx50("span", { className: "fd-body-sm fd-muted", children: mode2 === "h" ? "Pick the hour \u2014 drag or tap" : "Now the minutes" }) })
3954
+ /* @__PURE__ */ jsx51("div", { className: "fd-row", style: { justifyContent: "center", gap: 6 }, children: /* @__PURE__ */ jsx51("span", { className: "fd-body-sm fd-muted", children: mode2 === "h" ? "Pick the hour \u2014 drag or tap" : "Now the minutes" }) })
3941
3955
  ] });
3942
3956
  }
3943
- function TimePicker({ label, help, error, required = false, disabled = false, value = "", onChange, placeholder = "Pick a time", className = "", style }) {
3944
- const [open, setOpen] = React22.useState(false);
3945
- const rootRef = React22.useRef(null);
3946
- const boxRef = React22.useRef(null);
3947
- const popRef = React22.useRef(null);
3957
+ function TimePicker({ label, help, error, required = false, disabled = false, value = "", onChange, placeholder = "Pick a time", id, className = "", style }) {
3958
+ const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
3959
+ const [open, setOpen] = React23.useState(false);
3960
+ const rootRef = React23.useRef(null);
3961
+ const boxRef = React23.useRef(null);
3962
+ const popRef = React23.useRef(null);
3948
3963
  const pos = usePopPos3(open, boxRef, 420, 262);
3949
- React22.useEffect(() => {
3964
+ React23.useEffect(() => {
3950
3965
  if (!open) return;
3951
3966
  const away = (e) => {
3952
3967
  if (rootRef.current && rootRef.current.contains(e.target)) return;
@@ -3971,17 +3986,16 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
3971
3986
  const toggle = () => {
3972
3987
  if (!disabled) setOpen(!open);
3973
3988
  };
3974
- return /* @__PURE__ */ jsxs45("div", { className: ["fd-field", "fd-popfield", open ? "is-open" : "", className].filter(Boolean).join(" "), style, ref: rootRef, children: [
3975
- label ? /* @__PURE__ */ jsxs45("label", { className: "fd-field-label", onClick: toggle, children: [
3976
- label,
3977
- required ? /* @__PURE__ */ jsx50("span", { className: "fd-field-req", children: "*" }) : null
3978
- ] }) : null,
3979
- /* @__PURE__ */ jsxs45("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: [
3980
- /* @__PURE__ */ jsx50("span", { className: "fd-input-icon", children: /* @__PURE__ */ jsx50("i", { className: "ph ph-clock", "aria-hidden": "true" }) }),
3981
- /* @__PURE__ */ jsx50(
3989
+ return /* @__PURE__ */ jsxs46("div", { className: ["fd-field", "fd-popfield", open ? "is-open" : "", className].filter(Boolean).join(" "), style, ref: rootRef, children: [
3990
+ label ? /* @__PURE__ */ jsx51(FieldLabel, { id: labelId, required, onClick: toggle, children: label }) : null,
3991
+ /* @__PURE__ */ jsxs46("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: [
3992
+ /* @__PURE__ */ jsx51("span", { className: "fd-input-icon", children: /* @__PURE__ */ jsx51("i", { className: "ph ph-clock", "aria-hidden": "true" }) }),
3993
+ /* @__PURE__ */ jsx51(
3982
3994
  "button",
3983
3995
  {
3984
3996
  type: "button",
3997
+ id: fieldId,
3998
+ "aria-labelledby": ariaLabelledBy,
3985
3999
  disabled,
3986
4000
  onKeyDown: (e) => {
3987
4001
  if (e.key === "Enter" || e.key === " ") {
@@ -3993,13 +4007,13 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
3993
4007
  children: disp() || placeholder
3994
4008
  }
3995
4009
  ),
3996
- /* @__PURE__ */ jsx50("span", { className: "fd-select-caret", children: /* @__PURE__ */ jsx50("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
4010
+ /* @__PURE__ */ jsx51("span", { className: "fd-select-caret", children: /* @__PURE__ */ jsx51("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
3997
4011
  ] }),
3998
4012
  open && pos ? createPortal7(
3999
- /* @__PURE__ */ jsxs45("div", { className: "fd-pop" + (pos.up ? " is-up" : ""), ref: popRef, style: popStyle3(pos, { width: 262, minWidth: 0, zIndex: 130 }), children: [
4000
- /* @__PURE__ */ jsx50(ClockFace, { value: value || "09:00", onChange: (v) => onChange && onChange({ target: { value: v } }) }),
4001
- /* @__PURE__ */ jsxs45("div", { className: "fd-cal-foot", style: { margin: "0 14px 12px", paddingTop: 10 }, children: [
4002
- /* @__PURE__ */ jsx50(
4013
+ /* @__PURE__ */ jsxs46("div", { className: "fd-pop" + (pos.up ? " is-up" : ""), ref: popRef, style: popStyle3(pos, { width: 262, minWidth: 0, zIndex: 130 }), children: [
4014
+ /* @__PURE__ */ jsx51(ClockFace, { value: value || "09:00", onChange: (v) => onChange && onChange({ target: { value: v } }) }),
4015
+ /* @__PURE__ */ jsxs46("div", { className: "fd-cal-foot", style: { margin: "0 14px 12px", paddingTop: 10 }, children: [
4016
+ /* @__PURE__ */ jsx51(
4003
4017
  "button",
4004
4018
  {
4005
4019
  type: "button",
@@ -4012,22 +4026,22 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
4012
4026
  children: "Now"
4013
4027
  }
4014
4028
  ),
4015
- /* @__PURE__ */ jsx50("span", { style: { flex: 1 } }),
4016
- /* @__PURE__ */ jsx50("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", onClick: () => setOpen(false), children: "Done" })
4029
+ /* @__PURE__ */ jsx51("span", { style: { flex: 1 } }),
4030
+ /* @__PURE__ */ jsx51("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", onClick: () => setOpen(false), children: "Done" })
4017
4031
  ] })
4018
4032
  ] }),
4019
4033
  document.body
4020
4034
  ) : null,
4021
- error ? /* @__PURE__ */ jsxs45("span", { className: "fd-field-error", children: [
4022
- /* @__PURE__ */ jsx50("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
4035
+ error ? /* @__PURE__ */ jsxs46("span", { className: "fd-field-error", children: [
4036
+ /* @__PURE__ */ jsx51("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
4023
4037
  error
4024
- ] }) : help ? /* @__PURE__ */ jsx50("span", { className: "fd-field-help", children: help }) : null
4038
+ ] }) : help ? /* @__PURE__ */ jsx51("span", { className: "fd-field-help", children: help }) : null
4025
4039
  ] });
4026
4040
  }
4027
4041
 
4028
4042
  // src/components/forms/Slider.tsx
4029
- import * as React23 from "react";
4030
- import { jsx as jsx51, jsxs as jsxs46 } from "react/jsx-runtime";
4043
+ import * as React24 from "react";
4044
+ import { jsx as jsx52, jsxs as jsxs47 } from "react/jsx-runtime";
4031
4045
  function Slider({
4032
4046
  label,
4033
4047
  min = 0,
@@ -4038,23 +4052,27 @@ function Slider({
4038
4052
  format = (v) => String(v),
4039
4053
  showChip = true,
4040
4054
  help,
4055
+ id,
4056
+ "aria-label": ariaLabel,
4041
4057
  className = "",
4042
4058
  ...rest
4043
4059
  }) {
4044
- const [dragging, setDragging] = React23.useState(false);
4060
+ const fieldId = useFieldId(id);
4061
+ const [dragging, setDragging] = React24.useState(false);
4045
4062
  const v = value === void 0 ? min : Number(value);
4046
4063
  const pct = max === min ? 0 : (v - min) / (max - min) * 100;
4047
- return /* @__PURE__ */ jsxs46("div", { className: ["fd-field", className].filter(Boolean).join(" "), children: [
4048
- label ? /* @__PURE__ */ jsxs46("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
4049
- /* @__PURE__ */ jsx51("span", { className: "fd-field-label", children: label }),
4050
- /* @__PURE__ */ jsx51("span", { className: "fd-num", style: { color: "var(--text-2)" }, children: format(v) })
4064
+ return /* @__PURE__ */ jsxs47("div", { className: ["fd-field", className].filter(Boolean).join(" "), children: [
4065
+ label ? /* @__PURE__ */ jsxs47("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
4066
+ /* @__PURE__ */ jsx52(FieldLabel, { htmlFor: fieldId, children: label }),
4067
+ /* @__PURE__ */ jsx52("span", { className: "fd-num", style: { color: "var(--text-2)" }, children: format(v) })
4051
4068
  ] }) : null,
4052
- /* @__PURE__ */ jsxs46("div", { className: "fd-slider", children: [
4053
- /* @__PURE__ */ jsx51("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
4054
- showChip && dragging ? /* @__PURE__ */ jsx51("span", { className: "fd-slider-chip", style: { left: pct + "%" }, children: format(v) }) : null,
4055
- /* @__PURE__ */ jsx51(
4069
+ /* @__PURE__ */ jsxs47("div", { className: "fd-slider", children: [
4070
+ /* @__PURE__ */ jsx52("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
4071
+ showChip && dragging ? /* @__PURE__ */ jsx52("span", { className: "fd-slider-chip", style: { left: pct + "%" }, children: format(v) }) : null,
4072
+ /* @__PURE__ */ jsx52(
4056
4073
  "input",
4057
4074
  {
4075
+ id: fieldId,
4058
4076
  type: "range",
4059
4077
  min,
4060
4078
  max,
@@ -4064,18 +4082,18 @@ function Slider({
4064
4082
  onPointerDown: () => setDragging(true),
4065
4083
  onPointerUp: () => setDragging(false),
4066
4084
  onBlur: () => setDragging(false),
4067
- "aria-label": label,
4085
+ "aria-label": ariaLabel,
4068
4086
  ...rest
4069
4087
  }
4070
4088
  )
4071
4089
  ] }),
4072
- help ? /* @__PURE__ */ jsx51("span", { className: "fd-field-help", children: help }) : null
4090
+ help ? /* @__PURE__ */ jsx52("span", { className: "fd-field-help", children: help }) : null
4073
4091
  ] });
4074
4092
  }
4075
4093
 
4076
4094
  // src/components/forms/RangeSlider.tsx
4077
- import * as React24 from "react";
4078
- import { jsx as jsx52, jsxs as jsxs47 } from "react/jsx-runtime";
4095
+ import * as React25 from "react";
4096
+ import { jsx as jsx53, jsxs as jsxs48 } from "react/jsx-runtime";
4079
4097
  function RangeSlider({
4080
4098
  label,
4081
4099
  min = 0,
@@ -4094,9 +4112,9 @@ function RangeSlider({
4094
4112
  }) {
4095
4113
  const fmt2 = format || ((v) => String(v));
4096
4114
  const [a, b] = value || [min, max];
4097
- const [drag, setDrag] = React24.useState(null);
4098
- const [focus, setFocus] = React24.useState(null);
4099
- const railRef = React24.useRef(null);
4115
+ const [drag, setDrag] = React25.useState(null);
4116
+ const [focus, setFocus] = React25.useState(null);
4117
+ const railRef = React25.useRef(null);
4100
4118
  const pct = (v) => max === min ? 0 : (v - min) / (max - min) * 100;
4101
4119
  const clampPair = (i, v) => {
4102
4120
  v = Math.min(max, Math.max(min, Math.round(v / step) * step));
@@ -4111,7 +4129,7 @@ function RangeSlider({
4111
4129
  const r = railRef.current.getBoundingClientRect();
4112
4130
  return min + Math.min(1, Math.max(0, (e.clientX - r.left) / r.width)) * (max - min);
4113
4131
  };
4114
- React24.useEffect(() => {
4132
+ React25.useEffect(() => {
4115
4133
  if (drag === null) return;
4116
4134
  const mv = (e) => onChange && onChange(clampPair(drag, fromEvent(e)));
4117
4135
  const upH = () => setDrag(null);
@@ -4132,7 +4150,7 @@ function RangeSlider({
4132
4150
  };
4133
4151
  const thin = S.length > 7 ? Math.ceil(S.length / 5) : 1;
4134
4152
  const pair = value || [S[0].value, S[S.length - 1].value];
4135
- return /* @__PURE__ */ jsx52(
4153
+ return /* @__PURE__ */ jsx53(
4136
4154
  RangeSlider,
4137
4155
  {
4138
4156
  ...rest,
@@ -4180,23 +4198,23 @@ function RangeSlider({
4180
4198
  };
4181
4199
  const showChip = (i) => drag === i || focus === i;
4182
4200
  const hasLabels = marks.some((m) => m.label);
4183
- return /* @__PURE__ */ jsxs47("div", { className: ["fd-field", className].filter(Boolean).join(" "), ...rest, children: [
4184
- label ? /* @__PURE__ */ jsxs47("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
4185
- /* @__PURE__ */ jsx52("span", { className: "fd-field-label", children: label }),
4186
- /* @__PURE__ */ jsxs47("span", { className: "fd-num", style: { color: "var(--text-2)" }, children: [
4201
+ return /* @__PURE__ */ jsxs48("div", { className: ["fd-field", className].filter(Boolean).join(" "), ...rest, children: [
4202
+ label ? /* @__PURE__ */ jsxs48("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
4203
+ /* @__PURE__ */ jsx53("span", { className: "fd-field-label", children: label }),
4204
+ /* @__PURE__ */ jsxs48("span", { className: "fd-num", style: { color: "var(--text-2)" }, children: [
4187
4205
  fmt2(a),
4188
4206
  " \u2013 ",
4189
4207
  fmt2(b)
4190
4208
  ] })
4191
4209
  ] }) : null,
4192
- /* @__PURE__ */ jsxs47("div", { className: "fd-range" + (hasLabels ? " has-labels" : ""), onPointerDown: onRailDown, children: [
4193
- /* @__PURE__ */ jsx52("span", { className: "fd-range-rail", ref: railRef }),
4194
- /* @__PURE__ */ jsx52("span", { className: "fd-range-fill", style: { left: pct(a) + "%", width: pct(b) - pct(a) + "%" } }),
4195
- marks.map((m) => /* @__PURE__ */ jsxs47(React24.Fragment, { children: [
4196
- /* @__PURE__ */ jsx52("span", { className: "fd-range-mark" + (m.value >= a && m.value <= b ? " is-in" : ""), style: { left: pct(m.value) + "%" } }),
4197
- m.label ? /* @__PURE__ */ jsx52("span", { className: "fd-range-mark-label", style: { left: pct(m.value) + "%" }, children: m.label }) : null
4210
+ /* @__PURE__ */ jsxs48("div", { className: "fd-range" + (hasLabels ? " has-labels" : ""), onPointerDown: onRailDown, children: [
4211
+ /* @__PURE__ */ jsx53("span", { className: "fd-range-rail", ref: railRef }),
4212
+ /* @__PURE__ */ jsx53("span", { className: "fd-range-fill", style: { left: pct(a) + "%", width: pct(b) - pct(a) + "%" } }),
4213
+ marks.map((m) => /* @__PURE__ */ jsxs48(React25.Fragment, { children: [
4214
+ /* @__PURE__ */ jsx53("span", { className: "fd-range-mark" + (m.value >= a && m.value <= b ? " is-in" : ""), style: { left: pct(m.value) + "%" } }),
4215
+ m.label ? /* @__PURE__ */ jsx53("span", { className: "fd-range-mark-label", style: { left: pct(m.value) + "%" }, children: m.label }) : null
4198
4216
  ] }, m.value)),
4199
- [a, b].map((v, i) => /* @__PURE__ */ jsx52(
4217
+ [a, b].map((v, i) => /* @__PURE__ */ jsx53(
4200
4218
  "span",
4201
4219
  {
4202
4220
  className: "fd-range-thumb" + (drag === i ? " is-drag" : ""),
@@ -4211,18 +4229,18 @@ function RangeSlider({
4211
4229
  onKeyDown: key(i),
4212
4230
  onFocus: () => setFocus(i),
4213
4231
  onBlur: () => setFocus(null),
4214
- children: /* @__PURE__ */ jsx52("span", { className: "fd-range-chip", style: { opacity: showChip(i) ? 1 : void 0 }, children: fmt2(v) })
4232
+ children: /* @__PURE__ */ jsx53("span", { className: "fd-range-chip", style: { opacity: showChip(i) ? 1 : void 0 }, children: fmt2(v) })
4215
4233
  },
4216
4234
  i
4217
4235
  ))
4218
4236
  ] }),
4219
- help ? /* @__PURE__ */ jsx52("span", { className: "fd-field-help", children: help }) : null
4237
+ help ? /* @__PURE__ */ jsx53("span", { className: "fd-field-help", children: help }) : null
4220
4238
  ] });
4221
4239
  }
4222
4240
 
4223
4241
  // src/components/forms/Dropzone.tsx
4224
- import * as React25 from "react";
4225
- import { jsx as jsx53, jsxs as jsxs48 } from "react/jsx-runtime";
4242
+ import * as React26 from "react";
4243
+ import { jsx as jsx54, jsxs as jsxs49 } from "react/jsx-runtime";
4226
4244
  function Dropzone({
4227
4245
  onFiles,
4228
4246
  onReject,
@@ -4236,8 +4254,8 @@ function Dropzone({
4236
4254
  className = "",
4237
4255
  style
4238
4256
  }) {
4239
- const [over, setOver] = React25.useState(false);
4240
- const depth = React25.useRef(0);
4257
+ const [over, setOver] = React26.useState(false);
4258
+ const depth = React26.useRef(0);
4241
4259
  const has = (e) => {
4242
4260
  const dt = e.dataTransfer;
4243
4261
  if (!dt) return false;
@@ -4267,7 +4285,7 @@ function Dropzone({
4267
4285
  if (rejected.length && onReject) onReject(rejected);
4268
4286
  if (accepted.length && onFiles) onFiles(accepted);
4269
4287
  };
4270
- return /* @__PURE__ */ jsxs48(
4288
+ return /* @__PURE__ */ jsxs49(
4271
4289
  "div",
4272
4290
  {
4273
4291
  className: ["fd-dropzone", over ? "is-over" : "", className].filter(Boolean).join(" "),
@@ -4278,10 +4296,10 @@ function Dropzone({
4278
4296
  onDrop: drop,
4279
4297
  children: [
4280
4298
  children,
4281
- over ? /* @__PURE__ */ jsx53("div", { className: "fd-dropzone-veil", "aria-hidden": "true", children: /* @__PURE__ */ jsxs48("div", { className: "fd-dropzone-card", children: [
4282
- /* @__PURE__ */ jsx53("i", { className: "ph ph-tray-arrow-down" }),
4283
- /* @__PURE__ */ jsx53("span", { className: "fd-dropzone-label", children: label }),
4284
- hint ? /* @__PURE__ */ jsx53("span", { className: "fd-dropzone-hint", children: hint }) : null
4299
+ over ? /* @__PURE__ */ jsx54("div", { className: "fd-dropzone-veil", "aria-hidden": "true", children: /* @__PURE__ */ jsxs49("div", { className: "fd-dropzone-card", children: [
4300
+ /* @__PURE__ */ jsx54("i", { className: "ph ph-tray-arrow-down" }),
4301
+ /* @__PURE__ */ jsx54("span", { className: "fd-dropzone-label", children: label }),
4302
+ hint ? /* @__PURE__ */ jsx54("span", { className: "fd-dropzone-hint", children: hint }) : null
4285
4303
  ] }) }) : null
4286
4304
  ]
4287
4305
  }
@@ -4299,9 +4317,9 @@ function FilePickButton({
4299
4317
  className = "",
4300
4318
  children
4301
4319
  }) {
4302
- const ref = React25.useRef(null);
4303
- return /* @__PURE__ */ jsxs48(React25.Fragment, { children: [
4304
- /* @__PURE__ */ jsx53(
4320
+ const ref = React26.useRef(null);
4321
+ return /* @__PURE__ */ jsxs49(React26.Fragment, { children: [
4322
+ /* @__PURE__ */ jsx54(
4305
4323
  "button",
4306
4324
  {
4307
4325
  type: "button",
@@ -4310,10 +4328,10 @@ function FilePickButton({
4310
4328
  "aria-label": label,
4311
4329
  title: label,
4312
4330
  onClick: () => ref.current && ref.current.click(),
4313
- children: children != null ? children : /* @__PURE__ */ jsx53("i", { className: "ph ph-" + icon, "aria-hidden": "true" })
4331
+ children: children != null ? children : /* @__PURE__ */ jsx54("i", { className: "ph ph-" + icon, "aria-hidden": "true" })
4314
4332
  }
4315
4333
  ),
4316
- /* @__PURE__ */ jsx53(
4334
+ /* @__PURE__ */ jsx54(
4317
4335
  "input",
4318
4336
  {
4319
4337
  ref,
@@ -4333,10 +4351,10 @@ function FilePickButton({
4333
4351
  }
4334
4352
  function useStagedFiles(upload, opts) {
4335
4353
  const o = opts || {};
4336
- const [items, setItems] = React25.useState([]);
4337
- const controllers = React25.useRef({});
4354
+ const [items, setItems] = React26.useState([]);
4355
+ const controllers = React26.useRef({});
4338
4356
  const patch = (id, next) => setItems((list) => list.map((f) => f.id === id ? Object.assign({}, f, next) : f));
4339
- const run = React25.useCallback((att) => {
4357
+ const run = React26.useCallback((att) => {
4340
4358
  if (!upload) return;
4341
4359
  const ac = typeof AbortController !== "undefined" ? new AbortController() : null;
4342
4360
  controllers.current[att.id] = ac;
@@ -4353,14 +4371,14 @@ function useStagedFiles(upload, opts) {
4353
4371
  delete controllers.current[att.id];
4354
4372
  });
4355
4373
  }, [upload]);
4356
- const add = React25.useCallback((files) => {
4374
+ const add = React26.useCallback((files) => {
4357
4375
  if (!upload) return [];
4358
4376
  const atts = Array.from(files).map((f) => toAttachment(f));
4359
4377
  setItems((list) => list.concat(atts));
4360
4378
  atts.forEach(run);
4361
4379
  return atts;
4362
4380
  }, [upload, run]);
4363
- const remove = React25.useCallback((att) => {
4381
+ const remove = React26.useCallback((att) => {
4364
4382
  const ac = controllers.current[att.id];
4365
4383
  if (ac) {
4366
4384
  try {
@@ -4371,10 +4389,10 @@ function useStagedFiles(upload, opts) {
4371
4389
  }
4372
4390
  setItems((list) => list.filter((f) => f.id !== att.id));
4373
4391
  }, []);
4374
- const retry = React25.useCallback((att) => {
4392
+ const retry = React26.useCallback((att) => {
4375
4393
  run(att);
4376
4394
  }, [run]);
4377
- const clear = React25.useCallback(() => {
4395
+ const clear = React26.useCallback(() => {
4378
4396
  Object.values(controllers.current).forEach((ac) => {
4379
4397
  try {
4380
4398
  ac && ac.abort();
@@ -4390,7 +4408,7 @@ function useStagedFiles(upload, opts) {
4390
4408
  var DropzoneKit = { useStagedFiles };
4391
4409
 
4392
4410
  // src/components/forms/FileGrid.tsx
4393
- import { jsx as jsx54, jsxs as jsxs49 } from "react/jsx-runtime";
4411
+ import { jsx as jsx55, jsxs as jsxs50 } from "react/jsx-runtime";
4394
4412
  var truncateMiddle = (name, max = 34) => {
4395
4413
  if (!name || name.length <= max) return name;
4396
4414
  const ext = /\.[A-Za-z0-9]+$/.exec(name);
@@ -4399,7 +4417,7 @@ var truncateMiddle = (name, max = 34) => {
4399
4417
  return head + "\u2026" + tail;
4400
4418
  };
4401
4419
  function Progress({ value }) {
4402
- return /* @__PURE__ */ jsx54("span", { className: "fd-file-prog", role: "progressbar", "aria-valuenow": Math.round(value), "aria-valuemin": 0, "aria-valuemax": 100, children: /* @__PURE__ */ jsx54("span", { className: "fd-file-prog-fill", style: { width: Math.max(4, Math.min(100, value)) + "%" } }) });
4420
+ return /* @__PURE__ */ jsx55("span", { className: "fd-file-prog", role: "progressbar", "aria-valuenow": Math.round(value), "aria-valuemin": 0, "aria-valuemax": 100, children: /* @__PURE__ */ jsx55("span", { className: "fd-file-prog-fill", style: { width: Math.max(4, Math.min(100, value)) + "%" } }) });
4403
4421
  }
4404
4422
  function FileChip({ file, onOpen, onRemove, onRetry, compact: compact3 = false, className = "" }) {
4405
4423
  if (!file) return null;
@@ -4408,8 +4426,8 @@ function FileChip({ file, onOpen, onRemove, onRetry, compact: compact3 = false,
4408
4426
  const thumb = file.thumb && file.thumb.url || (image ? file.blobUrl || file.url : null);
4409
4427
  const meta = file.meta || (file.size ? formatBytes(file.size) : "");
4410
4428
  const clickable = !!onOpen && !uploading;
4411
- return /* @__PURE__ */ jsxs49("div", { className: ["fd-file", compact3 ? "is-compact" : "", file.error ? "is-error" : "", uploading ? "is-uploading" : "", className].filter(Boolean).join(" "), children: [
4412
- /* @__PURE__ */ jsxs49(
4429
+ return /* @__PURE__ */ jsxs50("div", { className: ["fd-file", compact3 ? "is-compact" : "", file.error ? "is-error" : "", uploading ? "is-uploading" : "", className].filter(Boolean).join(" "), children: [
4430
+ /* @__PURE__ */ jsxs50(
4413
4431
  "button",
4414
4432
  {
4415
4433
  type: "button",
@@ -4418,16 +4436,16 @@ function FileChip({ file, onOpen, onRemove, onRetry, compact: compact3 = false,
4418
4436
  onClick: clickable ? () => onOpen(file) : void 0,
4419
4437
  title: file.name + (meta ? " \xB7 " + meta : ""),
4420
4438
  children: [
4421
- /* @__PURE__ */ jsxs49("span", { className: "fd-file-icon", children: [
4422
- thumb ? /* @__PURE__ */ jsx54("img", { src: thumb, alt: "" }) : /* @__PURE__ */ jsx54("i", { className: "ph ph-" + iconForMime(file.mime, file.name), "aria-hidden": "true" }),
4423
- (file.mime || "").startsWith("video/") ? /* @__PURE__ */ jsx54("i", { className: "ph ph-play fd-file-play", "aria-hidden": "true" }) : null
4439
+ /* @__PURE__ */ jsxs50("span", { className: "fd-file-icon", children: [
4440
+ thumb ? /* @__PURE__ */ jsx55("img", { src: thumb, alt: "" }) : /* @__PURE__ */ jsx55("i", { className: "ph ph-" + iconForMime(file.mime, file.name), "aria-hidden": "true" }),
4441
+ (file.mime || "").startsWith("video/") ? /* @__PURE__ */ jsx55("i", { className: "ph ph-play fd-file-play", "aria-hidden": "true" }) : null
4424
4442
  ] }),
4425
- /* @__PURE__ */ jsxs49("span", { className: "fd-file-text", children: [
4426
- /* @__PURE__ */ jsx54("span", { className: "fd-file-name", children: truncateMiddle(file.name, compact3 ? 26 : 40) }),
4427
- /* @__PURE__ */ jsx54("span", { className: "fd-file-meta", children: file.error ? /* @__PURE__ */ jsxs49("span", { className: "fd-file-err", children: [
4428
- /* @__PURE__ */ jsx54("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
4443
+ /* @__PURE__ */ jsxs50("span", { className: "fd-file-text", children: [
4444
+ /* @__PURE__ */ jsx55("span", { className: "fd-file-name", children: truncateMiddle(file.name, compact3 ? 26 : 40) }),
4445
+ /* @__PURE__ */ jsx55("span", { className: "fd-file-meta", children: file.error ? /* @__PURE__ */ jsxs50("span", { className: "fd-file-err", children: [
4446
+ /* @__PURE__ */ jsx55("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
4429
4447
  file.error
4430
- ] }) : uploading ? /* @__PURE__ */ jsxs49("span", { className: "fd-tabular", children: [
4448
+ ] }) : uploading ? /* @__PURE__ */ jsxs50("span", { className: "fd-tabular", children: [
4431
4449
  Math.round(file.progress),
4432
4450
  "% uploaded"
4433
4451
  ] }) : meta })
@@ -4435,29 +4453,29 @@ function FileChip({ file, onOpen, onRemove, onRetry, compact: compact3 = false,
4435
4453
  ]
4436
4454
  }
4437
4455
  ),
4438
- uploading ? /* @__PURE__ */ jsx54(Progress, { value: file.progress }) : null,
4439
- file.error && onRetry ? /* @__PURE__ */ jsx54("button", { type: "button", className: "fd-file-act", onClick: () => onRetry(file), "aria-label": "Retry upload of " + file.name, children: /* @__PURE__ */ jsx54("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
4440
- onRemove ? /* @__PURE__ */ jsx54("button", { type: "button", className: "fd-file-act", onClick: () => onRemove(file), "aria-label": "Remove " + file.name, children: /* @__PURE__ */ jsx54("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
4456
+ uploading ? /* @__PURE__ */ jsx55(Progress, { value: file.progress }) : null,
4457
+ file.error && onRetry ? /* @__PURE__ */ jsx55("button", { type: "button", className: "fd-file-act", onClick: () => onRetry(file), "aria-label": "Retry upload of " + file.name, children: /* @__PURE__ */ jsx55("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
4458
+ onRemove ? /* @__PURE__ */ jsx55("button", { type: "button", className: "fd-file-act", onClick: () => onRemove(file), "aria-label": "Remove " + file.name, children: /* @__PURE__ */ jsx55("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
4441
4459
  ] });
4442
4460
  }
4443
4461
  function FileTile({ file, onOpen, onRemove, maxHeight = 200, className = "" }) {
4444
4462
  if (!file) return null;
4445
4463
  const src = file.thumb && file.thumb.url || file.blobUrl || file.url;
4446
4464
  const uploading = file.progress != null && file.progress < 100 && !file.error;
4447
- return /* @__PURE__ */ jsxs49("figure", { className: ["fd-tile", uploading ? "is-uploading" : "", file.error ? "is-error" : "", className].filter(Boolean).join(" "), children: [
4448
- /* @__PURE__ */ jsx54("button", { type: "button", className: "fd-tile-btn", onClick: onOpen ? () => onOpen(file) : void 0, disabled: !onOpen, children: src ? /* @__PURE__ */ jsx54("img", { src, alt: file.name || "", style: { maxHeight }, loading: "lazy" }) : /* @__PURE__ */ jsx54("span", { className: "fd-tile-fallback", children: /* @__PURE__ */ jsx54("i", { className: "ph ph-" + iconForMime(file.mime, file.name), "aria-hidden": "true" }) }) }),
4449
- uploading ? /* @__PURE__ */ jsx54(Progress, { value: file.progress }) : null,
4450
- file.error ? /* @__PURE__ */ jsxs49("figcaption", { className: "fd-tile-err", children: [
4451
- /* @__PURE__ */ jsx54("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
4465
+ return /* @__PURE__ */ jsxs50("figure", { className: ["fd-tile", uploading ? "is-uploading" : "", file.error ? "is-error" : "", className].filter(Boolean).join(" "), children: [
4466
+ /* @__PURE__ */ jsx55("button", { type: "button", className: "fd-tile-btn", onClick: onOpen ? () => onOpen(file) : void 0, disabled: !onOpen, children: src ? /* @__PURE__ */ jsx55("img", { src, alt: file.name || "", style: { maxHeight }, loading: "lazy" }) : /* @__PURE__ */ jsx55("span", { className: "fd-tile-fallback", children: /* @__PURE__ */ jsx55("i", { className: "ph ph-" + iconForMime(file.mime, file.name), "aria-hidden": "true" }) }) }),
4467
+ uploading ? /* @__PURE__ */ jsx55(Progress, { value: file.progress }) : null,
4468
+ file.error ? /* @__PURE__ */ jsxs50("figcaption", { className: "fd-tile-err", children: [
4469
+ /* @__PURE__ */ jsx55("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
4452
4470
  file.error
4453
4471
  ] }) : null,
4454
- onRemove ? /* @__PURE__ */ jsx54("button", { type: "button", className: "fd-tile-x", onClick: () => onRemove(file), "aria-label": "Remove " + file.name, children: /* @__PURE__ */ jsx54("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
4472
+ onRemove ? /* @__PURE__ */ jsx55("button", { type: "button", className: "fd-tile-x", onClick: () => onRemove(file), "aria-label": "Remove " + file.name, children: /* @__PURE__ */ jsx55("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
4455
4473
  ] });
4456
4474
  }
4457
4475
  function FileStrip({ files = [], size = 68, onOpen, onRemove, onRetry, className = "" }) {
4458
4476
  const list = files.filter(Boolean);
4459
4477
  if (!list.length) return null;
4460
- return /* @__PURE__ */ jsx54("div", { className: ["fd-filestrip", "fd-scrollbar", className].filter(Boolean).join(" "), style: { "--fd-cell": size + "px" }, children: list.map((f) => /* @__PURE__ */ jsx54(FileCell, { file: f, onOpen, onRemove, onRetry }, f.id || f.name)) });
4478
+ return /* @__PURE__ */ jsx55("div", { className: ["fd-filestrip", "fd-scrollbar", className].filter(Boolean).join(" "), style: { "--fd-cell": size + "px" }, children: list.map((f) => /* @__PURE__ */ jsx55(FileCell, { file: f, onOpen, onRemove, onRetry }, f.id || f.name)) });
4461
4479
  }
4462
4480
  var shortName = (name, keep = 5) => {
4463
4481
  const s = String(name || "file");
@@ -4471,19 +4489,19 @@ function FileCell({ file, onOpen, onRemove, onRetry }) {
4471
4489
  const image = isImage(file.mime, file.name);
4472
4490
  const thumb = file.thumb && file.thumb.url || (image ? file.blobUrl || file.url : null);
4473
4491
  const label = file.name + (file.size ? " \xB7 " + formatBytes(file.size) : "");
4474
- return /* @__PURE__ */ jsxs49("div", { className: ["fd-cell", file.error ? "is-error" : "", uploading ? "is-uploading" : ""].filter(Boolean).join(" "), title: file.error ? file.name + " \u2014 " + file.error : label, children: [
4475
- /* @__PURE__ */ jsxs49("button", { type: "button", className: "fd-cell-main", onClick: onOpen ? () => onOpen(file) : void 0, disabled: !onOpen || uploading, "aria-label": "Open " + file.name, children: [
4476
- thumb ? /* @__PURE__ */ jsx54("img", { src: thumb, alt: "" }) : /* @__PURE__ */ jsxs49("span", { className: "fd-cell-doc", children: [
4477
- /* @__PURE__ */ jsx54("i", { className: "ph ph-" + iconForMime(file.mime, file.name), "aria-hidden": "true" }),
4478
- /* @__PURE__ */ jsx54("span", { className: "fd-cell-name", children: shortName(file.name) }),
4479
- /* @__PURE__ */ jsx54("span", { className: "fd-cell-size", children: file.meta || formatBytes(file.size) })
4492
+ return /* @__PURE__ */ jsxs50("div", { className: ["fd-cell", file.error ? "is-error" : "", uploading ? "is-uploading" : ""].filter(Boolean).join(" "), title: file.error ? file.name + " \u2014 " + file.error : label, children: [
4493
+ /* @__PURE__ */ jsxs50("button", { type: "button", className: "fd-cell-main", onClick: onOpen ? () => onOpen(file) : void 0, disabled: !onOpen || uploading, "aria-label": "Open " + file.name, children: [
4494
+ thumb ? /* @__PURE__ */ jsx55("img", { src: thumb, alt: "" }) : /* @__PURE__ */ jsxs50("span", { className: "fd-cell-doc", children: [
4495
+ /* @__PURE__ */ jsx55("i", { className: "ph ph-" + iconForMime(file.mime, file.name), "aria-hidden": "true" }),
4496
+ /* @__PURE__ */ jsx55("span", { className: "fd-cell-name", children: shortName(file.name) }),
4497
+ /* @__PURE__ */ jsx55("span", { className: "fd-cell-size", children: file.meta || formatBytes(file.size) })
4480
4498
  ] }),
4481
- (file.mime || "").startsWith("video/") ? /* @__PURE__ */ jsx54("i", { className: "ph ph-play fd-cell-play", "aria-hidden": "true" }) : null
4499
+ (file.mime || "").startsWith("video/") ? /* @__PURE__ */ jsx55("i", { className: "ph ph-play fd-cell-play", "aria-hidden": "true" }) : null
4482
4500
  ] }),
4483
- uploading ? /* @__PURE__ */ jsx54(Progress, { value: file.progress }) : null,
4484
- file.error ? /* @__PURE__ */ jsx54("span", { className: "fd-cell-err", "aria-hidden": "true", children: /* @__PURE__ */ jsx54("i", { className: "ph ph-warning-circle" }) }) : null,
4485
- file.error && onRetry ? /* @__PURE__ */ jsx54("button", { type: "button", className: "fd-cell-x is-retry", onClick: () => onRetry(file), "aria-label": "Retry upload of " + file.name, children: /* @__PURE__ */ jsx54("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
4486
- onRemove ? /* @__PURE__ */ jsx54("button", { type: "button", className: "fd-cell-x", onClick: () => onRemove(file), "aria-label": "Remove " + file.name, children: /* @__PURE__ */ jsx54("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
4501
+ uploading ? /* @__PURE__ */ jsx55(Progress, { value: file.progress }) : null,
4502
+ file.error ? /* @__PURE__ */ jsx55("span", { className: "fd-cell-err", "aria-hidden": "true", children: /* @__PURE__ */ jsx55("i", { className: "ph ph-warning-circle" }) }) : null,
4503
+ file.error && onRetry ? /* @__PURE__ */ jsx55("button", { type: "button", className: "fd-cell-x is-retry", onClick: () => onRetry(file), "aria-label": "Retry upload of " + file.name, children: /* @__PURE__ */ jsx55("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
4504
+ onRemove ? /* @__PURE__ */ jsx55("button", { type: "button", className: "fd-cell-x", onClick: () => onRemove(file), "aria-label": "Remove " + file.name, children: /* @__PURE__ */ jsx55("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
4487
4505
  ] });
4488
4506
  }
4489
4507
  function FileGrid({ files = [], onOpen, onRemove, onRetry, tiles = true, maxHeight = 200, compact: compact3 = false, className = "" }) {
@@ -4491,15 +4509,15 @@ function FileGrid({ files = [], onOpen, onRemove, onRetry, tiles = true, maxHeig
4491
4509
  if (!list.length) return null;
4492
4510
  const pics = tiles ? list.filter((f) => isImage(f.mime, f.name)) : [];
4493
4511
  const rest = list.filter((f) => pics.indexOf(f) === -1);
4494
- return /* @__PURE__ */ jsxs49("div", { className: ["fd-filegrid", className].filter(Boolean).join(" "), children: [
4495
- pics.length ? /* @__PURE__ */ jsx54("div", { className: "fd-filegrid-tiles", children: pics.map((f) => /* @__PURE__ */ jsx54(FileTile, { file: f, onOpen, onRemove, maxHeight }, f.id || f.name)) }) : null,
4496
- rest.length ? /* @__PURE__ */ jsx54("div", { className: "fd-filegrid-chips", children: rest.map((f) => /* @__PURE__ */ jsx54(FileChip, { file: f, onOpen, onRemove, onRetry, compact: compact3 }, f.id || f.name)) }) : null
4512
+ return /* @__PURE__ */ jsxs50("div", { className: ["fd-filegrid", className].filter(Boolean).join(" "), children: [
4513
+ pics.length ? /* @__PURE__ */ jsx55("div", { className: "fd-filegrid-tiles", children: pics.map((f) => /* @__PURE__ */ jsx55(FileTile, { file: f, onOpen, onRemove, maxHeight }, f.id || f.name)) }) : null,
4514
+ rest.length ? /* @__PURE__ */ jsx55("div", { className: "fd-filegrid-chips", children: rest.map((f) => /* @__PURE__ */ jsx55(FileChip, { file: f, onOpen, onRemove, onRetry, compact: compact3 }, f.id || f.name)) }) : null
4497
4515
  ] });
4498
4516
  }
4499
4517
 
4500
4518
  // src/components/forms/MarkdownEditor.tsx
4501
- import * as React26 from "react";
4502
- import { jsx as jsx55, jsxs as jsxs50 } from "react/jsx-runtime";
4519
+ import * as React27 from "react";
4520
+ import { jsx as jsx56, jsxs as jsxs51 } from "react/jsx-runtime";
4503
4521
  var isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent || "");
4504
4522
  var INLINE_RE = /(\*\*\*[^*\n]+\*\*\*|\*\*[^*\n]+\*\*|__[^_\n]+__|~~[^~\n]+~~|`[^`\n]+`|\*[^*\s][^*\n]*\*|(?<![A-Za-z0-9_])_[^_\s][^_\n]*_|\[[^\]\n]*\]\([^)\s\n]*\)|https?:\/\/\S+)/g;
4505
4523
  function inlineParts(text) {
@@ -4712,7 +4730,7 @@ function syncDom(root, value) {
4712
4730
  while (root.children.length > lines.length) root.removeChild(root.lastChild);
4713
4731
  }
4714
4732
  var LIST_CONT = RE_LI;
4715
- var MarkdownEditor = React26.forwardRef(function MarkdownEditor2({
4733
+ var MarkdownEditor = React27.forwardRef(function MarkdownEditor2({
4716
4734
  value = "",
4717
4735
  onChange,
4718
4736
  onSubmit,
@@ -4731,10 +4749,10 @@ var MarkdownEditor = React26.forwardRef(function MarkdownEditor2({
4731
4749
  className = "",
4732
4750
  id
4733
4751
  }, ref) {
4734
- const boxRef = React26.useRef(null);
4735
- const composing = React26.useRef(false);
4736
- const pendingCaret = React26.useRef(null);
4737
- React26.useLayoutEffect(() => {
4752
+ const boxRef = React27.useRef(null);
4753
+ const composing = React27.useRef(false);
4754
+ const pendingCaret = React27.useRef(null);
4755
+ React27.useLayoutEffect(() => {
4738
4756
  const root = boxRef.current;
4739
4757
  if (!root || composing.current) return;
4740
4758
  const active = document.activeElement === root || root.contains(document.activeElement);
@@ -4743,7 +4761,7 @@ var MarkdownEditor = React26.forwardRef(function MarkdownEditor2({
4743
4761
  pendingCaret.current = null;
4744
4762
  if (active && caret != null) placeCaret(root, caret);
4745
4763
  }, [value]);
4746
- React26.useEffect(() => {
4764
+ React27.useEffect(() => {
4747
4765
  if (autoFocus && boxRef.current) boxRef.current.focus();
4748
4766
  }, [autoFocus]);
4749
4767
  const caretNow = () => {
@@ -4810,7 +4828,7 @@ var MarkdownEditor = React26.forwardRef(function MarkdownEditor2({
4810
4828
  api.replaceRange(from, to, next, from + next.length);
4811
4829
  }
4812
4830
  };
4813
- React26.useImperativeHandle(ref, () => api);
4831
+ React27.useImperativeHandle(ref, () => api);
4814
4832
  function detect(text, caret) {
4815
4833
  if (!onTrigger) return;
4816
4834
  const upto = text.slice(0, caret);
@@ -4923,8 +4941,8 @@ var MarkdownEditor = React26.forwardRef(function MarkdownEditor2({
4923
4941
  api.replaceRange(s.start, s.end, text.replace(/\r\n?/g, "\n"));
4924
4942
  };
4925
4943
  const lh = 1.55;
4926
- return /* @__PURE__ */ jsxs50("div", { className: ["fd-rme-wrap", disabled ? "is-disabled" : "", className].filter(Boolean).join(" "), children: [
4927
- /* @__PURE__ */ jsx55(
4944
+ return /* @__PURE__ */ jsxs51("div", { className: ["fd-rme-wrap", disabled ? "is-disabled" : "", className].filter(Boolean).join(" "), children: [
4945
+ /* @__PURE__ */ jsx56(
4928
4946
  "div",
4929
4947
  {
4930
4948
  ref: boxRef,
@@ -4957,15 +4975,15 @@ var MarkdownEditor = React26.forwardRef(function MarkdownEditor2({
4957
4975
  }
4958
4976
  }
4959
4977
  ),
4960
- !value ? /* @__PURE__ */ jsx55("span", { className: "fd-rme-ph", "aria-hidden": "true", children: placeholder }) : null
4978
+ !value ? /* @__PURE__ */ jsx56("span", { className: "fd-rme-ph", "aria-hidden": "true", children: placeholder }) : null
4961
4979
  ] });
4962
4980
  });
4963
4981
 
4964
4982
  // src/components/platform/AccountMenu.tsx
4965
- import * as React28 from "react";
4983
+ import * as React29 from "react";
4966
4984
 
4967
4985
  // src/kits/session.ts
4968
- import * as React27 from "react";
4986
+ import * as React28 from "react";
4969
4987
  var PERMISSION_CATALOG = [
4970
4988
  { group: "Plans", items: [
4971
4989
  { key: "plan.view", label: "View plans", detail: "Read any plan in the workspace." },
@@ -6532,8 +6550,8 @@ function roadmap(overrides) {
6532
6550
  };
6533
6551
  }
6534
6552
  function useSession() {
6535
- const [s, setS] = React27.useState(getSession);
6536
- React27.useEffect(() => subscribe(setS), []);
6553
+ const [s, setS] = React28.useState(getSession);
6554
+ React28.useEffect(() => subscribe(setS), []);
6537
6555
  return s;
6538
6556
  }
6539
6557
  var SessionKit = {
@@ -6566,7 +6584,7 @@ var SessionKit = {
6566
6584
  };
6567
6585
 
6568
6586
  // src/components/platform/AccountMenu.tsx
6569
- import { Fragment as Fragment12, jsx as jsx56, jsxs as jsxs51 } from "react/jsx-runtime";
6587
+ import { Fragment as Fragment12, jsx as jsx57, jsxs as jsxs52 } from "react/jsx-runtime";
6570
6588
  var DEFAULT_LINKS = [
6571
6589
  { id: "profile", label: "Your profile", icon: "user-circle", href: "../admin/index.html#profile" },
6572
6590
  { id: "preferences", label: "Preferences", icon: "sliders-horizontal", href: "../admin/index.html#preferences" }
@@ -6577,7 +6595,7 @@ var DEFAULT_ADMIN_LINKS = [
6577
6595
  { id: "flags", label: "Feature flags", icon: "toggle-right", href: "../admin/index.html#flags", perm: "flags.manage" }
6578
6596
  ];
6579
6597
  function Item({ item, onPick }) {
6580
- return /* @__PURE__ */ jsxs51(
6598
+ return /* @__PURE__ */ jsxs52(
6581
6599
  "button",
6582
6600
  {
6583
6601
  type: "button",
@@ -6585,9 +6603,9 @@ function Item({ item, onPick }) {
6585
6603
  className: "fd-acct-item",
6586
6604
  onClick: () => onPick(item),
6587
6605
  children: [
6588
- /* @__PURE__ */ jsx56("i", { className: "ph ph-" + item.icon, "aria-hidden": "true" }),
6589
- /* @__PURE__ */ jsx56("span", { style: { flex: 1 }, children: item.label }),
6590
- item.badge ? /* @__PURE__ */ jsx56(Badge, { tone: "neutral", children: item.badge }) : null
6606
+ /* @__PURE__ */ jsx57("i", { className: "ph ph-" + item.icon, "aria-hidden": "true" }),
6607
+ /* @__PURE__ */ jsx57("span", { style: { flex: 1 }, children: item.label }),
6608
+ item.badge ? /* @__PURE__ */ jsx57(Badge, { tone: "neutral", children: item.badge }) : null
6591
6609
  ]
6592
6610
  }
6593
6611
  );
@@ -6603,9 +6621,9 @@ function AccountMenu({
6603
6621
  ...rest
6604
6622
  }) {
6605
6623
  const session = SessionKit.useSession();
6606
- const [open, setOpen] = React28.useState(false);
6607
- const [switching, setSwitching] = React28.useState(false);
6608
- const ref = React28.useRef(null);
6624
+ const [open, setOpen] = React29.useState(false);
6625
+ const [switching, setSwitching] = React29.useState(false);
6626
+ const ref = React29.useRef(null);
6609
6627
  const user = session.user;
6610
6628
  const visibleAdmin = adminLinks.filter((l) => !l.perm || SessionKit.can(l.perm));
6611
6629
  const pick = (item) => {
@@ -6619,8 +6637,8 @@ function AccountMenu({
6619
6637
  if (onSignOut) return onSignOut();
6620
6638
  window.alert("Signed out. (Simulated \u2014 no auth provider is wired up.)");
6621
6639
  };
6622
- return /* @__PURE__ */ jsxs51(Fragment12, { children: [
6623
- /* @__PURE__ */ jsxs51(
6640
+ return /* @__PURE__ */ jsxs52(Fragment12, { children: [
6641
+ /* @__PURE__ */ jsxs52(
6624
6642
  "button",
6625
6643
  {
6626
6644
  type: "button",
@@ -6632,32 +6650,32 @@ function AccountMenu({
6632
6650
  onClick: () => setOpen((o) => !o),
6633
6651
  ...rest,
6634
6652
  children: [
6635
- /* @__PURE__ */ jsx56(Avatar, { name: user.name, size: "sm" }),
6636
- /* @__PURE__ */ jsx56("i", { className: "ph ph-caret-down", "aria-hidden": "true", style: { fontSize: 11, color: "var(--text-muted)" } })
6653
+ /* @__PURE__ */ jsx57(Avatar, { name: user.name, size: "sm" }),
6654
+ /* @__PURE__ */ jsx57("i", { className: "ph ph-caret-down", "aria-hidden": "true", style: { fontSize: 11, color: "var(--text-muted)" } })
6637
6655
  ]
6638
6656
  }
6639
6657
  ),
6640
- /* @__PURE__ */ jsx56(Popover, { open, anchorRef: ref, onClose: () => setOpen(false), placement: "bottom-end", width: 272, children: /* @__PURE__ */ jsxs51("div", { role: "menu", className: "fd-stack", style: { gap: 0 }, children: [
6641
- /* @__PURE__ */ jsxs51("div", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
6642
- /* @__PURE__ */ jsx56(Avatar, { name: user.name }),
6643
- /* @__PURE__ */ jsxs51("span", { className: "fd-stack", style: { gap: 1, minWidth: 0, flex: 1 }, children: [
6644
- /* @__PURE__ */ jsx56("span", { className: "fd-body-sm", style: { fontWeight: 700 }, children: user.name }),
6645
- /* @__PURE__ */ jsx56("span", { className: "fd-body-sm fd-muted fd-table-trunc", children: user.email })
6658
+ /* @__PURE__ */ jsx57(Popover, { open, anchorRef: ref, onClose: () => setOpen(false), placement: "bottom-end", width: 272, children: /* @__PURE__ */ jsxs52("div", { role: "menu", className: "fd-stack", style: { gap: 0 }, children: [
6659
+ /* @__PURE__ */ jsxs52("div", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
6660
+ /* @__PURE__ */ jsx57(Avatar, { name: user.name }),
6661
+ /* @__PURE__ */ jsxs52("span", { className: "fd-stack", style: { gap: 1, minWidth: 0, flex: 1 }, children: [
6662
+ /* @__PURE__ */ jsx57("span", { className: "fd-body-sm", style: { fontWeight: 700 }, children: user.name }),
6663
+ /* @__PURE__ */ jsx57("span", { className: "fd-body-sm fd-muted fd-table-trunc", children: user.email })
6646
6664
  ] })
6647
6665
  ] }),
6648
- showRoles && session.roles.length ? /* @__PURE__ */ jsx56("div", { className: "fd-row", style: { gap: 6, padding: "10px 14px", flexWrap: "wrap", borderBottom: "1px solid var(--border)" }, children: session.roles.map((r) => /* @__PURE__ */ jsx56(Badge, { tone: r.id === "owner" ? "success" : "neutral", children: r.name }, r.id)) }) : null,
6649
- /* @__PURE__ */ jsx56("div", { className: "fd-acct-group", children: links.map((l) => /* @__PURE__ */ jsx56(Item, { item: l, onPick: pick }, l.id)) }),
6650
- visibleAdmin.length ? /* @__PURE__ */ jsxs51("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: [
6651
- /* @__PURE__ */ jsx56("span", { className: "fd-overline fd-muted", style: { padding: "8px 14px 4px", display: "block" }, children: "Administration" }),
6652
- visibleAdmin.map((l) => /* @__PURE__ */ jsx56(Item, { item: l, onPick: pick }, l.id))
6666
+ showRoles && session.roles.length ? /* @__PURE__ */ jsx57("div", { className: "fd-row", style: { gap: 6, padding: "10px 14px", flexWrap: "wrap", borderBottom: "1px solid var(--border)" }, children: session.roles.map((r) => /* @__PURE__ */ jsx57(Badge, { tone: r.id === "owner" ? "success" : "neutral", children: r.name }, r.id)) }) : null,
6667
+ /* @__PURE__ */ jsx57("div", { className: "fd-acct-group", children: links.map((l) => /* @__PURE__ */ jsx57(Item, { item: l, onPick: pick }, l.id)) }),
6668
+ visibleAdmin.length ? /* @__PURE__ */ jsxs52("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: [
6669
+ /* @__PURE__ */ jsx57("span", { className: "fd-overline fd-muted", style: { padding: "8px 14px 4px", display: "block" }, children: "Administration" }),
6670
+ visibleAdmin.map((l) => /* @__PURE__ */ jsx57(Item, { item: l, onPick: pick }, l.id))
6653
6671
  ] }) : null,
6654
- allowUserSwitch ? /* @__PURE__ */ jsxs51("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: [
6655
- /* @__PURE__ */ jsxs51("button", { type: "button", role: "menuitem", className: "fd-acct-item", onClick: () => setSwitching((s) => !s), children: [
6656
- /* @__PURE__ */ jsx56("i", { className: "ph ph-user-switch", "aria-hidden": "true" }),
6657
- /* @__PURE__ */ jsx56("span", { style: { flex: 1 }, children: "View as another member" }),
6658
- /* @__PURE__ */ jsx56("i", { className: "ph ph-caret-" + (switching ? "up" : "down"), "aria-hidden": "true", style: { fontSize: 11 } })
6672
+ allowUserSwitch ? /* @__PURE__ */ jsxs52("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: [
6673
+ /* @__PURE__ */ jsxs52("button", { type: "button", role: "menuitem", className: "fd-acct-item", onClick: () => setSwitching((s) => !s), children: [
6674
+ /* @__PURE__ */ jsx57("i", { className: "ph ph-user-switch", "aria-hidden": "true" }),
6675
+ /* @__PURE__ */ jsx57("span", { style: { flex: 1 }, children: "View as another member" }),
6676
+ /* @__PURE__ */ jsx57("i", { className: "ph ph-caret-" + (switching ? "up" : "down"), "aria-hidden": "true", style: { fontSize: 11 } })
6659
6677
  ] }),
6660
- switching ? /* @__PURE__ */ jsx56("div", { className: "fd-stack", style: { gap: 0, maxHeight: 208, overflowY: "auto" }, children: session.allUsers.filter((u) => u.status === "active").map((u) => /* @__PURE__ */ jsxs51(
6678
+ switching ? /* @__PURE__ */ jsx57("div", { className: "fd-stack", style: { gap: 0, maxHeight: 208, overflowY: "auto" }, children: session.allUsers.filter((u) => u.status === "active").map((u) => /* @__PURE__ */ jsxs52(
6661
6679
  "button",
6662
6680
  {
6663
6681
  type: "button",
@@ -6669,34 +6687,34 @@ function AccountMenu({
6669
6687
  setSwitching(false);
6670
6688
  },
6671
6689
  children: [
6672
- /* @__PURE__ */ jsx56(Avatar, { name: u.name, size: "sm" }),
6673
- /* @__PURE__ */ jsxs51("span", { className: "fd-stack", style: { gap: 0, flex: 1, minWidth: 0, alignItems: "flex-start" }, children: [
6674
- /* @__PURE__ */ jsx56("span", { style: { fontWeight: u.id === user.id ? 700 : 500 }, children: u.name }),
6675
- /* @__PURE__ */ jsx56("span", { className: "fd-muted", style: { fontSize: 11.5 }, children: u.roles.join(", ") })
6690
+ /* @__PURE__ */ jsx57(Avatar, { name: u.name, size: "sm" }),
6691
+ /* @__PURE__ */ jsxs52("span", { className: "fd-stack", style: { gap: 0, flex: 1, minWidth: 0, alignItems: "flex-start" }, children: [
6692
+ /* @__PURE__ */ jsx57("span", { style: { fontWeight: u.id === user.id ? 700 : 500 }, children: u.name }),
6693
+ /* @__PURE__ */ jsx57("span", { className: "fd-muted", style: { fontSize: 11.5 }, children: u.roles.join(", ") })
6676
6694
  ] }),
6677
- u.id === user.id ? /* @__PURE__ */ jsx56("i", { className: "ph ph-check", "aria-hidden": "true", style: { color: "var(--ok-text)" } }) : null
6695
+ u.id === user.id ? /* @__PURE__ */ jsx57("i", { className: "ph ph-check", "aria-hidden": "true", style: { color: "var(--ok-text)" } }) : null
6678
6696
  ]
6679
6697
  },
6680
6698
  u.id
6681
6699
  )) }) : null
6682
6700
  ] }) : null,
6683
- /* @__PURE__ */ jsx56("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: /* @__PURE__ */ jsxs51("button", { type: "button", role: "menuitem", className: "fd-acct-item", "data-danger": "true", onClick: signOut, children: [
6684
- /* @__PURE__ */ jsx56("i", { className: "ph ph-sign-out", "aria-hidden": "true" }),
6685
- /* @__PURE__ */ jsx56("span", { style: { flex: 1 }, children: "Sign out" })
6701
+ /* @__PURE__ */ jsx57("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: /* @__PURE__ */ jsxs52("button", { type: "button", role: "menuitem", className: "fd-acct-item", "data-danger": "true", onClick: signOut, children: [
6702
+ /* @__PURE__ */ jsx57("i", { className: "ph ph-sign-out", "aria-hidden": "true" }),
6703
+ /* @__PURE__ */ jsx57("span", { style: { flex: 1 }, children: "Sign out" })
6686
6704
  ] }) })
6687
6705
  ] }) })
6688
6706
  ] });
6689
6707
  }
6690
6708
 
6691
6709
  // src/components/platform/ApiSpecBrowser.tsx
6692
- import * as React29 from "react";
6693
- import { jsx as jsx57, jsxs as jsxs52 } from "react/jsx-runtime";
6710
+ import * as React30 from "react";
6711
+ import { jsx as jsx58, jsxs as jsxs53 } from "react/jsx-runtime";
6694
6712
  var METHOD_TONE = { GET: "success", POST: "info", PATCH: "warning", PUT: "warning", DELETE: "danger" };
6695
6713
  function Json({ obj }) {
6696
- return /* @__PURE__ */ jsx57("pre", { className: "fd-json", children: JSON.stringify(obj, null, 2) });
6714
+ return /* @__PURE__ */ jsx58("pre", { className: "fd-json", children: JSON.stringify(obj, null, 2) });
6697
6715
  }
6698
6716
  function Endpoint({ s, onRequest }) {
6699
- const [tried, setTried] = React29.useState(null);
6717
+ const [tried, setTried] = React30.useState(null);
6700
6718
  const run = async () => {
6701
6719
  setTried("busy");
6702
6720
  const t0 = (window.performance || Date).now();
@@ -6707,50 +6725,50 @@ function Endpoint({ s, onRequest }) {
6707
6725
  setTried({ ms: Math.round((window.performance || Date).now() - t0), error: String(e && e.message || e) });
6708
6726
  }
6709
6727
  };
6710
- return /* @__PURE__ */ jsx57(Card, { elevation: "flat", padded: false, children: /* @__PURE__ */ jsxs52("div", { className: "fd-stack", style: { gap: 0 }, children: [
6711
- /* @__PURE__ */ jsxs52("div", { className: "fd-row", style: { gap: 10, padding: "14px 18px", flexWrap: "wrap" }, children: [
6712
- /* @__PURE__ */ jsx57(Badge, { tone: METHOD_TONE[s.method] || "neutral", children: s.method }),
6713
- /* @__PURE__ */ jsx57("code", { className: "fd-mono", style: { fontSize: 12.5, fontWeight: 600, color: "var(--text)", wordBreak: "break-all" }, children: s.path }),
6714
- s.isList ? /* @__PURE__ */ jsx57(Badge, { tone: "neutral", icon: "rows", children: "Paged list" }) : null,
6715
- /* @__PURE__ */ jsx57("span", { style: { flex: 1 } }),
6716
- /* @__PURE__ */ jsxs52("span", { className: "fd-body-sm fd-muted fd-mono", children: [
6728
+ return /* @__PURE__ */ jsx58(Card, { elevation: "flat", padded: false, children: /* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 0 }, children: [
6729
+ /* @__PURE__ */ jsxs53("div", { className: "fd-row", style: { gap: 10, padding: "14px 18px", flexWrap: "wrap" }, children: [
6730
+ /* @__PURE__ */ jsx58(Badge, { tone: METHOD_TONE[s.method] || "neutral", children: s.method }),
6731
+ /* @__PURE__ */ jsx58("code", { className: "fd-mono", style: { fontSize: 12.5, fontWeight: 600, color: "var(--text)", wordBreak: "break-all" }, children: s.path }),
6732
+ s.isList ? /* @__PURE__ */ jsx58(Badge, { tone: "neutral", icon: "rows", children: "Paged list" }) : null,
6733
+ /* @__PURE__ */ jsx58("span", { style: { flex: 1 } }),
6734
+ /* @__PURE__ */ jsxs53("span", { className: "fd-body-sm fd-muted fd-mono", children: [
6717
6735
  s.latency[0],
6718
6736
  "\u2013",
6719
6737
  s.latency[1],
6720
6738
  "ms"
6721
6739
  ] }),
6722
- /* @__PURE__ */ jsx57(Button, { size: "sm", variant: "secondary", icon: "play", loading: tried === "busy", onClick: run, children: "Try it" })
6740
+ /* @__PURE__ */ jsx58(Button, { size: "sm", variant: "secondary", icon: "play", loading: tried === "busy", onClick: run, children: "Try it" })
6723
6741
  ] }),
6724
- /* @__PURE__ */ jsxs52("div", { className: "fd-stack", style: { gap: 14, padding: "0 18px 16px" }, children: [
6725
- /* @__PURE__ */ jsxs52("div", { className: "fd-stack", style: { gap: 6 }, children: [
6726
- /* @__PURE__ */ jsx57("span", { className: "fd-body-sm", style: { fontWeight: 700 }, children: s.title }),
6727
- /* @__PURE__ */ jsx57("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: s.purpose }),
6728
- s.usedBy && s.usedBy.length ? /* @__PURE__ */ jsx57("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: s.usedBy.map((u) => /* @__PURE__ */ jsx57(Tag, { children: u }, u)) }) : null
6742
+ /* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 14, padding: "0 18px 16px" }, children: [
6743
+ /* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 6 }, children: [
6744
+ /* @__PURE__ */ jsx58("span", { className: "fd-body-sm", style: { fontWeight: 700 }, children: s.title }),
6745
+ /* @__PURE__ */ jsx58("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: s.purpose }),
6746
+ s.usedBy && s.usedBy.length ? /* @__PURE__ */ jsx58("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: s.usedBy.map((u) => /* @__PURE__ */ jsx58(Tag, { children: u }, u)) }) : null
6729
6747
  ] }),
6730
- /* @__PURE__ */ jsxs52("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(280px,1fr))", gap: 12, alignItems: "start" }, children: [
6731
- s.request ? /* @__PURE__ */ jsxs52("div", { className: "fd-stack", style: { gap: 6 }, children: [
6732
- /* @__PURE__ */ jsx57("span", { className: "fd-overline fd-muted", children: "Request body" }),
6733
- /* @__PURE__ */ jsx57(Json, { obj: s.request })
6748
+ /* @__PURE__ */ jsxs53("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(280px,1fr))", gap: 12, alignItems: "start" }, children: [
6749
+ s.request ? /* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 6 }, children: [
6750
+ /* @__PURE__ */ jsx58("span", { className: "fd-overline fd-muted", children: "Request body" }),
6751
+ /* @__PURE__ */ jsx58(Json, { obj: s.request })
6734
6752
  ] }) : null,
6735
- s.query ? /* @__PURE__ */ jsxs52("div", { className: "fd-stack", style: { gap: 6 }, children: [
6736
- /* @__PURE__ */ jsx57("span", { className: "fd-overline fd-muted", children: "Query" }),
6737
- /* @__PURE__ */ jsx57(Json, { obj: s.query })
6753
+ s.query ? /* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 6 }, children: [
6754
+ /* @__PURE__ */ jsx58("span", { className: "fd-overline fd-muted", children: "Query" }),
6755
+ /* @__PURE__ */ jsx58(Json, { obj: s.query })
6738
6756
  ] }) : null,
6739
- /* @__PURE__ */ jsxs52("div", { className: "fd-stack", style: { gap: 6 }, children: [
6740
- /* @__PURE__ */ jsx57("span", { className: "fd-overline fd-muted", children: "Response 200" }),
6741
- /* @__PURE__ */ jsx57(Json, { obj: s.response })
6757
+ /* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 6 }, children: [
6758
+ /* @__PURE__ */ jsx58("span", { className: "fd-overline fd-muted", children: "Response 200" }),
6759
+ /* @__PURE__ */ jsx58(Json, { obj: s.response })
6742
6760
  ] })
6743
6761
  ] }),
6744
- s.notes ? /* @__PURE__ */ jsx57(Flag, { tone: "info", statement: "Implementation note", cost: s.notes, actions: null }) : null,
6745
- tried && tried !== "busy" ? /* @__PURE__ */ jsxs52("div", { className: "fd-stack", style: { gap: 6 }, children: [
6746
- /* @__PURE__ */ jsxs52("span", { className: "fd-row", style: { gap: 8 }, children: [
6747
- /* @__PURE__ */ jsx57("span", { className: "fd-overline fd-muted", children: "Simulated response" }),
6748
- /* @__PURE__ */ jsxs52(Badge, { tone: tried.error ? "danger" : "success", icon: "timer", children: [
6762
+ s.notes ? /* @__PURE__ */ jsx58(Flag, { tone: "info", statement: "Implementation note", cost: s.notes, actions: null }) : null,
6763
+ tried && tried !== "busy" ? /* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 6 }, children: [
6764
+ /* @__PURE__ */ jsxs53("span", { className: "fd-row", style: { gap: 8 }, children: [
6765
+ /* @__PURE__ */ jsx58("span", { className: "fd-overline fd-muted", children: "Simulated response" }),
6766
+ /* @__PURE__ */ jsxs53(Badge, { tone: tried.error ? "danger" : "success", icon: "timer", children: [
6749
6767
  tried.ms,
6750
6768
  "ms"
6751
6769
  ] })
6752
6770
  ] }),
6753
- /* @__PURE__ */ jsx57(Json, { obj: tried.error ? { error: tried.error } : tried.data })
6771
+ /* @__PURE__ */ jsx58(Json, { obj: tried.error ? { error: tried.error } : tried.data })
6754
6772
  ] }) : null
6755
6773
  ] })
6756
6774
  ] }) });
@@ -6769,58 +6787,58 @@ function ApiSpecBrowser({
6769
6787
  className = "",
6770
6788
  ...rest
6771
6789
  }) {
6772
- const [q, setQ] = React29.useState("");
6773
- const [method, setMethod] = React29.useState(null);
6774
- const [mod, setMod] = React29.useState(null);
6775
- const [listOnly, setListOnly] = React29.useState(false);
6790
+ const [q, setQ] = React30.useState("");
6791
+ const [method, setMethod] = React30.useState(null);
6792
+ const [mod, setMod] = React30.useState(null);
6793
+ const [listOnly, setListOnly] = React30.useState(false);
6776
6794
  const activeModule = modules && modules.find((m) => m.id === mod);
6777
6795
  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())));
6778
6796
  const effGroups = groups && groups.length ? groups : [["All endpoints", spec.map((s) => s.id)]];
6779
6797
  const methods = [...new Set(spec.map((s) => s.method))];
6780
6798
  const listCount = spec.filter((s) => s.isList).length;
6781
- return /* @__PURE__ */ jsxs52("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 1100 }, ...rest, children: [
6782
- /* @__PURE__ */ jsxs52("div", { className: "fd-stack", style: { gap: 10 }, children: [
6783
- kicker ? /* @__PURE__ */ jsx57("span", { className: "fd-overline fd-muted", children: kicker }) : null,
6784
- /* @__PURE__ */ jsx57("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
6785
- lede ? /* @__PURE__ */ jsx57("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: lede }) : null
6799
+ return /* @__PURE__ */ jsxs53("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 1100 }, ...rest, children: [
6800
+ /* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 10 }, children: [
6801
+ kicker ? /* @__PURE__ */ jsx58("span", { className: "fd-overline fd-muted", children: kicker }) : null,
6802
+ /* @__PURE__ */ jsx58("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
6803
+ lede ? /* @__PURE__ */ jsx58("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: lede }) : null
6786
6804
  ] }),
6787
- modules && modules.length ? /* @__PURE__ */ jsxs52("div", { className: "fd-stack", style: { gap: 8 }, children: [
6788
- /* @__PURE__ */ jsx57("span", { className: "fd-overline fd-muted", children: "Filter by screen \u2014 every endpoint that screen depends on" }),
6789
- /* @__PURE__ */ jsxs52("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
6790
- /* @__PURE__ */ jsxs52(Tag, { icon: "stack", selected: !mod, onClick: () => setMod(null), children: [
6805
+ modules && modules.length ? /* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 8 }, children: [
6806
+ /* @__PURE__ */ jsx58("span", { className: "fd-overline fd-muted", children: "Filter by screen \u2014 every endpoint that screen depends on" }),
6807
+ /* @__PURE__ */ jsxs53("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
6808
+ /* @__PURE__ */ jsxs53(Tag, { icon: "stack", selected: !mod, onClick: () => setMod(null), children: [
6791
6809
  "All screens ",
6792
- /* @__PURE__ */ jsx57("span", { className: "fd-mono", children: spec.length })
6810
+ /* @__PURE__ */ jsx58("span", { className: "fd-mono", children: spec.length })
6793
6811
  ] }),
6794
- modules.map((m) => /* @__PURE__ */ jsxs52(Tag, { icon: m.icon, selected: mod === m.id, onClick: () => setMod(mod === m.id ? null : m.id), children: [
6812
+ modules.map((m) => /* @__PURE__ */ jsxs53(Tag, { icon: m.icon, selected: mod === m.id, onClick: () => setMod(mod === m.id ? null : m.id), children: [
6795
6813
  m.label,
6796
6814
  " ",
6797
- /* @__PURE__ */ jsx57("span", { className: "fd-mono", children: m.endpoints.length })
6815
+ /* @__PURE__ */ jsx58("span", { className: "fd-mono", children: m.endpoints.length })
6798
6816
  ] }, m.id))
6799
6817
  ] }),
6800
- activeModule ? /* @__PURE__ */ jsx57(
6818
+ activeModule ? /* @__PURE__ */ jsx58(
6801
6819
  Flag,
6802
6820
  {
6803
6821
  tone: "info",
6804
6822
  statement: activeModule.label + " calls " + activeModule.endpoints.length + " endpoints.",
6805
6823
  cost: "Integration checklist for this screen: " + activeModule.endpoints.join(", ") + ". Wire these and the screen is done.",
6806
- actions: /* @__PURE__ */ jsx57(Button, { size: "sm", variant: "ghost", icon: "x", onClick: () => setMod(null), children: "Show all screens" })
6824
+ actions: /* @__PURE__ */ jsx58(Button, { size: "sm", variant: "ghost", icon: "x", onClick: () => setMod(null), children: "Show all screens" })
6807
6825
  }
6808
6826
  ) : null
6809
6827
  ] }) : null,
6810
- sourceNote ? /* @__PURE__ */ jsx57(Flag, { tone: "info", statement: "Design-first: this page is the spec.", cost: sourceNote, actions: null }) : null,
6811
- /* @__PURE__ */ jsxs52("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
6812
- /* @__PURE__ */ jsx57(Input, { icon: "magnifying-glass", placeholder: "Find an endpoint, screen, or behavior", value: q, onChange: (e) => setQ(e.target.value), style: { width: 300 } }),
6813
- methods.map((m) => /* @__PURE__ */ jsxs52(Tag, { selected: method === m, onClick: () => setMethod(method === m ? null : m), children: [
6828
+ sourceNote ? /* @__PURE__ */ jsx58(Flag, { tone: "info", statement: "Design-first: this page is the spec.", cost: sourceNote, actions: null }) : null,
6829
+ /* @__PURE__ */ jsxs53("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
6830
+ /* @__PURE__ */ jsx58(Input, { icon: "magnifying-glass", placeholder: "Find an endpoint, screen, or behavior", value: q, onChange: (e) => setQ(e.target.value), style: { width: 300 } }),
6831
+ methods.map((m) => /* @__PURE__ */ jsxs53(Tag, { selected: method === m, onClick: () => setMethod(method === m ? null : m), children: [
6814
6832
  m,
6815
6833
  " ",
6816
- /* @__PURE__ */ jsx57("span", { className: "fd-mono", children: spec.filter((s) => s.method === m).length })
6834
+ /* @__PURE__ */ jsx58("span", { className: "fd-mono", children: spec.filter((s) => s.method === m).length })
6817
6835
  ] }, m)),
6818
- listCount ? /* @__PURE__ */ jsxs52(Tag, { icon: "rows", selected: listOnly, onClick: () => setListOnly(!listOnly), children: [
6836
+ listCount ? /* @__PURE__ */ jsxs53(Tag, { icon: "rows", selected: listOnly, onClick: () => setListOnly(!listOnly), children: [
6819
6837
  "Paged lists ",
6820
- /* @__PURE__ */ jsx57("span", { className: "fd-mono", children: listCount })
6838
+ /* @__PURE__ */ jsx58("span", { className: "fd-mono", children: listCount })
6821
6839
  ] }) : null,
6822
- /* @__PURE__ */ jsx57("span", { style: { flex: 1 } }),
6823
- /* @__PURE__ */ jsxs52("span", { className: "fd-body-sm fd-muted", children: [
6840
+ /* @__PURE__ */ jsx58("span", { style: { flex: 1 } }),
6841
+ /* @__PURE__ */ jsxs53("span", { className: "fd-body-sm fd-muted", children: [
6824
6842
  hits.length,
6825
6843
  " of ",
6826
6844
  spec.length,
@@ -6828,31 +6846,31 @@ function ApiSpecBrowser({
6828
6846
  listCount ? " \xB7 " + listCount + " paged" : ""
6829
6847
  ] })
6830
6848
  ] }),
6831
- hits.length === 0 ? /* @__PURE__ */ jsx57(Card, { elevation: "flat", children: /* @__PURE__ */ jsx57("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: "No endpoint matches those filters." }) }) : effGroups.map(([g, ids]) => {
6849
+ hits.length === 0 ? /* @__PURE__ */ jsx58(Card, { elevation: "flat", children: /* @__PURE__ */ jsx58("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: "No endpoint matches those filters." }) }) : effGroups.map(([g, ids]) => {
6832
6850
  const items = hits.filter((s) => ids.indexOf(s.id) >= 0);
6833
6851
  if (!items.length) return null;
6834
- return /* @__PURE__ */ jsxs52("div", { className: "fd-stack", style: { gap: 12 }, children: [
6835
- /* @__PURE__ */ jsx57("span", { className: "fd-label-lg", children: g }),
6836
- items.map((s) => /* @__PURE__ */ jsx57(Endpoint, { s, onRequest }, s.id))
6852
+ return /* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 12 }, children: [
6853
+ /* @__PURE__ */ jsx58("span", { className: "fd-label-lg", children: g }),
6854
+ items.map((s) => /* @__PURE__ */ jsx58(Endpoint, { s, onRequest }, s.id))
6837
6855
  ] }, g);
6838
6856
  }),
6839
- conventions && conventions.length ? /* @__PURE__ */ jsx57(Card, { title: "Cross-cutting conventions", elevation: "flat", children: /* @__PURE__ */ jsx57("div", { className: "fd-stack", style: { gap: 10 }, children: conventions.map(([k, v]) => /* @__PURE__ */ jsxs52("div", { className: "fd-row", style: { gap: 12, alignItems: "flex-start" }, children: [
6840
- /* @__PURE__ */ jsx57("span", { className: "fd-overline fd-muted", style: { width: 110, flex: "none", paddingTop: 2 }, children: k }),
6841
- /* @__PURE__ */ jsx57("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: v })
6857
+ conventions && conventions.length ? /* @__PURE__ */ jsx58(Card, { title: "Cross-cutting conventions", elevation: "flat", children: /* @__PURE__ */ jsx58("div", { className: "fd-stack", style: { gap: 10 }, children: conventions.map(([k, v]) => /* @__PURE__ */ jsxs53("div", { className: "fd-row", style: { gap: 12, alignItems: "flex-start" }, children: [
6858
+ /* @__PURE__ */ jsx58("span", { className: "fd-overline fd-muted", style: { width: 110, flex: "none", paddingTop: 2 }, children: k }),
6859
+ /* @__PURE__ */ jsx58("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: v })
6842
6860
  ] }, k)) }) }) : null,
6843
- openQuestions && openQuestions.length ? /* @__PURE__ */ jsx57(Collapsible, { icon: "list-checks", title: "Open questions before implementation", subtitle: openQuestions.length + " unresolved", children: /* @__PURE__ */ jsx57("div", { className: "fd-stack", style: { gap: 8 }, children: openQuestions.map(([id, question, why]) => /* @__PURE__ */ jsxs52("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start", padding: "8px 0", borderTop: "1px solid var(--border)" }, children: [
6844
- /* @__PURE__ */ jsx57(Badge, { tone: "danger", children: id }),
6845
- /* @__PURE__ */ jsxs52("span", { className: "fd-stack", style: { gap: 2, flex: 1 }, children: [
6846
- /* @__PURE__ */ jsx57("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: question }),
6847
- /* @__PURE__ */ jsx57("span", { className: "fd-body-sm fd-muted", children: why })
6861
+ openQuestions && openQuestions.length ? /* @__PURE__ */ jsx58(Collapsible, { icon: "list-checks", title: "Open questions before implementation", subtitle: openQuestions.length + " unresolved", children: /* @__PURE__ */ jsx58("div", { className: "fd-stack", style: { gap: 8 }, children: openQuestions.map(([id, question, why]) => /* @__PURE__ */ jsxs53("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start", padding: "8px 0", borderTop: "1px solid var(--border)" }, children: [
6862
+ /* @__PURE__ */ jsx58(Badge, { tone: "danger", children: id }),
6863
+ /* @__PURE__ */ jsxs53("span", { className: "fd-stack", style: { gap: 2, flex: 1 }, children: [
6864
+ /* @__PURE__ */ jsx58("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: question }),
6865
+ /* @__PURE__ */ jsx58("span", { className: "fd-body-sm fd-muted", children: why })
6848
6866
  ] })
6849
6867
  ] }, id)) }) }) : null
6850
6868
  ] });
6851
6869
  }
6852
6870
 
6853
6871
  // src/components/platform/ProfilePage.tsx
6854
- import * as React30 from "react";
6855
- import { jsx as jsx58, jsxs as jsxs53 } from "react/jsx-runtime";
6872
+ import * as React31 from "react";
6873
+ import { jsx as jsx59, jsxs as jsxs54 } from "react/jsx-runtime";
6856
6874
  var TIMEZONES = ["America/New_York", "America/Chicago", "America/Denver", "America/Los_Angeles", "America/Anchorage", "Pacific/Honolulu", "Europe/London", "Europe/Berlin"];
6857
6875
  var NOTIFY = [
6858
6876
  { key: "planShared", label: "A plan is shared with me", detail: "Someone sends you a plan or a client link." },
@@ -6864,7 +6882,7 @@ var NOTIFY = [
6864
6882
  function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSessions = true, className = "", ...rest }) {
6865
6883
  const session = SessionKit.useSession();
6866
6884
  const user = userProp || session.user;
6867
- const [draft, setDraft] = React30.useState(() => ({
6885
+ const [draft, setDraft] = React31.useState(() => ({
6868
6886
  name: user.name || "",
6869
6887
  title: user.title || "",
6870
6888
  email: user.email || "",
@@ -6873,8 +6891,8 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
6873
6891
  bio: user.bio || "",
6874
6892
  notify: user.notify || { planShared: true, planChanged: true, goalMissed: true, flagChanged: false, weekly: true }
6875
6893
  }));
6876
- const [saving, setSaving] = React30.useState(false);
6877
- const [saved, setSaved] = React30.useState(false);
6894
+ const [saving, setSaving] = React31.useState(false);
6895
+ const [saved, setSaved] = React31.useState(false);
6878
6896
  const set = (k, v) => {
6879
6897
  setDraft((d) => Object.assign({}, d, { [k]: v }));
6880
6898
  setSaved(false);
@@ -6896,43 +6914,43 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
6896
6914
  { id: "s2", device: "iPhone 15 \xB7 Safari", where: "Denver, CO", when: "2 hours ago" },
6897
6915
  { id: "s3", device: "Windows \xB7 Edge", where: "Chicago, IL", when: "Aug 12" }
6898
6916
  ];
6899
- return /* @__PURE__ */ jsxs53("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 860 }, ...rest, children: [
6900
- /* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 10 }, children: [
6901
- /* @__PURE__ */ jsx58("span", { className: "fd-overline fd-muted", children: "Account" }),
6902
- /* @__PURE__ */ jsx58("h1", { className: "fd-h1", style: { margin: 0 }, children: "Your profile" }),
6903
- /* @__PURE__ */ jsx58("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." })
6917
+ return /* @__PURE__ */ jsxs54("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 860 }, ...rest, children: [
6918
+ /* @__PURE__ */ jsxs54("div", { className: "fd-stack", style: { gap: 10 }, children: [
6919
+ /* @__PURE__ */ jsx59("span", { className: "fd-overline fd-muted", children: "Account" }),
6920
+ /* @__PURE__ */ jsx59("h1", { className: "fd-h1", style: { margin: 0 }, children: "Your profile" }),
6921
+ /* @__PURE__ */ jsx59("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." })
6904
6922
  ] }),
6905
- /* @__PURE__ */ jsx58(Card, { elevation: "flat", children: /* @__PURE__ */ jsxs53("div", { className: "fd-row", style: { gap: 16, flexWrap: "wrap", alignItems: "flex-start" }, children: [
6906
- /* @__PURE__ */ jsx58(Avatar, { name: draft.name || user.name, size: "lg" }),
6907
- /* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 4, flex: 1, minWidth: 200 }, children: [
6908
- /* @__PURE__ */ jsx58("span", { className: "fd-h3", style: { margin: 0 }, children: draft.name || user.name }),
6909
- /* @__PURE__ */ jsxs53("span", { className: "fd-body-sm fd-muted", children: [
6923
+ /* @__PURE__ */ jsx59(Card, { elevation: "flat", children: /* @__PURE__ */ jsxs54("div", { className: "fd-row", style: { gap: 16, flexWrap: "wrap", alignItems: "flex-start" }, children: [
6924
+ /* @__PURE__ */ jsx59(Avatar, { name: draft.name || user.name, size: "lg" }),
6925
+ /* @__PURE__ */ jsxs54("div", { className: "fd-stack", style: { gap: 4, flex: 1, minWidth: 200 }, children: [
6926
+ /* @__PURE__ */ jsx59("span", { className: "fd-h3", style: { margin: 0 }, children: draft.name || user.name }),
6927
+ /* @__PURE__ */ jsxs54("span", { className: "fd-body-sm fd-muted", children: [
6910
6928
  draft.title || "No title set",
6911
6929
  " \xB7 ",
6912
6930
  user.team || "No team"
6913
6931
  ] }),
6914
- /* @__PURE__ */ jsxs53("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 4 }, children: [
6915
- session.roles.map((r) => /* @__PURE__ */ jsx58(Badge, { tone: r.id === "owner" ? "success" : "neutral", children: r.name }, r.id)),
6916
- user.sso ? /* @__PURE__ */ jsx58(Badge, { tone: "info", icon: "shield-check", children: "SSO" }) : null
6932
+ /* @__PURE__ */ jsxs54("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 4 }, children: [
6933
+ session.roles.map((r) => /* @__PURE__ */ jsx59(Badge, { tone: r.id === "owner" ? "success" : "neutral", children: r.name }, r.id)),
6934
+ user.sso ? /* @__PURE__ */ jsx59(Badge, { tone: "info", icon: "shield-check", children: "SSO" }) : null
6917
6935
  ] })
6918
6936
  ] }),
6919
- /* @__PURE__ */ jsx58(Button, { variant: "secondary", size: "sm", icon: "image", children: "Change photo" })
6937
+ /* @__PURE__ */ jsx59(Button, { variant: "secondary", size: "sm", icon: "image", children: "Change photo" })
6920
6938
  ] }) }),
6921
- /* @__PURE__ */ jsx58(
6939
+ /* @__PURE__ */ jsx59(
6922
6940
  Card,
6923
6941
  {
6924
- title: /* @__PURE__ */ jsxs53("span", { className: "fd-stack", style: { gap: 2 }, children: [
6925
- /* @__PURE__ */ jsx58("span", { children: "Identity" }),
6926
- /* @__PURE__ */ jsx58("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "Name and title appear on plans you share" })
6942
+ title: /* @__PURE__ */ jsxs54("span", { className: "fd-stack", style: { gap: 2 }, children: [
6943
+ /* @__PURE__ */ jsx59("span", { children: "Identity" }),
6944
+ /* @__PURE__ */ jsx59("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "Name and title appear on plans you share" })
6927
6945
  ] }),
6928
6946
  elevation: "flat",
6929
- children: /* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 14 }, children: [
6930
- /* @__PURE__ */ jsxs53("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: [
6931
- /* @__PURE__ */ jsx58(Input, { label: "Full name", value: draft.name, onChange: (e) => set("name", e.target.value) }),
6932
- /* @__PURE__ */ jsx58(Input, { label: "Job title", value: draft.title, onChange: (e) => set("title", e.target.value), placeholder: "e.g. Senior media planner" })
6947
+ children: /* @__PURE__ */ jsxs54("div", { className: "fd-stack", style: { gap: 14 }, children: [
6948
+ /* @__PURE__ */ jsxs54("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: [
6949
+ /* @__PURE__ */ jsx59(Input, { label: "Full name", value: draft.name, onChange: (e) => set("name", e.target.value) }),
6950
+ /* @__PURE__ */ jsx59(Input, { label: "Job title", value: draft.title, onChange: (e) => set("title", e.target.value), placeholder: "e.g. Senior media planner" })
6933
6951
  ] }),
6934
- /* @__PURE__ */ jsxs53("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: [
6935
- /* @__PURE__ */ jsx58(
6952
+ /* @__PURE__ */ jsxs54("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: [
6953
+ /* @__PURE__ */ jsx59(
6936
6954
  Input,
6937
6955
  {
6938
6956
  label: "Work email",
@@ -6942,9 +6960,9 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
6942
6960
  help: user.sso ? "Managed by your identity provider \u2014 change it there." : "Contact an administrator to change this."
6943
6961
  }
6944
6962
  ),
6945
- /* @__PURE__ */ jsx58(Input, { label: "Phone", value: draft.phone, onChange: (e) => set("phone", e.target.value), placeholder: "Optional" })
6963
+ /* @__PURE__ */ jsx59(Input, { label: "Phone", value: draft.phone, onChange: (e) => set("phone", e.target.value), placeholder: "Optional" })
6946
6964
  ] }),
6947
- /* @__PURE__ */ jsx58(
6965
+ /* @__PURE__ */ jsx59(
6948
6966
  Textarea,
6949
6967
  {
6950
6968
  label: "Short bio",
@@ -6958,8 +6976,8 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
6958
6976
  ] })
6959
6977
  }
6960
6978
  ),
6961
- /* @__PURE__ */ jsx58(Card, { title: "Working preferences", elevation: "flat", children: /* @__PURE__ */ jsxs53("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: [
6962
- /* @__PURE__ */ jsx58(
6979
+ /* @__PURE__ */ jsx59(Card, { title: "Working preferences", elevation: "flat", children: /* @__PURE__ */ jsxs54("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: [
6980
+ /* @__PURE__ */ jsx59(
6963
6981
  Select,
6964
6982
  {
6965
6983
  label: "Time zone",
@@ -6969,28 +6987,28 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
6969
6987
  help: "Flight dates and schedules render in this zone."
6970
6988
  }
6971
6989
  ),
6972
- /* @__PURE__ */ jsx58(Select, { label: "Start of week", options: ["Monday", "Sunday"], placeholder: "Monday" })
6990
+ /* @__PURE__ */ jsx59(Select, { label: "Start of week", options: ["Monday", "Sunday"], placeholder: "Monday" })
6973
6991
  ] }) }),
6974
- /* @__PURE__ */ jsx58(
6992
+ /* @__PURE__ */ jsx59(
6975
6993
  Card,
6976
6994
  {
6977
- title: /* @__PURE__ */ jsxs53("span", { className: "fd-stack", style: { gap: 2 }, children: [
6978
- /* @__PURE__ */ jsx58("span", { children: "Notifications" }),
6979
- /* @__PURE__ */ jsx58("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "Email only for now \u2014 in-app notifications are on the roadmap" })
6995
+ title: /* @__PURE__ */ jsxs54("span", { className: "fd-stack", style: { gap: 2 }, children: [
6996
+ /* @__PURE__ */ jsx59("span", { children: "Notifications" }),
6997
+ /* @__PURE__ */ jsx59("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "Email only for now \u2014 in-app notifications are on the roadmap" })
6980
6998
  ] }),
6981
6999
  elevation: "flat",
6982
- children: /* @__PURE__ */ jsx58("div", { className: "fd-stack", style: { gap: 14 }, children: NOTIFY.map((n) => /* @__PURE__ */ jsx58(Switch, { checked: !!draft.notify[n.key], onChange: () => setNotify(n.key), label: n.label, description: n.detail }, n.key)) })
7000
+ children: /* @__PURE__ */ jsx59("div", { className: "fd-stack", style: { gap: 14 }, children: NOTIFY.map((n) => /* @__PURE__ */ jsx59(Switch, { checked: !!draft.notify[n.key], onChange: () => setNotify(n.key), label: n.label, description: n.detail }, n.key)) })
6983
7001
  }
6984
7002
  ),
6985
- /* @__PURE__ */ jsxs53(
7003
+ /* @__PURE__ */ jsxs54(
6986
7004
  Card,
6987
7005
  {
6988
- title: /* @__PURE__ */ jsxs53("span", { className: "fd-stack", style: { gap: 2 }, children: [
6989
- /* @__PURE__ */ jsx58("span", { children: "Access" }),
6990
- /* @__PURE__ */ jsx58("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "What your roles grant you" })
7006
+ title: /* @__PURE__ */ jsxs54("span", { className: "fd-stack", style: { gap: 2 }, children: [
7007
+ /* @__PURE__ */ jsx59("span", { children: "Access" }),
7008
+ /* @__PURE__ */ jsx59("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "What your roles grant you" })
6991
7009
  ] }),
6992
7010
  elevation: "flat",
6993
- action: /* @__PURE__ */ jsx58(
7011
+ action: /* @__PURE__ */ jsx59(
6994
7012
  Button,
6995
7013
  {
6996
7014
  size: "sm",
@@ -7001,39 +7019,39 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
7001
7019
  }
7002
7020
  ),
7003
7021
  children: [
7004
- /* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 0 }, children: [
7005
- /* @__PURE__ */ jsx58(CardRow, { label: "Roles", children: session.roles.map((r) => r.name).join(", ") || "None" }),
7006
- /* @__PURE__ */ jsxs53(CardRow, { label: "Permissions", children: [
7022
+ /* @__PURE__ */ jsxs54("div", { className: "fd-stack", style: { gap: 0 }, children: [
7023
+ /* @__PURE__ */ jsx59(CardRow, { label: "Roles", children: session.roles.map((r) => r.name).join(", ") || "None" }),
7024
+ /* @__PURE__ */ jsxs54(CardRow, { label: "Permissions", children: [
7007
7025
  session.permissions.length,
7008
7026
  " granted"
7009
7027
  ] }),
7010
- /* @__PURE__ */ jsx58(CardRow, { label: "Member since", children: user.joined || "\u2014" })
7028
+ /* @__PURE__ */ jsx59(CardRow, { label: "Member since", children: user.joined || "\u2014" })
7011
7029
  ] }),
7012
- /* @__PURE__ */ jsx58("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." })
7030
+ /* @__PURE__ */ jsx59("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." })
7013
7031
  ]
7014
7032
  }
7015
7033
  ),
7016
- showSessions ? /* @__PURE__ */ jsx58(
7034
+ showSessions ? /* @__PURE__ */ jsx59(
7017
7035
  Card,
7018
7036
  {
7019
7037
  title: "Signed-in devices",
7020
7038
  elevation: "flat",
7021
- action: /* @__PURE__ */ jsx58(Button, { size: "sm", variant: "ghost", icon: "sign-out", children: "Sign out everywhere" }),
7022
- children: /* @__PURE__ */ jsx58("div", { className: "fd-stack", style: { gap: 0 }, children: liveSessions.map((s) => /* @__PURE__ */ jsxs53("div", { className: "fd-row", style: { gap: 12, padding: "10px 0", borderTop: "1px solid var(--border)", flexWrap: "wrap" }, children: [
7023
- /* @__PURE__ */ jsx58("i", { className: "ph ph-device-mobile", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
7024
- /* @__PURE__ */ jsxs53("span", { className: "fd-stack", style: { gap: 1, flex: 1, minWidth: 160 }, children: [
7025
- /* @__PURE__ */ jsx58("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: s.device }),
7026
- /* @__PURE__ */ jsxs53("span", { className: "fd-body-sm fd-muted", children: [
7039
+ action: /* @__PURE__ */ jsx59(Button, { size: "sm", variant: "ghost", icon: "sign-out", children: "Sign out everywhere" }),
7040
+ children: /* @__PURE__ */ jsx59("div", { className: "fd-stack", style: { gap: 0 }, children: liveSessions.map((s) => /* @__PURE__ */ jsxs54("div", { className: "fd-row", style: { gap: 12, padding: "10px 0", borderTop: "1px solid var(--border)", flexWrap: "wrap" }, children: [
7041
+ /* @__PURE__ */ jsx59("i", { className: "ph ph-device-mobile", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
7042
+ /* @__PURE__ */ jsxs54("span", { className: "fd-stack", style: { gap: 1, flex: 1, minWidth: 160 }, children: [
7043
+ /* @__PURE__ */ jsx59("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: s.device }),
7044
+ /* @__PURE__ */ jsxs54("span", { className: "fd-body-sm fd-muted", children: [
7027
7045
  s.where,
7028
7046
  " \xB7 ",
7029
7047
  s.when
7030
7048
  ] })
7031
7049
  ] }),
7032
- s.current ? /* @__PURE__ */ jsx58(Badge, { tone: "success", dot: true, children: "This device" }) : /* @__PURE__ */ jsx58(Button, { size: "sm", variant: "ghost", children: "Revoke" })
7050
+ s.current ? /* @__PURE__ */ jsx59(Badge, { tone: "success", dot: true, children: "This device" }) : /* @__PURE__ */ jsx59(Button, { size: "sm", variant: "ghost", children: "Revoke" })
7033
7051
  ] }, s.id)) })
7034
7052
  }
7035
7053
  ) : null,
7036
- /* @__PURE__ */ jsxs53("div", { className: "fd-row", style: {
7054
+ /* @__PURE__ */ jsxs54("div", { className: "fd-row", style: {
7037
7055
  gap: 10,
7038
7056
  flexWrap: "wrap",
7039
7057
  position: "sticky",
@@ -7044,8 +7062,8 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
7044
7062
  border: "1px solid var(--border)",
7045
7063
  boxShadow: "0 -4px 16px rgba(11,13,17,.06)"
7046
7064
  }, children: [
7047
- /* @__PURE__ */ jsx58("span", { className: "fd-body-sm", style: { fontWeight: 600, flex: 1 }, children: saved ? "Saved." : dirty ? "Unsaved changes" : "No pending changes" }),
7048
- /* @__PURE__ */ jsx58(
7065
+ /* @__PURE__ */ jsx59("span", { className: "fd-body-sm", style: { fontWeight: 600, flex: 1 }, children: saved ? "Saved." : dirty ? "Unsaved changes" : "No pending changes" }),
7066
+ /* @__PURE__ */ jsx59(
7049
7067
  Button,
7050
7068
  {
7051
7069
  size: "sm",
@@ -7058,16 +7076,16 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
7058
7076
  children: "Discard"
7059
7077
  }
7060
7078
  ),
7061
- /* @__PURE__ */ jsx58(Button, { size: "sm", icon: "check", disabled: !dirty, loading: saving, onClick: save, children: "Save changes" })
7079
+ /* @__PURE__ */ jsx59(Button, { size: "sm", icon: "check", disabled: !dirty, loading: saving, onClick: save, children: "Save changes" })
7062
7080
  ] })
7063
7081
  ] });
7064
7082
  }
7065
7083
 
7066
7084
  // src/components/platform/RoadmapTimeline.tsx
7067
- import * as React32 from "react";
7085
+ import * as React33 from "react";
7068
7086
 
7069
7087
  // src/kits/runtime.ts
7070
- import * as React31 from "react";
7088
+ import * as React32 from "react";
7071
7089
  var WIRED_ENDPOINTS = [
7072
7090
  // Nothing yet. Every id below would come from a real service:
7073
7091
  // "plan.get", "placements.list", …
@@ -7238,8 +7256,8 @@ var RuntimeKit = {
7238
7256
  };
7239
7257
  RuntimeKit.declare(FEATURE_NEEDS);
7240
7258
  function useRuntimeMode() {
7241
- const [m, setM] = React31.useState(RuntimeKit.getMode());
7242
- React31.useEffect(() => RuntimeKit.subscribe(setM), []);
7259
+ const [m, setM] = React32.useState(RuntimeKit.getMode());
7260
+ React32.useEffect(() => RuntimeKit.subscribe(setM), []);
7243
7261
  return m;
7244
7262
  }
7245
7263
  function useFeatureStatus(key) {
@@ -7258,7 +7276,7 @@ var UseRuntimeMode = useRuntimeMode;
7258
7276
  var UseFeatureStatus = useFeatureStatus;
7259
7277
 
7260
7278
  // src/components/platform/RoadmapTimeline.tsx
7261
- import { jsx as jsx59, jsxs as jsxs54 } from "react/jsx-runtime";
7279
+ import { jsx as jsx60, jsxs as jsxs55 } from "react/jsx-runtime";
7262
7280
  var STATUS = {
7263
7281
  shipped: { tone: "success", icon: "check-circle", label: "Wired" },
7264
7282
  next: { tone: "warning", icon: "traffic-cone", label: "Not wired" },
@@ -7273,45 +7291,45 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
7273
7291
  const s = STATUS[item.status] || STATUS.planned;
7274
7292
  const deps = (item.dependsOn || []).map((k) => byKey[k]).filter(Boolean);
7275
7293
  const blocking = deps.filter((d) => !d.implemented);
7276
- return /* @__PURE__ */ jsx59(Card, { elevation: "flat", children: /* @__PURE__ */ jsxs54("div", { className: "fd-stack", style: { gap: 10 }, children: [
7277
- /* @__PURE__ */ jsxs54("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
7278
- /* @__PURE__ */ jsx59("span", { className: "fd-body", style: { fontWeight: 700, flex: 1, minWidth: 140 }, children: item.label }),
7279
- /* @__PURE__ */ jsx59(Badge, { tone: "neutral", icon: PROJECT_ICON[item.project] || "squares-four", children: item.project }),
7280
- /* @__PURE__ */ jsx59(Badge, { tone: s.tone, icon: s.icon, children: s.label })
7294
+ return /* @__PURE__ */ jsx60(Card, { elevation: "flat", children: /* @__PURE__ */ jsxs55("div", { className: "fd-stack", style: { gap: 10 }, children: [
7295
+ /* @__PURE__ */ jsxs55("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
7296
+ /* @__PURE__ */ jsx60("span", { className: "fd-body", style: { fontWeight: 700, flex: 1, minWidth: 140 }, children: item.label }),
7297
+ /* @__PURE__ */ jsx60(Badge, { tone: "neutral", icon: PROJECT_ICON[item.project] || "squares-four", children: item.project }),
7298
+ /* @__PURE__ */ jsx60(Badge, { tone: s.tone, icon: s.icon, children: s.label })
7281
7299
  ] }),
7282
- /* @__PURE__ */ jsx59("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: item.description }),
7283
- item.backend ? /* @__PURE__ */ jsxs54("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start" }, children: [
7284
- /* @__PURE__ */ jsx59("span", { className: "fd-overline fd-muted", style: { width: 62, flex: "none", paddingTop: 2 }, children: "Backend" }),
7285
- /* @__PURE__ */ jsx59("span", { className: "fd-body-sm", style: { flex: 1, textWrap: "pretty" }, children: item.backend })
7300
+ /* @__PURE__ */ jsx60("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: item.description }),
7301
+ item.backend ? /* @__PURE__ */ jsxs55("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start" }, children: [
7302
+ /* @__PURE__ */ jsx60("span", { className: "fd-overline fd-muted", style: { width: 62, flex: "none", paddingTop: 2 }, children: "Backend" }),
7303
+ /* @__PURE__ */ jsx60("span", { className: "fd-body-sm", style: { flex: 1, textWrap: "pretty" }, children: item.backend })
7286
7304
  ] }) : null,
7287
- /* @__PURE__ */ jsxs54("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
7288
- item.effort ? /* @__PURE__ */ jsxs54("span", { className: "fd-body-sm fd-muted", children: [
7289
- /* @__PURE__ */ jsx59("i", { className: "ph ph-hourglass-medium" }),
7305
+ /* @__PURE__ */ jsxs55("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
7306
+ item.effort ? /* @__PURE__ */ jsxs55("span", { className: "fd-body-sm fd-muted", children: [
7307
+ /* @__PURE__ */ jsx60("i", { className: "ph ph-hourglass-medium" }),
7290
7308
  " ",
7291
7309
  item.effort
7292
7310
  ] }) : null,
7293
- /* @__PURE__ */ jsxs54("span", { className: "fd-body-sm fd-muted", children: [
7294
- /* @__PURE__ */ jsx59("i", { className: "ph ph-user" }),
7311
+ /* @__PURE__ */ jsxs55("span", { className: "fd-body-sm fd-muted", children: [
7312
+ /* @__PURE__ */ jsx60("i", { className: "ph ph-user" }),
7295
7313
  " ",
7296
7314
  item.owner
7297
7315
  ] }),
7298
- item.screen ? /* @__PURE__ */ jsx59(Badge, { tone: "neutral", icon: "browser", children: "screen" }) : null,
7299
- /* @__PURE__ */ jsx59("span", { style: { flex: 1 } }),
7300
- /* @__PURE__ */ jsx59(
7316
+ item.screen ? /* @__PURE__ */ jsx60(Badge, { tone: "neutral", icon: "browser", children: "screen" }) : null,
7317
+ /* @__PURE__ */ jsx60("span", { style: { flex: 1 } }),
7318
+ /* @__PURE__ */ jsx60(
7301
7319
  "button",
7302
7320
  {
7303
7321
  type: "button",
7304
7322
  onClick: () => onOpenFlag && onOpenFlag(item.key),
7305
7323
  style: { all: "unset", cursor: "pointer", display: "inline-flex", alignItems: "center", gap: 5 },
7306
- children: /* @__PURE__ */ jsx59("code", { className: "fd-mono", style: { fontSize: 11, color: "var(--brand)" }, children: item.key })
7324
+ children: /* @__PURE__ */ jsx60("code", { className: "fd-mono", style: { fontSize: 11, color: "var(--brand)" }, children: item.key })
7307
7325
  }
7308
7326
  )
7309
7327
  ] }),
7310
- deps.length ? /* @__PURE__ */ jsxs54("div", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 6, borderTop: "1px solid var(--border)" }, children: [
7311
- /* @__PURE__ */ jsx59("span", { className: "fd-overline fd-muted", style: { paddingTop: 3 }, children: "After" }),
7312
- deps.map((d) => /* @__PURE__ */ jsx59(Tag, { icon: d.implemented ? "check" : "clock", children: d.label }, d.key))
7328
+ deps.length ? /* @__PURE__ */ jsxs55("div", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 6, borderTop: "1px solid var(--border)" }, children: [
7329
+ /* @__PURE__ */ jsx60("span", { className: "fd-overline fd-muted", style: { paddingTop: 3 }, children: "After" }),
7330
+ deps.map((d) => /* @__PURE__ */ jsx60(Tag, { icon: d.implemented ? "check" : "clock", children: d.label }, d.key))
7313
7331
  ] }) : null,
7314
- blocking.length && !item.implemented ? /* @__PURE__ */ jsxs54("span", { className: "fd-body-sm", style: { color: "var(--warn-text)" }, children: [
7332
+ blocking.length && !item.implemented ? /* @__PURE__ */ jsxs55("span", { className: "fd-body-sm", style: { color: "var(--warn-text)" }, children: [
7315
7333
  "Blocked until ",
7316
7334
  blocking.map((d) => d.label).join(" and "),
7317
7335
  " ",
@@ -7322,12 +7340,12 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
7322
7340
  }
7323
7341
  function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
7324
7342
  const session = SessionKit.useSession();
7325
- const [project, setProject] = React32.useState("");
7326
- const [q, setQ] = React32.useState("");
7327
- const scrollRef = React32.useRef(null);
7328
- const nowRef = React32.useRef(null);
7329
- const rm = React32.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
7330
- const byKey = React32.useMemo(() => {
7343
+ const [project, setProject] = React33.useState("");
7344
+ const [q, setQ] = React33.useState("");
7345
+ const scrollRef = React33.useRef(null);
7346
+ const nowRef = React33.useRef(null);
7347
+ const rm = React33.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
7348
+ const byKey = React33.useMemo(() => {
7331
7349
  const m = {};
7332
7350
  rm.items.forEach((i) => {
7333
7351
  m[i.key] = i;
@@ -7336,7 +7354,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
7336
7354
  }, [rm]);
7337
7355
  const items = rm.items.filter((i) => (!project || i.project === project) && (!q || (i.label + " " + i.description + " " + (i.backend || "") + " " + i.key).toLowerCase().includes(q.toLowerCase())));
7338
7356
  const projects = [...new Set(rm.items.map((i) => i.project))];
7339
- React32.useEffect(() => {
7357
+ React33.useEffect(() => {
7340
7358
  let raf1 = 0, raf2 = 0;
7341
7359
  const place = () => {
7342
7360
  const box = scrollRef.current, mark = nowRef.current;
@@ -7364,23 +7382,23 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
7364
7382
  }, 0);
7365
7383
  const nextPhase = items.find((i) => !i.implemented);
7366
7384
  let lastPhase = null;
7367
- return /* @__PURE__ */ jsxs54("div", { className: "fd-stack", style: { gap: 16, maxWidth: 1e3 }, children: [
7368
- /* @__PURE__ */ jsxs54("div", { className: "fd-stack", style: { gap: 10 }, children: [
7369
- /* @__PURE__ */ jsx59("span", { className: "fd-overline fd-muted", children: "Architecture" }),
7370
- /* @__PURE__ */ jsx59("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
7371
- /* @__PURE__ */ jsx59("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." })
7385
+ return /* @__PURE__ */ jsxs55("div", { className: "fd-stack", style: { gap: 16, maxWidth: 1e3 }, children: [
7386
+ /* @__PURE__ */ jsxs55("div", { className: "fd-stack", style: { gap: 10 }, children: [
7387
+ /* @__PURE__ */ jsx60("span", { className: "fd-overline fd-muted", children: "Architecture" }),
7388
+ /* @__PURE__ */ jsx60("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
7389
+ /* @__PURE__ */ jsx60("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." })
7372
7390
  ] }),
7373
- /* @__PURE__ */ jsxs54("div", { className: "fd-grid-stats is-thin", children: [
7374
- /* @__PURE__ */ jsx59(StatTile, { compact: true, label: "Wired", value: String(rm.shipped), sub: "of " + rm.items.length + " features" }),
7375
- /* @__PURE__ */ jsx59(StatTile, { compact: true, label: "Remaining", value: String(rm.remaining), sub: "backend work" }),
7376
- /* @__PURE__ */ jsx59(StatTile, { compact: true, label: "Est. effort", value: days ? days + " days" : "\u2014", sub: "sum of estimates, not calendar" }),
7377
- /* @__PURE__ */ jsx59(StatTile, { compact: true, label: "Up next", value: nextPhase ? "Phase " + nextPhase.phase : "\u2014", sub: nextPhase ? nextPhase.phaseName : "all wired" })
7391
+ /* @__PURE__ */ jsxs55("div", { className: "fd-grid-stats is-thin", children: [
7392
+ /* @__PURE__ */ jsx60(StatTile, { compact: true, label: "Wired", value: String(rm.shipped), sub: "of " + rm.items.length + " features" }),
7393
+ /* @__PURE__ */ jsx60(StatTile, { compact: true, label: "Remaining", value: String(rm.remaining), sub: "backend work" }),
7394
+ /* @__PURE__ */ jsx60(StatTile, { compact: true, label: "Est. effort", value: days ? days + " days" : "\u2014", sub: "sum of estimates, not calendar" }),
7395
+ /* @__PURE__ */ jsx60(StatTile, { compact: true, label: "Up next", value: nextPhase ? "Phase " + nextPhase.phase : "\u2014", sub: nextPhase ? nextPhase.phaseName : "all wired" })
7378
7396
  ] }),
7379
- /* @__PURE__ */ jsxs54("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
7380
- /* @__PURE__ */ jsx59(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 } }),
7381
- /* @__PURE__ */ jsx59(Select, { placeholder: "All projects", value: project, onChange: (e) => setProject(e.target.value), options: projects, style: { width: 190 } }),
7382
- /* @__PURE__ */ jsx59("span", { style: { flex: 1 } }),
7383
- /* @__PURE__ */ jsx59(
7397
+ /* @__PURE__ */ jsxs55("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
7398
+ /* @__PURE__ */ jsx60(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 } }),
7399
+ /* @__PURE__ */ jsx60(Select, { placeholder: "All projects", value: project, onChange: (e) => setProject(e.target.value), options: projects, style: { width: 190 } }),
7400
+ /* @__PURE__ */ jsx60("span", { style: { flex: 1 } }),
7401
+ /* @__PURE__ */ jsx60(
7384
7402
  Button,
7385
7403
  {
7386
7404
  size: "sm",
@@ -7394,7 +7412,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
7394
7412
  }
7395
7413
  )
7396
7414
  ] }),
7397
- /* @__PURE__ */ jsx59(
7415
+ /* @__PURE__ */ jsx60(
7398
7416
  Flag,
7399
7417
  {
7400
7418
  tone: "info",
@@ -7403,60 +7421,60 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
7403
7421
  actions: null
7404
7422
  }
7405
7423
  ),
7406
- /* @__PURE__ */ jsx59("div", { className: "fd-rm", children: /* @__PURE__ */ jsx59("div", { className: "fd-rm-scroll", ref: scrollRef, children: /* @__PURE__ */ jsxs54("div", { className: "fd-rm-track", children: [
7407
- /* @__PURE__ */ jsx59("span", { className: "fd-rm-spine", children: /* @__PURE__ */ jsx59("span", { className: "fd-rm-spine-done", style: { height: items.length ? 100 * shippedShown / items.length + "%" : "0%" } }) }),
7424
+ /* @__PURE__ */ jsx60("div", { className: "fd-rm", children: /* @__PURE__ */ jsx60("div", { className: "fd-rm-scroll", ref: scrollRef, children: /* @__PURE__ */ jsxs55("div", { className: "fd-rm-track", children: [
7425
+ /* @__PURE__ */ jsx60("span", { className: "fd-rm-spine", children: /* @__PURE__ */ jsx60("span", { className: "fd-rm-spine-done", style: { height: items.length ? 100 * shippedShown / items.length + "%" : "0%" } }) }),
7408
7426
  items.map((item, n) => {
7409
7427
  const showPhase = item.phase !== lastPhase;
7410
7428
  lastPhase = item.phase;
7411
7429
  const inPhase = items.filter((i) => i.phase === item.phase).length;
7412
7430
  const isBoundary = n === firstPending;
7413
- return /* @__PURE__ */ jsxs54(React32.Fragment, { children: [
7414
- showPhase ? /* @__PURE__ */ jsxs54("div", { className: "fd-rm-era", children: [
7415
- /* @__PURE__ */ jsxs54("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
7416
- /* @__PURE__ */ jsx59("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
7417
- item.phase === 0 ? null : /* @__PURE__ */ jsxs54("span", { className: "fd-mono", style: { opacity: 0.7, fontWeight: 400 }, children: [
7431
+ return /* @__PURE__ */ jsxs55(React33.Fragment, { children: [
7432
+ showPhase ? /* @__PURE__ */ jsxs55("div", { className: "fd-rm-era", children: [
7433
+ /* @__PURE__ */ jsxs55("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
7434
+ /* @__PURE__ */ jsx60("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
7435
+ item.phase === 0 ? null : /* @__PURE__ */ jsxs55("span", { className: "fd-mono", style: { opacity: 0.7, fontWeight: 400 }, children: [
7418
7436
  fmtDate(item.phaseStart),
7419
7437
  " \u2013 ",
7420
7438
  fmtDate(item.date)
7421
7439
  ] }),
7422
- /* @__PURE__ */ jsxs54("span", { style: { opacity: 0.7, fontWeight: 400 }, children: [
7440
+ /* @__PURE__ */ jsxs55("span", { style: { opacity: 0.7, fontWeight: 400 }, children: [
7423
7441
  "\xB7 ",
7424
7442
  inPhase,
7425
7443
  " feature",
7426
7444
  inPhase === 1 ? "" : "s"
7427
7445
  ] })
7428
7446
  ] }),
7429
- item.phaseWhy ? /* @__PURE__ */ jsx59("p", { className: "fd-rm-era-why", children: item.phaseWhy }) : null
7447
+ item.phaseWhy ? /* @__PURE__ */ jsx60("p", { className: "fd-rm-era-why", children: item.phaseWhy }) : null
7430
7448
  ] }) : null,
7431
- isBoundary ? /* @__PURE__ */ jsx59("div", { className: "fd-rm-now", ref: nowRef, children: /* @__PURE__ */ jsxs54("span", { className: "fd-rm-now-pill", children: [
7432
- /* @__PURE__ */ jsx59("i", { className: "ph ph-map-pin" }),
7449
+ isBoundary ? /* @__PURE__ */ jsx60("div", { className: "fd-rm-now", ref: nowRef, children: /* @__PURE__ */ jsxs55("span", { className: "fd-rm-now-pill", children: [
7450
+ /* @__PURE__ */ jsx60("i", { className: "ph ph-map-pin" }),
7433
7451
  " You are here \u2014 everything above is wired"
7434
7452
  ] }) }) : null,
7435
- /* @__PURE__ */ jsxs54("div", { className: "fd-rm-row", children: [
7436
- /* @__PURE__ */ jsx59("span", { className: "fd-rm-dot " + (item.implemented ? "is-shipped" : item.status === "next" ? "is-next" : "") }),
7437
- /* @__PURE__ */ jsxs54("div", { className: "fd-rm-date", children: [
7453
+ /* @__PURE__ */ jsxs55("div", { className: "fd-rm-row", children: [
7454
+ /* @__PURE__ */ jsx60("span", { className: "fd-rm-dot " + (item.implemented ? "is-shipped" : item.status === "next" ? "is-next" : "") }),
7455
+ /* @__PURE__ */ jsxs55("div", { className: "fd-rm-date", children: [
7438
7456
  fmtDate(item.date),
7439
- /* @__PURE__ */ jsx59("br", {}),
7440
- /* @__PURE__ */ jsx59("span", { style: { opacity: 0.75 }, children: item.implemented ? "shipped" : "phase " + item.phase })
7457
+ /* @__PURE__ */ jsx60("br", {}),
7458
+ /* @__PURE__ */ jsx60("span", { style: { opacity: 0.75 }, children: item.implemented ? "shipped" : "phase " + item.phase })
7441
7459
  ] }),
7442
- /* @__PURE__ */ jsx59(RoadmapCard, { item, byKey, onOpenFlag })
7460
+ /* @__PURE__ */ jsx60(RoadmapCard, { item, byKey, onOpenFlag })
7443
7461
  ] })
7444
7462
  ] }, item.key);
7445
7463
  }),
7446
- !items.length ? /* @__PURE__ */ jsx59("p", { className: "fd-body-sm fd-muted", children: "Nothing matches that filter." }) : null
7464
+ !items.length ? /* @__PURE__ */ jsx60("p", { className: "fd-body-sm fd-muted", children: "Nothing matches that filter." }) : null
7447
7465
  ] }) }) }),
7448
- /* @__PURE__ */ jsxs54("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: [
7466
+ /* @__PURE__ */ jsxs55("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: [
7449
7467
  "Derived from the feature-flag registry \u2014 each entry's status is its flag's ",
7450
- /* @__PURE__ */ jsx59("code", { className: "fd-mono", children: "implemented" }),
7468
+ /* @__PURE__ */ jsx60("code", { className: "fd-mono", children: "implemented" }),
7451
7469
  " field, so this page cannot drift from what the apps actually do."
7452
7470
  ] })
7453
7471
  ] });
7454
7472
  }
7455
7473
 
7456
7474
  // src/components/platform/ComingSoon.tsx
7457
- import * as React33 from "react";
7475
+ import * as React34 from "react";
7458
7476
  import { createPortal as createPortal8 } from "react-dom";
7459
- import { Fragment as Fragment14, jsx as jsx60, jsxs as jsxs55 } from "react/jsx-runtime";
7477
+ import { Fragment as Fragment14, jsx as jsx61, jsxs as jsxs56 } from "react/jsx-runtime";
7460
7478
  var BYPASS_STORE = "fd.soon.bypass.v1";
7461
7479
  function readBypassed() {
7462
7480
  try {
@@ -7472,8 +7490,8 @@ function writeBypassed(list) {
7472
7490
  }
7473
7491
  }
7474
7492
  function useBypass(key) {
7475
- const [on, setOn] = React33.useState(() => !!key && readBypassed().indexOf(key) >= 0);
7476
- React33.useEffect(() => {
7493
+ const [on, setOn] = React34.useState(() => !!key && readBypassed().indexOf(key) >= 0);
7494
+ React34.useEffect(() => {
7477
7495
  setOn(!!key && readBypassed().indexOf(key) >= 0);
7478
7496
  }, [key]);
7479
7497
  const set = (next) => {
@@ -7486,43 +7504,43 @@ function useBypass(key) {
7486
7504
  return [on, set];
7487
7505
  }
7488
7506
  function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass }) {
7489
- return /* @__PURE__ */ jsxs55(Fragment14, { children: [
7490
- /* @__PURE__ */ jsxs55("span", { className: "fd-soon-badge", children: [
7491
- /* @__PURE__ */ jsx60("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
7507
+ return /* @__PURE__ */ jsxs56(Fragment14, { children: [
7508
+ /* @__PURE__ */ jsxs56("span", { className: "fd-soon-badge", children: [
7509
+ /* @__PURE__ */ jsx61("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
7492
7510
  label
7493
7511
  ] }),
7494
- detail ? /* @__PURE__ */ jsx60("span", { className: "fd-soon-detail", children: detail }) : null,
7495
- backend ? /* @__PURE__ */ jsxs55("span", { className: "fd-soon-backend", children: [
7496
- /* @__PURE__ */ jsx60("span", { className: "fd-overline", children: "Needs" }),
7512
+ detail ? /* @__PURE__ */ jsx61("span", { className: "fd-soon-detail", children: detail }) : null,
7513
+ backend ? /* @__PURE__ */ jsxs56("span", { className: "fd-soon-backend", children: [
7514
+ /* @__PURE__ */ jsx61("span", { className: "fd-overline", children: "Needs" }),
7497
7515
  " ",
7498
7516
  backend
7499
7517
  ] }) : null,
7500
- eta || effort || onRoadmap ? /* @__PURE__ */ jsxs55("span", { className: "fd-soon-meta", children: [
7501
- eta ? /* @__PURE__ */ jsxs55("span", { children: [
7502
- /* @__PURE__ */ jsx60("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }),
7518
+ eta || effort || onRoadmap ? /* @__PURE__ */ jsxs56("span", { className: "fd-soon-meta", children: [
7519
+ eta ? /* @__PURE__ */ jsxs56("span", { children: [
7520
+ /* @__PURE__ */ jsx61("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }),
7503
7521
  " ",
7504
7522
  eta
7505
7523
  ] }) : null,
7506
- effort ? /* @__PURE__ */ jsxs55("span", { children: [
7507
- /* @__PURE__ */ jsx60("i", { className: "ph ph-hourglass-medium", "aria-hidden": "true" }),
7524
+ effort ? /* @__PURE__ */ jsxs56("span", { children: [
7525
+ /* @__PURE__ */ jsx61("i", { className: "ph ph-hourglass-medium", "aria-hidden": "true" }),
7508
7526
  " ",
7509
7527
  effort
7510
7528
  ] }) : null,
7511
- onRoadmap ? /* @__PURE__ */ jsxs55("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
7529
+ onRoadmap ? /* @__PURE__ */ jsxs56("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
7512
7530
  "See the roadmap ",
7513
- /* @__PURE__ */ jsx60("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
7531
+ /* @__PURE__ */ jsx61("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
7514
7532
  ] }) : null
7515
7533
  ] }) : null,
7516
- allowed ? /* @__PURE__ */ jsxs55("button", { type: "button", className: "fd-soon-view", onClick: onBypass, children: [
7517
- /* @__PURE__ */ jsx60("i", { className: "ph ph-eye", "aria-hidden": "true" }),
7534
+ allowed ? /* @__PURE__ */ jsxs56("button", { type: "button", className: "fd-soon-view", onClick: onBypass, children: [
7535
+ /* @__PURE__ */ jsx61("i", { className: "ph ph-eye", "aria-hidden": "true" }),
7518
7536
  " View and use it anyway"
7519
7537
  ] }) : null
7520
7538
  ] });
7521
7539
  }
7522
7540
  function useHoverCard(open) {
7523
- const anchor = React33.useRef(null);
7524
- const [pos, setPos] = React33.useState(null);
7525
- React33.useLayoutEffect(() => {
7541
+ const anchor = React34.useRef(null);
7542
+ const [pos, setPos] = React34.useState(null);
7543
+ React34.useLayoutEffect(() => {
7526
7544
  if (!open || !anchor.current) {
7527
7545
  setPos(null);
7528
7546
  return;
@@ -7574,9 +7592,9 @@ function ComingSoon({
7574
7592
  const tip = [label, detail, backend ? "Needs " + backend : null, eta ? "ETA " + eta : null, effort].filter(Boolean).join(" \xB7 ");
7575
7593
  if (inline) {
7576
7594
  if (allowed && bypassed) {
7577
- return /* @__PURE__ */ jsxs55("span", { className: ["fd-soon-inline-on", className].filter(Boolean).join(" "), ...rest, children: [
7595
+ return /* @__PURE__ */ jsxs56("span", { className: ["fd-soon-inline-on", className].filter(Boolean).join(" "), ...rest, children: [
7578
7596
  children,
7579
- /* @__PURE__ */ jsx60(
7597
+ /* @__PURE__ */ jsx61(
7580
7598
  "button",
7581
7599
  {
7582
7600
  type: "button",
@@ -7584,12 +7602,12 @@ function ComingSoon({
7584
7602
  title: "Unwired \u2014 writes go to the simulated backend. " + tip + " Click to re-blur.",
7585
7603
  onClick: () => setBypassed(false),
7586
7604
  "aria-label": "Re-blur this unwired feature",
7587
- children: /* @__PURE__ */ jsx60("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
7605
+ children: /* @__PURE__ */ jsx61("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
7588
7606
  }
7589
7607
  )
7590
7608
  ] });
7591
7609
  }
7592
- return /* @__PURE__ */ jsx60(
7610
+ return /* @__PURE__ */ jsx61(
7593
7611
  InlineSoon,
7594
7612
  {
7595
7613
  label,
@@ -7609,20 +7627,20 @@ function ComingSoon({
7609
7627
  );
7610
7628
  }
7611
7629
  if (allowed && bypassed) {
7612
- return /* @__PURE__ */ jsxs55("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, ...rest, children: [
7613
- /* @__PURE__ */ jsxs55("div", { className: "fd-soon-bar", role: "status", children: [
7614
- /* @__PURE__ */ jsxs55("span", { className: "fd-soon-badge", children: [
7615
- /* @__PURE__ */ jsx60("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
7630
+ return /* @__PURE__ */ jsxs56("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, ...rest, children: [
7631
+ /* @__PURE__ */ jsxs56("div", { className: "fd-soon-bar", role: "status", children: [
7632
+ /* @__PURE__ */ jsxs56("span", { className: "fd-soon-badge", children: [
7633
+ /* @__PURE__ */ jsx61("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
7616
7634
  "Unwired feature \u2014 you are using it anyway"
7617
7635
  ] }),
7618
- /* @__PURE__ */ jsx60("span", { className: "fd-soon-bar-detail", children: "Every action here writes to the simulated backend, so nothing you do persists beyond this session." }),
7619
- /* @__PURE__ */ jsxs55("span", { className: "fd-soon-bar-actions", children: [
7620
- onRoadmap ? /* @__PURE__ */ jsxs55("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
7636
+ /* @__PURE__ */ jsx61("span", { className: "fd-soon-bar-detail", children: "Every action here writes to the simulated backend, so nothing you do persists beyond this session." }),
7637
+ /* @__PURE__ */ jsxs56("span", { className: "fd-soon-bar-actions", children: [
7638
+ onRoadmap ? /* @__PURE__ */ jsxs56("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
7621
7639
  "Roadmap ",
7622
- /* @__PURE__ */ jsx60("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
7640
+ /* @__PURE__ */ jsx61("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
7623
7641
  ] }) : null,
7624
- /* @__PURE__ */ jsxs55("button", { type: "button", className: "fd-soon-link", onClick: () => setBypassed(false), children: [
7625
- /* @__PURE__ */ jsx60("i", { className: "ph ph-eye-slash", "aria-hidden": "true" }),
7642
+ /* @__PURE__ */ jsxs56("button", { type: "button", className: "fd-soon-link", onClick: () => setBypassed(false), children: [
7643
+ /* @__PURE__ */ jsx61("i", { className: "ph ph-eye-slash", "aria-hidden": "true" }),
7626
7644
  " Re-blur"
7627
7645
  ] })
7628
7646
  ] })
@@ -7630,10 +7648,10 @@ function ComingSoon({
7630
7648
  children
7631
7649
  ] });
7632
7650
  }
7633
- return /* @__PURE__ */ jsxs55("div", { className: ["fd-soon", className].filter(Boolean).join(" "), style: minHeight ? { minHeight } : void 0, ...rest, children: [
7634
- /* @__PURE__ */ jsx60("div", { className: "fd-soon-under", style: { filter: "blur(" + blur + "px) saturate(.62)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
7635
- /* @__PURE__ */ jsx60("div", { className: "fd-soon-veil" }),
7636
- /* @__PURE__ */ jsx60("div", { className: "fd-soon-note", role: "note", children: /* @__PURE__ */ jsx60(
7651
+ return /* @__PURE__ */ jsxs56("div", { className: ["fd-soon", className].filter(Boolean).join(" "), style: minHeight ? { minHeight } : void 0, ...rest, children: [
7652
+ /* @__PURE__ */ jsx61("div", { className: "fd-soon-under", style: { filter: "blur(" + blur + "px) saturate(.62)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
7653
+ /* @__PURE__ */ jsx61("div", { className: "fd-soon-veil" }),
7654
+ /* @__PURE__ */ jsx61("div", { className: "fd-soon-note", role: "note", children: /* @__PURE__ */ jsx61(
7637
7655
  SoonCard,
7638
7656
  {
7639
7657
  label,
@@ -7649,9 +7667,9 @@ function ComingSoon({
7649
7667
  ] });
7650
7668
  }
7651
7669
  function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass, blur, tip, className, rest, children }) {
7652
- const [open, setOpen] = React33.useState(false);
7670
+ const [open, setOpen] = React34.useState(false);
7653
7671
  const [anchor, pos] = useHoverCard(open);
7654
- const close = React33.useRef(null);
7672
+ const close = React34.useRef(null);
7655
7673
  const show = () => {
7656
7674
  if (close.current) {
7657
7675
  clearTimeout(close.current);
@@ -7667,10 +7685,10 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
7667
7685
  setOpen(false);
7668
7686
  }, 140);
7669
7687
  };
7670
- React33.useEffect(() => () => {
7688
+ React34.useEffect(() => () => {
7671
7689
  if (close.current) clearTimeout(close.current);
7672
7690
  }, []);
7673
- return /* @__PURE__ */ jsxs55(
7691
+ return /* @__PURE__ */ jsxs56(
7674
7692
  "span",
7675
7693
  {
7676
7694
  ref: anchor,
@@ -7681,8 +7699,8 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
7681
7699
  onBlur: hide,
7682
7700
  ...rest,
7683
7701
  children: [
7684
- /* @__PURE__ */ jsx60("span", { className: "fd-soon-under", style: { filter: "blur(" + Math.min(blur, 1.1) + "px) saturate(.66)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
7685
- /* @__PURE__ */ jsx60(
7702
+ /* @__PURE__ */ jsx61("span", { className: "fd-soon-under", style: { filter: "blur(" + Math.min(blur, 1.1) + "px) saturate(.66)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
7703
+ /* @__PURE__ */ jsx61(
7686
7704
  "button",
7687
7705
  {
7688
7706
  type: "button",
@@ -7693,11 +7711,11 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
7693
7711
  onFocus: show,
7694
7712
  onBlur: hide,
7695
7713
  onClick: () => open ? setOpen(false) : show(),
7696
- children: /* @__PURE__ */ jsx60("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
7714
+ children: /* @__PURE__ */ jsx61("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
7697
7715
  }
7698
7716
  ),
7699
7717
  open && pos ? createPortal8(
7700
- /* @__PURE__ */ jsx60(
7718
+ /* @__PURE__ */ jsx61(
7701
7719
  "div",
7702
7720
  {
7703
7721
  className: "fd-soon-note fd-soon-hovercard",
@@ -7705,7 +7723,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
7705
7723
  style: { position: "fixed", left: pos.left, top: pos.top, bottom: pos.bottom, width: pos.width },
7706
7724
  onMouseEnter: show,
7707
7725
  onMouseLeave: hide,
7708
- children: /* @__PURE__ */ jsx60(
7726
+ children: /* @__PURE__ */ jsx61(
7709
7727
  SoonCard,
7710
7728
  {
7711
7729
  label,
@@ -7735,10 +7753,10 @@ function formatEta(iso2) {
7735
7753
  var FormatEta = formatEta;
7736
7754
 
7737
7755
  // src/components/platform/Gate.tsx
7738
- import { jsx as jsx61, jsxs as jsxs56 } from "react/jsx-runtime";
7756
+ import { jsx as jsx62, jsxs as jsxs57 } from "react/jsx-runtime";
7739
7757
  function PermissionDenied({ permission, title, detail, compact: compact3 = false, className = "", ...rest }) {
7740
7758
  const need = Array.isArray(permission) ? permission : [permission].filter(Boolean);
7741
- return /* @__PURE__ */ jsxs56(
7759
+ return /* @__PURE__ */ jsxs57(
7742
7760
  "div",
7743
7761
  {
7744
7762
  className: ["fd-stack", className].filter(Boolean).join(" "),
@@ -7754,14 +7772,14 @@ function PermissionDenied({ permission, title, detail, compact: compact3 = false
7754
7772
  },
7755
7773
  ...rest,
7756
7774
  children: [
7757
- /* @__PURE__ */ jsxs56("span", { className: "fd-row", style: { gap: 8 }, children: [
7758
- /* @__PURE__ */ jsx61("i", { className: "ph ph-lock-simple", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
7759
- /* @__PURE__ */ jsx61("span", { className: compact3 ? "fd-label-lg" : "fd-h3", children: title || "You do not have access to this" })
7775
+ /* @__PURE__ */ jsxs57("span", { className: "fd-row", style: { gap: 8 }, children: [
7776
+ /* @__PURE__ */ jsx62("i", { className: "ph ph-lock-simple", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
7777
+ /* @__PURE__ */ jsx62("span", { className: compact3 ? "fd-label-lg" : "fd-h3", children: title || "You do not have access to this" })
7760
7778
  ] }),
7761
- /* @__PURE__ */ jsx61("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." }),
7762
- need.length ? /* @__PURE__ */ jsxs56("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: [
7763
- /* @__PURE__ */ jsx61("span", { className: "fd-overline fd-muted", children: "Requires" }),
7764
- need.map((p) => /* @__PURE__ */ jsx61("code", { className: "fd-mono", style: {
7779
+ /* @__PURE__ */ jsx62("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." }),
7780
+ need.length ? /* @__PURE__ */ jsxs57("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: [
7781
+ /* @__PURE__ */ jsx62("span", { className: "fd-overline fd-muted", children: "Requires" }),
7782
+ need.map((p) => /* @__PURE__ */ jsx62("code", { className: "fd-mono", style: {
7765
7783
  fontSize: 11.5,
7766
7784
  padding: "2px 7px",
7767
7785
  borderRadius: 5,
@@ -7782,7 +7800,7 @@ function Gate({ perm, anyOf, role, silent = false, fallback, compact: compact3 =
7782
7800
  if (ok) return children;
7783
7801
  if (fallback !== void 0) return fallback;
7784
7802
  if (silent) return null;
7785
- return /* @__PURE__ */ jsx61(PermissionDenied, { permission: perm || anyOf, compact: compact3 });
7803
+ return /* @__PURE__ */ jsx62(PermissionDenied, { permission: perm || anyOf, compact: compact3 });
7786
7804
  }
7787
7805
  function FeatureGate({
7788
7806
  flag,
@@ -7803,7 +7821,7 @@ function FeatureGate({
7803
7821
  if (!preview) return fallback;
7804
7822
  const f = SessionKit.findFlag(flag) || {};
7805
7823
  const missing = rt.missing || [];
7806
- return /* @__PURE__ */ jsx61(
7824
+ return /* @__PURE__ */ jsx62(
7807
7825
  ComingSoon,
7808
7826
  {
7809
7827
  label: label || (variant === "inline" ? f.label || "Not wired yet" : "Designed \u2014 backend not wired yet"),
@@ -7824,25 +7842,25 @@ function FeatureGate({
7824
7842
  function PermissionHint({ perm, children }) {
7825
7843
  SessionKit.useSession();
7826
7844
  if (SessionKit.can(perm)) return children;
7827
- return /* @__PURE__ */ jsx61(
7845
+ return /* @__PURE__ */ jsx62(
7828
7846
  "span",
7829
7847
  {
7830
7848
  title: "Requires " + (Array.isArray(perm) ? perm.join(", ") : perm),
7831
7849
  style: { display: "inline-flex", opacity: 0.45, cursor: "not-allowed" },
7832
7850
  "aria-disabled": "true",
7833
- children: /* @__PURE__ */ jsx61("span", { style: { pointerEvents: "none" }, children })
7851
+ children: /* @__PURE__ */ jsx62("span", { style: { pointerEvents: "none" }, children })
7834
7852
  }
7835
7853
  );
7836
7854
  }
7837
7855
 
7838
7856
  // src/components/platform/ModeSwitch.tsx
7839
- import * as React34 from "react";
7840
- import { Fragment as Fragment15, jsx as jsx62, jsxs as jsxs57 } from "react/jsx-runtime";
7857
+ import * as React35 from "react";
7858
+ import { Fragment as Fragment15, jsx as jsx63, jsxs as jsxs58 } from "react/jsx-runtime";
7841
7859
  function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
7842
7860
  const mode2 = useRuntimeMode();
7843
- const [open, setOpen] = React34.useState(false);
7844
- const ref = React34.useRef(null);
7845
- React34.useEffect(() => {
7861
+ const [open, setOpen] = React35.useState(false);
7862
+ const ref = React35.useRef(null);
7863
+ React35.useEffect(() => {
7846
7864
  if (!open) return;
7847
7865
  const away = (e) => {
7848
7866
  if (ref.current && !ref.current.contains(e.target)) setOpen(false);
@@ -7864,8 +7882,8 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
7864
7882
  RuntimeKit.setMode(next);
7865
7883
  setOpen(false);
7866
7884
  };
7867
- return /* @__PURE__ */ jsxs57("span", { style: { position: "relative", display: "inline-flex" }, ref, children: [
7868
- /* @__PURE__ */ jsxs57(
7885
+ return /* @__PURE__ */ jsxs58("span", { style: { position: "relative", display: "inline-flex" }, ref, children: [
7886
+ /* @__PURE__ */ jsxs58(
7869
7887
  "button",
7870
7888
  {
7871
7889
  type: "button",
@@ -7875,29 +7893,29 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
7875
7893
  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.",
7876
7894
  className: "fd-mode-btn" + (test ? " is-test" : "") + (open ? " is-open" : ""),
7877
7895
  children: [
7878
- /* @__PURE__ */ jsx62("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), style: { fontSize: 17 } }),
7879
- test && requestCount ? /* @__PURE__ */ jsx62("span", { className: "fd-mono fd-mode-count", children: requestCount > 99 ? "99+" : requestCount }, requestCount) : null
7896
+ /* @__PURE__ */ jsx63("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), style: { fontSize: 17 } }),
7897
+ test && requestCount ? /* @__PURE__ */ jsx63("span", { className: "fd-mono fd-mode-count", children: requestCount > 99 ? "99+" : requestCount }, requestCount) : null
7880
7898
  ]
7881
7899
  }
7882
7900
  ),
7883
- open ? /* @__PURE__ */ jsxs57("span", { className: "fd-view-enter fd-mode-pop", children: [
7884
- /* @__PURE__ */ jsxs57("span", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
7885
- /* @__PURE__ */ jsxs57("span", { className: "fd-badge " + (test ? "fd-badge-warning" : "fd-badge-neutral"), children: [
7886
- /* @__PURE__ */ jsx62("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), "aria-hidden": "true" }),
7901
+ open ? /* @__PURE__ */ jsxs58("span", { className: "fd-view-enter fd-mode-pop", children: [
7902
+ /* @__PURE__ */ jsxs58("span", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
7903
+ /* @__PURE__ */ jsxs58("span", { className: "fd-badge " + (test ? "fd-badge-warning" : "fd-badge-neutral"), children: [
7904
+ /* @__PURE__ */ jsx63("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), "aria-hidden": "true" }),
7887
7905
  test ? "Test mode" : "Live mode"
7888
7906
  ] }),
7889
- test ? /* @__PURE__ */ jsxs57("span", { className: "fd-body-sm fd-muted fd-mono", children: [
7907
+ test ? /* @__PURE__ */ jsxs58("span", { className: "fd-body-sm fd-muted fd-mono", children: [
7890
7908
  requestCount,
7891
7909
  " simulated request",
7892
7910
  requestCount === 1 ? "" : "s"
7893
7911
  ] }) : null,
7894
- /* @__PURE__ */ jsx62("span", { style: { flex: 1 } }),
7895
- test && onClearLog ? /* @__PURE__ */ jsx62("button", { type: "button", className: "fd-soon-link", onClick: onClearLog, children: "Clear" }) : null
7912
+ /* @__PURE__ */ jsx63("span", { style: { flex: 1 } }),
7913
+ test && onClearLog ? /* @__PURE__ */ jsx63("button", { type: "button", className: "fd-soon-link", onClick: onClearLog, children: "Clear" }) : null
7896
7914
  ] }),
7897
- /* @__PURE__ */ jsxs57("span", { style: { display: "block", padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
7898
- /* @__PURE__ */ jsx62("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." }),
7899
- /* @__PURE__ */ jsxs57("span", { className: "fd-row", style: { gap: 8, marginTop: 10, flexWrap: "wrap" }, children: [
7900
- /* @__PURE__ */ jsxs57("span", { className: "fd-body-sm fd-muted fd-mono", children: [
7915
+ /* @__PURE__ */ jsxs58("span", { style: { display: "block", padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
7916
+ /* @__PURE__ */ jsx63("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." }),
7917
+ /* @__PURE__ */ jsxs58("span", { className: "fd-row", style: { gap: 8, marginTop: 10, flexWrap: "wrap" }, children: [
7918
+ /* @__PURE__ */ jsxs58("span", { className: "fd-body-sm fd-muted fd-mono", children: [
7901
7919
  s.endpointsWired,
7902
7920
  " endpoint",
7903
7921
  s.endpointsWired === 1 ? "" : "s",
@@ -7907,58 +7925,58 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
7907
7925
  s.total,
7908
7926
  " features complete"
7909
7927
  ] }),
7910
- onOpenSpec ? /* @__PURE__ */ jsxs57(Fragment15, { children: [
7911
- /* @__PURE__ */ jsx62("span", { style: { flex: 1 } }),
7912
- /* @__PURE__ */ jsxs57("button", { type: "button", className: "fd-soon-link", onClick: () => {
7928
+ onOpenSpec ? /* @__PURE__ */ jsxs58(Fragment15, { children: [
7929
+ /* @__PURE__ */ jsx63("span", { style: { flex: 1 } }),
7930
+ /* @__PURE__ */ jsxs58("button", { type: "button", className: "fd-soon-link", onClick: () => {
7913
7931
  setOpen(false);
7914
7932
  onOpenSpec();
7915
7933
  }, children: [
7916
7934
  "API spec ",
7917
- /* @__PURE__ */ jsx62("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
7935
+ /* @__PURE__ */ jsx63("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
7918
7936
  ] })
7919
7937
  ] }) : null
7920
7938
  ] })
7921
7939
  ] }),
7922
- /* @__PURE__ */ jsxs57("span", { className: "fd-mode-choice", children: [
7923
- /* @__PURE__ */ jsxs57("button", { type: "button", className: "fd-mode-opt" + (!test ? " is-on" : ""), onClick: () => go("live"), children: [
7924
- /* @__PURE__ */ jsx62("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
7925
- /* @__PURE__ */ jsxs57("span", { className: "fd-mode-opt-text", children: [
7926
- /* @__PURE__ */ jsx62("span", { className: "fd-mode-opt-title", children: "Live mode" }),
7927
- /* @__PURE__ */ jsx62("span", { className: "fd-mode-opt-desc", children: "Incomplete features under construction" })
7940
+ /* @__PURE__ */ jsxs58("span", { className: "fd-mode-choice", children: [
7941
+ /* @__PURE__ */ jsxs58("button", { type: "button", className: "fd-mode-opt" + (!test ? " is-on" : ""), onClick: () => go("live"), children: [
7942
+ /* @__PURE__ */ jsx63("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
7943
+ /* @__PURE__ */ jsxs58("span", { className: "fd-mode-opt-text", children: [
7944
+ /* @__PURE__ */ jsx63("span", { className: "fd-mode-opt-title", children: "Live mode" }),
7945
+ /* @__PURE__ */ jsx63("span", { className: "fd-mode-opt-desc", children: "Incomplete features under construction" })
7928
7946
  ] }),
7929
- !test ? /* @__PURE__ */ jsx62("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
7947
+ !test ? /* @__PURE__ */ jsx63("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
7930
7948
  ] }),
7931
- /* @__PURE__ */ jsxs57("button", { type: "button", className: "fd-mode-opt" + (test ? " is-on" : ""), onClick: () => go("test"), children: [
7932
- /* @__PURE__ */ jsx62("i", { className: "ph ph-flask", "aria-hidden": "true" }),
7933
- /* @__PURE__ */ jsxs57("span", { className: "fd-mode-opt-text", children: [
7934
- /* @__PURE__ */ jsx62("span", { className: "fd-mode-opt-title", children: "Test mode" }),
7935
- /* @__PURE__ */ jsx62("span", { className: "fd-mode-opt-desc", children: "Everything usable, all data simulated" })
7949
+ /* @__PURE__ */ jsxs58("button", { type: "button", className: "fd-mode-opt" + (test ? " is-on" : ""), onClick: () => go("test"), children: [
7950
+ /* @__PURE__ */ jsx63("i", { className: "ph ph-flask", "aria-hidden": "true" }),
7951
+ /* @__PURE__ */ jsxs58("span", { className: "fd-mode-opt-text", children: [
7952
+ /* @__PURE__ */ jsx63("span", { className: "fd-mode-opt-title", children: "Test mode" }),
7953
+ /* @__PURE__ */ jsx63("span", { className: "fd-mode-opt-desc", children: "Everything usable, all data simulated" })
7936
7954
  ] }),
7937
- test ? /* @__PURE__ */ jsx62("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
7955
+ test ? /* @__PURE__ */ jsx63("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
7938
7956
  ] })
7939
7957
  ] }),
7940
- test && renderLog ? /* @__PURE__ */ jsx62("span", { style: { display: "block", maxHeight: 340, overflowY: "auto", borderTop: "1px solid var(--border)" }, children: renderLog() }) : null
7958
+ test && renderLog ? /* @__PURE__ */ jsx63("span", { style: { display: "block", maxHeight: 340, overflowY: "auto", borderTop: "1px solid var(--border)" }, children: renderLog() }) : null
7941
7959
  ] }) : null
7942
7960
  ] });
7943
7961
  }
7944
7962
  function TestModeBar({ onExit }) {
7945
7963
  const mode2 = useRuntimeMode();
7946
7964
  if (mode2 !== "test") return null;
7947
- return /* @__PURE__ */ jsxs57("div", { className: "fd-testbar", role: "status", children: [
7948
- /* @__PURE__ */ jsxs57("span", { className: "fd-badge fd-badge-warning", children: [
7949
- /* @__PURE__ */ jsx62("i", { className: "ph ph-flask", "aria-hidden": "true" }),
7965
+ return /* @__PURE__ */ jsxs58("div", { className: "fd-testbar", role: "status", children: [
7966
+ /* @__PURE__ */ jsxs58("span", { className: "fd-badge fd-badge-warning", children: [
7967
+ /* @__PURE__ */ jsx63("i", { className: "ph ph-flask", "aria-hidden": "true" }),
7950
7968
  "Test mode"
7951
7969
  ] }),
7952
- /* @__PURE__ */ jsx62("span", { className: "fd-testbar-detail", children: "Every feature is unlocked and every response is simulated \u2014 nothing here persists." }),
7953
- /* @__PURE__ */ jsxs57("button", { type: "button", className: "fd-soon-link", onClick: () => onExit ? onExit() : RuntimeKit.setMode("live"), children: [
7954
- /* @__PURE__ */ jsx62("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
7970
+ /* @__PURE__ */ jsx63("span", { className: "fd-testbar-detail", children: "Every feature is unlocked and every response is simulated \u2014 nothing here persists." }),
7971
+ /* @__PURE__ */ jsxs58("button", { type: "button", className: "fd-soon-link", onClick: () => onExit ? onExit() : RuntimeKit.setMode("live"), children: [
7972
+ /* @__PURE__ */ jsx63("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
7955
7973
  " Back to live mode"
7956
7974
  ] })
7957
7975
  ] });
7958
7976
  }
7959
7977
 
7960
7978
  // src/components/planner/ChannelMeta.tsx
7961
- import { jsx as jsx63, jsxs as jsxs58 } from "react/jsx-runtime";
7979
+ import { jsx as jsx64, jsxs as jsxs59 } from "react/jsx-runtime";
7962
7980
  var CHANNEL_WEIGHTS = {
7963
7981
  "OOH": 50,
7964
7982
  "DOOH": 50,
@@ -8011,9 +8029,9 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
8011
8029
  const m = ChannelMeta(channel);
8012
8030
  const wt = channelWeightOf(channel || "");
8013
8031
  if (dot) {
8014
- return /* @__PURE__ */ jsx63("span", { className: ["fd-chan-dot", className].filter(Boolean).join(" "), title: m.name, style: { background: m.color }, ...rest });
8032
+ return /* @__PURE__ */ jsx64("span", { className: ["fd-chan-dot", className].filter(Boolean).join(" "), title: m.name, style: { background: m.color }, ...rest });
8015
8033
  }
8016
- return /* @__PURE__ */ jsxs58(
8034
+ return /* @__PURE__ */ jsxs59(
8017
8035
  "span",
8018
8036
  {
8019
8037
  className: ["fd-chan", size === "sm" ? "fd-chan-sm" : "", className].filter(Boolean).join(" "),
@@ -8021,16 +8039,16 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
8021
8039
  style: { "--chan": m.color },
8022
8040
  ...rest,
8023
8041
  children: [
8024
- /* @__PURE__ */ jsx63("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }),
8025
- showLabel ? /* @__PURE__ */ jsx63("span", { className: "fd-chan-label", children: m.label }) : null,
8026
- weight ? /* @__PURE__ */ jsx63("span", { className: "fd-chan-weight", children: wt || 0 }) : null
8042
+ /* @__PURE__ */ jsx64("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }),
8043
+ showLabel ? /* @__PURE__ */ jsx64("span", { className: "fd-chan-label", children: m.label }) : null,
8044
+ weight ? /* @__PURE__ */ jsx64("span", { className: "fd-chan-weight", children: wt || 0 }) : null
8027
8045
  ]
8028
8046
  }
8029
8047
  );
8030
8048
  }
8031
8049
 
8032
8050
  // src/components/planner/SaturationDistribution.tsx
8033
- import { jsx as jsx64, jsxs as jsxs59 } from "react/jsx-runtime";
8051
+ import { jsx as jsx65, jsxs as jsxs60 } from "react/jsx-runtime";
8034
8052
  var BANDS2 = [
8035
8053
  { key: "weak", label: "Weak", n: 1, range: "< 50" },
8036
8054
  { key: "adequate", label: "Adequate", n: 2, range: "50\u2013100" },
@@ -8041,18 +8059,18 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
8041
8059
  const grouped = BANDS2.map((b) => ({ ...b, items: campuses.filter((c) => c.band === b.key) }));
8042
8060
  const tallest = Math.max(1, ...grouped.map((g) => g.items.length));
8043
8061
  const floor = BANDS2.find((b) => b.key === floorBand) || BANDS2[0];
8044
- return /* @__PURE__ */ jsxs59("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
8045
- /* @__PURE__ */ jsx64("div", { style: { display: "grid", gridTemplateColumns: "repeat(4,1fr)", gap: 12, alignItems: "end" }, children: grouped.map((g) => {
8062
+ return /* @__PURE__ */ jsxs60("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
8063
+ /* @__PURE__ */ jsx65("div", { style: { display: "grid", gridTemplateColumns: "repeat(4,1fr)", gap: 12, alignItems: "end" }, children: grouped.map((g) => {
8046
8064
  const mark = "var(--csi-" + g.n + "-mark)";
8047
8065
  const active = selectedBand === g.key;
8048
- return /* @__PURE__ */ jsxs59(
8066
+ return /* @__PURE__ */ jsxs60(
8049
8067
  "button",
8050
8068
  {
8051
8069
  type: "button",
8052
8070
  onClick: onSelectBand ? () => onSelectBand(active ? null : g.key) : void 0,
8053
8071
  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)" },
8054
8072
  children: [
8055
- /* @__PURE__ */ jsx64("span", { style: { display: "flex", flexDirection: "column-reverse", gap: 4, minHeight: tallest * 24 }, children: loading ? Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ jsx64("span", { className: "fd-skel", style: { height: 16, borderRadius: 4 } }, i)) : g.items.map((c) => /* @__PURE__ */ jsx64(
8073
+ /* @__PURE__ */ jsx65("span", { style: { display: "flex", flexDirection: "column-reverse", gap: 4, minHeight: tallest * 24 }, children: loading ? Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ jsx65("span", { className: "fd-skel", style: { height: 16, borderRadius: 4 } }, i)) : g.items.map((c) => /* @__PURE__ */ jsx65(
8056
8074
  "span",
8057
8075
  {
8058
8076
  title: c.name + " \xB7 " + c.crp,
@@ -8061,13 +8079,13 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
8061
8079
  },
8062
8080
  c.name
8063
8081
  )) }),
8064
- /* @__PURE__ */ jsxs59("span", { className: "fd-row", style: { gap: 8, alignItems: "baseline" }, children: [
8065
- /* @__PURE__ */ jsx64("span", { className: "fd-num-hero", style: { fontSize: 30, color: g.items.length ? "var(--text)" : "var(--text-disabled)" }, children: loading ? "\u2013" : g.items.length }),
8066
- /* @__PURE__ */ jsx64("span", { className: "fd-meter", style: { gap: 2, color: mark }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx64("span", { className: "fd-meter-seg" + (i <= g.n ? " is-on" : ""), style: { width: 4, height: 9 } }, i)) })
8082
+ /* @__PURE__ */ jsxs60("span", { className: "fd-row", style: { gap: 8, alignItems: "baseline" }, children: [
8083
+ /* @__PURE__ */ jsx65("span", { className: "fd-num-hero", style: { fontSize: 30, color: g.items.length ? "var(--text)" : "var(--text-disabled)" }, children: loading ? "\u2013" : g.items.length }),
8084
+ /* @__PURE__ */ jsx65("span", { className: "fd-meter", style: { gap: 2, color: mark }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx65("span", { className: "fd-meter-seg" + (i <= g.n ? " is-on" : ""), style: { width: 4, height: 9 } }, i)) })
8067
8085
  ] }),
8068
- /* @__PURE__ */ jsxs59("span", { className: "fd-stack", style: { gap: 1 }, children: [
8069
- /* @__PURE__ */ jsx64("span", { className: "fd-label-lg", children: g.label }),
8070
- /* @__PURE__ */ jsxs59("span", { className: "fd-body-sm fd-muted", style: { fontSize: 11.5 }, children: [
8086
+ /* @__PURE__ */ jsxs60("span", { className: "fd-stack", style: { gap: 1 }, children: [
8087
+ /* @__PURE__ */ jsx65("span", { className: "fd-label-lg", children: g.label }),
8088
+ /* @__PURE__ */ jsxs60("span", { className: "fd-body-sm fd-muted", style: { fontSize: 11.5 }, children: [
8071
8089
  "CRP ",
8072
8090
  g.range
8073
8091
  ] })
@@ -8077,10 +8095,10 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
8077
8095
  g.key
8078
8096
  );
8079
8097
  }) }),
8080
- floorBand ? /* @__PURE__ */ jsxs59("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: [
8081
- /* @__PURE__ */ jsx64("span", { className: "fd-meter", style: { gap: 2, color: "var(--csi-" + floor.n + "-mark)" }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx64("span", { className: "fd-meter-seg" + (i <= floor.n ? " is-on" : ""), style: { width: 5, height: 12 } }, i)) }),
8082
- /* @__PURE__ */ jsxs59("span", { className: "fd-body-sm fd-secondary", style: { flex: 1, minWidth: 240 }, children: [
8083
- /* @__PURE__ */ jsxs59("strong", { style: { color: "var(--text)" }, children: [
8098
+ floorBand ? /* @__PURE__ */ jsxs60("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: [
8099
+ /* @__PURE__ */ jsx65("span", { className: "fd-meter", style: { gap: 2, color: "var(--csi-" + floor.n + "-mark)" }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx65("span", { className: "fd-meter-seg" + (i <= floor.n ? " is-on" : ""), style: { width: 5, height: 12 } }, i)) }),
8100
+ /* @__PURE__ */ jsxs60("span", { className: "fd-body-sm fd-secondary", style: { flex: 1, minWidth: 240 }, children: [
8101
+ /* @__PURE__ */ jsxs60("strong", { style: { color: "var(--text)" }, children: [
8084
8102
  "Plan floor ",
8085
8103
  floorScore
8086
8104
  ] }),
@@ -8091,21 +8109,21 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
8091
8109
  }
8092
8110
 
8093
8111
  // src/components/planner/MixGap.tsx
8094
- import * as React35 from "react";
8095
- import { Fragment as Fragment16, jsx as jsx65, jsxs as jsxs60 } from "react/jsx-runtime";
8112
+ import * as React36 from "react";
8113
+ import { Fragment as Fragment16, jsx as jsx66, jsxs as jsxs61 } from "react/jsx-runtime";
8096
8114
  function MixGap({ rows = [], loading = false, className = "" }) {
8097
8115
  const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
8098
- const [hover, setHover] = React35.useState(null);
8116
+ const [hover, setHover] = React36.useState(null);
8099
8117
  const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
8100
8118
  const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
8101
- return /* @__PURE__ */ jsxs60("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 4 }, children: [
8102
- /* @__PURE__ */ jsxs60("div", { className: "fd-row", style: { gap: 16, justifyContent: "flex-end", paddingBottom: 6, flexWrap: "wrap" }, children: [
8103
- [["On target", TONE.ok], ["Close", TONE.warn], ["Short", TONE.danger]].map(([l, c]) => /* @__PURE__ */ jsxs60("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
8104
- /* @__PURE__ */ jsx65("span", { style: { width: 14, height: 9, borderRadius: 2, background: c } }),
8119
+ return /* @__PURE__ */ jsxs61("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 4 }, children: [
8120
+ /* @__PURE__ */ jsxs61("div", { className: "fd-row", style: { gap: 16, justifyContent: "flex-end", paddingBottom: 6, flexWrap: "wrap" }, children: [
8121
+ [["On target", TONE.ok], ["Close", TONE.warn], ["Short", TONE.danger]].map(([l, c]) => /* @__PURE__ */ jsxs61("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
8122
+ /* @__PURE__ */ jsx66("span", { style: { width: 14, height: 9, borderRadius: 2, background: c } }),
8105
8123
  l
8106
8124
  ] }, l)),
8107
- /* @__PURE__ */ jsxs60("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
8108
- /* @__PURE__ */ jsx65("span", { style: { width: 3, height: 14, background: "var(--n-500)" } }),
8125
+ /* @__PURE__ */ jsxs61("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
8126
+ /* @__PURE__ */ jsx66("span", { style: { width: 3, height: 14, background: "var(--n-500)" } }),
8109
8127
  "Target"
8110
8128
  ] })
8111
8129
  ] }),
@@ -8113,7 +8131,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
8113
8131
  const gap = r.realized - r.target;
8114
8132
  const tone = toneOf(gap);
8115
8133
  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 : "");
8116
- return /* @__PURE__ */ jsxs60(
8134
+ return /* @__PURE__ */ jsxs61(
8117
8135
  "div",
8118
8136
  {
8119
8137
  className: "fd-row",
@@ -8121,15 +8139,15 @@ function MixGap({ rows = [], loading = false, className = "" }) {
8121
8139
  onMouseEnter: () => setHover(r.channel),
8122
8140
  onMouseLeave: () => setHover(null),
8123
8141
  children: [
8124
- /* @__PURE__ */ jsx65("span", { style: { width: 128, flex: "none" }, children: /* @__PURE__ */ jsx65(ChannelTag, { channel: r.channel, size: "sm" }) }),
8125
- /* @__PURE__ */ jsx65("span", { style: { position: "relative", flex: 1, height: 22, minWidth: 120 }, children: loading ? /* @__PURE__ */ jsx65("span", { className: "fd-skel", style: { position: "absolute", inset: "5px 0", borderRadius: 3 } }) : /* @__PURE__ */ jsxs60(Fragment16, { children: [
8126
- /* @__PURE__ */ jsx65("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)" } }),
8127
- /* @__PURE__ */ jsx65("span", { style: { position: "absolute", left: r.target / max * 100 + "%", top: 0, width: 3, height: 22, background: "var(--n-500)", borderRadius: 1 } }),
8128
- /* @__PURE__ */ jsxs60("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: [
8142
+ /* @__PURE__ */ jsx66("span", { style: { width: 128, flex: "none" }, children: /* @__PURE__ */ jsx66(ChannelTag, { channel: r.channel, size: "sm" }) }),
8143
+ /* @__PURE__ */ jsx66("span", { style: { position: "relative", flex: 1, height: 22, minWidth: 120 }, children: loading ? /* @__PURE__ */ jsx66("span", { className: "fd-skel", style: { position: "absolute", inset: "5px 0", borderRadius: 3 } }) : /* @__PURE__ */ jsxs61(Fragment16, { children: [
8144
+ /* @__PURE__ */ jsx66("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)" } }),
8145
+ /* @__PURE__ */ jsx66("span", { style: { position: "absolute", left: r.target / max * 100 + "%", top: 0, width: 3, height: 22, background: "var(--n-500)", borderRadius: 1 } }),
8146
+ /* @__PURE__ */ jsxs61("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: [
8129
8147
  r.realized,
8130
8148
  "%"
8131
8149
  ] }),
8132
- hover === r.channel ? /* @__PURE__ */ jsx65("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
8150
+ hover === r.channel ? /* @__PURE__ */ jsx66("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
8133
8151
  ] }) })
8134
8152
  ]
8135
8153
  },
@@ -8140,7 +8158,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
8140
8158
  }
8141
8159
 
8142
8160
  // src/components/planner/ChannelContribution.tsx
8143
- import { jsx as jsx66, jsxs as jsxs61 } from "react/jsx-runtime";
8161
+ import { jsx as jsx67, jsxs as jsxs62 } from "react/jsx-runtime";
8144
8162
  var money = (n) => "$" + Math.round(n).toLocaleString();
8145
8163
  function ChannelContribution({
8146
8164
  channels = [],
@@ -8156,9 +8174,9 @@ function ChannelContribution({
8156
8174
  const grand = total !== void 0 ? total : base + bonus;
8157
8175
  const pct = (v) => grand ? v / grand * 100 : 0;
8158
8176
  const spendTotal = channels.reduce((s, c) => s + Number(String(c.spend || 0).replace(/[^0-9.]/g, "")), 0);
8159
- return /* @__PURE__ */ jsxs61("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
8160
- loading ? /* @__PURE__ */ jsx66("span", { className: "fd-skel", style: { height: 34, borderRadius: "var(--r-sm)" } }) : /* @__PURE__ */ jsxs61("div", { className: "fd-row", style: { height: 34, borderRadius: "var(--r-sm)", overflow: "hidden", gap: 2, background: "var(--surface-3)" }, children: [
8161
- channels.map((c) => /* @__PURE__ */ jsx66(
8177
+ return /* @__PURE__ */ jsxs62("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
8178
+ loading ? /* @__PURE__ */ jsx67("span", { className: "fd-skel", style: { height: 34, borderRadius: "var(--r-sm)" } }) : /* @__PURE__ */ jsxs62("div", { className: "fd-row", style: { height: 34, borderRadius: "var(--r-sm)", overflow: "hidden", gap: 2, background: "var(--surface-3)" }, children: [
8179
+ channels.map((c) => /* @__PURE__ */ jsx67(
8162
8180
  "span",
8163
8181
  {
8164
8182
  title: c.name + " \xB7 " + c.crp.toFixed(1) + " CRP",
@@ -8167,7 +8185,7 @@ function ChannelContribution({
8167
8185
  },
8168
8186
  c.name
8169
8187
  )),
8170
- bonus > 0 ? /* @__PURE__ */ jsx66(
8188
+ bonus > 0 ? /* @__PURE__ */ jsx67(
8171
8189
  "span",
8172
8190
  {
8173
8191
  title: "Surround-sound bonus +" + bonusPct + "%",
@@ -8176,18 +8194,18 @@ function ChannelContribution({
8176
8194
  }
8177
8195
  ) : null
8178
8196
  ] }),
8179
- showTable ? /* @__PURE__ */ jsxs61("table", { className: "fd-table", style: { fontSize: "var(--body-sm-size)" }, children: [
8180
- /* @__PURE__ */ jsx66("thead", { children: /* @__PURE__ */ jsxs61("tr", { children: [
8181
- /* @__PURE__ */ jsx66("th", { style: { width: "34%" }, children: "Channel" }),
8182
- /* @__PURE__ */ jsx66("th", { style: { width: "16%" }, children: "Weight" }),
8183
- /* @__PURE__ */ jsx66("th", { className: "is-num", style: { width: "16%" }, children: "Spend" }),
8184
- /* @__PURE__ */ jsx66("th", { className: "is-num", style: { width: "17%" }, children: "CRP" }),
8185
- /* @__PURE__ */ jsx66("th", { className: "is-num", style: { width: "17%" }, children: "Share" })
8197
+ showTable ? /* @__PURE__ */ jsxs62("table", { className: "fd-table", style: { fontSize: "var(--body-sm-size)" }, children: [
8198
+ /* @__PURE__ */ jsx67("thead", { children: /* @__PURE__ */ jsxs62("tr", { children: [
8199
+ /* @__PURE__ */ jsx67("th", { style: { width: "34%" }, children: "Channel" }),
8200
+ /* @__PURE__ */ jsx67("th", { style: { width: "16%" }, children: "Weight" }),
8201
+ /* @__PURE__ */ jsx67("th", { className: "is-num", style: { width: "16%" }, children: "Spend" }),
8202
+ /* @__PURE__ */ jsx67("th", { className: "is-num", style: { width: "17%" }, children: "CRP" }),
8203
+ /* @__PURE__ */ jsx67("th", { className: "is-num", style: { width: "17%" }, children: "Share" })
8186
8204
  ] }) }),
8187
- /* @__PURE__ */ jsxs61("tbody", { children: [
8188
- channels.map((c) => /* @__PURE__ */ jsxs61("tr", { children: [
8189
- /* @__PURE__ */ jsx66("td", { children: /* @__PURE__ */ jsx66(ChannelTag, { channel: c.name, size: "sm" }) }),
8190
- /* @__PURE__ */ jsx66("td", { children: /* @__PURE__ */ jsx66(
8205
+ /* @__PURE__ */ jsxs62("tbody", { children: [
8206
+ channels.map((c) => /* @__PURE__ */ jsxs62("tr", { children: [
8207
+ /* @__PURE__ */ jsx67("td", { children: /* @__PURE__ */ jsx67(ChannelTag, { channel: c.name, size: "sm" }) }),
8208
+ /* @__PURE__ */ jsx67("td", { children: /* @__PURE__ */ jsx67(
8191
8209
  "span",
8192
8210
  {
8193
8211
  className: "fd-badge fd-badge-neutral",
@@ -8196,38 +8214,38 @@ function ChannelContribution({
8196
8214
  children: "weight " + (channelWeightOf(c.name) || 0)
8197
8215
  }
8198
8216
  ) }),
8199
- /* @__PURE__ */ jsx66("td", { className: "is-num", children: c.spend }),
8200
- /* @__PURE__ */ jsx66("td", { className: "is-num", children: c.crp.toFixed(1) }),
8201
- /* @__PURE__ */ jsxs61("td", { className: "is-num", children: [
8217
+ /* @__PURE__ */ jsx67("td", { className: "is-num", children: c.spend }),
8218
+ /* @__PURE__ */ jsx67("td", { className: "is-num", children: c.crp.toFixed(1) }),
8219
+ /* @__PURE__ */ jsxs62("td", { className: "is-num", children: [
8202
8220
  pct(c.crp).toFixed(0),
8203
8221
  "%"
8204
8222
  ] })
8205
8223
  ] }, c.name)),
8206
- bonus > 0 ? /* @__PURE__ */ jsxs61("tr", { children: [
8207
- /* @__PURE__ */ jsx66("td", { children: /* @__PURE__ */ jsxs61("span", { className: "fd-row", style: { gap: 9, fontWeight: 600 }, children: [
8208
- /* @__PURE__ */ jsx66("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" } }),
8224
+ bonus > 0 ? /* @__PURE__ */ jsxs62("tr", { children: [
8225
+ /* @__PURE__ */ jsx67("td", { children: /* @__PURE__ */ jsxs62("span", { className: "fd-row", style: { gap: 9, fontWeight: 600 }, children: [
8226
+ /* @__PURE__ */ jsx67("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" } }),
8209
8227
  "Surround-sound bonus"
8210
8228
  ] }) }),
8211
- /* @__PURE__ */ jsx66("td", { children: /* @__PURE__ */ jsxs61("span", { className: "fd-badge fd-badge-success", style: { height: 20, fontSize: 11 }, children: [
8229
+ /* @__PURE__ */ jsx67("td", { children: /* @__PURE__ */ jsxs62("span", { className: "fd-badge fd-badge-success", style: { height: 20, fontSize: 11 }, children: [
8212
8230
  "+",
8213
8231
  bonusPct,
8214
8232
  "% of +",
8215
8233
  bonusMax,
8216
8234
  "%"
8217
8235
  ] }) }),
8218
- /* @__PURE__ */ jsx66("td", { className: "is-num fd-muted", children: "\u2014" }),
8219
- /* @__PURE__ */ jsx66("td", { className: "is-num", children: bonus.toFixed(1) }),
8220
- /* @__PURE__ */ jsxs61("td", { className: "is-num", children: [
8236
+ /* @__PURE__ */ jsx67("td", { className: "is-num fd-muted", children: "\u2014" }),
8237
+ /* @__PURE__ */ jsx67("td", { className: "is-num", children: bonus.toFixed(1) }),
8238
+ /* @__PURE__ */ jsxs62("td", { className: "is-num", children: [
8221
8239
  pct(bonus).toFixed(0),
8222
8240
  "%"
8223
8241
  ] })
8224
8242
  ] }) : null,
8225
- /* @__PURE__ */ jsxs61("tr", { style: { background: "var(--surface-2)" }, children: [
8226
- /* @__PURE__ */ jsx66("td", { style: { fontWeight: 700 }, children: "Campus total" }),
8227
- /* @__PURE__ */ jsx66("td", {}),
8228
- /* @__PURE__ */ jsx66("td", { className: "is-num", style: { fontWeight: 700 }, children: money(spendTotal) }),
8229
- /* @__PURE__ */ jsx66("td", { className: "is-num", style: { fontWeight: 700 }, children: grand.toFixed(1) }),
8230
- /* @__PURE__ */ jsx66("td", { className: "is-num", style: { fontWeight: 700 }, children: "100%" })
8243
+ /* @__PURE__ */ jsxs62("tr", { style: { background: "var(--surface-2)" }, children: [
8244
+ /* @__PURE__ */ jsx67("td", { style: { fontWeight: 700 }, children: "Campus total" }),
8245
+ /* @__PURE__ */ jsx67("td", {}),
8246
+ /* @__PURE__ */ jsx67("td", { className: "is-num", style: { fontWeight: 700 }, children: money(spendTotal) }),
8247
+ /* @__PURE__ */ jsx67("td", { className: "is-num", style: { fontWeight: 700 }, children: grand.toFixed(1) }),
8248
+ /* @__PURE__ */ jsx67("td", { className: "is-num", style: { fontWeight: 700 }, children: "100%" })
8231
8249
  ] })
8232
8250
  ] })
8233
8251
  ] }) : null
@@ -8235,8 +8253,8 @@ function ChannelContribution({
8235
8253
  }
8236
8254
 
8237
8255
  // src/components/planner/BudgetReallocator.tsx
8238
- import * as React36 from "react";
8239
- import { Fragment as Fragment17, jsx as jsx67, jsxs as jsxs62 } from "react/jsx-runtime";
8256
+ import * as React37 from "react";
8257
+ import { Fragment as Fragment17, jsx as jsx68, jsxs as jsxs63 } from "react/jsx-runtime";
8240
8258
  var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
8241
8259
  function BudgetReallocator({
8242
8260
  campus,
@@ -8251,8 +8269,8 @@ function BudgetReallocator({
8251
8269
  onCancel,
8252
8270
  className = ""
8253
8271
  }) {
8254
- const [draft, setDraft] = React36.useState(spend);
8255
- React36.useEffect(() => setDraft(spend), [spend]);
8272
+ const [draft, setDraft] = React37.useState(spend);
8273
+ React37.useEffect(() => setDraft(spend), [spend]);
8256
8274
  const dirty = draft !== spend;
8257
8275
  const nextCrp = scoreFor ? scoreFor(draft) : crp;
8258
8276
  const nextBand = bandFor(nextCrp);
@@ -8267,24 +8285,24 @@ function BudgetReallocator({
8267
8285
  setDraft(spend);
8268
8286
  if (onCancel) onCancel();
8269
8287
  };
8270
- return /* @__PURE__ */ jsxs62(
8288
+ return /* @__PURE__ */ jsxs63(
8271
8289
  "div",
8272
8290
  {
8273
8291
  className: ["fd-stack", className].filter(Boolean).join(" "),
8274
8292
  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)" },
8275
8293
  children: [
8276
- /* @__PURE__ */ jsxs62("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
8277
- /* @__PURE__ */ jsx67("span", { className: "fd-h4", style: { flex: 1, minWidth: 140 }, children: campus }),
8278
- /* @__PURE__ */ jsx67(CsiBadge, { band: nowBand, crp, size: "medium" }),
8279
- dirty ? /* @__PURE__ */ jsxs62(Fragment17, { children: [
8280
- /* @__PURE__ */ jsx67("i", { className: "ph ph-arrow-right fd-muted", "aria-hidden": "true" }),
8281
- /* @__PURE__ */ jsx67(CsiBadge, { band: nextBand, crp: nextCrp, size: "medium", preview: true })
8294
+ /* @__PURE__ */ jsxs63("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
8295
+ /* @__PURE__ */ jsx68("span", { className: "fd-h4", style: { flex: 1, minWidth: 140 }, children: campus }),
8296
+ /* @__PURE__ */ jsx68(CsiBadge, { band: nowBand, crp, size: "medium" }),
8297
+ dirty ? /* @__PURE__ */ jsxs63(Fragment17, { children: [
8298
+ /* @__PURE__ */ jsx68("i", { className: "ph ph-arrow-right fd-muted", "aria-hidden": "true" }),
8299
+ /* @__PURE__ */ jsx68(CsiBadge, { band: nextBand, crp: nextCrp, size: "medium", preview: true })
8282
8300
  ] }) : null
8283
8301
  ] }),
8284
- /* @__PURE__ */ jsxs62("div", { className: "fd-slider", children: [
8285
- /* @__PURE__ */ jsx67("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
8286
- dirty ? /* @__PURE__ */ jsx67("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,
8287
- /* @__PURE__ */ jsx67(
8302
+ /* @__PURE__ */ jsxs63("div", { className: "fd-slider", children: [
8303
+ /* @__PURE__ */ jsx68("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
8304
+ dirty ? /* @__PURE__ */ jsx68("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,
8305
+ /* @__PURE__ */ jsx68(
8288
8306
  "input",
8289
8307
  {
8290
8308
  type: "range",
@@ -8300,13 +8318,13 @@ function BudgetReallocator({
8300
8318
  }
8301
8319
  )
8302
8320
  ] }),
8303
- /* @__PURE__ */ jsxs62("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
8304
- /* @__PURE__ */ jsxs62("span", { className: "fd-stack", style: { gap: 2, flex: 1, minWidth: 150 }, children: [
8305
- /* @__PURE__ */ jsx67("span", { className: "fd-num", style: { fontSize: 19, fontWeight: 700 }, children: "$" + draft.toLocaleString() }),
8306
- /* @__PURE__ */ jsx67("span", { className: "fd-body-sm fd-muted", children: "Arrow keys step $100, shift+arrow $1,000. Escape reverts." })
8321
+ /* @__PURE__ */ jsxs63("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
8322
+ /* @__PURE__ */ jsxs63("span", { className: "fd-stack", style: { gap: 2, flex: 1, minWidth: 150 }, children: [
8323
+ /* @__PURE__ */ jsx68("span", { className: "fd-num", style: { fontSize: 19, fontWeight: 700 }, children: "$" + draft.toLocaleString() }),
8324
+ /* @__PURE__ */ jsx68("span", { className: "fd-body-sm fd-muted", children: "Arrow keys step $100, shift+arrow $1,000. Escape reverts." })
8307
8325
  ] }),
8308
- /* @__PURE__ */ jsx67("button", { type: "button", className: "fd-btn fd-btn-ghost", disabled: !dirty, onClick: revert, children: "Cancel" }),
8309
- /* @__PURE__ */ jsx67(
8326
+ /* @__PURE__ */ jsx68("button", { type: "button", className: "fd-btn fd-btn-ghost", disabled: !dirty, onClick: revert, children: "Cancel" }),
8327
+ /* @__PURE__ */ jsx68(
8310
8328
  "button",
8311
8329
  {
8312
8330
  type: "button",
@@ -8325,7 +8343,7 @@ function BudgetReallocator({
8325
8343
  }
8326
8344
 
8327
8345
  // src/components/planner/SurroundSound.tsx
8328
- import { jsx as jsx68, jsxs as jsxs63 } from "react/jsx-runtime";
8346
+ import { jsx as jsx69, jsxs as jsxs64 } from "react/jsx-runtime";
8329
8347
  var CATEGORIES = [
8330
8348
  { key: "ooh", label: "OOH", icon: "flag-banner", color: "var(--ch-ooh)" },
8331
8349
  { key: "transit", label: "Transit", icon: "bus", color: "var(--ch-transit)" },
@@ -8337,26 +8355,26 @@ var CATEGORIES = [
8337
8355
  function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost, className = "" }) {
8338
8356
  const earned = Math.max(0, Math.min(1, bonusPct / bonusMax));
8339
8357
  const single = present.length <= 2;
8340
- return /* @__PURE__ */ jsxs63("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, children: [
8341
- /* @__PURE__ */ jsx68("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: CATEGORIES.map((c) => {
8358
+ return /* @__PURE__ */ jsxs64("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, children: [
8359
+ /* @__PURE__ */ jsx69("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: CATEGORIES.map((c) => {
8342
8360
  const on = present.includes(c.key);
8343
- return /* @__PURE__ */ jsxs63(
8361
+ return /* @__PURE__ */ jsxs64(
8344
8362
  "span",
8345
8363
  {
8346
8364
  title: c.label + (on ? " \u2014 present" : " \u2014 not bought"),
8347
8365
  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)" },
8348
8366
  children: [
8349
- /* @__PURE__ */ jsx68("i", { className: "ph ph-" + c.icon, style: { fontSize: 19, color: on ? c.color : "var(--text-muted)" }, "aria-hidden": "true" }),
8350
- /* @__PURE__ */ jsx68("span", { style: { fontSize: 10.5, fontWeight: 700 }, children: c.label })
8367
+ /* @__PURE__ */ jsx69("i", { className: "ph ph-" + c.icon, style: { fontSize: 19, color: on ? c.color : "var(--text-muted)" }, "aria-hidden": "true" }),
8368
+ /* @__PURE__ */ jsx69("span", { style: { fontSize: 10.5, fontWeight: 700 }, children: c.label })
8351
8369
  ]
8352
8370
  },
8353
8371
  c.key
8354
8372
  );
8355
8373
  }) }),
8356
- /* @__PURE__ */ jsxs63("div", { className: "fd-stack", style: { gap: 8 }, children: [
8357
- /* @__PURE__ */ jsxs63("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
8358
- /* @__PURE__ */ jsx68("span", { className: "fd-label-lg", children: "Surround-sound bonus earned" }),
8359
- /* @__PURE__ */ jsxs63("span", { className: "fd-num", style: { color: single ? "var(--warn-text)" : "var(--csi-3-mark)", fontWeight: 700 }, children: [
8374
+ /* @__PURE__ */ jsxs64("div", { className: "fd-stack", style: { gap: 8 }, children: [
8375
+ /* @__PURE__ */ jsxs64("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
8376
+ /* @__PURE__ */ jsx69("span", { className: "fd-label-lg", children: "Surround-sound bonus earned" }),
8377
+ /* @__PURE__ */ jsxs64("span", { className: "fd-num", style: { color: single ? "var(--warn-text)" : "var(--csi-3-mark)", fontWeight: 700 }, children: [
8360
8378
  "+",
8361
8379
  bonusPct,
8362
8380
  "% of +",
@@ -8364,8 +8382,8 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
8364
8382
  "%"
8365
8383
  ] })
8366
8384
  ] }),
8367
- /* @__PURE__ */ jsx68("div", { style: { height: 8, borderRadius: "var(--r-xs)", background: "var(--surface-3)", overflow: "hidden" }, children: /* @__PURE__ */ jsx68("div", { style: { height: "100%", width: earned * 100 + "%", background: "var(--csi-3-mark)", borderRadius: "inherit", transition: "width var(--dur-slow) var(--ease)" } }) }),
8368
- /* @__PURE__ */ jsxs63("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: [
8385
+ /* @__PURE__ */ jsx69("div", { style: { height: 8, borderRadius: "var(--r-xs)", background: "var(--surface-3)", overflow: "hidden" }, children: /* @__PURE__ */ jsx69("div", { style: { height: "100%", width: earned * 100 + "%", background: "var(--csi-3-mark)", borderRadius: "inherit", transition: "width var(--dur-slow) var(--ease)" } }) }),
8386
+ /* @__PURE__ */ jsxs64("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: [
8369
8387
  present.length,
8370
8388
  " of 6 channel categories present.",
8371
8389
  " ",
@@ -8377,7 +8395,7 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
8377
8395
  }
8378
8396
 
8379
8397
  // src/components/planner/Importance.tsx
8380
- import { jsx as jsx69, jsxs as jsxs64 } from "react/jsx-runtime";
8398
+ import { jsx as jsx70, jsxs as jsxs65 } from "react/jsx-runtime";
8381
8399
  var IMPORTANCE_LEVELS = [
8382
8400
  { id: "nudge", rank: 1, label: "Nudge", icon: "feather", description: "Breaks a tie, nothing more." },
8383
8401
  { id: "lean", rank: 2, label: "Lean", icon: "arrow-bend-up-right", description: "A mild preference between otherwise equal options." },
@@ -8407,23 +8425,23 @@ function importanceTokens(id) {
8407
8425
  function ImportanceTag({ level, showLabel = true, size = "sm", className = "" }) {
8408
8426
  const lvl = importanceLevel(level);
8409
8427
  const t = importanceTokens(level);
8410
- return /* @__PURE__ */ jsxs64(
8428
+ return /* @__PURE__ */ jsxs65(
8411
8429
  "span",
8412
8430
  {
8413
8431
  className: ["fd-imp-tag", size === "md" ? "is-md" : "", className].filter(Boolean).join(" "),
8414
8432
  style: { background: t.fill, borderColor: t.edge, color: t.text },
8415
8433
  title: lvl.label + " \u2014 " + lvl.description,
8416
8434
  children: [
8417
- /* @__PURE__ */ jsx69("i", { className: "ph ph-" + lvl.icon, "aria-hidden": "true" }),
8418
- showLabel ? lvl.label : /* @__PURE__ */ jsx69("span", { className: "fd-sr", children: lvl.label })
8435
+ /* @__PURE__ */ jsx70("i", { className: "ph ph-" + lvl.icon, "aria-hidden": "true" }),
8436
+ showLabel ? lvl.label : /* @__PURE__ */ jsx70("span", { className: "fd-sr", children: lvl.label })
8419
8437
  ]
8420
8438
  }
8421
8439
  );
8422
8440
  }
8423
8441
 
8424
8442
  // src/components/planner/PreferenceMeter.tsx
8425
- import * as React37 from "react";
8426
- import { jsx as jsx70, jsxs as jsxs65 } from "react/jsx-runtime";
8443
+ import * as React38 from "react";
8444
+ import { jsx as jsx71, jsxs as jsxs66 } from "react/jsx-runtime";
8427
8445
  function preferenceScore(criteria) {
8428
8446
  const earned = criteria.reduce((n, c) => n + (Number(c.earned) || 0), 0);
8429
8447
  const weight = criteria.reduce((n, c) => n + (Number(c.weight) || 0), 0);
@@ -8452,8 +8470,8 @@ function PreferenceMeter({
8452
8470
  className = ""
8453
8471
  }) {
8454
8472
  const value = score == null ? preferenceScore(criteria) : score;
8455
- const segments = React37.useMemo(() => preferenceSegments(criteria), [criteria]);
8456
- return /* @__PURE__ */ jsx70(
8473
+ const segments = React38.useMemo(() => preferenceSegments(criteria), [criteria]);
8474
+ return /* @__PURE__ */ jsx71(
8457
8475
  ScoreMeter,
8458
8476
  {
8459
8477
  score: value,
@@ -8465,22 +8483,22 @@ function PreferenceMeter({
8465
8483
  placement,
8466
8484
  className,
8467
8485
  breakdownLabel: breakdownTitle,
8468
- breakdown: /* @__PURE__ */ jsxs65("div", { className: "fd-prefbreak", children: [
8469
- /* @__PURE__ */ jsxs65("div", { className: "fd-prefbreak-head", children: [
8470
- /* @__PURE__ */ jsx70("span", { className: "fd-label-lg", children: breakdownTitle }),
8471
- /* @__PURE__ */ jsx70("span", { className: "fd-prefbreak-score fd-tabular", children: Math.round(value) })
8486
+ breakdown: /* @__PURE__ */ jsxs66("div", { className: "fd-prefbreak", children: [
8487
+ /* @__PURE__ */ jsxs66("div", { className: "fd-prefbreak-head", children: [
8488
+ /* @__PURE__ */ jsx71("span", { className: "fd-label-lg", children: breakdownTitle }),
8489
+ /* @__PURE__ */ jsx71("span", { className: "fd-prefbreak-score fd-tabular", children: Math.round(value) })
8472
8490
  ] }),
8473
- /* @__PURE__ */ jsx70("ul", { className: "fd-prefbreak-list", children: criteria.map((c) => {
8491
+ /* @__PURE__ */ jsx71("ul", { className: "fd-prefbreak-list", children: criteria.map((c) => {
8474
8492
  const pct = c.weight > 0 ? Math.round((Number(c.earned) || 0) / c.weight * 100) : 0;
8475
- return /* @__PURE__ */ jsxs65("li", { className: pct === 0 ? "fd-prefbreak-item is-unmet" : "fd-prefbreak-item", children: [
8476
- /* @__PURE__ */ jsx70(ImportanceTag, { level: c.importance }),
8477
- /* @__PURE__ */ jsxs65("span", { className: "fd-prefbreak-text", children: [
8478
- /* @__PURE__ */ jsx70("span", { className: "fd-prefbreak-label", children: c.label }),
8479
- c.note ? /* @__PURE__ */ jsx70("span", { className: "fd-prefbreak-note", children: c.note }) : null
8493
+ return /* @__PURE__ */ jsxs66("li", { className: pct === 0 ? "fd-prefbreak-item is-unmet" : "fd-prefbreak-item", children: [
8494
+ /* @__PURE__ */ jsx71(ImportanceTag, { level: c.importance }),
8495
+ /* @__PURE__ */ jsxs66("span", { className: "fd-prefbreak-text", children: [
8496
+ /* @__PURE__ */ jsx71("span", { className: "fd-prefbreak-label", children: c.label }),
8497
+ c.note ? /* @__PURE__ */ jsx71("span", { className: "fd-prefbreak-note", children: c.note }) : null
8480
8498
  ] }),
8481
- /* @__PURE__ */ jsxs65("span", { className: "fd-prefbreak-val fd-tabular", children: [
8499
+ /* @__PURE__ */ jsxs66("span", { className: "fd-prefbreak-val fd-tabular", children: [
8482
8500
  Math.round(Number(c.earned) || 0),
8483
- /* @__PURE__ */ jsx70("span", { className: "fd-prefbreak-sep", children: "/" }),
8501
+ /* @__PURE__ */ jsx71("span", { className: "fd-prefbreak-sep", children: "/" }),
8484
8502
  Math.round(c.weight)
8485
8503
  ] })
8486
8504
  ] }, c.id);
@@ -8491,10 +8509,10 @@ function PreferenceMeter({
8491
8509
  }
8492
8510
 
8493
8511
  // src/components/chat/AgentChatPanel.tsx
8494
- import * as React43 from "react";
8512
+ import * as React44 from "react";
8495
8513
 
8496
8514
  // src/components/chat/chatEngine.ts
8497
- import * as React38 from "react";
8515
+ import * as React39 from "react";
8498
8516
  var CHAT_UNAVAILABLE = "chat_unavailable";
8499
8517
  var JOB_PENDING = ["queued", "running"];
8500
8518
  var JOB_SUCCESS = ["completed", "recovered"];
@@ -8548,22 +8566,22 @@ function useChatEngine(opts) {
8548
8566
  onClear,
8549
8567
  onFeedback
8550
8568
  } = opts || {};
8551
- const [status, setStatus] = React38.useState("idle");
8552
- const [threadId, setThreadId] = React38.useState(null);
8553
- const [messages, setMessages] = React38.useState([]);
8554
- const [queue, setQueue] = React38.useState([]);
8555
- const [fatal, setFatal] = React38.useState(null);
8556
- const [busy, setBusy] = React38.useState(false);
8557
- const [turnStartedAt, setTurnStartedAt] = React38.useState(null);
8558
- const listRef = React38.useRef([]);
8559
- const queueRef = React38.useRef([]);
8560
- const busyRef = React38.useRef(false);
8561
- const stoppedRef = React38.useRef(false);
8562
- const abortRef = React38.useRef(null);
8563
- const serverCount = React38.useRef(0);
8564
- const threadRef = React38.useRef(null);
8565
- const mounted = React38.useRef(true);
8566
- React38.useEffect(() => {
8569
+ const [status, setStatus] = React39.useState("idle");
8570
+ const [threadId, setThreadId] = React39.useState(null);
8571
+ const [messages, setMessages] = React39.useState([]);
8572
+ const [queue, setQueue] = React39.useState([]);
8573
+ const [fatal, setFatal] = React39.useState(null);
8574
+ const [busy, setBusy] = React39.useState(false);
8575
+ const [turnStartedAt, setTurnStartedAt] = React39.useState(null);
8576
+ const listRef = React39.useRef([]);
8577
+ const queueRef = React39.useRef([]);
8578
+ const busyRef = React39.useRef(false);
8579
+ const stoppedRef = React39.useRef(false);
8580
+ const abortRef = React39.useRef(null);
8581
+ const serverCount = React39.useRef(0);
8582
+ const threadRef = React39.useRef(null);
8583
+ const mounted = React39.useRef(true);
8584
+ React39.useEffect(() => {
8567
8585
  mounted.current = true;
8568
8586
  return () => {
8569
8587
  mounted.current = false;
@@ -8585,14 +8603,14 @@ function useChatEngine(opts) {
8585
8603
  }
8586
8604
  return false;
8587
8605
  };
8588
- const loadThread = React38.useCallback(async (id) => {
8606
+ const loadThread = React39.useCallback(async (id) => {
8589
8607
  const data = await apiAdapter.getThread(id);
8590
8608
  const list = [...data && data.messages || []];
8591
8609
  serverCount.current = list.length;
8592
8610
  commit(list);
8593
8611
  return list;
8594
8612
  }, [apiAdapter]);
8595
- React38.useEffect(() => {
8613
+ React39.useEffect(() => {
8596
8614
  if (!apiAdapter) {
8597
8615
  setStatus("idle");
8598
8616
  setFatal(null);
@@ -8805,7 +8823,7 @@ function useChatEngine(opts) {
8805
8823
  await dispatchTurn(turn);
8806
8824
  }
8807
8825
  }
8808
- const send = React38.useCallback((text, attachments) => {
8826
+ const send = React39.useCallback((text, attachments) => {
8809
8827
  const body = (text || "").trim();
8810
8828
  if (!body && !(attachments && attachments.length)) return;
8811
8829
  if (status === "disconnected") return;
@@ -8815,7 +8833,7 @@ function useChatEngine(opts) {
8815
8833
  stoppedRef.current = false;
8816
8834
  drain();
8817
8835
  }, [status]);
8818
- const stop = React38.useCallback(() => {
8836
+ const stop = React39.useCallback(() => {
8819
8837
  stoppedRef.current = true;
8820
8838
  const ac = abortRef.current;
8821
8839
  if (ac) {
@@ -8834,11 +8852,11 @@ function useChatEngine(opts) {
8834
8852
  store.del(STORAGE_PREFIX + threadRef.current);
8835
8853
  }
8836
8854
  }, [apiAdapter]);
8837
- const removeQueued = React38.useCallback((id) => {
8855
+ const removeQueued = React39.useCallback((id) => {
8838
8856
  queueRef.current = queueRef.current.filter((t) => t.id !== id);
8839
8857
  setQueue(queueRef.current.slice());
8840
8858
  }, []);
8841
- const retry = React38.useCallback(() => {
8859
+ const retry = React39.useCallback(() => {
8842
8860
  const list = listRef.current;
8843
8861
  let at = -1;
8844
8862
  for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
@@ -8854,19 +8872,19 @@ function useChatEngine(opts) {
8854
8872
  setQueue(queueRef.current.slice());
8855
8873
  drain();
8856
8874
  }, []);
8857
- const clear = React38.useCallback(() => {
8875
+ const clear = React39.useCallback(() => {
8858
8876
  commit([]);
8859
8877
  serverCount.current = 0;
8860
8878
  queueRef.current = [];
8861
8879
  setQueue([]);
8862
8880
  onClear && onClear();
8863
8881
  }, [onClear]);
8864
- const setFeedback = React38.useCallback((id, value) => {
8882
+ const setFeedback = React39.useCallback((id, value) => {
8865
8883
  patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
8866
8884
  const msg = listRef.current.find((m) => m.id === id);
8867
8885
  onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
8868
8886
  }, [onFeedback]);
8869
- const reload = React38.useCallback(async () => {
8887
+ const reload = React39.useCallback(async () => {
8870
8888
  if (!threadRef.current) return;
8871
8889
  setStatus("loading");
8872
8890
  try {
@@ -8904,11 +8922,11 @@ var ChatKit = {
8904
8922
  };
8905
8923
 
8906
8924
  // src/components/chat/ChatTranscript.tsx
8907
- import * as React40 from "react";
8925
+ import * as React41 from "react";
8908
8926
 
8909
8927
  // src/components/chat/ChatTurn.tsx
8910
- import * as React39 from "react";
8911
- import { jsx as jsx71, jsxs as jsxs66 } from "react/jsx-runtime";
8928
+ import * as React40 from "react";
8929
+ import { jsx as jsx72, jsxs as jsxs67 } from "react/jsx-runtime";
8912
8930
  function JsonView({ value }) {
8913
8931
  let text;
8914
8932
  try {
@@ -8916,67 +8934,67 @@ function JsonView({ value }) {
8916
8934
  } catch (e) {
8917
8935
  text = String(value);
8918
8936
  }
8919
- return /* @__PURE__ */ jsx71(CodeBlock, { code: text, language: "json", collapseAfter: 18 });
8937
+ return /* @__PURE__ */ jsx72(CodeBlock, { code: text, language: "json", collapseAfter: 18 });
8920
8938
  }
8921
8939
  function PacketCard({ packet, schema, render, onApply, applied }) {
8922
8940
  if (!packet) return null;
8923
8941
  const s = schema || {};
8924
8942
  const invalid = packet.valid === false;
8925
8943
  const title = s.heading || packet.type;
8926
- return /* @__PURE__ */ jsxs66("section", { className: "fdc-packet" + (invalid ? " is-invalid" : ""), "aria-label": title, children: [
8927
- /* @__PURE__ */ jsxs66("header", { className: "fdc-packet-head", children: [
8928
- /* @__PURE__ */ jsx71("i", { className: "ph ph-" + (s.icon || "package"), "aria-hidden": "true" }),
8929
- /* @__PURE__ */ jsx71("span", { className: "fdc-packet-title", children: title }),
8930
- packet.repaired ? /* @__PURE__ */ jsx71("span", { className: "fdc-packet-badge", children: "Repaired" }) : null,
8931
- invalid ? /* @__PURE__ */ jsx71("span", { className: "fdc-packet-badge is-danger", children: "Invalid" }) : null
8944
+ return /* @__PURE__ */ jsxs67("section", { className: "fdc-packet" + (invalid ? " is-invalid" : ""), "aria-label": title, children: [
8945
+ /* @__PURE__ */ jsxs67("header", { className: "fdc-packet-head", children: [
8946
+ /* @__PURE__ */ jsx72("i", { className: "ph ph-" + (s.icon || "package"), "aria-hidden": "true" }),
8947
+ /* @__PURE__ */ jsx72("span", { className: "fdc-packet-title", children: title }),
8948
+ packet.repaired ? /* @__PURE__ */ jsx72("span", { className: "fdc-packet-badge", children: "Repaired" }) : null,
8949
+ invalid ? /* @__PURE__ */ jsx72("span", { className: "fdc-packet-badge is-danger", children: "Invalid" }) : null
8932
8950
  ] }),
8933
- invalid ? /* @__PURE__ */ jsxs66("div", { className: "fdc-packet-alert", role: "alert", children: [
8934
- /* @__PURE__ */ jsx71("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
8935
- /* @__PURE__ */ jsx71("span", { children: packet.error || "This result failed validation and can\u2019t be applied." })
8936
- ] }) : /* @__PURE__ */ jsx71("div", { className: "fdc-packet-body", children: render ? render(packet) : /* @__PURE__ */ jsx71(JsonView, { value: packet.payload }) }),
8937
- !invalid && onApply ? /* @__PURE__ */ jsxs66("footer", { className: "fdc-packet-foot", children: [
8938
- packet.repaired ? /* @__PURE__ */ jsx71("span", { className: "fdc-packet-note", children: "Corrected by the backend after a first attempt." }) : /* @__PURE__ */ jsx71("span", {}),
8939
- /* @__PURE__ */ jsxs66("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", disabled: applied, onClick: () => onApply(packet), children: [
8940
- /* @__PURE__ */ jsx71("i", { className: "ph ph-" + (applied ? "check" : "arrow-square-in"), "aria-hidden": "true" }),
8951
+ invalid ? /* @__PURE__ */ jsxs67("div", { className: "fdc-packet-alert", role: "alert", children: [
8952
+ /* @__PURE__ */ jsx72("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
8953
+ /* @__PURE__ */ jsx72("span", { children: packet.error || "This result failed validation and can\u2019t be applied." })
8954
+ ] }) : /* @__PURE__ */ jsx72("div", { className: "fdc-packet-body", children: render ? render(packet) : /* @__PURE__ */ jsx72(JsonView, { value: packet.payload }) }),
8955
+ !invalid && onApply ? /* @__PURE__ */ jsxs67("footer", { className: "fdc-packet-foot", children: [
8956
+ packet.repaired ? /* @__PURE__ */ jsx72("span", { className: "fdc-packet-note", children: "Corrected by the backend after a first attempt." }) : /* @__PURE__ */ jsx72("span", {}),
8957
+ /* @__PURE__ */ jsxs67("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", disabled: applied, onClick: () => onApply(packet), children: [
8958
+ /* @__PURE__ */ jsx72("i", { className: "ph ph-" + (applied ? "check" : "arrow-square-in"), "aria-hidden": "true" }),
8941
8959
  applied ? "Applied" : s.applyLabel || "Apply"
8942
8960
  ] })
8943
8961
  ] }) : null
8944
8962
  ] });
8945
8963
  }
8946
8964
  function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
8947
- const [open, setOpen] = React39.useState(defaultOpen);
8965
+ const [open, setOpen] = React40.useState(defaultOpen);
8948
8966
  if (!text) return null;
8949
- return /* @__PURE__ */ jsxs66("div", { className: "fdc-think" + (open ? " is-open" : ""), children: [
8950
- /* @__PURE__ */ jsxs66("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
8951
- /* @__PURE__ */ jsx71("i", { className: "ph ph-brain", "aria-hidden": "true" }),
8952
- /* @__PURE__ */ jsx71("span", { children: streaming ? "Thinking" : durationMs ? "Thought for " + formatDuration(durationMs) : "Thought process" }),
8953
- streaming ? /* @__PURE__ */ jsxs66("span", { className: "fdc-dots", "aria-hidden": "true", children: [
8954
- /* @__PURE__ */ jsx71("span", {}),
8955
- /* @__PURE__ */ jsx71("span", {}),
8956
- /* @__PURE__ */ jsx71("span", {})
8967
+ return /* @__PURE__ */ jsxs67("div", { className: "fdc-think" + (open ? " is-open" : ""), children: [
8968
+ /* @__PURE__ */ jsxs67("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
8969
+ /* @__PURE__ */ jsx72("i", { className: "ph ph-brain", "aria-hidden": "true" }),
8970
+ /* @__PURE__ */ jsx72("span", { children: streaming ? "Thinking" : durationMs ? "Thought for " + formatDuration(durationMs) : "Thought process" }),
8971
+ streaming ? /* @__PURE__ */ jsxs67("span", { className: "fdc-dots", "aria-hidden": "true", children: [
8972
+ /* @__PURE__ */ jsx72("span", {}),
8973
+ /* @__PURE__ */ jsx72("span", {}),
8974
+ /* @__PURE__ */ jsx72("span", {})
8957
8975
  ] }) : null,
8958
- /* @__PURE__ */ jsx71("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" })
8976
+ /* @__PURE__ */ jsx72("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" })
8959
8977
  ] }),
8960
- open ? /* @__PURE__ */ jsx71("div", { className: "fdc-think-body", children: text }) : null
8978
+ open ? /* @__PURE__ */ jsx72("div", { className: "fdc-think-body", children: text }) : null
8961
8979
  ] });
8962
8980
  }
8963
8981
  function Citations({ items = [], onOpen }) {
8964
- const [open, setOpen] = React39.useState(false);
8982
+ const [open, setOpen] = React40.useState(false);
8965
8983
  if (!items.length) return null;
8966
- return /* @__PURE__ */ jsxs66("div", { className: "fdc-cites", children: [
8967
- /* @__PURE__ */ jsxs66("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
8968
- /* @__PURE__ */ jsx71("i", { className: "ph ph-quotes", "aria-hidden": "true" }),
8969
- /* @__PURE__ */ jsxs66("span", { children: [
8984
+ return /* @__PURE__ */ jsxs67("div", { className: "fdc-cites", children: [
8985
+ /* @__PURE__ */ jsxs67("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
8986
+ /* @__PURE__ */ jsx72("i", { className: "ph ph-quotes", "aria-hidden": "true" }),
8987
+ /* @__PURE__ */ jsxs67("span", { children: [
8970
8988
  items.length,
8971
8989
  " source",
8972
8990
  items.length === 1 ? "" : "s"
8973
8991
  ] }),
8974
- /* @__PURE__ */ jsx71("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" })
8992
+ /* @__PURE__ */ jsx72("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" })
8975
8993
  ] }),
8976
- open ? /* @__PURE__ */ jsx71("ol", { className: "fdc-cites-list", children: items.map((c, i) => /* @__PURE__ */ jsxs66("li", { children: [
8977
- /* @__PURE__ */ jsx71("span", { className: "fdc-cite-n fd-tabular", children: c.marker || i + 1 }),
8978
- c.url ? /* @__PURE__ */ jsx71("a", { href: c.url, target: "_blank", rel: "noopener noreferrer", onClick: onOpen ? (e) => onOpen(c, e) : void 0, children: c.title || c.url }) : /* @__PURE__ */ jsx71("span", { children: c.title || "Source" }),
8979
- c.detail ? /* @__PURE__ */ jsx71("span", { className: "fdc-cite-detail", children: c.detail }) : null
8994
+ open ? /* @__PURE__ */ jsx72("ol", { className: "fdc-cites-list", children: items.map((c, i) => /* @__PURE__ */ jsxs67("li", { children: [
8995
+ /* @__PURE__ */ jsx72("span", { className: "fdc-cite-n fd-tabular", children: c.marker || i + 1 }),
8996
+ c.url ? /* @__PURE__ */ jsx72("a", { href: c.url, target: "_blank", rel: "noopener noreferrer", onClick: onOpen ? (e) => onOpen(c, e) : void 0, children: c.title || c.url }) : /* @__PURE__ */ jsx72("span", { children: c.title || "Source" }),
8997
+ c.detail ? /* @__PURE__ */ jsx72("span", { className: "fdc-cite-detail", children: c.detail }) : null
8980
8998
  ] }, c.id || i)) }) : null
8981
8999
  ] });
8982
9000
  }
@@ -8987,29 +9005,29 @@ function clampText(text, max) {
8987
9005
  return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
8988
9006
  }
8989
9007
  function MessageBody({ message: m, ctx }) {
8990
- const [expanded, setExpanded] = React39.useState(false);
9008
+ const [expanded, setExpanded] = React40.useState(false);
8991
9009
  const isUser = m.role === "user";
8992
9010
  const raw = m.text || "";
8993
9011
  const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
8994
9012
  const body = clamped != null ? clamped : raw;
8995
9013
  const showMd = ctx.markdown && !isUser;
8996
- return /* @__PURE__ */ jsxs66("div", { className: "fdc-body", children: [
8997
- m.thinking && ctx.showThinking ? /* @__PURE__ */ jsx71(ThinkingBlock, { text: m.thinking, durationMs: m.thinkingMs, streaming: m.streaming && !m.text }) : null,
8998
- m.steps && m.steps.length && ctx.showSteps ? /* @__PURE__ */ jsx71(StepList, { steps: m.steps, defaultOpen: m.steps.some((s) => s.status === "running"), dense: true }) : null,
8999
- body ? /* @__PURE__ */ jsxs66("div", { className: "fdc-text" + (isUser ? " is-user" : ""), children: [
9000
- showMd ? /* @__PURE__ */ jsx71(Markdown, { source: body, headingOffset: 2, codeProps: { collapseAfter: 22 }, renderCitation: ctx.renderCitation }) : /* @__PURE__ */ jsx71("div", { className: "fdc-plain", children: body }),
9001
- m.streaming ? /* @__PURE__ */ jsx71("span", { className: "fdc-caret", "aria-hidden": "true" }) : null
9014
+ return /* @__PURE__ */ jsxs67("div", { className: "fdc-body", children: [
9015
+ m.thinking && ctx.showThinking ? /* @__PURE__ */ jsx72(ThinkingBlock, { text: m.thinking, durationMs: m.thinkingMs, streaming: m.streaming && !m.text }) : null,
9016
+ m.steps && m.steps.length && ctx.showSteps ? /* @__PURE__ */ jsx72(StepList, { steps: m.steps, defaultOpen: m.steps.some((s) => s.status === "running"), dense: true }) : null,
9017
+ body ? /* @__PURE__ */ jsxs67("div", { className: "fdc-text" + (isUser ? " is-user" : ""), children: [
9018
+ showMd ? /* @__PURE__ */ jsx72(Markdown, { source: body, headingOffset: 2, codeProps: { collapseAfter: 22 }, renderCitation: ctx.renderCitation }) : /* @__PURE__ */ jsx72("div", { className: "fdc-plain", children: body }),
9019
+ m.streaming ? /* @__PURE__ */ jsx72("span", { className: "fdc-caret", "aria-hidden": "true" }) : null
9002
9020
  ] }) : null,
9003
- clamped != null ? /* @__PURE__ */ jsxs66("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(true), children: [
9004
- /* @__PURE__ */ jsx71("i", { className: "ph ph-caret-down", "aria-hidden": "true" }),
9021
+ clamped != null ? /* @__PURE__ */ jsxs67("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(true), children: [
9022
+ /* @__PURE__ */ jsx72("i", { className: "ph ph-caret-down", "aria-hidden": "true" }),
9005
9023
  "Show more",
9006
- /* @__PURE__ */ jsx71("span", { className: "fdc-more-len fd-tabular", children: raw.length < 2e3 ? raw.length.toLocaleString() + " characters" : Math.round(raw.length / 100) / 10 + "k characters" })
9007
- ] }) : expanded && ctx.maxVisibleChars && raw.length > ctx.maxVisibleChars ? /* @__PURE__ */ jsxs66("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(false), children: [
9008
- /* @__PURE__ */ jsx71("i", { className: "ph ph-caret-up", "aria-hidden": "true" }),
9024
+ /* @__PURE__ */ jsx72("span", { className: "fdc-more-len fd-tabular", children: raw.length < 2e3 ? raw.length.toLocaleString() + " characters" : Math.round(raw.length / 100) / 10 + "k characters" })
9025
+ ] }) : expanded && ctx.maxVisibleChars && raw.length > ctx.maxVisibleChars ? /* @__PURE__ */ jsxs67("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(false), children: [
9026
+ /* @__PURE__ */ jsx72("i", { className: "ph ph-caret-up", "aria-hidden": "true" }),
9009
9027
  "Show less"
9010
9028
  ] }) : null,
9011
- m.attachments && m.attachments.length ? /* @__PURE__ */ jsx71(FileGrid, { files: m.attachments, onOpen: ctx.onOpenAttachment, tiles: true, maxHeight: ctx.attachmentHeight || 220, compact: ctx.narrow }) : null,
9012
- m.packet ? /* @__PURE__ */ jsx71(
9029
+ m.attachments && m.attachments.length ? /* @__PURE__ */ jsx72(FileGrid, { files: m.attachments, onOpen: ctx.onOpenAttachment, tiles: true, maxHeight: ctx.attachmentHeight || 220, compact: ctx.narrow }) : null,
9030
+ m.packet ? /* @__PURE__ */ jsx72(
9013
9031
  PacketCard,
9014
9032
  {
9015
9033
  packet: m.packet,
@@ -9019,44 +9037,44 @@ function MessageBody({ message: m, ctx }) {
9019
9037
  applied: ctx.appliedPackets && ctx.appliedPackets[m.id]
9020
9038
  }
9021
9039
  ) : null,
9022
- m.citations && m.citations.length ? /* @__PURE__ */ jsx71(Citations, { items: m.citations, onOpen: ctx.onOpenCitation }) : null,
9023
- m.working ? /* @__PURE__ */ jsxs66("div", { className: "fdc-working", role: "status", children: [
9024
- /* @__PURE__ */ jsxs66("span", { className: "fdc-dots", "aria-hidden": "true", children: [
9025
- /* @__PURE__ */ jsx71("span", {}),
9026
- /* @__PURE__ */ jsx71("span", {}),
9027
- /* @__PURE__ */ jsx71("span", {})
9040
+ m.citations && m.citations.length ? /* @__PURE__ */ jsx72(Citations, { items: m.citations, onOpen: ctx.onOpenCitation }) : null,
9041
+ m.working ? /* @__PURE__ */ jsxs67("div", { className: "fdc-working", role: "status", children: [
9042
+ /* @__PURE__ */ jsxs67("span", { className: "fdc-dots", "aria-hidden": "true", children: [
9043
+ /* @__PURE__ */ jsx72("span", {}),
9044
+ /* @__PURE__ */ jsx72("span", {}),
9045
+ /* @__PURE__ */ jsx72("span", {})
9028
9046
  ] }),
9029
- /* @__PURE__ */ jsxs66("span", { className: "fdc-working-label", children: [
9047
+ /* @__PURE__ */ jsxs67("span", { className: "fdc-working-label", children: [
9030
9048
  m.resumed ? "Resuming" : "Working",
9031
- m.job && m.job.status ? /* @__PURE__ */ jsxs66("span", { className: "fdc-working-job", children: [
9049
+ m.job && m.job.status ? /* @__PURE__ */ jsxs67("span", { className: "fdc-working-job", children: [
9032
9050
  " \xB7 ",
9033
9051
  m.job.status
9034
9052
  ] }) : null,
9035
- m.job && m.job.detail ? /* @__PURE__ */ jsxs66("span", { className: "fdc-working-job", children: [
9053
+ m.job && m.job.detail ? /* @__PURE__ */ jsxs67("span", { className: "fdc-working-job", children: [
9036
9054
  " \xB7 ",
9037
9055
  m.job.detail
9038
9056
  ] }) : null
9039
9057
  ] }),
9040
- m.jobId ? /* @__PURE__ */ jsx71("span", { className: "fdc-working-id fd-mono", children: String(m.jobId).slice(0, 12) }) : null
9058
+ m.jobId ? /* @__PURE__ */ jsx72("span", { className: "fdc-working-id fd-mono", children: String(m.jobId).slice(0, 12) }) : null
9041
9059
  ] }) : null,
9042
- m.stopped ? /* @__PURE__ */ jsxs66("div", { className: "fdc-stopped", children: [
9043
- /* @__PURE__ */ jsx71("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
9060
+ m.stopped ? /* @__PURE__ */ jsxs67("div", { className: "fdc-stopped", children: [
9061
+ /* @__PURE__ */ jsx72("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
9044
9062
  "Stopped"
9045
9063
  ] }) : null,
9046
- m.error ? /* @__PURE__ */ jsxs66("div", { className: "fdc-error", role: "alert", children: [
9047
- /* @__PURE__ */ jsx71("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
9048
- /* @__PURE__ */ jsx71("span", { className: "fdc-error-text", children: ctx.errorCopy ? ctx.errorCopy(m.error) : m.error }),
9049
- m.retryable && ctx.onRetry ? /* @__PURE__ */ jsxs66("button", { type: "button", className: "fdc-error-retry", onClick: ctx.onRetry, children: [
9050
- /* @__PURE__ */ jsx71("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
9064
+ m.error ? /* @__PURE__ */ jsxs67("div", { className: "fdc-error", role: "alert", children: [
9065
+ /* @__PURE__ */ jsx72("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
9066
+ /* @__PURE__ */ jsx72("span", { className: "fdc-error-text", children: ctx.errorCopy ? ctx.errorCopy(m.error) : m.error }),
9067
+ m.retryable && ctx.onRetry ? /* @__PURE__ */ jsxs67("button", { type: "button", className: "fdc-error-retry", onClick: ctx.onRetry, children: [
9068
+ /* @__PURE__ */ jsx72("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
9051
9069
  "Retry"
9052
9070
  ] }) : null
9053
9071
  ] }) : null
9054
9072
  ] });
9055
9073
  }
9056
9074
  function useCopyRun() {
9057
- const [done, setDone] = React39.useState(false);
9058
- const t = React39.useRef(null);
9059
- React39.useEffect(() => () => {
9075
+ const [done, setDone] = React40.useState(false);
9076
+ const t = React40.useRef(null);
9077
+ React40.useEffect(() => () => {
9060
9078
  if (t.current) clearTimeout(t.current);
9061
9079
  }, []);
9062
9080
  return [done, (text) => {
@@ -9076,16 +9094,16 @@ function RunActions({ group, ctx }) {
9076
9094
  const isAssistant = group.role === "assistant";
9077
9095
  const fb = last.feedback;
9078
9096
  if (!ctx.messageActions) return null;
9079
- return /* @__PURE__ */ jsxs66("div", { className: "fdc-actions", role: "group", "aria-label": "Message actions", children: [
9080
- /* @__PURE__ */ jsxs66("button", { type: "button", className: "fdc-act" + (copied ? " is-done" : ""), onClick: () => copy(markdownToText(text)), "aria-label": "Copy message", children: [
9081
- /* @__PURE__ */ jsx71("i", { className: "ph ph-" + (copied ? "check" : "copy"), "aria-hidden": "true" }),
9082
- /* @__PURE__ */ jsx71("span", { className: "fdc-act-label", children: copied ? "Copied" : "Copy" })
9097
+ return /* @__PURE__ */ jsxs67("div", { className: "fdc-actions", role: "group", "aria-label": "Message actions", children: [
9098
+ /* @__PURE__ */ jsxs67("button", { type: "button", className: "fdc-act" + (copied ? " is-done" : ""), onClick: () => copy(markdownToText(text)), "aria-label": "Copy message", children: [
9099
+ /* @__PURE__ */ jsx72("i", { className: "ph ph-" + (copied ? "check" : "copy"), "aria-hidden": "true" }),
9100
+ /* @__PURE__ */ jsx72("span", { className: "fdc-act-label", children: copied ? "Copied" : "Copy" })
9083
9101
  ] }),
9084
- isAssistant && ctx.onRetry ? /* @__PURE__ */ jsx71("button", { type: "button", className: "fdc-act", onClick: ctx.onRetry, "aria-label": "Retry this turn", children: /* @__PURE__ */ jsx71("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
9085
- group.role === "user" && ctx.onEdit ? /* @__PURE__ */ jsx71("button", { type: "button", className: "fdc-act", onClick: () => ctx.onEdit(last), "aria-label": "Edit and resend", children: /* @__PURE__ */ jsx71("i", { className: "ph ph-pencil-simple", "aria-hidden": "true" }) }) : null,
9086
- isAssistant && ctx.onFeedback ? /* @__PURE__ */ jsxs66(React39.Fragment, { children: [
9087
- /* @__PURE__ */ jsx71("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__ */ jsx71("i", { className: "ph ph-thumbs-up", "aria-hidden": "true" }) }),
9088
- /* @__PURE__ */ jsx71("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__ */ jsx71("i", { className: "ph ph-thumbs-down", "aria-hidden": "true" }) })
9102
+ isAssistant && ctx.onRetry ? /* @__PURE__ */ jsx72("button", { type: "button", className: "fdc-act", onClick: ctx.onRetry, "aria-label": "Retry this turn", children: /* @__PURE__ */ jsx72("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
9103
+ group.role === "user" && ctx.onEdit ? /* @__PURE__ */ jsx72("button", { type: "button", className: "fdc-act", onClick: () => ctx.onEdit(last), "aria-label": "Edit and resend", children: /* @__PURE__ */ jsx72("i", { className: "ph ph-pencil-simple", "aria-hidden": "true" }) }) : null,
9104
+ isAssistant && ctx.onFeedback ? /* @__PURE__ */ jsxs67(React40.Fragment, { children: [
9105
+ /* @__PURE__ */ jsx72("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__ */ jsx72("i", { className: "ph ph-thumbs-up", "aria-hidden": "true" }) }),
9106
+ /* @__PURE__ */ jsx72("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__ */ jsx72("i", { className: "ph ph-thumbs-down", "aria-hidden": "true" }) })
9089
9107
  ] }) : null,
9090
9108
  ctx.extraActions ? ctx.extraActions(group) : null
9091
9109
  ] });
@@ -9095,22 +9113,22 @@ function ChatTurn({ group, ctx }) {
9095
9113
  const name = isUser ? ctx.userName : group.author || ctx.assistantName;
9096
9114
  const avatar = isUser ? ctx.userAvatar : ctx.assistantAvatar;
9097
9115
  const stamp = group.messages[0].timestamp;
9098
- return /* @__PURE__ */ jsxs66("article", { className: "fdc-turn is-" + group.role, "aria-label": String(name) + (stamp ? " at " + formatClock(stamp) : ""), children: [
9099
- /* @__PURE__ */ jsxs66("div", { className: "fdc-turn-head", children: [
9100
- ctx.showAvatars ? /* @__PURE__ */ jsx71("span", { className: "fdc-avatar is-" + group.role, "aria-hidden": "true", children: avatar ? /* @__PURE__ */ jsx71("img", { src: avatar, alt: "" }) : isUser ? /* @__PURE__ */ jsx71("span", { className: "fdc-avatar-txt", children: (name || "You").slice(0, 1).toUpperCase() }) : /* @__PURE__ */ jsx71("i", { className: "ph ph-" + (ctx.assistantIcon || "sparkle") }) }) : null,
9101
- /* @__PURE__ */ jsx71("span", { className: "fdc-who", children: name }),
9102
- stamp ? /* @__PURE__ */ jsx71(RelativeTime, { className: "fdc-when", value: stamp }) : null,
9103
- group.messages.some((m) => m.model) ? /* @__PURE__ */ jsx71("span", { className: "fdc-turn-model", children: group.messages.find((m) => m.model).model }) : null
9116
+ return /* @__PURE__ */ jsxs67("article", { className: "fdc-turn is-" + group.role, "aria-label": String(name) + (stamp ? " at " + formatClock(stamp) : ""), children: [
9117
+ /* @__PURE__ */ jsxs67("div", { className: "fdc-turn-head", children: [
9118
+ ctx.showAvatars ? /* @__PURE__ */ jsx72("span", { className: "fdc-avatar is-" + group.role, "aria-hidden": "true", children: avatar ? /* @__PURE__ */ jsx72("img", { src: avatar, alt: "" }) : isUser ? /* @__PURE__ */ jsx72("span", { className: "fdc-avatar-txt", children: (name || "You").slice(0, 1).toUpperCase() }) : /* @__PURE__ */ jsx72("i", { className: "ph ph-" + (ctx.assistantIcon || "sparkle") }) }) : null,
9119
+ /* @__PURE__ */ jsx72("span", { className: "fdc-who", children: name }),
9120
+ stamp ? /* @__PURE__ */ jsx72(RelativeTime, { className: "fdc-when", value: stamp }) : null,
9121
+ group.messages.some((m) => m.model) ? /* @__PURE__ */ jsx72("span", { className: "fdc-turn-model", children: group.messages.find((m) => m.model).model }) : null
9104
9122
  ] }),
9105
- /* @__PURE__ */ jsxs66("div", { className: "fdc-turn-body", children: [
9106
- group.messages.map((m) => /* @__PURE__ */ jsx71("div", { className: "fdc-msg" + (m.pending ? " is-pending" : ""), children: /* @__PURE__ */ jsx71(MessageBody, { message: m, ctx }) }, m.id)),
9107
- /* @__PURE__ */ jsx71(RunActions, { group, ctx })
9123
+ /* @__PURE__ */ jsxs67("div", { className: "fdc-turn-body", children: [
9124
+ group.messages.map((m) => /* @__PURE__ */ jsx72("div", { className: "fdc-msg" + (m.pending ? " is-pending" : ""), children: /* @__PURE__ */ jsx72(MessageBody, { message: m, ctx }) }, m.id)),
9125
+ /* @__PURE__ */ jsx72(RunActions, { group, ctx })
9108
9126
  ] })
9109
9127
  ] });
9110
9128
  }
9111
9129
 
9112
9130
  // src/components/chat/ChatTranscript.tsx
9113
- import { jsx as jsx72, jsxs as jsxs67 } from "react/jsx-runtime";
9131
+ import { jsx as jsx73, jsxs as jsxs68 } from "react/jsx-runtime";
9114
9132
  var GROUP_WINDOW = 6e4;
9115
9133
  var STICK_PX = 100;
9116
9134
  function groupMessages(list) {
@@ -9143,25 +9161,25 @@ function dayLabel(key) {
9143
9161
  }
9144
9162
  function Suggestions({ items = [], onPick }) {
9145
9163
  if (!items.length) return null;
9146
- return /* @__PURE__ */ jsx72("div", { className: "fdc-suggest", children: items.map((s, i) => {
9164
+ return /* @__PURE__ */ jsx73("div", { className: "fdc-suggest", children: items.map((s, i) => {
9147
9165
  const it = typeof s === "string" ? { label: s, text: s } : s;
9148
- return /* @__PURE__ */ jsxs67("button", { type: "button", className: "fdc-suggest-item", onClick: () => onPick && onPick(it.text || it.label), children: [
9149
- it.icon ? /* @__PURE__ */ jsx72("i", { className: "ph ph-" + it.icon, "aria-hidden": "true" }) : null,
9150
- /* @__PURE__ */ jsxs67("span", { className: "fdc-suggest-text", children: [
9151
- /* @__PURE__ */ jsx72("span", { className: "fdc-suggest-label", children: it.label }),
9152
- it.description ? /* @__PURE__ */ jsx72("span", { className: "fdc-suggest-desc", children: it.description }) : null
9166
+ return /* @__PURE__ */ jsxs68("button", { type: "button", className: "fdc-suggest-item", onClick: () => onPick && onPick(it.text || it.label), children: [
9167
+ it.icon ? /* @__PURE__ */ jsx73("i", { className: "ph ph-" + it.icon, "aria-hidden": "true" }) : null,
9168
+ /* @__PURE__ */ jsxs68("span", { className: "fdc-suggest-text", children: [
9169
+ /* @__PURE__ */ jsx73("span", { className: "fdc-suggest-label", children: it.label }),
9170
+ it.description ? /* @__PURE__ */ jsx73("span", { className: "fdc-suggest-desc", children: it.description }) : null
9153
9171
  ] }),
9154
- /* @__PURE__ */ jsx72("i", { className: "ph ph-arrow-up-right fdc-suggest-go", "aria-hidden": "true" })
9172
+ /* @__PURE__ */ jsx73("i", { className: "ph ph-arrow-up-right fdc-suggest-go", "aria-hidden": "true" })
9155
9173
  ] }, it.id || i);
9156
9174
  }) });
9157
9175
  }
9158
9176
  function LoadingTurns() {
9159
- return /* @__PURE__ */ jsx72("div", { className: "fdc-skel", "aria-hidden": "true", children: [0, 1].map((i) => /* @__PURE__ */ jsxs67("div", { className: "fdc-skel-turn", children: [
9160
- /* @__PURE__ */ jsx72("div", { className: "fd-skel fd-skel-circle", style: { width: 22, height: 22 } }),
9161
- /* @__PURE__ */ jsxs67("div", { className: "fdc-skel-lines", children: [
9162
- /* @__PURE__ */ jsx72("div", { className: "fd-skel", style: { width: i ? "62%" : "44%", height: 11 } }),
9163
- /* @__PURE__ */ jsx72("div", { className: "fd-skel", style: { width: i ? "94%" : "78%", height: 11 } }),
9164
- /* @__PURE__ */ jsx72("div", { className: "fd-skel", style: { width: i ? "71%" : "56%", height: 11 } })
9177
+ return /* @__PURE__ */ jsx73("div", { className: "fdc-skel", "aria-hidden": "true", children: [0, 1].map((i) => /* @__PURE__ */ jsxs68("div", { className: "fdc-skel-turn", children: [
9178
+ /* @__PURE__ */ jsx73("div", { className: "fd-skel fd-skel-circle", style: { width: 22, height: 22 } }),
9179
+ /* @__PURE__ */ jsxs68("div", { className: "fdc-skel-lines", children: [
9180
+ /* @__PURE__ */ jsx73("div", { className: "fd-skel", style: { width: i ? "62%" : "44%", height: 11 } }),
9181
+ /* @__PURE__ */ jsx73("div", { className: "fd-skel", style: { width: i ? "94%" : "78%", height: 11 } }),
9182
+ /* @__PURE__ */ jsx73("div", { className: "fd-skel", style: { width: i ? "71%" : "56%", height: 11 } })
9165
9183
  ] })
9166
9184
  ] }, i)) });
9167
9185
  }
@@ -9178,10 +9196,10 @@ function ChatTranscript({
9178
9196
  renderEmpty,
9179
9197
  className = ""
9180
9198
  }) {
9181
- const scroller = React40.useRef(null);
9182
- const stick = React40.useRef(true);
9183
- const [pill, setPill] = React40.useState(0);
9184
- const seen = React40.useRef(0);
9199
+ const scroller = React41.useRef(null);
9200
+ const stick = React41.useRef(true);
9201
+ const [pill, setPill] = React41.useState(0);
9202
+ const seen = React41.useRef(0);
9185
9203
  const toBottom = (smooth) => {
9186
9204
  const el = scroller.current;
9187
9205
  if (!el) return;
@@ -9200,7 +9218,7 @@ function ChatTranscript({
9200
9218
  seen.current = messages.length;
9201
9219
  }
9202
9220
  };
9203
- React40.useLayoutEffect(() => {
9221
+ React41.useLayoutEffect(() => {
9204
9222
  const el = scroller.current;
9205
9223
  if (!el) return;
9206
9224
  if (stick.current) {
@@ -9208,7 +9226,7 @@ function ChatTranscript({
9208
9226
  seen.current = messages.length;
9209
9227
  } else setPill(Math.max(0, messages.length - seen.current));
9210
9228
  }, [messages]);
9211
- React40.useEffect(() => {
9229
+ React41.useEffect(() => {
9212
9230
  const el = scroller.current;
9213
9231
  const inner = el && el.firstChild;
9214
9232
  if (!el || !inner || typeof ResizeObserver === "undefined") return;
@@ -9218,38 +9236,38 @@ function ChatTranscript({
9218
9236
  ro.observe(inner);
9219
9237
  return () => ro.disconnect();
9220
9238
  }, []);
9221
- const groups = React40.useMemo(() => groupMessages(messages), [messages]);
9239
+ const groups = React41.useMemo(() => groupMessages(messages), [messages]);
9222
9240
  const empty = !messages.length && status === "ready";
9223
- return /* @__PURE__ */ jsxs67("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
9224
- /* @__PURE__ */ jsxs67("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
9225
- status === "loading" || status === "resolving" ? /* @__PURE__ */ jsx72(LoadingTurns, {}) : null,
9226
- status === "disconnected" ? /* @__PURE__ */ jsxs67("div", { className: "fdc-dead", children: [
9227
- /* @__PURE__ */ jsx72("span", { className: "fdc-dead-icon", children: /* @__PURE__ */ jsx72("i", { className: "ph ph-plugs", "aria-hidden": "true" }) }),
9228
- /* @__PURE__ */ jsx72("h3", { className: "fdc-dead-title", children: ctx.deadTitle || "The assistant isn\u2019t reachable" }),
9229
- /* @__PURE__ */ jsx72("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." }),
9230
- ctx.onReconnect ? /* @__PURE__ */ jsxs67("button", { type: "button", className: "fd-btn fd-btn-secondary fd-btn-sm", onClick: ctx.onReconnect, children: [
9231
- /* @__PURE__ */ jsx72("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
9241
+ return /* @__PURE__ */ jsxs68("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
9242
+ /* @__PURE__ */ jsxs68("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
9243
+ status === "loading" || status === "resolving" ? /* @__PURE__ */ jsx73(LoadingTurns, {}) : null,
9244
+ status === "disconnected" ? /* @__PURE__ */ jsxs68("div", { className: "fdc-dead", children: [
9245
+ /* @__PURE__ */ jsx73("span", { className: "fdc-dead-icon", children: /* @__PURE__ */ jsx73("i", { className: "ph ph-plugs", "aria-hidden": "true" }) }),
9246
+ /* @__PURE__ */ jsx73("h3", { className: "fdc-dead-title", children: ctx.deadTitle || "The assistant isn\u2019t reachable" }),
9247
+ /* @__PURE__ */ jsx73("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." }),
9248
+ ctx.onReconnect ? /* @__PURE__ */ jsxs68("button", { type: "button", className: "fd-btn fd-btn-secondary fd-btn-sm", onClick: ctx.onReconnect, children: [
9249
+ /* @__PURE__ */ jsx73("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
9232
9250
  "Try again"
9233
9251
  ] }) : null
9234
9252
  ] }) : null,
9235
- empty ? renderEmpty ? renderEmpty() : /* @__PURE__ */ jsxs67("div", { className: "fdc-empty", children: [
9236
- /* @__PURE__ */ jsx72("span", { className: "fdc-empty-icon", children: /* @__PURE__ */ jsx72("i", { className: "ph ph-" + emptyIcon, "aria-hidden": "true" }) }),
9237
- /* @__PURE__ */ jsx72("h3", { className: "fdc-empty-title", children: emptyTitle }),
9238
- emptyDescription ? /* @__PURE__ */ jsx72("p", { className: "fdc-empty-body", children: emptyDescription }) : null,
9239
- /* @__PURE__ */ jsx72(Suggestions, { items: suggestions, onPick })
9253
+ empty ? renderEmpty ? renderEmpty() : /* @__PURE__ */ jsxs68("div", { className: "fdc-empty", children: [
9254
+ /* @__PURE__ */ jsx73("span", { className: "fdc-empty-icon", children: /* @__PURE__ */ jsx73("i", { className: "ph ph-" + emptyIcon, "aria-hidden": "true" }) }),
9255
+ /* @__PURE__ */ jsx73("h3", { className: "fdc-empty-title", children: emptyTitle }),
9256
+ emptyDescription ? /* @__PURE__ */ jsx73("p", { className: "fdc-empty-body", children: emptyDescription }) : null,
9257
+ /* @__PURE__ */ jsx73(Suggestions, { items: suggestions, onPick })
9240
9258
  ] }) : null,
9241
9259
  groups.map((g, i) => {
9242
9260
  const prev = groups[i - 1];
9243
9261
  const k = dayKey(g.messages[0].timestamp);
9244
9262
  const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
9245
- return /* @__PURE__ */ jsxs67(React40.Fragment, { children: [
9246
- showDay ? /* @__PURE__ */ jsx72("div", { className: "fdc-day", children: /* @__PURE__ */ jsx72("span", { children: dayLabel(k) }) }) : null,
9247
- /* @__PURE__ */ jsx72(ChatTurn, { group: g, ctx })
9263
+ return /* @__PURE__ */ jsxs68(React41.Fragment, { children: [
9264
+ showDay ? /* @__PURE__ */ jsx73("div", { className: "fdc-day", children: /* @__PURE__ */ jsx73("span", { children: dayLabel(k) }) }) : null,
9265
+ /* @__PURE__ */ jsx73(ChatTurn, { group: g, ctx })
9248
9266
  ] }, g.key || i);
9249
9267
  })
9250
9268
  ] }),
9251
- pill ? /* @__PURE__ */ jsxs67("button", { type: "button", className: "fdc-pill", onClick: () => toBottom(true), children: [
9252
- /* @__PURE__ */ jsx72("i", { className: "ph ph-arrow-down", "aria-hidden": "true" }),
9269
+ pill ? /* @__PURE__ */ jsxs68("button", { type: "button", className: "fdc-pill", onClick: () => toBottom(true), children: [
9270
+ /* @__PURE__ */ jsx73("i", { className: "ph ph-arrow-down", "aria-hidden": "true" }),
9253
9271
  pill,
9254
9272
  " new message",
9255
9273
  pill === 1 ? "" : "s"
@@ -9259,8 +9277,8 @@ function ChatTranscript({
9259
9277
  var TranscriptKit = { groupMessages };
9260
9278
 
9261
9279
  // src/components/chat/ChatComposer.tsx
9262
- import * as React41 from "react";
9263
- import { jsx as jsx73, jsxs as jsxs68 } from "react/jsx-runtime";
9280
+ import * as React42 from "react";
9281
+ import { jsx as jsx74, jsxs as jsxs69 } from "react/jsx-runtime";
9264
9282
  function ChatComposer({
9265
9283
  onSubmit,
9266
9284
  onStop,
@@ -9287,17 +9305,17 @@ function ChatComposer({
9287
9305
  onReject,
9288
9306
  onOpenAttachment
9289
9307
  }) {
9290
- const [text, setText] = React41.useState(draft || "");
9291
- const [trigger, setTrigger] = React41.useState(null);
9292
- const [mentionItems, setMentionItems] = React41.useState([]);
9293
- const [listening, setListening] = React41.useState(false);
9294
- const [notice, setNotice] = React41.useState(null);
9295
- const editor = React41.useRef(null);
9296
- const wrap = React41.useRef(null);
9297
- const stopVoice = React41.useRef(null);
9308
+ const [text, setText] = React42.useState(draft || "");
9309
+ const [trigger, setTrigger] = React42.useState(null);
9310
+ const [mentionItems, setMentionItems] = React42.useState([]);
9311
+ const [listening, setListening] = React42.useState(false);
9312
+ const [notice, setNotice] = React42.useState(null);
9313
+ const editor = React42.useRef(null);
9314
+ const wrap = React42.useRef(null);
9315
+ const stopVoice = React42.useRef(null);
9298
9316
  const staged = useStagedFiles(fileUploadHandler, { onError: () => {
9299
9317
  } });
9300
- React41.useEffect(() => {
9318
+ React42.useEffect(() => {
9301
9319
  if (draft != null && draft !== text) setText(draft);
9302
9320
  }, [draft]);
9303
9321
  const change = (v) => {
@@ -9331,7 +9349,7 @@ function ChatComposer({
9331
9349
  e.preventDefault();
9332
9350
  staged.add(found.files);
9333
9351
  };
9334
- React41.useEffect(() => {
9352
+ React42.useEffect(() => {
9335
9353
  if (!trigger || trigger.type !== "mention" || !mentionSources) {
9336
9354
  setMentionItems([]);
9337
9355
  return;
@@ -9349,7 +9367,7 @@ function ChatComposer({
9349
9367
  const q = (trigger.query || "").toLowerCase();
9350
9368
  setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
9351
9369
  }, [trigger, mentionSources]);
9352
- const slashItems = React41.useMemo(() => {
9370
+ const slashItems = React42.useMemo(() => {
9353
9371
  if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
9354
9372
  const q = (trigger.query || "").toLowerCase();
9355
9373
  return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
@@ -9363,7 +9381,7 @@ function ChatComposer({
9363
9381
  description: it.description,
9364
9382
  icon: it.icon,
9365
9383
  meta: mention.meta,
9366
- shortcut: slash.shortcut ? /* @__PURE__ */ jsx73(KeyHint, { keys: slash.shortcut, size: "sm" }) : void 0,
9384
+ shortcut: slash.shortcut ? /* @__PURE__ */ jsx74(KeyHint, { keys: slash.shortcut, size: "sm" }) : void 0,
9367
9385
  onSelect: () => {
9368
9386
  const insert = trigger.type === "slash" ? slash.immediate ? "/" + slash.id : "/" + slash.id + " " : "@" + (mention.value || mention.label) + " ";
9369
9387
  editor.current && editor.current.replaceRange(trigger.from, trigger.to, insert);
@@ -9426,14 +9444,14 @@ function ChatComposer({
9426
9444
  stopVoice.current = typeof res === "function" ? res : () => {
9427
9445
  };
9428
9446
  };
9429
- return /* @__PURE__ */ jsxs68("div", { className: "fdc-composer" + (disabled ? " is-disabled" : "") + (narrow ? " is-narrow" : ""), children: [
9430
- queue.length ? /* @__PURE__ */ jsx73("div", { className: "fdc-queue", "aria-label": "Queued messages", children: queue.map((q) => /* @__PURE__ */ jsxs68("div", { className: "fdc-queue-row", children: [
9431
- /* @__PURE__ */ jsx73("i", { className: "ph ph-clock-countdown", "aria-hidden": "true" }),
9432
- /* @__PURE__ */ jsx73("span", { className: "fdc-queue-text", children: q.text || (q.attachments ? q.attachments.length + " file(s)" : "") }),
9433
- onRemoveQueued ? /* @__PURE__ */ jsx73("button", { type: "button", className: "fdc-queue-x", onClick: () => onRemoveQueued(q.id), "aria-label": "Remove queued message", children: /* @__PURE__ */ jsx73("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
9447
+ return /* @__PURE__ */ jsxs69("div", { className: "fdc-composer" + (disabled ? " is-disabled" : "") + (narrow ? " is-narrow" : ""), children: [
9448
+ queue.length ? /* @__PURE__ */ jsx74("div", { className: "fdc-queue", "aria-label": "Queued messages", children: queue.map((q) => /* @__PURE__ */ jsxs69("div", { className: "fdc-queue-row", children: [
9449
+ /* @__PURE__ */ jsx74("i", { className: "ph ph-clock-countdown", "aria-hidden": "true" }),
9450
+ /* @__PURE__ */ jsx74("span", { className: "fdc-queue-text", children: q.text || (q.attachments ? q.attachments.length + " file(s)" : "") }),
9451
+ onRemoveQueued ? /* @__PURE__ */ jsx74("button", { type: "button", className: "fdc-queue-x", onClick: () => onRemoveQueued(q.id), "aria-label": "Remove queued message", children: /* @__PURE__ */ jsx74("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
9434
9452
  ] }, q.id)) }) : null,
9435
9453
  sessionBar,
9436
- /* @__PURE__ */ jsx73(
9454
+ /* @__PURE__ */ jsx74(
9437
9455
  Dropzone,
9438
9456
  {
9439
9457
  className: "fdc-field",
@@ -9447,9 +9465,9 @@ function ChatComposer({
9447
9465
  disabled: !fileUploadHandler || disabled,
9448
9466
  label: "Drop to attach",
9449
9467
  hint: acceptFiles ? acceptFiles.replace(/,/g, " \xB7 ") : void 0,
9450
- children: /* @__PURE__ */ jsxs68("div", { ref: wrap, className: "fdc-field-inner", children: [
9451
- staged.items.length ? /* @__PURE__ */ jsx73("div", { className: "fdc-staged", children: /* @__PURE__ */ jsx73(FileStrip, { files: staged.items, size: narrow ? 60 : 68, onRemove: staged.remove, onRetry: staged.retry, onOpen: onOpenAttachment }) }) : null,
9452
- /* @__PURE__ */ jsx73(
9468
+ children: /* @__PURE__ */ jsxs69("div", { ref: wrap, className: "fdc-field-inner", children: [
9469
+ staged.items.length ? /* @__PURE__ */ jsx74("div", { className: "fdc-staged", children: /* @__PURE__ */ jsx74(FileStrip, { files: staged.items, size: narrow ? 60 : 68, onRemove: staged.remove, onRetry: staged.retry, onOpen: onOpenAttachment }) }) : null,
9470
+ /* @__PURE__ */ jsx74(
9453
9471
  MarkdownEditor,
9454
9472
  {
9455
9473
  ref: editor,
@@ -9468,33 +9486,33 @@ function ChatComposer({
9468
9486
  ariaLabel: "Message"
9469
9487
  }
9470
9488
  ),
9471
- /* @__PURE__ */ jsxs68("div", { className: "fdc-tools", children: [
9472
- fileUploadHandler ? /* @__PURE__ */ jsx73(FilePickButton, { onFiles: staged.add, onReject: (r) => flash(r[0].message), accept: acceptFiles, maxFileSize, label: "Attach files", icon: "plus" }) : null,
9473
- voiceHandler ? /* @__PURE__ */ jsx73("button", { type: "button", className: "fd-attachbtn" + (listening ? " is-live" : ""), onClick: voice, "aria-pressed": listening, "aria-label": listening ? "Stop dictation" : "Dictate", children: /* @__PURE__ */ jsx73("i", { className: "ph ph-" + (listening ? "waveform" : "microphone"), "aria-hidden": "true" }) }) : null,
9489
+ /* @__PURE__ */ jsxs69("div", { className: "fdc-tools", children: [
9490
+ fileUploadHandler ? /* @__PURE__ */ jsx74(FilePickButton, { onFiles: staged.add, onReject: (r) => flash(r[0].message), accept: acceptFiles, maxFileSize, label: "Attach files", icon: "plus" }) : null,
9491
+ voiceHandler ? /* @__PURE__ */ jsx74("button", { type: "button", className: "fd-attachbtn" + (listening ? " is-live" : ""), onClick: voice, "aria-pressed": listening, "aria-label": listening ? "Stop dictation" : "Dictate", children: /* @__PURE__ */ jsx74("i", { className: "ph ph-" + (listening ? "waveform" : "microphone"), "aria-hidden": "true" }) }) : null,
9474
9492
  toolbarExtras,
9475
- /* @__PURE__ */ jsx73("span", { className: "fdc-tools-gap" }),
9476
- maxLength && text.length > maxLength * 0.6 ? /* @__PURE__ */ jsxs68("span", { className: "fdc-count fd-tabular" + (text.length > maxLength * 0.95 ? " is-hot" : ""), children: [
9493
+ /* @__PURE__ */ jsx74("span", { className: "fdc-tools-gap" }),
9494
+ maxLength && text.length > maxLength * 0.6 ? /* @__PURE__ */ jsxs69("span", { className: "fdc-count fd-tabular" + (text.length > maxLength * 0.95 ? " is-hot" : ""), children: [
9477
9495
  text.length,
9478
9496
  "/",
9479
9497
  maxLength
9480
9498
  ] }) : null,
9481
- busy ? /* @__PURE__ */ jsxs68("button", { type: "button", className: "fdc-stop", onClick: onStop, "aria-label": "Stop generating", children: [
9482
- /* @__PURE__ */ jsx73("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
9483
- /* @__PURE__ */ jsx73("span", { children: "Stop" })
9484
- ] }) : /* @__PURE__ */ jsxs68("button", { type: "button", className: "fdc-send", onClick: submit, disabled: !canSend, "aria-label": "Send message", children: [
9485
- /* @__PURE__ */ jsx73("i", { className: "ph ph-paper-plane-right", "aria-hidden": "true" }),
9486
- /* @__PURE__ */ jsx73("span", { className: "fdc-send-label", children: "Send" })
9499
+ busy ? /* @__PURE__ */ jsxs69("button", { type: "button", className: "fdc-stop", onClick: onStop, "aria-label": "Stop generating", children: [
9500
+ /* @__PURE__ */ jsx74("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
9501
+ /* @__PURE__ */ jsx74("span", { children: "Stop" })
9502
+ ] }) : /* @__PURE__ */ jsxs69("button", { type: "button", className: "fdc-send", onClick: submit, disabled: !canSend, "aria-label": "Send message", children: [
9503
+ /* @__PURE__ */ jsx74("i", { className: "ph ph-paper-plane-right", "aria-hidden": "true" }),
9504
+ /* @__PURE__ */ jsx74("span", { className: "fdc-send-label", children: "Send" })
9487
9505
  ] })
9488
9506
  ] })
9489
9507
  ] })
9490
9508
  }
9491
9509
  ),
9492
- notice ? /* @__PURE__ */ jsxs68("div", { className: "fdc-notice", role: "status", children: [
9493
- /* @__PURE__ */ jsx73("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
9510
+ notice ? /* @__PURE__ */ jsxs69("div", { className: "fdc-notice", role: "status", children: [
9511
+ /* @__PURE__ */ jsx74("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
9494
9512
  notice
9495
9513
  ] }) : null,
9496
- hint && !notice ? /* @__PURE__ */ jsx73("div", { className: "fdc-hint", children: hint }) : null,
9497
- /* @__PURE__ */ jsx73(
9514
+ hint && !notice ? /* @__PURE__ */ jsx74("div", { className: "fdc-hint", children: hint }) : null,
9515
+ /* @__PURE__ */ jsx74(
9498
9516
  Popover,
9499
9517
  {
9500
9518
  open: menuOpen,
@@ -9508,12 +9526,12 @@ function ChatComposer({
9508
9526
  returnFocus: false,
9509
9527
  closeOnOutside: true,
9510
9528
  label: trigger && trigger.type === "slash" ? "Commands" : "Mentions",
9511
- children: /* @__PURE__ */ jsx73(
9529
+ children: /* @__PURE__ */ jsx74(
9512
9530
  Menu,
9513
9531
  {
9514
9532
  items: menuItems,
9515
9533
  autoFocus: false,
9516
- header: /* @__PURE__ */ jsx73("div", { className: "fd-pop-group", children: trigger && trigger.type === "slash" ? "Commands" : "Attach context" }),
9534
+ header: /* @__PURE__ */ jsx74("div", { className: "fd-pop-group", children: trigger && trigger.type === "slash" ? "Commands" : "Attach context" }),
9517
9535
  onClose: () => setTrigger(null)
9518
9536
  }
9519
9537
  )
@@ -9523,12 +9541,12 @@ function ChatComposer({
9523
9541
  }
9524
9542
 
9525
9543
  // src/components/chat/ChatSessionBar.tsx
9526
- import * as React42 from "react";
9527
- import { jsx as jsx74, jsxs as jsxs69 } from "react/jsx-runtime";
9544
+ import * as React43 from "react";
9545
+ import { jsx as jsx75, jsxs as jsxs70 } from "react/jsx-runtime";
9528
9546
  var compact2 = meterFormats.compact;
9529
9547
  function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
9530
- const [open, setOpen] = React42.useState(false);
9531
- const anchor = React42.useRef(null);
9548
+ const [open, setOpen] = React43.useState(false);
9549
+ const anchor = React43.useRef(null);
9532
9550
  const stats = sessionStats || null;
9533
9551
  const cu = contextUsage || null;
9534
9552
  const limits = usageLimits || null;
@@ -9543,9 +9561,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
9543
9561
  if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
9544
9562
  if (cu) bits.push(pct + "% context");
9545
9563
  const expandable = !!(cu || limits);
9546
- return /* @__PURE__ */ jsxs69(React42.Fragment, { children: [
9547
- /* @__PURE__ */ jsxs69("div", { className: "fdc-bar", children: [
9548
- /* @__PURE__ */ jsxs69(
9564
+ return /* @__PURE__ */ jsxs70(React43.Fragment, { children: [
9565
+ /* @__PURE__ */ jsxs70("div", { className: "fdc-bar", children: [
9566
+ /* @__PURE__ */ jsxs70(
9549
9567
  "button",
9550
9568
  {
9551
9569
  type: "button",
@@ -9556,16 +9574,16 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
9556
9574
  "aria-expanded": expandable ? open : void 0,
9557
9575
  "aria-label": expandable ? "Usage details" : void 0,
9558
9576
  children: [
9559
- cu ? /* @__PURE__ */ jsx74("span", { className: "fdc-bar-mini", "aria-hidden": "true", children: /* @__PURE__ */ jsx74(SegmentedMeter, { total, segments: cu.segments, height: 4, showTotal: false }) }) : null,
9560
- /* @__PURE__ */ jsx74("span", { className: "fdc-bar-text", children: bits.join(" \xB7 ") }),
9561
- expandable ? /* @__PURE__ */ jsx74("i", { className: "ph ph-caret-right fdc-bar-caret", "aria-hidden": "true" }) : null
9577
+ cu ? /* @__PURE__ */ jsx75("span", { className: "fdc-bar-mini", "aria-hidden": "true", children: /* @__PURE__ */ jsx75(SegmentedMeter, { total, segments: cu.segments, height: 4, showTotal: false }) }) : null,
9578
+ /* @__PURE__ */ jsx75("span", { className: "fdc-bar-text", children: bits.join(" \xB7 ") }),
9579
+ expandable ? /* @__PURE__ */ jsx75("i", { className: "ph ph-caret-right fdc-bar-caret", "aria-hidden": "true" }) : null
9562
9580
  ]
9563
9581
  }
9564
9582
  ),
9565
9583
  extras
9566
9584
  ] }),
9567
- /* @__PURE__ */ jsx74(Popover, { open, anchorRef: anchor, placement: "top-start", onClose: () => setOpen(false), minWidth: 330, maxHeight: 460, padded: true, label: "Usage", children: /* @__PURE__ */ jsxs69("div", { className: "fdc-usage", children: [
9568
- cu ? /* @__PURE__ */ jsx74("section", { className: "fdc-usage-sec", children: /* @__PURE__ */ jsx74(
9585
+ /* @__PURE__ */ jsx75(Popover, { open, anchorRef: anchor, placement: "top-start", onClose: () => setOpen(false), minWidth: 330, maxHeight: 460, padded: true, label: "Usage", children: /* @__PURE__ */ jsxs70("div", { className: "fdc-usage", children: [
9586
+ cu ? /* @__PURE__ */ jsx75("section", { className: "fdc-usage-sec", children: /* @__PURE__ */ jsx75(
9569
9587
  SegmentedMeter,
9570
9588
  {
9571
9589
  total,
@@ -9577,9 +9595,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
9577
9595
  remainderLabel: "Free"
9578
9596
  }
9579
9597
  ) }) : null,
9580
- limits && limits.length ? /* @__PURE__ */ jsxs69("section", { className: "fdc-usage-sec", children: [
9581
- /* @__PURE__ */ jsx74("h4", { className: "fdc-usage-h", children: "Usage limits" }),
9582
- /* @__PURE__ */ jsx74("div", { className: "fdc-usage-rows", children: limits.map((l) => /* @__PURE__ */ jsx74(
9598
+ limits && limits.length ? /* @__PURE__ */ jsxs70("section", { className: "fdc-usage-sec", children: [
9599
+ /* @__PURE__ */ jsx75("h4", { className: "fdc-usage-h", children: "Usage limits" }),
9600
+ /* @__PURE__ */ jsx75("div", { className: "fdc-usage-rows", children: limits.map((l) => /* @__PURE__ */ jsx75(
9583
9601
  QuotaRow,
9584
9602
  {
9585
9603
  label: l.label,
@@ -9589,32 +9607,32 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
9589
9607
  l.id
9590
9608
  )) })
9591
9609
  ] }) : null,
9592
- stats ? /* @__PURE__ */ jsxs69("section", { className: "fdc-usage-sec fdc-usage-stats", children: [
9593
- stats.elapsedMs ? /* @__PURE__ */ jsxs69("div", { children: [
9594
- /* @__PURE__ */ jsx74("span", { children: "Session" }),
9595
- /* @__PURE__ */ jsx74("b", { className: "fd-tabular", children: formatDuration(stats.elapsedMs) })
9610
+ stats ? /* @__PURE__ */ jsxs70("section", { className: "fdc-usage-sec fdc-usage-stats", children: [
9611
+ stats.elapsedMs ? /* @__PURE__ */ jsxs70("div", { children: [
9612
+ /* @__PURE__ */ jsx75("span", { children: "Session" }),
9613
+ /* @__PURE__ */ jsx75("b", { className: "fd-tabular", children: formatDuration(stats.elapsedMs) })
9596
9614
  ] }) : null,
9597
- stats.tokens ? /* @__PURE__ */ jsxs69("div", { children: [
9598
- /* @__PURE__ */ jsx74("span", { children: "Tokens" }),
9599
- /* @__PURE__ */ jsx74("b", { className: "fd-tabular", children: stats.tokens.toLocaleString() })
9615
+ stats.tokens ? /* @__PURE__ */ jsxs70("div", { children: [
9616
+ /* @__PURE__ */ jsx75("span", { children: "Tokens" }),
9617
+ /* @__PURE__ */ jsx75("b", { className: "fd-tabular", children: stats.tokens.toLocaleString() })
9600
9618
  ] }) : null,
9601
- stats.costUsd != null ? /* @__PURE__ */ jsxs69("div", { children: [
9602
- /* @__PURE__ */ jsx74("span", { children: "Cost" }),
9603
- /* @__PURE__ */ jsxs69("b", { className: "fd-tabular", children: [
9619
+ stats.costUsd != null ? /* @__PURE__ */ jsxs70("div", { children: [
9620
+ /* @__PURE__ */ jsx75("span", { children: "Cost" }),
9621
+ /* @__PURE__ */ jsxs70("b", { className: "fd-tabular", children: [
9604
9622
  "$",
9605
9623
  Number(stats.costUsd).toFixed(3)
9606
9624
  ] })
9607
9625
  ] }) : null,
9608
- stats.turns ? /* @__PURE__ */ jsxs69("div", { children: [
9609
- /* @__PURE__ */ jsx74("span", { children: "Turns" }),
9610
- /* @__PURE__ */ jsx74("b", { className: "fd-tabular", children: stats.turns })
9626
+ stats.turns ? /* @__PURE__ */ jsxs70("div", { children: [
9627
+ /* @__PURE__ */ jsx75("span", { children: "Turns" }),
9628
+ /* @__PURE__ */ jsx75("b", { className: "fd-tabular", children: stats.turns })
9611
9629
  ] }) : null
9612
9630
  ] }) : null,
9613
- onClear ? /* @__PURE__ */ jsx74("footer", { className: "fdc-usage-foot", children: /* @__PURE__ */ jsxs69("button", { type: "button", className: "fdc-usage-clear", onClick: () => {
9631
+ onClear ? /* @__PURE__ */ jsx75("footer", { className: "fdc-usage-foot", children: /* @__PURE__ */ jsxs70("button", { type: "button", className: "fdc-usage-clear", onClick: () => {
9614
9632
  setOpen(false);
9615
9633
  onClear();
9616
9634
  }, children: [
9617
- /* @__PURE__ */ jsx74("i", { className: "ph ph-trash", "aria-hidden": "true" }),
9635
+ /* @__PURE__ */ jsx75("i", { className: "ph ph-trash", "aria-hidden": "true" }),
9618
9636
  "Clear conversation"
9619
9637
  ] }) }) : null
9620
9638
  ] }) })
@@ -9651,7 +9669,7 @@ function ModelControls({
9651
9669
  disabled: m.disabled,
9652
9670
  checked: m.id === (current2 && current2.id),
9653
9671
  meta: m.meta,
9654
- shortcut: m.shortcut ? /* @__PURE__ */ jsx74(KeyHint, { keys: m.shortcut, size: "sm" }) : void 0,
9672
+ shortcut: m.shortcut ? /* @__PURE__ */ jsx75(KeyHint, { keys: m.shortcut, size: "sm" }) : void 0,
9655
9673
  onSelect: () => onModelChange && onModelChange(m.id)
9656
9674
  });
9657
9675
  const items = [{ kind: "section", label: "Models" }].concat(flat.map(item));
@@ -9664,15 +9682,15 @@ function ModelControls({
9664
9682
  items.push({ kind: "section", label: "Fast mode" });
9665
9683
  items.push({
9666
9684
  kind: "custom",
9667
- render: () => /* @__PURE__ */ jsxs69("label", { className: "fdc-switchrow", children: [
9668
- /* @__PURE__ */ jsx74("span", { children: fastModeLabel }),
9669
- /* @__PURE__ */ jsx74("input", { type: "checkbox", className: "fd-sr", checked: !!fastMode, onChange: (e) => onFastModeChange(e.target.checked) }),
9670
- /* @__PURE__ */ jsx74("span", { className: "fd-switch-track" + (fastMode ? " is-on" : ""), "aria-hidden": "true", children: /* @__PURE__ */ jsx74("span", { className: "fd-switch-thumb" }) })
9685
+ render: () => /* @__PURE__ */ jsxs70("label", { className: "fdc-switchrow", children: [
9686
+ /* @__PURE__ */ jsx75("span", { children: fastModeLabel }),
9687
+ /* @__PURE__ */ jsx75("input", { type: "checkbox", className: "fd-sr", checked: !!fastMode, onChange: (e) => onFastModeChange(e.target.checked) }),
9688
+ /* @__PURE__ */ jsx75("span", { className: "fd-switch-track" + (fastMode ? " is-on" : ""), "aria-hidden": "true", children: /* @__PURE__ */ jsx75("span", { className: "fd-switch-thumb" }) })
9671
9689
  ] })
9672
9690
  });
9673
9691
  }
9674
- return /* @__PURE__ */ jsxs69(React42.Fragment, { children: [
9675
- /* @__PURE__ */ jsx74(
9692
+ return /* @__PURE__ */ jsxs70(React43.Fragment, { children: [
9693
+ /* @__PURE__ */ jsx75(
9676
9694
  MenuButton,
9677
9695
  {
9678
9696
  items,
@@ -9683,7 +9701,7 @@ function ModelControls({
9683
9701
  title: "Choose a model"
9684
9702
  }
9685
9703
  ),
9686
- effortLevels && effortLevels.length ? /* @__PURE__ */ jsx74(
9704
+ effortLevels && effortLevels.length ? /* @__PURE__ */ jsx75(
9687
9705
  MenuButton,
9688
9706
  {
9689
9707
  placement: "top-end",
@@ -9704,7 +9722,7 @@ function ModelControls({
9704
9722
  }
9705
9723
 
9706
9724
  // src/components/chat/AgentChatPanel.tsx
9707
- import { jsx as jsx75, jsxs as jsxs70 } from "react/jsx-runtime";
9725
+ import { jsx as jsx76, jsxs as jsxs71 } from "react/jsx-runtime";
9708
9726
  var SURFACES = { sidebar: "is-sidebar", inline: "is-inline", page: "is-page", modal: "is-modal", sheet: "is-sheet" };
9709
9727
  function AgentChatPanel({
9710
9728
  /* required */
@@ -9788,11 +9806,11 @@ function AgentChatPanel({
9788
9806
  onFeedback,
9789
9807
  onEditMessage
9790
9808
  }) {
9791
- const [panelWidth, setPanelWidth] = React43.useState(width);
9792
- const [applied, setApplied] = React43.useState({});
9793
- const [draft, setDraft] = React43.useState("");
9794
- const dragging = React43.useRef(null);
9795
- React43.useEffect(() => setPanelWidth(width), [width]);
9809
+ const [panelWidth, setPanelWidth] = React44.useState(width);
9810
+ const [applied, setApplied] = React44.useState({});
9811
+ const [draft, setDraft] = React44.useState("");
9812
+ const dragging = React44.useRef(null);
9813
+ React44.useEffect(() => setPanelWidth(width), [width]);
9796
9814
  const engine = useChatEngine({
9797
9815
  contextType,
9798
9816
  contextId,
@@ -9858,7 +9876,7 @@ function AgentChatPanel({
9858
9876
  onReconnect: engine.reload,
9859
9877
  deadTitle: "The assistant isn\u2019t reachable"
9860
9878
  };
9861
- const sessionBar = /* @__PURE__ */ jsx75(
9879
+ const sessionBar = /* @__PURE__ */ jsx76(
9862
9880
  ChatSessionBar,
9863
9881
  {
9864
9882
  sessionStats,
@@ -9867,7 +9885,7 @@ function AgentChatPanel({
9867
9885
  onClear: engine.visible.length ? engine.clear : void 0
9868
9886
  }
9869
9887
  );
9870
- const modelControls = /* @__PURE__ */ jsx75(
9888
+ const modelControls = /* @__PURE__ */ jsx76(
9871
9889
  ModelControls,
9872
9890
  {
9873
9891
  models,
@@ -9882,7 +9900,7 @@ function AgentChatPanel({
9882
9900
  narrow
9883
9901
  }
9884
9902
  );
9885
- const threadMenu = threads && threads.length ? /* @__PURE__ */ jsx75(
9903
+ const threadMenu = threads && threads.length ? /* @__PURE__ */ jsx76(
9886
9904
  MenuButton,
9887
9905
  {
9888
9906
  variant: "ghost",
@@ -9909,7 +9927,7 @@ function AgentChatPanel({
9909
9927
  })))
9910
9928
  }
9911
9929
  ) : null;
9912
- return /* @__PURE__ */ jsxs70(
9930
+ return /* @__PURE__ */ jsxs71(
9913
9931
  "aside",
9914
9932
  {
9915
9933
  className: ["fdc-panel", SURFACES[surface] || SURFACES.sidebar, narrow ? "is-narrow" : "", className].filter(Boolean).join(" "),
@@ -9920,7 +9938,7 @@ function AgentChatPanel({
9920
9938
  },
9921
9939
  "aria-label": title,
9922
9940
  children: [
9923
- surface === "sidebar" && resizable ? /* @__PURE__ */ jsx75(
9941
+ surface === "sidebar" && resizable ? /* @__PURE__ */ jsx76(
9924
9942
  "div",
9925
9943
  {
9926
9944
  className: "fdc-grip",
@@ -9935,20 +9953,20 @@ function AgentChatPanel({
9935
9953
  }
9936
9954
  }
9937
9955
  ) : null,
9938
- showHeader ? /* @__PURE__ */ jsxs70("header", { className: "fdc-head", children: [
9939
- /* @__PURE__ */ jsx75("span", { className: "fdc-head-mark", "aria-hidden": "true", children: /* @__PURE__ */ jsx75("i", { className: "ph ph-" + assistantIcon }) }),
9940
- /* @__PURE__ */ jsxs70("span", { className: "fdc-head-titles", children: [
9941
- /* @__PURE__ */ jsx75("span", { className: "fdc-head-title", children: title }),
9942
- subtitle ? /* @__PURE__ */ jsx75("span", { className: "fdc-head-sub", children: subtitle }) : null
9956
+ showHeader ? /* @__PURE__ */ jsxs71("header", { className: "fdc-head", children: [
9957
+ /* @__PURE__ */ jsx76("span", { className: "fdc-head-mark", "aria-hidden": "true", children: /* @__PURE__ */ jsx76("i", { className: "ph ph-" + assistantIcon }) }),
9958
+ /* @__PURE__ */ jsxs71("span", { className: "fdc-head-titles", children: [
9959
+ /* @__PURE__ */ jsx76("span", { className: "fdc-head-title", children: title }),
9960
+ subtitle ? /* @__PURE__ */ jsx76("span", { className: "fdc-head-sub", children: subtitle }) : null
9943
9961
  ] }),
9944
- /* @__PURE__ */ jsxs70("span", { className: "fdc-head-acts", children: [
9962
+ /* @__PURE__ */ jsxs71("span", { className: "fdc-head-acts", children: [
9945
9963
  headerActions,
9946
9964
  threadMenu,
9947
- onNewThread ? /* @__PURE__ */ jsx75("button", { type: "button", className: "fdc-iconbtn", onClick: onNewThread, "aria-label": "New conversation", title: "New conversation", children: /* @__PURE__ */ jsx75("i", { className: "ph ph-plus", "aria-hidden": "true" }) }) : null,
9948
- onClose ? /* @__PURE__ */ jsx75("button", { type: "button", className: "fdc-iconbtn", onClick: onClose, "aria-label": "Close panel", title: "Close", children: /* @__PURE__ */ jsx75("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
9965
+ onNewThread ? /* @__PURE__ */ jsx76("button", { type: "button", className: "fdc-iconbtn", onClick: onNewThread, "aria-label": "New conversation", title: "New conversation", children: /* @__PURE__ */ jsx76("i", { className: "ph ph-plus", "aria-hidden": "true" }) }) : null,
9966
+ onClose ? /* @__PURE__ */ jsx76("button", { type: "button", className: "fdc-iconbtn", onClick: onClose, "aria-label": "Close panel", title: "Close", children: /* @__PURE__ */ jsx76("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
9949
9967
  ] })
9950
9968
  ] }) : null,
9951
- /* @__PURE__ */ jsx75(
9969
+ /* @__PURE__ */ jsx76(
9952
9970
  ChatTranscript,
9953
9971
  {
9954
9972
  messages: engine.visible,
@@ -9963,7 +9981,7 @@ function AgentChatPanel({
9963
9981
  renderEmpty
9964
9982
  }
9965
9983
  ),
9966
- /* @__PURE__ */ jsx75(
9984
+ /* @__PURE__ */ jsx76(
9967
9985
  ChatComposer,
9968
9986
  {
9969
9987
  onSubmit: (text, atts) => engine.send(text, atts),
@@ -9996,7 +10014,7 @@ function AgentChatPanel({
9996
10014
  }
9997
10015
 
9998
10016
  // src/kits/query.ts
9999
- import * as React44 from "react";
10017
+ import * as React45 from "react";
10000
10018
  function eqFilter(get2) {
10001
10019
  return (row, value) => Array.isArray(value) ? value.includes(get2(row)) : get2(row) === value;
10002
10020
  }
@@ -10028,22 +10046,22 @@ function compare(a, b, dir) {
10028
10046
  var API = null;
10029
10047
  var PREFS = null;
10030
10048
  function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
10031
- const [query, setQuery] = React44.useState(() => {
10049
+ const [query, setQuery] = React45.useState(() => {
10032
10050
  const store = PREFS || window.PlannerPrefs;
10033
10051
  const saved = prefsKey && store ? store.getTable(prefsKey) : {};
10034
10052
  return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
10035
10053
  });
10036
- const savePref = React44.useCallback((patch2) => {
10054
+ const savePref = React45.useCallback((patch2) => {
10037
10055
  const store = PREFS || window.PlannerPrefs;
10038
10056
  if (prefsKey && store) store.setTable(prefsKey, patch2);
10039
10057
  }, [prefsKey]);
10040
- const [res, setRes] = React44.useState(null);
10041
- const [loading, setLoading] = React44.useState(true);
10042
- const seq2 = React44.useRef(0);
10058
+ const [res, setRes] = React45.useState(null);
10059
+ const [loading, setLoading] = React45.useState(true);
10060
+ const seq2 = React45.useRef(0);
10043
10061
  const depKey = (deps || []).join("|");
10044
10062
  const paramKey = JSON.stringify(params || {});
10045
10063
  const queryKey = JSON.stringify(query);
10046
- React44.useEffect(() => {
10064
+ React45.useEffect(() => {
10047
10065
  const id = ++seq2.current;
10048
10066
  setLoading(true);
10049
10067
  const t = setTimeout(() => {