@flytedan/flytebot-design-system 0.9.1 → 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.cjs CHANGED
@@ -2946,11 +2946,30 @@ function EntityRow({
2946
2946
  }
2947
2947
 
2948
2948
  // src/components/data/TransferList.tsx
2949
- var React17 = __toESM(require("react"), 1);
2949
+ var React18 = __toESM(require("react"), 1);
2950
2950
  var import_react_dom4 = require("react-dom");
2951
2951
 
2952
- // src/components/forms/Input.tsx
2952
+ // src/components/forms/field.tsx
2953
+ var React17 = __toESM(require("react"), 1);
2953
2954
  var import_jsx_runtime41 = require("react/jsx-runtime");
2955
+ function useFieldId(id) {
2956
+ const generated = React17.useId();
2957
+ return id || generated;
2958
+ }
2959
+ function FieldLabel({ htmlFor, id, required = false, onClick, children }) {
2960
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { className: "fd-field-label", htmlFor, id, onClick, children: [
2961
+ children,
2962
+ required ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "fd-field-req", "aria-hidden": "true", children: "*" }) : null
2963
+ ] });
2964
+ }
2965
+ function useTriggerLabelling(label, id) {
2966
+ const fieldId = useFieldId(id);
2967
+ const labelId = fieldId + "-label";
2968
+ return { fieldId, labelId, ariaLabelledBy: label ? labelId + " " + fieldId : void 0 };
2969
+ }
2970
+
2971
+ // src/components/forms/Input.tsx
2972
+ var import_jsx_runtime42 = require("react/jsx-runtime");
2954
2973
  function Input({
2955
2974
  label,
2956
2975
  help,
@@ -2969,7 +2988,7 @@ function Input({
2969
2988
  inputStyle,
2970
2989
  ...rest
2971
2990
  }) {
2972
- const fieldId = id || (rest.name ? "fd-" + rest.name : void 0);
2991
+ const fieldId = useFieldId(id);
2973
2992
  const box = [
2974
2993
  "fd-input",
2975
2994
  numeric ? "fd-input-num" : "",
@@ -2978,27 +2997,24 @@ function Input({
2978
2997
  size === "lg" ? "fd-input-lg" : "",
2979
2998
  className
2980
2999
  ].filter(Boolean).join(" ");
2981
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "fd-field", style, children: [
2982
- label ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { className: "fd-field-label", htmlFor: fieldId, children: [
2983
- label,
2984
- required ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "fd-field-req", "aria-hidden": "true", children: "*" }) : null
2985
- ] }) : null,
2986
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: box, children: [
2987
- icon ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "fd-input-icon", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("i", { className: "ph ph-" + icon, "aria-hidden": "true" }) }) : null,
2988
- prefix ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "fd-input-affix", children: prefix }) : null,
2989
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("input", { id: fieldId, disabled, style: inputStyle, "aria-invalid": error ? "true" : void 0, ...rest }),
2990
- loading ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "fd-spinner", style: { color: "var(--text-muted)" }, "aria-label": "Loading" }) : null,
2991
- suffix && !loading ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "fd-input-affix", children: suffix }) : null
3000
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "fd-field", style, children: [
3001
+ label ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(FieldLabel, { htmlFor: fieldId, required, children: label }) : null,
3002
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: box, children: [
3003
+ icon ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "fd-input-icon", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("i", { className: "ph ph-" + icon, "aria-hidden": "true" }) }) : null,
3004
+ prefix ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "fd-input-affix", children: prefix }) : null,
3005
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("input", { id: fieldId, disabled, style: inputStyle, "aria-invalid": error ? "true" : void 0, ...rest }),
3006
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "fd-spinner", style: { color: "var(--text-muted)" }, "aria-label": "Loading" }) : null,
3007
+ suffix && !loading ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "fd-input-affix", children: suffix }) : null
2992
3008
  ] }),
2993
- error ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { className: "fd-field-error", children: [
2994
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
3009
+ error ? /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "fd-field-error", children: [
3010
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
2995
3011
  error
2996
- ] }) : help ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "fd-field-help", children: help }) : null
3012
+ ] }) : help ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "fd-field-help", children: help }) : null
2997
3013
  ] });
2998
3014
  }
2999
3015
 
3000
3016
  // src/components/forms/SearchField.tsx
3001
- var import_jsx_runtime42 = require("react/jsx-runtime");
3017
+ var import_jsx_runtime43 = require("react/jsx-runtime");
3002
3018
  function SearchField({
3003
3019
  value,
3004
3020
  onChange,
@@ -3013,7 +3029,7 @@ function SearchField({
3013
3029
  ...rest
3014
3030
  }) {
3015
3031
  const clear = onClear || (() => onChange(""));
3016
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
3032
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
3017
3033
  Input,
3018
3034
  {
3019
3035
  id,
@@ -3026,14 +3042,14 @@ function SearchField({
3026
3042
  style,
3027
3043
  className,
3028
3044
  onChange: (e) => onChange(e.target.value),
3029
- suffix: value ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
3045
+ suffix: value ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
3030
3046
  "button",
3031
3047
  {
3032
3048
  type: "button",
3033
3049
  "aria-label": "Clear search",
3034
3050
  onClick: clear,
3035
3051
  style: { all: "unset", cursor: "pointer", color: "var(--text-muted)", display: "grid", placeItems: "center", padding: 2 },
3036
- children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("i", { className: "ph ph-x-circle", style: { fontSize: 15 }, "aria-hidden": "true" })
3052
+ children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("i", { className: "ph ph-x-circle", style: { fontSize: 15 }, "aria-hidden": "true" })
3037
3053
  }
3038
3054
  ) : void 0,
3039
3055
  ...rest
@@ -3042,7 +3058,7 @@ function SearchField({
3042
3058
  }
3043
3059
 
3044
3060
  // src/components/data/TransferList.tsx
3045
- var import_jsx_runtime43 = require("react/jsx-runtime");
3061
+ var import_jsx_runtime44 = require("react/jsx-runtime");
3046
3062
  var emptyHasMore = {};
3047
3063
  var DRAG_THRESHOLD_PX = 5;
3048
3064
  function TransferList({
@@ -3056,12 +3072,12 @@ function TransferList({
3056
3072
  listHeight = 440,
3057
3073
  className = ""
3058
3074
  }) {
3059
- const [drag, setDrag] = React17.useState(null);
3060
- const [dragOverSide, setDragOverSide] = React17.useState(null);
3061
- const dragRef = React17.useRef(null);
3062
- const armedRef = React17.useRef(null);
3063
- const sideRefs = React17.useRef({ left: null, right: null });
3064
- const hitTestSide = React17.useCallback((x, y) => {
3075
+ const [drag, setDrag] = React18.useState(null);
3076
+ const [dragOverSide, setDragOverSide] = React18.useState(null);
3077
+ const dragRef = React18.useRef(null);
3078
+ const armedRef = React18.useRef(null);
3079
+ const sideRefs = React18.useRef({ left: null, right: null });
3080
+ const hitTestSide = React18.useCallback((x, y) => {
3065
3081
  for (const side of ["left", "right"]) {
3066
3082
  const el = sideRefs.current[side];
3067
3083
  if (!el) continue;
@@ -3070,7 +3086,7 @@ function TransferList({
3070
3086
  }
3071
3087
  return null;
3072
3088
  }, []);
3073
- const findItem = React17.useCallback(
3089
+ const findItem = React18.useCallback(
3074
3090
  (side, key) => (side === "left" ? left.items : right.items).find((it) => keyOf(it) === key),
3075
3091
  [left.items, right.items, keyOf]
3076
3092
  );
@@ -3092,7 +3108,7 @@ function TransferList({
3092
3108
  height: rect.height
3093
3109
  };
3094
3110
  };
3095
- React17.useEffect(() => {
3111
+ React18.useEffect(() => {
3096
3112
  const onMovePointer = (e) => {
3097
3113
  const armed = armedRef.current;
3098
3114
  if (!armed || e.pointerId !== armed.pointerId) return;
@@ -3145,7 +3161,7 @@ function TransferList({
3145
3161
  window.removeEventListener("pointercancel", endDrag);
3146
3162
  };
3147
3163
  }, [hitTestSide, findItem, onMove]);
3148
- React17.useEffect(() => {
3164
+ React18.useEffect(() => {
3149
3165
  if (!drag || typeof document === "undefined") return;
3150
3166
  const prev = document.body.style.userSelect;
3151
3167
  document.body.style.userSelect = "none";
@@ -3155,7 +3171,7 @@ function TransferList({
3155
3171
  }, [drag]);
3156
3172
  const renderSide = (side, cfg, opposite) => {
3157
3173
  const showOverlay = drag != null && dragOverSide === side;
3158
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
3174
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
3159
3175
  "div",
3160
3176
  {
3161
3177
  ref: (el) => {
@@ -3174,16 +3190,16 @@ function TransferList({
3174
3190
  position: "relative"
3175
3191
  },
3176
3192
  children: [
3177
- cfg.label ? /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: "fd-overline fd-muted", children: [
3193
+ cfg.label ? /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "fd-overline fd-muted", children: [
3178
3194
  cfg.label,
3179
3195
  cfg.total != null ? " (" + cfg.total.toLocaleString() + ")" : ""
3180
3196
  ] }) : null,
3181
- cfg.header ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "fd-tlist-header", children: cfg.header }) : null,
3182
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: "fd-row", style: { gap: 8 }, children: [
3183
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(SearchField, { value: cfg.search, onChange: cfg.onSearchChange, placeholder: "Search", "aria-label": (cfg.label || side) + " search", style: { flex: 1 } }),
3184
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(SortMenu, { fields: cfg.sortFields, sort: cfg.sort, onSort: cfg.onSort, align: side === "left" ? "left" : "right" })
3197
+ cfg.header ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "fd-tlist-header", children: cfg.header }) : null,
3198
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "fd-row", style: { gap: 8 }, children: [
3199
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(SearchField, { value: cfg.search, onChange: cfg.onSearchChange, placeholder: "Search", "aria-label": (cfg.label || side) + " search", style: { flex: 1 } }),
3200
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(SortMenu, { fields: cfg.sortFields, sort: cfg.sort, onSort: cfg.onSort, align: side === "left" ? "left" : "right" })
3185
3201
  ] }),
3186
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
3202
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
3187
3203
  VirtualList,
3188
3204
  {
3189
3205
  items: cfg.items,
@@ -3197,13 +3213,13 @@ function TransferList({
3197
3213
  firstItemIndex: cfg.firstItemIndex,
3198
3214
  totalCount: cfg.totalCount,
3199
3215
  onNeedMore: cfg.onNeedMore,
3200
- emptyState: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(EmptyState, { icon: "tray", title: "Nothing here" }),
3216
+ emptyState: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(EmptyState, { icon: "tray", title: "Nothing here" }),
3201
3217
  renderItem: (item) => {
3202
3218
  const isBeingDragged = drag != null && drag.from === side && drag.key === keyOf(item);
3203
3219
  if (isBeingDragged) {
3204
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "fd-erow-placeholder", "aria-hidden": "true" });
3220
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "fd-erow-placeholder", "aria-hidden": "true" });
3205
3221
  }
3206
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
3222
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
3207
3223
  EntityRow,
3208
3224
  {
3209
3225
  ...renderRow(item),
@@ -3220,20 +3236,20 @@ function TransferList({
3220
3236
  }
3221
3237
  }
3222
3238
  ),
3223
- cfg.footer ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "fd-tlist-footer", children: cfg.footer }) : null,
3224
- showOverlay ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "fd-tlist-drop-overlay", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: "fd-tlist-drop-card", children: [
3225
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("i", { className: "ph ph-tray-arrow-down", style: { fontSize: 18 }, "aria-hidden": "true" }),
3226
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: cfg.dropLabel || "Drop here" + (cfg.label ? " \u2014 " + cfg.label : "") })
3239
+ cfg.footer ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "fd-tlist-footer", children: cfg.footer }) : null,
3240
+ showOverlay ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "fd-tlist-drop-overlay", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "fd-tlist-drop-card", children: [
3241
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("i", { className: "ph ph-tray-arrow-down", style: { fontSize: 18 }, "aria-hidden": "true" }),
3242
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: cfg.dropLabel || "Drop here" + (cfg.label ? " \u2014 " + cfg.label : "") })
3227
3243
  ] }) }) : null
3228
3244
  ]
3229
3245
  }
3230
3246
  );
3231
3247
  };
3232
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: ["fd-tlist", className].filter(Boolean).join(" "), style: { display: "flex", gap: 16, alignItems: "flex-start" }, children: [
3248
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: ["fd-tlist", className].filter(Boolean).join(" "), style: { display: "flex", gap: 16, alignItems: "flex-start" }, children: [
3233
3249
  renderSide("left", left, "right"),
3234
3250
  renderSide("right", right, "left"),
3235
3251
  drag ? (0, import_react_dom4.createPortal)(
3236
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
3252
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
3237
3253
  "div",
3238
3254
  {
3239
3255
  "aria-hidden": "true",
@@ -3248,7 +3264,7 @@ function TransferList({
3248
3264
  pointerEvents: "none",
3249
3265
  zIndex: 1e3
3250
3266
  },
3251
- children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(EntityRow, { ...renderRow(drag.item), draggable: true, className: "fd-erow-dragging" })
3267
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(EntityRow, { ...renderRow(drag.item), draggable: true, className: "fd-erow-dragging" })
3252
3268
  }
3253
3269
  ),
3254
3270
  document.body
@@ -3257,74 +3273,71 @@ function TransferList({
3257
3273
  }
3258
3274
 
3259
3275
  // src/components/forms/Checkbox.tsx
3260
- var React18 = __toESM(require("react"), 1);
3261
- var import_jsx_runtime44 = require("react/jsx-runtime");
3276
+ var React19 = __toESM(require("react"), 1);
3277
+ var import_jsx_runtime45 = require("react/jsx-runtime");
3262
3278
  function Checkbox({ label, description, card = false, indeterminate = false, className = "", ...rest }) {
3263
- const ref = React18.useRef(null);
3264
- React18.useEffect(() => {
3279
+ const ref = React19.useRef(null);
3280
+ React19.useEffect(() => {
3265
3281
  if (ref.current) ref.current.indeterminate = indeterminate;
3266
3282
  }, [indeterminate]);
3267
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
3268
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "fd-choice-input", children: [
3269
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("input", { ref, type: "checkbox", ...rest }),
3270
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "fd-choice-box", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("i", { className: indeterminate ? "ph ph-minus" : "ph ph-check" }) })
3283
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
3284
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "fd-choice-input", children: [
3285
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("input", { ref, type: "checkbox", ...rest }),
3286
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "fd-choice-box", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("i", { className: indeterminate ? "ph ph-minus" : "ph ph-check" }) })
3271
3287
  ] }),
3272
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "fd-choice-text", children: [
3273
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "fd-choice-title", children: label }),
3274
- description ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "fd-choice-desc", children: description }) : null
3288
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "fd-choice-text", children: [
3289
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "fd-choice-title", children: label }),
3290
+ description ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "fd-choice-desc", children: description }) : null
3275
3291
  ] })
3276
3292
  ] });
3277
3293
  }
3278
3294
 
3279
3295
  // src/components/forms/Radio.tsx
3280
- var import_jsx_runtime45 = require("react/jsx-runtime");
3296
+ var import_jsx_runtime46 = require("react/jsx-runtime");
3281
3297
  function Radio({ label, description, card = false, className = "", ...rest }) {
3282
- return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
3283
- /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "fd-choice-input", children: [
3284
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("input", { type: "radio", ...rest }),
3285
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "fd-choice-box fd-choice-box-round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "fd-choice-dot" }) })
3298
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
3299
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("span", { className: "fd-choice-input", children: [
3300
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("input", { type: "radio", ...rest }),
3301
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "fd-choice-box fd-choice-box-round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "fd-choice-dot" }) })
3286
3302
  ] }),
3287
- /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "fd-choice-text", children: [
3288
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "fd-choice-title", children: label }),
3289
- description ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "fd-choice-desc", children: description }) : null
3303
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("span", { className: "fd-choice-text", children: [
3304
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "fd-choice-title", children: label }),
3305
+ description ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "fd-choice-desc", children: description }) : null
3290
3306
  ] })
3291
3307
  ] });
3292
3308
  }
3293
3309
 
3294
3310
  // src/components/forms/Switch.tsx
3295
- var import_jsx_runtime46 = require("react/jsx-runtime");
3311
+ var import_jsx_runtime47 = require("react/jsx-runtime");
3296
3312
  function Switch({ label, description, className = "", ...rest }) {
3297
- return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("label", { className: ["fd-switch", className].filter(Boolean).join(" "), children: [
3298
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("input", { type: "checkbox", role: "switch", ...rest }),
3299
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "fd-switch-track", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "fd-switch-thumb" }) }),
3300
- label ? /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("span", { className: "fd-choice-text", children: [
3301
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "fd-switch-label", children: label }),
3302
- description ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "fd-choice-desc", children: description }) : null
3313
+ return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("label", { className: ["fd-switch", className].filter(Boolean).join(" "), children: [
3314
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("input", { type: "checkbox", role: "switch", ...rest }),
3315
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "fd-switch-track", children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "fd-switch-thumb" }) }),
3316
+ label ? /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "fd-choice-text", children: [
3317
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "fd-switch-label", children: label }),
3318
+ description ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "fd-choice-desc", children: description }) : null
3303
3319
  ] }) : null
3304
3320
  ] });
3305
3321
  }
3306
3322
 
3307
3323
  // src/components/forms/Textarea.tsx
3308
- var import_jsx_runtime47 = require("react/jsx-runtime");
3324
+ var import_jsx_runtime48 = require("react/jsx-runtime");
3309
3325
  function Textarea({ label, help, error, required = false, rows = 4, disabled = false, id, className = "", style, ...rest }) {
3310
- const fieldId = id || (rest.name ? "fd-" + rest.name : void 0);
3326
+ const fieldId = useFieldId(id);
3311
3327
  const box = ["fd-input", "fd-input-textarea", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : "", className].filter(Boolean).join(" ");
3312
- return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "fd-field", style, children: [
3313
- label ? /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("label", { className: "fd-field-label", htmlFor: fieldId, children: [
3314
- label,
3315
- required ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "fd-field-req", children: "*" }) : null
3316
- ] }) : null,
3317
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: box, children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("textarea", { id: fieldId, rows, disabled, "aria-invalid": error ? "true" : void 0, ...rest }) }),
3318
- error ? /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "fd-field-error", children: [
3319
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
3328
+ return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "fd-field", style, children: [
3329
+ label ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(FieldLabel, { htmlFor: fieldId, required, children: label }) : null,
3330
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: box, children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("textarea", { id: fieldId, rows, disabled, "aria-invalid": error ? "true" : void 0, ...rest }) }),
3331
+ error ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { className: "fd-field-error", children: [
3332
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
3320
3333
  error
3321
- ] }) : help ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "fd-field-help", children: help }) : null
3334
+ ] }) : help ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "fd-field-help", children: help }) : null
3322
3335
  ] });
3323
3336
  }
3324
3337
 
3325
3338
  // src/components/forms/NumberInput.tsx
3326
- var React19 = __toESM(require("react"), 1);
3327
- var import_jsx_runtime48 = require("react/jsx-runtime");
3339
+ var React20 = __toESM(require("react"), 1);
3340
+ var import_jsx_runtime49 = require("react/jsx-runtime");
3328
3341
  function NumberInput({
3329
3342
  label,
3330
3343
  help,
@@ -3342,16 +3355,19 @@ function NumberInput({
3342
3355
  format = true,
3343
3356
  className = "",
3344
3357
  style,
3345
- placeholder
3358
+ placeholder,
3359
+ id,
3360
+ "aria-label": ariaLabel
3346
3361
  }) {
3362
+ const fieldId = useFieldId(id);
3347
3363
  const num = (v) => {
3348
3364
  const n = Number(String(v == null ? "" : v).replace(/[^0-9.-]/g, ""));
3349
3365
  return isNaN(n) ? null : n;
3350
3366
  };
3351
- const [text, setText] = React19.useState(value == null || value === "" ? "" : String(value));
3352
- const [editing, setEditing] = React19.useState(false);
3353
- const timer = React19.useRef(null);
3354
- React19.useEffect(() => {
3367
+ const [text, setText] = React20.useState(value == null || value === "" ? "" : String(value));
3368
+ const [editing, setEditing] = React20.useState(false);
3369
+ const timer = React20.useRef(null);
3370
+ React20.useEffect(() => {
3355
3371
  if (!editing) setText(value == null || value === "" ? "" : String(value));
3356
3372
  }, [value, editing]);
3357
3373
  const clamp = (n) => Math.min(max, Math.max(min, n));
@@ -3375,7 +3391,7 @@ function NumberInput({
3375
3391
  const release = () => {
3376
3392
  if (timer.current) clearTimeout(timer.current);
3377
3393
  };
3378
- React19.useEffect(() => () => {
3394
+ React20.useEffect(() => () => {
3379
3395
  if (timer.current) clearTimeout(timer.current);
3380
3396
  }, []);
3381
3397
  const shown = editing ? text : (() => {
@@ -3383,16 +3399,17 @@ function NumberInput({
3383
3399
  return n == null ? "" : format ? n.toLocaleString() : String(n);
3384
3400
  })();
3385
3401
  const box = ["fd-input", "fd-input-num", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" ");
3386
- return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: ["fd-field", className].filter(Boolean).join(" "), style, children: [
3387
- label ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "fd-field-label", children: [
3388
- label,
3389
- required ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "fd-field-req", children: "*" }) : null
3390
- ] }) : null,
3391
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: box, style: { gap: 8 }, children: [
3392
- prefix ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "fd-input-affix", children: prefix }) : null,
3393
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
3402
+ const fieldName = label || ariaLabel;
3403
+ const stepperName = (verb) => fieldName ? verb + " " + fieldName : verb;
3404
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: ["fd-field", className].filter(Boolean).join(" "), style, children: [
3405
+ label ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(FieldLabel, { htmlFor: fieldId, required, children: label }) : null,
3406
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: box, style: { gap: 8 }, children: [
3407
+ prefix ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "fd-input-affix", children: prefix }) : null,
3408
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3394
3409
  "input",
3395
3410
  {
3411
+ id: fieldId,
3412
+ "aria-label": ariaLabel,
3396
3413
  inputMode: "numeric",
3397
3414
  disabled,
3398
3415
  placeholder,
@@ -3423,51 +3440,51 @@ function NumberInput({
3423
3440
  }
3424
3441
  }
3425
3442
  ),
3426
- suffix ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "fd-input-affix", children: suffix }) : null,
3427
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { className: "fd-row", style: { gap: 4, flex: "none" }, children: [
3428
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
3443
+ suffix ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "fd-input-affix", children: suffix }) : null,
3444
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("span", { className: "fd-row", style: { gap: 4, flex: "none" }, children: [
3445
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3429
3446
  "button",
3430
3447
  {
3431
3448
  type: "button",
3432
3449
  className: "fd-stepbtn",
3433
- "aria-label": "Decrease",
3450
+ "aria-label": stepperName("Decrease"),
3434
3451
  disabled: disabled || (num(text) ?? 0) <= min,
3435
3452
  onPointerDown: () => hold(-1),
3436
3453
  onPointerUp: release,
3437
3454
  onPointerLeave: release,
3438
- children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("i", { className: "ph ph-minus" })
3455
+ children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("i", { className: "ph ph-minus" })
3439
3456
  }
3440
3457
  ),
3441
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
3458
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3442
3459
  "button",
3443
3460
  {
3444
3461
  type: "button",
3445
3462
  className: "fd-stepbtn",
3446
- "aria-label": "Increase",
3463
+ "aria-label": stepperName("Increase"),
3447
3464
  disabled: disabled || (num(text) ?? 0) >= max,
3448
3465
  onPointerDown: () => hold(1),
3449
3466
  onPointerUp: release,
3450
3467
  onPointerLeave: release,
3451
- children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("i", { className: "ph ph-plus" })
3468
+ children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("i", { className: "ph ph-plus" })
3452
3469
  }
3453
3470
  )
3454
3471
  ] })
3455
3472
  ] }),
3456
- error ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { className: "fd-field-error", children: [
3457
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
3473
+ error ? /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("span", { className: "fd-field-error", children: [
3474
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
3458
3475
  error
3459
- ] }) : help ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "fd-field-help", children: help }) : null
3476
+ ] }) : help ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "fd-field-help", children: help }) : null
3460
3477
  ] });
3461
3478
  }
3462
3479
 
3463
3480
  // src/components/forms/Select.tsx
3464
- var React20 = __toESM(require("react"), 1);
3481
+ var React21 = __toESM(require("react"), 1);
3465
3482
  var import_react_dom5 = require("react-dom");
3466
- var import_jsx_runtime49 = require("react/jsx-runtime");
3483
+ var import_jsx_runtime50 = require("react/jsx-runtime");
3467
3484
  var norm = (o) => typeof o === "string" ? { value: o, label: o } : o;
3468
3485
  function usePopPos(open, ref, estH, estW) {
3469
- const [pos, setPos] = React20.useState(null);
3470
- React20.useLayoutEffect(() => {
3486
+ const [pos, setPos] = React21.useState(null);
3487
+ React21.useLayoutEffect(() => {
3471
3488
  if (!open || !ref.current) {
3472
3489
  setPos(null);
3473
3490
  return;
@@ -3524,21 +3541,21 @@ function Select({
3524
3541
  summary,
3525
3542
  id,
3526
3543
  className = "",
3527
- style,
3528
- ...rest
3544
+ style
3529
3545
  }) {
3530
3546
  const opts = options.map(norm);
3531
3547
  const vals = multiple ? Array.isArray(value) ? value : value ? [value] : [] : [];
3532
3548
  const isOn = (v) => multiple ? vals.includes(v) : v === value;
3533
3549
  const hasSearch = searchable === void 0 ? opts.length > 8 : searchable;
3534
- const [open, setOpen] = React20.useState(false);
3535
- const [q, setQ] = React20.useState("");
3536
- const [active, setActive] = React20.useState(-1);
3537
- const rootRef = React20.useRef(null);
3538
- const boxRef = React20.useRef(null);
3539
- const popRef = React20.useRef(null);
3540
- const listRef = React20.useRef(null);
3541
- const typeBuf = React20.useRef({ s: "", t: 0 });
3550
+ const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
3551
+ const [open, setOpen] = React21.useState(false);
3552
+ const [q, setQ] = React21.useState("");
3553
+ const [active, setActive] = React21.useState(-1);
3554
+ const rootRef = React21.useRef(null);
3555
+ const boxRef = React21.useRef(null);
3556
+ const popRef = React21.useRef(null);
3557
+ const listRef = React21.useRef(null);
3558
+ const typeBuf = React21.useRef({ s: "", t: 0 });
3542
3559
  const selected = multiple ? null : opts.find((o) => o.value === value);
3543
3560
  const chosen = multiple ? opts.filter((o) => vals.includes(o.value)) : [];
3544
3561
  const pos = usePopPos(open, boxRef, hasSearch ? 390 : 340, 260);
@@ -3564,7 +3581,7 @@ function Select({
3564
3581
  }
3565
3582
  setOpen(!open);
3566
3583
  };
3567
- React20.useEffect(() => {
3584
+ React21.useEffect(() => {
3568
3585
  if (!open) return;
3569
3586
  const away = (e) => {
3570
3587
  if (rootRef.current && rootRef.current.contains(e.target)) return;
@@ -3574,7 +3591,7 @@ function Select({
3574
3591
  document.addEventListener("pointerdown", away);
3575
3592
  return () => document.removeEventListener("pointerdown", away);
3576
3593
  }, [open]);
3577
- React20.useEffect(() => {
3594
+ React21.useEffect(() => {
3578
3595
  if (!open || active < 0 || !listRef.current) return;
3579
3596
  const el = listRef.current.querySelector('[data-i="' + active + '"]');
3580
3597
  if (el) {
@@ -3626,15 +3643,11 @@ function Select({
3626
3643
  if (!last || last.g !== g) groups.push({ g, items: [{ o, i }] });
3627
3644
  else last.items.push({ o, i });
3628
3645
  });
3629
- const fieldId = id || (rest.name ? "fd-" + rest.name : void 0);
3630
3646
  const box = ["fd-input", "fd-select", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" ");
3631
- return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: ["fd-field", "fd-popfield", open ? "is-open" : "", className].filter(Boolean).join(" "), style, ref: rootRef, children: [
3632
- label ? /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("label", { className: "fd-field-label", htmlFor: fieldId, onClick: toggle, children: [
3633
- label,
3634
- required ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "fd-field-req", children: "*" }) : null
3635
- ] }) : null,
3636
- /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: box, style: { cursor: disabled ? "not-allowed" : "pointer" }, ref: boxRef, children: [
3637
- /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
3647
+ return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: ["fd-field", "fd-popfield", open ? "is-open" : "", className].filter(Boolean).join(" "), style, ref: rootRef, children: [
3648
+ label ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(FieldLabel, { id: labelId, required, onClick: toggle, children: label }) : null,
3649
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: box, style: { cursor: disabled ? "not-allowed" : "pointer" }, ref: boxRef, children: [
3650
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
3638
3651
  "button",
3639
3652
  {
3640
3653
  type: "button",
@@ -3645,15 +3658,16 @@ function Select({
3645
3658
  role: "combobox",
3646
3659
  "aria-expanded": open,
3647
3660
  "aria-haspopup": "listbox",
3661
+ "aria-labelledby": ariaLabelledBy,
3648
3662
  style: { all: "unset", flex: 1, minWidth: 0, display: "flex", alignItems: "center", gap: 8, cursor: "inherit", overflow: "hidden" },
3649
3663
  children: [
3650
- selected && selected.icon ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("i", { className: "ph ph-" + selected.icon, style: { flex: "none", color: "var(--text-2)" } }) : null,
3651
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", color: (multiple ? chosen.length : selected) ? "var(--text)" : "var(--text-muted)" }, children: boxText }),
3652
- multiple && chosen.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("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
3664
+ selected && selected.icon ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("i", { className: "ph ph-" + selected.icon, style: { flex: "none", color: "var(--text-2)" } }) : null,
3665
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", color: (multiple ? chosen.length : selected) ? "var(--text)" : "var(--text-muted)" }, children: boxText }),
3666
+ multiple && chosen.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("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
3653
3667
  ]
3654
3668
  }
3655
3669
  ),
3656
- clearable && (multiple ? chosen.length > 0 : selected) && !loading ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3670
+ clearable && (multiple ? chosen.length > 0 : selected) && !loading ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
3657
3671
  "button",
3658
3672
  {
3659
3673
  type: "button",
@@ -3663,22 +3677,22 @@ function Select({
3663
3677
  fire(multiple ? [] : "");
3664
3678
  },
3665
3679
  style: { all: "unset", cursor: "pointer", color: "var(--text-muted)", display: "grid", placeItems: "center", padding: 2 },
3666
- children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("i", { className: "ph ph-x-circle", style: { fontSize: 15 } })
3680
+ children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("i", { className: "ph ph-x-circle", style: { fontSize: 15 } })
3667
3681
  }
3668
3682
  ) : null,
3669
- loading ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "fd-spinner", style: { color: "var(--text-muted)" }, "aria-label": "Loading options" }) : /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "fd-select-caret", onClick: toggle, children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
3683
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "fd-spinner", style: { color: "var(--text-muted)" }, "aria-label": "Loading options" }) : /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "fd-select-caret", onClick: toggle, children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
3670
3684
  ] }),
3671
3685
  open && pos ? (0, import_react_dom5.createPortal)(
3672
- /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
3686
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
3673
3687
  "div",
3674
3688
  {
3675
3689
  className: "fd-pop" + (pos.up ? " is-up" : ""),
3676
3690
  ref: popRef,
3677
3691
  style: popStyle(pos, { minWidth: Math.max(pos.width, 260), maxWidth: 380, zIndex: 130, overflowY: "hidden" }),
3678
3692
  children: [
3679
- hasSearch ? /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "fd-pop-search", children: [
3680
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("i", { className: "ph ph-magnifying-glass", style: { color: "var(--text-muted)", fontSize: 14 } }),
3681
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3693
+ hasSearch ? /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "fd-pop-search", children: [
3694
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("i", { className: "ph ph-magnifying-glass", style: { color: "var(--text-muted)", fontSize: 14 } }),
3695
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
3682
3696
  "input",
3683
3697
  {
3684
3698
  autoFocus: true,
@@ -3691,15 +3705,15 @@ function Select({
3691
3705
  }
3692
3706
  }
3693
3707
  ),
3694
- q ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "fd-body-sm fd-muted", children: visible.length }) : null
3708
+ q ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "fd-body-sm fd-muted", children: visible.length }) : null
3695
3709
  ] }) : null,
3696
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("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__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "fd-pop-empty", children: [
3710
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("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__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "fd-pop-empty", children: [
3697
3711
  'Nothing matches "',
3698
3712
  q,
3699
3713
  '".'
3700
- ] }) : groups.map((grp) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(React20.Fragment, { children: [
3701
- grp.g ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "fd-pop-group", children: grp.g }) : null,
3702
- grp.items.map(({ o, i }) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
3714
+ ] }) : groups.map((grp) => /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(React21.Fragment, { children: [
3715
+ grp.g ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "fd-pop-group", children: grp.g }) : null,
3716
+ grp.items.map(({ o, i }) => /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
3703
3717
  "button",
3704
3718
  {
3705
3719
  type: "button",
@@ -3711,21 +3725,21 @@ function Select({
3711
3725
  onMouseEnter: () => setActive(i),
3712
3726
  onClick: () => pick(o),
3713
3727
  children: [
3714
- multiple ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("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__ */ (0, import_jsx_runtime49.jsx)("i", { className: "ph ph-check", style: { fontSize: 11 } }) : null }) : null,
3715
- o.icon ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "fd-opt-icon", children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("i", { className: "ph ph-" + o.icon }) }) : null,
3716
- /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("span", { style: { flex: 1, minWidth: 0 }, children: [
3717
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "fd-opt-label", children: o.label }),
3718
- o.description ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "fd-opt-desc", children: o.description }) : null
3728
+ multiple ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("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__ */ (0, import_jsx_runtime50.jsx)("i", { className: "ph ph-check", style: { fontSize: 11 } }) : null }) : null,
3729
+ o.icon ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "fd-opt-icon", children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("i", { className: "ph ph-" + o.icon }) }) : null,
3730
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("span", { style: { flex: 1, minWidth: 0 }, children: [
3731
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "fd-opt-label", children: o.label }),
3732
+ o.description ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "fd-opt-desc", children: o.description }) : null
3719
3733
  ] }),
3720
- o.meta ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "fd-opt-meta", children: o.meta }) : null,
3721
- multiple ? null : /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "fd-opt-check", children: o.value === value ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("i", { className: "ph ph-check" }) : null })
3734
+ o.meta ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "fd-opt-meta", children: o.meta }) : null,
3735
+ multiple ? null : /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "fd-opt-check", children: o.value === value ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("i", { className: "ph ph-check" }) : null })
3722
3736
  ]
3723
3737
  },
3724
3738
  String(o.value)
3725
3739
  ))
