@flytedan/flytebot-design-system 0.19.0 → 0.21.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
@@ -146,6 +146,7 @@ __export(index_exports, {
146
146
  SessionKit: () => SessionKit,
147
147
  SessionProvider: () => SessionProvider,
148
148
  SidebarNav: () => SidebarNav,
149
+ SignInPage: () => SignInPage,
149
150
  Skeleton: () => Skeleton,
150
151
  SkeletonText: () => SkeletonText,
151
152
  Slider: () => Slider,
@@ -6608,11 +6609,204 @@ function ProfilePage({
6608
6609
  ] });
6609
6610
  }
6610
6611
 
6612
+ // src/components/platform/SignInPage.tsx
6613
+ var React42 = __toESM(require("react"), 1);
6614
+ var import_jsx_runtime68 = require("react/jsx-runtime");
6615
+ function SignInPage({ productName, onSignIn, continueAs, error }) {
6616
+ const [signingIn, setSigningIn] = React42.useState(false);
6617
+ const [resuming, setResuming] = React42.useState(false);
6618
+ function handleSignIn() {
6619
+ setSigningIn(true);
6620
+ onSignIn();
6621
+ }
6622
+ function handleContinue() {
6623
+ setResuming(true);
6624
+ continueAs.onContinue().finally(() => setResuming(false));
6625
+ }
6626
+ return /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
6627
+ "div",
6628
+ {
6629
+ style: {
6630
+ position: "relative",
6631
+ display: "grid",
6632
+ placeItems: "center",
6633
+ minHeight: "100vh",
6634
+ padding: "24px 16px",
6635
+ boxSizing: "border-box",
6636
+ overflow: "hidden",
6637
+ background: "radial-gradient(circle at 15% 15%, var(--blue-700) 0%, transparent 45%), radial-gradient(circle at 85% 85%, var(--blue-600) 0%, transparent 40%), linear-gradient(160deg, var(--navy) 0%, var(--blue-950) 55%, var(--blue-900) 100%)"
6638
+ },
6639
+ children: [
6640
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
6641
+ "div",
6642
+ {
6643
+ "aria-hidden": true,
6644
+ style: {
6645
+ position: "absolute",
6646
+ inset: 0,
6647
+ backgroundImage: "linear-gradient(rgba(255,255,255,0.05) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.05) 1px, transparent 1px)",
6648
+ backgroundSize: "48px 48px",
6649
+ maskImage: "radial-gradient(circle at 50% 40%, black, transparent 70%)"
6650
+ }
6651
+ }
6652
+ ),
6653
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
6654
+ "div",
6655
+ {
6656
+ style: {
6657
+ position: "relative",
6658
+ width: "100%",
6659
+ maxWidth: 408,
6660
+ display: "flex",
6661
+ flexDirection: "column",
6662
+ alignItems: "center"
6663
+ },
6664
+ children: [
6665
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("div", { style: { marginBottom: "var(--s-32)" }, "data-theme": "dark", children: /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(FlytedeskMark, { size: "lg" }) }),
6666
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
6667
+ "div",
6668
+ {
6669
+ style: {
6670
+ width: "100%",
6671
+ borderRadius: "var(--r-2xl)",
6672
+ overflow: "hidden",
6673
+ boxShadow: "0 24px 64px -12px rgba(2, 8, 20, 0.55), 0 2px 8px rgba(2, 8, 20, 0.3)"
6674
+ },
6675
+ children: [
6676
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
6677
+ "div",
6678
+ {
6679
+ style: {
6680
+ height: 4,
6681
+ background: "linear-gradient(90deg, var(--blue-400), var(--blue-600), var(--navy))"
6682
+ }
6683
+ }
6684
+ ),
6685
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(Card, { children: /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
6686
+ "div",
6687
+ {
6688
+ style: {
6689
+ display: "flex",
6690
+ flexDirection: "column",
6691
+ gap: "var(--s-20)",
6692
+ alignItems: "center",
6693
+ textAlign: "center",
6694
+ padding: "var(--s-8) 0"
6695
+ },
6696
+ children: [
6697
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { children: [
6698
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("h1", { className: "fd-h3", style: { color: "var(--navy)" }, children: productName }),
6699
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("p", { className: "fd-body-sm fd-muted", style: { marginTop: "var(--s-4)" }, children: continueAs ? "Your session timed out, but you're likely still signed in" : "Sign in with your flytedesk workspace account" })
6700
+ ] }),
6701
+ error ? /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("div", { role: "alert", style: { width: "100%" }, children: /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(Banner, { tone: "danger", title: error }) }) : null,
6702
+ continueAs ? /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(import_jsx_runtime68.Fragment, { children: [
6703
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
6704
+ Button,
6705
+ {
6706
+ variant: "primary",
6707
+ style: { width: "100%" },
6708
+ loading: resuming,
6709
+ disabled: resuming,
6710
+ onClick: handleContinue,
6711
+ children: resuming ? "Resuming\u2026" : `Continue as ${continueAs.name}`
6712
+ }
6713
+ ),
6714
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
6715
+ "button",
6716
+ {
6717
+ type: "button",
6718
+ className: "fd-body-sm fd-muted",
6719
+ style: {
6720
+ background: "none",
6721
+ border: "none",
6722
+ cursor: "pointer",
6723
+ textDecoration: "underline",
6724
+ padding: 0
6725
+ },
6726
+ disabled: resuming,
6727
+ onClick: continueAs.onDecline,
6728
+ children: "Not you? Sign in with flytedesk ID"
6729
+ }
6730
+ )
6731
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
6732
+ Button,
6733
+ {
6734
+ variant: "primary",
6735
+ style: { width: "100%" },
6736
+ loading: signingIn,
6737
+ disabled: signingIn,
6738
+ onClick: handleSignIn,
6739
+ children: /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
6740
+ "span",
6741
+ {
6742
+ style: {
6743
+ display: "flex",
6744
+ flexDirection: "row",
6745
+ alignItems: "center",
6746
+ justifyContent: "center",
6747
+ gap: "var(--s-8)",
6748
+ flexWrap: "nowrap"
6749
+ },
6750
+ children: [
6751
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(GoogleGlyph, {}),
6752
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { children: signingIn ? "Signing in\u2026" : "Sign in with flytedesk ID" })
6753
+ ]
6754
+ }
6755
+ )
6756
+ }
6757
+ ),
6758
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("p", { className: "fd-body-sm fd-muted", style: { fontSize: "12px" }, children: "One account, every flytedesk app." })
6759
+ ]
6760
+ }
6761
+ ) })
6762
+ ]
6763
+ }
6764
+ )
6765
+ ]
6766
+ }
6767
+ )
6768
+ ]
6769
+ }
6770
+ );
6771
+ }
6772
+ function GoogleGlyph() {
6773
+ return /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 18 18", "aria-hidden": true, children: [
6774
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
6775
+ "path",
6776
+ {
6777
+ fill: "#4285F4",
6778
+ d: "M17.64 9.2c0-.64-.06-1.25-.16-1.84H9v3.48h4.84a4.14 4.14 0 0 1-1.8 2.72v2.26h2.92c1.7-1.57 2.68-3.87 2.68-6.62Z"
6779
+ }
6780
+ ),
6781
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
6782
+ "path",
6783
+ {
6784
+ fill: "#34A853",
6785
+ d: "M9 18c2.43 0 4.47-.8 5.96-2.18l-2.92-2.26c-.81.54-1.84.87-3.04.87-2.34 0-4.32-1.58-5.03-3.7H.96v2.33A9 9 0 0 0 9 18Z"
6786
+ }
6787
+ ),
6788
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
6789
+ "path",
6790
+ {
6791
+ fill: "#FBBC05",
6792
+ d: "M3.97 10.73A5.4 5.4 0 0 1 3.68 9c0-.6.1-1.19.29-1.73V4.94H.96A9 9 0 0 0 0 9c0 1.45.35 2.83.96 4.06l3.01-2.33Z"
6793
+ }
6794
+ ),
6795
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
6796
+ "path",
6797
+ {
6798
+ fill: "#EA4335",
6799
+ d: "M9 3.58c1.32 0 2.51.45 3.44 1.35l2.59-2.59C13.46.89 11.43 0 9 0A9 9 0 0 0 .96 4.94l3.01 2.33C4.68 5.16 6.66 3.58 9 3.58Z"
6800
+ }
6801
+ )
6802
+ ] });
6803
+ }
6804
+
6611
6805
  // src/components/platform/RoadmapTimeline.tsx
6612
- var React44 = __toESM(require("react"), 1);
6806
+ var React45 = __toESM(require("react"), 1);
6613
6807
 
6614
6808
  // src/kits/session.ts
6615
- var React42 = __toESM(require("react"), 1);
6809
+ var React43 = __toESM(require("react"), 1);
6616
6810
  var PERMISSION_CATALOG = [
6617
6811
  { group: "Plans", items: [
6618
6812
  { key: "plan.view", label: "View plans", detail: "Read any plan in the workspace." },
@@ -8179,8 +8373,8 @@ function roadmap(overrides) {
8179
8373
  };
8180
8374
  }
8181
8375
  function useSession() {
8182
- const [s, setS] = React42.useState(getSession);
8183
- React42.useEffect(() => subscribe(setS), []);
8376
+ const [s, setS] = React43.useState(getSession);
8377
+ React43.useEffect(() => subscribe(setS), []);
8184
8378
  return s;
8185
8379
  }
8186
8380
  var SessionKit = {
@@ -8213,7 +8407,7 @@ var SessionKit = {
8213
8407
  };
8214
8408
  function DemoSessionProvider({ children }) {
8215
8409
  const session = useSession();
8216
- const value = React42.useMemo(
8410
+ const value = React43.useMemo(
8217
8411
  () => ({
8218
8412
  user: session.user,
8219
8413
  roles: session.roles,
@@ -8229,11 +8423,11 @@ function DemoSessionProvider({ children }) {
8229
8423
  }),
8230
8424
  [session]
8231
8425
  );
8232
- return React42.createElement(SessionProvider, { value }, children);
8426
+ return React43.createElement(SessionProvider, { value }, children);
8233
8427
  }
8234
8428
 
8235
8429
  // src/kits/runtime.ts
8236
- var React43 = __toESM(require("react"), 1);
8430
+ var React44 = __toESM(require("react"), 1);
8237
8431
  var WIRED_ENDPOINTS = [
8238
8432
  // Nothing yet. Every id below would come from a real service:
8239
8433
  // "plan.get", "placements.list", …
@@ -8404,8 +8598,8 @@ var RuntimeKit = {
8404
8598
  };
8405
8599
  RuntimeKit.declare(FEATURE_NEEDS);
8406
8600
  function useRuntimeMode() {
8407
- const [m, setM] = React43.useState(RuntimeKit.getMode());
8408
- React43.useEffect(() => RuntimeKit.subscribe(setM), []);
8601
+ const [m, setM] = React44.useState(RuntimeKit.getMode());
8602
+ React44.useEffect(() => RuntimeKit.subscribe(setM), []);
8409
8603
  return m;
8410
8604
  }
8411
8605
  function useFeatureStatus(key) {
@@ -8424,7 +8618,7 @@ var UseRuntimeMode = useRuntimeMode;
8424
8618
  var UseFeatureStatus = useFeatureStatus;
8425
8619
 
8426
8620
  // src/components/platform/RoadmapTimeline.tsx
8427
- var import_jsx_runtime68 = require("react/jsx-runtime");
8621
+ var import_jsx_runtime69 = require("react/jsx-runtime");
8428
8622
  var STATUS = {
8429
8623
  shipped: { tone: "success", icon: "check-circle", label: "Wired" },
8430
8624
  next: { tone: "warning", icon: "traffic-cone", label: "Not wired" },
@@ -8439,45 +8633,45 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
8439
8633
  const s = STATUS[item.status] || STATUS.planned;
8440
8634
  const deps = (item.dependsOn || []).map((k) => byKey[k]).filter(Boolean);
8441
8635
  const blocking = deps.filter((d) => !d.implemented);
8442
- return /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(Card, { elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
8443
- /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
8444
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { className: "fd-body", style: { fontWeight: 700, flex: 1, minWidth: 140 }, children: item.label }),
8445
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(Badge, { tone: "neutral", icon: PROJECT_ICON[item.project] || "squares-four", children: item.project }),
8446
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(Badge, { tone: s.tone, icon: s.icon, children: s.label })
8636
+ return /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(Card, { elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
8637
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
8638
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-body", style: { fontWeight: 700, flex: 1, minWidth: 140 }, children: item.label }),
8639
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(Badge, { tone: "neutral", icon: PROJECT_ICON[item.project] || "squares-four", children: item.project }),
8640
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(Badge, { tone: s.tone, icon: s.icon, children: s.label })
8447
8641
  ] }),
8448
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: item.description }),
8449
- item.backend ? /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start" }, children: [
8450
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { className: "fd-overline fd-muted", style: { width: 62, flex: "none", paddingTop: 2 }, children: "Backend" }),
8451
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { className: "fd-body-sm", style: { flex: 1, textWrap: "pretty" }, children: item.backend })
8642
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: item.description }),
8643
+ item.backend ? /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start" }, children: [
8644
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-overline fd-muted", style: { width: 62, flex: "none", paddingTop: 2 }, children: "Backend" }),
8645
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-body-sm", style: { flex: 1, textWrap: "pretty" }, children: item.backend })
8452
8646
  ] }) : null,
8453
- /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
8454
- item.effort ? /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
8455
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("i", { className: "ph ph-hourglass-medium" }),
8647
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
8648
+ item.effort ? /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
8649
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("i", { className: "ph ph-hourglass-medium" }),
8456
8650
  " ",
8457
8651
  item.effort
8458
8652
  ] }) : null,
8459
- /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
8460
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("i", { className: "ph ph-user" }),
8653
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
8654
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("i", { className: "ph ph-user" }),
8461
8655
  " ",
8462
8656
  item.owner
8463
8657
  ] }),
8464
- item.screen ? /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(Badge, { tone: "neutral", icon: "browser", children: "screen" }) : null,
8465
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { style: { flex: 1 } }),
8466
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
8658
+ item.screen ? /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(Badge, { tone: "neutral", icon: "browser", children: "screen" }) : null,
8659
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { style: { flex: 1 } }),
8660
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
8467
8661
  "button",
8468
8662
  {
8469
8663
  type: "button",
8470
8664
  onClick: () => onOpenFlag && onOpenFlag(item.key),
8471
8665
  style: { all: "unset", cursor: "pointer", display: "inline-flex", alignItems: "center", gap: 5 },
8472
- children: /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("code", { className: "fd-mono", style: { fontSize: 11, color: "var(--brand)" }, children: item.key })
8666
+ children: /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("code", { className: "fd-mono", style: { fontSize: 11, color: "var(--brand)" }, children: item.key })
8473
8667
  }
8474
8668
  )
8475
8669
  ] }),
8476
- deps.length ? /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 6, borderTop: "1px solid var(--border)" }, children: [
8477
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { className: "fd-overline fd-muted", style: { paddingTop: 3 }, children: "After" }),
8478
- deps.map((d) => /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(Tag, { icon: d.implemented ? "check" : "clock", children: d.label }, d.key))
8670
+ deps.length ? /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 6, borderTop: "1px solid var(--border)" }, children: [
8671
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-overline fd-muted", style: { paddingTop: 3 }, children: "After" }),
8672
+ deps.map((d) => /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(Tag, { icon: d.implemented ? "check" : "clock", children: d.label }, d.key))
8479
8673
  ] }) : null,
8480
- blocking.length && !item.implemented ? /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("span", { className: "fd-body-sm", style: { color: "var(--warn-text)" }, children: [
8674
+ blocking.length && !item.implemented ? /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "fd-body-sm", style: { color: "var(--warn-text)" }, children: [
8481
8675
  "Blocked until ",
8482
8676
  blocking.map((d) => d.label).join(" and "),
8483
8677
  " ",
@@ -8488,12 +8682,12 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
8488
8682
  }
8489
8683
  function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
8490
8684
  const session = SessionKit.useSession();
8491
- const [project, setProject] = React44.useState("");
8492
- const [q, setQ] = React44.useState("");
8493
- const scrollRef = React44.useRef(null);
8494
- const nowRef = React44.useRef(null);
8495
- const rm = React44.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
8496
- const byKey = React44.useMemo(() => {
8685
+ const [project, setProject] = React45.useState("");
8686
+ const [q, setQ] = React45.useState("");
8687
+ const scrollRef = React45.useRef(null);
8688
+ const nowRef = React45.useRef(null);
8689
+ const rm = React45.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
8690
+ const byKey = React45.useMemo(() => {
8497
8691
  const m = {};
8498
8692
  rm.items.forEach((i) => {
8499
8693
  m[i.key] = i;
@@ -8502,7 +8696,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
8502
8696
  }, [rm]);
8503
8697
  const items = rm.items.filter((i) => (!project || i.project === project) && (!q || (i.label + " " + i.description + " " + (i.backend || "") + " " + i.key).toLowerCase().includes(q.toLowerCase())));
8504
8698
  const projects = [...new Set(rm.items.map((i) => i.project))];
8505
- React44.useEffect(() => {
8699
+ React45.useEffect(() => {
8506
8700
  let raf1 = 0, raf2 = 0;
8507
8701
  const place = () => {
8508
8702
  const box = scrollRef.current, mark = nowRef.current;
@@ -8530,23 +8724,23 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
8530
8724
  }, 0);
8531
8725
  const nextPhase = items.find((i) => !i.implemented);
8532
8726
  let lastPhase = null;
8533
- return /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "fd-stack", style: { gap: 16, maxWidth: 1e3 }, children: [
8534
- /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
8535
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { className: "fd-overline fd-muted", children: "Architecture" }),
8536
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
8537
- /* @__PURE__ */ (0, import_jsx_runtime68.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." })
8727
+ return /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-stack", style: { gap: 16, maxWidth: 1e3 }, children: [
8728
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
8729
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-overline fd-muted", children: "Architecture" }),
8730
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
8731
+ /* @__PURE__ */ (0, import_jsx_runtime69.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." })
8538
8732
  ] }),
8539
- /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "fd-grid-stats is-thin", children: [
8540
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(StatTile, { compact: true, label: "Wired", value: String(rm.shipped), sub: "of " + rm.items.length + " features" }),
8541
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(StatTile, { compact: true, label: "Remaining", value: String(rm.remaining), sub: "backend work" }),
8542
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(StatTile, { compact: true, label: "Est. effort", value: days ? days + " days" : "\u2014", sub: "sum of estimates, not calendar" }),
8543
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(StatTile, { compact: true, label: "Up next", value: nextPhase ? "Phase " + nextPhase.phase : "\u2014", sub: nextPhase ? nextPhase.phaseName : "all wired" })
8733
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-grid-stats is-thin", children: [
8734
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(StatTile, { compact: true, label: "Wired", value: String(rm.shipped), sub: "of " + rm.items.length + " features" }),
8735
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(StatTile, { compact: true, label: "Remaining", value: String(rm.remaining), sub: "backend work" }),
8736
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(StatTile, { compact: true, label: "Est. effort", value: days ? days + " days" : "\u2014", sub: "sum of estimates, not calendar" }),
8737
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(StatTile, { compact: true, label: "Up next", value: nextPhase ? "Phase " + nextPhase.phase : "\u2014", sub: nextPhase ? nextPhase.phaseName : "all wired" })
8544
8738
  ] }),
8545
- /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
8546
- /* @__PURE__ */ (0, import_jsx_runtime68.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 } }),
8547
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(Select, { placeholder: "All projects", value: project, onChange: (e) => setProject(e.target.value), options: projects, style: { width: 190 } }),
8548
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { style: { flex: 1 } }),
8549
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
8739
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
8740
+ /* @__PURE__ */ (0, import_jsx_runtime69.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 } }),
8741
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(Select, { placeholder: "All projects", value: project, onChange: (e) => setProject(e.target.value), options: projects, style: { width: 190 } }),
8742
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { style: { flex: 1 } }),
8743
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
8550
8744
  Button,
8551
8745
  {
8552
8746
  size: "sm",
@@ -8560,7 +8754,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
8560
8754
  }
8561
8755
  )
8562
8756
  ] }),
8563
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
8757
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
8564
8758
  Flag,
8565
8759
  {
8566
8760
  tone: "info",
@@ -8569,60 +8763,60 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
8569
8763
  actions: null
8570
8764
  }
8571
8765
  ),
8572
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("div", { className: "fd-rm", children: /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("div", { className: "fd-rm-scroll", ref: scrollRef, children: /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "fd-rm-track", children: [
8573
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { className: "fd-rm-spine", children: /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { className: "fd-rm-spine-done", style: { height: items.length ? 100 * shippedShown / items.length + "%" : "0%" } }) }),
8766
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("div", { className: "fd-rm", children: /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("div", { className: "fd-rm-scroll", ref: scrollRef, children: /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-rm-track", children: [
8767
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-rm-spine", children: /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-rm-spine-done", style: { height: items.length ? 100 * shippedShown / items.length + "%" : "0%" } }) }),
8574
8768
  items.map((item, n) => {
8575
8769
  const showPhase = item.phase !== lastPhase;
8576
8770
  lastPhase = item.phase;
8577
8771
  const inPhase = items.filter((i) => i.phase === item.phase).length;
8578
8772
  const isBoundary = n === firstPending;
8579
- return /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(React44.Fragment, { children: [
8580
- showPhase ? /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "fd-rm-era", children: [
8581
- /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
8582
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
8583
- item.phase === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("span", { className: "fd-mono", style: { opacity: 0.7, fontWeight: 400 }, children: [
8773
+ return /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)(React45.Fragment, { children: [
8774
+ showPhase ? /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-rm-era", children: [
8775
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
8776
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
8777
+ item.phase === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "fd-mono", style: { opacity: 0.7, fontWeight: 400 }, children: [
8584
8778
  fmtDate(item.phaseStart),
8585
8779
  " \u2013 ",
8586
8780
  fmtDate(item.date)
8587
8781
  ] }),
8588
- /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("span", { style: { opacity: 0.7, fontWeight: 400 }, children: [
8782
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { style: { opacity: 0.7, fontWeight: 400 }, children: [
8589
8783
  "\xB7 ",
8590
8784
  inPhase,
8591
8785
  " feature",
8592
8786
  inPhase === 1 ? "" : "s"
8593
8787
  ] })
8594
8788
  ] }),
8595
- item.phaseWhy ? /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("p", { className: "fd-rm-era-why", children: item.phaseWhy }) : null
8789
+ item.phaseWhy ? /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("p", { className: "fd-rm-era-why", children: item.phaseWhy }) : null
8596
8790
  ] }) : null,
8597
- isBoundary ? /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("div", { className: "fd-rm-now", ref: nowRef, children: /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("span", { className: "fd-rm-now-pill", children: [
8598
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("i", { className: "ph ph-map-pin" }),
8791
+ isBoundary ? /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("div", { className: "fd-rm-now", ref: nowRef, children: /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "fd-rm-now-pill", children: [
8792
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("i", { className: "ph ph-map-pin" }),
8599
8793
  " You are here \u2014 everything above is wired"
8600
8794
  ] }) }) : null,
8601
- /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "fd-rm-row", children: [
8602
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { className: "fd-rm-dot " + (item.implemented ? "is-shipped" : item.status === "next" ? "is-next" : "") }),
8603
- /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "fd-rm-date", children: [
8795
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-rm-row", children: [
8796
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-rm-dot " + (item.implemented ? "is-shipped" : item.status === "next" ? "is-next" : "") }),
8797
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-rm-date", children: [
8604
8798
  fmtDate(item.date),
8605
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("br", {}),
8606
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { style: { opacity: 0.75 }, children: item.implemented ? "shipped" : "phase " + item.phase })
8799
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("br", {}),
8800
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { style: { opacity: 0.75 }, children: item.implemented ? "shipped" : "phase " + item.phase })
8607
8801
  ] }),
8608
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(RoadmapCard, { item, byKey, onOpenFlag })
8802
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(RoadmapCard, { item, byKey, onOpenFlag })
8609
8803
  ] })
8610
8804
  ] }, item.key);
8611
8805
  }),
