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