3726
3740
  ] }, grp.g || "_")) }),
3727
- multiple ? /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "fd-row", style: { gap: 10, padding: "8px 12px", borderTop: "1px solid var(--border)" }, children: [
3728
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3741
+ multiple ? /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "fd-row", style: { gap: 10, padding: "8px 12px", borderTop: "1px solid var(--border)" }, children: [
3742
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
3729
3743
  "button",
3730
3744
  {
3731
3745
  type: "button",
@@ -3734,13 +3748,13 @@ function Select({
3734
3748
  children: "Select all"
3735
3749
  }
3736
3750
  ),
3737
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { style: { flex: 1 } }),
3738
- /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
3751
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { style: { flex: 1 } }),
3752
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
3739
3753
  vals.length,
3740
3754
  " of ",
3741
3755
  opts.length
3742
3756
  ] }),
3743
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3757
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
3744
3758
  "button",
3745
3759
  {
3746
3760
  type: "button",
@@ -3756,17 +3770,17 @@ function Select({
3756
3770
  ),
3757
3771
  document.body
3758
3772
  ) : null,
3759
- error ? /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("span", { className: "fd-field-error", children: [
3760
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
3773
+ error ? /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("span", { className: "fd-field-error", children: [
3774
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
3761
3775
  error
3762
- ] }) : help ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "fd-field-help", children: help }) : null
3776
+ ] }) : help ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "fd-field-help", children: help }) : null
3763
3777
  ] });
3764
3778
  }
3765
3779
 
3766
3780
  // src/components/forms/DatePicker.tsx
3767
- var React21 = __toESM(require("react"), 1);
3781
+ var React22 = __toESM(require("react"), 1);
3768
3782
  var import_react_dom6 = require("react-dom");
3769
- var import_jsx_runtime50 = require("react/jsx-runtime");
3783
+ var import_jsx_runtime51 = require("react/jsx-runtime");
3770
3784
  var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
3771
3785
  var DOW = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
3772
3786
  var iso = (d) => d.getFullYear() + "-" + String(d.getMonth() + 1).padStart(2, "0") + "-" + String(d.getDate()).padStart(2, "0");
@@ -3780,8 +3794,8 @@ var fmt = (s) => {
3780
3794
  return d ? MONTHS[d.getMonth()].slice(0, 3) + " " + d.getDate() + ", " + d.getFullYear() : "";
3781
3795
  };
3782
3796
  function usePopPos2(open, ref, estH, estW) {
3783
- const [pos, setPos] = React21.useState(null);
3784
- React21.useLayoutEffect(() => {
3797
+ const [pos, setPos] = React22.useState(null);
3798
+ React22.useLayoutEffect(() => {
3785
3799
  if (!open || !ref.current) {
3786
3800
  setPos(null);
3787
3801
  return;
@@ -3825,10 +3839,10 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3825
3839
  const today = /* @__PURE__ */ new Date();
3826
3840
  const sel = range ? value || {} : { start: value, end: value };
3827
3841
  const anchor = parse(sel.start) || parse(initialMonth) || today;
3828
- const [vy, setVy] = React21.useState(anchor.getFullYear());
3829
- const [vm, setVm] = React21.useState(anchor.getMonth());
3830
- const [mode2, setMode] = React21.useState("days");
3831
- const [hover, setHover] = React21.useState(null);
3842
+ const [vy, setVy] = React22.useState(anchor.getFullYear());
3843
+ const [vm, setVm] = React22.useState(anchor.getMonth());
3844
+ const [mode2, setMode] = React22.useState("days");
3845
+ const [hover, setHover] = React22.useState(null);
3832
3846
  const s = parse(sel.start), e = parse(sel.end);
3833
3847
  const hoverEnd = range && s && !e && hover ? parse(hover) : null;
3834
3848
  const inRange = (d) => {
@@ -3865,9 +3879,9 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3865
3879
  const startPad = new Date(y, m, 1).getDay();
3866
3880
  const cells = [];
3867
3881
  for (let i = 0; i < 42; i++) cells.push(new Date(y, m, i - startPad + 1));
3868
- return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "fd-cal-grid", style: { width: months > 1 ? 252 : "auto", flex: "none" }, onMouseLeave: () => setHover(null), children: [
3869
- DOW.map((d) => /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "fd-cal-dow", children: d }, d)),
3870
- cells.map((d, i) => /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
3882
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "fd-cal-grid", style: { width: months > 1 ? 252 : "auto", flex: "none" }, onMouseLeave: () => setHover(null), children: [
3883
+ DOW.map((d) => /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "fd-cal-dow", children: d }, d)),
3884
+ cells.map((d, i) => /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3871
3885
  "button",
3872
3886
  {
3873
3887
  type: "button",
@@ -3881,20 +3895,20 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3881
3895
  ] });
3882
3896
  };
3883
3897
  const nextY = vm === 11 ? vy + 1 : vy, nextM = (vm + 1) % 12;
3884
- return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "fd-cal", style: { width: months > 1 && mode2 === "days" ? "auto" : void 0 }, children: [
3885
- /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "fd-cal-head", children: [
3886
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("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__ */ (0, import_jsx_runtime50.jsx)("i", { className: "ph ph-caret-left" }) }),
3887
- /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("button", { type: "button", className: "fd-cal-title", onClick: () => setMode(mode2 === "days" ? "months" : mode2 === "months" ? "years" : "days"), children: [
3898
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "fd-cal", style: { width: months > 1 && mode2 === "days" ? "auto" : void 0 }, children: [
3899
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "fd-cal-head", children: [
3900
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("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__ */ (0, import_jsx_runtime51.jsx)("i", { className: "ph ph-caret-left" }) }),
3901
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("button", { type: "button", className: "fd-cal-title", onClick: () => setMode(mode2 === "days" ? "months" : mode2 === "months" ? "years" : "days"), children: [
3888
3902
  mode2 === "days" ? MONTHS[vm] + " " + vy : mode2 === "months" ? vy : vy - 5 + " \u2013 " + (vy + 6),
3889
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("i", { className: "ph ph-caret-down", style: { fontSize: 10, marginLeft: 6, color: "var(--text-muted)" } })
3903
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("i", { className: "ph ph-caret-down", style: { fontSize: 10, marginLeft: 6, color: "var(--text-muted)" } })
3890
3904
  ] }),
3891
- months > 1 && mode2 === "days" ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "fd-cal-title", style: { cursor: "default", background: "none" }, children: MONTHS[nextM] + " " + nextY }) : null,
3892
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("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__ */ (0, import_jsx_runtime50.jsx)("i", { className: "ph ph-caret-right" }) })
3905
+ months > 1 && mode2 === "days" ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "fd-cal-title", style: { cursor: "default", background: "none" }, children: MONTHS[nextM] + " " + nextY }) : null,
3906
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("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__ */ (0, import_jsx_runtime51.jsx)("i", { className: "ph ph-caret-right" }) })
3893
3907
  ] }),
3894
- mode2 === "days" ? /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { style: { display: "flex", gap: 18 }, children: [
3908
+ mode2 === "days" ? /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { style: { display: "flex", gap: 18 }, children: [
3895
3909
  monthGrid(vy, vm),
3896
3910
  months > 1 ? monthGrid(nextY, nextM) : null
3897
- ] }) : mode2 === "months" ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "fd-cal-grid-months", children: MONTHS.map((m, i) => /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
3911
+ ] }) : mode2 === "months" ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "fd-cal-grid-months", children: MONTHS.map((m, i) => /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3898
3912
  "button",
3899
3913
  {
3900
3914
  type: "button",
@@ -3906,7 +3920,7 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3906
3920
  children: m.slice(0, 3)
3907
3921
  },
3908
3922
  m
3909
- )) }) : /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "fd-cal-grid-months", children: Array.from({ length: 12 }, (_, i) => vy - 5 + i).map((y) => /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
3923
+ )) }) : /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "fd-cal-grid-months", children: Array.from({ length: 12 }, (_, i) => vy - 5 + i).map((y) => /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3910
3924
  "button",
3911
3925
  {
3912
3926
  type: "button",
@@ -3919,8 +3933,8 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3919
3933
  },
3920
3934
  y
3921
3935
  )) }),
3922
- /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "fd-cal-foot", children: [
3923
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
3936
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "fd-cal-foot", children: [
3937
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3924
3938
  "button",
3925
3939
  {
3926
3940
  type: "button",
@@ -3934,21 +3948,22 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3934
3948
  children: "Today"
3935
3949
  }
3936
3950
  ),
3937
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { style: { flex: 1 } }),
3938
- range && sel.start ? /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
3951
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { style: { flex: 1 } }),
3952
+ range && sel.start ? /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
3939
3953
  fmt(sel.start),
3940
3954
  sel.end ? " \u2192 " + fmt(sel.end) : " \u2192 pick an end"
3941
3955
  ] }) : null
3942
3956
  ] })
3943
3957
  ] });
3944
3958
  }
3945
- function DatePicker({ label, help, error, required = false, disabled = false, range = false, value, onChange, placeholder, className = "", style, ...rest }) {
3946
- const [open, setOpen] = React21.useState(false);
3947
- const rootRef = React21.useRef(null);
3948
- const boxRef = React21.useRef(null);
3949
- const popRef = React21.useRef(null);
3959
+ function DatePicker({ label, help, error, required = false, disabled = false, range = false, value, onChange, placeholder, id, className = "", style, ...rest }) {
3960
+ const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
3961
+ const [open, setOpen] = React22.useState(false);
3962
+ const rootRef = React22.useRef(null);
3963
+ const boxRef = React22.useRef(null);
3964
+ const popRef = React22.useRef(null);
3950
3965
  const pos = usePopPos2(open, boxRef, 430, range ? 600 : 316);
3951
- React21.useEffect(() => {
3966
+ React22.useEffect(() => {
3952
3967
  if (!open) return;
3953
3968
  const away = (e) => {
3954
3969
  if (rootRef.current && rootRef.current.contains(e.target)) return;
@@ -3969,17 +3984,16 @@ function DatePicker({ label, help, error, required = false, disabled = false, ra
3969
3984
  const toggle = () => {
3970
3985
  if (!disabled) setOpen(!open);
3971
3986
  };
3972
- return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: ["fd-field", "fd-popfield", open ? "is-open" : "", className].filter(Boolean).join(" "), style, ref: rootRef, children: [
3973
- label ? /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("label", { className: "fd-field-label", onClick: toggle, children: [
3974
- label,
3975
- required ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "fd-field-req", children: "*" }) : null
3976
- ] }) : null,
3977
- /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("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: [
3978
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "fd-input-icon", children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }) }),
3979
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
3987
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: ["fd-field", "fd-popfield", open ? "is-open" : "", className].filter(Boolean).join(" "), style, ref: rootRef, children: [
3988
+ label ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(FieldLabel, { id: labelId, required, onClick: toggle, children: label }) : null,
3989
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("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: [
3990
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "fd-input-icon", children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }) }),
3991
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3980
3992
  "button",
3981
3993
  {
3982
3994
  type: "button",
3995
+ id: fieldId,
3996
+ "aria-labelledby": ariaLabelledBy,
3983
3997
  disabled,
3984
3998
  onKeyDown: (e) => {
3985
3999
  if (e.key === "Enter" || e.key === " ") {
@@ -3992,10 +4006,10 @@ function DatePicker({ label, help, error, required = false, disabled = false, ra
3992
4006
  children: display || placeholder || (range ? "Pick a date range" : "Pick a date")
3993
4007
  }
3994
4008
  ),
3995
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "fd-select-caret", children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
4009
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "fd-select-caret", children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
3996
4010
  ] }),
3997
4011
  open && pos ? (0, import_react_dom6.createPortal)(
3998
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "fd-pop" + (pos.up ? " is-up" : ""), ref: popRef, style: popStyle2(pos, { width: "max-content", minWidth: 0, zIndex: 130 }), children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
4012
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "fd-pop" + (pos.up ? " is-up" : ""), ref: popRef, style: popStyle2(pos, { width: "max-content", minWidth: 0, zIndex: 130 }), children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3999
4013
  Calendar,
4000
4014
  {
4001
4015
  range,
@@ -4009,21 +4023,21 @@ function DatePicker({ label, help, error, required = false, disabled = false, ra
4009
4023
  ) }),
4010
4024
  document.body
4011
4025
  ) : null,
4012
- error ? /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("span", { className: "fd-field-error", children: [
4013
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
4026
+ error ? /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("span", { className: "fd-field-error", children: [
4027
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
4014
4028
  error
4015
- ] }) : help ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "fd-field-help", children: help }) : null
4029
+ ] }) : help ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "fd-field-help", children: help }) : null
4016
4030
  ] });
4017
4031
  }
4018
4032
 
4019
4033
  // src/components/forms/TimePicker.tsx
4020
- var React22 = __toESM(require("react"), 1);
4034
+ var React23 = __toESM(require("react"), 1);
4021
4035
  var import_react_dom7 = require("react-dom");
4022
- var import_jsx_runtime51 = require("react/jsx-runtime");
4036
+ var import_jsx_runtime52 = require("react/jsx-runtime");
4023
4037
  var pad = (n) => String(n).padStart(2, "0");
4024
4038
  function usePopPos3(open, ref, estH, estW) {
4025
- const [pos, setPos] = React22.useState(null);
4026
- React22.useLayoutEffect(() => {
4039
+ const [pos, setPos] = React23.useState(null);
4040
+ React23.useLayoutEffect(() => {
4027
4041
  if (!open || !ref.current) {
4028
4042
  setPos(null);
4029
4043
  return;
@@ -4069,9 +4083,9 @@ function ClockFace({ value = "09:00", onChange }) {
4069
4083
  if (isNaN(m)) m = 0;
4070
4084
  const pm = h24 >= 12;
4071
4085
  const h12 = h24 % 12 === 0 ? 12 : h24 % 12;
4072
- const [mode2, setMode] = React22.useState("h");
4073
- const faceRef = React22.useRef(null);
4074
- const dragging = React22.useRef(false);
4086
+ const [mode2, setMode] = React23.useState("h");
4087
+ const faceRef = React23.useRef(null);
4088
+ const dragging = React23.useRef(false);
4075
4089
  const set = (h, mm, isPm) => onChange((isPm ? h % 12 + 12 : h % 12) + ":" + pad(mm));
4076
4090
  const R = 108, NR = 80;
4077
4091
  const nums = mode2 === "h" ? Array.from({ length: 12 }, (_, i) => i + 1) : Array.from({ length: 12 }, (_, i) => i * 5);
@@ -4106,12 +4120,12 @@ function ClockFace({ value = "09:00", onChange }) {
4106
4120
  };
4107
4121
  const handAngle = mode2 === "h" ? h12 % 12 * 30 : m * 6;
4108
4122
  const minuteOff = mode2 === "m" && m % 5 !== 0;
4109
- return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { style: { padding: "4px 14px 14px" }, children: [
4110
- /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "fd-clock-digits", children: [
4111
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("button", { type: "button", className: "fd-clock-digit" + (mode2 === "h" ? " is-active" : ""), onClick: () => setMode("h"), children: pad(h12) }),
4112
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { style: { fontSize: 24, fontWeight: 700, color: "var(--text-muted)" }, children: ":" }),
4113
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("button", { type: "button", className: "fd-clock-digit" + (mode2 === "m" ? " is-active" : ""), onClick: () => setMode("m"), children: pad(m) }),
4114
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "fd-stack", style: { gap: 3, marginLeft: 8 }, children: ["AM", "PM"].map((ap) => /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
4123
+ return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { style: { padding: "4px 14px 14px" }, children: [
4124
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "fd-clock-digits", children: [
4125
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("button", { type: "button", className: "fd-clock-digit" + (mode2 === "h" ? " is-active" : ""), onClick: () => setMode("h"), children: pad(h12) }),
4126
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { style: { fontSize: 24, fontWeight: 700, color: "var(--text-muted)" }, children: ":" }),
4127
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("button", { type: "button", className: "fd-clock-digit" + (mode2 === "m" ? " is-active" : ""), onClick: () => setMode("m"), children: pad(m) }),
4128
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "fd-stack", style: { gap: 3, marginLeft: 8 }, children: ["AM", "PM"].map((ap) => /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
4115
4129
  "button",
4116
4130
  {
4117
4131
  type: "button",
@@ -4122,13 +4136,13 @@ function ClockFace({ value = "09:00", onChange }) {
4122
4136
  ap
4123
4137
  )) })
4124
4138
  ] }),
4125
- /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "fd-clock", ref: faceRef, onPointerDown: down, onPointerMove: move, onPointerUp: upH, children: [
4126
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "fd-clock-hand", style: { height: NR - (minuteOff ? 14 : 16), transform: "translateX(-50%) rotate(" + handAngle + "deg)", bottom: "50%" } }),
4127
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "fd-clock-pivot" }),
4128
- minuteOff ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("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,
4139
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "fd-clock", ref: faceRef, onPointerDown: down, onPointerMove: move, onPointerUp: upH, children: [
4140
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "fd-clock-hand", style: { height: NR - (minuteOff ? 14 : 16), transform: "translateX(-50%) rotate(" + handAngle + "deg)", bottom: "50%" } }),
4141
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "fd-clock-pivot" }),
4142
+ minuteOff ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("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,
4129
4143
  nums.map((n) => {
4130
4144
  const a = angleOf(n) * Math.PI / 180;
4131
- return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
4145
+ return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
4132
4146
  "span",
4133
4147
  {
4134
4148
  className: "fd-clock-num" + (n === selNum || mode2 === "m" && n === Math.round(m / 5) * 5 % 60 && m % 5 === 0 ? " is-sel" : ""),
@@ -4139,16 +4153,17 @@ function ClockFace({ value = "09:00", onChange }) {
4139
4153
  );
4140
4154
  })
4141
4155
  ] }),
4142
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "fd-row", style: { justifyContent: "center", gap: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "fd-body-sm fd-muted", children: mode2 === "h" ? "Pick the hour \u2014 drag or tap" : "Now the minutes" }) })
4156
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "fd-row", style: { justifyContent: "center", gap: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "fd-body-sm fd-muted", children: mode2 === "h" ? "Pick the hour \u2014 drag or tap" : "Now the minutes" }) })
4143
4157
  ] });
4144
4158
  }
4145
- function TimePicker({ label, help, error, required = false, disabled = false, value = "", onChange, placeholder = "Pick a time", className = "", style }) {
4146
- const [open, setOpen] = React22.useState(false);
4147
- const rootRef = React22.useRef(null);
4148
- const boxRef = React22.useRef(null);
4149
- const popRef = React22.useRef(null);
4159
+ function TimePicker({ label, help, error, required = false, disabled = false, value = "", onChange, placeholder = "Pick a time", id, className = "", style }) {
4160
+ const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
4161
+ const [open, setOpen] = React23.useState(false);
4162
+ const rootRef = React23.useRef(null);
4163
+ const boxRef = React23.useRef(null);
4164
+ const popRef = React23.useRef(null);
4150
4165
  const pos = usePopPos3(open, boxRef, 420, 262);
4151
- React22.useEffect(() => {
4166
+ React23.useEffect(() => {
4152
4167
  if (!open) return;
4153
4168
  const away = (e) => {
4154
4169
  if (rootRef.current && rootRef.current.contains(e.target)) return;
@@ -4173,17 +4188,16 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
4173
4188
  const toggle = () => {
4174
4189
  if (!disabled) setOpen(!open);
4175
4190
  };
4176
- return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: ["fd-field", "fd-popfield", open ? "is-open" : "", className].filter(Boolean).join(" "), style, ref: rootRef, children: [
4177
- label ? /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("label", { className: "fd-field-label", onClick: toggle, children: [
4178
- label,
4179
- required ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "fd-field-req", children: "*" }) : null
4180
- ] }) : null,
4181
- /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("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: [
4182
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "fd-input-icon", children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("i", { className: "ph ph-clock", "aria-hidden": "true" }) }),
4183
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
4191
+ return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: ["fd-field", "fd-popfield", open ? "is-open" : "", className].filter(Boolean).join(" "), style, ref: rootRef, children: [
4192
+ label ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(FieldLabel, { id: labelId, required, onClick: toggle, children: label }) : null,
4193
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("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: [
4194
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "fd-input-icon", children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("i", { className: "ph ph-clock", "aria-hidden": "true" }) }),
4195
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
4184
4196
  "button",
4185
4197
  {
4186
4198
  type: "button",
4199
+ id: fieldId,
4200
+ "aria-labelledby": ariaLabelledBy,
4187
4201
  disabled,
4188
4202
  onKeyDown: (e) => {
4189
4203
  if (e.key === "Enter" || e.key === " ") {
@@ -4195,13 +4209,13 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
4195
4209
  children: disp() || placeholder
4196
4210
  }
4197
4211
  ),
4198
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "fd-select-caret", children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
4212
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "fd-select-caret", children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
4199
4213
  ] }),
4200
4214
  open && pos ? (0, import_react_dom7.createPortal)(
4201
- /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "fd-pop" + (pos.up ? " is-up" : ""), ref: popRef, style: popStyle3(pos, { width: 262, minWidth: 0, zIndex: 130 }), children: [
4202
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ClockFace, { value: value || "09:00", onChange: (v) => onChange && onChange({ target: { value: v } }) }),
4203
- /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "fd-cal-foot", style: { margin: "0 14px 12px", paddingTop: 10 }, children: [
4204
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
4215
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "fd-pop" + (pos.up ? " is-up" : ""), ref: popRef, style: popStyle3(pos, { width: 262, minWidth: 0, zIndex: 130 }), children: [
4216
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(ClockFace, { value: value || "09:00", onChange: (v) => onChange && onChange({ target: { value: v } }) }),
4217
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "fd-cal-foot", style: { margin: "0 14px 12px", paddingTop: 10 }, children: [
4218
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
4205
4219
  "button",
4206
4220
  {
4207
4221
  type: "button",
@@ -4214,22 +4228,22 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
4214
4228
  children: "Now"
4215
4229
  }
4216
4230
  ),
4217
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { style: { flex: 1 } }),
4218
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", onClick: () => setOpen(false), children: "Done" })
4231
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { style: { flex: 1 } }),
4232
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", onClick: () => setOpen(false), children: "Done" })
4219
4233
  ] })
4220
4234
  ] }),
4221
4235
  document.body
4222
4236
  ) : null,
4223
- error ? /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("span", { className: "fd-field-error", children: [
4224
- /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
4237
+ error ? /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("span", { className: "fd-field-error", children: [
4238
+ /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
4225
4239
  error
4226
- ] }) : help ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "fd-field-help", children: help }) : null
4240
+ ] }) : help ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "fd-field-help", children: help }) : null
4227
4241
  ] });
4228
4242
  }
4229
4243
 
4230
4244
  // src/components/forms/Slider.tsx
4231
- var React23 = __toESM(require("react"), 1);
4232
- var import_jsx_runtime52 = require("react/jsx-runtime");
4245
+ var React24 = __toESM(require("react"), 1);
4246
+ var import_jsx_runtime53 = require("react/jsx-runtime");
4233
4247
  function Slider({
4234
4248
  label,
4235
4249
  min = 0,
@@ -4240,23 +4254,27 @@ function Slider({
4240
4254
  format = (v) => String(v),
4241
4255
  showChip = true,
4242
4256
  help,
4257
+ id,
4258
+ "aria-label": ariaLabel,
4243
4259
  className = "",
4244
4260
  ...rest
4245
4261
  }) {
4246
- const [dragging, setDragging] = React23.useState(false);
4262
+ const fieldId = useFieldId(id);
4263
+ const [dragging, setDragging] = React24.useState(false);
4247
4264
  const v = value === void 0 ? min : Number(value);
4248
4265
  const pct = max === min ? 0 : (v - min) / (max - min) * 100;
4249
- return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: ["fd-field", className].filter(Boolean).join(" "), children: [
4250
- label ? /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
4251
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "fd-field-label", children: label }),
4252
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "fd-num", style: { color: "var(--text-2)" }, children: format(v) })
4266
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: ["fd-field", className].filter(Boolean).join(" "), children: [
4267
+ label ? /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
4268
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(FieldLabel, { htmlFor: fieldId, children: label }),
4269
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "fd-num", style: { color: "var(--text-2)" }, children: format(v) })
4253
4270
  ] }) : null,
4254
- /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "fd-slider", children: [
4255
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
4256
- showChip && dragging ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "fd-slider-chip", style: { left: pct + "%" }, children: format(v) }) : null,
4257
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
4271
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "fd-slider", children: [
4272
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
4273
+ showChip && dragging ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "fd-slider-chip", style: { left: pct + "%" }, children: format(v) }) : null,
4274
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
4258
4275
  "input",
4259
4276
  {
4277
+ id: fieldId,
4260
4278
  type: "range",
4261
4279
  min,
4262
4280
  max,
@@ -4266,18 +4284,18 @@ function Slider({
4266
4284
  onPointerDown: () => setDragging(true),
4267
4285
  onPointerUp: () => setDragging(false),
4268
4286
  onBlur: () => setDragging(false),
4269
- "aria-label": label,
4287
+ "aria-label": ariaLabel,
4270
4288
  ...rest
4271
4289
  }
4272
4290
  )
4273
4291
  ] }),
4274
- help ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "fd-field-help", children: help }) : null
4292
+ help ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "fd-field-help", children: help }) : null
4275
4293
  ] });
4276
4294
  }
4277
4295
 
4278
4296
  // src/components/forms/RangeSlider.tsx
4279
- var React24 = __toESM(require("react"), 1);
4280
- var import_jsx_runtime53 = require("react/jsx-runtime");
4297
+ var React25 = __toESM(require("react"), 1);
4298
+ var import_jsx_runtime54 = require("react/jsx-runtime");
4281
4299
  function RangeSlider({
4282
4300
  label,
4283
4301
  min = 0,
@@ -4296,9 +4314,9 @@ function RangeSlider({
4296
4314
  }) {
4297
4315
  const fmt2 = format || ((v) => String(v));
4298
4316
  const [a, b] = value || [min, max];
4299
- const [drag, setDrag] = React24.useState(null);
4300
- const [focus, setFocus] = React24.useState(null);
4301
- const railRef = React24.useRef(null);
4317
+ const [drag, setDrag] = React25.useState(null);
4318
+ const [focus, setFocus] = React25.useState(null);
4319
+ const railRef = React25.useRef(null);
4302
4320
  const pct = (v) => max === min ? 0 : (v - min) / (max - min) * 100;
4303
4321
  const clampPair = (i, v) => {
4304
4322
  v = Math.min(max, Math.max(min, Math.round(v / step) * step));
@@ -4313,7 +4331,7 @@ function RangeSlider({
4313
4331
  const r = railRef.current.getBoundingClientRect();
4314
4332
  return min + Math.min(1, Math.max(0, (e.clientX - r.left) / r.width)) * (max - min);
4315
4333
  };
4316
- React24.useEffect(() => {
4334
+ React25.useEffect(() => {
4317
4335
  if (drag === null) return;
4318
4336
  const mv = (e) => onChange && onChange(clampPair(drag, fromEvent(e)));
4319
4337
  const upH = () => setDrag(null);
@@ -4334,7 +4352,7 @@ function RangeSlider({
4334
4352
  };
4335
4353
  const thin = S.length > 7 ? Math.ceil(S.length / 5) : 1;
4336
4354
  const pair = value || [S[0].value, S[S.length - 1].value];
4337
- return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
4355
+ return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
4338
4356
  RangeSlider,
4339
4357
  {
4340
4358
  ...rest,
@@ -4382,23 +4400,23 @@ function RangeSlider({
4382
4400
  };
4383
4401
  const showChip = (i) => drag === i || focus === i;
4384
4402
  const hasLabels = marks.some((m) => m.label);
4385
- return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: ["fd-field", className].filter(Boolean).join(" "), ...rest, children: [
4386
- label ? /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
4387
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "fd-field-label", children: label }),
4388
- /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("span", { className: "fd-num", style: { color: "var(--text-2)" }, children: [
4403
+ return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: ["fd-field", className].filter(Boolean).join(" "), ...rest, children: [
4404
+ label ? /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
4405
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "fd-field-label", children: label }),
4406
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("span", { className: "fd-num", style: { color: "var(--text-2)" }, children: [
4389
4407
  fmt2(a),
4390
4408
  " \u2013 ",
4391
4409
  fmt2(b)
4392
4410
  ] })
4393
4411
  ] }) : null,
4394
- /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "fd-range" + (hasLabels ? " has-labels" : ""), onPointerDown: onRailDown, children: [
4395
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "fd-range-rail", ref: railRef }),
4396
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "fd-range-fill", style: { left: pct(a) + "%", width: pct(b) - pct(a) + "%" } }),
4397
- marks.map((m) => /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(React24.Fragment, { children: [
4398
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "fd-range-mark" + (m.value >= a && m.value <= b ? " is-in" : ""), style: { left: pct(m.value) + "%" } }),
4399
- m.label ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "fd-range-mark-label", style: { left: pct(m.value) + "%" }, children: m.label }) : null
4412
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "fd-range" + (hasLabels ? " has-labels" : ""), onPointerDown: onRailDown, children: [
4413
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "fd-range-rail", ref: railRef }),
4414
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "fd-range-fill", style: { left: pct(a) + "%", width: pct(b) - pct(a) + "%" } }),
4415
+ marks.map((m) => /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(React25.Fragment, { children: [
4416
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "fd-range-mark" + (m.value >= a && m.value <= b ? " is-in" : ""), style: { left: pct(m.value) + "%" } }),
4417
+ m.label ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "fd-range-mark-label", style: { left: pct(m.value) + "%" }, children: m.label }) : null
4400
4418
  ] }, m.value)),
4401
- [a, b].map((v, i) => /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
4419
+ [a, b].map((v, i) => /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
4402
4420
  "span",
4403
4421
  {
4404
4422
  className: "fd-range-thumb" + (drag === i ? " is-drag" : ""),
@@ -4413,18 +4431,18 @@ function RangeSlider({
4413
4431
  onKeyDown: key(i),
4414
4432
  onFocus: () => setFocus(i),
4415
4433
  onBlur: () => setFocus(null),
4416
- children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "fd-range-chip", style: { opacity: showChip(i) ? 1 : void 0 }, children: fmt2(v) })
4434
+ children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "fd-range-chip", style: { opacity: showChip(i) ? 1 : void 0 }, children: fmt2(v) })
4417
4435
  },