8612
- !items.length ? /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("p", { className: "fd-body-sm fd-muted", children: "Nothing matches that filter." }) : null
8806
+ !items.length ? /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("p", { className: "fd-body-sm fd-muted", children: "Nothing matches that filter." }) : null
8613
8807
  ] }) }) }),
8614
- /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: [
8808
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: [
8615
8809
  "Derived from the feature-flag registry \u2014 each entry's status is its flag's ",
8616
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("code", { className: "fd-mono", children: "implemented" }),
8810
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("code", { className: "fd-mono", children: "implemented" }),
8617
8811
  " field, so this page cannot drift from what the apps actually do."
8618
8812
  ] })
8619
8813
  ] });
8620
8814
  }
8621
8815
 
8622
8816
  // src/components/platform/ComingSoon.tsx
8623
- var React45 = __toESM(require("react"), 1);
8817
+ var React46 = __toESM(require("react"), 1);
8624
8818
  var import_react_dom6 = require("react-dom");
8625
- var import_jsx_runtime69 = require("react/jsx-runtime");
8819
+ var import_jsx_runtime70 = require("react/jsx-runtime");
8626
8820
  var BYPASS_STORE = "fd.soon.bypass.v1";
8627
8821
  function readBypassed() {
8628
8822
  try {
@@ -8638,8 +8832,8 @@ function writeBypassed(list) {
8638
8832
  }
8639
8833
  }
8640
8834
  function useBypass(key) {
8641
- const [on, setOn] = React45.useState(() => !!key && readBypassed().indexOf(key) >= 0);
8642
- React45.useEffect(() => {
8835
+ const [on, setOn] = React46.useState(() => !!key && readBypassed().indexOf(key) >= 0);
8836
+ React46.useEffect(() => {
8643
8837
  setOn(!!key && readBypassed().indexOf(key) >= 0);
8644
8838
  }, [key]);
8645
8839
  const set = (next) => {
@@ -8652,43 +8846,43 @@ function useBypass(key) {
8652
8846
  return [on, set];
8653
8847
  }
8654
8848
  function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass }) {
8655
- return /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)(import_jsx_runtime69.Fragment, { children: [
8656
- /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "fd-soon-badge", children: [
8657
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
8849
+ return /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)(import_jsx_runtime70.Fragment, { children: [
8850
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { className: "fd-soon-badge", children: [
8851
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
8658
8852
  label
8659
8853
  ] }),
8660
- detail ? /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-soon-detail", children: detail }) : null,
8661
- backend ? /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "fd-soon-backend", children: [
8662
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-overline", children: "Needs" }),
8854
+ detail ? /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("span", { className: "fd-soon-detail", children: detail }) : null,
8855
+ backend ? /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { className: "fd-soon-backend", children: [
8856
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("span", { className: "fd-overline", children: "Needs" }),
8663
8857
  " ",
8664
8858
  backend
8665
8859
  ] }) : null,
8666
- eta || effort || onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "fd-soon-meta", children: [
8667
- eta ? /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { children: [
8668
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }),
8860
+ eta || effort || onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { className: "fd-soon-meta", children: [
8861
+ eta ? /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { children: [
8862
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }),
8669
8863
  " ",
8670
8864
  eta
8671
8865
  ] }) : null,
8672
- effort ? /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { children: [
8673
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("i", { className: "ph ph-hourglass-medium", "aria-hidden": "true" }),
8866
+ effort ? /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { children: [
8867
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-hourglass-medium", "aria-hidden": "true" }),
8674
8868
  " ",
8675
8869
  effort
8676
8870
  ] }) : null,
8677
- onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
8871
+ onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
8678
8872
  "See the roadmap ",
8679
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
8873
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
8680
8874
  ] }) : null
8681
8875
  ] }) : null,
8682
- allowed ? /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("button", { type: "button", className: "fd-soon-view", onClick: onBypass, children: [
8683
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("i", { className: "ph ph-eye", "aria-hidden": "true" }),
8876
+ allowed ? /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("button", { type: "button", className: "fd-soon-view", onClick: onBypass, children: [
8877
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-eye", "aria-hidden": "true" }),
8684
8878
  " View and use it anyway"
8685
8879
  ] }) : null
8686
8880
  ] });
8687
8881
  }
8688
8882
  function useHoverCard(open) {
8689
- const anchor = React45.useRef(null);
8690
- const [pos, setPos] = React45.useState(null);
8691
- React45.useLayoutEffect(() => {
8883
+ const anchor = React46.useRef(null);
8884
+ const [pos, setPos] = React46.useState(null);
8885
+ React46.useLayoutEffect(() => {
8692
8886
  if (!open || !anchor.current) {
8693
8887
  setPos(null);
8694
8888
  return;
@@ -8740,9 +8934,9 @@ function ComingSoon({
8740
8934
  const tip = [label, detail, backend ? "Needs " + backend : null, eta ? "ETA " + eta : null, effort].filter(Boolean).join(" \xB7 ");
8741
8935
  if (inline) {
8742
8936
  if (allowed && bypassed) {
8743
- return /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: ["fd-soon-inline-on", className].filter(Boolean).join(" "), ...rest, children: [
8937
+ return /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { className: ["fd-soon-inline-on", className].filter(Boolean).join(" "), ...rest, children: [
8744
8938
  children,
8745
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
8939
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
8746
8940
  "button",
8747
8941
  {
8748
8942
  type: "button",
@@ -8750,12 +8944,12 @@ function ComingSoon({
8750
8944
  title: "Unwired \u2014 writes go to the simulated backend. " + tip + " Click to re-blur.",
8751
8945
  onClick: () => setBypassed(false),
8752
8946
  "aria-label": "Re-blur this unwired feature",
8753
- children: /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
8947
+ children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
8754
8948
  }
8755
8949
  )
8756
8950
  ] });
8757
8951
  }
8758
- return /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
8952
+ return /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
8759
8953
  InlineSoon,
8760
8954
  {
8761
8955
  label,
@@ -8775,20 +8969,20 @@ function ComingSoon({
8775
8969
  );
8776
8970
  }
8777
8971
  if (allowed && bypassed) {
8778
- return /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, ...rest, children: [
8779
- /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-soon-bar", role: "status", children: [
8780
- /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "fd-soon-badge", children: [
8781
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
8972
+ return /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, ...rest, children: [
8973
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("div", { className: "fd-soon-bar", role: "status", children: [
8974
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { className: "fd-soon-badge", children: [
8975
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
8782
8976
  "Unwired feature \u2014 you are using it anyway"
8783
8977
  ] }),
8784
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-soon-bar-detail", children: "Every action here writes to the simulated backend, so nothing you do persists beyond this session." }),
8785
- /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "fd-soon-bar-actions", children: [
8786
- onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
8978
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("span", { className: "fd-soon-bar-detail", children: "Every action here writes to the simulated backend, so nothing you do persists beyond this session." }),
8979
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { className: "fd-soon-bar-actions", children: [
8980
+ onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
8787
8981
  "Roadmap ",
8788
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
8982
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
8789
8983
  ] }) : null,
8790
- /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => setBypassed(false), children: [
8791
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("i", { className: "ph ph-eye-slash", "aria-hidden": "true" }),
8984
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => setBypassed(false), children: [
8985
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-eye-slash", "aria-hidden": "true" }),
8792
8986
  " Re-blur"
8793
8987
  ] })
8794
8988
  ] })
@@ -8796,10 +8990,10 @@ function ComingSoon({
8796
8990
  children
8797
8991
  ] });
8798
8992
  }
8799
- return /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: ["fd-soon", className].filter(Boolean).join(" "), style: minHeight ? { minHeight } : void 0, ...rest, children: [
8800
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("div", { className: "fd-soon-under", style: { filter: "blur(" + blur + "px) saturate(.62)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
8801
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("div", { className: "fd-soon-veil" }),
8802
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("div", { className: "fd-soon-note", role: "note", children: /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
8993
+ return /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("div", { className: ["fd-soon", className].filter(Boolean).join(" "), style: minHeight ? { minHeight } : void 0, ...rest, children: [
8994
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("div", { className: "fd-soon-under", style: { filter: "blur(" + blur + "px) saturate(.62)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
8995
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("div", { className: "fd-soon-veil" }),
8996
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("div", { className: "fd-soon-note", role: "note", children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
8803
8997
  SoonCard,
8804
8998
  {
8805
8999
  label,
@@ -8815,10 +9009,10 @@ function ComingSoon({
8815
9009
  ] });
8816
9010
  }
8817
9011
  function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass, blur, tip, className, rest, children }) {
8818
- const [open, setOpen] = React45.useState(false);
9012
+ const [open, setOpen] = React46.useState(false);
8819
9013
  const [anchor, pos] = useHoverCard(open);
8820
9014
  const zIndex = useOverlayLayer(open);
8821
- const close = React45.useRef(null);
9015
+ const close = React46.useRef(null);
8822
9016
  const show = () => {
8823
9017
  if (close.current) {
8824
9018
  clearTimeout(close.current);
@@ -8834,10 +9028,10 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
8834
9028
  setOpen(false);
8835
9029
  }, 140);
8836
9030
  };
8837
- React45.useEffect(() => () => {
9031
+ React46.useEffect(() => () => {
8838
9032
  if (close.current) clearTimeout(close.current);
8839
9033
  }, []);
8840
- return /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)(
9034
+ return /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)(
8841
9035
  "span",
8842
9036
  {
8843
9037
  ref: anchor,
@@ -8848,8 +9042,8 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
8848
9042
  onBlur: hide,
8849
9043
  ...rest,
8850
9044
  children: [
8851
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-soon-under", style: { filter: "blur(" + Math.min(blur, 1.1) + "px) saturate(.66)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
8852
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
9045
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("span", { className: "fd-soon-under", style: { filter: "blur(" + Math.min(blur, 1.1) + "px) saturate(.66)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
9046
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
8853
9047
  "button",
8854
9048
  {
8855
9049
  type: "button",
@@ -8860,11 +9054,11 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
8860
9054
  onFocus: show,
8861
9055
  onBlur: hide,
8862
9056
  onClick: () => open ? setOpen(false) : show(),
8863
- children: /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
9057
+ children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
8864
9058
  }
8865
9059
  ),
8866
9060
  open && pos ? (0, import_react_dom6.createPortal)(
8867
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(LayerProvider, { zIndex, children: /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
9061
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(LayerProvider, { zIndex, children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
8868
9062
  "div",
8869
9063
  {
8870
9064
  className: "fd-soon-note fd-soon-hovercard",
@@ -8872,7 +9066,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
8872
9066
  style: { position: "fixed", left: pos.left, top: pos.top, bottom: pos.bottom, width: pos.width, zIndex },
8873
9067
  onMouseEnter: show,
8874
9068
  onMouseLeave: hide,
8875
- children: /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
9069
+ children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
8876
9070
  SoonCard,
8877
9071
  {
8878
9072
  label,
@@ -8902,10 +9096,10 @@ function formatEta(iso2) {
8902
9096
  var FormatEta = formatEta;
8903
9097
 
8904
9098
  // src/components/platform/Gate.tsx
8905
- var import_jsx_runtime70 = require("react/jsx-runtime");
9099
+ var import_jsx_runtime71 = require("react/jsx-runtime");
8906
9100
  function PermissionDenied({ permission, title, detail, compact: compact3 = false, className = "", ...rest }) {
8907
9101
  const need = Array.isArray(permission) ? permission : [permission].filter(Boolean);
8908
- return /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)(
9102
+ return /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(
8909
9103
  "div",
8910
9104
  {
8911
9105
  className: ["fd-stack", className].filter(Boolean).join(" "),
@@ -8921,14 +9115,14 @@ function PermissionDenied({ permission, title, detail, compact: compact3 = false
8921
9115
  },
8922
9116
  ...rest,
8923
9117
  children: [
8924
- /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { className: "fd-row", style: { gap: 8 }, children: [
8925
- /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-lock-simple", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
8926
- /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("span", { className: compact3 ? "fd-label-lg" : "fd-h3", children: title || "You do not have access to this" })
9118
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("span", { className: "fd-row", style: { gap: 8 }, children: [
9119
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("i", { className: "ph ph-lock-simple", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
9120
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("span", { className: compact3 ? "fd-label-lg" : "fd-h3", children: title || "You do not have access to this" })
8927
9121
  ] }),
8928
- /* @__PURE__ */ (0, import_jsx_runtime70.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." }),
8929
- need.length ? /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: [
8930
- /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("span", { className: "fd-overline fd-muted", children: "Requires" }),
8931
- need.map((p) => /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("code", { className: "fd-mono", style: {
9122
+ /* @__PURE__ */ (0, import_jsx_runtime71.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." }),
9123
+ need.length ? /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: [
9124
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("span", { className: "fd-overline fd-muted", children: "Requires" }),
9125
+ need.map((p) => /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("code", { className: "fd-mono", style: {
8932
9126
  fontSize: 11.5,
8933
9127
  padding: "2px 7px",
8934
9128
  borderRadius: 5,
@@ -8949,7 +9143,7 @@ function Gate({ perm, anyOf, role, silent = false, fallback, compact: compact3 =
8949
9143
  if (ok) return children;
8950
9144
  if (fallback !== void 0) return fallback;
8951
9145
  if (silent) return null;
8952
- return /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(PermissionDenied, { permission: perm || anyOf, compact: compact3 });
9146
+ return /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(PermissionDenied, { permission: perm || anyOf, compact: compact3 });
8953
9147
  }
8954
9148
  function FeatureGate({
8955
9149
  flag,
@@ -8972,7 +9166,7 @@ function FeatureGate({
8972
9166
  const f = SessionKit.findFlag(flag) || {};
8973
9167
  const missing = rt.missing || [];
8974
9168
  const canBypass = bypassPerm === null ? false : !bypassPerm || can2(bypassPerm);
8975
- return /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
9169
+ return /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
8976
9170
  ComingSoon,
8977
9171
  {
8978
9172
  label: label || (variant === "inline" ? f.label || "Not wired yet" : "Designed \u2014 backend not wired yet"),
@@ -8993,26 +9187,26 @@ function FeatureGate({
8993
9187
  function PermissionHint({ perm, children }) {
8994
9188
  const { can: can2 } = useSessionContext();
8995
9189
  if (can2(perm)) return children;
8996
- return /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
9190
+ return /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
8997
9191
  "span",
8998
9192
  {
8999
9193
  title: "Requires " + (Array.isArray(perm) ? perm.join(", ") : perm),
9000
9194
  style: { display: "inline-flex", opacity: 0.45, cursor: "not-allowed" },
9001
9195
  "aria-disabled": "true",
9002
- children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("span", { style: { pointerEvents: "none" }, children })
9196
+ children: /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("span", { style: { pointerEvents: "none" }, children })
9003
9197
  }
9004
9198
  );
9005
9199
  }
9006
9200
 
9007
9201
  // src/components/platform/ModeSwitch.tsx
9008
- var React46 = __toESM(require("react"), 1);
9009
- var import_jsx_runtime71 = require("react/jsx-runtime");
9202
+ var React47 = __toESM(require("react"), 1);
9203
+ var import_jsx_runtime72 = require("react/jsx-runtime");
9010
9204
  function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
9011
9205
  const mode2 = useRuntimeMode();
9012
- const [open, setOpen] = React46.useState(false);
9206
+ const [open, setOpen] = React47.useState(false);
9013
9207
  const zIndex = useOverlayLayer(open);
9014
- const ref = React46.useRef(null);
9015
- React46.useEffect(() => {
9208
+ const ref = React47.useRef(null);
9209
+ React47.useEffect(() => {
9016
9210
  if (!open) return;
9017
9211
  const away = (e) => {
9018
9212
  if (ref.current && !ref.current.contains(e.target)) setOpen(false);
@@ -9034,8 +9228,8 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
9034
9228
  RuntimeKit.setMode(next);
9035
9229
  setOpen(false);
9036
9230
  };
9037
- return /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("span", { style: { position: "relative", display: "inline-flex" }, ref, children: [
9038
- /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(
9231
+ return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { style: { position: "relative", display: "inline-flex" }, ref, children: [
9232
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)(
9039
9233
  "button",
9040
9234
  {
9041
9235
  type: "button",
@@ -9045,29 +9239,29 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
9045
9239
  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.",
9046
9240
  className: "fd-mode-btn" + (test ? " is-test" : "") + (open ? " is-open" : ""),
9047
9241
  children: [
9048
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), style: { fontSize: 17 } }),
9049
- test && requestCount ? /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("span", { className: "fd-mono fd-mode-count", children: requestCount > 99 ? "99+" : requestCount }, requestCount) : null
9242
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), style: { fontSize: 17 } }),
9243
+ test && requestCount ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fd-mono fd-mode-count", children: requestCount > 99 ? "99+" : requestCount }, requestCount) : null
9050
9244
  ]
9051
9245
  }
9052
9246
  ),
9053
- open ? /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(LayerProvider, { zIndex, children: /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("span", { className: "fd-view-enter fd-mode-pop", style: { zIndex }, children: [
9054
- /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("span", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
9055
- /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("span", { className: "fd-badge " + (test ? "fd-badge-warning" : "fd-badge-neutral"), children: [
9056
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), "aria-hidden": "true" }),
9247
+ open ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(LayerProvider, { zIndex, children: /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-view-enter fd-mode-pop", style: { zIndex }, children: [
9248
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
9249
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-badge " + (test ? "fd-badge-warning" : "fd-badge-neutral"), children: [
9250
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), "aria-hidden": "true" }),
9057
9251
  test ? "Test mode" : "Live mode"
9058
9252
  ] }),
9059
- test ? /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
9253
+ test ? /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
9060
9254
  requestCount,
9061
9255
  " simulated request",
9062
9256
  requestCount === 1 ? "" : "s"
9063
9257
  ] }) : null,
9064
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("span", { style: { flex: 1 } }),
9065
- test && onClearLog ? /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("button", { type: "button", className: "fd-soon-link", onClick: onClearLog, children: "Clear" }) : null
9258
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { style: { flex: 1 } }),
9259
+ test && onClearLog ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("button", { type: "button", className: "fd-soon-link", onClick: onClearLog, children: "Clear" }) : null
9066
9260
  ] }),
9067
- /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("span", { style: { display: "block", padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
9068
- /* @__PURE__ */ (0, import_jsx_runtime71.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." }),
9069
- /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("span", { className: "fd-row", style: { gap: 8, marginTop: 10, flexWrap: "wrap" }, children: [
9070
- /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
9261
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { style: { display: "block", padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
9262
+ /* @__PURE__ */ (0, import_jsx_runtime72.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." }),
9263
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-row", style: { gap: 8, marginTop: 10, flexWrap: "wrap" }, children: [
9264
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
9071
9265
  s.endpointsWired,
9072
9266
  " endpoint",
9073
9267
  s.endpointsWired === 1 ? "" : "s",
@@ -9077,58 +9271,58 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
9077
9271
  s.total,
9078
9272
  " features complete"
9079
9273
  ] }),
9080
- onOpenSpec ? /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(import_jsx_runtime71.Fragment, { children: [
9081
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("span", { style: { flex: 1 } }),
9082
- /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => {
9274
+ onOpenSpec ? /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)(import_jsx_runtime72.Fragment, { children: [
9275
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { style: { flex: 1 } }),
9276
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => {
9083
9277
  setOpen(false);
9084
9278
  onOpenSpec();
9085
9279
  }, children: [
9086
9280
  "API spec ",
9087
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
9281
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
9088
9282
  ] })
9089
9283
  ] }) : null
9090
9284
  ] })
9091
9285
  ] }),
9092
- /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("span", { className: "fd-mode-choice", children: [
9093
- /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("button", { type: "button", className: "fd-mode-opt" + (!test ? " is-on" : ""), onClick: () => go("live"), children: [
9094
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
9095
- /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("span", { className: "fd-mode-opt-text", children: [
9096
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("span", { className: "fd-mode-opt-title", children: "Live mode" }),
9097
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("span", { className: "fd-mode-opt-desc", children: "Incomplete features under construction" })
9286
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-mode-choice", children: [
9287
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("button", { type: "button", className: "fd-mode-opt" + (!test ? " is-on" : ""), onClick: () => go("live"), children: [
9288
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
9289
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-mode-opt-text", children: [
9290
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fd-mode-opt-title", children: "Live mode" }),
9291
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fd-mode-opt-desc", children: "Incomplete features under construction" })
9098
9292
  ] }),
9099
- !test ? /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
9293
+ !test ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
9100
9294
  ] }),
9101
- /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("button", { type: "button", className: "fd-mode-opt" + (test ? " is-on" : ""), onClick: () => go("test"), children: [
9102
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("i", { className: "ph ph-flask", "aria-hidden": "true" }),
9103
- /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("span", { className: "fd-mode-opt-text", children: [
9104
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("span", { className: "fd-mode-opt-title", children: "Test mode" }),
9105
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("span", { className: "fd-mode-opt-desc", children: "Everything usable, all data simulated" })
9295
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("button", { type: "button", className: "fd-mode-opt" + (test ? " is-on" : ""), onClick: () => go("test"), children: [
9296
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-flask", "aria-hidden": "true" }),
9297
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-mode-opt-text", children: [
9298
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fd-mode-opt-title", children: "Test mode" }),
9299
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fd-mode-opt-desc", children: "Everything usable, all data simulated" })
9106
9300
  ] }),
9107
- test ? /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
9301
+ test ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
9108
9302
  ] })
9109
9303
  ] }),
9110
- test && renderLog ? /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("span", { style: { display: "block", maxHeight: 340, overflowY: "auto", borderTop: "1px solid var(--border)" }, children: renderLog() }) : null
9304
+ test && renderLog ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { style: { display: "block", maxHeight: 340, overflowY: "auto", borderTop: "1px solid var(--border)" }, children: renderLog() }) : null
9111
9305
  ] }) }) : null
9112
9306
  ] });
9113
9307
  }
9114
9308
  function TestModeBar({ onExit }) {
9115
9309
  const mode2 = useRuntimeMode();
9116
9310
  if (mode2 !== "test") return null;
9117
- return /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("div", { className: "fd-testbar", role: "status", children: [
9118
- /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("span", { className: "fd-badge fd-badge-warning", children: [
9119
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("i", { className: "ph ph-flask", "aria-hidden": "true" }),
9311
+ return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("div", { className: "fd-testbar", role: "status", children: [
9312
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-badge fd-badge-warning", children: [
9313
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-flask", "aria-hidden": "true" }),
9120
9314
  "Test mode"
9121
9315
  ] }),
9122
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("span", { className: "fd-testbar-detail", children: "Every feature is unlocked and every response is simulated \u2014 nothing here persists." }),
9123
- /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => onExit ? onExit() : RuntimeKit.setMode("live"), children: [
9124
- /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
9316
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fd-testbar-detail", children: "Every feature is unlocked and every response is simulated \u2014 nothing here persists." }),
9317
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => onExit ? onExit() : RuntimeKit.setMode("live"), children: [
9318
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
9125
9319
  " Back to live mode"
9126
9320
  ] })
9127
9321
  ] });
9128
9322
  }
9129
9323
 
9130
9324
  // src/components/planner/ChannelMeta.tsx
9131
- var import_jsx_runtime72 = require("react/jsx-runtime");
9325
+ var import_jsx_runtime73 = require("react/jsx-runtime");
9132
9326
  var CHANNEL_WEIGHTS = {
9133
9327
  "OOH": 50,
9134
9328
  "DOOH": 50,
@@ -9181,9 +9375,9 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
9181
9375
  const m = ChannelMeta(channel);
9182
9376
  const wt = channelWeightOf(channel || "");
9183
9377
  if (dot) {
9184
- return /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: ["fd-chan-dot", className].filter(Boolean).join(" "), title: m.name, style: { background: m.color }, ...rest });
9378
+ return /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: ["fd-chan-dot", className].filter(Boolean).join(" "), title: m.name, style: { background: m.color }, ...rest });
9185
9379
  }
9186
- return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)(
9380
+ return /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)(
9187
9381
  "span",
9188
9382
  {
9189
9383
  className: ["fd-chan", size === "sm" ? "fd-chan-sm" : "", className].filter(Boolean).join(" "),
@@ -9191,16 +9385,16 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
9191
9385
  style: { "--chan": m.color },
9192
9386
  ...rest,
9193
9387
  children: [
9194
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }),
9195
- showLabel ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fd-chan-label", children: m.label }) : null,
9196
- weight ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fd-chan-weight", children: wt || 0 }) : null
9388
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }),
9389
+ showLabel ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fd-chan-label", children: m.label }) : null,
9390
+ weight ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fd-chan-weight", children: wt || 0 }) : null
9197
9391
  ]
9198
9392
  }
9199
9393
  );
9200
9394
  }
9201
9395
 
9202
9396
  // src/components/planner/SaturationDistribution.tsx
9203
- var import_jsx_runtime73 = require("react/jsx-runtime");
9397
+ var import_jsx_runtime74 = require("react/jsx-runtime");
9204
9398
  var BANDS2 = [
9205
9399
  { key: "weak", label: "Weak", n: 1, range: "< 50" },
9206
9400
  { key: "adequate", label: "Adequate", n: 2, range: "50\u2013100" },
@@ -9211,24 +9405,24 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
9211
9405
  const grouped = BANDS2.map((b) => ({ ...b, items: campuses.filter((c) => c.band === b.key) }));
9212
9406
  const tallest = Math.max(1, ...grouped.map((g) => g.items.length));
9213
9407
  const floor = BANDS2.find((b) => b.key === floorBand) || BANDS2[0];
9214
- return /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
9215
- /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("div", { style: { display: "grid", gridTemplateColumns: "repeat(4,minmax(0,1fr))", gap: 12, alignItems: "end" }, children: grouped.map((g) => {
9408
+ return /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
9409
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("div", { style: { display: "grid", gridTemplateColumns: "repeat(4,minmax(0,1fr))", gap: 12, alignItems: "end" }, children: grouped.map((g) => {
9216
9410
  const mark = "var(--csi-" + g.n + "-mark)";
9217
9411
  const active = selectedBand === g.key;
9218
- return /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)(
9412
+ return /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)(
9219
9413
  "button",
9220
9414
  {
9221
9415
  type: "button",
9222
9416
  onClick: onSelectBand ? () => onSelectBand(active ? null : g.key) : void 0,
9223
9417
  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, minWidth: 0, transition: "background var(--dur-fast) var(--ease),border-color var(--dur-fast) var(--ease)" },
9224
9418
  children: [
9225
- /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { style: { display: "flex", flexDirection: "column-reverse", gap: 4, minHeight: tallest * 24, minWidth: 0 }, children: loading ? Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fd-skel", style: { height: 16, borderRadius: 4 } }, i)) : g.items.map((c) => (
9419
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { style: { display: "flex", flexDirection: "column-reverse", gap: 4, minHeight: tallest * 24, minWidth: 0 }, children: loading ? Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { className: "fd-skel", style: { height: 16, borderRadius: 4 } }, i)) : g.items.map((c) => (
9226
9420
  // `overflow: hidden` + `white-space: nowrap` only clips once the span
9227
9421
  // actually HAS a bounded width to clip against (see the grid/flex
9228
9422
  // `minWidth: 0` chain above) — `textOverflow: ellipsis` then makes
9229
9423
  // that clip readable instead of a hard cut mid-letter; the full name
9230
9424
  // is still one hover away via `title`.
9231
- /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(
9425
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(
9232
9426
  "span",
9233
9427
  {
9234
9428
  title: c.name + " \xB7 " + c.crp,
@@ -9238,13 +9432,13 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
9238
9432
  c.name
9239
9433
  )
9240
9434
  )) }),
9241
- /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("span", { className: "fd-row", style: { gap: 8, alignItems: "baseline" }, children: [
9242
- /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fd-num-hero", style: { fontSize: 30, color: g.items.length ? "var(--text)" : "var(--text-disabled)" }, children: loading ? "\u2013" : g.items.length }),
9243
- /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fd-meter", style: { gap: 2, color: mark }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fd-meter-seg" + (i <= g.n ? " is-on" : ""), style: { width: 4, height: 9 } }, i)) })
9435
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("span", { className: "fd-row", style: { gap: 8, alignItems: "baseline" }, children: [
9436
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { className: "fd-num-hero", style: { fontSize: 30, color: g.items.length ? "var(--text)" : "var(--text-disabled)" }, children: loading ? "\u2013" : g.items.length }),
9437
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { className: "fd-meter", style: { gap: 2, color: mark }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { className: "fd-meter-seg" + (i <= g.n ? " is-on" : ""), style: { width: 4, height: 9 } }, i)) })
9244
9438
  ] }),
9245
- /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("span", { className: "fd-stack", style: { gap: 1 }, children: [
9246
- /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fd-label-lg", children: g.label }),
9247
- /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("span", { className: "fd-body-sm fd-muted", style: { fontSize: 11.5 }, children: [
9439
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("span", { className: "fd-stack", style: { gap: 1 }, children: [
9440
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { className: "fd-label-lg", children: g.label }),
9441
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("span", { className: "fd-body-sm fd-muted", style: { fontSize: 11.5 }, children: [
9248
9442
  "CRP ",
9249
9443
  g.range
9250
9444
  ] })
@@ -9254,10 +9448,10 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
9254
9448
  g.key
9255
9449
  );
9256
9450
  }) }),
9257
- floorBand ? /* @__PURE__ */ (0, import_jsx_runtime73.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: [
9258
- /* @__PURE__ */ (0, import_jsx_runtime73.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_runtime73.jsx)("span", { className: "fd-meter-seg" + (i <= floor.n ? " is-on" : ""), style: { width: 5, height: 12 } }, i)) }),
9259
- /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("span", { className: "fd-body-sm fd-secondary", style: { flex: 1, minWidth: 240 }, children: [
9260
- /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("strong", { style: { color: "var(--text)" }, children: [
9451
+ floorBand ? /* @__PURE__ */ (0, import_jsx_runtime74.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: [
9452
+ /* @__PURE__ */ (0, import_jsx_runtime74.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_runtime74.jsx)("span", { className: "fd-meter-seg" + (i <= floor.n ? " is-on" : ""), style: { width: 5, height: 12 } }, i)) }),
9453
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("span", { className: "fd-body-sm fd-secondary", style: { flex: 1, minWidth: 240 }, children: [
9454
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("strong", { style: { color: "var(--text)" }, children: [
9261
9455
  "Plan floor ",
9262
9456
  floorScore
9263
9457
  ] }),
@@ -9268,8 +9462,8 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
9268
9462
  }
9269
9463
 
9270
9464
  // src/components/planner/MixGap.tsx
9271
- var React47 = __toESM(require("react"), 1);
9272
- var import_jsx_runtime74 = require("react/jsx-runtime");
9465
+ var React48 = __toESM(require("react"), 1);
9466
+ var import_jsx_runtime75 = require("react/jsx-runtime");
9273
9467
  var MIX_GAP_LAYOUT = {
9274
9468
  trackHeight: 30,
9275
9469
  barHeight: 20,
@@ -9283,19 +9477,19 @@ function mixGapOffset(value, max) {
9283
9477
  }
9284
9478
  function MixGap({ rows = [], loading = false, className = "" }) {
9285
9479
  const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
9286
- const [hover, setHover] = React47.useState(null);
9480
+ const [hover, setHover] = React48.useState(null);
9287
9481
  const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
9288
9482
  const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
9289
9483
  const { trackHeight, barHeight, targetWidth, labelGap } = MIX_GAP_LAYOUT;
9290
9484
  const barTop = (trackHeight - barHeight) / 2;
9291
- return /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 4 }, children: [
9292
- /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("div", { className: "fd-row", style: { gap: 16, justifyContent: "flex-end", paddingBottom: 6, flexWrap: "wrap" }, children: [
9293
- [["On target", TONE.ok], ["Close", TONE.warn], ["Short", TONE.danger]].map(([l, c]) => /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
9294
- /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { style: { width: 14, height: 9, borderRadius: 2, background: c } }),
9485
+ return /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 4 }, children: [
9486
+ /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("div", { className: "fd-row", style: { gap: 16, justifyContent: "flex-end", paddingBottom: 6, flexWrap: "wrap" }, children: [
9487
+ [["On target", TONE.ok], ["Close", TONE.warn], ["Short", TONE.danger]].map(([l, c]) => /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
9488
+ /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { style: { width: 14, height: 9, borderRadius: 2, background: c } }),
9295
9489
  l
9296
9490
  ] }, l)),
9297
- /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
9298
- /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { "data-mixgap-legend-target": "", style: { width: targetWidth, height: 16, borderRadius: 1, background: MIX_GAP_TARGET_STRIPE } }),
9491
+ /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
9492
+ /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { "data-mixgap-legend-target": "", style: { width: targetWidth, height: 16, borderRadius: 1, background: MIX_GAP_TARGET_STRIPE } }),
9299
9493
  "Target"
9300
9494
  ] })
9301
9495
  ] }),
@@ -9304,7 +9498,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
9304
9498
  const tone = toneOf(gap);
9305
9499
  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 : "");
9306
9500
  const labelLeft = r.realized > r.target ? `calc(${mixGapOffset(r.realized, max)} + ${labelGap}px)` : `calc(${mixGapOffset(r.target, max)} + ${targetWidth / 2 + labelGap}px)`;
9307
- return /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)(
9501
+ return /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)(
9308
9502
  "div",
9309
9503
  {
9310
9504
  className: "fd-row",
@@ -9312,15 +9506,15 @@ function MixGap({ rows = [], loading = false, className = "" }) {
9312
9506
  onMouseEnter: () => setHover(r.channel),
9313
9507
  onMouseLeave: () => setHover(null),
9314
9508
  children: [
9315
- /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { style: { width: 128, flex: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(ChannelTag, { channel: r.channel, size: "sm" }) }),
9316
- /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { style: { position: "relative", flex: 1, height: trackHeight, minWidth: 120 }, children: loading ? /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { className: "fd-skel", style: { position: "absolute", left: 0, right: 0, top: barTop, height: barHeight, borderRadius: 3 } }) : /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)(import_jsx_runtime74.Fragment, { children: [
9317
- /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { "data-mixgap-bar": "", style: { position: "absolute", left: 0, top: barTop, height: barHeight, width: mixGapOffset(r.realized, max), background: TONE[tone], borderRadius: "2px 3px 3px 2px", transition: "width var(--dur-slow) var(--ease), background var(--dur-base) var(--ease)" } }),
9318
- /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { "data-mixgap-target": "", style: { position: "absolute", left: `calc(${mixGapOffset(r.target, max)} - ${targetWidth / 2}px)`, top: 0, width: targetWidth, height: trackHeight, background: MIX_GAP_TARGET_STRIPE, borderRadius: 1 } }),
9319
- /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("span", { "data-mixgap-label": "", className: "fd-num", style: { position: "absolute", left: labelLeft, top: "50%", transform: "translateY(-50%)", fontSize: 12, color: "var(--text-muted)", whiteSpace: "nowrap" }, children: [
9509
+ /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { style: { width: 128, flex: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(ChannelTag, { channel: r.channel, size: "sm" }) }),
9510
+ /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { style: { position: "relative", flex: 1, height: trackHeight, minWidth: 120 }, children: loading ? /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { className: "fd-skel", style: { position: "absolute", left: 0, right: 0, top: barTop, height: barHeight, borderRadius: 3 } }) : /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)(import_jsx_runtime75.Fragment, { children: [
9511
+ /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { "data-mixgap-bar": "", style: { position: "absolute", left: 0, top: barTop, height: barHeight, width: mixGapOffset(r.realized, max), background: TONE[tone], borderRadius: "2px 3px 3px 2px", transition: "width var(--dur-slow) var(--ease), background var(--dur-base) var(--ease)" } }),
9512
+ /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { "data-mixgap-target": "", style: { position: "absolute", left: `calc(${mixGapOffset(r.target, max)} - ${targetWidth / 2}px)`, top: 0, width: targetWidth, height: trackHeight, background: MIX_GAP_TARGET_STRIPE, borderRadius: 1 } }),
9513
+ /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("span", { "data-mixgap-label": "", className: "fd-num", style: { position: "absolute", left: labelLeft, top: "50%", transform: "translateY(-50%)", fontSize: 12, color: "var(--text-muted)", whiteSpace: "nowrap" }, children: [
9320
9514
  r.realized,
9321
9515
  "%"
9322
9516
  ] }),
9323
- hover === r.channel ? /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { className: "fd-tooltip", role: "tooltip", style: { position: "absolute", left: 0, right: "auto", bottom: trackHeight + 4, maxWidth: "min(340px, 100%)", whiteSpace: "normal", textAlign: "left", width: "max-content" }, children: tip }) : null
9517
+ hover === r.channel ? /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { className: "fd-tooltip", role: "tooltip", style: { position: "absolute", left: 0, right: "auto", bottom: trackHeight + 4, maxWidth: "min(340px, 100%)", whiteSpace: "normal", textAlign: "left", width: "max-content" }, children: tip }) : null
9324
9518
  ] }) })
9325
9519
  ]
9326
9520
  },
@@ -9331,7 +9525,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
9331
9525
  }
9332
9526
 
9333
9527
  // src/components/planner/ChannelContribution.tsx
9334
- var import_jsx_runtime75 = require("react/jsx-runtime");
9528
+ var import_jsx_runtime76 = require("react/jsx-runtime");
9335
9529
  var money = (n) => "$" + Math.round(n).toLocaleString();
9336
9530
  function ChannelContribution({
9337
9531
  channels = [],
@@ -9347,9 +9541,9 @@ function ChannelContribution({
9347
9541
  const grand = total !== void 0 ? total : base + bonus;
9348
9542
  const pct = (v) => grand ? v / grand * 100 : 0;
9349
9543
  const spendTotal = channels.reduce((s, c) => s + Number(String(c.spend || 0).replace(/[^0-9.]/g, "")), 0);
9350
- return /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
9351
- loading ? /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { className: "fd-skel", style: { height: 34, borderRadius: "var(--r-sm)" } }) : /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("div", { className: "fd-row", style: { height: 34, borderRadius: "var(--r-sm)", overflow: "hidden", gap: 2, background: "var(--surface-3)" }, children: [
9352
- channels.map((c) => /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(
9544
+ return /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
9545
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { className: "fd-skel", style: { height: 34, borderRadius: "var(--r-sm)" } }) : /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "fd-row", style: { height: 34, borderRadius: "var(--r-sm)", overflow: "hidden", gap: 2, background: "var(--surface-3)" }, children: [
9546
+ channels.map((c) => /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
9353
9547
  "span",
9354
9548
  {
9355
9549
  title: c.name + " \xB7 " + c.crp.toFixed(1) + " CRP",
@@ -9358,7 +9552,7 @@ function ChannelContribution({
9358
9552
  },
9359
9553
  c.name
9360
9554
  )),
9361
- bonus > 0 ? /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(
9555
+ bonus > 0 ? /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
9362
9556
  "span",
9363
9557
  {
9364
9558
  title: "Surround-sound bonus +" + bonusPct + "%",
@@ -9367,18 +9561,18 @@ function ChannelContribution({
9367
9561
  }
9368
9562
  ) : null
9369
9563
  ] }),
9370
- showTable ? /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("table", { className: "fd-table", style: { fontSize: "var(--body-sm-size)" }, children: [
9371
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("tr", { children: [
9372
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("th", { style: { width: "34%" }, children: "Channel" }),
9373
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("th", { style: { width: "16%" }, children: "Weight" }),
9374
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("th", { className: "is-num", style: { width: "16%" }, children: "Spend" }),
9375
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("th", { className: "is-num", style: { width: "17%" }, children: "CRP" }),
9376
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("th", { className: "is-num", style: { width: "17%" }, children: "Share" })
9564
+ showTable ? /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("table", { className: "fd-table", style: { fontSize: "var(--body-sm-size)" }, children: [
9565
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("tr", { children: [
9566
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("th", { style: { width: "34%" }, children: "Channel" }),
9567
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("th", { style: { width: "16%" }, children: "Weight" }),
9568
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("th", { className: "is-num", style: { width: "16%" }, children: "Spend" }),
9569
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("th", { className: "is-num", style: { width: "17%" }, children: "CRP" }),
9570
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("th", { className: "is-num", style: { width: "17%" }, children: "Share" })
9377
9571
  ] }) }),
9378
- /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("tbody", { children: [
9379
- channels.map((c) => /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("tr", { children: [
9380
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(ChannelTag, { channel: c.name, size: "sm" }) }),
9381
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(
9572
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("tbody", { children: [
9573
+ channels.map((c) => /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("tr", { children: [
9574
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(ChannelTag, { channel: c.name, size: "sm" }) }),
9575
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
9382
9576
  "span",
9383
9577
  {
9384
9578
  className: "fd-badge fd-badge-neutral",
@@ -9387,38 +9581,38 @@ function ChannelContribution({
9387
9581
  children: "weight " + (channelWeightOf(c.name) || 0)
9388
9582
  }
9389
9583
  ) }),
9390
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("td", { className: "is-num", children: c.spend }),
9391
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("td", { className: "is-num", children: c.crp.toFixed(1) }),
9392
- /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("td", { className: "is-num", children: [
9584
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { className: "is-num", children: c.spend }),
9585
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { className: "is-num", children: c.crp.toFixed(1) }),
9586
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("td", { className: "is-num", children: [
9393
9587
  pct(c.crp).toFixed(0),
9394
9588
  "%"
9395
9589
  ] })
9396
9590
  ] }, c.name)),
9397
- bonus > 0 ? /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("tr", { children: [
9398
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("span", { className: "fd-row", style: { gap: 9, fontWeight: 600 }, children: [
9399
- /* @__PURE__ */ (0, import_jsx_runtime75.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" } }),
9591
+ bonus > 0 ? /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("tr", { children: [
9592
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("span", { className: "fd-row", style: { gap: 9, fontWeight: 600 }, children: [
9593
+ /* @__PURE__ */ (0, import_jsx_runtime76.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" } }),
9400
9594
  "Surround-sound bonus"
9401
9595
  ] }) }),
9402
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("span", { className: "fd-badge fd-badge-success", style: { height: 20, fontSize: 11 }, children: [
9596
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("span", { className: "fd-badge fd-badge-success", style: { height: 20, fontSize: 11 }, children: [
9403
9597
  "+",
9404
9598
  bonusPct,
9405
9599
  "% of +",
9406
9600
  bonusMax,
9407
9601
  "%"
9408
9602
  ] }) }),
9409
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("td", { className: "is-num fd-muted", children: "\u2014" }),
9410
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("td", { className: "is-num", children: bonus.toFixed(1) }),
9411
- /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("td", { className: "is-num", children: [
9603
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { className: "is-num fd-muted", children: "\u2014" }),
9604
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { className: "is-num", children: bonus.toFixed(1) }),
9605
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("td", { className: "is-num", children: [
9412
9606
  pct(bonus).toFixed(0),
9413
9607
  "%"
9414
9608
  ] })
9415
9609
  ] }) : null,
9416
- /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("tr", { style: { background: "var(--surface-2)" }, children: [
9417
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("td", { style: { fontWeight: 700 }, children: "Campus total" }),
9418
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("td", {}),
9419
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: money(spendTotal) }),
9420
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: grand.toFixed(1) }),
9421
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: "100%" })
9610
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("tr", { style: { background: "var(--surface-2)" }, children: [
9611
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { style: { fontWeight: 700 }, children: "Campus total" }),
9612
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", {}),
9613
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: money(spendTotal) }),
9614
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: grand.toFixed(1) }),
9615
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: "100%" })
9422
9616
  ] })
9423
9617
  ] })
9424
9618
  ] }) : null
@@ -9426,8 +9620,8 @@ function ChannelContribution({
9426
9620
  }
9427
9621
 
9428
9622
  // src/components/planner/BudgetReallocator.tsx
9429
- var React48 = __toESM(require("react"), 1);
9430
- var import_jsx_runtime76 = require("react/jsx-runtime");
9623
+ var React49 = __toESM(require("react"), 1);
9624
+ var import_jsx_runtime77 = require("react/jsx-runtime");
9431
9625
  var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
9432
9626
  function BudgetReallocator({
9433
9627
  campus,
@@ -9442,8 +9636,8 @@ function BudgetReallocator({
9442
9636
  onCancel,
9443
9637
  className = ""
9444
9638
  }) {
9445
- const [draft, setDraft] = React48.useState(spend);
9446
- React48.useEffect(() => setDraft(spend), [spend]);
9639
+ const [draft, setDraft] = React49.useState(spend);
9640
+ React49.useEffect(() => setDraft(spend), [spend]);
9447
9641
  const dirty = draft !== spend;
9448
9642
  const nextCrp = scoreFor ? scoreFor(draft) : crp;
9449
9643
  const nextBand = bandFor(nextCrp);
@@ -9458,10 +9652,10 @@ function BudgetReallocator({
9458
9652
  setDraft(spend);
9459
9653
  if (onCancel) onCancel();
9460
9654
  };
9461
- const trackRef = React48.useRef(null);
9462
- const chipRef = React48.useRef(null);
9463
- const [chipLeft, setChipLeft] = React48.useState(null);
9464
- React48.useLayoutEffect(() => {
9655
+ const trackRef = React49.useRef(null);
9656
+ const chipRef = React49.useRef(null);
9657
+ const [chipLeft, setChipLeft] = React49.useState(null);
9658
+ React49.useLayoutEffect(() => {
9465
9659
  const track = trackRef.current;
9466
9660
  if (!dirty || !track) {
9467
9661
  setChipLeft(null);
@@ -9482,23 +9676,23 @@ function BudgetReallocator({
9482
9676
  ro.observe(track);
9483
9677
  return () => ro.disconnect();
9484
9678
  }, [dirty, pct]);
9485
- return /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(
9679
+ return /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)(
9486
9680
  "div",
9487
9681
  {
9488
9682
  className: ["fd-stack", className].filter(Boolean).join(" "),
9489
9683
  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)" },
9490
9684
  children: [
9491
- /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
9492
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { className: "fd-h4", style: { flex: 1, minWidth: 140 }, children: campus }),
9493
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(CsiBadge, { band: nowBand, crp, size: "medium" }),
9494
- dirty ? /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(import_jsx_runtime76.Fragment, { children: [
9495
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("i", { className: "ph ph-arrow-right fd-muted", "aria-hidden": "true" }),
9496
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(CsiBadge, { band: nextBand, crp: nextCrp, size: "medium", preview: true })
9685
+ /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
9686
+ /* @__PURE__ */ (0, import_jsx_runtime77.jsx)("span", { className: "fd-h4", style: { flex: 1, minWidth: 140 }, children: campus }),
9687
+ /* @__PURE__ */ (0, import_jsx_runtime77.jsx)(CsiBadge, { band: nowBand, crp, size: "medium" }),
9688
+ dirty ? /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)(import_jsx_runtime77.Fragment, { children: [
9689
+ /* @__PURE__ */ (0, import_jsx_runtime77.jsx)("i", { className: "ph ph-arrow-right fd-muted", "aria-hidden": "true" }),
9690
+ /* @__PURE__ */ (0, import_jsx_runtime77.jsx)(CsiBadge, { band: nextBand, crp: nextCrp, size: "medium", preview: true })
9497
9691
  ] }) : null
9498
9692
  ] }),
9499
- /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "fd-slider", ref: trackRef, children: [
9500
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
9501
- dirty ? /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
9693
+ /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)("div", { className: "fd-slider", ref: trackRef, children: [
9694
+ /* @__PURE__ */ (0, import_jsx_runtime77.jsx)("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
9695
+ dirty ? /* @__PURE__ */ (0, import_jsx_runtime77.jsx)(
9502
9696
  "span",
9503
9697
  {
9504
9698
  ref: chipRef,
@@ -9510,7 +9704,7 @@ function BudgetReallocator({
9510
9704
  children: (delta < 0 ? "\u2212$" : "+$") + Math.abs(delta).toLocaleString()
9511
9705
  }
9512
9706
  ) : null,
9513
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
9707
+ /* @__PURE__ */ (0, import_jsx_runtime77.jsx)(
9514
9708
  "input",
9515
9709
  {
9516
9710
  type: "range",
@@ -9526,13 +9720,13 @@ function BudgetReallocator({
9526
9720
  }
9527
9721
  )
9528
9722
  ] }),
9529
- /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
9530
- /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("span", { className: "fd-stack", style: { gap: 2, flex: 1, minWidth: 150 }, children: [
9531
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { className: "fd-num", style: { fontSize: 19, fontWeight: 700 }, children: "$" + draft.toLocaleString() }),
9532
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { className: "fd-body-sm fd-muted", children: "Arrow keys step $100, shift+arrow $1,000. Escape reverts." })
9723
+ /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
9724
+ /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)("span", { className: "fd-stack", style: { gap: 2, flex: 1, minWidth: 150 }, children: [
9725
+ /* @__PURE__ */ (0, import_jsx_runtime77.jsx)("span", { className: "fd-num", style: { fontSize: 19, fontWeight: 700 }, children: "$" + draft.toLocaleString() }),
9726
+ /* @__PURE__ */ (0, import_jsx_runtime77.jsx)("span", { className: "fd-body-sm fd-muted", children: "Arrow keys step $100, shift+arrow $1,000. Escape reverts." })
9533
9727
  ] }),
9534
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("button", { type: "button", className: "fd-btn fd-btn-ghost", disabled: !dirty, onClick: revert, children: "Cancel" }),
9535
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
9728
+ /* @__PURE__ */ (0, import_jsx_runtime77.jsx)("button", { type: "button", className: "fd-btn fd-btn-ghost", disabled: !dirty, onClick: revert, children: "Cancel" }),
9729
+ /* @__PURE__ */ (0, import_jsx_runtime77.jsx)(
9536
9730
  "button",
9537
9731
  {
9538
9732
  type: "button",
@@ -9551,7 +9745,7 @@ function BudgetReallocator({
9551
9745
  }
9552
9746
 
9553
9747
  // src/components/planner/SurroundSound.tsx
9554
- var import_jsx_runtime77 = require("react/jsx-runtime");
9748
+ var import_jsx_runtime78 = require("react/jsx-runtime");
9555
9749
  var CATEGORIES = [
9556
9750
  { key: "ooh", label: "OOH", icon: "flag-banner", color: "var(--ch-ooh)" },
9557
9751
  { key: "transit", label: "Transit", icon: "bus", color: "var(--ch-transit)" },
@@ -9563,26 +9757,26 @@ var CATEGORIES = [
9563
9757
  function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost, className = "" }) {
9564
9758
  const earned = Math.max(0, Math.min(1, bonusPct / bonusMax));
9565
9759
  const single = present.length <= 2;
9566
- return /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, children: [
9567
- /* @__PURE__ */ (0, import_jsx_runtime77.jsx)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: CATEGORIES.map((c) => {
9760
+ return /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, children: [
9761
+ /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: CATEGORIES.map((c) => {
9568
9762
  const on = present.includes(c.key);
9569
- return /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)(
9763
+ return /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)(
9570
9764
  "span",
9571
9765
  {
9572
9766
  title: c.label + (on ? " \u2014 present" : " \u2014 not bought"),
9573
9767
  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)" },
9574
9768
  children: [
9575
- /* @__PURE__ */ (0, import_jsx_runtime77.jsx)("i", { className: "ph ph-" + c.icon, style: { fontSize: 19, color: on ? c.color : "var(--text-muted)" }, "aria-hidden": "true" }),
9576
- /* @__PURE__ */ (0, import_jsx_runtime77.jsx)("span", { style: { fontSize: 10.5, fontWeight: 700 }, children: c.label })
9769
+ /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("i", { className: "ph ph-" + c.icon, style: { fontSize: 19, color: on ? c.color : "var(--text-muted)" }, "aria-hidden": "true" }),
9770
+ /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("span", { style: { fontSize: 10.5, fontWeight: 700 }, children: c.label })
9577
9771
  ]
9578
9772
  },
9579
9773
  c.key
9580
9774
  );
9581
9775
  }) }),
9582
- /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)("div", { className: "fd-stack", style: { gap: 8 }, children: [
9583
- /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
9584
- /* @__PURE__ */ (0, import_jsx_runtime77.jsx)("span", { className: "fd-label-lg", children: "Surround-sound bonus earned" }),
9585
- /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)("span", { className: "fd-num", style: { color: single ? "var(--warn-text)" : "var(--csi-3-mark)", fontWeight: 700 }, children: [
9776
+ /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("div", { className: "fd-stack", style: { gap: 8 }, children: [
9777
+ /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
9778
+ /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("span", { className: "fd-label-lg", children: "Surround-sound bonus earned" }),
9779
+ /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("span", { className: "fd-num", style: { color: single ? "var(--warn-text)" : "var(--csi-3-mark)", fontWeight: 700 }, children: [
9586
9780
  "+",
9587
9781
  bonusPct,
9588
9782
  "% of +",
@@ -9590,8 +9784,8 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
9590
9784
  "%"
9591
9785
  ] })
9592
9786
  ] }),
9593
- /* @__PURE__ */ (0, import_jsx_runtime77.jsx)("div", { style: { height: 8, borderRadius: "var(--r-xs)", background: "var(--surface-3)", overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime77.jsx)("div", { style: { height: "100%", width: earned * 100 + "%", background: "var(--csi-3-mark)", borderRadius: "inherit", transition: "width var(--dur-slow) var(--ease)" } }) }),
9594
- /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: [
9787
+ /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("div", { style: { height: 8, borderRadius: "var(--r-xs)", background: "var(--surface-3)", overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("div", { style: { height: "100%", width: earned * 100 + "%", background: "var(--csi-3-mark)", borderRadius: "inherit", transition: "width var(--dur-slow) var(--ease)" } }) }),
9788
+ /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: [
9595
9789
  present.length,
9596
9790
  " of 6 channel categories present.",
9597
9791
  " ",
@@ -9603,7 +9797,7 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
9603
9797
  }
9604
9798
 
9605
9799
  // src/components/planner/Importance.tsx
9606
- var import_jsx_runtime78 = require("react/jsx-runtime");
9800
+ var import_jsx_runtime79 = require("react/jsx-runtime");
9607
9801
  var IMPORTANCE_LEVELS = [
9608
9802
  { id: "nudge", rank: 1, label: "Nudge", icon: "feather", description: "Breaks a tie, nothing more." },
9609
9803
  { id: "lean", rank: 2, label: "Lean", icon: "arrow-bend-up-right", description: "A mild preference between otherwise equal options." },
@@ -9633,23 +9827,23 @@ function importanceTokens(id) {
9633
9827
  function ImportanceTag({ level, showLabel = true, size = "sm", className = "" }) {
9634
9828
  const lvl = importanceLevel(level);
9635
9829
  const t = importanceTokens(level);
9636
- return /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)(
9830
+ return /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)(
9637
9831
  "span",
9638
9832
  {
9639
9833
  className: ["fd-imp-tag", size === "md" ? "is-md" : "", className].filter(Boolean).join(" "),
9640
9834
  style: { background: t.fill, borderColor: t.edge, color: t.text },
9641
9835
  title: lvl.label + " \u2014 " + lvl.description,
9642
9836
  children: [
9643
- /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("i", { className: "ph ph-" + lvl.icon, "aria-hidden": "true" }),
9644
- showLabel ? lvl.label : /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("span", { className: "fd-sr", children: lvl.label })
9837
+ /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("i", { className: "ph ph-" + lvl.icon, "aria-hidden": "true" }),
9838
+ showLabel ? lvl.label : /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-sr", children: lvl.label })
9645
9839
  ]
9646
9840
  }
9647
9841
  );
9648
9842
  }
9649
9843
 
9650
9844
  // src/components/planner/PreferenceMeter.tsx
9651
- var React49 = __toESM(require("react"), 1);
9652
- var import_jsx_runtime79 = require("react/jsx-runtime");
9845
+ var React50 = __toESM(require("react"), 1);
9846
+ var import_jsx_runtime80 = require("react/jsx-runtime");
9653
9847
  function preferenceScore(criteria) {
9654
9848
  const earned = criteria.reduce((n, c) => n + (Number(c.earned) || 0), 0);
9655
9849
  const weight = criteria.reduce((n, c) => n + (Number(c.weight) || 0), 0);
@@ -9678,8 +9872,8 @@ function PreferenceMeter({
9678
9872
  className = ""
9679
9873
  }) {
9680
9874
  const value = score == null ? preferenceScore(criteria) : score;
9681
- const segments = React49.useMemo(() => preferenceSegments(criteria), [criteria]);
9682
- return /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
9875
+ const segments = React50.useMemo(() => preferenceSegments(criteria), [criteria]);
9876
+ return /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
9683
9877
  ScoreMeter,
9684
9878
  {
9685
9879
  score: value,
@@ -9691,22 +9885,22 @@ function PreferenceMeter({
9691
9885
  placement,
9692
9886
  className,
9693
9887
  breakdownLabel: breakdownTitle,
9694
- breakdown: /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-prefbreak", children: [
9695
- /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-prefbreak-head", children: [
9696
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-label-lg", children: breakdownTitle }),
9697
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-prefbreak-score fd-tabular", children: Math.round(value) })
9888
+ breakdown: /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-prefbreak", children: [
9889
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-prefbreak-head", children: [
9890
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-label-lg", children: breakdownTitle }),
9891
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-prefbreak-score fd-tabular", children: Math.round(value) })
9698
9892
  ] }),
9699
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("ul", { className: "fd-prefbreak-list", children: criteria.map((c) => {
9893
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("ul", { className: "fd-prefbreak-list", children: criteria.map((c) => {
9700
9894
  const pct = c.weight > 0 ? Math.round((Number(c.earned) || 0) / c.weight * 100) : 0;
9701
- return /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("li", { className: pct === 0 ? "fd-prefbreak-item is-unmet" : "fd-prefbreak-item", children: [
9702
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(ImportanceTag, { level: c.importance }),
9703
- /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("span", { className: "fd-prefbreak-text", children: [
9704
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-prefbreak-label", children: c.label }),
9705
- c.note ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-prefbreak-note", children: c.note }) : null
9895
+ return /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("li", { className: pct === 0 ? "fd-prefbreak-item is-unmet" : "fd-prefbreak-item", children: [
9896
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(ImportanceTag, { level: c.importance }),
9897
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fd-prefbreak-text", children: [
9898
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-prefbreak-label", children: c.label }),
9899
+ c.note ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-prefbreak-note", children: c.note }) : null
9706
9900
  ] }),
9707
- /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("span", { className: "fd-prefbreak-val fd-tabular", children: [
9901
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fd-prefbreak-val fd-tabular", children: [
9708
9902
  Math.round(Number(c.earned) || 0),
9709
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-prefbreak-sep", children: "/" }),
9903
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-prefbreak-sep", children: "/" }),
9710
9904
  Math.round(c.weight)
9711
9905
  ] })
9712
9906
  ] }, c.id);
@@ -9717,10 +9911,10 @@ function PreferenceMeter({
9717
9911
  }
9718
9912
 
9719
9913
  // src/components/chat/AgentChatPanel.tsx
9720
- var React55 = __toESM(require("react"), 1);
9914
+ var React56 = __toESM(require("react"), 1);
9721
9915
 
9722
9916
  // src/components/chat/chatEngine.ts
9723
- var React50 = __toESM(require("react"), 1);
9917
+ var React51 = __toESM(require("react"), 1);
9724
9918
  var CHAT_UNAVAILABLE = "chat_unavailable";
9725
9919
  var JOB_PENDING = ["queued", "running"];
9726
9920
  var JOB_SUCCESS = ["completed", "recovered"];
@@ -9774,22 +9968,22 @@ function useChatEngine(opts) {
9774
9968
  onClear,
9775
9969
  onFeedback
9776
9970
  } = opts || {};
9777
- const [status, setStatus] = React50.useState("idle");
9778
- const [threadId, setThreadId] = React50.useState(null);
9779
- const [messages, setMessages] = React50.useState([]);
9780
- const [queue, setQueue] = React50.useState([]);
9781
- const [fatal, setFatal] = React50.useState(null);
9782
- const [busy, setBusy] = React50.useState(false);
9783
- const [turnStartedAt, setTurnStartedAt] = React50.useState(null);
9784
- const listRef = React50.useRef([]);
9785
- const queueRef = React50.useRef([]);
9786
- const busyRef = React50.useRef(false);
9787
- const stoppedRef = React50.useRef(false);
9788
- const abortRef = React50.useRef(null);
9789
- const serverCount = React50.useRef(0);
9790
- const threadRef = React50.useRef(null);
9791
- const mounted = React50.useRef(true);
9792
- React50.useEffect(() => {
9971
+ const [status, setStatus] = React51.useState("idle");
9972
+ const [threadId, setThreadId] = React51.useState(null);
9973
+ const [messages, setMessages] = React51.useState([]);
9974
+ const [queue, setQueue] = React51.useState([]);
9975
+ const [fatal, setFatal] = React51.useState(null);
9976
+ const [busy, setBusy] = React51.useState(false);
9977
+ const [turnStartedAt, setTurnStartedAt] = React51.useState(null);
9978
+ const listRef = React51.useRef([]);
9979
+ const queueRef = React51.useRef([]);
9980
+ const busyRef = React51.useRef(false);
9981
+ const stoppedRef = React51.useRef(false);
9982
+ const abortRef = React51.useRef(null);
9983
+ const serverCount = React51.useRef(0);
9984
+ const threadRef = React51.useRef(null);
9985
+ const mounted = React51.useRef(true);
9986
+ React51.useEffect(() => {
9793
9987
  mounted.current = true;
9794
9988
  return () => {
9795
9989
  mounted.current = false;
@@ -9811,14 +10005,14 @@ function useChatEngine(opts) {
9811
10005
  }
9812
10006
  return false;
9813
10007
  };
9814
- const loadThread = React50.useCallback(async (id) => {
10008
+ const loadThread = React51.useCallback(async (id) => {
9815
10009
  const data = await apiAdapter.getThread(id);
9816
10010
  const list = [...data && data.messages || []];
9817
10011
  serverCount.current = list.length;
9818
10012
  commit(list);
9819
10013
  return list;
9820
10014
  }, [apiAdapter]);
9821
- React50.useEffect(() => {
10015
+ React51.useEffect(() => {
9822
10016
  if (!apiAdapter) {
9823
10017
  setStatus("idle");
9824
10018
  setFatal(null);
@@ -10031,7 +10225,7 @@ function useChatEngine(opts) {
10031
10225
  await dispatchTurn(turn);
10032
10226
  }
10033
10227
  }
10034
- const send = React50.useCallback((text, attachments) => {
10228
+ const send = React51.useCallback((text, attachments) => {
10035
10229
  const body = (text || "").trim();
10036
10230
  if (!body && !(attachments && attachments.length)) return;
10037
10231
  if (status === "disconnected") return;
@@ -10041,7 +10235,7 @@ function useChatEngine(opts) {
10041
10235
  stoppedRef.current = false;
10042
10236
  drain();
10043
10237
  }, [status]);
10044
- const stop = React50.useCallback(() => {
10238
+ const stop = React51.useCallback(() => {
10045
10239
  stoppedRef.current = true;
10046
10240
  const ac = abortRef.current;
10047
10241
  if (ac) {
@@ -10060,11 +10254,11 @@ function useChatEngine(opts) {
10060
10254
  store.del(STORAGE_PREFIX + threadRef.current);
10061
10255
  }
10062
10256
  }, [apiAdapter]);
10063
- const removeQueued = React50.useCallback((id) => {
10257
+ const removeQueued = React51.useCallback((id) => {
10064
10258
  queueRef.current = queueRef.current.filter((t) => t.id !== id);
10065
10259
  setQueue(queueRef.current.slice());
10066
10260
  }, []);
10067
- const retry = React50.useCallback(() => {
10261
+ const retry = React51.useCallback(() => {
10068
10262
  const list = listRef.current;
10069
10263
  let at = -1;
10070
10264
  for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
@@ -10080,19 +10274,19 @@ function useChatEngine(opts) {
10080
10274
  setQueue(queueRef.current.slice());
10081
10275
  drain();
10082
10276
  }, []);
10083
- const clear = React50.useCallback(() => {
10277
+ const clear = React51.useCallback(() => {
10084
10278
  commit([]);
10085
10279
  serverCount.current = 0;
10086
10280
  queueRef.current = [];
10087
10281
  setQueue([]);
10088
10282
  onClear && onClear();
10089
10283
  }, [onClear]);
10090
- const setFeedback = React50.useCallback((id, value) => {
10284
+ const setFeedback = React51.useCallback((id, value) => {
10091
10285
  patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
10092
10286
  const msg = listRef.current.find((m) => m.id === id);
10093
10287
  onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
10094
10288
  }, [onFeedback]);
10095
- const reload = React50.useCallback(async () => {
10289
+ const reload = React51.useCallback(async () => {
10096
10290
  if (!threadRef.current) return;
10097
10291
  setStatus("loading");
10098
10292
  try {
@@ -10130,11 +10324,11 @@ var ChatKit = {
10130
10324
  };
10131
10325
 
10132
10326
  // src/components/chat/ChatTranscript.tsx
10133
- var React52 = __toESM(require("react"), 1);
10327
+ var React53 = __toESM(require("react"), 1);
10134
10328
 
10135
10329
  // src/components/chat/ChatTurn.tsx
10136
- var React51 = __toESM(require("react"), 1);
10137
- var import_jsx_runtime80 = require("react/jsx-runtime");
10330
+ var React52 = __toESM(require("react"), 1);
10331
+ var import_jsx_runtime81 = require("react/jsx-runtime");
10138
10332
  function JsonView({ value }) {
10139
10333
  let text;
10140
10334
  try {
@@ -10142,67 +10336,67 @@ function JsonView({ value }) {
10142
10336
  } catch (e) {
10143
10337
  text = String(value);
10144
10338
  }
10145
- return /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(CodeBlock, { code: text, language: "json", collapseAfter: 18 });
10339
+ return /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(CodeBlock, { code: text, language: "json", collapseAfter: 18 });
10146
10340
  }
10147
10341
  function PacketCard({ packet, schema, render, onApply, applied }) {
10148
10342
  if (!packet) return null;
10149
10343
  const s = schema || {};
10150
10344
  const invalid = packet.valid === false;
10151
10345
  const title = s.heading || packet.type;
10152
- return /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("section", { className: "fdc-packet" + (invalid ? " is-invalid" : ""), "aria-label": title, children: [
10153
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("header", { className: "fdc-packet-head", children: [
10154
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("i", { className: "ph ph-" + (s.icon || "package"), "aria-hidden": "true" }),
10155
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fdc-packet-title", title: truncationTitle(title), children: title }),
10156
- packet.repaired ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fdc-packet-badge", children: "Repaired" }) : null,
10157
- invalid ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fdc-packet-badge is-danger", children: "Invalid" }) : null
10346
+ return /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("section", { className: "fdc-packet" + (invalid ? " is-invalid" : ""), "aria-label": title, children: [
10347
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("header", { className: "fdc-packet-head", children: [
10348
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-" + (s.icon || "package"), "aria-hidden": "true" }),
10349
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-packet-title", title: truncationTitle(title), children: title }),
10350
+ packet.repaired ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-packet-badge", children: "Repaired" }) : null,
10351
+ invalid ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-packet-badge is-danger", children: "Invalid" }) : null
10158
10352
  ] }),
10159
- invalid ? /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fdc-packet-alert", role: "alert", children: [
10160
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
10161
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { children: packet.error || "This result failed validation and can\u2019t be applied." })
10162
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("div", { className: "fdc-packet-body", children: render ? render(packet) : /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(JsonView, { value: packet.payload }) }),
10163
- !invalid && onApply ? /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("footer", { className: "fdc-packet-foot", children: [
10164
- packet.repaired ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fdc-packet-note", children: "Corrected by the backend after a first attempt." }) : /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", {}),
10165
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", disabled: applied, onClick: () => onApply(packet), children: [
10166
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("i", { className: "ph ph-" + (applied ? "check" : "arrow-square-in"), "aria-hidden": "true" }),
10353
+ invalid ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-packet-alert", role: "alert", children: [
10354
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
10355
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { children: packet.error || "This result failed validation and can\u2019t be applied." })
10356
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("div", { className: "fdc-packet-body", children: render ? render(packet) : /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(JsonView, { value: packet.payload }) }),
10357
+ !invalid && onApply ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("footer", { className: "fdc-packet-foot", children: [
10358
+ packet.repaired ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-packet-note", children: "Corrected by the backend after a first attempt." }) : /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", {}),
10359
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", disabled: applied, onClick: () => onApply(packet), children: [
10360
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-" + (applied ? "check" : "arrow-square-in"), "aria-hidden": "true" }),
10167
10361
  applied ? "Applied" : s.applyLabel || "Apply"
10168
10362
  ] })
10169
10363
  ] }) : null
10170
10364
  ] });
10171
10365
  }
10172
10366
  function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
10173
- const [open, setOpen] = React51.useState(defaultOpen);
10367
+ const [open, setOpen] = React52.useState(defaultOpen);
10174
10368
  if (!text) return null;
10175
- return /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fdc-think" + (open ? " is-open" : ""), children: [
10176
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
10177
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("i", { className: "ph ph-brain", "aria-hidden": "true" }),
10178
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { children: streaming ? "Thinking" : durationMs ? "Thought for " + formatDuration(durationMs) : "Thought process" }),
10179
- streaming ? /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fdc-dots", "aria-hidden": "true", children: [
10180
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", {}),
10181
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", {}),
10182
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", {})
10369
+ return /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-think" + (open ? " is-open" : ""), children: [
10370
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
10371
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-brain", "aria-hidden": "true" }),
10372
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { children: streaming ? "Thinking" : durationMs ? "Thought for " + formatDuration(durationMs) : "Thought process" }),
10373
+ streaming ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("span", { className: "fdc-dots", "aria-hidden": "true", children: [
10374
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", {}),
10375
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", {}),
10376
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", {})
10183
10377
  ] }) : null,
10184
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" })
10378
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" })
10185
10379
  ] }),
10186
- open ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("div", { className: "fdc-think-body", children: text }) : null
10380
+ open ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("div", { className: "fdc-think-body", children: text }) : null
10187
10381
  ] });
10188
10382
  }
10189
10383
  function Citations({ items = [], onOpen }) {
10190
- const [open, setOpen] = React51.useState(false);
10384
+ const [open, setOpen] = React52.useState(false);
10191
10385
  if (!items.length) return null;
10192
- return /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fdc-cites", children: [
10193
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
10194
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("i", { className: "ph ph-quotes", "aria-hidden": "true" }),
10195
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { children: [
10386
+ return /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-cites", children: [
10387
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
10388
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-quotes", "aria-hidden": "true" }),
10389
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("span", { children: [
10196
10390
  items.length,
10197
10391
  " source",
10198
10392
  items.length === 1 ? "" : "s"
10199
10393
  ] }),
10200
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" })
10394
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" })
10201
10395
  ] }),
10202
- open ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("ol", { className: "fdc-cites-list", children: items.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("li", { children: [
10203
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fdc-cite-n fd-tabular", children: c.marker || i + 1 }),
10204
- c.url ? /* @__PURE__ */ (0, import_jsx_runtime80.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_runtime80.jsx)("span", { children: c.title || "Source" }),
10205
- c.detail ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fdc-cite-detail", children: c.detail }) : null
10396
+ open ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("ol", { className: "fdc-cites-list", children: items.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("li", { children: [
10397
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-cite-n fd-tabular", children: c.marker || i + 1 }),
10398
+ c.url ? /* @__PURE__ */ (0, import_jsx_runtime81.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_runtime81.jsx)("span", { children: c.title || "Source" }),
10399
+ c.detail ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-cite-detail", children: c.detail }) : null
10206
10400
  ] }, c.id || i)) }) : null
10207
10401
  ] });
10208
10402
  }
@@ -10213,29 +10407,29 @@ function clampText(text, max) {
10213
10407
  return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
10214
10408
  }
10215
10409
  function MessageBody({ message: m, ctx }) {
10216
- const [expanded, setExpanded] = React51.useState(false);
10410
+ const [expanded, setExpanded] = React52.useState(false);
10217
10411
  const isUser = m.role === "user";
10218
10412
  const raw = m.text || "";
10219
10413
  const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
10220
10414
  const body = clamped != null ? clamped : raw;
10221
10415
  const showMd = ctx.markdown && !isUser;
10222
- return /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fdc-body", children: [
10223
- m.thinking && ctx.showThinking ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(ThinkingBlock, { text: m.thinking, durationMs: m.thinkingMs, streaming: m.streaming && !m.text }) : null,
10224
- m.steps && m.steps.length && ctx.showSteps ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(StepList, { steps: m.steps, defaultOpen: m.steps.some((s) => s.status === "running"), dense: true }) : null,
10225
- body ? /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fdc-text" + (isUser ? " is-user" : ""), children: [
10226
- showMd ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Markdown, { source: body, headingOffset: 2, codeProps: { collapseAfter: 22 }, renderCitation: ctx.renderCitation }) : /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("div", { className: "fdc-plain", children: body }),
10227
- m.streaming ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fdc-caret", "aria-hidden": "true" }) : null
10416
+ return /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-body", children: [
10417
+ m.thinking && ctx.showThinking ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(ThinkingBlock, { text: m.thinking, durationMs: m.thinkingMs, streaming: m.streaming && !m.text }) : null,
10418
+ m.steps && m.steps.length && ctx.showSteps ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(StepList, { steps: m.steps, defaultOpen: m.steps.some((s) => s.status === "running"), dense: true }) : null,
10419
+ body ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-text" + (isUser ? " is-user" : ""), children: [
10420
+ showMd ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Markdown, { source: body, headingOffset: 2, codeProps: { collapseAfter: 22 }, renderCitation: ctx.renderCitation }) : /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("div", { className: "fdc-plain", children: body }),
10421
+ m.streaming ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-caret", "aria-hidden": "true" }) : null
10228
10422
  ] }) : null,
10229
- clamped != null ? /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(true), children: [
10230
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("i", { className: "ph ph-caret-down", "aria-hidden": "true" }),
10423
+ clamped != null ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(true), children: [
10424
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-caret-down", "aria-hidden": "true" }),
10231
10425
  "Show more",
10232
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fdc-more-len fd-tabular", children: raw.length < 2e3 ? raw.length.toLocaleString() + " characters" : Math.round(raw.length / 100) / 10 + "k characters" })
10233
- ] }) : expanded && ctx.maxVisibleChars && raw.length > ctx.maxVisibleChars ? /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(false), children: [
10234
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("i", { className: "ph ph-caret-up", "aria-hidden": "true" }),
10426
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-more-len fd-tabular", children: raw.length < 2e3 ? raw.length.toLocaleString() + " characters" : Math.round(raw.length / 100) / 10 + "k characters" })
10427
+ ] }) : expanded && ctx.maxVisibleChars && raw.length > ctx.maxVisibleChars ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(false), children: [
10428
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-caret-up", "aria-hidden": "true" }),
10235
10429
  "Show less"
10236
10430
  ] }) : null,
10237
- m.attachments && m.attachments.length ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(FileGrid, { files: m.attachments, onOpen: ctx.onOpenAttachment, tiles: true, maxHeight: ctx.attachmentHeight || 220, compact: ctx.narrow }) : null,
10238
- m.packet ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
10431
+ m.attachments && m.attachments.length ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(FileGrid, { files: m.attachments, onOpen: ctx.onOpenAttachment, tiles: true, maxHeight: ctx.attachmentHeight || 220, compact: ctx.narrow }) : null,
10432
+ m.packet ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
10239
10433
  PacketCard,
10240
10434
  {
10241
10435
  packet: m.packet,
@@ -10245,44 +10439,44 @@ function MessageBody({ message: m, ctx }) {
10245
10439
  applied: ctx.appliedPackets && ctx.appliedPackets[m.id]
10246
10440
  }
10247
10441
  ) : null,
10248
- m.citations && m.citations.length ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Citations, { items: m.citations, onOpen: ctx.onOpenCitation }) : null,
10249
- m.working ? /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fdc-working", role: "status", children: [
10250
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fdc-dots", "aria-hidden": "true", children: [
10251
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", {}),
10252
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", {}),
10253
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", {})
10442
+ m.citations && m.citations.length ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Citations, { items: m.citations, onOpen: ctx.onOpenCitation }) : null,
10443
+ m.working ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-working", role: "status", children: [
10444
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("span", { className: "fdc-dots", "aria-hidden": "true", children: [
10445
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", {}),
10446
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", {}),
10447
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", {})
10254
10448
  ] }),
10255
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fdc-working-label", children: [
10449
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("span", { className: "fdc-working-label", children: [
10256
10450
  m.resumed ? "Resuming" : "Working",
10257
- m.job && m.job.status ? /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fdc-working-job", children: [
10451
+ m.job && m.job.status ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("span", { className: "fdc-working-job", children: [
10258
10452
  " \xB7 ",
10259
10453
  m.job.status
10260
10454
  ] }) : null,
10261
- m.job && m.job.detail ? /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fdc-working-job", children: [
10455
+ m.job && m.job.detail ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("span", { className: "fdc-working-job", children: [
10262
10456
  " \xB7 ",
10263
10457
  m.job.detail
10264
10458
  ] }) : null
10265
10459
  ] }),
10266
- m.jobId ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fdc-working-id fd-mono", children: String(m.jobId).slice(0, 12) }) : null
10460
+ m.jobId ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-working-id fd-mono", children: String(m.jobId).slice(0, 12) }) : null
10267
10461
  ] }) : null,
10268
- m.stopped ? /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fdc-stopped", children: [
10269
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
10462
+ m.stopped ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-stopped", children: [
10463
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
10270
10464
  "Stopped"
10271
10465
  ] }) : null,
10272
- m.error ? /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fdc-error", role: "alert", children: [
10273
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
10274
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fdc-error-text", children: ctx.errorCopy ? ctx.errorCopy(m.error) : m.error }),
10275
- m.retryable && ctx.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("button", { type: "button", className: "fdc-error-retry", onClick: ctx.onRetry, children: [
10276
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
10466
+ m.error ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-error", role: "alert", children: [
10467
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
10468
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-error-text", children: ctx.errorCopy ? ctx.errorCopy(m.error) : m.error }),
10469
+ m.retryable && ctx.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("button", { type: "button", className: "fdc-error-retry", onClick: ctx.onRetry, children: [
10470
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
10277
10471
  "Retry"
10278
10472
  ] }) : null
10279
10473
  ] }) : null
10280
10474
  ] });
10281
10475
  }
10282
10476
  function useCopyRun() {
10283
- const [done, setDone] = React51.useState(false);
10284
- const t = React51.useRef(null);
10285
- React51.useEffect(() => () => {
10477
+ const [done, setDone] = React52.useState(false);
10478
+ const t = React52.useRef(null);
10479
+ React52.useEffect(() => () => {
10286
10480
  if (t.current) clearTimeout(t.current);
10287
10481
  }, []);
10288
10482
  return [done, (text) => {
@@ -10302,16 +10496,16 @@ function RunActions({ group, ctx }) {
10302
10496
  const isAssistant = group.role === "assistant";
10303
10497
  const fb = last.feedback;
10304
10498
  if (!ctx.messageActions) return null;
10305
- return /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fdc-actions", role: "group", "aria-label": "Message actions", children: [
10306
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("button", { type: "button", className: "fdc-act" + (copied ? " is-done" : ""), onClick: () => copy(markdownToText(text)), "aria-label": "Copy message", children: [
10307
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("i", { className: "ph ph-" + (copied ? "check" : "copy"), "aria-hidden": "true" }),
10308
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fdc-act-label", children: copied ? "Copied" : "Copy" })
10499
+ return /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-actions", role: "group", "aria-label": "Message actions", children: [
10500
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("button", { type: "button", className: "fdc-act" + (copied ? " is-done" : ""), onClick: () => copy(markdownToText(text)), "aria-label": "Copy message", children: [
10501
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-" + (copied ? "check" : "copy"), "aria-hidden": "true" }),
10502
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-act-label", children: copied ? "Copied" : "Copy" })
10309
10503
  ] }),
10310
- isAssistant && ctx.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("button", { type: "button", className: "fdc-act", onClick: ctx.onRetry, "aria-label": "Retry this turn", children: /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
10311
- group.role === "user" && ctx.onEdit ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("button", { type: "button", className: "fdc-act", onClick: () => ctx.onEdit(last), "aria-label": "Edit and resend", children: /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("i", { className: "ph ph-pencil-simple", "aria-hidden": "true" }) }) : null,
10312
- isAssistant && ctx.onFeedback ? /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)(React51.Fragment, { children: [
10313
- /* @__PURE__ */ (0, import_jsx_runtime80.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_runtime80.jsx)("i", { className: "ph ph-thumbs-up", "aria-hidden": "true" }) }),
10314
- /* @__PURE__ */ (0, import_jsx_runtime80.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_runtime80.jsx)("i", { className: "ph ph-thumbs-down", "aria-hidden": "true" }) })
10504
+ isAssistant && ctx.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("button", { type: "button", className: "fdc-act", onClick: ctx.onRetry, "aria-label": "Retry this turn", children: /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
10505
+ group.role === "user" && ctx.onEdit ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("button", { type: "button", className: "fdc-act", onClick: () => ctx.onEdit(last), "aria-label": "Edit and resend", children: /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-pencil-simple", "aria-hidden": "true" }) }) : null,
10506
+ isAssistant && ctx.onFeedback ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)(React52.Fragment, { children: [
10507
+ /* @__PURE__ */ (0, import_jsx_runtime81.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_runtime81.jsx)("i", { className: "ph ph-thumbs-up", "aria-hidden": "true" }) }),
10508
+ /* @__PURE__ */ (0, import_jsx_runtime81.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_runtime81.jsx)("i", { className: "ph ph-thumbs-down", "aria-hidden": "true" }) })
10315
10509
  ] }) : null,
10316
10510
  ctx.extraActions ? ctx.extraActions(group) : null
10317
10511
  ] });
@@ -10321,22 +10515,22 @@ function ChatTurn({ group, ctx }) {
10321
10515
  const name = isUser ? ctx.userName : group.author || ctx.assistantName;
10322
10516
  const avatar = isUser ? ctx.userAvatar : ctx.assistantAvatar;
10323
10517
  const stamp = group.messages[0].timestamp;
10324
- return /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("article", { className: "fdc-turn is-" + group.role, "aria-label": String(name) + (stamp ? " at " + formatClock(stamp) : ""), children: [
10325
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fdc-turn-head", children: [
10326
- ctx.showAvatars ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fdc-avatar is-" + group.role, "aria-hidden": "true", children: avatar ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("img", { src: avatar, alt: "" }) : isUser ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fdc-avatar-txt", children: (name || "You").slice(0, 1).toUpperCase() }) : /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("i", { className: "ph ph-" + (ctx.assistantIcon || "sparkle") }) }) : null,
10327
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fdc-who", children: name }),
10328
- stamp ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(RelativeTime, { className: "fdc-when", value: stamp }) : null,
10329
- group.messages.some((m) => m.model) ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fdc-turn-model", children: group.messages.find((m) => m.model).model }) : null
10518
+ return /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("article", { className: "fdc-turn is-" + group.role, "aria-label": String(name) + (stamp ? " at " + formatClock(stamp) : ""), children: [
10519
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-turn-head", children: [
10520
+ ctx.showAvatars ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-avatar is-" + group.role, "aria-hidden": "true", children: avatar ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("img", { src: avatar, alt: "" }) : isUser ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-avatar-txt", children: (name || "You").slice(0, 1).toUpperCase() }) : /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-" + (ctx.assistantIcon || "sparkle") }) }) : null,
10521
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-who", children: name }),
10522
+ stamp ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(RelativeTime, { className: "fdc-when", value: stamp }) : null,
10523
+ group.messages.some((m) => m.model) ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-turn-model", children: group.messages.find((m) => m.model).model }) : null
10330
10524
  ] }),
10331
- /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fdc-turn-body", children: [
10332
- group.messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("div", { className: "fdc-msg" + (m.pending ? " is-pending" : ""), children: /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(MessageBody, { message: m, ctx }) }, m.id)),
10333
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(RunActions, { group, ctx })
10525
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-turn-body", children: [
10526
+ group.messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("div", { className: "fdc-msg" + (m.pending ? " is-pending" : ""), children: /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(MessageBody, { message: m, ctx }) }, m.id)),
10527
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(RunActions, { group, ctx })
10334
10528
  ] })
10335
10529
  ] });
10336
10530
  }
10337
10531
 
10338
10532
  // src/components/chat/ChatTranscript.tsx
10339
- var import_jsx_runtime81 = require("react/jsx-runtime");
10533
+ var import_jsx_runtime82 = require("react/jsx-runtime");
10340
10534
  var GROUP_WINDOW = 6e4;
10341
10535
  var STICK_PX = 100;
10342
10536
  function groupMessages(list) {
@@ -10369,25 +10563,25 @@ function dayLabel(key) {
10369
10563
  }
10370
10564
  function Suggestions({ items = [], onPick }) {
10371
10565
  if (!items.length) return null;
10372
- return /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("div", { className: "fdc-suggest", children: items.map((s, i) => {
10566
+ return /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fdc-suggest", children: items.map((s, i) => {
10373
10567
  const it = typeof s === "string" ? { label: s, text: s } : s;
10374
- return /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("button", { type: "button", className: "fdc-suggest-item", onClick: () => onPick && onPick(it.text || it.label), children: [
10375
- it.icon ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-" + it.icon, "aria-hidden": "true" }) : null,
10376
- /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("span", { className: "fdc-suggest-text", children: [
10377
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-suggest-label", children: it.label }),
10378
- it.description ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-suggest-desc", children: it.description }) : null
10568
+ return /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("button", { type: "button", className: "fdc-suggest-item", onClick: () => onPick && onPick(it.text || it.label), children: [
10569
+ it.icon ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-" + it.icon, "aria-hidden": "true" }) : null,
10570
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("span", { className: "fdc-suggest-text", children: [
10571
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fdc-suggest-label", children: it.label }),
10572
+ it.description ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fdc-suggest-desc", children: it.description }) : null
10379
10573
  ] }),
10380
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-arrow-up-right fdc-suggest-go", "aria-hidden": "true" })
10574
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-arrow-up-right fdc-suggest-go", "aria-hidden": "true" })
10381
10575
  ] }, it.id || i);
10382
10576
  }) });
10383
10577
  }
10384
10578
  function LoadingTurns() {
10385
- return /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("div", { className: "fdc-skel", "aria-hidden": "true", children: [0, 1].map((i) => /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-skel-turn", children: [
10386
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("div", { className: "fd-skel fd-skel-circle", style: { width: 22, height: 22 } }),
10387
- /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-skel-lines", children: [
10388
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("div", { className: "fd-skel", style: { width: i ? "62%" : "44%", height: 11 } }),
10389
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("div", { className: "fd-skel", style: { width: i ? "94%" : "78%", height: 11 } }),
10390
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("div", { className: "fd-skel", style: { width: i ? "71%" : "56%", height: 11 } })
10579
+ return /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fdc-skel", "aria-hidden": "true", children: [0, 1].map((i) => /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fdc-skel-turn", children: [
10580
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fd-skel fd-skel-circle", style: { width: 22, height: 22 } }),
10581
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fdc-skel-lines", children: [
10582
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fd-skel", style: { width: i ? "62%" : "44%", height: 11 } }),
10583
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fd-skel", style: { width: i ? "94%" : "78%", height: 11 } }),
10584
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fd-skel", style: { width: i ? "71%" : "56%", height: 11 } })
10391
10585
  ] })
10392
10586
  ] }, i)) });
10393
10587
  }
@@ -10404,10 +10598,10 @@ function ChatTranscript({
10404
10598
  renderEmpty,
10405
10599
  className = ""
10406
10600
  }) {
10407
- const scroller = React52.useRef(null);
10408
- const stick = React52.useRef(true);
10409
- const [pill, setPill] = React52.useState(0);
10410
- const seen = React52.useRef(0);
10601
+ const scroller = React53.useRef(null);
10602
+ const stick = React53.useRef(true);
10603
+ const [pill, setPill] = React53.useState(0);
10604
+ const seen = React53.useRef(0);
10411
10605
  const toBottom = (smooth) => {
10412
10606
  const el = scroller.current;
10413
10607
  if (!el) return;
@@ -10426,7 +10620,7 @@ function ChatTranscript({
10426
10620
  seen.current = messages.length;
10427
10621
  }
10428
10622
  };
10429
- React52.useLayoutEffect(() => {
10623
+ React53.useLayoutEffect(() => {
10430
10624
  const el = scroller.current;
10431
10625
  if (!el) return;
10432
10626
  if (stick.current) {
@@ -10434,7 +10628,7 @@ function ChatTranscript({
10434
10628
  seen.current = messages.length;
10435
10629
  } else setPill(Math.max(0, messages.length - seen.current));
10436
10630
  }, [messages]);
10437
- React52.useEffect(() => {
10631
+ React53.useEffect(() => {
10438
10632
  const el = scroller.current;
10439
10633
  const inner = el && el.firstChild;
10440
10634
  if (!el || !inner || typeof ResizeObserver === "undefined") return;
@@ -10444,38 +10638,38 @@ function ChatTranscript({
10444
10638
  ro.observe(inner);
10445
10639
  return () => ro.disconnect();
10446
10640
  }, []);
10447
- const groups = React52.useMemo(() => groupMessages(messages), [messages]);
10641
+ const groups = React53.useMemo(() => groupMessages(messages), [messages]);
10448
10642
  const empty = !messages.length && status === "ready";
10449
- return /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
10450
- /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
10451
- status === "loading" || status === "resolving" ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(LoadingTurns, {}) : null,
10452
- status === "disconnected" ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-dead", children: [
10453
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-dead-icon", children: /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-plugs", "aria-hidden": "true" }) }),
10454
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("h3", { className: "fdc-dead-title", children: ctx.deadTitle || "The assistant isn\u2019t reachable" }),
10455
- /* @__PURE__ */ (0, import_jsx_runtime81.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." }),
10456
- ctx.onReconnect ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("button", { type: "button", className: "fd-btn fd-btn-secondary fd-btn-sm", onClick: ctx.onReconnect, children: [
10457
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
10643
+ return /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
10644
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
10645
+ status === "loading" || status === "resolving" ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(LoadingTurns, {}) : null,
10646
+ status === "disconnected" ? /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fdc-dead", children: [
10647
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fdc-dead-icon", children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-plugs", "aria-hidden": "true" }) }),
10648
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("h3", { className: "fdc-dead-title", children: ctx.deadTitle || "The assistant isn\u2019t reachable" }),
10649
+ /* @__PURE__ */ (0, import_jsx_runtime82.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." }),
10650
+ ctx.onReconnect ? /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("button", { type: "button", className: "fd-btn fd-btn-secondary fd-btn-sm", onClick: ctx.onReconnect, children: [
10651
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
10458
10652
  "Try again"
10459
10653
  ] }) : null
10460
10654
  ] }) : null,
10461
- empty ? renderEmpty ? renderEmpty() : /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-empty", children: [
10462
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-empty-icon", children: /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-" + emptyIcon, "aria-hidden": "true" }) }),
10463
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("h3", { className: "fdc-empty-title", children: emptyTitle }),
10464
- emptyDescription ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("p", { className: "fdc-empty-body", children: emptyDescription }) : null,
10465
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Suggestions, { items: suggestions, onPick })
10655
+ empty ? renderEmpty ? renderEmpty() : /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fdc-empty", children: [
10656
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fdc-empty-icon", children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-" + emptyIcon, "aria-hidden": "true" }) }),
10657
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("h3", { className: "fdc-empty-title", children: emptyTitle }),
10658
+ emptyDescription ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("p", { className: "fdc-empty-body", children: emptyDescription }) : null,
10659
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Suggestions, { items: suggestions, onPick })
10466
10660
  ] }) : null,
10467
10661
  groups.map((g, i) => {
10468
10662
  const prev = groups[i - 1];
10469
10663
  const k = dayKey(g.messages[0].timestamp);
10470
10664
  const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
10471
- return /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)(React52.Fragment, { children: [
10472
- showDay ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("div", { className: "fdc-day", children: /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { children: dayLabel(k) }) }) : null,
10473
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(ChatTurn, { group: g, ctx })
10665
+ return /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)(React53.Fragment, { children: [
10666
+ showDay ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fdc-day", children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { children: dayLabel(k) }) }) : null,
10667
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(ChatTurn, { group: g, ctx })
10474
10668
  ] }, g.key || i);
10475
10669
  })
10476
10670
  ] }),
10477
- pill ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("button", { type: "button", className: "fdc-pill", onClick: () => toBottom(true), children: [
10478
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-arrow-down", "aria-hidden": "true" }),
10671
+ pill ? /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("button", { type: "button", className: "fdc-pill", onClick: () => toBottom(true), children: [
10672
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-arrow-down", "aria-hidden": "true" }),
10479
10673
  pill,
10480
10674
  " new message",
10481
10675
  pill === 1 ? "" : "s"
@@ -10485,8 +10679,8 @@ function ChatTranscript({
10485
10679
  var TranscriptKit = { groupMessages };
10486
10680
 
10487
10681
  // src/components/chat/ChatComposer.tsx
10488
- var React53 = __toESM(require("react"), 1);
10489
- var import_jsx_runtime82 = require("react/jsx-runtime");
10682
+ var React54 = __toESM(require("react"), 1);
10683
+ var import_jsx_runtime83 = require("react/jsx-runtime");
10490
10684
  function ChatComposer({
10491
10685
  onSubmit,
10492
10686
  onStop,
@@ -10513,17 +10707,17 @@ function ChatComposer({
10513
10707
  onReject,
10514
10708
  onOpenAttachment
10515
10709
  }) {
10516
- const [text, setText] = React53.useState(draft || "");
10517
- const [trigger, setTrigger] = React53.useState(null);
10518
- const [mentionItems, setMentionItems] = React53.useState([]);
10519
- const [listening, setListening] = React53.useState(false);
10520
- const [notice, setNotice] = React53.useState(null);
10521
- const editor = React53.useRef(null);
10522
- const wrap = React53.useRef(null);
10523
- const stopVoice = React53.useRef(null);
10710
+ const [text, setText] = React54.useState(draft || "");
10711
+ const [trigger, setTrigger] = React54.useState(null);
10712
+ const [mentionItems, setMentionItems] = React54.useState([]);
10713
+ const [listening, setListening] = React54.useState(false);
10714
+ const [notice, setNotice] = React54.useState(null);
10715
+ const editor = React54.useRef(null);
10716
+ const wrap = React54.useRef(null);
10717
+ const stopVoice = React54.useRef(null);
10524
10718
  const staged = useStagedFiles(fileUploadHandler, { onError: () => {
10525
10719
  } });
10526
- React53.useEffect(() => {
10720
+ React54.useEffect(() => {
10527
10721
  if (draft != null && draft !== text) setText(draft);
10528
10722
  }, [draft]);
10529
10723
  const change = (v) => {
@@ -10559,7 +10753,7 @@ function ChatComposer({
10559
10753
  e.preventDefault();
10560
10754
  staged.add(found.files);
10561
10755
  };
10562
- React53.useEffect(() => {
10756
+ React54.useEffect(() => {
10563
10757
  if (!trigger || trigger.type !== "mention" || !mentionSources) {
10564
10758
  setMentionItems([]);
10565
10759
  return;
@@ -10577,7 +10771,7 @@ function ChatComposer({
10577
10771
  const q = (trigger.query || "").toLowerCase();
10578
10772
  setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
10579
10773
  }, [trigger, mentionSources]);
10580
- const slashItems = React53.useMemo(() => {
10774
+ const slashItems = React54.useMemo(() => {
10581
10775
  if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
10582
10776
  const q = (trigger.query || "").toLowerCase();
10583
10777
  return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
@@ -10591,7 +10785,7 @@ function ChatComposer({
10591
10785
  description: it.description,
10592
10786
  icon: it.icon,
10593
10787
  meta: mention.meta,
10594
- shortcut: slash.shortcut ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(KeyHint, { keys: slash.shortcut, size: "sm" }) : void 0,
10788
+ shortcut: slash.shortcut ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(KeyHint, { keys: slash.shortcut, size: "sm" }) : void 0,
10595
10789
  onSelect: () => {
10596
10790
  const insert = trigger.type === "slash" ? slash.immediate ? "/" + slash.id : "/" + slash.id + " " : "@" + (mention.value || mention.label) + " ";
10597
10791
  editor.current && editor.current.replaceRange(trigger.from, trigger.to, insert);
@@ -10654,14 +10848,14 @@ function ChatComposer({
10654
10848
  stopVoice.current = typeof res === "function" ? res : () => {
10655
10849
  };
10656
10850
  };
10657
- return /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fdc-composer" + (disabled ? " is-disabled" : "") + (narrow ? " is-narrow" : ""), children: [
10658
- queue.length ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fdc-queue", "aria-label": "Queued messages", children: queue.map((q) => /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fdc-queue-row", children: [
10659
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-clock-countdown", "aria-hidden": "true" }),
10660
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fdc-queue-text", title: truncationTitle(q.text || (q.attachments ? q.attachments.length + " file(s)" : "")), children: q.text || (q.attachments ? q.attachments.length + " file(s)" : "") }),
10661
- onRemoveQueued ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("button", { type: "button", className: "fdc-queue-x", onClick: () => onRemoveQueued(q.id), "aria-label": "Remove queued message", children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
10851
+ return /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fdc-composer" + (disabled ? " is-disabled" : "") + (narrow ? " is-narrow" : ""), children: [
10852
+ queue.length ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: "fdc-queue", "aria-label": "Queued messages", children: queue.map((q) => /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fdc-queue-row", children: [
10853
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-clock-countdown", "aria-hidden": "true" }),
10854
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fdc-queue-text", title: truncationTitle(q.text || (q.attachments ? q.attachments.length + " file(s)" : "")), children: q.text || (q.attachments ? q.attachments.length + " file(s)" : "") }),
10855
+ onRemoveQueued ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("button", { type: "button", className: "fdc-queue-x", onClick: () => onRemoveQueued(q.id), "aria-label": "Remove queued message", children: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
10662
10856
  ] }, q.id)) }) : null,
10663
10857
  sessionBar,
10664
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
10858
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
10665
10859
  Dropzone,
10666
10860
  {
10667
10861
  className: "fdc-field",
@@ -10675,9 +10869,9 @@ function ChatComposer({
10675
10869
  disabled: !fileUploadHandler || disabled,
10676
10870
  label: "Drop to attach",
10677
10871
  hint: acceptFiles ? acceptFiles.replace(/,/g, " \xB7 ") : void 0,
10678
- children: /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { ref: wrap, className: "fdc-field-inner", children: [
10679
- staged.items.length ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fdc-staged", children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(FileStrip, { files: staged.items, size: narrow ? 60 : 68, onRemove: staged.remove, onRetry: staged.retry, onOpen: onOpenAttachment }) }) : null,
10680
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
10872
+ children: /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { ref: wrap, className: "fdc-field-inner", children: [
10873
+ staged.items.length ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: "fdc-staged", children: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(FileStrip, { files: staged.items, size: narrow ? 60 : 68, onRemove: staged.remove, onRetry: staged.retry, onOpen: onOpenAttachment }) }) : null,
10874
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
10681
10875
  MarkdownEditor,
10682
10876
  {
10683
10877
  ref: editor,
@@ -10696,33 +10890,33 @@ function ChatComposer({
10696
10890
  ariaLabel: "Message"
10697
10891
  }
10698
10892
  ),
10699
- /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fdc-tools", children: [
10700
- fileUploadHandler ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(FilePickButton, { onFiles: staged.add, onReject: (r) => flash(r[0].message), accept: acceptFiles, maxFileSize, label: "Attach files", icon: "plus" }) : null,
10701
- voiceHandler ? /* @__PURE__ */ (0, import_jsx_runtime82.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_runtime82.jsx)("i", { className: "ph ph-" + (listening ? "waveform" : "microphone"), "aria-hidden": "true" }) }) : null,
10893
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fdc-tools", children: [
10894
+ fileUploadHandler ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(FilePickButton, { onFiles: staged.add, onReject: (r) => flash(r[0].message), accept: acceptFiles, maxFileSize, label: "Attach files", icon: "plus" }) : null,
10895
+ voiceHandler ? /* @__PURE__ */ (0, import_jsx_runtime83.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_runtime83.jsx)("i", { className: "ph ph-" + (listening ? "waveform" : "microphone"), "aria-hidden": "true" }) }) : null,
10702
10896
  toolbarExtras,
10703
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fdc-tools-gap" }),
10704
- maxLength && text.length > maxLength * 0.6 ? /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("span", { className: "fdc-count fd-tabular" + (text.length > maxLength * 0.95 ? " is-hot" : ""), children: [
10897
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fdc-tools-gap" }),
10898
+ maxLength && text.length > maxLength * 0.6 ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { className: "fdc-count fd-tabular" + (text.length > maxLength * 0.95 ? " is-hot" : ""), children: [
10705
10899
  text.length,
10706
10900
  "/",
10707
10901
  maxLength
10708
10902
  ] }) : null,
10709
- busy ? /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("button", { type: "button", className: "fdc-stop", onClick: onStop, "aria-label": "Stop generating", children: [
10710
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
10711
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { children: "Stop" })
10712
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("button", { type: "button", className: "fdc-send", onClick: submit, disabled: !canSend, "aria-label": "Send message", children: [
10713
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-paper-plane-right", "aria-hidden": "true" }),
10714
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fdc-send-label", children: "Send" })
10903
+ busy ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("button", { type: "button", className: "fdc-stop", onClick: onStop, "aria-label": "Stop generating", children: [
10904
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
10905
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { children: "Stop" })
10906
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("button", { type: "button", className: "fdc-send", onClick: submit, disabled: !canSend, "aria-label": "Send message", children: [
10907
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-paper-plane-right", "aria-hidden": "true" }),
10908
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fdc-send-label", children: "Send" })
10715
10909
  ] })
10716
10910
  ] })
10717
10911
  ] })
10718
10912
  }
10719
10913
  ),
10720
- notice ? /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fdc-notice", role: "status", children: [
10721
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
10914
+ notice ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fdc-notice", role: "status", children: [
10915
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
10722
10916
  notice
10723
10917
  ] }) : null,
10724
- hint && !notice ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fdc-hint", children: hint }) : null,
10725
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
10918
+ hint && !notice ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: "fdc-hint", children: hint }) : null,
10919
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
10726
10920
  Popover,
10727
10921
  {
10728
10922
  open: menuOpen,
@@ -10736,12 +10930,12 @@ function ChatComposer({
10736
10930
  returnFocus: false,
10737
10931
  closeOnOutside: true,
10738
10932
  label: trigger && trigger.type === "slash" ? "Commands" : "Mentions",
10739
- children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
10933
+ children: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
10740
10934
  Menu,
10741
10935
  {
10742
10936
  items: menuItems,
10743
10937
  autoFocus: false,
10744
- header: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fd-pop-group", children: trigger && trigger.type === "slash" ? "Commands" : "Attach context" }),
10938
+ header: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: "fd-pop-group", children: trigger && trigger.type === "slash" ? "Commands" : "Attach context" }),
10745
10939
  onClose: () => setTrigger(null)
10746
10940
  }
10747
10941
  )
@@ -10751,12 +10945,12 @@ function ChatComposer({
10751
10945
  }
10752
10946
 
10753
10947
  // src/components/chat/ChatSessionBar.tsx
10754
- var React54 = __toESM(require("react"), 1);
10755
- var import_jsx_runtime83 = require("react/jsx-runtime");
10948
+ var React55 = __toESM(require("react"), 1);
10949
+ var import_jsx_runtime84 = require("react/jsx-runtime");
10756
10950
  var compact2 = meterFormats.compact;
10757
10951
  function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
10758
- const [open, setOpen] = React54.useState(false);
10759
- const anchor = React54.useRef(null);
10952
+ const [open, setOpen] = React55.useState(false);
10953
+ const anchor = React55.useRef(null);
10760
10954
  const stats = sessionStats || null;
10761
10955
  const cu = contextUsage || null;
10762
10956
  const limits = usageLimits || null;
@@ -10771,9 +10965,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
10771
10965
  if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
10772
10966
  if (cu) bits.push(pct + "% context");
10773
10967
  const expandable = !!(cu || limits);
10774
- return /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)(React54.Fragment, { children: [
10775
- /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fdc-bar", children: [
10776
- /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)(
10968
+ return /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(React55.Fragment, { children: [
10969
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: "fdc-bar", children: [
10970
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(
10777
10971
  "button",
10778
10972
  {
10779
10973
  type: "button",
@@ -10784,15 +10978,15 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
10784
10978
  "aria-expanded": expandable ? open : void 0,
10785
10979
  "aria-label": expandable ? "Usage details" : void 0,
10786
10980
  children: [
10787
- cu ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fdc-bar-mini", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(SegmentedMeter, { total, segments: cu.segments, height: 4, showTotal: false }) }) : null,
10788
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fdc-bar-text", title: truncationTitle(bits.join(" \xB7 ")), children: bits.join(" \xB7 ") }),
10789
- expandable ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-caret-right fdc-bar-caret", "aria-hidden": "true" }) : null
10981
+ cu ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fdc-bar-mini", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(SegmentedMeter, { total, segments: cu.segments, height: 4, showTotal: false }) }) : null,
10982
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fdc-bar-text", title: truncationTitle(bits.join(" \xB7 ")), children: bits.join(" \xB7 ") }),
10983
+ expandable ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-caret-right fdc-bar-caret", "aria-hidden": "true" }) : null
10790
10984
  ]
10791
10985
  }
10792
10986
  ),
10793
10987
  extras
10794
10988
  ] }),
10795
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
10989
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
10796
10990
  Popover,
10797
10991
  {
10798
10992
  open,
@@ -10803,15 +10997,15 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
10803
10997
  maxHeight: 460,
10804
10998
  padded: true,
10805
10999
  label: "Usage",
10806
- footer: onClear ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("button", { type: "button", className: "fdc-usage-clear", onClick: () => {
11000
+ footer: onClear ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("button", { type: "button", className: "fdc-usage-clear", onClick: () => {
10807
11001
  setOpen(false);
10808
11002
  onClear();
10809
11003
  }, children: [
10810
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-trash", "aria-hidden": "true" }),
11004
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-trash", "aria-hidden": "true" }),
10811
11005
  "Clear conversation"
10812
11006
  ] }) : void 0,
10813
- children: /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fdc-usage", children: [
10814
- cu ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("section", { className: "fdc-usage-sec", children: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
11007
+ children: /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: "fdc-usage", children: [
11008
+ cu ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("section", { className: "fdc-usage-sec", children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
10815
11009
  SegmentedMeter,
10816
11010
  {
10817
11011
  total,
@@ -10823,9 +11017,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
10823
11017
  remainderLabel: "Free"
10824
11018
  }
10825
11019
  ) }) : null,
10826
- limits && limits.length ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("section", { className: "fdc-usage-sec", children: [
10827
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("h4", { className: "fdc-usage-h", children: "Usage limits" }),
10828
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: "fdc-usage-rows", children: limits.map((l) => /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
11020
+ limits && limits.length ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("section", { className: "fdc-usage-sec", children: [
11021
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("h4", { className: "fdc-usage-h", children: "Usage limits" }),
11022
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("div", { className: "fdc-usage-rows", children: limits.map((l) => /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
10829
11023
  QuotaRow,
10830
11024
  {
10831
11025
  label: l.label,
@@ -10835,25 +11029,25 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
10835
11029
  l.id
10836
11030
  )) })
10837
11031
  ] }) : null,
10838
- stats ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("section", { className: "fdc-usage-sec fdc-usage-stats", children: [
10839
- stats.elapsedMs ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { children: [
10840
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { children: "Session" }),
10841
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("b", { className: "fd-tabular", children: formatDuration(stats.elapsedMs) })
11032
+ stats ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("section", { className: "fdc-usage-sec fdc-usage-stats", children: [
11033
+ stats.elapsedMs ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { children: [
11034
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { children: "Session" }),
11035
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("b", { className: "fd-tabular", children: formatDuration(stats.elapsedMs) })
10842
11036
  ] }) : null,
10843
- stats.tokens ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { children: [
10844
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { children: "Tokens" }),
10845
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("b", { className: "fd-tabular", children: stats.tokens.toLocaleString() })
11037
+ stats.tokens ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { children: [
11038
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { children: "Tokens" }),
11039
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("b", { className: "fd-tabular", children: stats.tokens.toLocaleString() })
10846
11040
  ] }) : null,
10847
- stats.costUsd != null ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { children: [
10848
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { children: "Cost" }),
10849
- /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("b", { className: "fd-tabular", children: [
11041
+ stats.costUsd != null ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { children: [
11042
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { children: "Cost" }),
11043
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("b", { className: "fd-tabular", children: [
10850
11044
  "$",
10851
11045
  Number(stats.costUsd).toFixed(3)
10852
11046
  ] })
10853
11047
  ] }) : null,
10854
- stats.turns ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { children: [
10855
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { children: "Turns" }),
10856
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("b", { className: "fd-tabular", children: stats.turns })
11048
+ stats.turns ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { children: [
11049
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { children: "Turns" }),
11050
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("b", { className: "fd-tabular", children: stats.turns })
10857
11051
  ] }) : null
10858
11052
  ] }) : null
10859
11053
  ] })
@@ -10892,7 +11086,7 @@ function ModelControls({
10892
11086
  disabled: m.disabled,
10893
11087
  checked: m.id === (current2 && current2.id),
10894
11088
  meta: m.meta,
10895
- shortcut: m.shortcut ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(KeyHint, { keys: m.shortcut, size: "sm" }) : void 0,
11089
+ shortcut: m.shortcut ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(KeyHint, { keys: m.shortcut, size: "sm" }) : void 0,
10896
11090
  onSelect: () => onModelChange && onModelChange(m.id)
10897
11091
  });
10898
11092
  const items = [{ kind: "section", label: "Models" }].concat(flat.map(item));
@@ -10905,15 +11099,15 @@ function ModelControls({
10905
11099
  items.push({ kind: "section", label: "Fast mode" });
10906
11100
  items.push({
10907
11101
  kind: "custom",
10908
- render: () => /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("label", { className: "fdc-switchrow", children: [
10909
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { children: fastModeLabel }),
10910
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("input", { type: "checkbox", className: "fd-sr", checked: !!fastMode, onChange: (e) => onFastModeChange(e.target.checked) }),
10911
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fd-switch-track" + (fastMode ? " is-on" : ""), "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fd-switch-thumb" }) })
11102
+ render: () => /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("label", { className: "fdc-switchrow", children: [
11103
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { children: fastModeLabel }),
11104
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("input", { type: "checkbox", className: "fd-sr", checked: !!fastMode, onChange: (e) => onFastModeChange(e.target.checked) }),
11105
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-switch-track" + (fastMode ? " is-on" : ""), "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-switch-thumb" }) })
10912
11106
  ] })
10913
11107
  });
10914
11108
  }
10915
- return /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)(React54.Fragment, { children: [
10916
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
11109
+ return /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(React55.Fragment, { children: [
11110
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
10917
11111
  MenuButton,
10918
11112
  {
10919
11113
  items,
@@ -10924,7 +11118,7 @@ function ModelControls({
10924
11118
  title: "Choose a model"
10925
11119
  }
10926
11120
  ),
10927
- effortLevels && effortLevels.length ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
11121
+ effortLevels && effortLevels.length ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
10928
11122
  MenuButton,
10929
11123
  {
10930
11124
  placement: "top-end",
@@ -10945,7 +11139,7 @@ function ModelControls({
10945
11139
  }
10946
11140
 
10947
11141
  // src/components/chat/AgentChatPanel.tsx
10948
- var import_jsx_runtime84 = require("react/jsx-runtime");
11142
+ var import_jsx_runtime85 = require("react/jsx-runtime");
10949
11143
  var SURFACES = { sidebar: "is-sidebar", inline: "is-inline", page: "is-page", modal: "is-modal", sheet: "is-sheet" };
10950
11144
  function AgentChatPanel({
10951
11145
  /* required */
@@ -11029,11 +11223,11 @@ function AgentChatPanel({
11029
11223
  onFeedback,
11030
11224
  onEditMessage
11031
11225
  }) {
11032
- const [panelWidth, setPanelWidth] = React55.useState(width);
11033
- const [applied, setApplied] = React55.useState({});
11034
- const [draft, setDraft] = React55.useState("");
11035
- const dragging = React55.useRef(null);
11036
- React55.useEffect(() => setPanelWidth(width), [width]);
11226
+ const [panelWidth, setPanelWidth] = React56.useState(width);
11227
+ const [applied, setApplied] = React56.useState({});
11228
+ const [draft, setDraft] = React56.useState("");
11229
+ const dragging = React56.useRef(null);
11230
+ React56.useEffect(() => setPanelWidth(width), [width]);
11037
11231
  const engine = useChatEngine({
11038
11232
  contextType,
11039
11233
  contextId,
@@ -11099,7 +11293,7 @@ function AgentChatPanel({
11099
11293
  onReconnect: engine.reload,
11100
11294
  deadTitle: "The assistant isn\u2019t reachable"
11101
11295
  };
11102
- const sessionBar = /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
11296
+ const sessionBar = /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
11103
11297
  ChatSessionBar,
11104
11298
  {
11105
11299
  sessionStats,
@@ -11108,7 +11302,7 @@ function AgentChatPanel({
11108
11302
  onClear: engine.visible.length ? engine.clear : void 0
11109
11303
  }
11110
11304
  );
11111
- const modelControls = /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
11305
+ const modelControls = /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
11112
11306
  ModelControls,
11113
11307
  {
11114
11308
  models,
@@ -11123,7 +11317,7 @@ function AgentChatPanel({
11123
11317
  narrow
11124
11318
  }
11125
11319
  );
11126
- const threadMenu = threads && threads.length ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
11320
+ const threadMenu = threads && threads.length ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
11127
11321
  MenuButton,
11128
11322
  {
11129
11323
  variant: "ghost",
@@ -11150,7 +11344,7 @@ function AgentChatPanel({
11150
11344
  })))
11151
11345
  }
11152
11346
  ) : null;
11153
- return /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(
11347
+ return /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)(
11154
11348
  "aside",
11155
11349
  {
11156
11350
  className: ["fdc-panel", SURFACES[surface] || SURFACES.sidebar, narrow ? "is-narrow" : "", className].filter(Boolean).join(" "),
@@ -11161,7 +11355,7 @@ function AgentChatPanel({
11161
11355
  },
11162
11356
  "aria-label": title,
11163
11357
  children: [
11164
- surface === "sidebar" && resizable ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
11358
+ surface === "sidebar" && resizable ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
11165
11359
  "div",
11166
11360
  {
11167
11361
  className: "fdc-grip",
@@ -11176,20 +11370,20 @@ function AgentChatPanel({
11176
11370
  }
11177
11371
  }
11178
11372
  ) : null,
11179
- showHeader ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("header", { className: "fdc-head", children: [
11180
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fdc-head-mark", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-" + assistantIcon }) }),
11181
- /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("span", { className: "fdc-head-titles", children: [
11182
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fdc-head-title", title: truncationTitle(title), children: title }),
11183
- subtitle ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fdc-head-sub", title: truncationTitle(subtitle), children: subtitle }) : null
11373
+ showHeader ? /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("header", { className: "fdc-head", children: [
11374
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fdc-head-mark", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("i", { className: "ph ph-" + assistantIcon }) }),
11375
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fdc-head-titles", children: [
11376
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fdc-head-title", title: truncationTitle(title), children: title }),
11377
+ subtitle ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fdc-head-sub", title: truncationTitle(subtitle), children: subtitle }) : null
11184
11378
  ] }),
11185
- /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("span", { className: "fdc-head-acts", children: [
11379
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fdc-head-acts", children: [
11186
11380
  headerActions,
11187
11381
  threadMenu,
11188
- onNewThread ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("button", { type: "button", className: "fdc-iconbtn", onClick: onNewThread, "aria-label": "New conversation", title: "New conversation", children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-plus", "aria-hidden": "true" }) }) : null,
11189
- onClose ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("button", { type: "button", className: "fdc-iconbtn", onClick: onClose, "aria-label": "Close panel", title: "Close", children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
11382
+ onNewThread ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("button", { type: "button", className: "fdc-iconbtn", onClick: onNewThread, "aria-label": "New conversation", title: "New conversation", children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("i", { className: "ph ph-plus", "aria-hidden": "true" }) }) : null,
11383
+ onClose ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("button", { type: "button", className: "fdc-iconbtn", onClick: onClose, "aria-label": "Close panel", title: "Close", children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
11190
11384
  ] })
11191
11385
  ] }) : null,
11192
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
11386
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
11193
11387
  ChatTranscript,
11194
11388
  {
11195
11389
  messages: engine.visible,
@@ -11204,7 +11398,7 @@ function AgentChatPanel({
11204
11398
  renderEmpty
11205
11399
  }
11206
11400
  ),
11207
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
11401
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
11208
11402
  ChatComposer,
11209
11403
  {
11210
11404
  onSubmit: (text, atts) => engine.send(text, atts),
@@ -11237,8 +11431,8 @@ function AgentChatPanel({
11237
11431
  }
11238
11432
 
11239
11433
  // src/components/files/FileViewer.tsx
11240
- var React56 = __toESM(require("react"), 1);
11241
- var import_jsx_runtime85 = require("react/jsx-runtime");
11434
+ var React57 = __toESM(require("react"), 1);
11435
+ var import_jsx_runtime86 = require("react/jsx-runtime");
11242
11436
  function previewKindOf(file) {
11243
11437
  const mime = (file.mime || "").toLowerCase();
11244
11438
  const ext = extensionOf(file.name || "");
@@ -11294,13 +11488,13 @@ function parseDelimited(text, delimiter) {
11294
11488
  return rows;
11295
11489
  }
11296
11490
  function usePreview(file, kind, resolveUrl) {
11297
- const [state, setState] = React56.useState({ status: "loading" });
11298
- const [attempt, setAttempt] = React56.useState(0);
11299
- const resolveRef = React56.useRef(resolveUrl);
11300
- React56.useEffect(() => {
11491
+ const [state, setState] = React57.useState({ status: "loading" });
11492
+ const [attempt, setAttempt] = React57.useState(0);
11493
+ const resolveRef = React57.useRef(resolveUrl);
11494
+ React57.useEffect(() => {
11301
11495
  resolveRef.current = resolveUrl;
11302
11496
  }, [resolveUrl]);
11303
- React56.useEffect(() => {
11497
+ React57.useEffect(() => {
11304
11498
  if (kind === "none") {
11305
11499
  setState({ status: "ready" });
11306
11500
  return;
@@ -11330,19 +11524,19 @@ function usePreview(file, kind, resolveUrl) {
11330
11524
  if (ac) ac.abort();
11331
11525
  };
11332
11526
  }, [file.id, kind, attempt]);
11333
- return { ...state, retry: React56.useCallback(() => setAttempt((a) => a + 1), []) };
11527
+ return { ...state, retry: React57.useCallback(() => setAttempt((a) => a + 1), []) };
11334
11528
  }
11335
11529
  function PreviewBody({ file, kind, state }) {
11336
- if (kind === "image") return /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("img", { className: "fd-fv-image", src: state.url, alt: file.name || "Preview" });
11337
- if (kind === "pdf") return /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("iframe", { className: "fd-fv-pdf", src: state.url, title: file.name || "PDF preview" });
11338
- if (kind === "markdown") return /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(Markdown, { className: "fd-fv-markdown", source: state.text || "" });
11530
+ if (kind === "image") return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("img", { className: "fd-fv-image", src: state.url, alt: file.name || "Preview" });
11531
+ if (kind === "pdf") return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("iframe", { className: "fd-fv-pdf", src: state.url, title: file.name || "PDF preview" });
11532
+ if (kind === "markdown") return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Markdown, { className: "fd-fv-markdown", source: state.text || "" });
11339
11533
  if (kind === "json") {
11340
11534
  let pretty = state.text || "";
11341
11535
  try {
11342
11536
  pretty = JSON.stringify(JSON.parse(pretty), null, 2);
11343
11537
  } catch {
11344
11538
  }
11345
- return /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(CodeBlock, { code: pretty, language: "json" });
11539
+ return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(CodeBlock, { code: pretty, language: "json" });
11346
11540
  }
11347
11541
  if (kind === "csv") {
11348
11542
  const tsv = extensionOf(file.name || "") === "tsv" || (file.mime || "").toLowerCase().includes("tab-separated");
@@ -11350,12 +11544,12 @@ function PreviewBody({ file, kind, state }) {
11350
11544
  const head = rows[0] || [];
11351
11545
  const dataRows = rows.slice(1);
11352
11546
  const shown = dataRows.slice(0, FILE_VIEWER_CSV_ROW_LIMIT);
11353
- return /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("div", { className: "fd-fv-csv", children: [
11354
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("table", { className: "fd-fv-csv-table", children: [
11355
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("tr", { children: head.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("th", { children: c }, i)) }) }),
11356
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("tbody", { children: shown.map((r, ri) => /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("tr", { children: head.map((_, ci) => /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("td", { children: r[ci] ?? "" }, ci)) }, ri)) })
11547
+ return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-fv-csv", children: [
11548
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("table", { className: "fd-fv-csv-table", children: [
11549
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("tr", { children: head.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("th", { children: c }, i)) }) }),
11550
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("tbody", { children: shown.map((r, ri) => /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("tr", { children: head.map((_, ci) => /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("td", { children: r[ci] ?? "" }, ci)) }, ri)) })
11357
11551
  ] }),
11358
- dataRows.length > FILE_VIEWER_CSV_ROW_LIMIT ? /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("p", { className: "fd-fv-csv-note fd-body-sm fd-muted", children: [
11552
+ dataRows.length > FILE_VIEWER_CSV_ROW_LIMIT ? /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("p", { className: "fd-fv-csv-note fd-body-sm fd-muted", children: [
11359
11553
  "Showing the first ",
11360
11554
  FILE_VIEWER_CSV_ROW_LIMIT.toLocaleString(),
11361
11555
  " of ",
@@ -11364,24 +11558,24 @@ function PreviewBody({ file, kind, state }) {
11364
11558
  ] }) : null
11365
11559
  ] });
11366
11560
  }
11367
- if (kind === "text") return /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(CodeBlock, { code: state.text || "", language: extensionOf(file.name || "") || void 0 });
11368
- return /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("div", { className: "fd-fv-fallback", children: [
11369
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fd-fv-fallback-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("i", { className: "ph ph-" + iconForMime(file.mime, file.name) }) }),
11370
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fd-fv-fallback-title", children: "No preview available" }),
11371
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-fv-fallback-meta", children: [
11561
+ if (kind === "text") return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(CodeBlock, { code: state.text || "", language: extensionOf(file.name || "") || void 0 });
11562
+ return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-fv-fallback", children: [
11563
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-fv-fallback-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph ph-" + iconForMime(file.mime, file.name) }) }),
11564
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-fv-fallback-title", children: "No preview available" }),
11565
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-fv-fallback-meta", children: [
11372
11566
  file.mime || "Unknown type",
11373
11567
  file.size ? " \xB7 " + formatBytes(file.size) : ""
11374
11568
  ] })
11375
11569
  ] });
11376
11570
  }
11377
11571
  function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", onClose, actions, className = "" }) {
11378
- const kind = React56.useMemo(() => previewKindOf(file), [file]);
11572
+ const kind = React57.useMemo(() => previewKindOf(file), [file]);
11379
11573
  const preview = usePreview(file, kind, resolveUrl);
11380
- const [tab, setTab] = React56.useState("preview");
11381
- const [downloading, setDownloading] = React56.useState(false);
11382
- const [downloadError, setDownloadError] = React56.useState(null);
11574
+ const [tab, setTab] = React57.useState("preview");
11575
+ const [downloading, setDownloading] = React57.useState(false);
11576
+ const [downloadError, setDownloadError] = React57.useState(null);
11383
11577
  const hasSide = sidePanel != null;
11384
- React56.useEffect(() => {
11578
+ React57.useEffect(() => {
11385
11579
  setTab("preview");
11386
11580
  }, [file.id]);
11387
11581
  const download = () => {
@@ -11397,29 +11591,29 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
11397
11591
  a.remove();
11398
11592
  }).catch((err) => setDownloadError(err && err.message || "Download failed.")).finally(() => setDownloading(false));
11399
11593
  };
11400
- return /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)(
11594
+ return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
11401
11595
  "section",
11402
11596
  {
11403
11597
  className: ["fd-fv", hasSide && tab === "side" ? "is-tab-side" : "is-tab-preview", className].filter(Boolean).join(" "),
11404
11598
  "aria-label": file.name || "File",
11405
11599
  children: [
11406
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("header", { className: "fd-fv-head", children: [
11407
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fd-fv-head-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("i", { className: "ph ph-" + iconForMime(file.mime, file.name) }) }),
11408
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-fv-head-titles", children: [
11409
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fd-fv-head-title", title: file.name, children: file.name }),
11410
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-fv-head-meta", children: [
11600
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("header", { className: "fd-fv-head", children: [
11601
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-fv-head-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph ph-" + iconForMime(file.mime, file.name) }) }),
11602
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-fv-head-titles", children: [
11603
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-fv-head-title", title: file.name, children: file.name }),
11604
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-fv-head-meta", children: [
11411
11605
  file.mime || "Unknown type",
11412
11606
  file.size ? " \xB7 " + formatBytes(file.size) : ""
11413
11607
  ] })
11414
11608
  ] }),
11415
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-fv-head-actions", children: [
11609
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-fv-head-actions", children: [
11416
11610
  actions,
11417
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(Button, { variant: "secondary", size: "sm", icon: "download-simple", loading: downloading, onClick: download, children: "Download" }),
11418
- onClose ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(IconButton, { icon: "x", label: "Close", onClick: onClose }) : null
11611
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Button, { variant: "secondary", size: "sm", icon: "download-simple", loading: downloading, onClick: download, children: "Download" }),
11612
+ onClose ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(IconButton, { icon: "x", label: "Close", onClick: onClose }) : null
11419
11613
  ] })
11420
11614
  ] }),
11421
- downloadError ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("div", { className: "fd-fv-download-error", role: "alert", children: downloadError }) : null,
11422
- hasSide ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
11615
+ downloadError ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "fd-fv-download-error", role: "alert", children: downloadError }) : null,
11616
+ hasSide ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
11423
11617
  Tabs,
11424
11618
  {
11425
11619
  className: "fd-fv-tabs",
@@ -11428,19 +11622,19 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
11428
11622
  onChange: (v) => setTab(v)
11429
11623
  }
11430
11624
  ) : null,
11431
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("div", { className: "fd-fv-body", children: [
11432
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("div", { className: "fd-fv-preview", role: "region", "aria-label": "Preview of " + (file.name || "file"), children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
11625
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-fv-body", children: [
11626
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "fd-fv-preview", role: "region", "aria-label": "Preview of " + (file.name || "file"), children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
11433
11627
  LoadingRegion,
11434
11628
  {
11435
11629
  state: preview.status === "loading" ? "loading" : preview.status === "error" ? "error" : "ready",
11436
11630
  error: preview.error,
11437
11631
  label: "Loading preview of " + (file.name || "file"),
11438
11632
  onRetry: preview.status === "error" ? preview.retry : void 0,
11439
- skeleton: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(Skeleton, { shape: "card", h: 220 }),
11440
- children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(PreviewBody, { file, kind, state: preview })
11633
+ skeleton: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Skeleton, { shape: "card", h: 220 }),
11634
+ children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(PreviewBody, { file, kind, state: preview })
11441
11635
  }
11442
11636
  ) }),
11443
- hasSide ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("div", { className: "fd-fv-side", role: "region", "aria-label": sidePanelLabel, children: sidePanel }) : null
11637
+ hasSide ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "fd-fv-side", role: "region", "aria-label": sidePanelLabel, children: sidePanel }) : null
11444
11638
  ] })
11445
11639
  ]
11446
11640
  }
@@ -11448,8 +11642,8 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
11448
11642
  }
11449
11643
 
11450
11644
  // src/components/files/FileBrowser.tsx
11451
- var React57 = __toESM(require("react"), 1);
11452
- var import_jsx_runtime86 = require("react/jsx-runtime");
11645
+ var React58 = __toESM(require("react"), 1);
11646
+ var import_jsx_runtime87 = require("react/jsx-runtime");
11453
11647
  function childrenOf(folders, parentId) {
11454
11648
  return folders.filter((f) => f.parentId === parentId).sort((a, b) => a.name.localeCompare(b.name));
11455
11649
  }
@@ -11519,10 +11713,10 @@ function FolderPickerMenu({
11519
11713
  destinations,
11520
11714
  onPick
11521
11715
  }) {
11522
- const [open, setOpen] = React57.useState(false);
11716
+ const [open, setOpen] = React58.useState(false);
11523
11717
  const zIndex = useOverlayLayer(open);
11524
- const ref = React57.useRef(null);
11525
- React57.useEffect(() => {
11718
+ const ref = React58.useRef(null);
11719
+ React58.useEffect(() => {
11526
11720
  if (!open) return;
11527
11721
  const away = (e) => {
11528
11722
  if (ref.current && !ref.current.contains(e.target)) setOpen(false);
@@ -11537,8 +11731,8 @@ function FolderPickerMenu({
11537
11731
  document.removeEventListener("keydown", esc);
11538
11732
  };
11539
11733
  }, [open]);
11540
- return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-fb-menu-anchor", ref, children: [
11541
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
11734
+ return /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("span", { className: "fd-fb-menu-anchor", ref, children: [
11735
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
11542
11736
  IconButton,
11543
11737
  {
11544
11738
  icon: "arrows-out-cardinal",
@@ -11550,9 +11744,9 @@ function FolderPickerMenu({
11550
11744
  onClick: () => setOpen((v) => !v)
11551
11745
  }
11552
11746
  ),
11553
- open ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(LayerProvider, { zIndex, children: /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-fb-menu", role: "menu", "aria-label": label, style: { zIndex }, children: [
11554
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-overline fd-muted fd-fb-menu-title", children: "Move to\u2026" }),
11555
- destinations.map((d) => /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
11747
+ open ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(LayerProvider, { zIndex, children: /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-fb-menu", role: "menu", "aria-label": label, style: { zIndex }, children: [
11748
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-overline fd-muted fd-fb-menu-title", children: "Move to\u2026" }),
11749
+ destinations.map((d) => /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(
11556
11750
  "button",
11557
11751
  {
11558
11752
  type: "button",
@@ -11564,7 +11758,7 @@ function FolderPickerMenu({
11564
11758
  setOpen(false);
11565
11759
  },
11566
11760
  children: [
11567
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph ph-" + (d.id == null ? "house-simple" : "folder-simple"), "aria-hidden": "true" }),
11761
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("i", { className: "ph ph-" + (d.id == null ? "house-simple" : "folder-simple"), "aria-hidden": "true" }),
11568
11762
  d.name
11569
11763
  ]
11570
11764
  },
@@ -11574,8 +11768,8 @@ function FolderPickerMenu({
11574
11768
  ] });
11575
11769
  }
11576
11770
  function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropPayload, actions, className = "" }) {
11577
- const [over, setOver] = React57.useState(false);
11578
- const dragCounter = React57.useRef(0);
11771
+ const [over, setOver] = React58.useState(false);
11772
+ const dragCounter = React58.useRef(0);
11579
11773
  const dropHandlers = isDropTarget ? {
11580
11774
  onDragEnter: (e) => {
11581
11775
  if (!hasInternalPayload(e)) return;
@@ -11600,8 +11794,8 @@ function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropP
11600
11794
  if (payload && onDropPayload) onDropPayload(payload);
11601
11795
  }
11602
11796
  } : {};
11603
- return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: ["fd-fb-row", over ? "is-drop-target" : "", className].filter(Boolean).join(" "), ...dropHandlers, children: [
11604
- /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
11797
+ return /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: ["fd-fb-row", over ? "is-drop-target" : "", className].filter(Boolean).join(" "), ...dropHandlers, children: [
11798
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(
11605
11799
  "button",
11606
11800
  {
11607
11801
  type: "button",
@@ -11610,26 +11804,26 @@ function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropP
11610
11804
  draggable: !!draggableId,
11611
11805
  onDragStart: draggableId ? (e) => writeDragPayload(e, draggableId) : void 0,
11612
11806
  children: [
11613
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-fb-row-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph ph-" + icon }) }),
11614
- /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-fb-row-text", children: [
11615
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-fb-row-name", title: name, children: name }),
11616
- meta ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-fb-row-meta", children: meta }) : null
11807
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-fb-row-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("i", { className: "ph ph-" + icon }) }),
11808
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("span", { className: "fd-fb-row-text", children: [
11809
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-fb-row-name", title: name, children: name }),
11810
+ meta ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-fb-row-meta", children: meta }) : null
11617
11811
  ] })
11618
11812
  ]
11619
11813
  }
11620
11814
  ),
11621
- actions ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-fb-row-actions", children: actions }) : null
11815
+ actions ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-fb-row-actions", children: actions }) : null
11622
11816
  ] });
11623
11817
  }
11624
11818
  function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveInto, canMove }) {
11625
11819
  const kids = childrenOf(folders, folder.id);
11626
- const [expanded, setExpanded] = React57.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
11627
- React57.useEffect(() => {
11820
+ const [expanded, setExpanded] = React58.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
11821
+ React58.useEffect(() => {
11628
11822
  if (currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId)) setExpanded(true);
11629
11823
  }, [currentFolderId, folder.id, folders]);
11630
11824
  const isCurrent = folder.id === currentFolderId;
11631
- return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-fb-tree-node", children: [
11632
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
11825
+ return /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-fb-tree-node", children: [
11826
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
11633
11827
  RowShell,
11634
11828
  {
11635
11829
  icon: folder.id === currentFolderId ? "folder-open" : "folder-simple",
@@ -11639,7 +11833,7 @@ function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveI
11639
11833
  isDropTarget: canMove,
11640
11834
  onDropPayload: (payload) => onMoveInto(payload, folder.id),
11641
11835
  className: ["fd-fb-tree-row", isCurrent ? "is-current" : ""].filter(Boolean).join(" "),
11642
- actions: kids.length ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
11836
+ actions: kids.length ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
11643
11837
  IconButton,
11644
11838
  {
11645
11839
  icon: expanded ? "caret-down" : "caret-right",
@@ -11651,7 +11845,7 @@ function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveI
11651
11845
  ) : void 0
11652
11846
  }
11653
11847
  ),
11654
- expanded && kids.length ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "fd-fb-tree-children", style: { paddingLeft: 14 }, children: kids.map((k) => /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
11848
+ expanded && kids.length ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("div", { className: "fd-fb-tree-children", style: { paddingLeft: 14 }, children: kids.map((k) => /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
11655
11849
  TreeNode,
11656
11850
  {
11657
11851
  folder: k,
@@ -11690,15 +11884,15 @@ function FileBrowser({
11690
11884
  const canUpload = perm.canUpload !== false && !!onUpload;
11691
11885
  const canRemoveFile = perm.canRemoveFile !== false && !!onRemoveFile;
11692
11886
  const canDeleteFolder = perm.canDeleteFolder !== false && !!onDeleteFolder;
11693
- const [createOpen, setCreateOpen] = React57.useState(false);
11694
- const [createName, setCreateName] = React57.useState("");
11695
- const [renameTarget, setRenameTarget] = React57.useState(null);
11696
- const [renameValue, setRenameValue] = React57.useState("");
11697
- const [deleteTarget, setDeleteTarget] = React57.useState(null);
11698
- const uploadInputRef = React57.useRef(null);
11699
- const crumbFolders = React57.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
11700
- const subfolders = React57.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
11701
- const currentFiles = React57.useMemo(
11887
+ const [createOpen, setCreateOpen] = React58.useState(false);
11888
+ const [createName, setCreateName] = React58.useState("");
11889
+ const [renameTarget, setRenameTarget] = React58.useState(null);
11890
+ const [renameValue, setRenameValue] = React58.useState("");
11891
+ const [deleteTarget, setDeleteTarget] = React58.useState(null);
11892
+ const uploadInputRef = React58.useRef(null);
11893
+ const crumbFolders = React58.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
11894
+ const subfolders = React58.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
11895
+ const currentFiles = React58.useMemo(
11702
11896
  () => files.filter((f) => f.folderId === currentFolderId).sort((a, b) => a.name.localeCompare(b.name)),
11703
11897
  [files, currentFolderId]
11704
11898
  );
@@ -11737,10 +11931,10 @@ function FileBrowser({
11737
11931
  if (deleteTarget && onDeleteFolder) onDeleteFolder(deleteTarget);
11738
11932
  setDeleteTarget(null);
11739
11933
  };
11740
- const content = /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: ["fd-fb", className].filter(Boolean).join(" "), children: [
11741
- /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-fb-head", children: [
11742
- /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("nav", { className: "fd-fb-crumbs", "aria-label": "Folder path", children: [
11743
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
11934
+ const content = /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: ["fd-fb", className].filter(Boolean).join(" "), children: [
11935
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-fb-head", children: [
11936
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("nav", { className: "fd-fb-crumbs", "aria-label": "Folder path", children: [
11937
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
11744
11938
  BreadcrumbCrumb,
11745
11939
  {
11746
11940
  label: "Home",
@@ -11750,7 +11944,7 @@ function FileBrowser({
11750
11944
  onDropPayload: (p) => moveIntoFolder(p, null)
11751
11945
  }
11752
11946
  ),
11753
- crumbFolders.map((f, i) => /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
11947
+ crumbFolders.map((f, i) => /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
11754
11948
  BreadcrumbCrumb,
11755
11949
  {
11756
11950
  label: f.name,
@@ -11762,11 +11956,11 @@ function FileBrowser({
11762
11956
  f.id
11763
11957
  ))
11764
11958
  ] }),
11765
- /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-fb-actions", children: [
11766
- canCreateFolder ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Button, { variant: "secondary", size: "sm", icon: "folder-simple-plus", onClick: openCreate, children: "New folder" }) : null,
11767
- canUpload ? /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(import_jsx_runtime86.Fragment, { children: [
11768
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Button, { variant: "secondary", size: "sm", icon: "upload-simple", onClick: () => uploadInputRef.current && uploadInputRef.current.click(), children: "Upload" }),
11769
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
11959
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("span", { className: "fd-fb-actions", children: [
11960
+ canCreateFolder ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Button, { variant: "secondary", size: "sm", icon: "folder-simple-plus", onClick: openCreate, children: "New folder" }) : null,
11961
+ canUpload ? /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(import_jsx_runtime87.Fragment, { children: [
11962
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Button, { variant: "secondary", size: "sm", icon: "upload-simple", onClick: () => uploadInputRef.current && uploadInputRef.current.click(), children: "Upload" }),
11963
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
11770
11964
  "input",
11771
11965
  {
11772
11966
  ref: uploadInputRef,
@@ -11784,9 +11978,9 @@ function FileBrowser({
11784
11978
  ] }) : null
11785
11979
  ] })
11786
11980
  ] }),
11787
- /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-fb-body", children: [
11788
- /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-fb-tree", role: "region", "aria-label": "Folder tree", children: [
11789
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
11981
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-fb-body", children: [
11982
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-fb-tree", role: "region", "aria-label": "Folder tree", children: [
11983
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
11790
11984
  RowShell,
11791
11985
  {
11792
11986
  icon: "house-simple",
@@ -11797,7 +11991,7 @@ function FileBrowser({
11797
11991
  className: ["fd-fb-tree-row", currentFolderId == null ? "is-current" : ""].filter(Boolean).join(" ")
11798
11992
  }
11799
11993
  ),
11800
- childrenOf(folders, null).map((f) => /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
11994
+ childrenOf(folders, null).map((f) => /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
11801
11995
  TreeNode,
11802
11996
  {
11803
11997
  folder: f,
@@ -11811,18 +12005,18 @@ function FileBrowser({
11811
12005
  f.id
11812
12006
  ))
11813
12007
  ] }),
11814
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "fd-fb-main", role: "region", "aria-label": "Folder contents", children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
12008
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("div", { className: "fd-fb-main", role: "region", "aria-label": "Folder contents", children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
11815
12009
  LoadingRegion,
11816
12010
  {
11817
12011
  state: loading ? "loading" : "ready",
11818
12012
  label: "Loading folder contents",
11819
- skeleton: /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-stack", style: { gap: 8, padding: 12 }, children: [
11820
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Skeleton, { h: 44, radius: "10px" }),
11821
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Skeleton, { h: 44, radius: "10px" }),
11822
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Skeleton, { h: 44, radius: "10px" })
12013
+ skeleton: /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-stack", style: { gap: 8, padding: 12 }, children: [
12014
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Skeleton, { h: 44, radius: "10px" }),
12015
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Skeleton, { h: 44, radius: "10px" }),
12016
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Skeleton, { h: 44, radius: "10px" })
11823
12017
  ] }),
11824
- children: isEmpty ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(EmptyState, { icon: "folder-open", title: "This folder is empty", children: canUpload ? "Drop files here, or use Upload above." : "Nothing has been filed here yet." }) : /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-fb-list", children: [
11825
- subfolders.map((f) => /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
12018
+ children: isEmpty ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(EmptyState, { icon: "folder-open", title: "This folder is empty", children: canUpload ? "Drop files here, or use Upload above." : "Nothing has been filed here yet." }) : /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-fb-list", children: [
12019
+ subfolders.map((f) => /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
11826
12020
  RowShell,
11827
12021
  {
11828
12022
  icon: "folder-simple",
@@ -11831,9 +12025,9 @@ function FileBrowser({
11831
12025
  draggableId: canMove ? { kind: "folder", id: f.id } : void 0,
11832
12026
  isDropTarget: canMove,
11833
12027
  onDropPayload: (p) => moveIntoFolder(p, f.id),
11834
- actions: /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(import_jsx_runtime86.Fragment, { children: [
11835
- canRenameFolder ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(IconButton, { icon: "pencil-simple", label: "Rename " + f.name, size: "sm", variant: "ghost", onClick: () => openRename(f) }) : null,
11836
- canMove ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
12028
+ actions: /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(import_jsx_runtime87.Fragment, { children: [
12029
+ canRenameFolder ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(IconButton, { icon: "pencil-simple", label: "Rename " + f.name, size: "sm", variant: "ghost", onClick: () => openRename(f) }) : null,
12030
+ canMove ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
11837
12031
  FolderPickerMenu,
11838
12032
  {
11839
12033
  label: "Move " + f.name,
@@ -11841,12 +12035,12 @@ function FileBrowser({
11841
12035
  onPick: (target) => moveIntoFolder({ kind: "folder", id: f.id }, target)
11842
12036
  }
11843
12037
  ) : null,
11844
- canDeleteFolder ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(IconButton, { icon: "trash-simple", label: "Delete " + f.name, size: "sm", variant: "ghost", onClick: () => openDelete(f) }) : null
12038
+ canDeleteFolder ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(IconButton, { icon: "trash-simple", label: "Delete " + f.name, size: "sm", variant: "ghost", onClick: () => openDelete(f) }) : null
11845
12039
  ] })
11846
12040
  },
11847
12041
  f.id
11848
12042
  )),
11849
- currentFiles.map((file) => /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
12043
+ currentFiles.map((file) => /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
11850
12044
  RowShell,
11851
12045
  {
11852
12046
  icon: iconForMime(file.mime, file.name),
@@ -11854,8 +12048,8 @@ function FileBrowser({
11854
12048
  meta: file.size ? formatBytes(file.size) : void 0,
11855
12049
  onOpen: onOpenFile ? () => onOpenFile(file) : void 0,
11856
12050
  draggableId: canMove ? { kind: "file", id: file.id } : void 0,
11857
- actions: /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(import_jsx_runtime86.Fragment, { children: [
11858
- canMove ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
12051
+ actions: /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(import_jsx_runtime87.Fragment, { children: [
12052
+ canMove ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
11859
12053
  FolderPickerMenu,
11860
12054
  {
11861
12055
  label: "Move " + file.name,
@@ -11863,7 +12057,7 @@ function FileBrowser({
11863
12057
  onPick: (target) => onMoveFile && onMoveFile(file.id, target)
11864
12058
  }
11865
12059
  ) : null,
11866
- canRemoveFile ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(IconButton, { icon: "trash-simple", label: "Remove " + file.name, size: "sm", variant: "ghost", onClick: () => onRemoveFile && onRemoveFile(file) }) : null
12060
+ canRemoveFile ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(IconButton, { icon: "trash-simple", label: "Remove " + file.name, size: "sm", variant: "ghost", onClick: () => onRemoveFile && onRemoveFile(file) }) : null
11867
12061
  ] })
11868
12062
  },
11869
12063
  file.id
@@ -11872,10 +12066,10 @@ function FileBrowser({
11872
12066
  }
11873
12067
  ) })
11874
12068
  ] }),
11875
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Modal, { open: createOpen, title: "New folder", onClose: () => setCreateOpen(false), footer: /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(import_jsx_runtime86.Fragment, { children: [
11876
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Button, { variant: "secondary", onClick: () => setCreateOpen(false), children: "Cancel" }),
11877
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Button, { onClick: submitCreate, disabled: !createName.trim(), children: "Create" })
11878
- ] }), children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
12069
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Modal, { open: createOpen, title: "New folder", onClose: () => setCreateOpen(false), footer: /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(import_jsx_runtime87.Fragment, { children: [
12070
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Button, { variant: "secondary", onClick: () => setCreateOpen(false), children: "Cancel" }),
12071
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Button, { onClick: submitCreate, disabled: !createName.trim(), children: "Create" })
12072
+ ] }), children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
11879
12073
  "input",
11880
12074
  {
11881
12075
  className: "fd-fb-input",
@@ -11889,10 +12083,10 @@ function FileBrowser({
11889
12083
  autoFocus: true
11890
12084
  }
11891
12085
  ) }),
11892
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Modal, { open: renameTarget != null, title: "Rename folder", onClose: () => setRenameTarget(null), footer: /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(import_jsx_runtime86.Fragment, { children: [
11893
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Button, { variant: "secondary", onClick: () => setRenameTarget(null), children: "Cancel" }),
11894
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Button, { onClick: submitRename, disabled: !renameValue.trim(), children: "Save" })
11895
- ] }), children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
12086
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Modal, { open: renameTarget != null, title: "Rename folder", onClose: () => setRenameTarget(null), footer: /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(import_jsx_runtime87.Fragment, { children: [
12087
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Button, { variant: "secondary", onClick: () => setRenameTarget(null), children: "Cancel" }),
12088
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Button, { onClick: submitRename, disabled: !renameValue.trim(), children: "Save" })
12089
+ ] }), children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
11896
12090
  "input",
11897
12091
  {
11898
12092
  className: "fd-fb-input",
@@ -11906,22 +12100,22 @@ function FileBrowser({
11906
12100
  autoFocus: true
11907
12101
  }
11908
12102
  ) }),
11909
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
12103
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
11910
12104
  Modal,
11911
12105
  {
11912
12106
  open: deleteTarget != null,
11913
12107
  title: deleteTarget ? "Delete \u201C" + deleteTarget.name + "\u201D?" : "Delete folder?",
11914
12108
  description: "This can't be undone. The folder must be empty.",
11915
12109
  onClose: () => setDeleteTarget(null),
11916
- footer: /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(import_jsx_runtime86.Fragment, { children: [
11917
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Button, { variant: "secondary", onClick: () => setDeleteTarget(null), children: "Cancel" }),
11918
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Button, { variant: "danger", onClick: confirmDelete, children: "Delete" })
12110
+ footer: /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(import_jsx_runtime87.Fragment, { children: [
12111
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Button, { variant: "secondary", onClick: () => setDeleteTarget(null), children: "Cancel" }),
12112
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Button, { variant: "danger", onClick: confirmDelete, children: "Delete" })
11919
12113
  ] })
11920
12114
  }
11921
12115
  )
11922
12116
  ] });
11923
12117
  if (!canUpload) return content;
11924
- return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Dropzone, { className: "fd-fb-dropzone", onFiles: (picked) => onUpload && onUpload(picked, currentFolderId), label: "Drop files to upload", children: content });
12118
+ return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Dropzone, { className: "fd-fb-dropzone", onFiles: (picked) => onUpload && onUpload(picked, currentFolderId), label: "Drop files to upload", children: content });
11925
12119
  }
11926
12120
  function BreadcrumbCrumb({
11927
12121
  label,
@@ -11930,8 +12124,8 @@ function BreadcrumbCrumb({
11930
12124
  isDropTarget,
11931
12125
  onDropPayload
11932
12126
  }) {
11933
- const [over, setOver] = React57.useState(false);
11934
- const dragCounter = React57.useRef(0);
12127
+ const [over, setOver] = React58.useState(false);
12128
+ const dragCounter = React58.useRef(0);
11935
12129
  const dropHandlers = isDropTarget ? {
11936
12130
  onDragEnter: (e) => {
11937
12131
  if (!hasInternalPayload(e)) return;
@@ -11956,11 +12150,11 @@ function BreadcrumbCrumb({
11956
12150
  if (payload && onDropPayload) onDropPayload(payload);
11957
12151
  }
11958
12152
  } : {};
11959
- return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: ["fd-fb-crumb", over ? "is-drop-target" : ""].filter(Boolean).join(" "), ...dropHandlers, children: isCurrent ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-fb-crumb-current", "aria-current": "page", children: label }) : /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("button", { type: "button", className: "fd-fb-crumb-link", onClick, children: label }) });
12153
+ return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: ["fd-fb-crumb", over ? "is-drop-target" : ""].filter(Boolean).join(" "), ...dropHandlers, children: isCurrent ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-fb-crumb-current", "aria-current": "page", children: label }) : /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("button", { type: "button", className: "fd-fb-crumb-link", onClick, children: label }) });
11960
12154
  }
11961
12155
 
11962
12156
  // src/kits/query.ts
11963
- var React58 = __toESM(require("react"), 1);
12157
+ var React59 = __toESM(require("react"), 1);
11964
12158
  function eqFilter(get2) {
11965
12159
  return (row, value) => Array.isArray(value) ? value.includes(get2(row)) : get2(row) === value;
11966
12160
  }
@@ -11992,22 +12186,22 @@ function compare(a, b, dir) {
11992
12186
  var API = null;
11993
12187
  var PREFS = null;
11994
12188
  function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
11995
- const [query, setQuery] = React58.useState(() => {
12189
+ const [query, setQuery] = React59.useState(() => {
11996
12190
  const store = PREFS || window.PlannerPrefs;
11997
12191
  const saved = prefsKey && store ? store.getTable(prefsKey) : {};
11998
12192
  return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
11999
12193
  });
12000
- const savePref = React58.useCallback((patch2) => {
12194
+ const savePref = React59.useCallback((patch2) => {
12001
12195
  const store = PREFS || window.PlannerPrefs;
12002
12196
  if (prefsKey && store) store.setTable(prefsKey, patch2);
12003
12197
  }, [prefsKey]);
12004
- const [res, setRes] = React58.useState(null);
12005
- const [loading, setLoading] = React58.useState(true);
12006
- const seq2 = React58.useRef(0);
12198
+ const [res, setRes] = React59.useState(null);
12199
+ const [loading, setLoading] = React59.useState(true);
12200
+ const seq2 = React59.useRef(0);
12007
12201
  const depKey = (deps || []).join("|");
12008
12202
  const paramKey = JSON.stringify(params || {});
12009
12203
  const queryKey = JSON.stringify(query);
12010
- React58.useEffect(() => {
12204
+ React59.useEffect(() => {
12011
12205
  const id = ++seq2.current;
12012
12206
  setLoading(true);
12013
12207
  const t = setTimeout(() => {
@@ -12306,12 +12500,12 @@ function createVersionStore(initialState, options) {
12306
12500
  }
12307
12501
 
12308
12502
  // src/kits/documentTitle.ts
12309
- var React59 = __toESM(require("react"), 1);
12503
+ var React60 = __toESM(require("react"), 1);
12310
12504
  function formatDocumentTitle(routeTitle, appName) {
12311
12505
  return [routeTitle, appName, "Flytedesk"].filter((part) => !!part && part.length > 0).join(" \xB7 ");
12312
12506
  }
12313
12507
  function useDocumentTitle(routeTitle, appName) {
12314
- React59.useEffect(() => {
12508
+ React60.useEffect(() => {
12315
12509
  if (typeof document === "undefined") return;
12316
12510
  document.title = formatDocumentTitle(routeTitle, appName);
12317
12511
  }, [routeTitle, appName]);
@@ -12434,6 +12628,7 @@ function useDocumentTitle(routeTitle, appName) {
12434
12628
  SessionKit,
12435
12629
  SessionProvider,
12436
12630
  SidebarNav,
12631
+ SignInPage,
12437
12632
  Skeleton,
12438
12633
  SkeletonText,
12439
12634
  Slider,