4418
4436
  i
4419
4437
  ))
4420
4438
  ] }),
4421
- help ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "fd-field-help", children: help }) : null
4439
+ help ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "fd-field-help", children: help }) : null
4422
4440
  ] });
4423
4441
  }
4424
4442
 
4425
4443
  // src/components/forms/Dropzone.tsx
4426
- var React25 = __toESM(require("react"), 1);
4427
- var import_jsx_runtime54 = require("react/jsx-runtime");
4444
+ var React26 = __toESM(require("react"), 1);
4445
+ var import_jsx_runtime55 = require("react/jsx-runtime");
4428
4446
  function Dropzone({
4429
4447
  onFiles,
4430
4448
  onReject,
@@ -4438,8 +4456,8 @@ function Dropzone({
4438
4456
  className = "",
4439
4457
  style
4440
4458
  }) {
4441
- const [over, setOver] = React25.useState(false);
4442
- const depth = React25.useRef(0);
4459
+ const [over, setOver] = React26.useState(false);
4460
+ const depth = React26.useRef(0);
4443
4461
  const has = (e) => {
4444
4462
  const dt = e.dataTransfer;
4445
4463
  if (!dt) return false;
@@ -4469,7 +4487,7 @@ function Dropzone({
4469
4487
  if (rejected.length && onReject) onReject(rejected);
4470
4488
  if (accepted.length && onFiles) onFiles(accepted);
4471
4489
  };
4472
- return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
4490
+ return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(
4473
4491
  "div",
4474
4492
  {
4475
4493
  className: ["fd-dropzone", over ? "is-over" : "", className].filter(Boolean).join(" "),
@@ -4480,10 +4498,10 @@ function Dropzone({
4480
4498
  onDrop: drop,
4481
4499
  children: [
4482
4500
  children,
4483
- over ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: "fd-dropzone-veil", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "fd-dropzone-card", children: [
4484
- /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("i", { className: "ph ph-tray-arrow-down" }),
4485
- /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "fd-dropzone-label", children: label }),
4486
- hint ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "fd-dropzone-hint", children: hint }) : null
4501
+ over ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "fd-dropzone-veil", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "fd-dropzone-card", children: [
4502
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("i", { className: "ph ph-tray-arrow-down" }),
4503
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("span", { className: "fd-dropzone-label", children: label }),
4504
+ hint ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("span", { className: "fd-dropzone-hint", children: hint }) : null
4487
4505
  ] }) }) : null
4488
4506
  ]
4489
4507
  }
@@ -4501,9 +4519,9 @@ function FilePickButton({
4501
4519
  className = "",
4502
4520
  children
4503
4521
  }) {
4504
- const ref = React25.useRef(null);
4505
- return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(React25.Fragment, { children: [
4506
- /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
4522
+ const ref = React26.useRef(null);
4523
+ return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(React26.Fragment, { children: [
4524
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
4507
4525
  "button",
4508
4526
  {
4509
4527
  type: "button",
@@ -4512,10 +4530,10 @@ function FilePickButton({
4512
4530
  "aria-label": label,
4513
4531
  title: label,
4514
4532
  onClick: () => ref.current && ref.current.click(),
4515
- children: children != null ? children : /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("i", { className: "ph ph-" + icon, "aria-hidden": "true" })
4533
+ children: children != null ? children : /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("i", { className: "ph ph-" + icon, "aria-hidden": "true" })
4516
4534
  }
4517
4535
  ),
4518
- /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
4536
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
4519
4537
  "input",
4520
4538
  {
4521
4539
  ref,
@@ -4535,10 +4553,10 @@ function FilePickButton({
4535
4553
  }
4536
4554
  function useStagedFiles(upload, opts) {
4537
4555
  const o = opts || {};
4538
- const [items, setItems] = React25.useState([]);
4539
- const controllers = React25.useRef({});
4556
+ const [items, setItems] = React26.useState([]);
4557
+ const controllers = React26.useRef({});
4540
4558
  const patch = (id, next) => setItems((list) => list.map((f) => f.id === id ? Object.assign({}, f, next) : f));
4541
- const run = React25.useCallback((att) => {
4559
+ const run = React26.useCallback((att) => {
4542
4560
  if (!upload) return;
4543
4561
  const ac = typeof AbortController !== "undefined" ? new AbortController() : null;
4544
4562
  controllers.current[att.id] = ac;
@@ -4555,14 +4573,14 @@ function useStagedFiles(upload, opts) {
4555
4573
  delete controllers.current[att.id];
4556
4574
  });
4557
4575
  }, [upload]);
4558
- const add = React25.useCallback((files) => {
4576
+ const add = React26.useCallback((files) => {
4559
4577
  if (!upload) return [];
4560
4578
  const atts = Array.from(files).map((f) => toAttachment(f));
4561
4579
  setItems((list) => list.concat(atts));
4562
4580
  atts.forEach(run);
4563
4581
  return atts;
4564
4582
  }, [upload, run]);
4565
- const remove = React25.useCallback((att) => {
4583
+ const remove = React26.useCallback((att) => {
4566
4584
  const ac = controllers.current[att.id];
4567
4585
  if (ac) {
4568
4586
  try {
@@ -4573,10 +4591,10 @@ function useStagedFiles(upload, opts) {
4573
4591
  }
4574
4592
  setItems((list) => list.filter((f) => f.id !== att.id));
4575
4593
  }, []);
4576
- const retry = React25.useCallback((att) => {
4594
+ const retry = React26.useCallback((att) => {
4577
4595
  run(att);
4578
4596
  }, [run]);
4579
- const clear = React25.useCallback(() => {
4597
+ const clear = React26.useCallback(() => {
4580
4598
  Object.values(controllers.current).forEach((ac) => {
4581
4599
  try {
4582
4600
  ac && ac.abort();
@@ -4592,7 +4610,7 @@ function useStagedFiles(upload, opts) {
4592
4610
  var DropzoneKit = { useStagedFiles };
4593
4611
 
4594
4612
  // src/components/forms/FileGrid.tsx
4595
- var import_jsx_runtime55 = require("react/jsx-runtime");
4613
+ var import_jsx_runtime56 = require("react/jsx-runtime");
4596
4614
  var truncateMiddle = (name, max = 34) => {
4597
4615
  if (!name || name.length <= max) return name;
4598
4616
  const ext = /\.[A-Za-z0-9]+$/.exec(name);
@@ -4601,7 +4619,7 @@ var truncateMiddle = (name, max = 34) => {
4601
4619
  return head + "\u2026" + tail;
4602
4620
  };
4603
4621
  function Progress({ value }) {
4604
- return /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("span", { className: "fd-file-prog", role: "progressbar", "aria-valuenow": Math.round(value), "aria-valuemin": 0, "aria-valuemax": 100, children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("span", { className: "fd-file-prog-fill", style: { width: Math.max(4, Math.min(100, value)) + "%" } }) });
4622
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "fd-file-prog", role: "progressbar", "aria-valuenow": Math.round(value), "aria-valuemin": 0, "aria-valuemax": 100, children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "fd-file-prog-fill", style: { width: Math.max(4, Math.min(100, value)) + "%" } }) });
4605
4623
  }
4606
4624
  function FileChip({ file, onOpen, onRemove, onRetry, compact: compact3 = false, className = "" }) {
4607
4625
  if (!file) return null;
@@ -4610,8 +4628,8 @@ function FileChip({ file, onOpen, onRemove, onRetry, compact: compact3 = false,
4610
4628
  const thumb = file.thumb && file.thumb.url || (image ? file.blobUrl || file.url : null);
4611
4629
  const meta = file.meta || (file.size ? formatBytes(file.size) : "");
4612
4630
  const clickable = !!onOpen && !uploading;
4613
- return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: ["fd-file", compact3 ? "is-compact" : "", file.error ? "is-error" : "", uploading ? "is-uploading" : "", className].filter(Boolean).join(" "), children: [
4614
- /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(
4631
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: ["fd-file", compact3 ? "is-compact" : "", file.error ? "is-error" : "", uploading ? "is-uploading" : "", className].filter(Boolean).join(" "), children: [
4632
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
4615
4633
  "button",
4616
4634
  {
4617
4635
  type: "button",
@@ -4620,16 +4638,16 @@ function FileChip({ file, onOpen, onRemove, onRetry, compact: compact3 = false,
4620
4638
  onClick: clickable ? () => onOpen(file) : void 0,
4621
4639
  title: file.name + (meta ? " \xB7 " + meta : ""),
4622
4640
  children: [
4623
- /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("span", { className: "fd-file-icon", children: [
4624
- thumb ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("img", { src: thumb, alt: "" }) : /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("i", { className: "ph ph-" + iconForMime(file.mime, file.name), "aria-hidden": "true" }),
4625
- (file.mime || "").startsWith("video/") ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("i", { className: "ph ph-play fd-file-play", "aria-hidden": "true" }) : null
4641
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("span", { className: "fd-file-icon", children: [
4642
+ thumb ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("img", { src: thumb, alt: "" }) : /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("i", { className: "ph ph-" + iconForMime(file.mime, file.name), "aria-hidden": "true" }),
4643
+ (file.mime || "").startsWith("video/") ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("i", { className: "ph ph-play fd-file-play", "aria-hidden": "true" }) : null
4626
4644
  ] }),
4627
- /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("span", { className: "fd-file-text", children: [
4628
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("span", { className: "fd-file-name", children: truncateMiddle(file.name, compact3 ? 26 : 40) }),
4629
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("span", { className: "fd-file-meta", children: file.error ? /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("span", { className: "fd-file-err", children: [
4630
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
4645
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("span", { className: "fd-file-text", children: [
4646
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "fd-file-name", children: truncateMiddle(file.name, compact3 ? 26 : 40) }),
4647
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "fd-file-meta", children: file.error ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("span", { className: "fd-file-err", children: [
4648
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
4631
4649
  file.error
4632
- ] }) : uploading ? /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("span", { className: "fd-tabular", children: [
4650
+ ] }) : uploading ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("span", { className: "fd-tabular", children: [
4633
4651
  Math.round(file.progress),
4634
4652
  "% uploaded"
4635
4653
  ] }) : meta })
@@ -4637,29 +4655,29 @@ function FileChip({ file, onOpen, onRemove, onRetry, compact: compact3 = false,
4637
4655
  ]
4638
4656
  }
4639
4657
  ),
4640
- uploading ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Progress, { value: file.progress }) : null,
4641
- file.error && onRetry ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("button", { type: "button", className: "fd-file-act", onClick: () => onRetry(file), "aria-label": "Retry upload of " + file.name, children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
4642
- onRemove ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("button", { type: "button", className: "fd-file-act", onClick: () => onRemove(file), "aria-label": "Remove " + file.name, children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
4658
+ uploading ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(Progress, { value: file.progress }) : null,
4659
+ file.error && onRetry ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("button", { type: "button", className: "fd-file-act", onClick: () => onRetry(file), "aria-label": "Retry upload of " + file.name, children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
4660
+ onRemove ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("button", { type: "button", className: "fd-file-act", onClick: () => onRemove(file), "aria-label": "Remove " + file.name, children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
4643
4661
  ] });
4644
4662
  }
4645
4663
  function FileTile({ file, onOpen, onRemove, maxHeight = 200, className = "" }) {
4646
4664
  if (!file) return null;
4647
4665
  const src = file.thumb && file.thumb.url || file.blobUrl || file.url;
4648
4666
  const uploading = file.progress != null && file.progress < 100 && !file.error;
4649
- return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("figure", { className: ["fd-tile", uploading ? "is-uploading" : "", file.error ? "is-error" : "", className].filter(Boolean).join(" "), children: [
4650
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("button", { type: "button", className: "fd-tile-btn", onClick: onOpen ? () => onOpen(file) : void 0, disabled: !onOpen, children: src ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("img", { src, alt: file.name || "", style: { maxHeight }, loading: "lazy" }) : /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("span", { className: "fd-tile-fallback", children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("i", { className: "ph ph-" + iconForMime(file.mime, file.name), "aria-hidden": "true" }) }) }),
4651
- uploading ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Progress, { value: file.progress }) : null,
4652
- file.error ? /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("figcaption", { className: "fd-tile-err", children: [
4653
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
4667
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("figure", { className: ["fd-tile", uploading ? "is-uploading" : "", file.error ? "is-error" : "", className].filter(Boolean).join(" "), children: [
4668
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("button", { type: "button", className: "fd-tile-btn", onClick: onOpen ? () => onOpen(file) : void 0, disabled: !onOpen, children: src ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("img", { src, alt: file.name || "", style: { maxHeight }, loading: "lazy" }) : /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "fd-tile-fallback", children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("i", { className: "ph ph-" + iconForMime(file.mime, file.name), "aria-hidden": "true" }) }) }),
4669
+ uploading ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(Progress, { value: file.progress }) : null,
4670
+ file.error ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("figcaption", { className: "fd-tile-err", children: [
4671
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
4654
4672
  file.error
4655
4673
  ] }) : null,
4656
- onRemove ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("button", { type: "button", className: "fd-tile-x", onClick: () => onRemove(file), "aria-label": "Remove " + file.name, children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
4674
+ onRemove ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("button", { type: "button", className: "fd-tile-x", onClick: () => onRemove(file), "aria-label": "Remove " + file.name, children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
4657
4675
  ] });
4658
4676
  }
4659
4677
  function FileStrip({ files = [], size = 68, onOpen, onRemove, onRetry, className = "" }) {
4660
4678
  const list = files.filter(Boolean);
4661
4679
  if (!list.length) return null;
4662
- return /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: ["fd-filestrip", "fd-scrollbar", className].filter(Boolean).join(" "), style: { "--fd-cell": size + "px" }, children: list.map((f) => /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(FileCell, { file: f, onOpen, onRemove, onRetry }, f.id || f.name)) });
4680
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: ["fd-filestrip", "fd-scrollbar", className].filter(Boolean).join(" "), style: { "--fd-cell": size + "px" }, children: list.map((f) => /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(FileCell, { file: f, onOpen, onRemove, onRetry }, f.id || f.name)) });
4663
4681
  }
4664
4682
  var shortName = (name, keep = 5) => {
4665
4683
  const s = String(name || "file");
@@ -4673,19 +4691,19 @@ function FileCell({ file, onOpen, onRemove, onRetry }) {
4673
4691
  const image = isImage(file.mime, file.name);
4674
4692
  const thumb = file.thumb && file.thumb.url || (image ? file.blobUrl || file.url : null);
4675
4693
  const label = file.name + (file.size ? " \xB7 " + formatBytes(file.size) : "");
4676
- return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: ["fd-cell", file.error ? "is-error" : "", uploading ? "is-uploading" : ""].filter(Boolean).join(" "), title: file.error ? file.name + " \u2014 " + file.error : label, children: [
4677
- /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("button", { type: "button", className: "fd-cell-main", onClick: onOpen ? () => onOpen(file) : void 0, disabled: !onOpen || uploading, "aria-label": "Open " + file.name, children: [
4678
- thumb ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("img", { src: thumb, alt: "" }) : /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("span", { className: "fd-cell-doc", children: [
4679
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("i", { className: "ph ph-" + iconForMime(file.mime, file.name), "aria-hidden": "true" }),
4680
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("span", { className: "fd-cell-name", children: shortName(file.name) }),
4681
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("span", { className: "fd-cell-size", children: file.meta || formatBytes(file.size) })
4694
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: ["fd-cell", file.error ? "is-error" : "", uploading ? "is-uploading" : ""].filter(Boolean).join(" "), title: file.error ? file.name + " \u2014 " + file.error : label, children: [
4695
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("button", { type: "button", className: "fd-cell-main", onClick: onOpen ? () => onOpen(file) : void 0, disabled: !onOpen || uploading, "aria-label": "Open " + file.name, children: [
4696
+ thumb ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("img", { src: thumb, alt: "" }) : /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("span", { className: "fd-cell-doc", children: [
4697
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("i", { className: "ph ph-" + iconForMime(file.mime, file.name), "aria-hidden": "true" }),
4698
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "fd-cell-name", children: shortName(file.name) }),
4699
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "fd-cell-size", children: file.meta || formatBytes(file.size) })
4682
4700
  ] }),
4683
- (file.mime || "").startsWith("video/") ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("i", { className: "ph ph-play fd-cell-play", "aria-hidden": "true" }) : null
4701
+ (file.mime || "").startsWith("video/") ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("i", { className: "ph ph-play fd-cell-play", "aria-hidden": "true" }) : null
4684
4702
  ] }),
4685
- uploading ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Progress, { value: file.progress }) : null,
4686
- file.error ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("span", { className: "fd-cell-err", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("i", { className: "ph ph-warning-circle" }) }) : null,
4687
- file.error && onRetry ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("button", { type: "button", className: "fd-cell-x is-retry", onClick: () => onRetry(file), "aria-label": "Retry upload of " + file.name, children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
4688
- onRemove ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("button", { type: "button", className: "fd-cell-x", onClick: () => onRemove(file), "aria-label": "Remove " + file.name, children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
4703
+ uploading ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(Progress, { value: file.progress }) : null,
4704
+ file.error ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "fd-cell-err", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("i", { className: "ph ph-warning-circle" }) }) : null,
4705
+ file.error && onRetry ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("button", { type: "button", className: "fd-cell-x is-retry", onClick: () => onRetry(file), "aria-label": "Retry upload of " + file.name, children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
4706
+ onRemove ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("button", { type: "button", className: "fd-cell-x", onClick: () => onRemove(file), "aria-label": "Remove " + file.name, children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
4689
4707
  ] });
4690
4708
  }
4691
4709
  function FileGrid({ files = [], onOpen, onRemove, onRetry, tiles = true, maxHeight = 200, compact: compact3 = false, className = "" }) {
@@ -4693,15 +4711,15 @@ function FileGrid({ files = [], onOpen, onRemove, onRetry, tiles = true, maxHeig
4693
4711
  if (!list.length) return null;
4694
4712
  const pics = tiles ? list.filter((f) => isImage(f.mime, f.name)) : [];
4695
4713
  const rest = list.filter((f) => pics.indexOf(f) === -1);
4696
- return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: ["fd-filegrid", className].filter(Boolean).join(" "), children: [
4697
- pics.length ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "fd-filegrid-tiles", children: pics.map((f) => /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(FileTile, { file: f, onOpen, onRemove, maxHeight }, f.id || f.name)) }) : null,
4698
- rest.length ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "fd-filegrid-chips", children: rest.map((f) => /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(FileChip, { file: f, onOpen, onRemove, onRetry, compact: compact3 }, f.id || f.name)) }) : null
4714
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: ["fd-filegrid", className].filter(Boolean).join(" "), children: [
4715
+ pics.length ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "fd-filegrid-tiles", children: pics.map((f) => /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(FileTile, { file: f, onOpen, onRemove, maxHeight }, f.id || f.name)) }) : null,
4716
+ rest.length ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "fd-filegrid-chips", children: rest.map((f) => /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(FileChip, { file: f, onOpen, onRemove, onRetry, compact: compact3 }, f.id || f.name)) }) : null
4699
4717
  ] });
4700
4718
  }
4701
4719
 
4702
4720
  // src/components/forms/MarkdownEditor.tsx
4703
- var React26 = __toESM(require("react"), 1);
4704
- var import_jsx_runtime56 = require("react/jsx-runtime");
4721
+ var React27 = __toESM(require("react"), 1);
4722
+ var import_jsx_runtime57 = require("react/jsx-runtime");
4705
4723
  var isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent || "");
4706
4724
  var INLINE_RE = /(\*\*\*[^*\n]+\*\*\*|\*\*[^*\n]+\*\*|__[^_\n]+__|~~[^~\n]+~~|`[^`\n]+`|\*[^*\s][^*\n]*\*|(?<![A-Za-z0-9_])_[^_\s][^_\n]*_|\[[^\]\n]*\]\([^)\s\n]*\)|https?:\/\/\S+)/g;
4707
4725
  function inlineParts(text) {
@@ -4914,7 +4932,7 @@ function syncDom(root, value) {
4914
4932
  while (root.children.length > lines.length) root.removeChild(root.lastChild);
4915
4933
  }
4916
4934
  var LIST_CONT = RE_LI;
4917
- var MarkdownEditor = React26.forwardRef(function MarkdownEditor2({
4935
+ var MarkdownEditor = React27.forwardRef(function MarkdownEditor2({
4918
4936
  value = "",
4919
4937
  onChange,
4920
4938
  onSubmit,
@@ -4933,10 +4951,10 @@ var MarkdownEditor = React26.forwardRef(function MarkdownEditor2({
4933
4951
  className = "",
4934
4952
  id
4935
4953
  }, ref) {
4936
- const boxRef = React26.useRef(null);
4937
- const composing = React26.useRef(false);
4938
- const pendingCaret = React26.useRef(null);
4939
- React26.useLayoutEffect(() => {
4954
+ const boxRef = React27.useRef(null);
4955
+ const composing = React27.useRef(false);
4956
+ const pendingCaret = React27.useRef(null);
4957
+ React27.useLayoutEffect(() => {
4940
4958
  const root = boxRef.current;
4941
4959
  if (!root || composing.current) return;
4942
4960
  const active = document.activeElement === root || root.contains(document.activeElement);
@@ -4945,7 +4963,7 @@ var MarkdownEditor = React26.forwardRef(function MarkdownEditor2({
4945
4963
  pendingCaret.current = null;
4946
4964
  if (active && caret != null) placeCaret(root, caret);
4947
4965
  }, [value]);
4948
- React26.useEffect(() => {
4966
+ React27.useEffect(() => {
4949
4967
  if (autoFocus && boxRef.current) boxRef.current.focus();
4950
4968
  }, [autoFocus]);
4951
4969
  const caretNow = () => {
@@ -5012,7 +5030,7 @@ var MarkdownEditor = React26.forwardRef(function MarkdownEditor2({
5012
5030
  api.replaceRange(from, to, next, from + next.length);
5013
5031
  }
5014
5032
  };
5015
- React26.useImperativeHandle(ref, () => api);
5033
+ React27.useImperativeHandle(ref, () => api);
5016
5034
  function detect(text, caret) {
5017
5035
  if (!onTrigger) return;
5018
5036
  const upto = text.slice(0, caret);
@@ -5125,8 +5143,8 @@ var MarkdownEditor = React26.forwardRef(function MarkdownEditor2({
5125
5143
  api.replaceRange(s.start, s.end, text.replace(/\r\n?/g, "\n"));
5126
5144
  };
5127
5145
  const lh = 1.55;
5128
- return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: ["fd-rme-wrap", disabled ? "is-disabled" : "", className].filter(Boolean).join(" "), children: [
5129
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
5146
+ return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: ["fd-rme-wrap", disabled ? "is-disabled" : "", className].filter(Boolean).join(" "), children: [
5147
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
5130
5148
  "div",
5131
5149
  {
5132
5150
  ref: boxRef,
@@ -5159,15 +5177,15 @@ var MarkdownEditor = React26.forwardRef(function MarkdownEditor2({
5159
5177
  }
5160
5178
  }
5161
5179
  ),
5162
- !value ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "fd-rme-ph", "aria-hidden": "true", children: placeholder }) : null
5180
+ !value ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "fd-rme-ph", "aria-hidden": "true", children: placeholder }) : null
5163
5181
  ] });
5164
5182
  });
5165
5183
 
5166
5184
  // src/components/platform/AccountMenu.tsx
5167
- var React28 = __toESM(require("react"), 1);
5185
+ var React29 = __toESM(require("react"), 1);
5168
5186
 
5169
5187
  // src/kits/session.ts
5170
- var React27 = __toESM(require("react"), 1);
5188
+ var React28 = __toESM(require("react"), 1);
5171
5189
  var PERMISSION_CATALOG = [
5172
5190
  { group: "Plans", items: [
5173
5191
  { key: "plan.view", label: "View plans", detail: "Read any plan in the workspace." },
@@ -6734,8 +6752,8 @@ function roadmap(overrides) {
6734
6752
  };
6735
6753
  }
6736
6754
  function useSession() {
6737
- const [s, setS] = React27.useState(getSession);
6738
- React27.useEffect(() => subscribe(setS), []);
6755
+ const [s, setS] = React28.useState(getSession);
6756
+ React28.useEffect(() => subscribe(setS), []);
6739
6757
  return s;
6740
6758
  }
6741
6759
  var SessionKit = {
@@ -6768,7 +6786,7 @@ var SessionKit = {
6768
6786
  };
6769
6787
 
6770
6788
  // src/components/platform/AccountMenu.tsx
6771
- var import_jsx_runtime57 = require("react/jsx-runtime");
6789
+ var import_jsx_runtime58 = require("react/jsx-runtime");
6772
6790
  var DEFAULT_LINKS = [
6773
6791
  { id: "profile", label: "Your profile", icon: "user-circle", href: "../admin/index.html#profile" },
6774
6792
  { id: "preferences", label: "Preferences", icon: "sliders-horizontal", href: "../admin/index.html#preferences" }
@@ -6779,7 +6797,7 @@ var DEFAULT_ADMIN_LINKS = [
6779
6797
  { id: "flags", label: "Feature flags", icon: "toggle-right", href: "../admin/index.html#flags", perm: "flags.manage" }
6780
6798
  ];
6781
6799
  function Item({ item, onPick }) {
6782
- return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(
6800
+ return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(
6783
6801
  "button",
6784
6802
  {
6785
6803
  type: "button",
@@ -6787,9 +6805,9 @@ function Item({ item, onPick }) {
6787
6805
  className: "fd-acct-item",
6788
6806
  onClick: () => onPick(item),
6789
6807
  children: [
6790
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("i", { className: "ph ph-" + item.icon, "aria-hidden": "true" }),
6791
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { style: { flex: 1 }, children: item.label }),
6792
- item.badge ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(Badge, { tone: "neutral", children: item.badge }) : null
6808
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("i", { className: "ph ph-" + item.icon, "aria-hidden": "true" }),
6809
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { style: { flex: 1 }, children: item.label }),
6810
+ item.badge ? /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(Badge, { tone: "neutral", children: item.badge }) : null
6793
6811
  ]
6794
6812
  }
6795
6813
  );
@@ -6805,9 +6823,9 @@ function AccountMenu({
6805
6823
  ...rest
6806
6824
  }) {
6807
6825
  const session = SessionKit.useSession();
6808
- const [open, setOpen] = React28.useState(false);
6809
- const [switching, setSwitching] = React28.useState(false);
6810
- const ref = React28.useRef(null);
6826
+ const [open, setOpen] = React29.useState(false);
6827
+ const [switching, setSwitching] = React29.useState(false);
6828
+ const ref = React29.useRef(null);
6811
6829
  const user = session.user;
6812
6830
  const visibleAdmin = adminLinks.filter((l) => !l.perm || SessionKit.can(l.perm));
6813
6831
  const pick = (item) => {
@@ -6821,8 +6839,8 @@ function AccountMenu({
6821
6839
  if (onSignOut) return onSignOut();
6822
6840
  window.alert("Signed out. (Simulated \u2014 no auth provider is wired up.)");
6823
6841
  };
6824
- return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(import_jsx_runtime57.Fragment, { children: [
6825
- /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(
6842
+ return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(import_jsx_runtime58.Fragment, { children: [
6843
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(
6826
6844
  "button",
6827
6845
  {
6828
6846
  type: "button",
@@ -6834,32 +6852,32 @@ function AccountMenu({
6834
6852
  onClick: () => setOpen((o) => !o),
6835
6853
  ...rest,
6836
6854
  children: [
6837
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(Avatar, { name: user.name, size: "sm" }),
6838
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("i", { className: "ph ph-caret-down", "aria-hidden": "true", style: { fontSize: 11, color: "var(--text-muted)" } })
6855
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(Avatar, { name: user.name, size: "sm" }),
6856
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("i", { className: "ph ph-caret-down", "aria-hidden": "true", style: { fontSize: 11, color: "var(--text-muted)" } })
6839
6857
  ]
6840
6858
  }
6841
6859
  ),
6842
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(Popover, { open, anchorRef: ref, onClose: () => setOpen(false), placement: "bottom-end", width: 272, children: /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { role: "menu", className: "fd-stack", style: { gap: 0 }, children: [
6843
- /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
6844
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(Avatar, { name: user.name }),
6845
- /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("span", { className: "fd-stack", style: { gap: 1, minWidth: 0, flex: 1 }, children: [
6846
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 700 }, children: user.name }),
6847
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "fd-body-sm fd-muted fd-table-trunc", children: user.email })
6860
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(Popover, { open, anchorRef: ref, onClose: () => setOpen(false), placement: "bottom-end", width: 272, children: /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { role: "menu", className: "fd-stack", style: { gap: 0 }, children: [
6861
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
6862
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(Avatar, { name: user.name }),
6863
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("span", { className: "fd-stack", style: { gap: 1, minWidth: 0, flex: 1 }, children: [
6864
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 700 }, children: user.name }),
6865
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "fd-body-sm fd-muted fd-table-trunc", children: user.email })
6848
6866
  ] })
6849
6867
  ] }),
6850
- showRoles && session.roles.length ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: "fd-row", style: { gap: 6, padding: "10px 14px", flexWrap: "wrap", borderBottom: "1px solid var(--border)" }, children: session.roles.map((r) => /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(Badge, { tone: r.id === "owner" ? "success" : "neutral", children: r.name }, r.id)) }) : null,
6851
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: "fd-acct-group", children: links.map((l) => /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(Item, { item: l, onPick: pick }, l.id)) }),
6852
- visibleAdmin.length ? /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: [
6853
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "fd-overline fd-muted", style: { padding: "8px 14px 4px", display: "block" }, children: "Administration" }),
6854
- visibleAdmin.map((l) => /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(Item, { item: l, onPick: pick }, l.id))
6868
+ showRoles && session.roles.length ? /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "fd-row", style: { gap: 6, padding: "10px 14px", flexWrap: "wrap", borderBottom: "1px solid var(--border)" }, children: session.roles.map((r) => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(Badge, { tone: r.id === "owner" ? "success" : "neutral", children: r.name }, r.id)) }) : null,
6869
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "fd-acct-group", children: links.map((l) => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(Item, { item: l, onPick: pick }, l.id)) }),
6870
+ visibleAdmin.length ? /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: [
6871
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "fd-overline fd-muted", style: { padding: "8px 14px 4px", display: "block" }, children: "Administration" }),
6872
+ visibleAdmin.map((l) => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(Item, { item: l, onPick: pick }, l.id))
6855
6873
  ] }) : null,
6856
- allowUserSwitch ? /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: [
6857
- /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("button", { type: "button", role: "menuitem", className: "fd-acct-item", onClick: () => setSwitching((s) => !s), children: [
6858
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("i", { className: "ph ph-user-switch", "aria-hidden": "true" }),
6859
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { style: { flex: 1 }, children: "View as another member" }),
6860
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("i", { className: "ph ph-caret-" + (switching ? "up" : "down"), "aria-hidden": "true", style: { fontSize: 11 } })
6874
+ allowUserSwitch ? /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: [
6875
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("button", { type: "button", role: "menuitem", className: "fd-acct-item", onClick: () => setSwitching((s) => !s), children: [
6876
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("i", { className: "ph ph-user-switch", "aria-hidden": "true" }),
6877
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { style: { flex: 1 }, children: "View as another member" }),
6878
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("i", { className: "ph ph-caret-" + (switching ? "up" : "down"), "aria-hidden": "true", style: { fontSize: 11 } })
6861
6879
  ] }),
6862
- switching ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: "fd-stack", style: { gap: 0, maxHeight: 208, overflowY: "auto" }, children: session.allUsers.filter((u) => u.status === "active").map((u) => /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(
6880
+ switching ? /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "fd-stack", style: { gap: 0, maxHeight: 208, overflowY: "auto" }, children: session.allUsers.filter((u) => u.status === "active").map((u) => /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(
6863
6881
  "button",
6864
6882
  {
6865
6883
  type: "button",
@@ -6871,34 +6889,34 @@ function AccountMenu({
6871
6889
  setSwitching(false);
6872
6890
  },
6873
6891
  children: [
6874
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(Avatar, { name: u.name, size: "sm" }),
6875
- /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("span", { className: "fd-stack", style: { gap: 0, flex: 1, minWidth: 0, alignItems: "flex-start" }, children: [
6876
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { style: { fontWeight: u.id === user.id ? 700 : 500 }, children: u.name }),
6877
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "fd-muted", style: { fontSize: 11.5 }, children: u.roles.join(", ") })
6892
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(Avatar, { name: u.name, size: "sm" }),
6893
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("span", { className: "fd-stack", style: { gap: 0, flex: 1, minWidth: 0, alignItems: "flex-start" }, children: [
6894
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { style: { fontWeight: u.id === user.id ? 700 : 500 }, children: u.name }),
6895
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "fd-muted", style: { fontSize: 11.5 }, children: u.roles.join(", ") })
6878
6896
  ] }),
6879
- u.id === user.id ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("i", { className: "ph ph-check", "aria-hidden": "true", style: { color: "var(--ok-text)" } }) : null
6897
+ u.id === user.id ? /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("i", { className: "ph ph-check", "aria-hidden": "true", style: { color: "var(--ok-text)" } }) : null
6880
6898
  ]
6881
6899
  },
6882
6900
  u.id
6883
6901
  )) }) : null
6884
6902
  ] }) : null,
6885
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("button", { type: "button", role: "menuitem", className: "fd-acct-item", "data-danger": "true", onClick: signOut, children: [
6886
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("i", { className: "ph ph-sign-out", "aria-hidden": "true" }),
6887
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { style: { flex: 1 }, children: "Sign out" })
6903
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("button", { type: "button", role: "menuitem", className: "fd-acct-item", "data-danger": "true", onClick: signOut, children: [
6904
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("i", { className: "ph ph-sign-out", "aria-hidden": "true" }),
6905
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { style: { flex: 1 }, children: "Sign out" })
6888
6906
  ] }) })
6889
6907
  ] }) })
6890
6908
  ] });
6891
6909
  }
6892
6910
 
6893
6911
  // src/components/platform/ApiSpecBrowser.tsx
6894
- var React29 = __toESM(require("react"), 1);
6895
- var import_jsx_runtime58 = require("react/jsx-runtime");
6912
+ var React30 = __toESM(require("react"), 1);
6913
+ var import_jsx_runtime59 = require("react/jsx-runtime");
6896
6914
  var METHOD_TONE = { GET: "success", POST: "info", PATCH: "warning", PUT: "warning", DELETE: "danger" };
6897
6915
  function Json({ obj }) {
6898
- return /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("pre", { className: "fd-json", children: JSON.stringify(obj, null, 2) });
6916
+ return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("pre", { className: "fd-json", children: JSON.stringify(obj, null, 2) });
6899
6917
  }
6900
6918
  function Endpoint({ s, onRequest }) {
6901
- const [tried, setTried] = React29.useState(null);
6919
+ const [tried, setTried] = React30.useState(null);
6902
6920
  const run = async () => {
6903
6921
  setTried("busy");
6904
6922
  const t0 = (window.performance || Date).now();
@@ -6909,50 +6927,50 @@ function Endpoint({ s, onRequest }) {
6909
6927
  setTried({ ms: Math.round((window.performance || Date).now() - t0), error: String(e && e.message || e) });
6910
6928
  }
6911
6929
  };
6912
- return /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(Card, { elevation: "flat", padded: false, children: /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "fd-stack", style: { gap: 0 }, children: [
6913
- /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "fd-row", style: { gap: 10, padding: "14px 18px", flexWrap: "wrap" }, children: [
6914
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(Badge, { tone: METHOD_TONE[s.method] || "neutral", children: s.method }),
6915
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("code", { className: "fd-mono", style: { fontSize: 12.5, fontWeight: 600, color: "var(--text)", wordBreak: "break-all" }, children: s.path }),
6916
- s.isList ? /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(Badge, { tone: "neutral", icon: "rows", children: "Paged list" }) : null,
6917
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { style: { flex: 1 } }),
6918
- /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
6930
+ return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Card, { elevation: "flat", padded: false, children: /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "fd-stack", style: { gap: 0 }, children: [
6931
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "fd-row", style: { gap: 10, padding: "14px 18px", flexWrap: "wrap" }, children: [
6932
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Badge, { tone: METHOD_TONE[s.method] || "neutral", children: s.method }),
6933
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("code", { className: "fd-mono", style: { fontSize: 12.5, fontWeight: 600, color: "var(--text)", wordBreak: "break-all" }, children: s.path }),
6934
+ s.isList ? /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Badge, { tone: "neutral", icon: "rows", children: "Paged list" }) : null,
6935
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { style: { flex: 1 } }),
6936
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
6919
6937
  s.latency[0],
6920
6938
  "\u2013",
6921
6939
  s.latency[1],
6922
6940
  "ms"
6923
6941
  ] }),
6924
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(Button, { size: "sm", variant: "secondary", icon: "play", loading: tried === "busy", onClick: run, children: "Try it" })
6942
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Button, { size: "sm", variant: "secondary", icon: "play", loading: tried === "busy", onClick: run, children: "Try it" })
6925
6943
  ] }),
6926
- /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "fd-stack", style: { gap: 14, padding: "0 18px 16px" }, children: [
6927
- /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
6928
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 700 }, children: s.title }),
6929
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: s.purpose }),
6930
- s.usedBy && s.usedBy.length ? /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: s.usedBy.map((u) => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(Tag, { children: u }, u)) }) : null
6944
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "fd-stack", style: { gap: 14, padding: "0 18px 16px" }, children: [
6945
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
6946
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 700 }, children: s.title }),
6947
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: s.purpose }),
6948
+ s.usedBy && s.usedBy.length ? /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: s.usedBy.map((u) => /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Tag, { children: u }, u)) }) : null
6931
6949
  ] }),
6932
- /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(280px,1fr))", gap: 12, alignItems: "start" }, children: [
6933
- s.request ? /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
6934
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "fd-overline fd-muted", children: "Request body" }),
6935
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(Json, { obj: s.request })
6950
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(280px,1fr))", gap: 12, alignItems: "start" }, children: [
6951
+ s.request ? /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
6952
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "fd-overline fd-muted", children: "Request body" }),
6953
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Json, { obj: s.request })
6936
6954
  ] }) : null,
6937
- s.query ? /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
6938
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "fd-overline fd-muted", children: "Query" }),
6939
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(Json, { obj: s.query })
6955
+ s.query ? /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
6956
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "fd-overline fd-muted", children: "Query" }),
6957
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Json, { obj: s.query })
6940
6958
  ] }) : null,
6941
- /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
6942
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "fd-overline fd-muted", children: "Response 200" }),
6943
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(Json, { obj: s.response })
6959
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
6960
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "fd-overline fd-muted", children: "Response 200" }),
6961
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Json, { obj: s.response })
6944
6962
  ] })
6945
6963
  ] }),
6946
- s.notes ? /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(Flag, { tone: "info", statement: "Implementation note", cost: s.notes, actions: null }) : null,
6947
- tried && tried !== "busy" ? /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
6948
- /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("span", { className: "fd-row", style: { gap: 8 }, children: [
6949
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "fd-overline fd-muted", children: "Simulated response" }),
6950
- /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(Badge, { tone: tried.error ? "danger" : "success", icon: "timer", children: [
6964
+ s.notes ? /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Flag, { tone: "info", statement: "Implementation note", cost: s.notes, actions: null }) : null,
6965
+ tried && tried !== "busy" ? /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
6966
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("span", { className: "fd-row", style: { gap: 8 }, children: [
6967
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "fd-overline fd-muted", children: "Simulated response" }),
6968
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(Badge, { tone: tried.error ? "danger" : "success", icon: "timer", children: [
6951
6969
  tried.ms,
6952
6970
  "ms"
6953
6971
  ] })
6954
6972
  ] }),
6955
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(Json, { obj: tried.error ? { error: tried.error } : tried.data })
6973
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Json, { obj: tried.error ? { error: tried.error } : tried.data })
6956
6974
  ] }) : null
6957
6975
  ] })
6958
6976
  ] }) });
@@ -6971,58 +6989,58 @@ function ApiSpecBrowser({
6971
6989
  className = "",
6972
6990
  ...rest
6973
6991
  }) {
6974
- const [q, setQ] = React29.useState("");
6975
- const [method, setMethod] = React29.useState(null);
6976
- const [mod, setMod] = React29.useState(null);
6977
- const [listOnly, setListOnly] = React29.useState(false);
6992
+ const [q, setQ] = React30.useState("");
6993
+ const [method, setMethod] = React30.useState(null);
6994
+ const [mod, setMod] = React30.useState(null);
6995
+ const [listOnly, setListOnly] = React30.useState(false);
6978
6996
  const activeModule = modules && modules.find((m) => m.id === mod);
6979
6997
  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())));
6980
6998
  const effGroups = groups && groups.length ? groups : [["All endpoints", spec.map((s) => s.id)]];
6981
6999
  const methods = [...new Set(spec.map((s) => s.method))];
6982
7000
  const listCount = spec.filter((s) => s.isList).length;
6983
- return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 1100 }, ...rest, children: [
6984
- /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
6985
- kicker ? /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "fd-overline fd-muted", children: kicker }) : null,
6986
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
6987
- lede ? /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: lede }) : null
7001
+ return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 1100 }, ...rest, children: [
7002
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
7003
+ kicker ? /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "fd-overline fd-muted", children: kicker }) : null,
7004
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
7005
+ lede ? /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: lede }) : null
6988
7006
  ] }),
6989
- modules && modules.length ? /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "fd-stack", style: { gap: 8 }, children: [
6990
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "fd-overline fd-muted", children: "Filter by screen \u2014 every endpoint that screen depends on" }),
6991
- /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
6992
- /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(Tag, { icon: "stack", selected: !mod, onClick: () => setMod(null), children: [
7007
+ modules && modules.length ? /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "fd-stack", style: { gap: 8 }, children: [
7008
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "fd-overline fd-muted", children: "Filter by screen \u2014 every endpoint that screen depends on" }),
7009
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
7010
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(Tag, { icon: "stack", selected: !mod, onClick: () => setMod(null), children: [
6993
7011
  "All screens ",
6994
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "fd-mono", children: spec.length })
7012
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "fd-mono", children: spec.length })
6995
7013
  ] }),
6996
- modules.map((m) => /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(Tag, { icon: m.icon, selected: mod === m.id, onClick: () => setMod(mod === m.id ? null : m.id), children: [
7014
+ modules.map((m) => /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(Tag, { icon: m.icon, selected: mod === m.id, onClick: () => setMod(mod === m.id ? null : m.id), children: [
6997
7015
  m.label,
6998
7016
  " ",
6999
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "fd-mono", children: m.endpoints.length })
7017
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "fd-mono", children: m.endpoints.length })
7000
7018
  ] }, m.id))
7001
7019
  ] }),
7002
- activeModule ? /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
7020
+ activeModule ? /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
7003
7021
  Flag,
7004
7022
  {
7005
7023
  tone: "info",
7006
7024
  statement: activeModule.label + " calls " + activeModule.endpoints.length + " endpoints.",
7007
7025
  cost: "Integration checklist for this screen: " + activeModule.endpoints.join(", ") + ". Wire these and the screen is done.",
7008
- actions: /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(Button, { size: "sm", variant: "ghost", icon: "x", onClick: () => setMod(null), children: "Show all screens" })
7026
+ actions: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Button, { size: "sm", variant: "ghost", icon: "x", onClick: () => setMod(null), children: "Show all screens" })
7009
7027
  }
7010
7028
  ) : null
7011
7029
  ] }) : null,
7012
- sourceNote ? /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(Flag, { tone: "info", statement: "Design-first: this page is the spec.", cost: sourceNote, actions: null }) : null,
7013
- /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
7014
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(Input, { icon: "magnifying-glass", placeholder: "Find an endpoint, screen, or behavior", value: q, onChange: (e) => setQ(e.target.value), style: { width: 300 } }),
7015
- methods.map((m) => /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(Tag, { selected: method === m, onClick: () => setMethod(method === m ? null : m), children: [
7030
+ sourceNote ? /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Flag, { tone: "info", statement: "Design-first: this page is the spec.", cost: sourceNote, actions: null }) : null,
7031
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
7032
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Input, { icon: "magnifying-glass", placeholder: "Find an endpoint, screen, or behavior", value: q, onChange: (e) => setQ(e.target.value), style: { width: 300 } }),
7033
+ methods.map((m) => /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(Tag, { selected: method === m, onClick: () => setMethod(method === m ? null : m), children: [
7016
7034
  m,
7017
7035
  " ",
7018
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "fd-mono", children: spec.filter((s) => s.method === m).length })
7036
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "fd-mono", children: spec.filter((s) => s.method === m).length })
7019
7037
  ] }, m)),
7020
- listCount ? /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(Tag, { icon: "rows", selected: listOnly, onClick: () => setListOnly(!listOnly), children: [
7038
+ listCount ? /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(Tag, { icon: "rows", selected: listOnly, onClick: () => setListOnly(!listOnly), children: [
7021
7039
  "Paged lists ",
7022
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "fd-mono", children: listCount })
7040
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "fd-mono", children: listCount })
7023
7041
  ] }) : null,
7024
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { style: { flex: 1 } }),
7025
- /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
7042
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { style: { flex: 1 } }),
7043
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
7026
7044
  hits.length,
7027
7045
  " of ",
7028
7046
  spec.length,
@@ -7030,31 +7048,31 @@ function ApiSpecBrowser({
7030
7048
  listCount ? " \xB7 " + listCount + " paged" : ""
7031
7049
  ] })
7032
7050
  ] }),
7033
- hits.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(Card, { elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: "No endpoint matches those filters." }) }) : effGroups.map(([g, ids]) => {
7051
+ hits.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Card, { elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: "No endpoint matches those filters." }) }) : effGroups.map(([g, ids]) => {
7034
7052
  const items = hits.filter((s) => ids.indexOf(s.id) >= 0);
7035
7053
  if (!items.length) return null;
7036
- return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "fd-stack", style: { gap: 12 }, children: [
7037
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "fd-label-lg", children: g }),
7038
- items.map((s) => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(Endpoint, { s, onRequest }, s.id))
7054
+ return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "fd-stack", style: { gap: 12 }, children: [
7055
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "fd-label-lg", children: g }),
7056
+ items.map((s) => /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Endpoint, { s, onRequest }, s.id))
7039
7057
  ] }, g);
7040
7058
  }),
7041
- conventions && conventions.length ? /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(Card, { title: "Cross-cutting conventions", elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "fd-stack", style: { gap: 10 }, children: conventions.map(([k, v]) => /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "fd-row", style: { gap: 12, alignItems: "flex-start" }, children: [
7042
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "fd-overline fd-muted", style: { width: 110, flex: "none", paddingTop: 2 }, children: k }),
7043
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: v })
7059
+ conventions && conventions.length ? /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Card, { title: "Cross-cutting conventions", elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("div", { className: "fd-stack", style: { gap: 10 }, children: conventions.map(([k, v]) => /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "fd-row", style: { gap: 12, alignItems: "flex-start" }, children: [
7060
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "fd-overline fd-muted", style: { width: 110, flex: "none", paddingTop: 2 }, children: k }),
7061
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: v })
7044
7062
  ] }, k)) }) }) : null,
7045
- openQuestions && openQuestions.length ? /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(Collapsible, { icon: "list-checks", title: "Open questions before implementation", subtitle: openQuestions.length + " unresolved", children: /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "fd-stack", style: { gap: 8 }, children: openQuestions.map(([id, question, why]) => /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start", padding: "8px 0", borderTop: "1px solid var(--border)" }, children: [
7046
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(Badge, { tone: "danger", children: id }),
7047
- /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("span", { className: "fd-stack", style: { gap: 2, flex: 1 }, children: [
7048
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: question }),
7049
- /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "fd-body-sm fd-muted", children: why })
7063
+ openQuestions && openQuestions.length ? /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Collapsible, { icon: "list-checks", title: "Open questions before implementation", subtitle: openQuestions.length + " unresolved", children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("div", { className: "fd-stack", style: { gap: 8 }, children: openQuestions.map(([id, question, why]) => /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start", padding: "8px 0", borderTop: "1px solid var(--border)" }, children: [
7064
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Badge, { tone: "danger", children: id }),
7065
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("span", { className: "fd-stack", style: { gap: 2, flex: 1 }, children: [
7066
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: question }),
7067
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "fd-body-sm fd-muted", children: why })
7050
7068
  ] })
7051
7069
  ] }, id)) }) }) : null
7052
7070
  ] });
7053
7071
  }
7054
7072
 
7055
7073
  // src/components/platform/ProfilePage.tsx
7056
- var React30 = __toESM(require("react"), 1);
7057
- var import_jsx_runtime59 = require("react/jsx-runtime");
7074
+ var React31 = __toESM(require("react"), 1);
7075
+ var import_jsx_runtime60 = require("react/jsx-runtime");
7058
7076
  var TIMEZONES = ["America/New_York", "America/Chicago", "America/Denver", "America/Los_Angeles", "America/Anchorage", "Pacific/Honolulu", "Europe/London", "Europe/Berlin"];
7059
7077
  var NOTIFY = [
7060
7078
  { key: "planShared", label: "A plan is shared with me", detail: "Someone sends you a plan or a client link." },
@@ -7066,7 +7084,7 @@ var NOTIFY = [
7066
7084
  function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSessions = true, className = "", ...rest }) {
7067
7085
  const session = SessionKit.useSession();
7068
7086
  const user = userProp || session.user;
7069
- const [draft, setDraft] = React30.useState(() => ({
7087
+ const [draft, setDraft] = React31.useState(() => ({
7070
7088
  name: user.name || "",
7071
7089
  title: user.title || "",
7072
7090
  email: user.email || "",
@@ -7075,8 +7093,8 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
7075
7093
  bio: user.bio || "",
7076
7094
  notify: user.notify || { planShared: true, planChanged: true, goalMissed: true, flagChanged: false, weekly: true }
7077
7095
  }));
7078
- const [saving, setSaving] = React30.useState(false);
7079
- const [saved, setSaved] = React30.useState(false);
7096
+ const [saving, setSaving] = React31.useState(false);
7097
+ const [saved, setSaved] = React31.useState(false);
7080
7098
  const set = (k, v) => {
7081
7099
  setDraft((d) => Object.assign({}, d, { [k]: v }));
7082
7100
  setSaved(false);
@@ -7098,43 +7116,43 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
7098
7116
  { id: "s2", device: "iPhone 15 \xB7 Safari", where: "Denver, CO", when: "2 hours ago" },
7099
7117
  { id: "s3", device: "Windows \xB7 Edge", where: "Chicago, IL", when: "Aug 12" }
7100
7118
  ];
7101
- return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 860 }, ...rest, children: [
7102
- /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
7103
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "fd-overline fd-muted", children: "Account" }),
7104
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("h1", { className: "fd-h1", style: { margin: 0 }, children: "Your profile" }),
7105
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: "How you appear to colleagues and clients across every flytedesk app, and what we send you." })
7119
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 860 }, ...rest, children: [
7120
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
7121
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "fd-overline fd-muted", children: "Account" }),
7122
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("h1", { className: "fd-h1", style: { margin: 0 }, children: "Your profile" }),
7123
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: "How you appear to colleagues and clients across every flytedesk app, and what we send you." })
7106
7124
  ] }),
7107
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Card, { elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "fd-row", style: { gap: 16, flexWrap: "wrap", alignItems: "flex-start" }, children: [
7108
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Avatar, { name: draft.name || user.name, size: "lg" }),
7109
- /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "fd-stack", style: { gap: 4, flex: 1, minWidth: 200 }, children: [
7110
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "fd-h3", style: { margin: 0 }, children: draft.name || user.name }),
7111
- /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
7125
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Card, { elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "fd-row", style: { gap: 16, flexWrap: "wrap", alignItems: "flex-start" }, children: [
7126
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Avatar, { name: draft.name || user.name, size: "lg" }),
7127
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "fd-stack", style: { gap: 4, flex: 1, minWidth: 200 }, children: [
7128
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "fd-h3", style: { margin: 0 }, children: draft.name || user.name }),
7129
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
7112
7130
  draft.title || "No title set",
7113
7131
  " \xB7 ",
7114
7132
  user.team || "No team"
7115
7133
  ] }),
7116
- /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 4 }, children: [
7117
- session.roles.map((r) => /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Badge, { tone: r.id === "owner" ? "success" : "neutral", children: r.name }, r.id)),
7118
- user.sso ? /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Badge, { tone: "info", icon: "shield-check", children: "SSO" }) : null
7134
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 4 }, children: [
7135
+ session.roles.map((r) => /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Badge, { tone: r.id === "owner" ? "success" : "neutral", children: r.name }, r.id)),
7136
+ user.sso ? /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Badge, { tone: "info", icon: "shield-check", children: "SSO" }) : null
7119
7137
  ] })
7120
7138
  ] }),
7121
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Button, { variant: "secondary", size: "sm", icon: "image", children: "Change photo" })
7139
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Button, { variant: "secondary", size: "sm", icon: "image", children: "Change photo" })
7122
7140
  ] }) }),
7123
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
7141
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
7124
7142
  Card,
7125
7143
  {
7126
- title: /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("span", { className: "fd-stack", style: { gap: 2 }, children: [
7127
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { children: "Identity" }),
7128
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "Name and title appear on plans you share" })
7144
+ title: /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("span", { className: "fd-stack", style: { gap: 2 }, children: [
7145
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { children: "Identity" }),
7146
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "Name and title appear on plans you share" })
7129
7147
  ] }),
7130
7148
  elevation: "flat",
7131
- children: /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "fd-stack", style: { gap: 14 }, children: [
7132
- /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: [
7133
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Input, { label: "Full name", value: draft.name, onChange: (e) => set("name", e.target.value) }),
7134
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Input, { label: "Job title", value: draft.title, onChange: (e) => set("title", e.target.value), placeholder: "e.g. Senior media planner" })
7149
+ children: /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "fd-stack", style: { gap: 14 }, children: [
7150
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: [
7151
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Input, { label: "Full name", value: draft.name, onChange: (e) => set("name", e.target.value) }),
7152
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Input, { label: "Job title", value: draft.title, onChange: (e) => set("title", e.target.value), placeholder: "e.g. Senior media planner" })
7135
7153
  ] }),
7136
- /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: [
7137
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
7154
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: [
7155
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
7138
7156
  Input,
7139
7157
  {
7140
7158
  label: "Work email",
@@ -7144,9 +7162,9 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
7144
7162
  help: user.sso ? "Managed by your identity provider \u2014 change it there." : "Contact an administrator to change this."
7145
7163
  }
7146
7164
  ),
7147
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Input, { label: "Phone", value: draft.phone, onChange: (e) => set("phone", e.target.value), placeholder: "Optional" })
7165
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Input, { label: "Phone", value: draft.phone, onChange: (e) => set("phone", e.target.value), placeholder: "Optional" })
7148
7166
  ] }),
7149
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
7167
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
7150
7168
  Textarea,
7151
7169
  {
7152
7170
  label: "Short bio",
@@ -7160,8 +7178,8 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
7160
7178
  ] })
7161
7179
  }
7162
7180
  ),
7163
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Card, { title: "Working preferences", elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: [
7164
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
7181
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Card, { title: "Working preferences", elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: [
7182
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
7165
7183
  Select,
7166
7184
  {
7167
7185
  label: "Time zone",
@@ -7171,28 +7189,28 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
7171
7189
  help: "Flight dates and schedules render in this zone."
7172
7190
  }
7173
7191
  ),
7174
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Select, { label: "Start of week", options: ["Monday", "Sunday"], placeholder: "Monday" })
7192
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Select, { label: "Start of week", options: ["Monday", "Sunday"], placeholder: "Monday" })
7175
7193
  ] }) }),
7176
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
7194
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
7177
7195
  Card,
7178
7196
  {
7179
- title: /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("span", { className: "fd-stack", style: { gap: 2 }, children: [
7180
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { children: "Notifications" }),
7181
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "Email only for now \u2014 in-app notifications are on the roadmap" })
7197
+ title: /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("span", { className: "fd-stack", style: { gap: 2 }, children: [
7198
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { children: "Notifications" }),
7199
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "Email only for now \u2014 in-app notifications are on the roadmap" })
7182
7200
  ] }),
7183
7201
  elevation: "flat",
7184
- children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("div", { className: "fd-stack", style: { gap: 14 }, children: NOTIFY.map((n) => /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Switch, { checked: !!draft.notify[n.key], onChange: () => setNotify(n.key), label: n.label, description: n.detail }, n.key)) })
7202
+ children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { className: "fd-stack", style: { gap: 14 }, children: NOTIFY.map((n) => /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Switch, { checked: !!draft.notify[n.key], onChange: () => setNotify(n.key), label: n.label, description: n.detail }, n.key)) })
7185
7203
  }
7186
7204
  ),
7187
- /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(
7205
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(
7188
7206
  Card,
7189
7207
  {
7190
- title: /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("span", { className: "fd-stack", style: { gap: 2 }, children: [
7191
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { children: "Access" }),
7192
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "What your roles grant you" })
7208
+ title: /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("span", { className: "fd-stack", style: { gap: 2 }, children: [
7209
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { children: "Access" }),
7210
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "What your roles grant you" })
7193
7211
  ] }),
7194
7212
  elevation: "flat",
7195
- action: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
7213
+ action: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
7196
7214
  Button,
7197
7215
  {
7198
7216
  size: "sm",
@@ -7203,39 +7221,39 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
7203
7221
  }
7204
7222
  ),
7205
7223
  children: [
7206
- /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "fd-stack", style: { gap: 0 }, children: [
7207
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(CardRow, { label: "Roles", children: session.roles.map((r) => r.name).join(", ") || "None" }),
7208
- /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(CardRow, { label: "Permissions", children: [
7224
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "fd-stack", style: { gap: 0 }, children: [
7225
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(CardRow, { label: "Roles", children: session.roles.map((r) => r.name).join(", ") || "None" }),
7226
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(CardRow, { label: "Permissions", children: [
7209
7227
  session.permissions.length,
7210
7228
  " granted"
7211
7229
  ] }),
7212
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(CardRow, { label: "Member since", children: user.joined || "\u2014" })
7230
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(CardRow, { label: "Member since", children: user.joined || "\u2014" })
7213
7231
  ] }),
7214
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("p", { className: "fd-body-sm fd-muted", style: { margin: "12px 0 0" }, children: "You cannot change your own roles \u2014 that is the point of them. An administrator manages roles from Admin \u2192 Users." })
7232
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("p", { className: "fd-body-sm fd-muted", style: { margin: "12px 0 0" }, children: "You cannot change your own roles \u2014 that is the point of them. An administrator manages roles from Admin \u2192 Users." })
7215
7233
  ]
7216
7234
  }
7217
7235
  ),
7218
- showSessions ? /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
7236
+ showSessions ? /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
7219
7237
  Card,
7220
7238
  {
7221
7239
  title: "Signed-in devices",
7222
7240
  elevation: "flat",
7223
- action: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Button, { size: "sm", variant: "ghost", icon: "sign-out", children: "Sign out everywhere" }),
7224
- children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("div", { className: "fd-stack", style: { gap: 0 }, children: liveSessions.map((s) => /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "fd-row", style: { gap: 12, padding: "10px 0", borderTop: "1px solid var(--border)", flexWrap: "wrap" }, children: [
7225
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("i", { className: "ph ph-device-mobile", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
7226
- /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("span", { className: "fd-stack", style: { gap: 1, flex: 1, minWidth: 160 }, children: [
7227
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: s.device }),
7228
- /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
7241
+ action: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Button, { size: "sm", variant: "ghost", icon: "sign-out", children: "Sign out everywhere" }),
7242
+ children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { className: "fd-stack", style: { gap: 0 }, children: liveSessions.map((s) => /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "fd-row", style: { gap: 12, padding: "10px 0", borderTop: "1px solid var(--border)", flexWrap: "wrap" }, children: [
7243
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("i", { className: "ph ph-device-mobile", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
7244
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("span", { className: "fd-stack", style: { gap: 1, flex: 1, minWidth: 160 }, children: [
7245
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: s.device }),
7246
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
7229
7247
  s.where,
7230
7248
  " \xB7 ",
7231
7249
  s.when
7232
7250
  ] })
7233
7251
  ] }),
7234
- s.current ? /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Badge, { tone: "success", dot: true, children: "This device" }) : /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Button, { size: "sm", variant: "ghost", children: "Revoke" })
7252
+ s.current ? /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Badge, { tone: "success", dot: true, children: "This device" }) : /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Button, { size: "sm", variant: "ghost", children: "Revoke" })
7235
7253
  ] }, s.id)) })
7236
7254
  }
7237
7255
  ) : null,
7238
- /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "fd-row", style: {
7256
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "fd-row", style: {
7239
7257
  gap: 10,
7240
7258
  flexWrap: "wrap",
7241
7259
  position: "sticky",
@@ -7246,8 +7264,8 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
7246
7264
  border: "1px solid var(--border)",
7247
7265
  boxShadow: "0 -4px 16px rgba(11,13,17,.06)"
7248
7266
  }, children: [
7249
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 600, flex: 1 }, children: saved ? "Saved." : dirty ? "Unsaved changes" : "No pending changes" }),
7250
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
7267
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 600, flex: 1 }, children: saved ? "Saved." : dirty ? "Unsaved changes" : "No pending changes" }),
7268
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
7251
7269
  Button,
7252
7270
  {
7253
7271
  size: "sm",
@@ -7260,16 +7278,16 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
7260
7278
  children: "Discard"
7261
7279
  }
7262
7280
  ),
7263
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Button, { size: "sm", icon: "check", disabled: !dirty, loading: saving, onClick: save, children: "Save changes" })
7281
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Button, { size: "sm", icon: "check", disabled: !dirty, loading: saving, onClick: save, children: "Save changes" })
7264
7282
  ] })
7265
7283
  ] });
7266
7284
  }
7267
7285
 
7268
7286
  // src/components/platform/RoadmapTimeline.tsx
7269
- var React32 = __toESM(require("react"), 1);
7287
+ var React33 = __toESM(require("react"), 1);
7270
7288
 
7271
7289
  // src/kits/runtime.ts
7272
- var React31 = __toESM(require("react"), 1);
7290
+ var React32 = __toESM(require("react"), 1);
7273
7291
  var WIRED_ENDPOINTS = [
7274
7292
  // Nothing yet. Every id below would come from a real service:
7275
7293
  // "plan.get", "placements.list", …
@@ -7440,8 +7458,8 @@ var RuntimeKit = {
7440
7458
  };
7441
7459
  RuntimeKit.declare(FEATURE_NEEDS);
7442
7460
  function useRuntimeMode() {
7443
- const [m, setM] = React31.useState(RuntimeKit.getMode());
7444
- React31.useEffect(() => RuntimeKit.subscribe(setM), []);
7461
+ const [m, setM] = React32.useState(RuntimeKit.getMode());
7462
+ React32.useEffect(() => RuntimeKit.subscribe(setM), []);
7445
7463
  return m;
7446
7464
  }
7447
7465
  function useFeatureStatus(key) {
@@ -7460,7 +7478,7 @@ var UseRuntimeMode = useRuntimeMode;
7460
7478
  var UseFeatureStatus = useFeatureStatus;
7461
7479
 
7462
7480
  // src/components/platform/RoadmapTimeline.tsx
7463
- var import_jsx_runtime60 = require("react/jsx-runtime");
7481
+ var import_jsx_runtime61 = require("react/jsx-runtime");
7464
7482
  var STATUS = {
7465
7483
  shipped: { tone: "success", icon: "check-circle", label: "Wired" },
7466
7484
  next: { tone: "warning", icon: "traffic-cone", label: "Not wired" },
@@ -7475,45 +7493,45 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
7475
7493
  const s = STATUS[item.status] || STATUS.planned;
7476
7494
  const deps = (item.dependsOn || []).map((k) => byKey[k]).filter(Boolean);
7477
7495
  const blocking = deps.filter((d) => !d.implemented);
7478
- return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Card, { elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
7479
- /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
7480
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "fd-body", style: { fontWeight: 700, flex: 1, minWidth: 140 }, children: item.label }),
7481
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Badge, { tone: "neutral", icon: PROJECT_ICON[item.project] || "squares-four", children: item.project }),
7482
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Badge, { tone: s.tone, icon: s.icon, children: s.label })
7496
+ return /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(Card, { elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
7497
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
7498
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "fd-body", style: { fontWeight: 700, flex: 1, minWidth: 140 }, children: item.label }),
7499
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(Badge, { tone: "neutral", icon: PROJECT_ICON[item.project] || "squares-four", children: item.project }),
7500
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(Badge, { tone: s.tone, icon: s.icon, children: s.label })
7483
7501
  ] }),
7484
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: item.description }),
7485
- item.backend ? /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start" }, children: [
7486
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "fd-overline fd-muted", style: { width: 62, flex: "none", paddingTop: 2 }, children: "Backend" }),
7487
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "fd-body-sm", style: { flex: 1, textWrap: "pretty" }, children: item.backend })
7502
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: item.description }),
7503
+ item.backend ? /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start" }, children: [
7504
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "fd-overline fd-muted", style: { width: 62, flex: "none", paddingTop: 2 }, children: "Backend" }),
7505
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "fd-body-sm", style: { flex: 1, textWrap: "pretty" }, children: item.backend })
7488
7506
  ] }) : null,
7489
- /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
7490
- item.effort ? /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
7491
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("i", { className: "ph ph-hourglass-medium" }),
7507
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
7508
+ item.effort ? /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
7509
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("i", { className: "ph ph-hourglass-medium" }),
7492
7510
  " ",
7493
7511
  item.effort
7494
7512
  ] }) : null,
7495
- /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
7496
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("i", { className: "ph ph-user" }),
7513
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
7514
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("i", { className: "ph ph-user" }),
7497
7515
  " ",
7498
7516
  item.owner
7499
7517
  ] }),
7500
- item.screen ? /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Badge, { tone: "neutral", icon: "browser", children: "screen" }) : null,
7501
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { style: { flex: 1 } }),
7502
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
7518
+ item.screen ? /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(Badge, { tone: "neutral", icon: "browser", children: "screen" }) : null,
7519
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { style: { flex: 1 } }),
7520
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
7503
7521
  "button",
7504
7522
  {
7505
7523
  type: "button",
7506
7524
  onClick: () => onOpenFlag && onOpenFlag(item.key),
7507
7525
  style: { all: "unset", cursor: "pointer", display: "inline-flex", alignItems: "center", gap: 5 },
7508
- children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("code", { className: "fd-mono", style: { fontSize: 11, color: "var(--brand)" }, children: item.key })
7526
+ children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("code", { className: "fd-mono", style: { fontSize: 11, color: "var(--brand)" }, children: item.key })
7509
7527
  }
7510
7528
  )
7511
7529
  ] }),
7512
- deps.length ? /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 6, borderTop: "1px solid var(--border)" }, children: [
7513
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "fd-overline fd-muted", style: { paddingTop: 3 }, children: "After" }),
7514
- deps.map((d) => /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Tag, { icon: d.implemented ? "check" : "clock", children: d.label }, d.key))
7530
+ deps.length ? /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 6, borderTop: "1px solid var(--border)" }, children: [
7531
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "fd-overline fd-muted", style: { paddingTop: 3 }, children: "After" }),
7532
+ deps.map((d) => /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(Tag, { icon: d.implemented ? "check" : "clock", children: d.label }, d.key))
7515
7533
  ] }) : null,
7516
- blocking.length && !item.implemented ? /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("span", { className: "fd-body-sm", style: { color: "var(--warn-text)" }, children: [
7534
+ blocking.length && !item.implemented ? /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("span", { className: "fd-body-sm", style: { color: "var(--warn-text)" }, children: [
7517
7535
  "Blocked until ",
7518
7536
  blocking.map((d) => d.label).join(" and "),
7519
7537
  " ",
@@ -7524,12 +7542,12 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
7524
7542
  }
7525
7543
  function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
7526
7544
  const session = SessionKit.useSession();
7527
- const [project, setProject] = React32.useState("");
7528
- const [q, setQ] = React32.useState("");
7529
- const scrollRef = React32.useRef(null);
7530
- const nowRef = React32.useRef(null);
7531
- const rm = React32.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
7532
- const byKey = React32.useMemo(() => {
7545
+ const [project, setProject] = React33.useState("");
7546
+ const [q, setQ] = React33.useState("");
7547
+ const scrollRef = React33.useRef(null);
7548
+ const nowRef = React33.useRef(null);
7549
+ const rm = React33.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
7550
+ const byKey = React33.useMemo(() => {
7533
7551
  const m = {};
7534
7552
  rm.items.forEach((i) => {
7535
7553
  m[i.key] = i;
@@ -7538,7 +7556,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
7538
7556
  }, [rm]);
7539
7557
  const items = rm.items.filter((i) => (!project || i.project === project) && (!q || (i.label + " " + i.description + " " + (i.backend || "") + " " + i.key).toLowerCase().includes(q.toLowerCase())));
7540
7558
  const projects = [...new Set(rm.items.map((i) => i.project))];
7541
- React32.useEffect(() => {
7559
+ React33.useEffect(() => {
7542
7560
  let raf1 = 0, raf2 = 0;
7543
7561
  const place = () => {
7544
7562
  const box = scrollRef.current, mark = nowRef.current;
@@ -7566,23 +7584,23 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
7566
7584
  }, 0);
7567
7585
  const nextPhase = items.find((i) => !i.implemented);
7568
7586
  let lastPhase = null;
7569
- return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "fd-stack", style: { gap: 16, maxWidth: 1e3 }, children: [
7570
- /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
7571
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "fd-overline fd-muted", children: "Architecture" }),
7572
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
7573
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: lede || "Every screen and feature in these tools is already designed and working against a simulated backend. This is the plan for connecting them to the real one \u2014 so the only work described here is server work." })
7587
+ return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "fd-stack", style: { gap: 16, maxWidth: 1e3 }, children: [
7588
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
7589
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "fd-overline fd-muted", children: "Architecture" }),
7590
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
7591
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: lede || "Every screen and feature in these tools is already designed and working against a simulated backend. This is the plan for connecting them to the real one \u2014 so the only work described here is server work." })
7574
7592
  ] }),
7575
- /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "fd-grid-stats is-thin", children: [
7576
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(StatTile, { compact: true, label: "Wired", value: String(rm.shipped), sub: "of " + rm.items.length + " features" }),
7577
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(StatTile, { compact: true, label: "Remaining", value: String(rm.remaining), sub: "backend work" }),
7578
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(StatTile, { compact: true, label: "Est. effort", value: days ? days + " days" : "\u2014", sub: "sum of estimates, not calendar" }),
7579
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(StatTile, { compact: true, label: "Up next", value: nextPhase ? "Phase " + nextPhase.phase : "\u2014", sub: nextPhase ? nextPhase.phaseName : "all wired" })
7593
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "fd-grid-stats is-thin", children: [
7594
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(StatTile, { compact: true, label: "Wired", value: String(rm.shipped), sub: "of " + rm.items.length + " features" }),
7595
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(StatTile, { compact: true, label: "Remaining", value: String(rm.remaining), sub: "backend work" }),
7596
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(StatTile, { compact: true, label: "Est. effort", value: days ? days + " days" : "\u2014", sub: "sum of estimates, not calendar" }),
7597
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(StatTile, { compact: true, label: "Up next", value: nextPhase ? "Phase " + nextPhase.phase : "\u2014", sub: nextPhase ? nextPhase.phaseName : "all wired" })
7580
7598
  ] }),
7581
- /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
7582
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Input, { icon: "magnifying-glass", placeholder: "Find a feature or a piece of backend work", value: q, onChange: (e) => setQ(e.target.value), style: { width: 300 } }),
7583
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Select, { placeholder: "All projects", value: project, onChange: (e) => setProject(e.target.value), options: projects, style: { width: 190 } }),
7584
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { style: { flex: 1 } }),
7585
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
7599
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
7600
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(Input, { icon: "magnifying-glass", placeholder: "Find a feature or a piece of backend work", value: q, onChange: (e) => setQ(e.target.value), style: { width: 300 } }),
7601
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(Select, { placeholder: "All projects", value: project, onChange: (e) => setProject(e.target.value), options: projects, style: { width: 190 } }),
7602
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { style: { flex: 1 } }),
7603
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
7586
7604
  Button,
7587
7605
  {
7588
7606
  size: "sm",
@@ -7596,7 +7614,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
7596
7614
  }
7597
7615
  )
7598
7616
  ] }),
7599
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
7617
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
7600
7618
  Flag,
7601
7619
  {
7602
7620
  tone: "info",
@@ -7605,60 +7623,60 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
7605
7623
  actions: null
7606
7624
  }
7607
7625
  ),
7608
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { className: "fd-rm", children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { className: "fd-rm-scroll", ref: scrollRef, children: /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "fd-rm-track", children: [
7609
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "fd-rm-spine", children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "fd-rm-spine-done", style: { height: items.length ? 100 * shippedShown / items.length + "%" : "0%" } }) }),
7626
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "fd-rm", children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "fd-rm-scroll", ref: scrollRef, children: /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "fd-rm-track", children: [
7627
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "fd-rm-spine", children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "fd-rm-spine-done", style: { height: items.length ? 100 * shippedShown / items.length + "%" : "0%" } }) }),
7610
7628
  items.map((item, n) => {
7611
7629
  const showPhase = item.phase !== lastPhase;
7612
7630
  lastPhase = item.phase;
7613
7631
  const inPhase = items.filter((i) => i.phase === item.phase).length;
7614
7632
  const isBoundary = n === firstPending;
7615
- return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(React32.Fragment, { children: [
7616
- showPhase ? /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "fd-rm-era", children: [
7617
- /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
7618
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
7619
- item.phase === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("span", { className: "fd-mono", style: { opacity: 0.7, fontWeight: 400 }, children: [
7633
+ return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(React33.Fragment, { children: [
7634
+ showPhase ? /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "fd-rm-era", children: [
7635
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
7636
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
7637
+ item.phase === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("span", { className: "fd-mono", style: { opacity: 0.7, fontWeight: 400 }, children: [
7620
7638
  fmtDate(item.phaseStart),
7621
7639
  " \u2013 ",
7622
7640
  fmtDate(item.date)
7623
7641
  ] }),
7624
- /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("span", { style: { opacity: 0.7, fontWeight: 400 }, children: [
7642
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("span", { style: { opacity: 0.7, fontWeight: 400 }, children: [
7625
7643
  "\xB7 ",
7626
7644
  inPhase,
7627
7645
  " feature",
7628
7646
  inPhase === 1 ? "" : "s"
7629
7647
  ] })
7630
7648
  ] }),
7631
- item.phaseWhy ? /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("p", { className: "fd-rm-era-why", children: item.phaseWhy }) : null
7649
+ item.phaseWhy ? /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("p", { className: "fd-rm-era-why", children: item.phaseWhy }) : null
7632
7650
  ] }) : null,
7633
- isBoundary ? /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { className: "fd-rm-now", ref: nowRef, children: /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("span", { className: "fd-rm-now-pill", children: [
7634
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("i", { className: "ph ph-map-pin" }),
7651
+ isBoundary ? /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "fd-rm-now", ref: nowRef, children: /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("span", { className: "fd-rm-now-pill", children: [
7652
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("i", { className: "ph ph-map-pin" }),
7635
7653
  " You are here \u2014 everything above is wired"
7636
7654
  ] }) }) : null,
7637
- /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "fd-rm-row", children: [
7638
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "fd-rm-dot " + (item.implemented ? "is-shipped" : item.status === "next" ? "is-next" : "") }),
7639
- /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "fd-rm-date", children: [
7655
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "fd-rm-row", children: [
7656
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "fd-rm-dot " + (item.implemented ? "is-shipped" : item.status === "next" ? "is-next" : "") }),
7657
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "fd-rm-date", children: [
7640
7658
  fmtDate(item.date),
7641
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("br", {}),
7642
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { style: { opacity: 0.75 }, children: item.implemented ? "shipped" : "phase " + item.phase })
7659
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("br", {}),
7660
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { style: { opacity: 0.75 }, children: item.implemented ? "shipped" : "phase " + item.phase })
7643
7661
  ] }),
7644
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(RoadmapCard, { item, byKey, onOpenFlag })
7662
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(RoadmapCard, { item, byKey, onOpenFlag })
7645
7663
  ] })
7646
7664
  ] }, item.key);
7647
7665
  }),
7648
- !items.length ? /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("p", { className: "fd-body-sm fd-muted", children: "Nothing matches that filter." }) : null
7666
+ !items.length ? /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("p", { className: "fd-body-sm fd-muted", children: "Nothing matches that filter." }) : null
7649
7667
  ] }) }) }),
7650
- /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: [
7668
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: [
7651
7669
  "Derived from the feature-flag registry \u2014 each entry's status is its flag's ",
7652
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("code", { className: "fd-mono", children: "implemented" }),
7670
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("code", { className: "fd-mono", children: "implemented" }),
7653
7671
  " field, so this page cannot drift from what the apps actually do."
7654
7672
  ] })
7655
7673
  ] });
7656
7674
  }
7657
7675
 
7658
7676
  // src/components/platform/ComingSoon.tsx
7659
- var React33 = __toESM(require("react"), 1);
7677
+ var React34 = __toESM(require("react"), 1);
7660
7678
  var import_react_dom8 = require("react-dom");
7661
- var import_jsx_runtime61 = require("react/jsx-runtime");
7679
+ var import_jsx_runtime62 = require("react/jsx-runtime");
7662
7680
  var BYPASS_STORE = "fd.soon.bypass.v1";
7663
7681
  function readBypassed() {
7664
7682
  try {
@@ -7674,8 +7692,8 @@ function writeBypassed(list) {
7674
7692
  }
7675
7693
  }
7676
7694
  function useBypass(key) {
7677
- const [on, setOn] = React33.useState(() => !!key && readBypassed().indexOf(key) >= 0);
7678
- React33.useEffect(() => {
7695
+ const [on, setOn] = React34.useState(() => !!key && readBypassed().indexOf(key) >= 0);
7696
+ React34.useEffect(() => {
7679
7697
  setOn(!!key && readBypassed().indexOf(key) >= 0);
7680
7698
  }, [key]);
7681
7699
  const set = (next) => {
@@ -7688,43 +7706,43 @@ function useBypass(key) {
7688
7706
  return [on, set];
7689
7707
  }
7690
7708
  function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass }) {
7691
- return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(import_jsx_runtime61.Fragment, { children: [
7692
- /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("span", { className: "fd-soon-badge", children: [
7693
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
7709
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(import_jsx_runtime62.Fragment, { children: [
7710
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("span", { className: "fd-soon-badge", children: [
7711
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
7694
7712
  label
7695
7713
  ] }),
7696
- detail ? /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "fd-soon-detail", children: detail }) : null,
7697
- backend ? /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("span", { className: "fd-soon-backend", children: [
7698
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "fd-overline", children: "Needs" }),
7714
+ detail ? /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { className: "fd-soon-detail", children: detail }) : null,
7715
+ backend ? /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("span", { className: "fd-soon-backend", children: [
7716
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { className: "fd-overline", children: "Needs" }),
7699
7717
  " ",
7700
7718
  backend
7701
7719
  ] }) : null,
7702
- eta || effort || onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("span", { className: "fd-soon-meta", children: [
7703
- eta ? /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("span", { children: [
7704
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }),
7720
+ eta || effort || onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("span", { className: "fd-soon-meta", children: [
7721
+ eta ? /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("span", { children: [
7722
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }),
7705
7723
  " ",
7706
7724
  eta
7707
7725
  ] }) : null,
7708
- effort ? /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("span", { children: [
7709
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("i", { className: "ph ph-hourglass-medium", "aria-hidden": "true" }),
7726
+ effort ? /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("span", { children: [
7727
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("i", { className: "ph ph-hourglass-medium", "aria-hidden": "true" }),
7710
7728
  " ",
7711
7729
  effort
7712
7730
  ] }) : null,
7713
- onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
7731
+ onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
7714
7732
  "See the roadmap ",
7715
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
7733
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
7716
7734
  ] }) : null
7717
7735
  ] }) : null,
7718
- allowed ? /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("button", { type: "button", className: "fd-soon-view", onClick: onBypass, children: [
7719
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("i", { className: "ph ph-eye", "aria-hidden": "true" }),
7736
+ allowed ? /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("button", { type: "button", className: "fd-soon-view", onClick: onBypass, children: [
7737
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("i", { className: "ph ph-eye", "aria-hidden": "true" }),
7720
7738
  " View and use it anyway"
7721
7739
  ] }) : null
7722
7740
  ] });
7723
7741
  }
7724
7742
  function useHoverCard(open) {
7725
- const anchor = React33.useRef(null);
7726
- const [pos, setPos] = React33.useState(null);
7727
- React33.useLayoutEffect(() => {
7743
+ const anchor = React34.useRef(null);
7744
+ const [pos, setPos] = React34.useState(null);
7745
+ React34.useLayoutEffect(() => {
7728
7746
  if (!open || !anchor.current) {
7729
7747
  setPos(null);
7730
7748
  return;
@@ -7776,9 +7794,9 @@ function ComingSoon({
7776
7794
  const tip = [label, detail, backend ? "Needs " + backend : null, eta ? "ETA " + eta : null, effort].filter(Boolean).join(" \xB7 ");
7777
7795
  if (inline) {
7778
7796
  if (allowed && bypassed) {
7779
- return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("span", { className: ["fd-soon-inline-on", className].filter(Boolean).join(" "), ...rest, children: [
7797
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("span", { className: ["fd-soon-inline-on", className].filter(Boolean).join(" "), ...rest, children: [
7780
7798
  children,
7781
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
7799
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
7782
7800
  "button",
7783
7801
  {
7784
7802
  type: "button",
@@ -7786,12 +7804,12 @@ function ComingSoon({
7786
7804
  title: "Unwired \u2014 writes go to the simulated backend. " + tip + " Click to re-blur.",
7787
7805
  onClick: () => setBypassed(false),
7788
7806
  "aria-label": "Re-blur this unwired feature",
7789
- children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
7807
+ children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
7790
7808
  }
7791
7809
  )
7792
7810
  ] });
7793
7811
  }
7794
- return /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
7812
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
7795
7813
  InlineSoon,
7796
7814
  {
7797
7815
  label,
@@ -7811,20 +7829,20 @@ function ComingSoon({
7811
7829
  );
7812
7830
  }
7813
7831
  if (allowed && bypassed) {
7814
- return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, ...rest, children: [
7815
- /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "fd-soon-bar", role: "status", children: [
7816
- /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("span", { className: "fd-soon-badge", children: [
7817
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
7832
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, ...rest, children: [
7833
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "fd-soon-bar", role: "status", children: [
7834
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("span", { className: "fd-soon-badge", children: [
7835
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
7818
7836
  "Unwired feature \u2014 you are using it anyway"
7819
7837
  ] }),
7820
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "fd-soon-bar-detail", children: "Every action here writes to the simulated backend, so nothing you do persists beyond this session." }),
7821
- /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("span", { className: "fd-soon-bar-actions", children: [
7822
- onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
7838
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { className: "fd-soon-bar-detail", children: "Every action here writes to the simulated backend, so nothing you do persists beyond this session." }),
7839
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("span", { className: "fd-soon-bar-actions", children: [
7840
+ onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
7823
7841
  "Roadmap ",
7824
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
7842
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
7825
7843
  ] }) : null,
7826
- /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => setBypassed(false), children: [
7827
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("i", { className: "ph ph-eye-slash", "aria-hidden": "true" }),
7844
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => setBypassed(false), children: [
7845
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("i", { className: "ph ph-eye-slash", "aria-hidden": "true" }),
7828
7846
  " Re-blur"
7829
7847
  ] })
7830
7848
  ] })
@@ -7832,10 +7850,10 @@ function ComingSoon({
7832
7850
  children
7833
7851
  ] });
7834
7852
  }
7835
- return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: ["fd-soon", className].filter(Boolean).join(" "), style: minHeight ? { minHeight } : void 0, ...rest, children: [
7836
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "fd-soon-under", style: { filter: "blur(" + blur + "px) saturate(.62)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
7837
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "fd-soon-veil" }),
7838
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "fd-soon-note", role: "note", children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
7853
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: ["fd-soon", className].filter(Boolean).join(" "), style: minHeight ? { minHeight } : void 0, ...rest, children: [
7854
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "fd-soon-under", style: { filter: "blur(" + blur + "px) saturate(.62)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
7855
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "fd-soon-veil" }),
7856
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "fd-soon-note", role: "note", children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
7839
7857
  SoonCard,
7840
7858
  {
7841
7859
  label,
@@ -7851,9 +7869,9 @@ function ComingSoon({
7851
7869
  ] });
7852
7870
  }
7853
7871
  function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass, blur, tip, className, rest, children }) {
7854
- const [open, setOpen] = React33.useState(false);
7872
+ const [open, setOpen] = React34.useState(false);
7855
7873
  const [anchor, pos] = useHoverCard(open);
7856
- const close = React33.useRef(null);
7874
+ const close = React34.useRef(null);
7857
7875
  const show = () => {
7858
7876
  if (close.current) {
7859
7877
  clearTimeout(close.current);
@@ -7869,10 +7887,10 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
7869
7887
  setOpen(false);
7870
7888
  }, 140);
7871
7889
  };
7872
- React33.useEffect(() => () => {
7890
+ React34.useEffect(() => () => {
7873
7891
  if (close.current) clearTimeout(close.current);
7874
7892
  }, []);
7875
- return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(
7893
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(
7876
7894
  "span",
7877
7895
  {
7878
7896
  ref: anchor,
@@ -7883,8 +7901,8 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
7883
7901
  onBlur: hide,
7884
7902
  ...rest,
7885
7903
  children: [
7886
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "fd-soon-under", style: { filter: "blur(" + Math.min(blur, 1.1) + "px) saturate(.66)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
7887
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
7904
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { className: "fd-soon-under", style: { filter: "blur(" + Math.min(blur, 1.1) + "px) saturate(.66)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
7905
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
7888
7906
  "button",
7889
7907
  {
7890
7908
  type: "button",
@@ -7895,11 +7913,11 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
7895
7913
  onFocus: show,
7896
7914
  onBlur: hide,
7897
7915
  onClick: () => open ? setOpen(false) : show(),
7898
- children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
7916
+ children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
7899
7917
  }
7900
7918
  ),
7901
7919
  open && pos ? (0, import_react_dom8.createPortal)(
7902
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
7920
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
7903
7921
  "div",
7904
7922
  {
7905
7923
  className: "fd-soon-note fd-soon-hovercard",
@@ -7907,7 +7925,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
7907
7925
  style: { position: "fixed", left: pos.left, top: pos.top, bottom: pos.bottom, width: pos.width },
7908
7926
  onMouseEnter: show,
7909
7927
  onMouseLeave: hide,
7910
- children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
7928
+ children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
7911
7929
  SoonCard,
7912
7930
  {
7913
7931
  label,
@@ -7937,10 +7955,10 @@ function formatEta(iso2) {
7937
7955
  var FormatEta = formatEta;
7938
7956
 
7939
7957
  // src/components/platform/Gate.tsx
7940
- var import_jsx_runtime62 = require("react/jsx-runtime");
7958
+ var import_jsx_runtime63 = require("react/jsx-runtime");
7941
7959
  function PermissionDenied({ permission, title, detail, compact: compact3 = false, className = "", ...rest }) {
7942
7960
  const need = Array.isArray(permission) ? permission : [permission].filter(Boolean);
7943
- return /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(
7961
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
7944
7962
  "div",
7945
7963
  {
7946
7964
  className: ["fd-stack", className].filter(Boolean).join(" "),
@@ -7956,14 +7974,14 @@ function PermissionDenied({ permission, title, detail, compact: compact3 = false
7956
7974
  },
7957
7975
  ...rest,
7958
7976
  children: [
7959
- /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("span", { className: "fd-row", style: { gap: 8 }, children: [
7960
- /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("i", { className: "ph ph-lock-simple", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
7961
- /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { className: compact3 ? "fd-label-lg" : "fd-h3", children: title || "You do not have access to this" })
7977
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("span", { className: "fd-row", style: { gap: 8 }, children: [
7978
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("i", { className: "ph ph-lock-simple", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
7979
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: compact3 ? "fd-label-lg" : "fd-h3", children: title || "You do not have access to this" })
7962
7980
  ] }),
7963
- /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: detail || "Your roles do not grant this. An administrator can change that from Admin \u2192 Users." }),
7964
- need.length ? /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: [
7965
- /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { className: "fd-overline fd-muted", children: "Requires" }),
7966
- need.map((p) => /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("code", { className: "fd-mono", style: {
7981
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: detail || "Your roles do not grant this. An administrator can change that from Admin \u2192 Users." }),
7982
+ need.length ? /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: [
7983
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: "fd-overline fd-muted", children: "Requires" }),
7984
+ need.map((p) => /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("code", { className: "fd-mono", style: {
7967
7985
  fontSize: 11.5,
7968
7986
  padding: "2px 7px",
7969
7987
  borderRadius: 5,
@@ -7984,7 +8002,7 @@ function Gate({ perm, anyOf, role, silent = false, fallback, compact: compact3 =
7984
8002
  if (ok) return children;
7985
8003
  if (fallback !== void 0) return fallback;
7986
8004
  if (silent) return null;
7987
- return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(PermissionDenied, { permission: perm || anyOf, compact: compact3 });
8005
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(PermissionDenied, { permission: perm || anyOf, compact: compact3 });
7988
8006
  }
7989
8007
  function FeatureGate({
7990
8008
  flag,
@@ -8005,7 +8023,7 @@ function FeatureGate({
8005
8023
  if (!preview) return fallback;
8006
8024
  const f = SessionKit.findFlag(flag) || {};
8007
8025
  const missing = rt.missing || [];
8008
- return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
8026
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
8009
8027
  ComingSoon,
8010
8028
  {
8011
8029
  label: label || (variant === "inline" ? f.label || "Not wired yet" : "Designed \u2014 backend not wired yet"),
@@ -8026,25 +8044,25 @@ function FeatureGate({
8026
8044
  function PermissionHint({ perm, children }) {
8027
8045
  SessionKit.useSession();
8028
8046
  if (SessionKit.can(perm)) return children;
8029
- return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
8047
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
8030
8048
  "span",
8031
8049
  {
8032
8050
  title: "Requires " + (Array.isArray(perm) ? perm.join(", ") : perm),
8033
8051
  style: { display: "inline-flex", opacity: 0.45, cursor: "not-allowed" },
8034
8052
  "aria-disabled": "true",
8035
- children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { style: { pointerEvents: "none" }, children })
8053
+ children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { style: { pointerEvents: "none" }, children })
8036
8054
  }
8037
8055
  );
8038
8056
  }
8039
8057
 
8040
8058
  // src/components/platform/ModeSwitch.tsx
8041
- var React34 = __toESM(require("react"), 1);
8042
- var import_jsx_runtime63 = require("react/jsx-runtime");
8059
+ var React35 = __toESM(require("react"), 1);
8060
+ var import_jsx_runtime64 = require("react/jsx-runtime");
8043
8061
  function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
8044
8062
  const mode2 = useRuntimeMode();
8045
- const [open, setOpen] = React34.useState(false);
8046
- const ref = React34.useRef(null);
8047
- React34.useEffect(() => {
8063
+ const [open, setOpen] = React35.useState(false);
8064
+ const ref = React35.useRef(null);
8065
+ React35.useEffect(() => {
8048
8066
  if (!open) return;
8049
8067
  const away = (e) => {
8050
8068
  if (ref.current && !ref.current.contains(e.target)) setOpen(false);
@@ -8066,8 +8084,8 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
8066
8084
  RuntimeKit.setMode(next);
8067
8085
  setOpen(false);
8068
8086
  };
8069
- return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("span", { style: { position: "relative", display: "inline-flex" }, ref, children: [
8070
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
8087
+ return /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("span", { style: { position: "relative", display: "inline-flex" }, ref, children: [
8088
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(
8071
8089
  "button",
8072
8090
  {
8073
8091
  type: "button",
@@ -8077,29 +8095,29 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
8077
8095
  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.",
8078
8096
  className: "fd-mode-btn" + (test ? " is-test" : "") + (open ? " is-open" : ""),
8079
8097
  children: [
8080
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), style: { fontSize: 17 } }),
8081
- test && requestCount ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: "fd-mono fd-mode-count", children: requestCount > 99 ? "99+" : requestCount }, requestCount) : null
8098
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), style: { fontSize: 17 } }),
8099
+ test && requestCount ? /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("span", { className: "fd-mono fd-mode-count", children: requestCount > 99 ? "99+" : requestCount }, requestCount) : null
8082
8100
  ]
8083
8101
  }
8084
8102
  ),
8085
- open ? /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("span", { className: "fd-view-enter fd-mode-pop", children: [
8086
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("span", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
8087
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("span", { className: "fd-badge " + (test ? "fd-badge-warning" : "fd-badge-neutral"), children: [
8088
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), "aria-hidden": "true" }),
8103
+ open ? /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("span", { className: "fd-view-enter fd-mode-pop", children: [
8104
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("span", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
8105
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("span", { className: "fd-badge " + (test ? "fd-badge-warning" : "fd-badge-neutral"), children: [
8106
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), "aria-hidden": "true" }),
8089
8107
  test ? "Test mode" : "Live mode"
8090
8108
  ] }),
8091
- test ? /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
8109
+ test ? /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
8092
8110
  requestCount,
8093
8111
  " simulated request",
8094
8112
  requestCount === 1 ? "" : "s"
8095
8113
  ] }) : null,
8096
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { style: { flex: 1 } }),
8097
- test && onClearLog ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("button", { type: "button", className: "fd-soon-link", onClick: onClearLog, children: "Clear" }) : null
8114
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("span", { style: { flex: 1 } }),
8115
+ test && onClearLog ? /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("button", { type: "button", className: "fd-soon-link", onClick: onClearLog, children: "Clear" }) : null
8098
8116
  ] }),
8099
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("span", { style: { display: "block", padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
8100
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: "fd-body-sm fd-secondary", style: { display: "block", textWrap: "pretty" }, children: test ? "Every feature is usable and nothing is obstructed, but no response comes from a real service \u2014 nothing you do here persists. Use this to review and demo the design." : "This is what a user would see today. " + s.incomplete + " of " + s.total + " features depend on backend work that is not wired yet, so they render under construction." }),
8101
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("span", { className: "fd-row", style: { gap: 8, marginTop: 10, flexWrap: "wrap" }, children: [
8102
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
8117
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("span", { style: { display: "block", padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
8118
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("span", { className: "fd-body-sm fd-secondary", style: { display: "block", textWrap: "pretty" }, children: test ? "Every feature is usable and nothing is obstructed, but no response comes from a real service \u2014 nothing you do here persists. Use this to review and demo the design." : "This is what a user would see today. " + s.incomplete + " of " + s.total + " features depend on backend work that is not wired yet, so they render under construction." }),
8119
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("span", { className: "fd-row", style: { gap: 8, marginTop: 10, flexWrap: "wrap" }, children: [
8120
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
8103
8121
  s.endpointsWired,
8104
8122
  " endpoint",
8105
8123
  s.endpointsWired === 1 ? "" : "s",
@@ -8109,58 +8127,58 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
8109
8127
  s.total,
8110
8128
  " features complete"
8111
8129
  ] }),
8112
- onOpenSpec ? /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(import_jsx_runtime63.Fragment, { children: [
8113
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { style: { flex: 1 } }),
8114
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => {
8130
+ onOpenSpec ? /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(import_jsx_runtime64.Fragment, { children: [
8131
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("span", { style: { flex: 1 } }),
8132
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => {
8115
8133
  setOpen(false);
8116
8134
  onOpenSpec();
8117
8135
  }, children: [
8118
8136
  "API spec ",
8119
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
8137
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
8120
8138
  ] })
8121
8139
  ] }) : null
8122
8140
  ] })
8123
8141
  ] }),
8124
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("span", { className: "fd-mode-choice", children: [
8125
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("button", { type: "button", className: "fd-mode-opt" + (!test ? " is-on" : ""), onClick: () => go("live"), children: [
8126
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
8127
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("span", { className: "fd-mode-opt-text", children: [
8128
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: "fd-mode-opt-title", children: "Live mode" }),
8129
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: "fd-mode-opt-desc", children: "Incomplete features under construction" })
8142
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("span", { className: "fd-mode-choice", children: [
8143
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("button", { type: "button", className: "fd-mode-opt" + (!test ? " is-on" : ""), onClick: () => go("live"), children: [
8144
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
8145
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("span", { className: "fd-mode-opt-text", children: [
8146
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("span", { className: "fd-mode-opt-title", children: "Live mode" }),
8147
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("span", { className: "fd-mode-opt-desc", children: "Incomplete features under construction" })
8130
8148
  ] }),
8131
- !test ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
8149
+ !test ? /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
8132
8150
  ] }),
8133
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("button", { type: "button", className: "fd-mode-opt" + (test ? " is-on" : ""), onClick: () => go("test"), children: [
8134
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("i", { className: "ph ph-flask", "aria-hidden": "true" }),
8135
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("span", { className: "fd-mode-opt-text", children: [
8136
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: "fd-mode-opt-title", children: "Test mode" }),
8137
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: "fd-mode-opt-desc", children: "Everything usable, all data simulated" })
8151
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("button", { type: "button", className: "fd-mode-opt" + (test ? " is-on" : ""), onClick: () => go("test"), children: [
8152
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("i", { className: "ph ph-flask", "aria-hidden": "true" }),
8153
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("span", { className: "fd-mode-opt-text", children: [
8154
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("span", { className: "fd-mode-opt-title", children: "Test mode" }),
8155
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("span", { className: "fd-mode-opt-desc", children: "Everything usable, all data simulated" })
8138
8156
  ] }),
8139
- test ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
8157
+ test ? /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
8140
8158
  ] })
8141
8159
  ] }),
8142
- test && renderLog ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { style: { display: "block", maxHeight: 340, overflowY: "auto", borderTop: "1px solid var(--border)" }, children: renderLog() }) : null
8160
+ test && renderLog ? /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("span", { style: { display: "block", maxHeight: 340, overflowY: "auto", borderTop: "1px solid var(--border)" }, children: renderLog() }) : null
8143
8161
  ] }) : null
8144
8162
  ] });
8145
8163
  }
8146
8164
  function TestModeBar({ onExit }) {
8147
8165
  const mode2 = useRuntimeMode();
8148
8166
  if (mode2 !== "test") return null;
8149
- return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "fd-testbar", role: "status", children: [
8150
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("span", { className: "fd-badge fd-badge-warning", children: [
8151
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("i", { className: "ph ph-flask", "aria-hidden": "true" }),
8167
+ return /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("div", { className: "fd-testbar", role: "status", children: [
8168
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("span", { className: "fd-badge fd-badge-warning", children: [
8169
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("i", { className: "ph ph-flask", "aria-hidden": "true" }),
8152
8170
  "Test mode"
8153
8171
  ] }),
8154
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: "fd-testbar-detail", children: "Every feature is unlocked and every response is simulated \u2014 nothing here persists." }),
8155
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => onExit ? onExit() : RuntimeKit.setMode("live"), children: [
8156
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
8172
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("span", { className: "fd-testbar-detail", children: "Every feature is unlocked and every response is simulated \u2014 nothing here persists." }),
8173
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => onExit ? onExit() : RuntimeKit.setMode("live"), children: [
8174
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
8157
8175
  " Back to live mode"
8158
8176
  ] })
8159
8177
  ] });
8160
8178
  }
8161
8179
 
8162
8180
  // src/components/planner/ChannelMeta.tsx
8163
- var import_jsx_runtime64 = require("react/jsx-runtime");
8181
+ var import_jsx_runtime65 = require("react/jsx-runtime");
8164
8182
  var CHANNEL_WEIGHTS = {
8165
8183
  "OOH": 50,
8166
8184
  "DOOH": 50,
@@ -8213,9 +8231,9 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
8213
8231
  const m = ChannelMeta(channel);
8214
8232
  const wt = channelWeightOf(channel || "");
8215
8233
  if (dot) {
8216
- return /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("span", { className: ["fd-chan-dot", className].filter(Boolean).join(" "), title: m.name, style: { background: m.color }, ...rest });
8234
+ return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("span", { className: ["fd-chan-dot", className].filter(Boolean).join(" "), title: m.name, style: { background: m.color }, ...rest });
8217
8235
  }
8218
- return /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(
8236
+ return /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(
8219
8237
  "span",
8220
8238
  {
8221
8239
  className: ["fd-chan", size === "sm" ? "fd-chan-sm" : "", className].filter(Boolean).join(" "),
@@ -8223,16 +8241,16 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
8223
8241
  style: { "--chan": m.color },
8224
8242
  ...rest,
8225
8243
  children: [
8226
- /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }),
8227
- showLabel ? /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("span", { className: "fd-chan-label", children: m.label }) : null,
8228
- weight ? /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("span", { className: "fd-chan-weight", children: wt || 0 }) : null
8244
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }),
8245
+ showLabel ? /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("span", { className: "fd-chan-label", children: m.label }) : null,
8246
+ weight ? /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("span", { className: "fd-chan-weight", children: wt || 0 }) : null
8229
8247
  ]
8230
8248
  }
8231
8249
  );
8232
8250
  }
8233
8251
 
8234
8252
  // src/components/planner/SaturationDistribution.tsx
8235
- var import_jsx_runtime65 = require("react/jsx-runtime");
8253
+ var import_jsx_runtime66 = require("react/jsx-runtime");
8236
8254
  var BANDS2 = [
8237
8255
  { key: "weak", label: "Weak", n: 1, range: "< 50" },
8238
8256
  { key: "adequate", label: "Adequate", n: 2, range: "50\u2013100" },
@@ -8243,18 +8261,18 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
8243
8261
  const grouped = BANDS2.map((b) => ({ ...b, items: campuses.filter((c) => c.band === b.key) }));
8244
8262
  const tallest = Math.max(1, ...grouped.map((g) => g.items.length));
8245
8263
  const floor = BANDS2.find((b) => b.key === floorBand) || BANDS2[0];
8246
- return /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
8247
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("div", { style: { display: "grid", gridTemplateColumns: "repeat(4,1fr)", gap: 12, alignItems: "end" }, children: grouped.map((g) => {
8264
+ return /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
8265
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("div", { style: { display: "grid", gridTemplateColumns: "repeat(4,1fr)", gap: 12, alignItems: "end" }, children: grouped.map((g) => {
8248
8266
  const mark = "var(--csi-" + g.n + "-mark)";
8249
8267
  const active = selectedBand === g.key;
8250
- return /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(
8268
+ return /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(
8251
8269
  "button",
8252
8270
  {
8253
8271
  type: "button",
8254
8272
  onClick: onSelectBand ? () => onSelectBand(active ? null : g.key) : void 0,
8255
8273
  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)" },
8256
8274
  children: [
8257
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("span", { style: { display: "flex", flexDirection: "column-reverse", gap: 4, minHeight: tallest * 24 }, children: loading ? Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("span", { className: "fd-skel", style: { height: 16, borderRadius: 4 } }, i)) : g.items.map((c) => /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
8275
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { style: { display: "flex", flexDirection: "column-reverse", gap: 4, minHeight: tallest * 24 }, children: loading ? Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "fd-skel", style: { height: 16, borderRadius: 4 } }, i)) : g.items.map((c) => /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
8258
8276
  "span",
8259
8277
  {
8260
8278
  title: c.name + " \xB7 " + c.crp,
@@ -8263,13 +8281,13 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
8263
8281
  },
8264
8282
  c.name
8265
8283
  )) }),
8266
- /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("span", { className: "fd-row", style: { gap: 8, alignItems: "baseline" }, children: [
8267
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("span", { className: "fd-num-hero", style: { fontSize: 30, color: g.items.length ? "var(--text)" : "var(--text-disabled)" }, children: loading ? "\u2013" : g.items.length }),
8268
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("span", { className: "fd-meter", style: { gap: 2, color: mark }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("span", { className: "fd-meter-seg" + (i <= g.n ? " is-on" : ""), style: { width: 4, height: 9 } }, i)) })
8284
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("span", { className: "fd-row", style: { gap: 8, alignItems: "baseline" }, children: [
8285
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "fd-num-hero", style: { fontSize: 30, color: g.items.length ? "var(--text)" : "var(--text-disabled)" }, children: loading ? "\u2013" : g.items.length }),
8286
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "fd-meter", style: { gap: 2, color: mark }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "fd-meter-seg" + (i <= g.n ? " is-on" : ""), style: { width: 4, height: 9 } }, i)) })
8269
8287
  ] }),
8270
- /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("span", { className: "fd-stack", style: { gap: 1 }, children: [
8271
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("span", { className: "fd-label-lg", children: g.label }),
8272
- /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("span", { className: "fd-body-sm fd-muted", style: { fontSize: 11.5 }, children: [
8288
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("span", { className: "fd-stack", style: { gap: 1 }, children: [
8289
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "fd-label-lg", children: g.label }),
8290
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("span", { className: "fd-body-sm fd-muted", style: { fontSize: 11.5 }, children: [
8273
8291
  "CRP ",
8274
8292
  g.range
8275
8293
  ] })
@@ -8279,10 +8297,10 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
8279
8297
  g.key
8280
8298
  );
8281
8299
  }) }),
8282
- floorBand ? /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("div", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderRadius: "var(--r-md)", background: "var(--surface-2)", border: "1px solid var(--border)", flexWrap: "wrap" }, children: [
8283
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("span", { className: "fd-meter", style: { gap: 2, color: "var(--csi-" + floor.n + "-mark)" }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("span", { className: "fd-meter-seg" + (i <= floor.n ? " is-on" : ""), style: { width: 5, height: 12 } }, i)) }),
8284
- /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("span", { className: "fd-body-sm fd-secondary", style: { flex: 1, minWidth: 240 }, children: [
8285
- /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("strong", { style: { color: "var(--text)" }, children: [
8300
+ floorBand ? /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderRadius: "var(--r-md)", background: "var(--surface-2)", border: "1px solid var(--border)", flexWrap: "wrap" }, children: [
8301
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "fd-meter", style: { gap: 2, color: "var(--csi-" + floor.n + "-mark)" }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "fd-meter-seg" + (i <= floor.n ? " is-on" : ""), style: { width: 5, height: 12 } }, i)) }),
8302
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("span", { className: "fd-body-sm fd-secondary", style: { flex: 1, minWidth: 240 }, children: [
8303
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("strong", { style: { color: "var(--text)" }, children: [
8286
8304
  "Plan floor ",
8287
8305
  floorScore
8288
8306
  ] }),
@@ -8293,21 +8311,21 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
8293
8311
  }
8294
8312
 
8295
8313
  // src/components/planner/MixGap.tsx
8296
- var React35 = __toESM(require("react"), 1);
8297
- var import_jsx_runtime66 = require("react/jsx-runtime");
8314
+ var React36 = __toESM(require("react"), 1);
8315
+ var import_jsx_runtime67 = require("react/jsx-runtime");
8298
8316
  function MixGap({ rows = [], loading = false, className = "" }) {
8299
8317
  const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
8300
- const [hover, setHover] = React35.useState(null);
8318
+ const [hover, setHover] = React36.useState(null);
8301
8319
  const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
8302
8320
  const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
8303
- return /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 4 }, children: [
8304
- /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "fd-row", style: { gap: 16, justifyContent: "flex-end", paddingBottom: 6, flexWrap: "wrap" }, children: [
8305
- [["On target", TONE.ok], ["Close", TONE.warn], ["Short", TONE.danger]].map(([l, c]) => /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
8306
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { style: { width: 14, height: 9, borderRadius: 2, background: c } }),
8321
+ return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 4 }, children: [
8322
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: "fd-row", style: { gap: 16, justifyContent: "flex-end", paddingBottom: 6, flexWrap: "wrap" }, children: [
8323
+ [["On target", TONE.ok], ["Close", TONE.warn], ["Short", TONE.danger]].map(([l, c]) => /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
8324
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { style: { width: 14, height: 9, borderRadius: 2, background: c } }),
8307
8325
  l
8308
8326
  ] }, l)),
8309
- /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
8310
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { style: { width: 3, height: 14, background: "var(--n-500)" } }),
8327
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
8328
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { style: { width: 3, height: 14, background: "var(--n-500)" } }),
8311
8329
  "Target"
8312
8330
  ] })
8313
8331
  ] }),
@@ -8315,7 +8333,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
8315
8333
  const gap = r.realized - r.target;
8316
8334
  const tone = toneOf(gap);
8317
8335
  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 : "");
8318
- return /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(
8336
+ return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(
8319
8337
  "div",
8320
8338
  {
8321
8339
  className: "fd-row",
@@ -8323,15 +8341,15 @@ function MixGap({ rows = [], loading = false, className = "" }) {
8323
8341
  onMouseEnter: () => setHover(r.channel),
8324
8342
  onMouseLeave: () => setHover(null),
8325
8343
  children: [
8326
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { style: { width: 128, flex: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(ChannelTag, { channel: r.channel, size: "sm" }) }),
8327
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { style: { position: "relative", flex: 1, height: 22, minWidth: 120 }, children: loading ? /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "fd-skel", style: { position: "absolute", inset: "5px 0", borderRadius: 3 } }) : /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(import_jsx_runtime66.Fragment, { children: [
8328
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("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)" } }),
8329
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { style: { position: "absolute", left: r.target / max * 100 + "%", top: 0, width: 3, height: 22, background: "var(--n-500)", borderRadius: 1 } }),
8330
- /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("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: [
8344
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { style: { width: 128, flex: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(ChannelTag, { channel: r.channel, size: "sm" }) }),
8345
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { style: { position: "relative", flex: 1, height: 22, minWidth: 120 }, children: loading ? /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { className: "fd-skel", style: { position: "absolute", inset: "5px 0", borderRadius: 3 } }) : /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(import_jsx_runtime67.Fragment, { children: [
8346
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("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)" } }),
8347
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { style: { position: "absolute", left: r.target / max * 100 + "%", top: 0, width: 3, height: 22, background: "var(--n-500)", borderRadius: 1 } }),
8348
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("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: [
8331
8349
  r.realized,
8332
8350
  "%"
8333
8351
  ] }),
8334
- hover === r.channel ? /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("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
8352
+ hover === r.channel ? /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("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
8335
8353
  ] }) })
8336
8354
  ]
8337
8355
  },
@@ -8342,7 +8360,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
8342
8360
  }
8343
8361
 
8344
8362
  // src/components/planner/ChannelContribution.tsx
8345
- var import_jsx_runtime67 = require("react/jsx-runtime");
8363
+ var import_jsx_runtime68 = require("react/jsx-runtime");
8346
8364
  var money = (n) => "$" + Math.round(n).toLocaleString();
8347
8365
  function ChannelContribution({
8348
8366
  channels = [],
@@ -8358,9 +8376,9 @@ function ChannelContribution({
8358
8376
  const grand = total !== void 0 ? total : base + bonus;
8359
8377
  const pct = (v) => grand ? v / grand * 100 : 0;
8360
8378
  const spendTotal = channels.reduce((s, c) => s + Number(String(c.spend || 0).replace(/[^0-9.]/g, "")), 0);
8361
- return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
8362
- loading ? /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { className: "fd-skel", style: { height: 34, borderRadius: "var(--r-sm)" } }) : /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: "fd-row", style: { height: 34, borderRadius: "var(--r-sm)", overflow: "hidden", gap: 2, background: "var(--surface-3)" }, children: [
8363
- channels.map((c) => /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
8379
+ return /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
8380
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { className: "fd-skel", style: { height: 34, borderRadius: "var(--r-sm)" } }) : /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "fd-row", style: { height: 34, borderRadius: "var(--r-sm)", overflow: "hidden", gap: 2, background: "var(--surface-3)" }, children: [
8381
+ channels.map((c) => /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
8364
8382
  "span",
8365
8383
  {
8366
8384
  title: c.name + " \xB7 " + c.crp.toFixed(1) + " CRP",
@@ -8369,7 +8387,7 @@ function ChannelContribution({
8369
8387
  },
8370
8388
  c.name
8371
8389
  )),
8372
- bonus > 0 ? /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
8390
+ bonus > 0 ? /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
8373
8391
  "span",
8374
8392
  {
8375
8393
  title: "Surround-sound bonus +" + bonusPct + "%",
@@ -8378,18 +8396,18 @@ function ChannelContribution({
8378
8396
  }
8379
8397
  ) : null
8380
8398
  ] }),
8381
- showTable ? /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("table", { className: "fd-table", style: { fontSize: "var(--body-sm-size)" }, children: [
8382
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("tr", { children: [
8383
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("th", { style: { width: "34%" }, children: "Channel" }),
8384
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("th", { style: { width: "16%" }, children: "Weight" }),
8385
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("th", { className: "is-num", style: { width: "16%" }, children: "Spend" }),
8386
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("th", { className: "is-num", style: { width: "17%" }, children: "CRP" }),
8387
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("th", { className: "is-num", style: { width: "17%" }, children: "Share" })
8399
+ showTable ? /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("table", { className: "fd-table", style: { fontSize: "var(--body-sm-size)" }, children: [
8400
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("tr", { children: [
8401
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("th", { style: { width: "34%" }, children: "Channel" }),
8402
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("th", { style: { width: "16%" }, children: "Weight" }),
8403
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("th", { className: "is-num", style: { width: "16%" }, children: "Spend" }),
8404
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("th", { className: "is-num", style: { width: "17%" }, children: "CRP" }),
8405
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("th", { className: "is-num", style: { width: "17%" }, children: "Share" })
8388
8406
  ] }) }),
8389
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("tbody", { children: [
8390
- channels.map((c) => /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("tr", { children: [
8391
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(ChannelTag, { channel: c.name, size: "sm" }) }),
8392
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
8407
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("tbody", { children: [
8408
+ channels.map((c) => /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("tr", { children: [
8409
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(ChannelTag, { channel: c.name, size: "sm" }) }),
8410
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
8393
8411
  "span",
8394
8412
  {
8395
8413
  className: "fd-badge fd-badge-neutral",
@@ -8398,38 +8416,38 @@ function ChannelContribution({
8398
8416
  children: "weight " + (channelWeightOf(c.name) || 0)
8399
8417
  }
8400
8418
  ) }),
8401
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("td", { className: "is-num", children: c.spend }),
8402
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("td", { className: "is-num", children: c.crp.toFixed(1) }),
8403
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("td", { className: "is-num", children: [
8419
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("td", { className: "is-num", children: c.spend }),
8420
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("td", { className: "is-num", children: c.crp.toFixed(1) }),
8421
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("td", { className: "is-num", children: [
8404
8422
  pct(c.crp).toFixed(0),
8405
8423
  "%"
8406
8424
  ] })
8407
8425
  ] }, c.name)),
8408
- bonus > 0 ? /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("tr", { children: [
8409
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("span", { className: "fd-row", style: { gap: 9, fontWeight: 600 }, children: [
8410
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { style: { width: 9, height: 9, borderRadius: 2, background: "repeating-linear-gradient(135deg,var(--csi-3-mark) 0 3px,var(--csi-2-mark) 3px 6px)", flex: "none" } }),
8426
+ bonus > 0 ? /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("tr", { children: [
8427
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("span", { className: "fd-row", style: { gap: 9, fontWeight: 600 }, children: [
8428
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { style: { width: 9, height: 9, borderRadius: 2, background: "repeating-linear-gradient(135deg,var(--csi-3-mark) 0 3px,var(--csi-2-mark) 3px 6px)", flex: "none" } }),
8411
8429
  "Surround-sound bonus"
8412
8430
  ] }) }),
8413
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("span", { className: "fd-badge fd-badge-success", style: { height: 20, fontSize: 11 }, children: [
8431
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("span", { className: "fd-badge fd-badge-success", style: { height: 20, fontSize: 11 }, children: [
8414
8432
  "+",
8415
8433
  bonusPct,
8416
8434
  "% of +",
8417
8435
  bonusMax,
8418
8436
  "%"
8419
8437
  ] }) }),
8420
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("td", { className: "is-num fd-muted", children: "\u2014" }),
8421
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("td", { className: "is-num", children: bonus.toFixed(1) }),
8422
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("td", { className: "is-num", children: [
8438
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("td", { className: "is-num fd-muted", children: "\u2014" }),
8439
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("td", { className: "is-num", children: bonus.toFixed(1) }),
8440
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("td", { className: "is-num", children: [
8423
8441
  pct(bonus).toFixed(0),
8424
8442
  "%"
8425
8443
  ] })
8426
8444
  ] }) : null,
8427
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("tr", { style: { background: "var(--surface-2)" }, children: [
8428
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("td", { style: { fontWeight: 700 }, children: "Campus total" }),
8429
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("td", {}),
8430
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: money(spendTotal) }),
8431
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: grand.toFixed(1) }),
8432
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: "100%" })
8445
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("tr", { style: { background: "var(--surface-2)" }, children: [
8446
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("td", { style: { fontWeight: 700 }, children: "Campus total" }),
8447
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("td", {}),
8448
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: money(spendTotal) }),
8449
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: grand.toFixed(1) }),
8450
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: "100%" })
8433
8451
  ] })
8434
8452
  ] })
8435
8453
  ] }) : null
@@ -8437,8 +8455,8 @@ function ChannelContribution({
8437
8455
  }
8438
8456
 
8439
8457
  // src/components/planner/BudgetReallocator.tsx
8440
- var React36 = __toESM(require("react"), 1);
8441
- var import_jsx_runtime68 = require("react/jsx-runtime");
8458
+ var React37 = __toESM(require("react"), 1);
8459
+ var import_jsx_runtime69 = require("react/jsx-runtime");
8442
8460
  var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
8443
8461
  function BudgetReallocator({
8444
8462
  campus,
@@ -8453,8 +8471,8 @@ function BudgetReallocator({
8453
8471
  onCancel,
8454
8472
  className = ""
8455
8473
  }) {
8456
- const [draft, setDraft] = React36.useState(spend);
8457
- React36.useEffect(() => setDraft(spend), [spend]);
8474
+ const [draft, setDraft] = React37.useState(spend);
8475
+ React37.useEffect(() => setDraft(spend), [spend]);
8458
8476
  const dirty = draft !== spend;
8459
8477
  const nextCrp = scoreFor ? scoreFor(draft) : crp;
8460
8478
  const nextBand = bandFor(nextCrp);
@@ -8469,24 +8487,24 @@ function BudgetReallocator({
8469
8487
  setDraft(spend);
8470
8488
  if (onCancel) onCancel();
8471
8489
  };
8472
- return /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
8490
+ return /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)(
8473
8491
  "div",
8474
8492
  {
8475
8493
  className: ["fd-stack", className].filter(Boolean).join(" "),
8476
8494
  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)" },
8477
8495
  children: [
8478
- /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
8479
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { className: "fd-h4", style: { flex: 1, minWidth: 140 }, children: campus }),
8480
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(CsiBadge, { band: nowBand, crp, size: "medium" }),
8481
- dirty ? /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(import_jsx_runtime68.Fragment, { children: [
8482
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("i", { className: "ph ph-arrow-right fd-muted", "aria-hidden": "true" }),
8483
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(CsiBadge, { band: nextBand, crp: nextCrp, size: "medium", preview: true })
8496
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
8497
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-h4", style: { flex: 1, minWidth: 140 }, children: campus }),
8498
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(CsiBadge, { band: nowBand, crp, size: "medium" }),
8499
+ dirty ? /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)(import_jsx_runtime69.Fragment, { children: [
8500
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("i", { className: "ph ph-arrow-right fd-muted", "aria-hidden": "true" }),
8501
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(CsiBadge, { band: nextBand, crp: nextCrp, size: "medium", preview: true })
8484
8502
  ] }) : null
8485
8503
  ] }),
8486
- /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "fd-slider", children: [
8487
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
8488
- dirty ? /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("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,
8489
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
8504
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-slider", children: [
8505
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
8506
+ dirty ? /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("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,
8507
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
8490
8508
  "input",
8491
8509
  {
8492
8510
  type: "range",
@@ -8502,13 +8520,13 @@ function BudgetReallocator({
8502
8520
  }
8503
8521
  )
8504
8522
  ] }),
8505
- /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
8506
- /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("span", { className: "fd-stack", style: { gap: 2, flex: 1, minWidth: 150 }, children: [
8507
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { className: "fd-num", style: { fontSize: 19, fontWeight: 700 }, children: "$" + draft.toLocaleString() }),
8508
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { className: "fd-body-sm fd-muted", children: "Arrow keys step $100, shift+arrow $1,000. Escape reverts." })
8523
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
8524
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "fd-stack", style: { gap: 2, flex: 1, minWidth: 150 }, children: [
8525
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-num", style: { fontSize: 19, fontWeight: 700 }, children: "$" + draft.toLocaleString() }),
8526
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-body-sm fd-muted", children: "Arrow keys step $100, shift+arrow $1,000. Escape reverts." })
8509
8527
  ] }),
8510
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("button", { type: "button", className: "fd-btn fd-btn-ghost", disabled: !dirty, onClick: revert, children: "Cancel" }),
8511
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
8528
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("button", { type: "button", className: "fd-btn fd-btn-ghost", disabled: !dirty, onClick: revert, children: "Cancel" }),
8529
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
8512
8530
  "button",
8513
8531
  {
8514
8532
  type: "button",
@@ -8527,7 +8545,7 @@ function BudgetReallocator({
8527
8545
  }
8528
8546
 
8529
8547
  // src/components/planner/SurroundSound.tsx
8530
- var import_jsx_runtime69 = require("react/jsx-runtime");
8548
+ var import_jsx_runtime70 = require("react/jsx-runtime");
8531
8549
  var CATEGORIES = [
8532
8550
  { key: "ooh", label: "OOH", icon: "flag-banner", color: "var(--ch-ooh)" },
8533
8551
  { key: "transit", label: "Transit", icon: "bus", color: "var(--ch-transit)" },
@@ -8539,26 +8557,26 @@ var CATEGORIES = [
8539
8557
  function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost, className = "" }) {
8540
8558
  const earned = Math.max(0, Math.min(1, bonusPct / bonusMax));
8541
8559
  const single = present.length <= 2;
8542
- return /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, children: [
8543
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: CATEGORIES.map((c) => {
8560
+ return /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, children: [
8561
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: CATEGORIES.map((c) => {
8544
8562
  const on = present.includes(c.key);
8545
- return /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)(
8563
+ return /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)(
8546
8564
  "span",
8547
8565
  {
8548
8566
  title: c.label + (on ? " \u2014 present" : " \u2014 not bought"),
8549
8567
  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)" },
8550
8568
  children: [
8551
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("i", { className: "ph ph-" + c.icon, style: { fontSize: 19, color: on ? c.color : "var(--text-muted)" }, "aria-hidden": "true" }),
8552
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { style: { fontSize: 10.5, fontWeight: 700 }, children: c.label })
8569
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-" + c.icon, style: { fontSize: 19, color: on ? c.color : "var(--text-muted)" }, "aria-hidden": "true" }),
8570
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("span", { style: { fontSize: 10.5, fontWeight: 700 }, children: c.label })
8553
8571
  ]
8554
8572
  },
8555
8573
  c.key
8556
8574
  );
8557
8575
  }) }),
8558
- /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-stack", style: { gap: 8 }, children: [
8559
- /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
8560
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-label-lg", children: "Surround-sound bonus earned" }),
8561
- /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "fd-num", style: { color: single ? "var(--warn-text)" : "var(--csi-3-mark)", fontWeight: 700 }, children: [
8576
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("div", { className: "fd-stack", style: { gap: 8 }, children: [
8577
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
8578
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("span", { className: "fd-label-lg", children: "Surround-sound bonus earned" }),
8579
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { className: "fd-num", style: { color: single ? "var(--warn-text)" : "var(--csi-3-mark)", fontWeight: 700 }, children: [
8562
8580
  "+",
8563
8581
  bonusPct,
8564
8582
  "% of +",
@@ -8566,8 +8584,8 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
8566
8584
  "%"
8567
8585
  ] })
8568
8586
  ] }),
8569
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("div", { style: { height: 8, borderRadius: "var(--r-xs)", background: "var(--surface-3)", overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("div", { style: { height: "100%", width: earned * 100 + "%", background: "var(--csi-3-mark)", borderRadius: "inherit", transition: "width var(--dur-slow) var(--ease)" } }) }),
8570
- /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: [
8587
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("div", { style: { height: 8, borderRadius: "var(--r-xs)", background: "var(--surface-3)", overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("div", { style: { height: "100%", width: earned * 100 + "%", background: "var(--csi-3-mark)", borderRadius: "inherit", transition: "width var(--dur-slow) var(--ease)" } }) }),
8588
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: [
8571
8589
  present.length,
8572
8590
  " of 6 channel categories present.",
8573
8591
  " ",
@@ -8579,7 +8597,7 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
8579
8597
  }
8580
8598
 
8581
8599
  // src/components/planner/Importance.tsx
8582
- var import_jsx_runtime70 = require("react/jsx-runtime");
8600
+ var import_jsx_runtime71 = require("react/jsx-runtime");
8583
8601
  var IMPORTANCE_LEVELS = [
8584
8602
  { id: "nudge", rank: 1, label: "Nudge", icon: "feather", description: "Breaks a tie, nothing more." },
8585
8603
  { id: "lean", rank: 2, label: "Lean", icon: "arrow-bend-up-right", description: "A mild preference between otherwise equal options." },
@@ -8609,23 +8627,23 @@ function importanceTokens(id) {
8609
8627
  function ImportanceTag({ level, showLabel = true, size = "sm", className = "" }) {
8610
8628
  const lvl = importanceLevel(level);
8611
8629
  const t = importanceTokens(level);
8612
- return /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)(
8630
+ return /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(
8613
8631
  "span",
8614
8632
  {
8615
8633
  className: ["fd-imp-tag", size === "md" ? "is-md" : "", className].filter(Boolean).join(" "),
8616
8634
  style: { background: t.fill, borderColor: t.edge, color: t.text },
8617
8635
  title: lvl.label + " \u2014 " + lvl.description,
8618
8636
  children: [
8619
- /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-" + lvl.icon, "aria-hidden": "true" }),
8620
- showLabel ? lvl.label : /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("span", { className: "fd-sr", children: lvl.label })
8637
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("i", { className: "ph ph-" + lvl.icon, "aria-hidden": "true" }),
8638
+ showLabel ? lvl.label : /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("span", { className: "fd-sr", children: lvl.label })
8621
8639
  ]
8622
8640
  }
8623
8641
  );
8624
8642
  }
8625
8643
 
8626
8644
  // src/components/planner/PreferenceMeter.tsx
8627
- var React37 = __toESM(require("react"), 1);
8628
- var import_jsx_runtime71 = require("react/jsx-runtime");
8645
+ var React38 = __toESM(require("react"), 1);
8646
+ var import_jsx_runtime72 = require("react/jsx-runtime");
8629
8647
  function preferenceScore(criteria) {
8630
8648
  const earned = criteria.reduce((n, c) => n + (Number(c.earned) || 0), 0);
8631
8649
  const weight = criteria.reduce((n, c) => n + (Number(c.weight) || 0), 0);
@@ -8654,8 +8672,8 @@ function PreferenceMeter({
8654
8672
  className = ""
8655
8673
  }) {
8656
8674
  const value = score == null ? preferenceScore(criteria) : score;
8657
- const segments = React37.useMemo(() => preferenceSegments(criteria), [criteria]);
8658
- return /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
8675
+ const segments = React38.useMemo(() => preferenceSegments(criteria), [criteria]);
8676
+ return /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(
8659
8677
  ScoreMeter,
8660
8678
  {
8661
8679
  score: value,
@@ -8667,22 +8685,22 @@ function PreferenceMeter({
8667
8685
  placement,
8668
8686
  className,
8669
8687
  breakdownLabel: breakdownTitle,
8670
- breakdown: /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("div", { className: "fd-prefbreak", children: [
8671
- /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("div", { className: "fd-prefbreak-head", children: [
8672
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("span", { className: "fd-label-lg", children: breakdownTitle }),
8673
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("span", { className: "fd-prefbreak-score fd-tabular", children: Math.round(value) })
8688
+ breakdown: /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("div", { className: "fd-prefbreak", children: [
8689
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("div", { className: "fd-prefbreak-head", children: [
8690
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fd-label-lg", children: breakdownTitle }),
8691
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fd-prefbreak-score fd-tabular", children: Math.round(value) })
8674
8692
  ] }),
8675
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("ul", { className: "fd-prefbreak-list", children: criteria.map((c) => {
8693
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("ul", { className: "fd-prefbreak-list", children: criteria.map((c) => {
8676
8694
  const pct = c.weight > 0 ? Math.round((Number(c.earned) || 0) / c.weight * 100) : 0;
8677
- return /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("li", { className: pct === 0 ? "fd-prefbreak-item is-unmet" : "fd-prefbreak-item", children: [
8678
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(ImportanceTag, { level: c.importance }),
8679
- /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("span", { className: "fd-prefbreak-text", children: [
8680
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("span", { className: "fd-prefbreak-label", children: c.label }),
8681
- c.note ? /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("span", { className: "fd-prefbreak-note", children: c.note }) : null
8695
+ return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("li", { className: pct === 0 ? "fd-prefbreak-item is-unmet" : "fd-prefbreak-item", children: [
8696
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(ImportanceTag, { level: c.importance }),
8697
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-prefbreak-text", children: [
8698
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fd-prefbreak-label", children: c.label }),
8699
+ c.note ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fd-prefbreak-note", children: c.note }) : null
8682
8700
  ] }),
8683
- /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("span", { className: "fd-prefbreak-val fd-tabular", children: [
8701
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-prefbreak-val fd-tabular", children: [
8684
8702
  Math.round(Number(c.earned) || 0),
8685
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("span", { className: "fd-prefbreak-sep", children: "/" }),
8703
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fd-prefbreak-sep", children: "/" }),
8686
8704
  Math.round(c.weight)
8687
8705
  ] })
8688
8706
  ] }, c.id);
@@ -8693,10 +8711,10 @@ function PreferenceMeter({
8693
8711
  }
8694
8712
 
8695
8713
  // src/components/chat/AgentChatPanel.tsx
8696
- var React43 = __toESM(require("react"), 1);
8714
+ var React44 = __toESM(require("react"), 1);
8697
8715
 
8698
8716
  // src/components/chat/chatEngine.ts
8699
- var React38 = __toESM(require("react"), 1);
8717
+ var React39 = __toESM(require("react"), 1);
8700
8718
  var CHAT_UNAVAILABLE = "chat_unavailable";
8701
8719
  var JOB_PENDING = ["queued", "running"];
8702
8720
  var JOB_SUCCESS = ["completed", "recovered"];
@@ -8750,22 +8768,22 @@ function useChatEngine(opts) {
8750
8768
  onClear,
8751
8769
  onFeedback
8752
8770
  } = opts || {};
8753
- const [status, setStatus] = React38.useState("idle");
8754
- const [threadId, setThreadId] = React38.useState(null);
8755
- const [messages, setMessages] = React38.useState([]);
8756
- const [queue, setQueue] = React38.useState([]);
8757
- const [fatal, setFatal] = React38.useState(null);
8758
- const [busy, setBusy] = React38.useState(false);
8759
- const [turnStartedAt, setTurnStartedAt] = React38.useState(null);
8760
- const listRef = React38.useRef([]);
8761
- const queueRef = React38.useRef([]);
8762
- const busyRef = React38.useRef(false);
8763
- const stoppedRef = React38.useRef(false);
8764
- const abortRef = React38.useRef(null);
8765
- const serverCount = React38.useRef(0);
8766
- const threadRef = React38.useRef(null);
8767
- const mounted = React38.useRef(true);
8768
- React38.useEffect(() => {
8771
+ const [status, setStatus] = React39.useState("idle");
8772
+ const [threadId, setThreadId] = React39.useState(null);
8773
+ const [messages, setMessages] = React39.useState([]);
8774
+ const [queue, setQueue] = React39.useState([]);
8775
+ const [fatal, setFatal] = React39.useState(null);
8776
+ const [busy, setBusy] = React39.useState(false);
8777
+ const [turnStartedAt, setTurnStartedAt] = React39.useState(null);
8778
+ const listRef = React39.useRef([]);
8779
+ const queueRef = React39.useRef([]);
8780
+ const busyRef = React39.useRef(false);
8781
+ const stoppedRef = React39.useRef(false);
8782
+ const abortRef = React39.useRef(null);
8783
+ const serverCount = React39.useRef(0);
8784
+ const threadRef = React39.useRef(null);
8785
+ const mounted = React39.useRef(true);
8786
+ React39.useEffect(() => {
8769
8787
  mounted.current = true;
8770
8788
  return () => {
8771
8789
  mounted.current = false;
@@ -8787,14 +8805,14 @@ function useChatEngine(opts) {
8787
8805
  }
8788
8806
  return false;
8789
8807
  };
8790
- const loadThread = React38.useCallback(async (id) => {
8808
+ const loadThread = React39.useCallback(async (id) => {
8791
8809
  const data = await apiAdapter.getThread(id);
8792
8810
  const list = [...data && data.messages || []];
8793
8811
  serverCount.current = list.length;
8794
8812
  commit(list);
8795
8813
  return list;
8796
8814
  }, [apiAdapter]);
8797
- React38.useEffect(() => {
8815
+ React39.useEffect(() => {
8798
8816
  if (!apiAdapter) {
8799
8817
  setStatus("idle");
8800
8818
  setFatal(null);
@@ -9007,7 +9025,7 @@ function useChatEngine(opts) {
9007
9025
  await dispatchTurn(turn);
9008
9026
  }
9009
9027
  }
9010
- const send = React38.useCallback((text, attachments) => {
9028
+ const send = React39.useCallback((text, attachments) => {
9011
9029
  const body = (text || "").trim();
9012
9030
  if (!body && !(attachments && attachments.length)) return;
9013
9031
  if (status === "disconnected") return;
@@ -9017,7 +9035,7 @@ function useChatEngine(opts) {
9017
9035
  stoppedRef.current = false;
9018
9036
  drain();
9019
9037
  }, [status]);
9020
- const stop = React38.useCallback(() => {
9038
+ const stop = React39.useCallback(() => {
9021
9039
  stoppedRef.current = true;
9022
9040
  const ac = abortRef.current;
9023
9041
  if (ac) {
@@ -9036,11 +9054,11 @@ function useChatEngine(opts) {
9036
9054
  store.del(STORAGE_PREFIX + threadRef.current);
9037
9055
  }
9038
9056
  }, [apiAdapter]);
9039
- const removeQueued = React38.useCallback((id) => {
9057
+ const removeQueued = React39.useCallback((id) => {
9040
9058
  queueRef.current = queueRef.current.filter((t) => t.id !== id);
9041
9059
  setQueue(queueRef.current.slice());
9042
9060
  }, []);
9043
- const retry = React38.useCallback(() => {
9061
+ const retry = React39.useCallback(() => {
9044
9062
  const list = listRef.current;
9045
9063
  let at = -1;
9046
9064
  for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
@@ -9056,19 +9074,19 @@ function useChatEngine(opts) {
9056
9074
  setQueue(queueRef.current.slice());
9057
9075
  drain();
9058
9076
  }, []);
9059
- const clear = React38.useCallback(() => {
9077
+ const clear = React39.useCallback(() => {
9060
9078
  commit([]);
9061
9079
  serverCount.current = 0;
9062
9080
  queueRef.current = [];
9063
9081
  setQueue([]);
9064
9082
  onClear && onClear();
9065
9083
  }, [onClear]);
9066
- const setFeedback = React38.useCallback((id, value) => {
9084
+ const setFeedback = React39.useCallback((id, value) => {
9067
9085
  patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
9068
9086
  const msg = listRef.current.find((m) => m.id === id);
9069
9087
  onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
9070
9088
  }, [onFeedback]);
9071
- const reload = React38.useCallback(async () => {
9089
+ const reload = React39.useCallback(async () => {
9072
9090
  if (!threadRef.current) return;
9073
9091
  setStatus("loading");
9074
9092
  try {
@@ -9106,11 +9124,11 @@ var ChatKit = {
9106
9124
  };
9107
9125
 
9108
9126
  // src/components/chat/ChatTranscript.tsx
9109
- var React40 = __toESM(require("react"), 1);
9127
+ var React41 = __toESM(require("react"), 1);
9110
9128
 
9111
9129
  // src/components/chat/ChatTurn.tsx
9112
- var React39 = __toESM(require("react"), 1);
9113
- var import_jsx_runtime72 = require("react/jsx-runtime");
9130
+ var React40 = __toESM(require("react"), 1);
9131
+ var import_jsx_runtime73 = require("react/jsx-runtime");
9114
9132
  function JsonView({ value }) {
9115
9133
  let text;
9116
9134
  try {
@@ -9118,67 +9136,67 @@ function JsonView({ value }) {
9118
9136
  } catch (e) {
9119
9137
  text = String(value);
9120
9138
  }
9121
- return /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(CodeBlock, { code: text, language: "json", collapseAfter: 18 });
9139
+ return /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(CodeBlock, { code: text, language: "json", collapseAfter: 18 });
9122
9140
  }
9123
9141
  function PacketCard({ packet, schema, render, onApply, applied }) {
9124
9142
  if (!packet) return null;
9125
9143
  const s = schema || {};
9126
9144
  const invalid = packet.valid === false;
9127
9145
  const title = s.heading || packet.type;
9128
- return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("section", { className: "fdc-packet" + (invalid ? " is-invalid" : ""), "aria-label": title, children: [
9129
- /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("header", { className: "fdc-packet-head", children: [
9130
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-" + (s.icon || "package"), "aria-hidden": "true" }),
9131
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fdc-packet-title", children: title }),
9132
- packet.repaired ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fdc-packet-badge", children: "Repaired" }) : null,
9133
- invalid ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fdc-packet-badge is-danger", children: "Invalid" }) : null
9146
+ return /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("section", { className: "fdc-packet" + (invalid ? " is-invalid" : ""), "aria-label": title, children: [
9147
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("header", { className: "fdc-packet-head", children: [
9148
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-" + (s.icon || "package"), "aria-hidden": "true" }),
9149
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fdc-packet-title", children: title }),
9150
+ packet.repaired ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fdc-packet-badge", children: "Repaired" }) : null,
9151
+ invalid ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fdc-packet-badge is-danger", children: "Invalid" }) : null
9134
9152
  ] }),
9135
- invalid ? /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("div", { className: "fdc-packet-alert", role: "alert", children: [
9136
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
9137
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { children: packet.error || "This result failed validation and can\u2019t be applied." })
9138
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("div", { className: "fdc-packet-body", children: render ? render(packet) : /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(JsonView, { value: packet.payload }) }),
9139
- !invalid && onApply ? /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("footer", { className: "fdc-packet-foot", children: [
9140
- packet.repaired ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fdc-packet-note", children: "Corrected by the backend after a first attempt." }) : /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", {}),
9141
- /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", disabled: applied, onClick: () => onApply(packet), children: [
9142
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-" + (applied ? "check" : "arrow-square-in"), "aria-hidden": "true" }),
9153
+ invalid ? /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("div", { className: "fdc-packet-alert", role: "alert", children: [
9154
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
9155
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { children: packet.error || "This result failed validation and can\u2019t be applied." })
9156
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("div", { className: "fdc-packet-body", children: render ? render(packet) : /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(JsonView, { value: packet.payload }) }),
9157
+ !invalid && onApply ? /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("footer", { className: "fdc-packet-foot", children: [
9158
+ packet.repaired ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fdc-packet-note", children: "Corrected by the backend after a first attempt." }) : /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", {}),
9159
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", disabled: applied, onClick: () => onApply(packet), children: [
9160
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-" + (applied ? "check" : "arrow-square-in"), "aria-hidden": "true" }),
9143
9161
  applied ? "Applied" : s.applyLabel || "Apply"
9144
9162
  ] })
9145
9163
  ] }) : null
9146
9164
  ] });
9147
9165
  }
9148
9166
  function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
9149
- const [open, setOpen] = React39.useState(defaultOpen);
9167
+ const [open, setOpen] = React40.useState(defaultOpen);
9150
9168
  if (!text) return null;
9151
- return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("div", { className: "fdc-think" + (open ? " is-open" : ""), children: [
9152
- /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
9153
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-brain", "aria-hidden": "true" }),
9154
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { children: streaming ? "Thinking" : durationMs ? "Thought for " + formatDuration(durationMs) : "Thought process" }),
9155
- streaming ? /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fdc-dots", "aria-hidden": "true", children: [
9156
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", {}),
9157
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", {}),
9158
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", {})
9169
+ return /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("div", { className: "fdc-think" + (open ? " is-open" : ""), children: [
9170
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
9171
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-brain", "aria-hidden": "true" }),
9172
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { children: streaming ? "Thinking" : durationMs ? "Thought for " + formatDuration(durationMs) : "Thought process" }),
9173
+ streaming ? /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("span", { className: "fdc-dots", "aria-hidden": "true", children: [
9174
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", {}),
9175
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", {}),
9176
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", {})
9159
9177
  ] }) : null,
9160
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" })
9178
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" })
9161
9179
  ] }),
9162
- open ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("div", { className: "fdc-think-body", children: text }) : null
9180
+ open ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("div", { className: "fdc-think-body", children: text }) : null
9163
9181
  ] });
9164
9182
  }
9165
9183
  function Citations({ items = [], onOpen }) {
9166
- const [open, setOpen] = React39.useState(false);
9184
+ const [open, setOpen] = React40.useState(false);
9167
9185
  if (!items.length) return null;
9168
- return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("div", { className: "fdc-cites", children: [
9169
- /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
9170
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-quotes", "aria-hidden": "true" }),
9171
- /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { children: [
9186
+ return /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("div", { className: "fdc-cites", children: [
9187
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
9188
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-quotes", "aria-hidden": "true" }),
9189
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("span", { children: [
9172
9190
  items.length,
9173
9191
  " source",
9174
9192
  items.length === 1 ? "" : "s"
9175
9193
  ] }),
9176
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" })
9194
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" })
9177
9195
  ] }),
9178
- open ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("ol", { className: "fdc-cites-list", children: items.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("li", { children: [
9179
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fdc-cite-n fd-tabular", children: c.marker || i + 1 }),
9180
- c.url ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("a", { href: c.url, target: "_blank", rel: "noopener noreferrer", onClick: onOpen ? (e) => onOpen(c, e) : void 0, children: c.title || c.url }) : /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { children: c.title || "Source" }),
9181
- c.detail ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fdc-cite-detail", children: c.detail }) : null
9196
+ open ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("ol", { className: "fdc-cites-list", children: items.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("li", { children: [
9197
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fdc-cite-n fd-tabular", children: c.marker || i + 1 }),
9198
+ c.url ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("a", { href: c.url, target: "_blank", rel: "noopener noreferrer", onClick: onOpen ? (e) => onOpen(c, e) : void 0, children: c.title || c.url }) : /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { children: c.title || "Source" }),
9199
+ c.detail ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fdc-cite-detail", children: c.detail }) : null
9182
9200
  ] }, c.id || i)) }) : null
9183
9201
  ] });
9184
9202
  }
@@ -9189,29 +9207,29 @@ function clampText(text, max) {
9189
9207
  return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
9190
9208
  }
9191
9209
  function MessageBody({ message: m, ctx }) {
9192
- const [expanded, setExpanded] = React39.useState(false);
9210
+ const [expanded, setExpanded] = React40.useState(false);
9193
9211
  const isUser = m.role === "user";
9194
9212
  const raw = m.text || "";
9195
9213
  const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
9196
9214
  const body = clamped != null ? clamped : raw;
9197
9215
  const showMd = ctx.markdown && !isUser;
9198
- return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("div", { className: "fdc-body", children: [
9199
- m.thinking && ctx.showThinking ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(ThinkingBlock, { text: m.thinking, durationMs: m.thinkingMs, streaming: m.streaming && !m.text }) : null,
9200
- m.steps && m.steps.length && ctx.showSteps ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(StepList, { steps: m.steps, defaultOpen: m.steps.some((s) => s.status === "running"), dense: true }) : null,
9201
- body ? /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("div", { className: "fdc-text" + (isUser ? " is-user" : ""), children: [
9202
- showMd ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(Markdown, { source: body, headingOffset: 2, codeProps: { collapseAfter: 22 }, renderCitation: ctx.renderCitation }) : /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("div", { className: "fdc-plain", children: body }),
9203
- m.streaming ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fdc-caret", "aria-hidden": "true" }) : null
9216
+ return /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("div", { className: "fdc-body", children: [
9217
+ m.thinking && ctx.showThinking ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(ThinkingBlock, { text: m.thinking, durationMs: m.thinkingMs, streaming: m.streaming && !m.text }) : null,
9218
+ m.steps && m.steps.length && ctx.showSteps ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(StepList, { steps: m.steps, defaultOpen: m.steps.some((s) => s.status === "running"), dense: true }) : null,
9219
+ body ? /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("div", { className: "fdc-text" + (isUser ? " is-user" : ""), children: [
9220
+ showMd ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(Markdown, { source: body, headingOffset: 2, codeProps: { collapseAfter: 22 }, renderCitation: ctx.renderCitation }) : /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("div", { className: "fdc-plain", children: body }),
9221
+ m.streaming ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fdc-caret", "aria-hidden": "true" }) : null
9204
9222
  ] }) : null,
9205
- clamped != null ? /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(true), children: [
9206
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-caret-down", "aria-hidden": "true" }),
9223
+ clamped != null ? /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(true), children: [
9224
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-caret-down", "aria-hidden": "true" }),
9207
9225
  "Show more",
9208
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fdc-more-len fd-tabular", children: raw.length < 2e3 ? raw.length.toLocaleString() + " characters" : Math.round(raw.length / 100) / 10 + "k characters" })
9209
- ] }) : expanded && ctx.maxVisibleChars && raw.length > ctx.maxVisibleChars ? /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(false), children: [
9210
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-caret-up", "aria-hidden": "true" }),
9226
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fdc-more-len fd-tabular", children: raw.length < 2e3 ? raw.length.toLocaleString() + " characters" : Math.round(raw.length / 100) / 10 + "k characters" })
9227
+ ] }) : expanded && ctx.maxVisibleChars && raw.length > ctx.maxVisibleChars ? /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(false), children: [
9228
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-caret-up", "aria-hidden": "true" }),
9211
9229
  "Show less"
9212
9230
  ] }) : null,
9213
- m.attachments && m.attachments.length ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(FileGrid, { files: m.attachments, onOpen: ctx.onOpenAttachment, tiles: true, maxHeight: ctx.attachmentHeight || 220, compact: ctx.narrow }) : null,
9214
- m.packet ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(
9231
+ m.attachments && m.attachments.length ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(FileGrid, { files: m.attachments, onOpen: ctx.onOpenAttachment, tiles: true, maxHeight: ctx.attachmentHeight || 220, compact: ctx.narrow }) : null,
9232
+ m.packet ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(
9215
9233
  PacketCard,
9216
9234
  {
9217
9235
  packet: m.packet,
@@ -9221,44 +9239,44 @@ function MessageBody({ message: m, ctx }) {
9221
9239
  applied: ctx.appliedPackets && ctx.appliedPackets[m.id]
9222
9240
  }
9223
9241
  ) : null,
9224
- m.citations && m.citations.length ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(Citations, { items: m.citations, onOpen: ctx.onOpenCitation }) : null,
9225
- m.working ? /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("div", { className: "fdc-working", role: "status", children: [
9226
- /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fdc-dots", "aria-hidden": "true", children: [
9227
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", {}),
9228
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", {}),
9229
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", {})
9242
+ m.citations && m.citations.length ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(Citations, { items: m.citations, onOpen: ctx.onOpenCitation }) : null,
9243
+ m.working ? /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("div", { className: "fdc-working", role: "status", children: [
9244
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("span", { className: "fdc-dots", "aria-hidden": "true", children: [
9245
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", {}),
9246
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", {}),
9247
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", {})
9230
9248
  ] }),
9231
- /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fdc-working-label", children: [
9249
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("span", { className: "fdc-working-label", children: [
9232
9250
  m.resumed ? "Resuming" : "Working",
9233
- m.job && m.job.status ? /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fdc-working-job", children: [
9251
+ m.job && m.job.status ? /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("span", { className: "fdc-working-job", children: [
9234
9252
  " \xB7 ",
9235
9253
  m.job.status
9236
9254
  ] }) : null,
9237
- m.job && m.job.detail ? /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fdc-working-job", children: [
9255
+ m.job && m.job.detail ? /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("span", { className: "fdc-working-job", children: [
9238
9256
  " \xB7 ",
9239
9257
  m.job.detail
9240
9258
  ] }) : null
9241
9259
  ] }),
9242
- m.jobId ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fdc-working-id fd-mono", children: String(m.jobId).slice(0, 12) }) : null
9260
+ m.jobId ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fdc-working-id fd-mono", children: String(m.jobId).slice(0, 12) }) : null
9243
9261
  ] }) : null,
9244
- m.stopped ? /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("div", { className: "fdc-stopped", children: [
9245
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
9262
+ m.stopped ? /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("div", { className: "fdc-stopped", children: [
9263
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
9246
9264
  "Stopped"
9247
9265
  ] }) : null,
9248
- m.error ? /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("div", { className: "fdc-error", role: "alert", children: [
9249
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
9250
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fdc-error-text", children: ctx.errorCopy ? ctx.errorCopy(m.error) : m.error }),
9251
- m.retryable && ctx.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("button", { type: "button", className: "fdc-error-retry", onClick: ctx.onRetry, children: [
9252
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
9266
+ m.error ? /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("div", { className: "fdc-error", role: "alert", children: [
9267
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
9268
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fdc-error-text", children: ctx.errorCopy ? ctx.errorCopy(m.error) : m.error }),
9269
+ m.retryable && ctx.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("button", { type: "button", className: "fdc-error-retry", onClick: ctx.onRetry, children: [
9270
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
9253
9271
  "Retry"
9254
9272
  ] }) : null
9255
9273
  ] }) : null
9256
9274
  ] });
9257
9275
  }
9258
9276
  function useCopyRun() {
9259
- const [done, setDone] = React39.useState(false);
9260
- const t = React39.useRef(null);
9261
- React39.useEffect(() => () => {
9277
+ const [done, setDone] = React40.useState(false);
9278
+ const t = React40.useRef(null);
9279
+ React40.useEffect(() => () => {
9262
9280
  if (t.current) clearTimeout(t.current);
9263
9281
  }, []);
9264
9282
  return [done, (text) => {
@@ -9278,16 +9296,16 @@ function RunActions({ group, ctx }) {
9278
9296
  const isAssistant = group.role === "assistant";
9279
9297
  const fb = last.feedback;
9280
9298
  if (!ctx.messageActions) return null;
9281
- return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("div", { className: "fdc-actions", role: "group", "aria-label": "Message actions", children: [
9282
- /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("button", { type: "button", className: "fdc-act" + (copied ? " is-done" : ""), onClick: () => copy(markdownToText(text)), "aria-label": "Copy message", children: [
9283
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-" + (copied ? "check" : "copy"), "aria-hidden": "true" }),
9284
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fdc-act-label", children: copied ? "Copied" : "Copy" })
9299
+ return /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("div", { className: "fdc-actions", role: "group", "aria-label": "Message actions", children: [
9300
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("button", { type: "button", className: "fdc-act" + (copied ? " is-done" : ""), onClick: () => copy(markdownToText(text)), "aria-label": "Copy message", children: [
9301
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-" + (copied ? "check" : "copy"), "aria-hidden": "true" }),
9302
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fdc-act-label", children: copied ? "Copied" : "Copy" })
9285
9303
  ] }),
9286
- isAssistant && ctx.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("button", { type: "button", className: "fdc-act", onClick: ctx.onRetry, "aria-label": "Retry this turn", children: /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
9287
- group.role === "user" && ctx.onEdit ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("button", { type: "button", className: "fdc-act", onClick: () => ctx.onEdit(last), "aria-label": "Edit and resend", children: /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-pencil-simple", "aria-hidden": "true" }) }) : null,
9288
- isAssistant && ctx.onFeedback ? /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)(React39.Fragment, { children: [
9289
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("button", { type: "button", className: "fdc-act" + (fb === "up" ? " is-on" : ""), onClick: () => ctx.onFeedback(last.id, "up"), "aria-pressed": fb === "up", "aria-label": "Good response", children: /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-thumbs-up", "aria-hidden": "true" }) }),
9290
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("button", { type: "button", className: "fdc-act" + (fb === "down" ? " is-on" : ""), onClick: () => ctx.onFeedback(last.id, "down"), "aria-pressed": fb === "down", "aria-label": "Bad response", children: /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-thumbs-down", "aria-hidden": "true" }) })
9304
+ isAssistant && ctx.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("button", { type: "button", className: "fdc-act", onClick: ctx.onRetry, "aria-label": "Retry this turn", children: /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
9305
+ group.role === "user" && ctx.onEdit ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("button", { type: "button", className: "fdc-act", onClick: () => ctx.onEdit(last), "aria-label": "Edit and resend", children: /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-pencil-simple", "aria-hidden": "true" }) }) : null,
9306
+ isAssistant && ctx.onFeedback ? /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)(React40.Fragment, { children: [
9307
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("button", { type: "button", className: "fdc-act" + (fb === "up" ? " is-on" : ""), onClick: () => ctx.onFeedback(last.id, "up"), "aria-pressed": fb === "up", "aria-label": "Good response", children: /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-thumbs-up", "aria-hidden": "true" }) }),
9308
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("button", { type: "button", className: "fdc-act" + (fb === "down" ? " is-on" : ""), onClick: () => ctx.onFeedback(last.id, "down"), "aria-pressed": fb === "down", "aria-label": "Bad response", children: /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-thumbs-down", "aria-hidden": "true" }) })
9291
9309
  ] }) : null,
9292
9310
  ctx.extraActions ? ctx.extraActions(group) : null
9293
9311
  ] });
@@ -9297,22 +9315,22 @@ function ChatTurn({ group, ctx }) {
9297
9315
  const name = isUser ? ctx.userName : group.author || ctx.assistantName;
9298
9316
  const avatar = isUser ? ctx.userAvatar : ctx.assistantAvatar;
9299
9317
  const stamp = group.messages[0].timestamp;
9300
- return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("article", { className: "fdc-turn is-" + group.role, "aria-label": String(name) + (stamp ? " at " + formatClock(stamp) : ""), children: [
9301
- /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("div", { className: "fdc-turn-head", children: [
9302
- ctx.showAvatars ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fdc-avatar is-" + group.role, "aria-hidden": "true", children: avatar ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("img", { src: avatar, alt: "" }) : isUser ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fdc-avatar-txt", children: (name || "You").slice(0, 1).toUpperCase() }) : /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-" + (ctx.assistantIcon || "sparkle") }) }) : null,
9303
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fdc-who", children: name }),
9304
- stamp ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(RelativeTime, { className: "fdc-when", value: stamp }) : null,
9305
- group.messages.some((m) => m.model) ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fdc-turn-model", children: group.messages.find((m) => m.model).model }) : null
9318
+ return /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("article", { className: "fdc-turn is-" + group.role, "aria-label": String(name) + (stamp ? " at " + formatClock(stamp) : ""), children: [
9319
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("div", { className: "fdc-turn-head", children: [
9320
+ ctx.showAvatars ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fdc-avatar is-" + group.role, "aria-hidden": "true", children: avatar ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("img", { src: avatar, alt: "" }) : isUser ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fdc-avatar-txt", children: (name || "You").slice(0, 1).toUpperCase() }) : /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-" + (ctx.assistantIcon || "sparkle") }) }) : null,
9321
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fdc-who", children: name }),
9322
+ stamp ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(RelativeTime, { className: "fdc-when", value: stamp }) : null,
9323
+ group.messages.some((m) => m.model) ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fdc-turn-model", children: group.messages.find((m) => m.model).model }) : null
9306
9324
  ] }),
9307
- /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("div", { className: "fdc-turn-body", children: [
9308
- group.messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("div", { className: "fdc-msg" + (m.pending ? " is-pending" : ""), children: /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(MessageBody, { message: m, ctx }) }, m.id)),
9309
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(RunActions, { group, ctx })
9325
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("div", { className: "fdc-turn-body", children: [
9326
+ group.messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("div", { className: "fdc-msg" + (m.pending ? " is-pending" : ""), children: /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(MessageBody, { message: m, ctx }) }, m.id)),
9327
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(RunActions, { group, ctx })
9310
9328
  ] })
9311
9329
  ] });
9312
9330
  }
9313
9331
 
9314
9332
  // src/components/chat/ChatTranscript.tsx
9315
- var import_jsx_runtime73 = require("react/jsx-runtime");
9333
+ var import_jsx_runtime74 = require("react/jsx-runtime");
9316
9334
  var GROUP_WINDOW = 6e4;
9317
9335
  var STICK_PX = 100;
9318
9336
  function groupMessages(list) {
@@ -9345,25 +9363,25 @@ function dayLabel(key) {
9345
9363
  }
9346
9364
  function Suggestions({ items = [], onPick }) {
9347
9365
  if (!items.length) return null;
9348
- return /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("div", { className: "fdc-suggest", children: items.map((s, i) => {
9366
+ return /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("div", { className: "fdc-suggest", children: items.map((s, i) => {
9349
9367
  const it = typeof s === "string" ? { label: s, text: s } : s;
9350
- return /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("button", { type: "button", className: "fdc-suggest-item", onClick: () => onPick && onPick(it.text || it.label), children: [
9351
- it.icon ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-" + it.icon, "aria-hidden": "true" }) : null,
9352
- /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("span", { className: "fdc-suggest-text", children: [
9353
- /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fdc-suggest-label", children: it.label }),
9354
- it.description ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fdc-suggest-desc", children: it.description }) : null
9368
+ return /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("button", { type: "button", className: "fdc-suggest-item", onClick: () => onPick && onPick(it.text || it.label), children: [
9369
+ it.icon ? /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("i", { className: "ph ph-" + it.icon, "aria-hidden": "true" }) : null,
9370
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("span", { className: "fdc-suggest-text", children: [
9371
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { className: "fdc-suggest-label", children: it.label }),
9372
+ it.description ? /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { className: "fdc-suggest-desc", children: it.description }) : null
9355
9373
  ] }),
9356
- /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-arrow-up-right fdc-suggest-go", "aria-hidden": "true" })
9374
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("i", { className: "ph ph-arrow-up-right fdc-suggest-go", "aria-hidden": "true" })
9357
9375
  ] }, it.id || i);
9358
9376
  }) });
9359
9377
  }
9360
9378
  function LoadingTurns() {
9361
- return /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("div", { className: "fdc-skel", "aria-hidden": "true", children: [0, 1].map((i) => /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("div", { className: "fdc-skel-turn", children: [
9362
- /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("div", { className: "fd-skel fd-skel-circle", style: { width: 22, height: 22 } }),
9363
- /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("div", { className: "fdc-skel-lines", children: [
9364
- /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("div", { className: "fd-skel", style: { width: i ? "62%" : "44%", height: 11 } }),
9365
- /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("div", { className: "fd-skel", style: { width: i ? "94%" : "78%", height: 11 } }),
9366
- /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("div", { className: "fd-skel", style: { width: i ? "71%" : "56%", height: 11 } })
9379
+ return /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("div", { className: "fdc-skel", "aria-hidden": "true", children: [0, 1].map((i) => /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("div", { className: "fdc-skel-turn", children: [
9380
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("div", { className: "fd-skel fd-skel-circle", style: { width: 22, height: 22 } }),
9381
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("div", { className: "fdc-skel-lines", children: [
9382
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("div", { className: "fd-skel", style: { width: i ? "62%" : "44%", height: 11 } }),
9383
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("div", { className: "fd-skel", style: { width: i ? "94%" : "78%", height: 11 } }),
9384
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("div", { className: "fd-skel", style: { width: i ? "71%" : "56%", height: 11 } })
9367
9385
  ] })
9368
9386
  ] }, i)) });
9369
9387
  }
@@ -9380,10 +9398,10 @@ function ChatTranscript({
9380
9398
  renderEmpty,
9381
9399
  className = ""
9382
9400
  }) {
9383
- const scroller = React40.useRef(null);
9384
- const stick = React40.useRef(true);
9385
- const [pill, setPill] = React40.useState(0);
9386
- const seen = React40.useRef(0);
9401
+ const scroller = React41.useRef(null);
9402
+ const stick = React41.useRef(true);
9403
+ const [pill, setPill] = React41.useState(0);
9404
+ const seen = React41.useRef(0);
9387
9405
  const toBottom = (smooth) => {
9388
9406
  const el = scroller.current;
9389
9407
  if (!el) return;
@@ -9402,7 +9420,7 @@ function ChatTranscript({
9402
9420
  seen.current = messages.length;
9403
9421
  }
9404
9422
  };
9405
- React40.useLayoutEffect(() => {
9423
+ React41.useLayoutEffect(() => {
9406
9424
  const el = scroller.current;
9407
9425
  if (!el) return;
9408
9426
  if (stick.current) {
@@ -9410,7 +9428,7 @@ function ChatTranscript({
9410
9428
  seen.current = messages.length;
9411
9429
  } else setPill(Math.max(0, messages.length - seen.current));
9412
9430
  }, [messages]);
9413
- React40.useEffect(() => {
9431
+ React41.useEffect(() => {
9414
9432
  const el = scroller.current;
9415
9433
  const inner = el && el.firstChild;
9416
9434
  if (!el || !inner || typeof ResizeObserver === "undefined") return;
@@ -9420,38 +9438,38 @@ function ChatTranscript({
9420
9438
  ro.observe(inner);
9421
9439
  return () => ro.disconnect();
9422
9440
  }, []);
9423
- const groups = React40.useMemo(() => groupMessages(messages), [messages]);
9441
+ const groups = React41.useMemo(() => groupMessages(messages), [messages]);
9424
9442
  const empty = !messages.length && status === "ready";
9425
- return /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
9426
- /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
9427
- status === "loading" || status === "resolving" ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(LoadingTurns, {}) : null,
9428
- status === "disconnected" ? /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("div", { className: "fdc-dead", children: [
9429
- /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fdc-dead-icon", children: /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-plugs", "aria-hidden": "true" }) }),
9430
- /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("h3", { className: "fdc-dead-title", children: ctx.deadTitle || "The assistant isn\u2019t reachable" }),
9431
- /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("p", { className: "fdc-dead-body", children: fatal === "chat_unavailable" ? "The service reported chat_unavailable. Nothing you type will be lost \u2014 reopen the panel once it\u2019s back." : "The thread couldn\u2019t be resolved" + (fatal ? " (" + fatal + ")" : "") + ". The composer stays disabled until it resolves." }),
9432
- ctx.onReconnect ? /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("button", { type: "button", className: "fd-btn fd-btn-secondary fd-btn-sm", onClick: ctx.onReconnect, children: [
9433
- /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
9443
+ return /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
9444
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
9445
+ status === "loading" || status === "resolving" ? /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(LoadingTurns, {}) : null,
9446
+ status === "disconnected" ? /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("div", { className: "fdc-dead", children: [
9447
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { className: "fdc-dead-icon", children: /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("i", { className: "ph ph-plugs", "aria-hidden": "true" }) }),
9448
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("h3", { className: "fdc-dead-title", children: ctx.deadTitle || "The assistant isn\u2019t reachable" }),
9449
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("p", { className: "fdc-dead-body", children: fatal === "chat_unavailable" ? "The service reported chat_unavailable. Nothing you type will be lost \u2014 reopen the panel once it\u2019s back." : "The thread couldn\u2019t be resolved" + (fatal ? " (" + fatal + ")" : "") + ". The composer stays disabled until it resolves." }),
9450
+ ctx.onReconnect ? /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("button", { type: "button", className: "fd-btn fd-btn-secondary fd-btn-sm", onClick: ctx.onReconnect, children: [
9451
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
9434
9452
  "Try again"
9435
9453
  ] }) : null
9436
9454
  ] }) : null,
9437
- empty ? renderEmpty ? renderEmpty() : /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("div", { className: "fdc-empty", children: [
9438
- /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fdc-empty-icon", children: /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-" + emptyIcon, "aria-hidden": "true" }) }),
9439
- /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("h3", { className: "fdc-empty-title", children: emptyTitle }),
9440
- emptyDescription ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("p", { className: "fdc-empty-body", children: emptyDescription }) : null,
9441
- /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(Suggestions, { items: suggestions, onPick })
9455
+ empty ? renderEmpty ? renderEmpty() : /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("div", { className: "fdc-empty", children: [
9456
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { className: "fdc-empty-icon", children: /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("i", { className: "ph ph-" + emptyIcon, "aria-hidden": "true" }) }),
9457
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("h3", { className: "fdc-empty-title", children: emptyTitle }),
9458
+ emptyDescription ? /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("p", { className: "fdc-empty-body", children: emptyDescription }) : null,
9459
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(Suggestions, { items: suggestions, onPick })
9442
9460
  ] }) : null,
9443
9461
  groups.map((g, i) => {
9444
9462
  const prev = groups[i - 1];
9445
9463
  const k = dayKey(g.messages[0].timestamp);
9446
9464
  const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
9447
- return /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)(React40.Fragment, { children: [
9448
- showDay ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("div", { className: "fdc-day", children: /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { children: dayLabel(k) }) }) : null,
9449
- /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(ChatTurn, { group: g, ctx })
9465
+ return /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)(React41.Fragment, { children: [
9466
+ showDay ? /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("div", { className: "fdc-day", children: /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { children: dayLabel(k) }) }) : null,
9467
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(ChatTurn, { group: g, ctx })
9450
9468
  ] }, g.key || i);
9451
9469
  })
9452
9470
  ] }),
9453
- pill ? /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("button", { type: "button", className: "fdc-pill", onClick: () => toBottom(true), children: [
9454
- /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-arrow-down", "aria-hidden": "true" }),
9471
+ pill ? /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("button", { type: "button", className: "fdc-pill", onClick: () => toBottom(true), children: [
9472
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("i", { className: "ph ph-arrow-down", "aria-hidden": "true" }),
9455
9473
  pill,
9456
9474
  " new message",
9457
9475
  pill === 1 ? "" : "s"
@@ -9461,8 +9479,8 @@ function ChatTranscript({
9461
9479
  var TranscriptKit = { groupMessages };
9462
9480
 
9463
9481
  // src/components/chat/ChatComposer.tsx
9464
- var React41 = __toESM(require("react"), 1);
9465
- var import_jsx_runtime74 = require("react/jsx-runtime");
9482
+ var React42 = __toESM(require("react"), 1);
9483
+ var import_jsx_runtime75 = require("react/jsx-runtime");
9466
9484
  function ChatComposer({
9467
9485
  onSubmit,
9468
9486
  onStop,
@@ -9489,17 +9507,17 @@ function ChatComposer({
9489
9507
  onReject,
9490
9508
  onOpenAttachment
9491
9509
  }) {
9492
- const [text, setText] = React41.useState(draft || "");
9493
- const [trigger, setTrigger] = React41.useState(null);
9494
- const [mentionItems, setMentionItems] = React41.useState([]);
9495
- const [listening, setListening] = React41.useState(false);
9496
- const [notice, setNotice] = React41.useState(null);
9497
- const editor = React41.useRef(null);
9498
- const wrap = React41.useRef(null);
9499
- const stopVoice = React41.useRef(null);
9510
+ const [text, setText] = React42.useState(draft || "");
9511
+ const [trigger, setTrigger] = React42.useState(null);
9512
+ const [mentionItems, setMentionItems] = React42.useState([]);
9513
+ const [listening, setListening] = React42.useState(false);
9514
+ const [notice, setNotice] = React42.useState(null);
9515
+ const editor = React42.useRef(null);
9516
+ const wrap = React42.useRef(null);
9517
+ const stopVoice = React42.useRef(null);
9500
9518
  const staged = useStagedFiles(fileUploadHandler, { onError: () => {
9501
9519
  } });
9502
- React41.useEffect(() => {
9520
+ React42.useEffect(() => {
9503
9521
  if (draft != null && draft !== text) setText(draft);
9504
9522
  }, [draft]);
9505
9523
  const change = (v) => {
@@ -9533,7 +9551,7 @@ function ChatComposer({
9533
9551
  e.preventDefault();
9534
9552
  staged.add(found.files);
9535
9553
  };
9536
- React41.useEffect(() => {
9554
+ React42.useEffect(() => {
9537
9555
  if (!trigger || trigger.type !== "mention" || !mentionSources) {
9538
9556
  setMentionItems([]);
9539
9557
  return;
@@ -9551,7 +9569,7 @@ function ChatComposer({
9551
9569
  const q = (trigger.query || "").toLowerCase();
9552
9570
  setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
9553
9571
  }, [trigger, mentionSources]);
9554
- const slashItems = React41.useMemo(() => {
9572
+ const slashItems = React42.useMemo(() => {
9555
9573
  if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
9556
9574
  const q = (trigger.query || "").toLowerCase();
9557
9575
  return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
@@ -9565,7 +9583,7 @@ function ChatComposer({
9565
9583
  description: it.description,
9566
9584
  icon: it.icon,
9567
9585
  meta: mention.meta,
9568
- shortcut: slash.shortcut ? /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(KeyHint, { keys: slash.shortcut, size: "sm" }) : void 0,
9586
+ shortcut: slash.shortcut ? /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(KeyHint, { keys: slash.shortcut, size: "sm" }) : void 0,
9569
9587
  onSelect: () => {
9570
9588
  const insert = trigger.type === "slash" ? slash.immediate ? "/" + slash.id : "/" + slash.id + " " : "@" + (mention.value || mention.label) + " ";
9571
9589
  editor.current && editor.current.replaceRange(trigger.from, trigger.to, insert);
@@ -9628,14 +9646,14 @@ function ChatComposer({
9628
9646
  stopVoice.current = typeof res === "function" ? res : () => {
9629
9647
  };
9630
9648
  };
9631
- return /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("div", { className: "fdc-composer" + (disabled ? " is-disabled" : "") + (narrow ? " is-narrow" : ""), children: [
9632
- queue.length ? /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("div", { className: "fdc-queue", "aria-label": "Queued messages", children: queue.map((q) => /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("div", { className: "fdc-queue-row", children: [
9633
- /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("i", { className: "ph ph-clock-countdown", "aria-hidden": "true" }),
9634
- /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { className: "fdc-queue-text", children: q.text || (q.attachments ? q.attachments.length + " file(s)" : "") }),
9635
- onRemoveQueued ? /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("button", { type: "button", className: "fdc-queue-x", onClick: () => onRemoveQueued(q.id), "aria-label": "Remove queued message", children: /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
9649
+ return /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("div", { className: "fdc-composer" + (disabled ? " is-disabled" : "") + (narrow ? " is-narrow" : ""), children: [
9650
+ queue.length ? /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("div", { className: "fdc-queue", "aria-label": "Queued messages", children: queue.map((q) => /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("div", { className: "fdc-queue-row", children: [
9651
+ /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("i", { className: "ph ph-clock-countdown", "aria-hidden": "true" }),
9652
+ /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { className: "fdc-queue-text", children: q.text || (q.attachments ? q.attachments.length + " file(s)" : "") }),
9653
+ onRemoveQueued ? /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("button", { type: "button", className: "fdc-queue-x", onClick: () => onRemoveQueued(q.id), "aria-label": "Remove queued message", children: /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
9636
9654
  ] }, q.id)) }) : null,
9637
9655
  sessionBar,
9638
- /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(
9656
+ /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(
9639
9657
  Dropzone,
9640
9658
  {
9641
9659
  className: "fdc-field",
@@ -9649,9 +9667,9 @@ function ChatComposer({
9649
9667
  disabled: !fileUploadHandler || disabled,
9650
9668
  label: "Drop to attach",
9651
9669
  hint: acceptFiles ? acceptFiles.replace(/,/g, " \xB7 ") : void 0,
9652
- children: /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("div", { ref: wrap, className: "fdc-field-inner", children: [
9653
- staged.items.length ? /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("div", { className: "fdc-staged", children: /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(FileStrip, { files: staged.items, size: narrow ? 60 : 68, onRemove: staged.remove, onRetry: staged.retry, onOpen: onOpenAttachment }) }) : null,
9654
- /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(
9670
+ children: /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("div", { ref: wrap, className: "fdc-field-inner", children: [
9671
+ staged.items.length ? /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("div", { className: "fdc-staged", children: /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(FileStrip, { files: staged.items, size: narrow ? 60 : 68, onRemove: staged.remove, onRetry: staged.retry, onOpen: onOpenAttachment }) }) : null,
9672
+ /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(
9655
9673
  MarkdownEditor,
9656
9674
  {
9657
9675
  ref: editor,
@@ -9670,33 +9688,33 @@ function ChatComposer({
9670
9688
  ariaLabel: "Message"
9671
9689
  }
9672
9690
  ),
9673
- /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("div", { className: "fdc-tools", children: [
9674
- fileUploadHandler ? /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(FilePickButton, { onFiles: staged.add, onReject: (r) => flash(r[0].message), accept: acceptFiles, maxFileSize, label: "Attach files", icon: "plus" }) : null,
9675
- voiceHandler ? /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("button", { type: "button", className: "fd-attachbtn" + (listening ? " is-live" : ""), onClick: voice, "aria-pressed": listening, "aria-label": listening ? "Stop dictation" : "Dictate", children: /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("i", { className: "ph ph-" + (listening ? "waveform" : "microphone"), "aria-hidden": "true" }) }) : null,
9691
+ /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("div", { className: "fdc-tools", children: [
9692
+ fileUploadHandler ? /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(FilePickButton, { onFiles: staged.add, onReject: (r) => flash(r[0].message), accept: acceptFiles, maxFileSize, label: "Attach files", icon: "plus" }) : null,
9693
+ voiceHandler ? /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("button", { type: "button", className: "fd-attachbtn" + (listening ? " is-live" : ""), onClick: voice, "aria-pressed": listening, "aria-label": listening ? "Stop dictation" : "Dictate", children: /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("i", { className: "ph ph-" + (listening ? "waveform" : "microphone"), "aria-hidden": "true" }) }) : null,
9676
9694
  toolbarExtras,
9677
- /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { className: "fdc-tools-gap" }),
9678
- maxLength && text.length > maxLength * 0.6 ? /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("span", { className: "fdc-count fd-tabular" + (text.length > maxLength * 0.95 ? " is-hot" : ""), children: [
9695
+ /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { className: "fdc-tools-gap" }),
9696
+ maxLength && text.length > maxLength * 0.6 ? /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("span", { className: "fdc-count fd-tabular" + (text.length > maxLength * 0.95 ? " is-hot" : ""), children: [
9679
9697
  text.length,
9680
9698
  "/",
9681
9699
  maxLength
9682
9700
  ] }) : null,
9683
- busy ? /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("button", { type: "button", className: "fdc-stop", onClick: onStop, "aria-label": "Stop generating", children: [
9684
- /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
9685
- /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { children: "Stop" })
9686
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("button", { type: "button", className: "fdc-send", onClick: submit, disabled: !canSend, "aria-label": "Send message", children: [
9687
- /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("i", { className: "ph ph-paper-plane-right", "aria-hidden": "true" }),
9688
- /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { className: "fdc-send-label", children: "Send" })
9701
+ busy ? /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("button", { type: "button", className: "fdc-stop", onClick: onStop, "aria-label": "Stop generating", children: [
9702
+ /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
9703
+ /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { children: "Stop" })
9704
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("button", { type: "button", className: "fdc-send", onClick: submit, disabled: !canSend, "aria-label": "Send message", children: [
9705
+ /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("i", { className: "ph ph-paper-plane-right", "aria-hidden": "true" }),
9706
+ /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { className: "fdc-send-label", children: "Send" })
9689
9707
  ] })
9690
9708
  ] })
9691
9709
  ] })
9692
9710
  }
9693
9711
  ),
9694
- notice ? /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("div", { className: "fdc-notice", role: "status", children: [
9695
- /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
9712
+ notice ? /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("div", { className: "fdc-notice", role: "status", children: [
9713
+ /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
9696
9714
  notice
9697
9715
  ] }) : null,
9698
- hint && !notice ? /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("div", { className: "fdc-hint", children: hint }) : null,
9699
- /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(
9716
+ hint && !notice ? /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("div", { className: "fdc-hint", children: hint }) : null,
9717
+ /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(
9700
9718
  Popover,
9701
9719
  {
9702
9720
  open: menuOpen,
@@ -9710,12 +9728,12 @@ function ChatComposer({
9710
9728
  returnFocus: false,
9711
9729
  closeOnOutside: true,
9712
9730
  label: trigger && trigger.type === "slash" ? "Commands" : "Mentions",
9713
- children: /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(
9731
+ children: /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(
9714
9732
  Menu,
9715
9733
  {
9716
9734
  items: menuItems,
9717
9735
  autoFocus: false,
9718
- header: /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("div", { className: "fd-pop-group", children: trigger && trigger.type === "slash" ? "Commands" : "Attach context" }),
9736
+ header: /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("div", { className: "fd-pop-group", children: trigger && trigger.type === "slash" ? "Commands" : "Attach context" }),
9719
9737
  onClose: () => setTrigger(null)
9720
9738
  }
9721
9739
  )
@@ -9725,12 +9743,12 @@ function ChatComposer({
9725
9743
  }
9726
9744
 
9727
9745
  // src/components/chat/ChatSessionBar.tsx
9728
- var React42 = __toESM(require("react"), 1);
9729
- var import_jsx_runtime75 = require("react/jsx-runtime");
9746
+ var React43 = __toESM(require("react"), 1);
9747
+ var import_jsx_runtime76 = require("react/jsx-runtime");
9730
9748
  var compact2 = meterFormats.compact;
9731
9749
  function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
9732
- const [open, setOpen] = React42.useState(false);
9733
- const anchor = React42.useRef(null);
9750
+ const [open, setOpen] = React43.useState(false);
9751
+ const anchor = React43.useRef(null);
9734
9752
  const stats = sessionStats || null;
9735
9753
  const cu = contextUsage || null;
9736
9754
  const limits = usageLimits || null;
@@ -9745,9 +9763,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
9745
9763
  if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
9746
9764
  if (cu) bits.push(pct + "% context");
9747
9765
  const expandable = !!(cu || limits);
9748
- return /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)(React42.Fragment, { children: [
9749
- /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("div", { className: "fdc-bar", children: [
9750
- /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)(
9766
+ return /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(React43.Fragment, { children: [
9767
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "fdc-bar", children: [
9768
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(
9751
9769
  "button",
9752
9770
  {
9753
9771
  type: "button",
@@ -9758,16 +9776,16 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
9758
9776
  "aria-expanded": expandable ? open : void 0,
9759
9777
  "aria-label": expandable ? "Usage details" : void 0,
9760
9778
  children: [
9761
- cu ? /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { className: "fdc-bar-mini", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(SegmentedMeter, { total, segments: cu.segments, height: 4, showTotal: false }) }) : null,
9762
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { className: "fdc-bar-text", children: bits.join(" \xB7 ") }),
9763
- expandable ? /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("i", { className: "ph ph-caret-right fdc-bar-caret", "aria-hidden": "true" }) : null
9779
+ cu ? /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { className: "fdc-bar-mini", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(SegmentedMeter, { total, segments: cu.segments, height: 4, showTotal: false }) }) : null,
9780
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { className: "fdc-bar-text", children: bits.join(" \xB7 ") }),
9781
+ expandable ? /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("i", { className: "ph ph-caret-right fdc-bar-caret", "aria-hidden": "true" }) : null
9764
9782
  ]
9765
9783
  }
9766
9784
  ),
9767
9785
  extras
9768
9786
  ] }),
9769
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(Popover, { open, anchorRef: anchor, placement: "top-start", onClose: () => setOpen(false), minWidth: 330, maxHeight: 460, padded: true, label: "Usage", children: /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("div", { className: "fdc-usage", children: [
9770
- cu ? /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("section", { className: "fdc-usage-sec", children: /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(
9787
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Popover, { open, anchorRef: anchor, placement: "top-start", onClose: () => setOpen(false), minWidth: 330, maxHeight: 460, padded: true, label: "Usage", children: /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "fdc-usage", children: [
9788
+ cu ? /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("section", { className: "fdc-usage-sec", children: /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
9771
9789
  SegmentedMeter,
9772
9790
  {
9773
9791
  total,
@@ -9779,9 +9797,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
9779
9797
  remainderLabel: "Free"
9780
9798
  }
9781
9799
  ) }) : null,
9782
- limits && limits.length ? /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("section", { className: "fdc-usage-sec", children: [
9783
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("h4", { className: "fdc-usage-h", children: "Usage limits" }),
9784
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("div", { className: "fdc-usage-rows", children: limits.map((l) => /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(
9800
+ limits && limits.length ? /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("section", { className: "fdc-usage-sec", children: [
9801
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("h4", { className: "fdc-usage-h", children: "Usage limits" }),
9802
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("div", { className: "fdc-usage-rows", children: limits.map((l) => /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
9785
9803
  QuotaRow,
9786
9804
  {
9787
9805
  label: l.label,
@@ -9791,32 +9809,32 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
9791
9809
  l.id
9792
9810
  )) })
9793
9811
  ] }) : null,
9794
- stats ? /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("section", { className: "fdc-usage-sec fdc-usage-stats", children: [
9795
- stats.elapsedMs ? /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("div", { children: [
9796
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { children: "Session" }),
9797
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("b", { className: "fd-tabular", children: formatDuration(stats.elapsedMs) })
9812
+ stats ? /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("section", { className: "fdc-usage-sec fdc-usage-stats", children: [
9813
+ stats.elapsedMs ? /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { children: [
9814
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { children: "Session" }),
9815
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("b", { className: "fd-tabular", children: formatDuration(stats.elapsedMs) })
9798
9816
  ] }) : null,
9799
- stats.tokens ? /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("div", { children: [
9800
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { children: "Tokens" }),
9801
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("b", { className: "fd-tabular", children: stats.tokens.toLocaleString() })
9817
+ stats.tokens ? /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { children: [
9818
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { children: "Tokens" }),
9819
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("b", { className: "fd-tabular", children: stats.tokens.toLocaleString() })
9802
9820
  ] }) : null,
9803
- stats.costUsd != null ? /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("div", { children: [
9804
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { children: "Cost" }),
9805
- /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("b", { className: "fd-tabular", children: [
9821
+ stats.costUsd != null ? /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { children: [
9822
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { children: "Cost" }),
9823
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("b", { className: "fd-tabular", children: [
9806
9824
  "$",
9807
9825
  Number(stats.costUsd).toFixed(3)
9808
9826
  ] })
9809
9827
  ] }) : null,
9810
- stats.turns ? /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("div", { children: [
9811
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { children: "Turns" }),
9812
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("b", { className: "fd-tabular", children: stats.turns })
9828
+ stats.turns ? /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { children: [
9829
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { children: "Turns" }),
9830
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("b", { className: "fd-tabular", children: stats.turns })
9813
9831
  ] }) : null
9814
9832
  ] }) : null,
9815
- onClear ? /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("footer", { className: "fdc-usage-foot", children: /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("button", { type: "button", className: "fdc-usage-clear", onClick: () => {
9833
+ onClear ? /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("footer", { className: "fdc-usage-foot", children: /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("button", { type: "button", className: "fdc-usage-clear", onClick: () => {
9816
9834
  setOpen(false);
9817
9835
  onClear();
9818
9836
  }, children: [
9819
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("i", { className: "ph ph-trash", "aria-hidden": "true" }),
9837
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("i", { className: "ph ph-trash", "aria-hidden": "true" }),
9820
9838
  "Clear conversation"
9821
9839
  ] }) }) : null
9822
9840
  ] }) })
@@ -9853,7 +9871,7 @@ function ModelControls({
9853
9871
  disabled: m.disabled,
9854
9872
  checked: m.id === (current2 && current2.id),
9855
9873
  meta: m.meta,
9856
- shortcut: m.shortcut ? /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(KeyHint, { keys: m.shortcut, size: "sm" }) : void 0,
9874
+ shortcut: m.shortcut ? /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(KeyHint, { keys: m.shortcut, size: "sm" }) : void 0,
9857
9875
  onSelect: () => onModelChange && onModelChange(m.id)
9858
9876
  });
9859
9877
  const items = [{ kind: "section", label: "Models" }].concat(flat.map(item));
@@ -9866,15 +9884,15 @@ function ModelControls({
9866
9884
  items.push({ kind: "section", label: "Fast mode" });
9867
9885
  items.push({
9868
9886
  kind: "custom",
9869
- render: () => /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("label", { className: "fdc-switchrow", children: [
9870
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { children: fastModeLabel }),
9871
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("input", { type: "checkbox", className: "fd-sr", checked: !!fastMode, onChange: (e) => onFastModeChange(e.target.checked) }),
9872
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { className: "fd-switch-track" + (fastMode ? " is-on" : ""), "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { className: "fd-switch-thumb" }) })
9887
+ render: () => /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("label", { className: "fdc-switchrow", children: [
9888
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { children: fastModeLabel }),
9889
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("input", { type: "checkbox", className: "fd-sr", checked: !!fastMode, onChange: (e) => onFastModeChange(e.target.checked) }),
9890
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { className: "fd-switch-track" + (fastMode ? " is-on" : ""), "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { className: "fd-switch-thumb" }) })
9873
9891
  ] })
9874
9892
  });
9875
9893
  }
9876
- return /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)(React42.Fragment, { children: [
9877
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(
9894
+ return /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(React43.Fragment, { children: [
9895
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
9878
9896
  MenuButton,
9879
9897
  {
9880
9898
  items,
@@ -9885,7 +9903,7 @@ function ModelControls({
9885
9903
  title: "Choose a model"
9886
9904
  }
9887
9905
  ),
9888
- effortLevels && effortLevels.length ? /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(
9906
+ effortLevels && effortLevels.length ? /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
9889
9907
  MenuButton,
9890
9908
  {
9891
9909
  placement: "top-end",
@@ -9906,7 +9924,7 @@ function ModelControls({
9906
9924
  }
9907
9925
 
9908
9926
  // src/components/chat/AgentChatPanel.tsx
9909
- var import_jsx_runtime76 = require("react/jsx-runtime");
9927
+ var import_jsx_runtime77 = require("react/jsx-runtime");
9910
9928
  var SURFACES = { sidebar: "is-sidebar", inline: "is-inline", page: "is-page", modal: "is-modal", sheet: "is-sheet" };
9911
9929
  function AgentChatPanel({
9912
9930
  /* required */
@@ -9990,11 +10008,11 @@ function AgentChatPanel({
9990
10008
  onFeedback,
9991
10009
  onEditMessage
9992
10010
  }) {
9993
- const [panelWidth, setPanelWidth] = React43.useState(width);
9994
- const [applied, setApplied] = React43.useState({});
9995
- const [draft, setDraft] = React43.useState("");
9996
- const dragging = React43.useRef(null);
9997
- React43.useEffect(() => setPanelWidth(width), [width]);
10011
+ const [panelWidth, setPanelWidth] = React44.useState(width);
10012
+ const [applied, setApplied] = React44.useState({});
10013
+ const [draft, setDraft] = React44.useState("");
10014
+ const dragging = React44.useRef(null);
10015
+ React44.useEffect(() => setPanelWidth(width), [width]);
9998
10016
  const engine = useChatEngine({
9999
10017
  contextType,
10000
10018
  contextId,
@@ -10060,7 +10078,7 @@ function AgentChatPanel({
10060
10078
  onReconnect: engine.reload,
10061
10079
  deadTitle: "The assistant isn\u2019t reachable"
10062
10080
  };
10063
- const sessionBar = /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
10081
+ const sessionBar = /* @__PURE__ */ (0, import_jsx_runtime77.jsx)(
10064
10082
  ChatSessionBar,
10065
10083
  {
10066
10084
  sessionStats,
@@ -10069,7 +10087,7 @@ function AgentChatPanel({
10069
10087
  onClear: engine.visible.length ? engine.clear : void 0
10070
10088
  }
10071
10089
  );
10072
- const modelControls = /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
10090
+ const modelControls = /* @__PURE__ */ (0, import_jsx_runtime77.jsx)(
10073
10091
  ModelControls,
10074
10092
  {
10075
10093
  models,
@@ -10084,7 +10102,7 @@ function AgentChatPanel({
10084
10102
  narrow
10085
10103
  }
10086
10104
  );
10087
- const threadMenu = threads && threads.length ? /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
10105
+ const threadMenu = threads && threads.length ? /* @__PURE__ */ (0, import_jsx_runtime77.jsx)(
10088
10106
  MenuButton,
10089
10107
  {
10090
10108
  variant: "ghost",
@@ -10111,7 +10129,7 @@ function AgentChatPanel({
10111
10129
  })))
10112
10130
  }
10113
10131
  ) : null;
10114
- return /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(
10132
+ return /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)(
10115
10133
  "aside",
10116
10134
  {
10117
10135
  className: ["fdc-panel", SURFACES[surface] || SURFACES.sidebar, narrow ? "is-narrow" : "", className].filter(Boolean).join(" "),
@@ -10122,7 +10140,7 @@ function AgentChatPanel({
10122
10140
  },
10123
10141
  "aria-label": title,
10124
10142
  children: [
10125
- surface === "sidebar" && resizable ? /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
10143
+ surface === "sidebar" && resizable ? /* @__PURE__ */ (0, import_jsx_runtime77.jsx)(
10126
10144
  "div",
10127
10145
  {
10128
10146
  className: "fdc-grip",
@@ -10137,20 +10155,20 @@ function AgentChatPanel({
10137
10155
  }
10138
10156
  }
10139
10157
  ) : null,
10140
- showHeader ? /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("header", { className: "fdc-head", children: [
10141
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { className: "fdc-head-mark", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("i", { className: "ph ph-" + assistantIcon }) }),
10142
- /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("span", { className: "fdc-head-titles", children: [
10143
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { className: "fdc-head-title", children: title }),
10144
- subtitle ? /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { className: "fdc-head-sub", children: subtitle }) : null
10158
+ showHeader ? /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)("header", { className: "fdc-head", children: [
10159
+ /* @__PURE__ */ (0, import_jsx_runtime77.jsx)("span", { className: "fdc-head-mark", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime77.jsx)("i", { className: "ph ph-" + assistantIcon }) }),
10160
+ /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)("span", { className: "fdc-head-titles", children: [
10161
+ /* @__PURE__ */ (0, import_jsx_runtime77.jsx)("span", { className: "fdc-head-title", children: title }),
10162
+ subtitle ? /* @__PURE__ */ (0, import_jsx_runtime77.jsx)("span", { className: "fdc-head-sub", children: subtitle }) : null
10145
10163
  ] }),
10146
- /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("span", { className: "fdc-head-acts", children: [
10164
+ /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)("span", { className: "fdc-head-acts", children: [
10147
10165
  headerActions,
10148
10166
  threadMenu,
10149
- onNewThread ? /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("button", { type: "button", className: "fdc-iconbtn", onClick: onNewThread, "aria-label": "New conversation", title: "New conversation", children: /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("i", { className: "ph ph-plus", "aria-hidden": "true" }) }) : null,
10150
- onClose ? /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("button", { type: "button", className: "fdc-iconbtn", onClick: onClose, "aria-label": "Close panel", title: "Close", children: /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
10167
+ onNewThread ? /* @__PURE__ */ (0, import_jsx_runtime77.jsx)("button", { type: "button", className: "fdc-iconbtn", onClick: onNewThread, "aria-label": "New conversation", title: "New conversation", children: /* @__PURE__ */ (0, import_jsx_runtime77.jsx)("i", { className: "ph ph-plus", "aria-hidden": "true" }) }) : null,
10168
+ onClose ? /* @__PURE__ */ (0, import_jsx_runtime77.jsx)("button", { type: "button", className: "fdc-iconbtn", onClick: onClose, "aria-label": "Close panel", title: "Close", children: /* @__PURE__ */ (0, import_jsx_runtime77.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
10151
10169
  ] })
10152
10170
  ] }) : null,
10153
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
10171
+ /* @__PURE__ */ (0, import_jsx_runtime77.jsx)(
10154
10172
  ChatTranscript,
10155
10173
  {
10156
10174
  messages: engine.visible,
@@ -10165,7 +10183,7 @@ function AgentChatPanel({
10165
10183
  renderEmpty
10166
10184
  }
10167
10185
  ),
10168
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
10186
+ /* @__PURE__ */ (0, import_jsx_runtime77.jsx)(
10169
10187
  ChatComposer,
10170
10188
  {
10171
10189
  onSubmit: (text, atts) => engine.send(text, atts),
@@ -10198,7 +10216,7 @@ function AgentChatPanel({
10198
10216
  }
10199
10217
 
10200
10218
  // src/kits/query.ts
10201
- var React44 = __toESM(require("react"), 1);
10219
+ var React45 = __toESM(require("react"), 1);
10202
10220
  function eqFilter(get2) {
10203
10221
  return (row, value) => Array.isArray(value) ? value.includes(get2(row)) : get2(row) === value;
10204
10222
  }
@@ -10230,22 +10248,22 @@ function compare(a, b, dir) {
10230
10248
  var API = null;
10231
10249
  var PREFS = null;
10232
10250
  function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
10233
- const [query, setQuery] = React44.useState(() => {
10251
+ const [query, setQuery] = React45.useState(() => {
10234
10252
  const store = PREFS || window.PlannerPrefs;
10235
10253
  const saved = prefsKey && store ? store.getTable(prefsKey) : {};
10236
10254
  return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
10237
10255
  });
10238
- const savePref = React44.useCallback((patch2) => {
10256
+ const savePref = React45.useCallback((patch2) => {
10239
10257
  const store = PREFS || window.PlannerPrefs;
10240
10258
  if (prefsKey && store) store.setTable(prefsKey, patch2);
10241
10259
  }, [prefsKey]);
10242
- const [res, setRes] = React44.useState(null);
10243
- const [loading, setLoading] = React44.useState(true);
10244
- const seq2 = React44.useRef(0);
10260
+ const [res, setRes] = React45.useState(null);
10261
+ const [loading, setLoading] = React45.useState(true);
10262
+ const seq2 = React45.useRef(0);
10245
10263
  const depKey = (deps || []).join("|");
10246
10264
  const paramKey = JSON.stringify(params || {});
10247
10265
  const queryKey = JSON.stringify(query);
10248
- React44.useEffect(() => {
10266
+ React45.useEffect(() => {
10249
10267
  const id = ++seq2.current;
10250
10268
  setLoading(true);
10251
10269
  const t = setTimeout(() => {