@odla-ai/chapter 0.48.2 → 0.49.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.
@@ -4,10 +4,10 @@ import {
4
4
  DEFAULT_CHAPTER_COPY,
5
5
  formatChapterCopy,
6
6
  useChapterCopy
7
- } from "./chunk-4HS2JPE2.js";
7
+ } from "./chunk-N2JIKINY.js";
8
8
 
9
9
  // src/ui/admin.tsx
10
- import { useEffect as useEffect12, useMemo as useMemo3, useRef as useRef3, useState as useState22 } from "preact/hooks";
10
+ import { useEffect as useEffect12, useMemo as useMemo3, useRef as useRef3, useState as useState24 } from "preact/hooks";
11
11
  import { ClerkGate, SignedIn, SignedOut, SignIn, useClerkAuth } from "@odla-ai/auth-clerk";
12
12
  import { CrmClient } from "@odla-ai/crm";
13
13
 
@@ -458,7 +458,12 @@ function AdminShell({
458
458
  import { Tabs as Tabs3 } from "@odla-ai/ui/components";
459
459
 
460
460
  // src/ui/admin-billing.tsx
461
- import { DataTable, StatBand } from "@odla-ai/ui/components";
461
+ import { useState as useState5 } from "preact/hooks";
462
+ import { Button as Button2 } from "@odla-ai/ui/components";
463
+
464
+ // src/ui/payment-recovery-queue.tsx
465
+ import { useState as useState4 } from "preact/hooks";
466
+ import { Button } from "@odla-ai/ui/components";
462
467
 
463
468
  // src/ui/admin-api.ts
464
469
  import { useCallback as useCallback2, useEffect as useEffect3, useState as useState3 } from "preact/hooks";
@@ -496,36 +501,103 @@ function useAdminResource(getToken, path) {
496
501
  return { data, loading, error, refresh };
497
502
  }
498
503
 
499
- // src/ui/admin-billing.tsx
504
+ // src/ui/payment-recovery-queue.tsx
500
505
  import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "preact/jsx-runtime";
506
+ function PaymentRecoveryQueue(props) {
507
+ const network = props.scope === "network";
508
+ const path = network ? "/api/admin/network-commercial-read-model" : "/api/admin/payment-recovery";
509
+ const { data, loading, error, refresh } = useAdminResource(props.getToken, path);
510
+ const [busy, setBusy] = useState4("");
511
+ const [message, setMessage] = useState4("");
512
+ const recover = async (eventId) => {
513
+ setBusy(eventId);
514
+ setMessage("");
515
+ try {
516
+ const result = await adminFetch(props.getToken, path, {
517
+ method: "POST",
518
+ body: JSON.stringify({ eventId, ...network ? { command: "recover-event" } : {} })
519
+ });
520
+ setMessage(result.disposition?.startsWith("quarantine_") || result.matched === false ? "This event still needs its application or payment linkage repaired. Its evidence is saved for another retry." : "Stripe evidence verified and reconciliation retried.");
521
+ refresh();
522
+ } catch (cause) {
523
+ setMessage(cause instanceof Error ? cause.message : "Recovery could not finish. Please retry.");
524
+ } finally {
525
+ setBusy("");
526
+ }
527
+ };
528
+ const rows = network ? data?.exceptions ?? [] : data?.rows ?? [];
529
+ return /* @__PURE__ */ jsxs4(Panel, { title: "Payment events needing attention", children: [
530
+ loading ? /* @__PURE__ */ jsx4("p", { children: "Checking payment reconciliation\u2026" }) : error ? /* @__PURE__ */ jsxs4("p", { role: "alert", children: [
531
+ "Payment recovery is unavailable: ",
532
+ error
533
+ ] }) : /* @__PURE__ */ jsxs4(Fragment2, { children: [
534
+ rows.length ? /* @__PURE__ */ jsxs4("p", { role: "alert", children: [
535
+ rows.length,
536
+ " payment event",
537
+ rows.length === 1 ? " needs" : "s need",
538
+ " review."
539
+ ] }) : /* @__PURE__ */ jsx4("p", { children: "All loaded payment events are reconciled." }),
540
+ data?.truncated ? /* @__PURE__ */ jsx4("p", { role: "alert", children: "This queue is incomplete. Review the remaining events before declaring reconciliation complete." }) : null,
541
+ /* @__PURE__ */ jsx4("ul", { children: rows.map((row) => /* @__PURE__ */ jsxs4("li", { children: [
542
+ row.eventId ? /* @__PURE__ */ jsx4("code", { children: row.eventId }) : null,
543
+ " ",
544
+ /* @__PURE__ */ jsx4("span", { children: row.disposition ?? row.kind }),
545
+ " ",
546
+ row.eventId?.startsWith("evt_") ? /* @__PURE__ */ jsx4(Button, { mini: true, disabled: Boolean(busy), onClick: () => void recover(row.eventId), children: busy === row.eventId ? "Verifying\u2026" : "Verify with Stripe and retry" }) : /* @__PURE__ */ jsx4("span", { children: "Repair the missing payment linkage before retrying." })
547
+ ] }, `${row.eventId}:${row.kind}`)) })
548
+ ] }),
549
+ message ? /* @__PURE__ */ jsx4("p", { role: "status", children: message }) : null
550
+ ] });
551
+ }
552
+
553
+ // src/ui/admin-billing.tsx
554
+ import { DataTable, StatBand } from "@odla-ai/ui/components";
555
+ import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs5 } from "preact/jsx-runtime";
501
556
  var money = (cents) => cents === null ? "Unknown" : `$${(cents / 100).toLocaleString()}`;
502
557
  var date = (t) => t ? new Date(t).toLocaleDateString([], { dateStyle: "medium" }) : "\u2014";
503
- var columns = (copy) => [
558
+ var columns = (copy, cancel, busy) => [
504
559
  { key: "name", header: copy.name, cell: (r) => r.name, sortAs: "string" },
505
560
  { key: "email", header: copy.email, cell: (r) => r.email },
506
561
  { key: "applicationStatus", header: copy.application, cell: (r) => r.applicationStatus },
507
562
  { key: "subscriptionStatus", header: copy.subscription, cell: (r) => r.subscriptionStatus ? `${r.subscriptionStatus}${r.cancelAtPeriodEnd ? ` \xB7 ${copy.cancelling}` : ""}` : "\u2014" },
508
- { key: "amountCents", header: "Next-term forecast", cell: (r) => r.amountCents === null ? "Unknown" : /* @__PURE__ */ jsxs4("span", { children: [
509
- r.listAmountCents != null && r.listAmountCents !== r.amountCents ? /* @__PURE__ */ jsxs4(Fragment2, { children: [
510
- /* @__PURE__ */ jsx4("s", { children: money(r.listAmountCents) }),
563
+ { key: "amountCents", header: "Next-term forecast", cell: (r) => r.amountCents === null ? "Unknown" : /* @__PURE__ */ jsxs5("span", { children: [
564
+ r.listAmountCents != null && r.listAmountCents !== r.amountCents ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
565
+ /* @__PURE__ */ jsx5("s", { children: money(r.listAmountCents) }),
511
566
  " "
512
567
  ] }) : null,
513
568
  money(r.amountCents),
514
569
  "/",
515
570
  r.interval === "month" ? "mo" : "yr"
516
571
  ] }), sortAs: "number", sortValue: (r) => r.amountCents ?? -1 },
572
+ { key: "cancelRenewal", header: "Renewal", cell: (row) => row.subscriptionStatus && ["active", "trialing", "past_due", "unpaid"].includes(row.subscriptionStatus) && !row.cancelAtPeriodEnd ? /* @__PURE__ */ jsx5(Button2, { mini: true, disabled: Boolean(busy), onClick: () => cancel(row.id), children: busy === row.id ? "Canceling\u2026" : "Cancel renewal" }) : row.cancelAtPeriodEnd ? "Ends after paid term" : "\u2014" },
517
573
  { key: "renewalAt", header: copy.renews, cell: (r) => date(r.renewalAt), sortAs: "number", sortValue: (r) => r.renewalAt ?? 0 }
518
574
  ];
519
575
  function BillingBody({ ctx }) {
520
576
  const copy = useChapterCopy().admin.billing;
521
- const { data, loading, error } = useAdminResource(ctx.getToken, "/api/admin/billing");
522
- if (loading) return /* @__PURE__ */ jsx4(AdminNote, { children: copy.loading });
523
- if (error || !data) return /* @__PURE__ */ jsxs4(AdminNote, { children: [
577
+ const [busy, setBusy] = useState5("");
578
+ const [note, setNote] = useState5("");
579
+ const { data, loading, error, refresh } = useAdminResource(ctx.getToken, "/api/admin/billing");
580
+ if (loading) return /* @__PURE__ */ jsx5(AdminNote, { children: copy.loading });
581
+ if (error || !data) return /* @__PURE__ */ jsxs5(AdminNote, { children: [
524
582
  copy.loadFailed,
525
583
  error ? `: ${error}` : "",
526
584
  "."
527
585
  ] });
528
- if (!data.billingReady) return /* @__PURE__ */ jsx4(AdminNote, { children: copy.notConfigured });
586
+ if (!data.billingReady) return /* @__PURE__ */ jsx5(AdminNote, { children: copy.notConfigured });
587
+ const cancel = async (id) => {
588
+ if (!globalThis.confirm?.("Cancel future renewals? Paid access continues through the current term. No refund will be issued.")) return;
589
+ setBusy(id);
590
+ setNote("");
591
+ try {
592
+ await adminFetch(ctx.getToken, `/api/admin/applications/${id}/cancel-renewal`, { method: "POST" });
593
+ setNote("Renewal canceled. Access continues through the paid term.");
594
+ refresh();
595
+ } catch (cause) {
596
+ setNote(cause instanceof Error ? cause.message : "Cancellation could not be confirmed. Please retry.");
597
+ } finally {
598
+ setBusy("");
599
+ }
600
+ };
529
601
  const s = data.summary;
530
602
  const stats = s ? [
531
603
  { value: s.activeCount, label: copy.active },
@@ -533,22 +605,24 @@ function BillingBody({ ctx }) {
533
605
  { value: s.renewingSoonCount, label: copy.renewingSoon },
534
606
  { value: s.pastDueCount, label: copy.pastDue }
535
607
  ] : [];
536
- return /* @__PURE__ */ jsxs4(AdminPage, { children: [
537
- s ? /* @__PURE__ */ jsx4(StatBand, { stats }) : null,
538
- /* @__PURE__ */ jsxs4(Panel, { title: copy.subscriptions, actions: data.testMode ? /* @__PURE__ */ jsx4("span", { className: "badge", children: copy.testMode }) : void 0, children: [
539
- data.truncated ? /* @__PURE__ */ jsx4("p", { className: "badge", children: copy.truncated }) : null,
540
- /* @__PURE__ */ jsx4(DataTable, { rows: data.rows, columns: columns(copy), rowKey: (r) => r.id })
608
+ return /* @__PURE__ */ jsxs5(AdminPage, { children: [
609
+ note ? /* @__PURE__ */ jsx5("p", { role: "status", children: note }) : null,
610
+ /* @__PURE__ */ jsx5(PaymentRecoveryQueue, { getToken: ctx.getToken }),
611
+ s ? /* @__PURE__ */ jsx5(StatBand, { stats }) : null,
612
+ /* @__PURE__ */ jsxs5(Panel, { title: copy.subscriptions, actions: data.testMode ? /* @__PURE__ */ jsx5("span", { className: "badge", children: copy.testMode }) : void 0, children: [
613
+ data.truncated ? /* @__PURE__ */ jsx5("p", { className: "badge", children: copy.truncated }) : null,
614
+ /* @__PURE__ */ jsx5(DataTable, { rows: data.rows, columns: columns(copy, (id) => void cancel(id), busy), rowKey: (r) => r.id })
541
615
  ] })
542
616
  ] });
543
617
  }
544
618
  function billingSection(options = {}) {
545
619
  const { id = "billing", label = "Billing" } = options;
546
- return { id, label, render: (ctx) => /* @__PURE__ */ jsx4(BillingBody, { ctx }) };
620
+ return { id, label, render: (ctx) => /* @__PURE__ */ jsx5(BillingBody, { ctx }) };
547
621
  }
548
622
 
549
623
  // src/ui/admin-dashboard.tsx
550
624
  import { MetricWidget, StepPipeline } from "@odla-ai/ui/components";
551
- import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs5 } from "preact/jsx-runtime";
625
+ import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs6 } from "preact/jsx-runtime";
552
626
  var number = (value) => Math.round(value).toLocaleString();
553
627
  var money2 = (cents) => `$${Math.round(cents / 100).toLocaleString()}`;
554
628
  var when = (time) => new Date(time).toLocaleString([], { dateStyle: "medium", timeStyle: "short" });
@@ -558,50 +632,50 @@ function DashboardBody({ ctx }) {
558
632
  ctx.getToken,
559
633
  "/api/admin/dashboard"
560
634
  );
561
- if (loading) return /* @__PURE__ */ jsx5(AdminNote, { children: copy.loading });
562
- if (error || !data) return /* @__PURE__ */ jsxs5(AdminNote, { children: [
635
+ if (loading) return /* @__PURE__ */ jsx6(AdminNote, { children: copy.loading });
636
+ if (error || !data) return /* @__PURE__ */ jsxs6(AdminNote, { children: [
563
637
  copy.loadFailed,
564
638
  error ? `: ${error}` : "",
565
639
  "."
566
640
  ] });
567
641
  const pipelineSteps = Object.entries(data.pipeline).filter(([stage]) => !["declined", "refunded"].includes(stage)).map(([stage, count]) => ({
568
- icon: /* @__PURE__ */ jsx5("span", { style: { fontSize: 22, fontWeight: 700 }, children: count }),
642
+ icon: /* @__PURE__ */ jsx6("span", { style: { fontSize: 22, fontWeight: 700 }, children: count }),
569
643
  title: stage.replaceAll("_", " "),
570
644
  description: data.pipelineDelta[stage] ? formatChapterCopy(copy.thisWeek, { count: data.pipelineDelta[stage] }) : copy.noChange
571
645
  }));
572
646
  const exceptions = ["declined", "refunded"].filter((stage) => stage in data.pipeline).map((stage) => `${stage} ${data.pipeline[stage]}`).join(" \xB7 ");
573
- return /* @__PURE__ */ jsxs5(AdminPage, { children: [
574
- data.incomplete ? /* @__PURE__ */ jsx5(AdminNote, { children: "This dashboard snapshot is incomplete. Counts and trends below cover only the loaded records, not the full chapter." }) : null,
575
- /* @__PURE__ */ jsx5(
647
+ return /* @__PURE__ */ jsxs6(AdminPage, { children: [
648
+ data.incomplete ? /* @__PURE__ */ jsx6(AdminNote, { children: "This dashboard snapshot is incomplete. Counts and trends below cover only the loaded records, not the full chapter." }) : null,
649
+ /* @__PURE__ */ jsx6(
576
650
  Panel,
577
651
  {
578
- title: /* @__PURE__ */ jsxs5(Fragment3, { children: [
652
+ title: /* @__PURE__ */ jsxs6(Fragment4, { children: [
579
653
  copy.upcomingCalls,
580
654
  " ",
581
- /* @__PURE__ */ jsxs5("span", { className: "muted", style: { fontWeight: 400 }, children: [
655
+ /* @__PURE__ */ jsxs6("span", { className: "muted", style: { fontWeight: 400 }, children: [
582
656
  "\xB7 ",
583
657
  data.timezone
584
658
  ] })
585
659
  ] }),
586
- actions: data.calls.needsAttention ? /* @__PURE__ */ jsx5("span", { className: "badge", children: formatChapterCopy(copy.callsNeedAttention, { count: data.calls.needsAttention }) }) : void 0,
587
- children: data.agenda.length === 0 ? /* @__PURE__ */ jsx5("p", { className: "muted", style: { margin: 0 }, children: copy.noUpcomingCalls }) : /* @__PURE__ */ jsx5("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "grid", gap: 10 }, children: data.agenda.map((meeting) => /* @__PURE__ */ jsxs5("li", { style: { display: "flex", alignItems: "center", gap: 12, flexWrap: "wrap" }, children: [
588
- /* @__PURE__ */ jsx5("strong", { style: { minWidth: 170 }, children: when(meeting.startAt) }),
589
- /* @__PURE__ */ jsxs5("span", { style: { flex: 1 }, children: [
660
+ actions: data.calls.needsAttention ? /* @__PURE__ */ jsx6("span", { className: "badge", children: formatChapterCopy(copy.callsNeedAttention, { count: data.calls.needsAttention }) }) : void 0,
661
+ children: data.agenda.length === 0 ? /* @__PURE__ */ jsx6("p", { className: "muted", style: { margin: 0 }, children: copy.noUpcomingCalls }) : /* @__PURE__ */ jsx6("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "grid", gap: 10 }, children: data.agenda.map((meeting) => /* @__PURE__ */ jsxs6("li", { style: { display: "flex", alignItems: "center", gap: 12, flexWrap: "wrap" }, children: [
662
+ /* @__PURE__ */ jsx6("strong", { style: { minWidth: 170 }, children: when(meeting.startAt) }),
663
+ /* @__PURE__ */ jsxs6("span", { style: { flex: 1 }, children: [
590
664
  meeting.name,
591
665
  meeting.email ? ` \xB7 ${meeting.email}` : ""
592
666
  ] }),
593
- meeting.drift && meeting.drift !== "none" ? /* @__PURE__ */ jsx5("span", { className: "badge", children: copy.drift }) : null,
594
- meeting.htmlLink ? /* @__PURE__ */ jsx5("a", { href: meeting.htmlLink, target: "_blank", rel: "noreferrer", children: copy.open }) : null,
595
- meeting.meetUrl ? /* @__PURE__ */ jsx5("a", { href: meeting.meetUrl, target: "_blank", rel: "noreferrer", children: copy.meet }) : null
667
+ meeting.drift && meeting.drift !== "none" ? /* @__PURE__ */ jsx6("span", { className: "badge", children: copy.drift }) : null,
668
+ meeting.htmlLink ? /* @__PURE__ */ jsx6("a", { href: meeting.htmlLink, target: "_blank", rel: "noreferrer", children: copy.open }) : null,
669
+ meeting.meetUrl ? /* @__PURE__ */ jsx6("a", { href: meeting.meetUrl, target: "_blank", rel: "noreferrer", children: copy.meet }) : null
596
670
  ] }, meeting.id)) })
597
671
  }
598
672
  ),
599
- /* @__PURE__ */ jsxs5("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(280px, 1fr))", gap: 18 }, children: [
600
- /* @__PURE__ */ jsx5(MetricWidget, { label: copy.applications, data: data.applicationsSeries, format: number }),
601
- data.membersSeries ? /* @__PURE__ */ jsx5(MetricWidget, { label: copy.newMembers, data: data.membersSeries, format: number }) : /* @__PURE__ */ jsx5(Panel, { title: copy.newMembers, children: /* @__PURE__ */ jsx5("p", { className: "muted", children: copy.newMembersUnavailable }) })
673
+ /* @__PURE__ */ jsxs6("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(280px, 1fr))", gap: 18 }, children: [
674
+ /* @__PURE__ */ jsx6(MetricWidget, { label: copy.applications, data: data.applicationsSeries, format: number }),
675
+ data.membersSeries ? /* @__PURE__ */ jsx6(MetricWidget, { label: copy.newMembers, data: data.membersSeries, format: number }) : /* @__PURE__ */ jsx6(Panel, { title: copy.newMembers, children: /* @__PURE__ */ jsx6("p", { className: "muted", children: copy.newMembersUnavailable }) })
602
676
  ] }),
603
- data.revenueSeries && data.revenue.billingReady ? /* @__PURE__ */ jsxs5("div", { children: [
604
- /* @__PURE__ */ jsx5(
677
+ data.revenueSeries && data.revenue.billingReady ? /* @__PURE__ */ jsxs6("div", { children: [
678
+ /* @__PURE__ */ jsx6(
605
679
  MetricWidget,
606
680
  {
607
681
  label: copy.revenueAdded,
@@ -610,7 +684,7 @@ function DashboardBody({ ctx }) {
610
684
  size: "large"
611
685
  }
612
686
  ),
613
- /* @__PURE__ */ jsxs5("p", { className: "muted", children: [
687
+ /* @__PURE__ */ jsxs6("p", { className: "muted", children: [
614
688
  copy.activeMemberships,
615
689
  ": ",
616
690
  data.revenue.activeCount ?? 0,
@@ -621,31 +695,31 @@ function DashboardBody({ ctx }) {
621
695
  data.revenue.annualRunRateCents == null ? "Unknown" : money2(data.revenue.annualRunRateCents),
622
696
  data.revenue.testMode ? ` \xB7 ${copy.testMode}` : ""
623
697
  ] })
624
- ] }) : /* @__PURE__ */ jsx5(Panel, { title: copy.revenue, children: /* @__PURE__ */ jsx5("p", { className: "muted", children: copy.revenueUnavailable }) }),
625
- /* @__PURE__ */ jsxs5(Panel, { title: copy.pipeline, children: [
626
- /* @__PURE__ */ jsx5(StepPipeline, { ariaLabel: copy.pipelineLabel, steps: pipelineSteps }),
627
- exceptions ? /* @__PURE__ */ jsx5("p", { className: "muted", style: { margin: 0 }, children: exceptions }) : null
698
+ ] }) : /* @__PURE__ */ jsx6(Panel, { title: copy.revenue, children: /* @__PURE__ */ jsx6("p", { className: "muted", children: copy.revenueUnavailable }) }),
699
+ /* @__PURE__ */ jsxs6(Panel, { title: copy.pipeline, children: [
700
+ /* @__PURE__ */ jsx6(StepPipeline, { ariaLabel: copy.pipelineLabel, steps: pipelineSteps }),
701
+ exceptions ? /* @__PURE__ */ jsx6("p", { className: "muted", style: { margin: 0 }, children: exceptions }) : null
628
702
  ] })
629
703
  ] });
630
704
  }
631
705
  function dashboardSection(options = {}) {
632
706
  const { id = "dashboard", label = "Dashboard" } = options;
633
- return { id, label, render: (ctx) => /* @__PURE__ */ jsx5(DashboardBody, { ctx }) };
707
+ return { id, label, render: (ctx) => /* @__PURE__ */ jsx6(DashboardBody, { ctx }) };
634
708
  }
635
709
 
636
710
  // src/ui/admin-people-workspace.tsx
637
711
  import { BillingCard, CrmWorkspace } from "@odla-ai/crm/ui";
638
712
 
639
713
  // src/ui/admin-application-repair.tsx
640
- import { useState as useState4 } from "preact/hooks";
641
- import { Button } from "@odla-ai/ui/components";
642
- import { jsx as jsx6, jsxs as jsxs6 } from "preact/jsx-runtime";
714
+ import { useState as useState6 } from "preact/hooks";
715
+ import { Button as Button3 } from "@odla-ai/ui/components";
716
+ import { jsx as jsx7, jsxs as jsxs7 } from "preact/jsx-runtime";
643
717
  function ApplicationLinkRepair({ recordId, getToken, onChanged }) {
644
- const [busy, setBusy] = useState4(false);
645
- const [error, setError] = useState4(null);
646
- return /* @__PURE__ */ jsxs6("section", { className: "panel", children: [
647
- /* @__PURE__ */ jsx6("p", { children: "This person is missing an application link. Repair checks for one matching chapter application; it does not change membership or profile details." }),
648
- /* @__PURE__ */ jsx6(Button, { variant: "secondary", disabled: busy, onClick: async () => {
718
+ const [busy, setBusy] = useState6(false);
719
+ const [error, setError] = useState6(null);
720
+ return /* @__PURE__ */ jsxs7("section", { className: "panel", children: [
721
+ /* @__PURE__ */ jsx7("p", { children: "This person is missing an application link. Repair checks for one matching chapter application; it does not change membership or profile details." }),
722
+ /* @__PURE__ */ jsx7(Button3, { variant: "secondary", disabled: busy, onClick: async () => {
649
723
  setBusy(true);
650
724
  setError(null);
651
725
  try {
@@ -657,33 +731,33 @@ function ApplicationLinkRepair({ recordId, getToken, onChanged }) {
657
731
  setBusy(false);
658
732
  }
659
733
  }, children: busy ? "Checking application link\u2026" : "Repair application link" }),
660
- error ? /* @__PURE__ */ jsx6("p", { role: "alert", children: error }) : null
734
+ error ? /* @__PURE__ */ jsx7("p", { role: "alert", children: error }) : null
661
735
  ] });
662
736
  }
663
737
 
664
738
  // src/ui/admin-application-stage.tsx
665
- import { useState as useState5 } from "preact/hooks";
666
- import { Button as Button2, Field, Select } from "@odla-ai/ui/components";
667
- import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs7 } from "preact/jsx-runtime";
739
+ import { useState as useState7 } from "preact/hooks";
740
+ import { Button as Button4, Field, Select } from "@odla-ai/ui/components";
741
+ import { Fragment as Fragment5, jsx as jsx8, jsxs as jsxs8 } from "preact/jsx-runtime";
668
742
  function ApplicationStagePanel(props) {
669
743
  const actions = useAdminResource(
670
744
  props.getToken,
671
745
  `/api/admin/applications/${encodeURIComponent(props.applicationId)}/actions`
672
746
  );
673
- const [selected, setSelected] = useState5("");
674
- const [busy, setBusy] = useState5(false);
675
- const [error, setError] = useState5(null);
676
- if (actions.loading) return /* @__PURE__ */ jsx7("p", { role: "status", children: "Loading available actions\u2026" });
677
- if (actions.error) return /* @__PURE__ */ jsxs7("p", { role: "alert", children: [
747
+ const [selected, setSelected] = useState7("");
748
+ const [busy, setBusy] = useState7(false);
749
+ const [error, setError] = useState7(null);
750
+ if (actions.loading) return /* @__PURE__ */ jsx8("p", { role: "status", children: "Loading available actions\u2026" });
751
+ if (actions.error) return /* @__PURE__ */ jsxs8("p", { role: "alert", children: [
678
752
  "Could not load application actions: ",
679
753
  actions.error
680
754
  ] });
681
755
  const allowed = actions.data?.allowedStages ?? [];
682
756
  const target = allowed.includes(selected) ? selected : "";
683
- return /* @__PURE__ */ jsxs7(Field, { label: "Stage", error, children: [
684
- /* @__PURE__ */ jsx7("p", { children: actions.data?.status?.replaceAll("_", " ") }),
685
- allowed.length ? /* @__PURE__ */ jsxs7(Fragment4, { children: [
686
- /* @__PURE__ */ jsx7(
757
+ return /* @__PURE__ */ jsxs8(Field, { label: "Stage", error, children: [
758
+ /* @__PURE__ */ jsx8("p", { children: actions.data?.status?.replaceAll("_", " ") }),
759
+ allowed.length ? /* @__PURE__ */ jsxs8(Fragment5, { children: [
760
+ /* @__PURE__ */ jsx8(
687
761
  Select,
688
762
  {
689
763
  "aria-label": "Move to stage",
@@ -693,7 +767,7 @@ function ApplicationStagePanel(props) {
693
767
  options: [{ value: "", label: "Move to\u2026" }, ...allowed.map((value) => ({ value, label: value.replaceAll("_", " ") }))]
694
768
  }
695
769
  ),
696
- /* @__PURE__ */ jsx7(Button2, { mini: true, disabled: busy || !target, onClick: async () => {
770
+ /* @__PURE__ */ jsx8(Button4, { mini: true, disabled: busy || !target, onClick: async () => {
697
771
  setBusy(true);
698
772
  setError(null);
699
773
  try {
@@ -706,19 +780,19 @@ function ApplicationStagePanel(props) {
706
780
  actions.refresh();
707
781
  }
708
782
  }, children: "Move" })
709
- ] }) : /* @__PURE__ */ jsx7("p", { children: "No stage changes are available under this chapter\u2019s current membership policy." })
783
+ ] }) : /* @__PURE__ */ jsx8("p", { children: "No stage changes are available under this chapter\u2019s current membership policy." })
710
784
  ] });
711
785
  }
712
786
 
713
787
  // src/ui/operational-profile-form.tsx
714
- import { Button as Button3, Field as Field2, Input, Select as Select2, Textarea } from "@odla-ai/ui/components";
715
- import { useRef, useState as useState6 } from "preact/hooks";
716
- import { jsx as jsx8, jsxs as jsxs8 } from "preact/jsx-runtime";
788
+ import { Button as Button5, Field as Field2, Input, Select as Select2, Textarea } from "@odla-ai/ui/components";
789
+ import { useRef, useState as useState8 } from "preact/hooks";
790
+ import { jsx as jsx9, jsxs as jsxs9 } from "preact/jsx-runtime";
717
791
  var valueText = (value) => value == null ? "" : typeof value === "object" ? JSON.stringify(value) : String(value);
718
792
  function OperationalProfileForm(props) {
719
- const [draft, setDraft] = useState6(() => Object.fromEntries(props.fields.map((field) => [field.id, valueText(props.values[field.id])])));
720
- const [busy, setBusy] = useState6(false);
721
- const [error, setError] = useState6(null);
793
+ const [draft, setDraft] = useState8(() => Object.fromEntries(props.fields.map((field) => [field.id, valueText(props.values[field.id])])));
794
+ const [busy, setBusy] = useState8(false);
795
+ const [error, setError] = useState8(null);
722
796
  const pending = useRef(null);
723
797
  const changed = props.fields.filter((field) => draft[field.id] !== valueText(props.values[field.id]));
724
798
  const save = async () => {
@@ -746,8 +820,8 @@ function OperationalProfileForm(props) {
746
820
  setBusy(false);
747
821
  }
748
822
  };
749
- return /* @__PURE__ */ jsxs8("section", { style: { display: "grid", gap: 16 }, children: [
750
- props.fields.map((field) => /* @__PURE__ */ jsx8(Field2, { label: field.label, children: field.options || field.type === "boolean" ? /* @__PURE__ */ jsxs8(
823
+ return /* @__PURE__ */ jsxs9("section", { style: { display: "grid", gap: 16 }, children: [
824
+ props.fields.map((field) => /* @__PURE__ */ jsx9(Field2, { label: field.label, children: field.options || field.type === "boolean" ? /* @__PURE__ */ jsxs9(
751
825
  Select2,
752
826
  {
753
827
  "aria-label": field.label,
@@ -755,11 +829,11 @@ function OperationalProfileForm(props) {
755
829
  disabled: busy,
756
830
  onChange: (event) => setDraft({ ...draft, [field.id]: event.currentTarget.value }),
757
831
  children: [
758
- /* @__PURE__ */ jsx8("option", { value: "", children: "Not set" }),
759
- (field.options ?? ["true", "false"]).map((option) => /* @__PURE__ */ jsx8("option", { value: option, children: option }, option))
832
+ /* @__PURE__ */ jsx9("option", { value: "", children: "Not set" }),
833
+ (field.options ?? ["true", "false"]).map((option) => /* @__PURE__ */ jsx9("option", { value: option, children: option }, option))
760
834
  ]
761
835
  }
762
- ) : field.type === "json" ? /* @__PURE__ */ jsx8(
836
+ ) : field.type === "json" ? /* @__PURE__ */ jsx9(
763
837
  Textarea,
764
838
  {
765
839
  "aria-label": field.label,
@@ -767,7 +841,7 @@ function OperationalProfileForm(props) {
767
841
  disabled: busy,
768
842
  onInput: (event) => setDraft({ ...draft, [field.id]: event.currentTarget.value })
769
843
  }
770
- ) : /* @__PURE__ */ jsx8(
844
+ ) : /* @__PURE__ */ jsx9(
771
845
  Input,
772
846
  {
773
847
  "aria-label": field.label,
@@ -777,26 +851,26 @@ function OperationalProfileForm(props) {
777
851
  onInput: (event) => setDraft({ ...draft, [field.id]: event.currentTarget.value })
778
852
  }
779
853
  ) }, field.id)),
780
- error ? /* @__PURE__ */ jsx8("p", { role: "alert", children: error }) : null,
781
- /* @__PURE__ */ jsx8("div", { children: /* @__PURE__ */ jsx8(Button3, { disabled: busy || !changed.length, onClick: () => void save(), children: busy ? "Saving\u2026" : "Save profile" }) })
854
+ error ? /* @__PURE__ */ jsx9("p", { role: "alert", children: error }) : null,
855
+ /* @__PURE__ */ jsx9("div", { children: /* @__PURE__ */ jsx9(Button5, { disabled: busy || !changed.length, onClick: () => void save(), children: busy ? "Saving\u2026" : "Save profile" }) })
782
856
  ] });
783
857
  }
784
858
 
785
859
  // src/ui/admin-person-profile.tsx
786
- import { Fragment as Fragment5, jsx as jsx9, jsxs as jsxs9 } from "preact/jsx-runtime";
860
+ import { Fragment as Fragment6, jsx as jsx10, jsxs as jsxs10 } from "preact/jsx-runtime";
787
861
  function ChapterPersonProfile(props) {
788
862
  const path = `/api/admin/people/profile?${new URLSearchParams({ recordId: props.recordId })}`;
789
863
  const resource = useAdminResource(props.getToken, path);
790
- if (resource.loading) return /* @__PURE__ */ jsx9("p", { children: "Loading profile\u2026" });
791
- if (resource.error) return /* @__PURE__ */ jsx9("p", { role: "alert", children: resource.error });
864
+ if (resource.loading) return /* @__PURE__ */ jsx10("p", { children: "Loading profile\u2026" });
865
+ if (resource.error) return /* @__PURE__ */ jsx10("p", { role: "alert", children: resource.error });
792
866
  const record = resource.data?.record;
793
- if (!record?.edit) return /* @__PURE__ */ jsx9("p", { children: "Profile editing is unavailable." });
794
- return /* @__PURE__ */ jsxs9(Fragment5, { children: [
795
- /* @__PURE__ */ jsxs9("p", { children: [
867
+ if (!record?.edit) return /* @__PURE__ */ jsx10("p", { children: "Profile editing is unavailable." });
868
+ return /* @__PURE__ */ jsxs10(Fragment6, { children: [
869
+ /* @__PURE__ */ jsxs10("p", { children: [
796
870
  String(record.fields.email ?? ""),
797
871
  " \u2014 login email changes use the verified account workflow."
798
872
  ] }),
799
- /* @__PURE__ */ jsx9(
873
+ /* @__PURE__ */ jsx10(
800
874
  OperationalProfileForm,
801
875
  {
802
876
  fields: record.edit.fields,
@@ -813,14 +887,14 @@ function ChapterPersonProfile(props) {
813
887
  }
814
888
 
815
889
  // src/ui/admin-account-sync.tsx
816
- import { useState as useState7 } from "preact/hooks";
817
- import { Button as Button4 } from "@odla-ai/ui/components";
818
- import { jsx as jsx10, jsxs as jsxs10 } from "preact/jsx-runtime";
890
+ import { useState as useState9 } from "preact/hooks";
891
+ import { Button as Button6 } from "@odla-ai/ui/components";
892
+ import { jsx as jsx11, jsxs as jsxs11 } from "preact/jsx-runtime";
819
893
  function AccountPeopleSync({ getToken, refresh }) {
820
- const [busy, setBusy] = useState7(false);
821
- const [message, setMessage] = useState7("");
822
- return /* @__PURE__ */ jsxs10("div", { children: [
823
- /* @__PURE__ */ jsx10(Button4, { mini: true, variant: "secondary", disabled: busy, onClick: async () => {
894
+ const [busy, setBusy] = useState9(false);
895
+ const [message, setMessage] = useState9("");
896
+ return /* @__PURE__ */ jsxs11("div", { children: [
897
+ /* @__PURE__ */ jsx11(Button6, { mini: true, variant: "secondary", disabled: busy, onClick: async () => {
824
898
  setBusy(true);
825
899
  setMessage("");
826
900
  let after = null, count = 0, errors = 0;
@@ -844,21 +918,21 @@ function AccountPeopleSync({ getToken, refresh }) {
844
918
  setBusy(false);
845
919
  }
846
920
  }, children: busy ? "Syncing accounts\u2026" : "Sync accounts" }),
847
- message ? /* @__PURE__ */ jsx10("p", { role: "status", children: message }) : null
921
+ message ? /* @__PURE__ */ jsx11("p", { role: "status", children: message }) : null
848
922
  ] });
849
923
  }
850
924
 
851
925
  // src/ui/admin-record-actions.tsx
852
- import { useEffect as useEffect4, useState as useState8 } from "preact/hooks";
853
- import { Button as Button5, Field as Field3, Select as Select3 } from "@odla-ai/ui/components";
854
- import { jsx as jsx11, jsxs as jsxs11 } from "preact/jsx-runtime";
926
+ import { useEffect as useEffect4, useState as useState10 } from "preact/hooks";
927
+ import { Button as Button7, Field as Field3, Select as Select3 } from "@odla-ai/ui/components";
928
+ import { jsx as jsx12, jsxs as jsxs12 } from "preact/jsx-runtime";
855
929
  function RecordActions({ getToken, record, roles, onChanged }) {
856
930
  const copy = useChapterCopy().admin.records;
857
931
  const userId = typeof record.clerkUserId === "string" ? record.clerkUserId : null;
858
932
  const applicationId = typeof record.fields?.applicationId === "string" ? record.fields.applicationId : null;
859
- const [access, setAccess] = useState8(null);
860
- const [busy, setBusy] = useState8(null);
861
- const [note, setNote] = useState8(null);
933
+ const [access, setAccess] = useState10(null);
934
+ const [busy, setBusy] = useState10(null);
935
+ const [note, setNote] = useState10(null);
862
936
  useEffect4(() => {
863
937
  if (!userId) {
864
938
  setAccess(null);
@@ -887,9 +961,9 @@ function RecordActions({ getToken, record, roles, onChanged }) {
887
961
  const approve = () => act("approve", () => adminFetch(getToken, `/api/admin/applications/${applicationId}/approve`, { method: "POST" }), copy.approved);
888
962
  const refund = () => act("refund", () => adminFetch(getToken, `/api/admin/applications/${applicationId}/refund`, { method: "POST" }), copy.refunded);
889
963
  if (!userId && !applicationId) return null;
890
- return /* @__PURE__ */ jsxs11("section", { className: "panel", style: { display: "flex", flexDirection: "column", gap: 14, marginTop: 16 }, children: [
891
- /* @__PURE__ */ jsx11("h3", { style: { margin: 0, fontSize: 16 }, children: copy.lifecycle }),
892
- userId ? /* @__PURE__ */ jsx11(Field3, { label: copy.role, hint: access?.superAdmin ? copy.superAdminHint : void 0, children: /* @__PURE__ */ jsx11(
964
+ return /* @__PURE__ */ jsxs12("section", { className: "panel", style: { display: "flex", flexDirection: "column", gap: 14, marginTop: 16 }, children: [
965
+ /* @__PURE__ */ jsx12("h3", { style: { margin: 0, fontSize: 16 }, children: copy.lifecycle }),
966
+ userId ? /* @__PURE__ */ jsx12(Field3, { label: copy.role, hint: access?.superAdmin ? copy.superAdminHint : void 0, children: /* @__PURE__ */ jsx12(
893
967
  Select3,
894
968
  {
895
969
  value: access?.role ?? "",
@@ -897,24 +971,24 @@ function RecordActions({ getToken, record, roles, onChanged }) {
897
971
  options: roles.map((r) => ({ value: r, label: r })),
898
972
  onChange: (e) => void setRole(e.target.value)
899
973
  }
900
- ) }) : /* @__PURE__ */ jsx11("p", { className: "muted", style: { margin: 0 }, children: copy.noAccount }),
901
- applicationId ? /* @__PURE__ */ jsxs11("div", { style: { display: "flex", gap: 8 }, children: [
902
- /* @__PURE__ */ jsx11(Button5, { variant: "secondary", mini: true, disabled: busy === "approve", onClick: () => void approve(), children: copy.approve }),
903
- /* @__PURE__ */ jsx11(Button5, { variant: "danger", mini: true, disabled: busy === "refund", onClick: () => void refund(), children: copy.refund })
974
+ ) }) : /* @__PURE__ */ jsx12("p", { className: "muted", style: { margin: 0 }, children: copy.noAccount }),
975
+ applicationId ? /* @__PURE__ */ jsxs12("div", { style: { display: "flex", gap: 8 }, children: [
976
+ /* @__PURE__ */ jsx12(Button7, { variant: "secondary", mini: true, disabled: busy === "approve", onClick: () => void approve(), children: copy.approve }),
977
+ /* @__PURE__ */ jsx12(Button7, { variant: "danger", mini: true, disabled: busy === "refund", onClick: () => void refund(), children: copy.refund })
904
978
  ] }) : null,
905
- note ? /* @__PURE__ */ jsx11("p", { className: "muted", style: { margin: 0 }, children: note }) : null
979
+ note ? /* @__PURE__ */ jsx12("p", { className: "muted", style: { margin: 0 }, children: note }) : null
906
980
  ] });
907
981
  }
908
982
 
909
983
  // src/ui/admin-network.tsx
910
- import { useState as useState9 } from "preact/hooks";
911
- import { jsx as jsx12, jsxs as jsxs12 } from "preact/jsx-runtime";
984
+ import { useState as useState11 } from "preact/hooks";
985
+ import { jsx as jsx13, jsxs as jsxs13 } from "preact/jsx-runtime";
912
986
  function NetworkShareActions(props) {
913
987
  const copy = useChapterCopy().admin.network;
914
988
  const { recordId, recordType, getToken } = props;
915
989
  const targets = useAdminResource(getToken, "/api/admin/network/targets");
916
- const [busy, setBusy] = useState9(null);
917
- const [message, setMessage] = useState9(null);
990
+ const [busy, setBusy] = useState11(null);
991
+ const [message, setMessage] = useState11(null);
918
992
  const compatible = (targets.data?.targets ?? []).filter((target) => target.types.includes(recordType));
919
993
  if (targets.loading || targets.error || compatible.length === 0) return null;
920
994
  const push = async (target) => {
@@ -933,26 +1007,26 @@ function NetworkShareActions(props) {
933
1007
  setBusy(null);
934
1008
  }
935
1009
  };
936
- return /* @__PURE__ */ jsxs12("section", { className: "panel", style: { marginTop: 14, display: "flex", flexDirection: "column", gap: 10 }, children: [
937
- /* @__PURE__ */ jsxs12("div", { children: [
938
- /* @__PURE__ */ jsx12("h3", { style: { margin: 0, fontSize: 16 }, children: copy.title }),
939
- /* @__PURE__ */ jsx12("p", { className: "muted", style: { margin: "4px 0 0", fontSize: 13 }, children: copy.allowlistDescription })
1010
+ return /* @__PURE__ */ jsxs13("section", { className: "panel", style: { marginTop: 14, display: "flex", flexDirection: "column", gap: 10 }, children: [
1011
+ /* @__PURE__ */ jsxs13("div", { children: [
1012
+ /* @__PURE__ */ jsx13("h3", { style: { margin: 0, fontSize: 16 }, children: copy.title }),
1013
+ /* @__PURE__ */ jsx13("p", { className: "muted", style: { margin: "4px 0 0", fontSize: 13 }, children: copy.allowlistDescription })
940
1014
  ] }),
941
- /* @__PURE__ */ jsx12("div", { style: { display: "flex", flexWrap: "wrap", gap: 8 }, children: compatible.map((target) => /* @__PURE__ */ jsx12("button", { className: "btn secondary mini", disabled: busy !== null, onClick: () => void push(target), children: busy === target.id ? copy.sharing : formatChapterCopy(copy.shareWith, { target: target.name }) }, target.id)) }),
942
- message ? /* @__PURE__ */ jsx12("p", { role: "status", style: { margin: 0, fontSize: 13 }, children: message }) : null
1015
+ /* @__PURE__ */ jsx13("div", { style: { display: "flex", flexWrap: "wrap", gap: 8 }, children: compatible.map((target) => /* @__PURE__ */ jsx13("button", { className: "btn secondary mini", disabled: busy !== null, onClick: () => void push(target), children: busy === target.id ? copy.sharing : formatChapterCopy(copy.shareWith, { target: target.name }) }, target.id)) }),
1016
+ message ? /* @__PURE__ */ jsx13("p", { role: "status", style: { margin: 0, fontSize: 13 }, children: message }) : null
943
1017
  ] });
944
1018
  }
945
1019
 
946
1020
  // src/ui/admin-record-activity.tsx
947
- import { useCallback as useCallback3, useEffect as useEffect5, useState as useState10 } from "preact/hooks";
1021
+ import { useCallback as useCallback3, useEffect as useEffect5, useState as useState12 } from "preact/hooks";
948
1022
  import { ActivityFeed } from "@odla-ai/crm/ui";
949
1023
  import { parseCrmDiscussionReference as parseCrmDiscussionReference2 } from "@odla-ai/crm";
950
- import { jsx as jsx13 } from "preact/jsx-runtime";
1024
+ import { jsx as jsx14 } from "preact/jsx-runtime";
951
1025
  function RecordActivityPanel(props) {
952
1026
  const { client, recordId } = props;
953
- const [activities, setActivities] = useState10([]);
954
- const [busy, setBusy] = useState10(false);
955
- const [error, setError] = useState10(null);
1027
+ const [activities, setActivities] = useState12([]);
1028
+ const [busy, setBusy] = useState12(false);
1029
+ const [error, setError] = useState12(null);
956
1030
  const reference = typeof window === "undefined" ? null : parseCrmDiscussionReference2(new URL(window.location.href));
957
1031
  const focusedActivityId = reference?.kind === "crm:activity" && reference.recordId === recordId ? reference.activityId : void 0;
958
1032
  const load = useCallback3(async () => {
@@ -974,8 +1048,8 @@ function RecordActivityPanel(props) {
974
1048
  setBusy(false);
975
1049
  }
976
1050
  };
977
- if (error) return /* @__PURE__ */ jsx13("p", { role: "alert", className: "muted", children: error });
978
- return /* @__PURE__ */ jsx13(
1051
+ if (error) return /* @__PURE__ */ jsx14("p", { role: "alert", className: "muted", children: error });
1052
+ return /* @__PURE__ */ jsx14(
979
1053
  ActivityFeed,
980
1054
  {
981
1055
  activities,
@@ -989,17 +1063,17 @@ function RecordActivityPanel(props) {
989
1063
  }
990
1064
 
991
1065
  // src/ui/admin-record-comms.tsx
992
- import { useCallback as useCallback4, useEffect as useEffect6, useState as useState11 } from "preact/hooks";
993
- import { Button as Button6, Field as Field4, Select as Select4 } from "@odla-ai/ui/components";
994
- import { jsx as jsx14, jsxs as jsxs13 } from "preact/jsx-runtime";
1066
+ import { useCallback as useCallback4, useEffect as useEffect6, useState as useState13 } from "preact/hooks";
1067
+ import { Button as Button8, Field as Field4, Select as Select4 } from "@odla-ai/ui/components";
1068
+ import { jsx as jsx15, jsxs as jsxs14 } from "preact/jsx-runtime";
995
1069
  function RecordCommsPanel(props) {
996
1070
  const copy = useChapterCopy().admin.records;
997
1071
  const { client, recordId, getToken } = props;
998
1072
  const config = useAdminResource(getToken, "/api/admin/group/email");
999
1073
  const templates = Object.entries(config.data?.emailTemplates ?? {}).filter(([, value]) => value.enabled);
1000
- const [template, setTemplate] = useState11("");
1001
- const [busy, setBusy] = useState11(false);
1002
- const [note, setNote] = useState11(null);
1074
+ const [template, setTemplate] = useState13("");
1075
+ const [busy, setBusy] = useState13(false);
1076
+ const [note, setNote] = useState13(null);
1003
1077
  const send = async () => {
1004
1078
  if (!template) return;
1005
1079
  setBusy(true);
@@ -1013,10 +1087,10 @@ function RecordCommsPanel(props) {
1013
1087
  setBusy(false);
1014
1088
  }
1015
1089
  };
1016
- if (config.loading) return /* @__PURE__ */ jsx14("p", { className: "muted", children: copy.loadingTemplates });
1017
- if (config.error) return /* @__PURE__ */ jsx14("p", { role: "alert", className: "muted", children: config.error });
1018
- return /* @__PURE__ */ jsxs13("div", { style: { display: "grid", gap: 14, maxWidth: 560 }, children: [
1019
- /* @__PURE__ */ jsx14(Field4, { label: copy.template, children: /* @__PURE__ */ jsx14(
1090
+ if (config.loading) return /* @__PURE__ */ jsx15("p", { className: "muted", children: copy.loadingTemplates });
1091
+ if (config.error) return /* @__PURE__ */ jsx15("p", { role: "alert", className: "muted", children: config.error });
1092
+ return /* @__PURE__ */ jsxs14("div", { style: { display: "grid", gap: 14, maxWidth: 560 }, children: [
1093
+ /* @__PURE__ */ jsx15(Field4, { label: copy.template, children: /* @__PURE__ */ jsx15(
1020
1094
  Select4,
1021
1095
  {
1022
1096
  value: template,
@@ -1027,15 +1101,15 @@ function RecordCommsPanel(props) {
1027
1101
  ]
1028
1102
  }
1029
1103
  ) }),
1030
- /* @__PURE__ */ jsx14("div", { children: /* @__PURE__ */ jsx14(Button6, { disabled: !template || busy, onClick: () => void send(), children: busy ? copy.sending : copy.send }) }),
1031
- note ? /* @__PURE__ */ jsx14("p", { role: "status", className: "muted", children: note }) : null
1104
+ /* @__PURE__ */ jsx15("div", { children: /* @__PURE__ */ jsx15(Button8, { disabled: !template || busy, onClick: () => void send(), children: busy ? copy.sending : copy.send }) }),
1105
+ note ? /* @__PURE__ */ jsx15("p", { role: "status", className: "muted", children: note }) : null
1032
1106
  ] });
1033
1107
  }
1034
1108
  function RecordCommsHistory(props) {
1035
1109
  const copy = useChapterCopy().admin.records;
1036
1110
  const { client, recordId } = props;
1037
- const [rows, setRows] = useState11([]);
1038
- const [error, setError] = useState11(null);
1111
+ const [rows, setRows] = useState13([]);
1112
+ const [error, setError] = useState13(null);
1039
1113
  const load = useCallback4(async () => {
1040
1114
  try {
1041
1115
  const result = await client.emailLog({ recordId, limit: 100 });
@@ -1046,11 +1120,11 @@ function RecordCommsHistory(props) {
1046
1120
  }
1047
1121
  }, [client, recordId]);
1048
1122
  useEffect6(() => void load(), [load]);
1049
- if (error) return /* @__PURE__ */ jsx14("p", { role: "alert", className: "muted", children: error });
1050
- if (rows.length === 0) return /* @__PURE__ */ jsx14("p", { className: "muted", children: copy.noMessages });
1051
- return /* @__PURE__ */ jsx14("ul", { style: { listStyle: "none", padding: 0, margin: 0, display: "grid", gap: 10 }, children: rows.map((row, index) => /* @__PURE__ */ jsxs13("li", { className: "panel", children: [
1052
- /* @__PURE__ */ jsx14("strong", { children: String(row["templateId"] ?? row["template"] ?? copy.message) }),
1053
- /* @__PURE__ */ jsxs13("div", { className: "muted", children: [
1123
+ if (error) return /* @__PURE__ */ jsx15("p", { role: "alert", className: "muted", children: error });
1124
+ if (rows.length === 0) return /* @__PURE__ */ jsx15("p", { className: "muted", children: copy.noMessages });
1125
+ return /* @__PURE__ */ jsx15("ul", { style: { listStyle: "none", padding: 0, margin: 0, display: "grid", gap: 10 }, children: rows.map((row, index) => /* @__PURE__ */ jsxs14("li", { className: "panel", children: [
1126
+ /* @__PURE__ */ jsx15("strong", { children: String(row["templateId"] ?? row["template"] ?? copy.message) }),
1127
+ /* @__PURE__ */ jsxs14("div", { className: "muted", children: [
1054
1128
  row["to"] ? String(row["to"]) : "",
1055
1129
  row["sentAt"] ? ` \xB7 ${new Date(Number(row["sentAt"])).toLocaleString()}` : ""
1056
1130
  ] })
@@ -1058,9 +1132,9 @@ function RecordCommsHistory(props) {
1058
1132
  }
1059
1133
 
1060
1134
  // src/ui/admin-record-scheduling.tsx
1061
- import { useState as useState12 } from "preact/hooks";
1062
- import { Button as Button7 } from "@odla-ai/ui/components";
1063
- import { Fragment as Fragment6, jsx as jsx15, jsxs as jsxs14 } from "preact/jsx-runtime";
1135
+ import { useState as useState14 } from "preact/hooks";
1136
+ import { Button as Button9 } from "@odla-ai/ui/components";
1137
+ import { Fragment as Fragment7, jsx as jsx16, jsxs as jsxs15 } from "preact/jsx-runtime";
1064
1138
  function RecordSchedulingPanel(props) {
1065
1139
  const copy = useChapterCopy().admin.records;
1066
1140
  const { getToken, applicationId } = props;
@@ -1068,8 +1142,8 @@ function RecordSchedulingPanel(props) {
1068
1142
  getToken,
1069
1143
  "/api/admin/meetings?all=1"
1070
1144
  );
1071
- const [busy, setBusy] = useState12(null);
1072
- const [note, setNote] = useState12(null);
1145
+ const [busy, setBusy] = useState14(null);
1146
+ const [note, setNote] = useState14(null);
1073
1147
  const meetings = (resource.data?.meetings ?? []).filter((meeting) => meeting.applicationId === applicationId);
1074
1148
  const run = async (meeting, action) => {
1075
1149
  let body;
@@ -1096,33 +1170,33 @@ function RecordSchedulingPanel(props) {
1096
1170
  setBusy(null);
1097
1171
  }
1098
1172
  };
1099
- if (!applicationId) return /* @__PURE__ */ jsx15("p", { className: "muted", children: copy.noApplication });
1100
- if (resource.loading) return /* @__PURE__ */ jsx15("p", { className: "muted", children: copy.loadingMeetings });
1101
- if (resource.error) return /* @__PURE__ */ jsx15("p", { role: "alert", className: "muted", children: resource.error });
1102
- if (meetings.length === 0) return /* @__PURE__ */ jsx15("p", { className: "muted", children: copy.noMeetings });
1103
- return /* @__PURE__ */ jsxs14("div", { style: { display: "grid", gap: 12 }, children: [
1104
- meetings.map((meeting) => /* @__PURE__ */ jsxs14("section", { className: "panel", children: [
1105
- /* @__PURE__ */ jsx15("strong", { children: new Date(meeting.startAt).toLocaleString() }),
1106
- /* @__PURE__ */ jsxs14("p", { className: "muted", children: [
1173
+ if (!applicationId) return /* @__PURE__ */ jsx16("p", { className: "muted", children: copy.noApplication });
1174
+ if (resource.loading) return /* @__PURE__ */ jsx16("p", { className: "muted", children: copy.loadingMeetings });
1175
+ if (resource.error) return /* @__PURE__ */ jsx16("p", { role: "alert", className: "muted", children: resource.error });
1176
+ if (meetings.length === 0) return /* @__PURE__ */ jsx16("p", { className: "muted", children: copy.noMeetings });
1177
+ return /* @__PURE__ */ jsxs15("div", { style: { display: "grid", gap: 12 }, children: [
1178
+ meetings.map((meeting) => /* @__PURE__ */ jsxs15("section", { className: "panel", children: [
1179
+ /* @__PURE__ */ jsx16("strong", { children: new Date(meeting.startAt).toLocaleString() }),
1180
+ /* @__PURE__ */ jsxs15("p", { className: "muted", children: [
1107
1181
  meeting.status,
1108
1182
  " \xB7 ",
1109
1183
  resource.data?.timezone
1110
1184
  ] }),
1111
- /* @__PURE__ */ jsxs14("div", { style: { display: "flex", gap: 8, flexWrap: "wrap" }, children: [
1112
- meeting.meetUrl ? /* @__PURE__ */ jsx15("a", { href: meeting.meetUrl, target: "_blank", rel: "noreferrer", children: copy.joinMeeting }) : null,
1113
- meeting.htmlLink ? /* @__PURE__ */ jsx15("a", { href: meeting.htmlLink, target: "_blank", rel: "noreferrer", children: copy.openCalendar }) : null,
1114
- meeting.status === "scheduled" ? /* @__PURE__ */ jsxs14(Fragment6, { children: [
1115
- /* @__PURE__ */ jsx15(Button7, { variant: "secondary", mini: true, disabled: busy === meeting.id, onClick: () => void run(meeting, "reschedule"), children: copy.reschedule }),
1116
- /* @__PURE__ */ jsx15(Button7, { variant: "danger", mini: true, disabled: busy === meeting.id, onClick: () => void run(meeting, "cancel"), children: copy.cancel })
1185
+ /* @__PURE__ */ jsxs15("div", { style: { display: "flex", gap: 8, flexWrap: "wrap" }, children: [
1186
+ meeting.meetUrl ? /* @__PURE__ */ jsx16("a", { href: meeting.meetUrl, target: "_blank", rel: "noreferrer", children: copy.joinMeeting }) : null,
1187
+ meeting.htmlLink ? /* @__PURE__ */ jsx16("a", { href: meeting.htmlLink, target: "_blank", rel: "noreferrer", children: copy.openCalendar }) : null,
1188
+ meeting.status === "scheduled" ? /* @__PURE__ */ jsxs15(Fragment7, { children: [
1189
+ /* @__PURE__ */ jsx16(Button9, { variant: "secondary", mini: true, disabled: busy === meeting.id, onClick: () => void run(meeting, "reschedule"), children: copy.reschedule }),
1190
+ /* @__PURE__ */ jsx16(Button9, { variant: "danger", mini: true, disabled: busy === meeting.id, onClick: () => void run(meeting, "cancel"), children: copy.cancel })
1117
1191
  ] }) : null
1118
1192
  ] })
1119
1193
  ] }, meeting.id)),
1120
- note ? /* @__PURE__ */ jsx15("p", { role: "status", className: "muted", children: note }) : null
1194
+ note ? /* @__PURE__ */ jsx16("p", { role: "status", className: "muted", children: note }) : null
1121
1195
  ] });
1122
1196
  }
1123
1197
 
1124
1198
  // src/ui/admin-people-workspace.tsx
1125
- import { Fragment as Fragment7, jsx as jsx16, jsxs as jsxs15 } from "preact/jsx-runtime";
1199
+ import { Fragment as Fragment8, jsx as jsx17, jsxs as jsxs16 } from "preact/jsx-runtime";
1126
1200
  function applicationLifecycleAdapter(ctx, copy = DEFAULT_CHAPTER_COPY.admin.records) {
1127
1201
  return {
1128
1202
  transitionStage: async ({ record, to }) => {
@@ -1171,7 +1245,7 @@ function PeopleBody(props) {
1171
1245
  const builtInLifecycle = lifecycle ? applicationLifecycleAdapter(ctx, copy) : void 0;
1172
1246
  const resolvedLifecycle = typeof lifecycleAdapter === "function" ? lifecycleAdapter(ctx) : lifecycleAdapter ?? builtInLifecycle;
1173
1247
  const workspaceClient = client;
1174
- return /* @__PURE__ */ jsx16(AdminPage, { children: /* @__PURE__ */ jsx16(
1248
+ return /* @__PURE__ */ jsx17(AdminPage, { children: /* @__PURE__ */ jsx17(
1175
1249
  CrmWorkspace,
1176
1250
  {
1177
1251
  crm,
@@ -1187,9 +1261,9 @@ function PeopleBody(props) {
1187
1261
  collapseClosedDetail,
1188
1262
  lifecycle: resolvedLifecycle,
1189
1263
  requireLifecycleAdapter: requireLifecycleAdapter ?? lifecycle,
1190
- renderSummary: (context) => /* @__PURE__ */ jsxs15(Fragment7, { children: [
1264
+ renderSummary: (context) => /* @__PURE__ */ jsxs16(Fragment8, { children: [
1191
1265
  renderSummary?.(context, ctx),
1192
- type === "person" ? /* @__PURE__ */ jsx16(AccountPeopleSync, { getToken: ctx.getToken, refresh: context.query.refresh }) : null
1266
+ type === "person" ? /* @__PURE__ */ jsx17(AccountPeopleSync, { getToken: ctx.getToken, refresh: context.query.refresh }) : null
1193
1267
  ] }),
1194
1268
  renderMaster: renderMaster ? (context) => renderMaster(context, ctx) : void 0,
1195
1269
  renderDetailHeader: renderDetailHeader ? (context) => renderDetailHeader(context, ctx) : void 0,
@@ -1203,7 +1277,7 @@ function PeopleBody(props) {
1203
1277
  const add = (id) => {
1204
1278
  const tab = byId.get(id);
1205
1279
  if (tab && lifecycle && type === "person" && id === "profile" && !lifecycleAdapter) {
1206
- tabs.push({ ...tab, panel: /* @__PURE__ */ jsx16(
1280
+ tabs.push({ ...tab, panel: /* @__PURE__ */ jsx17(
1207
1281
  ChapterPersonProfile,
1208
1282
  {
1209
1283
  recordId: record.id,
@@ -1218,7 +1292,7 @@ function PeopleBody(props) {
1218
1292
  return;
1219
1293
  }
1220
1294
  if (tab && lifecycle && applicationId && id === "stage" && !lifecycleAdapter) {
1221
- tabs.push({ ...tab, panel: /* @__PURE__ */ jsx16(
1295
+ tabs.push({ ...tab, panel: /* @__PURE__ */ jsx17(
1222
1296
  ApplicationStagePanel,
1223
1297
  {
1224
1298
  applicationId,
@@ -1231,8 +1305,8 @@ function PeopleBody(props) {
1231
1305
  }
1232
1306
  if (tab) tabs.push(lifecycle && !applicationId && id === "stage" ? {
1233
1307
  ...tab,
1234
- panel: record.stage == null ? /* @__PURE__ */ jsx16("p", { children: "Journey stage: Not applicable. No membership application is linked. Administrative access is separate." }) : /* @__PURE__ */ jsxs15(Fragment7, { children: [
1235
- /* @__PURE__ */ jsx16(ApplicationLinkRepair, { recordId: record.id, getToken: ctx.getToken, onChanged: () => {
1308
+ panel: record.stage == null ? /* @__PURE__ */ jsx17("p", { children: "Journey stage: Not applicable. No membership application is linked. Administrative access is separate." }) : /* @__PURE__ */ jsxs16(Fragment8, { children: [
1309
+ /* @__PURE__ */ jsx17(ApplicationLinkRepair, { recordId: record.id, getToken: ctx.getToken, onChanged: () => {
1236
1310
  context.refreshRecord();
1237
1311
  context.refreshList();
1238
1312
  } }, record.id),
@@ -1246,35 +1320,35 @@ function PeopleBody(props) {
1246
1320
  tabs.push({
1247
1321
  id: "comms",
1248
1322
  label: copy.comms,
1249
- panel: /* @__PURE__ */ jsx16(RecordCommsPanel, { client, recordId: record.id, getToken: ctx.getToken })
1323
+ panel: /* @__PURE__ */ jsx17(RecordCommsPanel, { client, recordId: record.id, getToken: ctx.getToken })
1250
1324
  });
1251
1325
  tabs.push({
1252
1326
  id: "history",
1253
1327
  label: copy.commsHistory,
1254
- panel: /* @__PURE__ */ jsx16(RecordCommsHistory, { client, recordId: record.id })
1328
+ panel: /* @__PURE__ */ jsx17(RecordCommsHistory, { client, recordId: record.id })
1255
1329
  });
1256
1330
  }
1257
1331
  if (lifecycle) {
1258
1332
  tabs.push({
1259
1333
  id: "scheduling",
1260
1334
  label: copy.scheduling,
1261
- panel: /* @__PURE__ */ jsx16(RecordSchedulingPanel, { getToken: ctx.getToken, applicationId })
1335
+ panel: /* @__PURE__ */ jsx17(RecordSchedulingPanel, { getToken: ctx.getToken, applicationId })
1262
1336
  });
1263
- tabs.push({ id: "billing", label: copy.billing, panel: /* @__PURE__ */ jsx16(BillingCard, { record }) });
1337
+ tabs.push({ id: "billing", label: copy.billing, panel: /* @__PURE__ */ jsx17(BillingCard, { record }) });
1264
1338
  } else {
1265
1339
  add("billing");
1266
1340
  }
1267
1341
  tabs.push({
1268
1342
  id: "notes",
1269
1343
  label: copy.notes,
1270
- panel: /* @__PURE__ */ jsx16(RecordActivityPanel, { client, recordId: record.id })
1344
+ panel: /* @__PURE__ */ jsx17(RecordActivityPanel, { client, recordId: record.id })
1271
1345
  });
1272
1346
  add("connections");
1273
1347
  if (lifecycle) {
1274
1348
  tabs.push({
1275
1349
  id: "access",
1276
1350
  label: copy.access,
1277
- panel: /* @__PURE__ */ jsx16(
1351
+ panel: /* @__PURE__ */ jsx17(
1278
1352
  RecordActions,
1279
1353
  {
1280
1354
  getToken: ctx.getToken,
@@ -1293,7 +1367,7 @@ function PeopleBody(props) {
1293
1367
  tabs.push({
1294
1368
  id: "sharing",
1295
1369
  label: copy.sharing,
1296
- panel: /* @__PURE__ */ jsx16(NetworkShareActions, { recordId: record.id, recordType: record.type, getToken: ctx.getToken })
1370
+ panel: /* @__PURE__ */ jsx17(NetworkShareActions, { recordId: record.id, recordType: record.type, getToken: ctx.getToken })
1297
1371
  });
1298
1372
  }
1299
1373
  return extendRecordTabs?.(tabs, context) ?? tabs;
@@ -1303,7 +1377,7 @@ function PeopleBody(props) {
1303
1377
  }
1304
1378
 
1305
1379
  // src/ui/admin-people.tsx
1306
- import { jsx as jsx17 } from "preact/jsx-runtime";
1380
+ import { jsx as jsx18 } from "preact/jsx-runtime";
1307
1381
  var DEFAULT_ROLES = ["provisional", "member", "admin"];
1308
1382
  function collectionSection(options) {
1309
1383
  const { crm, type } = options;
@@ -1333,7 +1407,7 @@ function collectionSection(options) {
1333
1407
  return {
1334
1408
  id,
1335
1409
  label,
1336
- render: (ctx) => /* @__PURE__ */ jsx17(
1410
+ render: (ctx) => /* @__PURE__ */ jsx18(
1337
1411
  PeopleBody,
1338
1412
  {
1339
1413
  crm,
@@ -1407,12 +1481,12 @@ import {
1407
1481
  Pagination,
1408
1482
  Select as Select5
1409
1483
  } from "@odla-ai/ui/components";
1410
- import { useEffect as useEffect7, useMemo, useState as useState14 } from "preact/hooks";
1484
+ import { useEffect as useEffect7, useMemo, useState as useState16 } from "preact/hooks";
1411
1485
 
1412
1486
  // src/ui/admin-network-notes.tsx
1413
- import { Button as Button8, Field as Field5, Textarea as Textarea2 } from "@odla-ai/ui/components";
1414
- import { useState as useState13 } from "preact/hooks";
1415
- import { jsx as jsx18, jsxs as jsxs16 } from "preact/jsx-runtime";
1487
+ import { Button as Button10, Field as Field5, Textarea as Textarea2 } from "@odla-ai/ui/components";
1488
+ import { useState as useState15 } from "preact/hooks";
1489
+ import { jsx as jsx19, jsxs as jsxs17 } from "preact/jsx-runtime";
1416
1490
  function displayValue(value) {
1417
1491
  if (Array.isArray(value)) return value.join(", ");
1418
1492
  if (value && typeof value === "object") return JSON.stringify(value);
@@ -1427,9 +1501,9 @@ function PrivateNotes(props) {
1427
1501
  });
1428
1502
  const path = `/api/admin/network/notes?${query}`;
1429
1503
  const notes = useAdminResource(ctx.getToken, path);
1430
- const [body, setBody] = useState13("");
1431
- const [busy, setBusy] = useState13(false);
1432
- const [error, setError] = useState13(null);
1504
+ const [body, setBody] = useState15("");
1505
+ const [busy, setBusy] = useState15(false);
1506
+ const [error, setError] = useState15(null);
1433
1507
  const submit = async () => {
1434
1508
  const trimmed = body.trim();
1435
1509
  if (!trimmed) return;
@@ -1448,18 +1522,18 @@ function PrivateNotes(props) {
1448
1522
  setBusy(false);
1449
1523
  }
1450
1524
  };
1451
- return /* @__PURE__ */ jsxs16("section", { style: { display: "grid", gap: 12 }, children: [
1452
- /* @__PURE__ */ jsxs16("h3", { style: { margin: "8px 0 0" }, children: [
1525
+ return /* @__PURE__ */ jsxs17("section", { style: { display: "grid", gap: 12 }, children: [
1526
+ /* @__PURE__ */ jsxs17("h3", { style: { margin: "8px 0 0" }, children: [
1453
1527
  "Private to ",
1454
1528
  leaderName
1455
1529
  ] }),
1456
- /* @__PURE__ */ jsx18(
1530
+ /* @__PURE__ */ jsx19(
1457
1531
  Field5,
1458
1532
  {
1459
1533
  label: "Add a note",
1460
1534
  hint: `Visible only to ${leaderName} admins. Nothing is written back to the follower.`,
1461
1535
  error,
1462
- children: /* @__PURE__ */ jsx18(
1536
+ children: /* @__PURE__ */ jsx19(
1463
1537
  Textarea2,
1464
1538
  {
1465
1539
  rows: 4,
@@ -1470,13 +1544,13 @@ function PrivateNotes(props) {
1470
1544
  )
1471
1545
  }
1472
1546
  ),
1473
- /* @__PURE__ */ jsx18("div", { children: /* @__PURE__ */ jsx18(Button8, { disabled: busy || !body.trim(), onClick: () => void submit(), children: busy ? "Saving\u2026" : "Save note" }) }),
1474
- notes.loading ? /* @__PURE__ */ jsx18("p", { className: "muted", children: "Loading notes\u2026" }) : null,
1475
- notes.error ? /* @__PURE__ */ jsx18("p", { role: "alert", children: notes.error }) : null,
1476
- !notes.loading && !notes.error && (notes.data?.notes.length ?? 0) === 0 ? /* @__PURE__ */ jsx18("p", { className: "muted", children: "No notes yet." }) : null,
1477
- (notes.data?.notes ?? []).map((note) => /* @__PURE__ */ jsxs16("article", { className: "panel", style: { padding: 14 }, children: [
1478
- /* @__PURE__ */ jsx18("p", { style: { margin: 0, whiteSpace: "pre-wrap" }, children: note.body }),
1479
- /* @__PURE__ */ jsxs16("p", { className: "muted", style: { margin: "8px 0 0", fontSize: 12 }, children: [
1547
+ /* @__PURE__ */ jsx19("div", { children: /* @__PURE__ */ jsx19(Button10, { disabled: busy || !body.trim(), onClick: () => void submit(), children: busy ? "Saving\u2026" : "Save note" }) }),
1548
+ notes.loading ? /* @__PURE__ */ jsx19("p", { className: "muted", children: "Loading notes\u2026" }) : null,
1549
+ notes.error ? /* @__PURE__ */ jsx19("p", { role: "alert", children: notes.error }) : null,
1550
+ !notes.loading && !notes.error && (notes.data?.notes.length ?? 0) === 0 ? /* @__PURE__ */ jsx19("p", { className: "muted", children: "No notes yet." }) : null,
1551
+ (notes.data?.notes ?? []).map((note) => /* @__PURE__ */ jsxs17("article", { className: "panel", style: { padding: 14 }, children: [
1552
+ /* @__PURE__ */ jsx19("p", { style: { margin: 0, whiteSpace: "pre-wrap" }, children: note.body }),
1553
+ /* @__PURE__ */ jsxs17("p", { className: "muted", style: { margin: "8px 0 0", fontSize: 12 }, children: [
1480
1554
  note.authorEmail ?? note.authorId,
1481
1555
  " \xB7 ",
1482
1556
  new Date(note.createdAt).toLocaleString()
@@ -1493,9 +1567,9 @@ function SharedNotes(props) {
1493
1567
  });
1494
1568
  const path = `/api/admin/network/shared-notes?${query}`;
1495
1569
  const notes = useAdminResource(ctx.getToken, path);
1496
- const [body, setBody] = useState13("");
1497
- const [busy, setBusy] = useState13(false);
1498
- const [error, setError] = useState13(null);
1570
+ const [body, setBody] = useState15("");
1571
+ const [busy, setBusy] = useState15(false);
1572
+ const [error, setError] = useState15(null);
1499
1573
  const submit = async () => {
1500
1574
  const trimmed = body.trim();
1501
1575
  if (!trimmed) return;
@@ -1514,18 +1588,18 @@ function SharedNotes(props) {
1514
1588
  setBusy(false);
1515
1589
  }
1516
1590
  };
1517
- return /* @__PURE__ */ jsxs16("section", { style: { display: "grid", gap: 12 }, children: [
1518
- /* @__PURE__ */ jsxs16("h3", { style: { margin: "8px 0 0" }, children: [
1591
+ return /* @__PURE__ */ jsxs17("section", { style: { display: "grid", gap: 12 }, children: [
1592
+ /* @__PURE__ */ jsxs17("h3", { style: { margin: "8px 0 0" }, children: [
1519
1593
  "Shared with ",
1520
1594
  targetName
1521
1595
  ] }),
1522
- /* @__PURE__ */ jsx18(
1596
+ /* @__PURE__ */ jsx19(
1523
1597
  Field5,
1524
1598
  {
1525
1599
  label: "Add a shared note",
1526
1600
  hint: `This is written to the record's Notes feed for ${targetName} admins.`,
1527
1601
  error,
1528
- children: /* @__PURE__ */ jsx18(
1602
+ children: /* @__PURE__ */ jsx19(
1529
1603
  Textarea2,
1530
1604
  {
1531
1605
  rows: 4,
@@ -1536,13 +1610,13 @@ function SharedNotes(props) {
1536
1610
  )
1537
1611
  }
1538
1612
  ),
1539
- /* @__PURE__ */ jsx18("div", { children: /* @__PURE__ */ jsx18(Button8, { disabled: busy || !body.trim(), onClick: () => void submit(), children: busy ? "Sharing\u2026" : `Share with ${targetName}` }) }),
1540
- notes.loading ? /* @__PURE__ */ jsx18("p", { className: "muted", children: "Loading shared notes\u2026" }) : null,
1541
- notes.error ? /* @__PURE__ */ jsx18("p", { role: "alert", children: notes.error }) : null,
1542
- !notes.loading && !notes.error && (notes.data?.notes.length ?? 0) === 0 ? /* @__PURE__ */ jsx18("p", { className: "muted", children: "No shared notes yet." }) : null,
1543
- (notes.data?.notes ?? []).map((note) => /* @__PURE__ */ jsxs16("article", { className: "panel", style: { padding: 14 }, children: [
1544
- /* @__PURE__ */ jsx18("p", { style: { margin: 0, whiteSpace: "pre-wrap" }, children: note.body }),
1545
- /* @__PURE__ */ jsxs16("p", { className: "muted", style: { margin: "8px 0 0", fontSize: 12 }, children: [
1613
+ /* @__PURE__ */ jsx19("div", { children: /* @__PURE__ */ jsx19(Button10, { disabled: busy || !body.trim(), onClick: () => void submit(), children: busy ? "Sharing\u2026" : `Share with ${targetName}` }) }),
1614
+ notes.loading ? /* @__PURE__ */ jsx19("p", { className: "muted", children: "Loading shared notes\u2026" }) : null,
1615
+ notes.error ? /* @__PURE__ */ jsx19("p", { role: "alert", children: notes.error }) : null,
1616
+ !notes.loading && !notes.error && (notes.data?.notes.length ?? 0) === 0 ? /* @__PURE__ */ jsx19("p", { className: "muted", children: "No shared notes yet." }) : null,
1617
+ (notes.data?.notes ?? []).map((note) => /* @__PURE__ */ jsxs17("article", { className: "panel", style: { padding: 14 }, children: [
1618
+ /* @__PURE__ */ jsx19("p", { style: { margin: 0, whiteSpace: "pre-wrap" }, children: note.body }),
1619
+ /* @__PURE__ */ jsxs17("p", { className: "muted", style: { margin: "8px 0 0", fontSize: 12 }, children: [
1546
1620
  "Shared with ",
1547
1621
  targetName,
1548
1622
  " \xB7 ",
@@ -1553,23 +1627,23 @@ function SharedNotes(props) {
1553
1627
  }
1554
1628
  function NetworkRecordDetail(props) {
1555
1629
  const { ctx, targetId, targetName, leaderName, sharedEnabled, record } = props;
1556
- return /* @__PURE__ */ jsxs16("div", { style: { display: "grid", gap: 14 }, children: [
1557
- /* @__PURE__ */ jsxs16("header", { children: [
1558
- /* @__PURE__ */ jsx18("h2", { style: { margin: 0 }, children: record.name }),
1559
- record.stage ? /* @__PURE__ */ jsx18("span", { className: "badge", style: { marginTop: 8 }, children: record.stage.replaceAll("_", " ") }) : null
1630
+ return /* @__PURE__ */ jsxs17("div", { style: { display: "grid", gap: 14 }, children: [
1631
+ /* @__PURE__ */ jsxs17("header", { children: [
1632
+ /* @__PURE__ */ jsx19("h2", { style: { margin: 0 }, children: record.name }),
1633
+ record.stage ? /* @__PURE__ */ jsx19("span", { className: "badge", style: { marginTop: 8 }, children: record.stage.replaceAll("_", " ") }) : null
1560
1634
  ] }),
1561
- /* @__PURE__ */ jsxs16("dl", { style: { display: "grid", gridTemplateColumns: "minmax(8rem, auto) 1fr", gap: "8px 16px", margin: 0 }, children: [
1562
- Object.entries(record.fields).map(([name, value]) => /* @__PURE__ */ jsxs16("div", { style: { display: "contents" }, children: [
1563
- /* @__PURE__ */ jsx18("dt", { className: "muted", children: name.replaceAll("_", " ") }),
1564
- /* @__PURE__ */ jsx18("dd", { style: { margin: 0, overflowWrap: "anywhere" }, children: displayValue(value) })
1635
+ /* @__PURE__ */ jsxs17("dl", { style: { display: "grid", gridTemplateColumns: "minmax(8rem, auto) 1fr", gap: "8px 16px", margin: 0 }, children: [
1636
+ Object.entries(record.fields).map(([name, value]) => /* @__PURE__ */ jsxs17("div", { style: { display: "contents" }, children: [
1637
+ /* @__PURE__ */ jsx19("dt", { className: "muted", children: name.replaceAll("_", " ") }),
1638
+ /* @__PURE__ */ jsx19("dd", { style: { margin: 0, overflowWrap: "anywhere" }, children: displayValue(value) })
1565
1639
  ] }, name)),
1566
- /* @__PURE__ */ jsxs16("div", { style: { display: "contents" }, children: [
1567
- /* @__PURE__ */ jsx18("dt", { className: "muted", children: "Updated" }),
1568
- /* @__PURE__ */ jsx18("dd", { style: { margin: 0 }, children: new Date(record.updatedAt).toLocaleString() })
1640
+ /* @__PURE__ */ jsxs17("div", { style: { display: "contents" }, children: [
1641
+ /* @__PURE__ */ jsx19("dt", { className: "muted", children: "Updated" }),
1642
+ /* @__PURE__ */ jsx19("dd", { style: { margin: 0 }, children: new Date(record.updatedAt).toLocaleString() })
1569
1643
  ] })
1570
1644
  ] }),
1571
- /* @__PURE__ */ jsxs16("div", { style: { display: "grid", gap: 22 }, children: [
1572
- /* @__PURE__ */ jsx18(
1645
+ /* @__PURE__ */ jsxs17("div", { style: { display: "grid", gap: 22 }, children: [
1646
+ /* @__PURE__ */ jsx19(
1573
1647
  PrivateNotes,
1574
1648
  {
1575
1649
  ctx,
@@ -1578,7 +1652,7 @@ function NetworkRecordDetail(props) {
1578
1652
  leaderName
1579
1653
  }
1580
1654
  ),
1581
- sharedEnabled ? /* @__PURE__ */ jsx18(
1655
+ sharedEnabled ? /* @__PURE__ */ jsx19(
1582
1656
  SharedNotes,
1583
1657
  {
1584
1658
  ctx,
@@ -1592,11 +1666,11 @@ function NetworkRecordDetail(props) {
1592
1666
  }
1593
1667
 
1594
1668
  // src/ui/admin-network-records.tsx
1595
- import { jsx as jsx19, jsxs as jsxs17 } from "preact/jsx-runtime";
1669
+ import { jsx as jsx20, jsxs as jsxs18 } from "preact/jsx-runtime";
1596
1670
  function RecordsExplorer(props) {
1597
1671
  const { ctx, target, type, leaderName } = props;
1598
- const [offset, setOffset] = useState14(0);
1599
- const [search, setSearch] = useState14("");
1672
+ const [offset, setOffset] = useState16(0);
1673
+ const [search, setSearch] = useState16("");
1600
1674
  const query = new URLSearchParams({
1601
1675
  targetId: target.id,
1602
1676
  type,
@@ -1609,16 +1683,16 @@ function RecordsExplorer(props) {
1609
1683
  `/api/admin/network/records?${query}`
1610
1684
  );
1611
1685
  const selected = page.data?.records.find((record) => record.id === ctx.route.recordId);
1612
- const columns2 = useMemo(() => [
1686
+ const columns3 = useMemo(() => [
1613
1687
  {
1614
1688
  key: "name",
1615
1689
  header: "Name",
1616
- cell: (record) => /* @__PURE__ */ jsx19("a", { href: ctx.href({ recordId: record.id, detailTab: null }), children: record.name })
1690
+ cell: (record) => /* @__PURE__ */ jsx20("a", { href: ctx.href({ recordId: record.id, detailTab: null }), children: record.name })
1617
1691
  },
1618
1692
  {
1619
1693
  key: "stage",
1620
1694
  header: "Stage",
1621
- cell: (record) => record.stage ? /* @__PURE__ */ jsx19("span", { className: "badge", children: record.stage.replaceAll("_", " ") }) : "\u2014"
1695
+ cell: (record) => record.stage ? /* @__PURE__ */ jsx20("span", { className: "badge", children: record.stage.replaceAll("_", " ") }) : "\u2014"
1622
1696
  },
1623
1697
  {
1624
1698
  key: "updatedAt",
@@ -1626,7 +1700,7 @@ function RecordsExplorer(props) {
1626
1700
  cell: (record) => new Date(record.updatedAt).toLocaleDateString()
1627
1701
  }
1628
1702
  ], [ctx]);
1629
- return /* @__PURE__ */ jsx19(
1703
+ return /* @__PURE__ */ jsx20(
1630
1704
  MasterDetail,
1631
1705
  {
1632
1706
  collapseClosedDetail: true,
@@ -1634,13 +1708,13 @@ function RecordsExplorer(props) {
1634
1708
  detailLabel: "Follower record details, private notes, and shared notes",
1635
1709
  detailOpen: Boolean(selected),
1636
1710
  closeHref: ctx.href({ recordId: null, detailTab: null }),
1637
- master: /* @__PURE__ */ jsxs17("div", { style: { display: "grid", gap: 14, padding: "var(--ui-space-4)" }, children: [
1638
- /* @__PURE__ */ jsxs17("h2", { style: { margin: 0, fontSize: 18 }, children: [
1711
+ master: /* @__PURE__ */ jsxs18("div", { style: { display: "grid", gap: 14, padding: "var(--ui-space-4)" }, children: [
1712
+ /* @__PURE__ */ jsxs18("h2", { style: { margin: 0, fontSize: 18 }, children: [
1639
1713
  target.name,
1640
1714
  " \xB7 ",
1641
1715
  type.replaceAll("_", " ")
1642
1716
  ] }),
1643
- /* @__PURE__ */ jsx19(
1717
+ /* @__PURE__ */ jsx20(
1644
1718
  DataTable2,
1645
1719
  {
1646
1720
  manual: true,
@@ -1653,14 +1727,14 @@ function RecordsExplorer(props) {
1653
1727
  ctx.navigate({ recordId: null, detailTab: null });
1654
1728
  },
1655
1729
  rows: page.data?.records ?? [],
1656
- columns: columns2,
1730
+ columns: columns3,
1657
1731
  rowKey: (record) => record.id,
1658
1732
  loading: page.loading,
1659
1733
  emptyState: page.error ? `Could not load records: ${page.error}` : "No records found.",
1660
1734
  ariaLabel: `${target.name} ${type} records`
1661
1735
  }
1662
1736
  ),
1663
- /* @__PURE__ */ jsx19(
1737
+ /* @__PURE__ */ jsx20(
1664
1738
  Pagination,
1665
1739
  {
1666
1740
  offset: page.data?.offset ?? offset,
@@ -1675,7 +1749,7 @@ function RecordsExplorer(props) {
1675
1749
  }
1676
1750
  )
1677
1751
  ] }),
1678
- detail: selected ? /* @__PURE__ */ jsx19(
1752
+ detail: selected ? /* @__PURE__ */ jsx20(
1679
1753
  NetworkRecordDetail,
1680
1754
  {
1681
1755
  ctx,
@@ -1692,8 +1766,8 @@ function RecordsExplorer(props) {
1692
1766
  function NetworkRecordsWorkspace(props) {
1693
1767
  const { chapter, ctx } = props;
1694
1768
  const targets = useAdminResource(ctx.getToken, "/api/admin/network/targets");
1695
- const [targetId, setTargetId] = useState14("");
1696
- const [type, setType] = useState14("");
1769
+ const [targetId, setTargetId] = useState16("");
1770
+ const [type, setType] = useState16("");
1697
1771
  const target = targets.data?.targets.find((candidate) => candidate.id === targetId) ?? targets.data?.targets[0];
1698
1772
  useEffect7(() => {
1699
1773
  if (target && target.id !== targetId) setTargetId(target.id);
@@ -1702,16 +1776,16 @@ function NetworkRecordsWorkspace(props) {
1702
1776
  const first = target?.types[0] ?? "";
1703
1777
  if (target && !target.types.includes(type)) setType(first);
1704
1778
  }, [target, type]);
1705
- if (targets.loading) return /* @__PURE__ */ jsx19(AdminNote, { children: "Loading follower records\u2026" });
1706
- if (targets.error || !targets.data) return /* @__PURE__ */ jsxs17(AdminNote, { children: [
1779
+ if (targets.loading) return /* @__PURE__ */ jsx20(AdminNote, { children: "Loading follower records\u2026" });
1780
+ if (targets.error || !targets.data) return /* @__PURE__ */ jsxs18(AdminNote, { children: [
1707
1781
  "Could not load followers",
1708
1782
  targets.error ? `: ${targets.error}` : "",
1709
1783
  "."
1710
1784
  ] });
1711
- if (!target) return /* @__PURE__ */ jsx19(AdminPage, { children: /* @__PURE__ */ jsx19(Panel, { title: "Follower records", children: /* @__PURE__ */ jsx19("p", { className: "muted", children: "No followers are configured." }) }) });
1712
- return /* @__PURE__ */ jsxs17(AdminPage, { children: [
1713
- /* @__PURE__ */ jsxs17("div", { style: { display: "flex", gap: 12, flexWrap: "wrap", alignItems: "end" }, children: [
1714
- /* @__PURE__ */ jsx19(Field6, { label: "Chapter", style: { minWidth: 240 }, children: /* @__PURE__ */ jsx19(
1785
+ if (!target) return /* @__PURE__ */ jsx20(AdminPage, { children: /* @__PURE__ */ jsx20(Panel, { title: "Follower records", children: /* @__PURE__ */ jsx20("p", { className: "muted", children: "No followers are configured." }) }) });
1786
+ return /* @__PURE__ */ jsxs18(AdminPage, { children: [
1787
+ /* @__PURE__ */ jsxs18("div", { style: { display: "flex", gap: 12, flexWrap: "wrap", alignItems: "end" }, children: [
1788
+ /* @__PURE__ */ jsx20(Field6, { label: "Chapter", style: { minWidth: 240 }, children: /* @__PURE__ */ jsx20(
1715
1789
  Select5,
1716
1790
  {
1717
1791
  value: target.id,
@@ -1723,7 +1797,7 @@ function NetworkRecordsWorkspace(props) {
1723
1797
  }
1724
1798
  }
1725
1799
  ) }),
1726
- /* @__PURE__ */ jsx19(Field6, { label: "Record type", style: { minWidth: 180 }, children: /* @__PURE__ */ jsx19(
1800
+ /* @__PURE__ */ jsx20(Field6, { label: "Record type", style: { minWidth: 180 }, children: /* @__PURE__ */ jsx20(
1727
1801
  Select5,
1728
1802
  {
1729
1803
  value: type,
@@ -1735,7 +1809,7 @@ function NetworkRecordsWorkspace(props) {
1735
1809
  }
1736
1810
  ) })
1737
1811
  ] }),
1738
- type ? /* @__PURE__ */ jsx19(
1812
+ type ? /* @__PURE__ */ jsx20(
1739
1813
  RecordsExplorer,
1740
1814
  {
1741
1815
  ctx,
@@ -1744,7 +1818,7 @@ function NetworkRecordsWorkspace(props) {
1744
1818
  leaderName: chapter.name
1745
1819
  },
1746
1820
  `${target.id}:${type}`
1747
- ) : /* @__PURE__ */ jsx19(Panel, { children: /* @__PURE__ */ jsx19("p", { className: "muted", children: "This follower has no browsable record types configured." }) })
1821
+ ) : /* @__PURE__ */ jsx20(Panel, { children: /* @__PURE__ */ jsx20("p", { className: "muted", children: "This follower has no browsable record types configured." }) })
1748
1822
  ] });
1749
1823
  }
1750
1824
  function networkRecordsWorkspace(chapter) {
@@ -1752,63 +1826,63 @@ function networkRecordsWorkspace(chapter) {
1752
1826
  id: "network",
1753
1827
  label: chapter.copy.admin.workspaces.network,
1754
1828
  defaultViewId: "records",
1755
- render: (ctx) => /* @__PURE__ */ jsx19(NetworkRecordsWorkspace, { chapter, ctx })
1829
+ render: (ctx) => /* @__PURE__ */ jsx20(NetworkRecordsWorkspace, { chapter, ctx })
1756
1830
  };
1757
1831
  }
1758
1832
 
1759
1833
  // src/ui/admin-portfolio.tsx
1760
1834
  import { StatBand as StatBand2, StepPipeline as StepPipeline2 } from "@odla-ai/ui/components";
1761
- import { jsx as jsx20, jsxs as jsxs18 } from "preact/jsx-runtime";
1835
+ import { jsx as jsx21, jsxs as jsxs19 } from "preact/jsx-runtime";
1762
1836
  function LeaderNetworkOverview({ ctx }) {
1763
1837
  const copy = useChapterCopy().admin.network;
1764
1838
  const { data, loading, error } = useAdminResource(
1765
1839
  ctx.getToken,
1766
1840
  "/api/admin/network/rollup"
1767
1841
  );
1768
- if (loading) return /* @__PURE__ */ jsx20(AdminNote, { children: copy.loadingRollup });
1769
- if (error || !data) return /* @__PURE__ */ jsxs18(AdminNote, { children: [
1842
+ if (loading) return /* @__PURE__ */ jsx21(AdminNote, { children: copy.loadingRollup });
1843
+ if (error || !data) return /* @__PURE__ */ jsxs19(AdminNote, { children: [
1770
1844
  copy.loadRollupFailed,
1771
1845
  error ? `: ${error}` : "",
1772
1846
  "."
1773
1847
  ] });
1774
- if (data.configured === 0) return /* @__PURE__ */ jsx20(AdminPage, { children: /* @__PURE__ */ jsx20(Panel, { title: copy.overview, children: /* @__PURE__ */ jsx20("p", { className: "muted", children: copy.noFollowers }) }) });
1848
+ if (data.configured === 0) return /* @__PURE__ */ jsx21(AdminPage, { children: /* @__PURE__ */ jsx21(Panel, { title: copy.overview, children: /* @__PURE__ */ jsx21("p", { className: "muted", children: copy.noFollowers }) }) });
1775
1849
  const stats = [
1776
1850
  { value: data.configured.toLocaleString(), label: copy.configuredFollowers },
1777
1851
  { value: data.available.toLocaleString(), label: copy.reachableFollowers },
1778
1852
  { value: data.totalRecords.toLocaleString(), label: copy.recordsAcrossFollowers }
1779
1853
  ];
1780
1854
  const steps = data.types.map((type) => ({
1781
- icon: /* @__PURE__ */ jsx20("span", { style: { fontSize: 22, fontWeight: 700 }, children: type.total }),
1855
+ icon: /* @__PURE__ */ jsx21("span", { style: { fontSize: 22, fontWeight: 700 }, children: type.total }),
1782
1856
  title: type.type.replaceAll("_", " "),
1783
1857
  description: Object.entries(type.stages).filter(([, count]) => count > 0).map(([stage, count]) => `${stage.replaceAll("_", " ")} ${count}`).join(" \xB7 ") || copy.noRecordTotals
1784
1858
  }));
1785
- return /* @__PURE__ */ jsxs18(AdminPage, { children: [
1786
- /* @__PURE__ */ jsx20(StatBand2, { stats }),
1787
- /* @__PURE__ */ jsx20(Panel, { title: copy.followers, children: /* @__PURE__ */ jsx20("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "grid", gap: 10 }, children: data.targets.map((target) => /* @__PURE__ */ jsxs18("li", { style: { display: "flex", gap: 12, alignItems: "baseline", flexWrap: "wrap" }, children: [
1788
- /* @__PURE__ */ jsx20("strong", { style: { minWidth: 180 }, children: target.name }),
1789
- /* @__PURE__ */ jsx20("span", { className: "badge", children: target.transport.reachable === null ? copy.transportNotChecked : target.transport.reachable ? copy.transportReachable : copy.transportUnavailable }),
1790
- /* @__PURE__ */ jsx20("span", { className: "muted", children: target.transport.kind === "binding" ? formatChapterCopy(copy.bindingTransport, { binding: target.transport.binding ?? "" }) : copy.urlTransport }),
1791
- /* @__PURE__ */ jsx20("span", { className: "muted", children: target.configuration.activeRevision === null ? copy.noActiveConfiguration : formatChapterCopy(copy.activeConfiguration, { revision: target.configuration.activeRevision }) }),
1792
- /* @__PURE__ */ jsx20("span", { className: "muted", children: target.publicSite.available === null ? copy.publicSiteNotChecked : target.publicSite.available ? copy.publicSiteAvailable : copy.publicSiteUnavailable }),
1793
- target.error ? /* @__PURE__ */ jsx20("span", { className: "muted", children: target.error }) : null,
1794
- /* @__PURE__ */ jsx20("a", { href: target.url, target: "_blank", rel: "noreferrer", style: { marginLeft: "auto" }, children: target.url })
1859
+ return /* @__PURE__ */ jsxs19(AdminPage, { children: [
1860
+ /* @__PURE__ */ jsx21(StatBand2, { stats }),
1861
+ /* @__PURE__ */ jsx21(Panel, { title: copy.followers, children: /* @__PURE__ */ jsx21("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "grid", gap: 10 }, children: data.targets.map((target) => /* @__PURE__ */ jsxs19("li", { style: { display: "flex", gap: 12, alignItems: "baseline", flexWrap: "wrap" }, children: [
1862
+ /* @__PURE__ */ jsx21("strong", { style: { minWidth: 180 }, children: target.name }),
1863
+ /* @__PURE__ */ jsx21("span", { className: "badge", children: target.transport.reachable === null ? copy.transportNotChecked : target.transport.reachable ? copy.transportReachable : copy.transportUnavailable }),
1864
+ /* @__PURE__ */ jsx21("span", { className: "muted", children: target.transport.kind === "binding" ? formatChapterCopy(copy.bindingTransport, { binding: target.transport.binding ?? "" }) : copy.urlTransport }),
1865
+ /* @__PURE__ */ jsx21("span", { className: "muted", children: target.configuration.activeRevision === null ? copy.noActiveConfiguration : formatChapterCopy(copy.activeConfiguration, { revision: target.configuration.activeRevision }) }),
1866
+ /* @__PURE__ */ jsx21("span", { className: "muted", children: target.publicSite.available === null ? copy.publicSiteNotChecked : target.publicSite.available ? copy.publicSiteAvailable : copy.publicSiteUnavailable }),
1867
+ target.error ? /* @__PURE__ */ jsx21("span", { className: "muted", children: target.error }) : null,
1868
+ /* @__PURE__ */ jsx21("a", { href: target.url, target: "_blank", rel: "noreferrer", style: { marginLeft: "auto" }, children: target.url })
1795
1869
  ] }, target.id)) }) }),
1796
- /* @__PURE__ */ jsx20(Panel, { title: copy.recordTotals, children: steps.length ? /* @__PURE__ */ jsx20(StepPipeline2, { ariaLabel: copy.recordTotals, steps }) : /* @__PURE__ */ jsx20("p", { className: "muted", children: copy.noRecordTotals }) })
1870
+ /* @__PURE__ */ jsx21(Panel, { title: copy.recordTotals, children: steps.length ? /* @__PURE__ */ jsx21(StepPipeline2, { ariaLabel: copy.recordTotals, steps }) : /* @__PURE__ */ jsx21("p", { className: "muted", children: copy.noRecordTotals }) })
1797
1871
  ] });
1798
1872
  }
1799
1873
 
1800
1874
  // src/ui/admin-admission.tsx
1801
- import { useEffect as useEffect8, useRef as useRef2, useState as useState15 } from "preact/hooks";
1802
- import { jsx as jsx21, jsxs as jsxs19 } from "preact/jsx-runtime";
1875
+ import { useEffect as useEffect8, useRef as useRef2, useState as useState17 } from "preact/hooks";
1876
+ import { jsx as jsx22, jsxs as jsxs20 } from "preact/jsx-runtime";
1803
1877
  function AdmissionGrantsWorkspace(props) {
1804
1878
  const copy = useChapterCopy().admin.admission;
1805
1879
  const resource = useAdminResource(props.getToken, "/api/admin/admission-grants");
1806
- const [email, setEmail] = useState15("");
1807
- const [decision, setDecision] = useState15("waive_interview");
1808
- const [note, setNote] = useState15("");
1809
- const [expires, setExpires] = useState15("");
1810
- const [busy, setBusy] = useState15(false);
1811
- const [error, setError] = useState15(null);
1880
+ const [email, setEmail] = useState17("");
1881
+ const [decision, setDecision] = useState17("waive_interview");
1882
+ const [note, setNote] = useState17("");
1883
+ const [expires, setExpires] = useState17("");
1884
+ const [busy, setBusy] = useState17(false);
1885
+ const [error, setError] = useState17(null);
1812
1886
  const submit = async (event) => {
1813
1887
  event.preventDefault();
1814
1888
  setBusy(true);
@@ -1845,48 +1919,48 @@ function AdmissionGrantsWorkspace(props) {
1845
1919
  setBusy(false);
1846
1920
  }
1847
1921
  };
1848
- return /* @__PURE__ */ jsxs19(AdminPage, { children: [
1849
- /* @__PURE__ */ jsxs19(Panel, { title: copy.title, children: [
1850
- /* @__PURE__ */ jsx21("p", { className: "muted", style: { margin: 0 }, children: copy.description }),
1851
- /* @__PURE__ */ jsxs19("form", { onSubmit: (event) => void submit(event), style: { display: "grid", gap: 12, gridTemplateColumns: "minmax(220px,2fr) minmax(180px,1fr) minmax(160px,1fr)" }, children: [
1852
- /* @__PURE__ */ jsxs19("label", { children: [
1922
+ return /* @__PURE__ */ jsxs20(AdminPage, { children: [
1923
+ /* @__PURE__ */ jsxs20(Panel, { title: copy.title, children: [
1924
+ /* @__PURE__ */ jsx22("p", { className: "muted", style: { margin: 0 }, children: copy.description }),
1925
+ /* @__PURE__ */ jsxs20("form", { onSubmit: (event) => void submit(event), style: { display: "grid", gap: 12, gridTemplateColumns: "minmax(220px,2fr) minmax(180px,1fr) minmax(160px,1fr)" }, children: [
1926
+ /* @__PURE__ */ jsxs20("label", { children: [
1853
1927
  copy.email,
1854
- /* @__PURE__ */ jsx21("input", { required: true, type: "email", value: email, onInput: (event) => setEmail(event.currentTarget.value) })
1928
+ /* @__PURE__ */ jsx22("input", { required: true, type: "email", value: email, onInput: (event) => setEmail(event.currentTarget.value) })
1855
1929
  ] }),
1856
- /* @__PURE__ */ jsxs19("label", { children: [
1930
+ /* @__PURE__ */ jsxs20("label", { children: [
1857
1931
  copy.decision,
1858
- /* @__PURE__ */ jsxs19("select", { value: decision, onChange: (event) => setDecision(event.currentTarget.value), children: [
1859
- /* @__PURE__ */ jsx21("option", { value: "waive_interview", children: copy.waive }),
1860
- /* @__PURE__ */ jsx21("option", { value: "require_interview", children: copy.require })
1932
+ /* @__PURE__ */ jsxs20("select", { value: decision, onChange: (event) => setDecision(event.currentTarget.value), children: [
1933
+ /* @__PURE__ */ jsx22("option", { value: "waive_interview", children: copy.waive }),
1934
+ /* @__PURE__ */ jsx22("option", { value: "require_interview", children: copy.require })
1861
1935
  ] })
1862
1936
  ] }),
1863
- /* @__PURE__ */ jsxs19("label", { children: [
1937
+ /* @__PURE__ */ jsxs20("label", { children: [
1864
1938
  copy.expires,
1865
- /* @__PURE__ */ jsx21("input", { type: "date", value: expires, onInput: (event) => setExpires(event.currentTarget.value) })
1939
+ /* @__PURE__ */ jsx22("input", { type: "date", value: expires, onInput: (event) => setExpires(event.currentTarget.value) })
1866
1940
  ] }),
1867
- /* @__PURE__ */ jsxs19("label", { style: { gridColumn: "1 / -1" }, children: [
1941
+ /* @__PURE__ */ jsxs20("label", { style: { gridColumn: "1 / -1" }, children: [
1868
1942
  copy.note,
1869
- /* @__PURE__ */ jsx21("input", { value: note, maxLength: 2e3, onInput: (event) => setNote(event.currentTarget.value) })
1943
+ /* @__PURE__ */ jsx22("input", { value: note, maxLength: 2e3, onInput: (event) => setNote(event.currentTarget.value) })
1870
1944
  ] }),
1871
- /* @__PURE__ */ jsx21("button", { className: "btn secondary", type: "submit", disabled: busy, children: copy.add })
1945
+ /* @__PURE__ */ jsx22("button", { className: "btn secondary", type: "submit", disabled: busy, children: copy.add })
1872
1946
  ] }),
1873
- error ? /* @__PURE__ */ jsx21("p", { role: "alert", children: error }) : null
1947
+ error ? /* @__PURE__ */ jsx22("p", { role: "alert", children: error }) : null
1874
1948
  ] }),
1875
- /* @__PURE__ */ jsxs19(Panel, { title: copy.ledger, children: [
1876
- resource.loading ? /* @__PURE__ */ jsx21("p", { className: "muted", children: copy.loading }) : resource.error ? /* @__PURE__ */ jsx21("p", { role: "alert", children: resource.error }) : null,
1877
- /* @__PURE__ */ jsx21("div", { style: { display: "grid", gap: 10 }, children: (resource.data?.grants ?? []).map((grant) => {
1949
+ /* @__PURE__ */ jsxs20(Panel, { title: copy.ledger, children: [
1950
+ resource.loading ? /* @__PURE__ */ jsx22("p", { className: "muted", children: copy.loading }) : resource.error ? /* @__PURE__ */ jsx22("p", { role: "alert", children: resource.error }) : null,
1951
+ /* @__PURE__ */ jsx22("div", { style: { display: "grid", gap: 10 }, children: (resource.data?.grants ?? []).map((grant) => {
1878
1952
  const state = grant.consumedAt ? copy.consumed : grant.revokedAt || !grant.active ? copy.revoked : grant.expiresAt && grant.expiresAt <= Date.now() ? copy.expired : copy.active;
1879
- return /* @__PURE__ */ jsxs19("article", { className: "card", style: { padding: 14 }, children: [
1880
- /* @__PURE__ */ jsx21("strong", { children: grant.email }),
1953
+ return /* @__PURE__ */ jsxs20("article", { className: "card", style: { padding: 14 }, children: [
1954
+ /* @__PURE__ */ jsx22("strong", { children: grant.email }),
1881
1955
  " \xB7 ",
1882
1956
  grant.decision === "waive_interview" ? copy.waive : copy.require,
1883
- /* @__PURE__ */ jsxs19("p", { className: "muted", style: { margin: "6px 0" }, children: [
1957
+ /* @__PURE__ */ jsxs20("p", { className: "muted", style: { margin: "6px 0" }, children: [
1884
1958
  grant.sourceScope === "local" ? copy.local : copy.parent,
1885
1959
  " \xB7 ",
1886
1960
  state,
1887
1961
  grant.note ? ` \xB7 ${grant.note}` : ""
1888
1962
  ] }),
1889
- grant.sourceScope === "local" && state === copy.active ? /* @__PURE__ */ jsx21("button", { className: "btn secondary mini", disabled: busy, onClick: () => void revoke(grant), children: copy.revoke }) : null
1963
+ grant.sourceScope === "local" && state === copy.active ? /* @__PURE__ */ jsx22("button", { className: "btn secondary mini", disabled: busy, onClick: () => void revoke(grant), children: copy.revoke }) : null
1890
1964
  ] }, grant.id);
1891
1965
  }) })
1892
1966
  ] })
@@ -1897,19 +1971,19 @@ function admissionGrantsWorkspace(label = "Admission") {
1897
1971
  id: "admission",
1898
1972
  label,
1899
1973
  defaultViewId: "grants",
1900
- render: (ctx) => /* @__PURE__ */ jsx21(AdmissionGrantsWorkspace, { getToken: ctx.getToken })
1974
+ render: (ctx) => /* @__PURE__ */ jsx22(AdmissionGrantsWorkspace, { getToken: ctx.getToken })
1901
1975
  };
1902
1976
  }
1903
1977
  function LeaderAdmissionAction(props) {
1904
- return /* @__PURE__ */ jsx21(LeaderAdmissionForm, { ...props }, JSON.stringify([props.targetId, props.personId, props.sourceRecordId]));
1978
+ return /* @__PURE__ */ jsx22(LeaderAdmissionForm, { ...props }, JSON.stringify([props.targetId, props.personId, props.sourceRecordId]));
1905
1979
  }
1906
1980
  function LeaderAdmissionForm(props) {
1907
- const [decision, setDecision] = useState15("");
1908
- const [note, setNote] = useState15("");
1909
- const [loaded, setLoaded] = useState15(false);
1910
- const [busy, setBusy] = useState15(false);
1911
- const [error, setError] = useState15(null);
1912
- const [status, setStatus] = useState15(null);
1981
+ const [decision, setDecision] = useState17("");
1982
+ const [note, setNote] = useState17("");
1983
+ const [loaded, setLoaded] = useState17(false);
1984
+ const [busy, setBusy] = useState17(false);
1985
+ const [error, setError] = useState17(null);
1986
+ const [status, setStatus] = useState17(null);
1913
1987
  const attempt = useRef2(null);
1914
1988
  useEffect8(() => {
1915
1989
  let live = true;
@@ -1954,22 +2028,22 @@ function LeaderAdmissionForm(props) {
1954
2028
  setBusy(false);
1955
2029
  }
1956
2030
  };
1957
- return /* @__PURE__ */ jsxs19("div", { style: { display: "grid", gap: 8 }, children: [
1958
- /* @__PURE__ */ jsxs19("label", { children: [
2031
+ return /* @__PURE__ */ jsxs20("div", { style: { display: "grid", gap: 8 }, children: [
2032
+ /* @__PURE__ */ jsxs20("label", { children: [
1959
2033
  "Interview",
1960
- /* @__PURE__ */ jsxs19("select", { disabled: !loaded || busy, value: decision, onChange: (event) => setDecision(event.currentTarget.value), children: [
1961
- /* @__PURE__ */ jsx21("option", { value: "", children: loaded ? "Choose an invitation setting" : "Loading saved setting\u2026" }),
1962
- /* @__PURE__ */ jsx21("option", { value: "waive_interview", children: "Already completed" }),
1963
- /* @__PURE__ */ jsx21("option", { value: "require_interview", children: "Required" })
2034
+ /* @__PURE__ */ jsxs20("select", { disabled: !loaded || busy, value: decision, onChange: (event) => setDecision(event.currentTarget.value), children: [
2035
+ /* @__PURE__ */ jsx22("option", { value: "", children: loaded ? "Choose an invitation setting" : "Loading saved setting\u2026" }),
2036
+ /* @__PURE__ */ jsx22("option", { value: "waive_interview", children: "Already completed" }),
2037
+ /* @__PURE__ */ jsx22("option", { value: "require_interview", children: "Required" })
1964
2038
  ] })
1965
2039
  ] }),
1966
- /* @__PURE__ */ jsxs19("label", { children: [
2040
+ /* @__PURE__ */ jsxs20("label", { children: [
1967
2041
  "Internal note",
1968
- /* @__PURE__ */ jsx21("input", { disabled: !loaded || busy, maxLength: 2e3, value: note, onInput: (event) => setNote(event.currentTarget.value) })
2042
+ /* @__PURE__ */ jsx22("input", { disabled: !loaded || busy, maxLength: 2e3, value: note, onInput: (event) => setNote(event.currentTarget.value) })
1969
2043
  ] }),
1970
- /* @__PURE__ */ jsx21("button", { className: "btn secondary", type: "button", disabled: busy || !loaded || !decision, onClick: () => void submit(), children: busy ? "Saving\u2026" : "Save invitation setting" }),
1971
- error ? /* @__PURE__ */ jsx21("p", { role: "alert", children: error }) : null,
1972
- status ? /* @__PURE__ */ jsx21("p", { role: "status", children: status }) : null
2044
+ /* @__PURE__ */ jsx22("button", { className: "btn secondary", type: "button", disabled: busy || !loaded || !decision, onClick: () => void submit(), children: busy ? "Saving\u2026" : "Save invitation setting" }),
2045
+ error ? /* @__PURE__ */ jsx22("p", { role: "alert", children: error }) : null,
2046
+ status ? /* @__PURE__ */ jsx22("p", { role: "status", children: status }) : null
1973
2047
  ] });
1974
2048
  }
1975
2049
 
@@ -1977,19 +2051,19 @@ function LeaderAdmissionForm(props) {
1977
2051
  import { Tabs as Tabs2 } from "@odla-ai/ui/components";
1978
2052
 
1979
2053
  // src/ui/admin-availability.tsx
1980
- import { useState as useState16 } from "preact/hooks";
1981
- import { Button as Button9, Checkbox, Field as Field7, Input as Input2 } from "@odla-ai/ui/components";
1982
- import { jsx as jsx22, jsxs as jsxs20 } from "preact/jsx-runtime";
2054
+ import { useState as useState18 } from "preact/hooks";
2055
+ import { Button as Button11, Checkbox, Field as Field7, Input as Input2 } from "@odla-ai/ui/components";
2056
+ import { jsx as jsx23, jsxs as jsxs21 } from "preact/jsx-runtime";
1983
2057
  function AvailabilityBody({ ctx }) {
1984
2058
  const copy = useChapterCopy().admin.availability;
1985
2059
  const { data, loading, error, refresh } = useAdminResource(ctx.getToken, "/api/admin/scheduling");
1986
- const [draft, setDraft] = useState16(null);
1987
- const [busy, setBusy] = useState16(false);
1988
- const [note, setNote] = useState16(null);
1989
- const [errors, setErrors] = useState16({});
2060
+ const [draft, setDraft] = useState18(null);
2061
+ const [busy, setBusy] = useState18(false);
2062
+ const [note, setNote] = useState18(null);
2063
+ const [errors, setErrors] = useState18({});
1990
2064
  const cfg = draft ?? data?.scheduling ?? null;
1991
- if (loading) return /* @__PURE__ */ jsx22(AdminNote, { children: copy.loading });
1992
- if (error || !cfg) return /* @__PURE__ */ jsxs20(AdminNote, { children: [
2065
+ if (loading) return /* @__PURE__ */ jsx23(AdminNote, { children: copy.loading });
2066
+ if (error || !cfg) return /* @__PURE__ */ jsxs21(AdminNote, { children: [
1993
2067
  copy.loadFailed,
1994
2068
  error ? `: ${error}` : "",
1995
2069
  "."
@@ -2019,29 +2093,29 @@ function AvailabilityBody({ ctx }) {
2019
2093
  setBusy(false);
2020
2094
  }
2021
2095
  };
2022
- const numField = (key, label) => /* @__PURE__ */ jsx22(Field7, { label, error: errors[key], children: /* @__PURE__ */ jsx22(Input2, { type: "number", value: cfg[key], onInput: (e) => edit({ [key]: num(e.target.value, cfg[key]) }) }) });
2023
- return /* @__PURE__ */ jsx22(AdminPage, { children: /* @__PURE__ */ jsxs20(Panel, { title: copy.title, actions: note ? /* @__PURE__ */ jsx22("span", { className: "muted", children: note }) : void 0, children: [
2024
- /* @__PURE__ */ jsx22(Field7, { label: copy.days, error: errors.days, children: /* @__PURE__ */ jsx22("div", { style: { display: "flex", gap: 14, flexWrap: "wrap" }, children: copy.dayLabels.map((d, i) => /* @__PURE__ */ jsx22(Checkbox, { label: d, checked: cfg.days.includes(i), onChange: () => toggleDay(i) }, d)) }) }),
2025
- /* @__PURE__ */ jsxs20("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))", gap: 14 }, children: [
2096
+ const numField = (key, label) => /* @__PURE__ */ jsx23(Field7, { label, error: errors[key], children: /* @__PURE__ */ jsx23(Input2, { type: "number", value: cfg[key], onInput: (e) => edit({ [key]: num(e.target.value, cfg[key]) }) }) });
2097
+ return /* @__PURE__ */ jsx23(AdminPage, { children: /* @__PURE__ */ jsxs21(Panel, { title: copy.title, actions: note ? /* @__PURE__ */ jsx23("span", { className: "muted", children: note }) : void 0, children: [
2098
+ /* @__PURE__ */ jsx23(Field7, { label: copy.days, error: errors.days, children: /* @__PURE__ */ jsx23("div", { style: { display: "flex", gap: 14, flexWrap: "wrap" }, children: copy.dayLabels.map((d, i) => /* @__PURE__ */ jsx23(Checkbox, { label: d, checked: cfg.days.includes(i), onChange: () => toggleDay(i) }, d)) }) }),
2099
+ /* @__PURE__ */ jsxs21("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))", gap: 14 }, children: [
2026
2100
  numField("startHour", copy.startHour),
2027
2101
  numField("endHour", copy.endHour),
2028
2102
  numField("slotMinutes", copy.slotMinutes),
2029
2103
  numField("minNoticeHours", copy.minNoticeHours),
2030
2104
  numField("windowDays", copy.windowDays),
2031
- /* @__PURE__ */ jsx22(Field7, { label: copy.timezone, error: errors.timezone, children: /* @__PURE__ */ jsx22(Input2, { value: cfg.timezone, onInput: (e) => edit({ timezone: e.target.value }) }) })
2105
+ /* @__PURE__ */ jsx23(Field7, { label: copy.timezone, error: errors.timezone, children: /* @__PURE__ */ jsx23(Input2, { value: cfg.timezone, onInput: (e) => edit({ timezone: e.target.value }) }) })
2032
2106
  ] }),
2033
- /* @__PURE__ */ jsx22(Field7, { label: copy.summaryTemplate, error: errors.summaryTemplate, children: /* @__PURE__ */ jsx22(Input2, { value: cfg.summaryTemplate, onInput: (e) => edit({ summaryTemplate: e.target.value }) }) }),
2034
- /* @__PURE__ */ jsx22("div", { children: /* @__PURE__ */ jsx22(Button9, { disabled: !draft || busy, onClick: () => void save(), children: copy.save }) })
2107
+ /* @__PURE__ */ jsx23(Field7, { label: copy.summaryTemplate, error: errors.summaryTemplate, children: /* @__PURE__ */ jsx23(Input2, { value: cfg.summaryTemplate, onInput: (e) => edit({ summaryTemplate: e.target.value }) }) }),
2108
+ /* @__PURE__ */ jsx23("div", { children: /* @__PURE__ */ jsx23(Button11, { disabled: !draft || busy, onClick: () => void save(), children: copy.save }) })
2035
2109
  ] }) });
2036
2110
  }
2037
2111
  function availabilitySection(options = {}) {
2038
2112
  const { id = "availability", label = "Availability" } = options;
2039
- return { id, label, render: (ctx) => /* @__PURE__ */ jsx22(AvailabilityBody, { ctx }) };
2113
+ return { id, label, render: (ctx) => /* @__PURE__ */ jsx23(AvailabilityBody, { ctx }) };
2040
2114
  }
2041
2115
 
2042
2116
  // src/ui/admin-builder-library.tsx
2043
- import { useEffect as useEffect9, useMemo as useMemo2, useState as useState17 } from "preact/hooks";
2044
- import { jsx as jsx23, jsxs as jsxs21 } from "preact/jsx-runtime";
2117
+ import { useEffect as useEffect9, useMemo as useMemo2, useState as useState19 } from "preact/hooks";
2118
+ import { jsx as jsx24, jsxs as jsxs22 } from "preact/jsx-runtime";
2045
2119
  var KINDS = ["document", "note", "link", "inspiration", "image", "file"];
2046
2120
  var KIND_LABEL = { document: "Document", note: "Note", link: "Link", inspiration: "Inspiration", image: "Image", file: "File" };
2047
2121
  var STATUS_LABEL = { draft: "Draft", published: "Published", archived: "Archived" };
@@ -2073,13 +2147,13 @@ function localResource(kind, chapterId, mode) {
2073
2147
  };
2074
2148
  }
2075
2149
  function ResourcePreview({ item }) {
2076
- return /* @__PURE__ */ jsxs21("div", { className: "card", style: { padding: 14 }, children: [
2077
- /* @__PURE__ */ jsx23("div", { className: "card-label", children: "Preview" }),
2078
- /* @__PURE__ */ jsx23("h3", { style: { margin: "6px 0" }, children: item.title || "Untitled" }),
2079
- item.summary ? /* @__PURE__ */ jsx23("p", { style: { margin: "0 0 10px" }, children: item.summary }) : null,
2080
- item.bodyMarkdown ? /* @__PURE__ */ jsx23("pre", { style: { margin: 0, whiteSpace: "pre-wrap", font: "inherit", lineHeight: 1.55 }, children: item.bodyMarkdown }) : null,
2081
- item.url ? /* @__PURE__ */ jsx23("a", { href: item.url, target: "_blank", rel: "noreferrer", children: item.url }) : null,
2082
- item.brandAsset ? /* @__PURE__ */ jsxs21("div", { style: META, children: [
2150
+ return /* @__PURE__ */ jsxs22("div", { className: "card", style: { padding: 14 }, children: [
2151
+ /* @__PURE__ */ jsx24("div", { className: "card-label", children: "Preview" }),
2152
+ /* @__PURE__ */ jsx24("h3", { style: { margin: "6px 0" }, children: item.title || "Untitled" }),
2153
+ item.summary ? /* @__PURE__ */ jsx24("p", { style: { margin: "0 0 10px" }, children: item.summary }) : null,
2154
+ item.bodyMarkdown ? /* @__PURE__ */ jsx24("pre", { style: { margin: 0, whiteSpace: "pre-wrap", font: "inherit", lineHeight: 1.55 }, children: item.bodyMarkdown }) : null,
2155
+ item.url ? /* @__PURE__ */ jsx24("a", { href: item.url, target: "_blank", rel: "noreferrer", children: item.url }) : null,
2156
+ item.brandAsset ? /* @__PURE__ */ jsxs22("div", { style: META, children: [
2083
2157
  "Brand asset \xB7 ",
2084
2158
  item.brandAsset.bookId,
2085
2159
  " / ",
@@ -2091,14 +2165,14 @@ function ResourcePreview({ item }) {
2091
2165
  function BuilderLibraryAdmin({ ctx, initialData }) {
2092
2166
  const remote = useAdminResource(ctx.getToken, "/api/admin/builder-library");
2093
2167
  const seed = initialData ?? remote.data;
2094
- const [resources, setResources] = useState17(() => [...seed?.local?.document.resources ?? []]);
2095
- const [selectedKey, setSelectedKey] = useState17(() => seed?.local?.document.resources[0]?.id ? localKey(seed.local.document.resources[0].id) : null);
2096
- const [query, setQuery] = useState17("");
2097
- const [kindFilter, setKindFilter] = useState17("all");
2098
- const [statusFilter, setStatusFilter] = useState17("all");
2099
- const [newKind, setNewKind] = useState17("document");
2100
- const [saveError, setSaveError] = useState17(null);
2101
- const [saving, setSaving] = useState17(false);
2168
+ const [resources, setResources] = useState19(() => [...seed?.local?.document.resources ?? []]);
2169
+ const [selectedKey, setSelectedKey] = useState19(() => seed?.local?.document.resources[0]?.id ? localKey(seed.local.document.resources[0].id) : null);
2170
+ const [query, setQuery] = useState19("");
2171
+ const [kindFilter, setKindFilter] = useState19("all");
2172
+ const [statusFilter, setStatusFilter] = useState19("all");
2173
+ const [newKind, setNewKind] = useState19("document");
2174
+ const [saveError, setSaveError] = useState19(null);
2175
+ const [saving, setSaving] = useState19(false);
2102
2176
  useEffect9(() => {
2103
2177
  if (!remote.data) return;
2104
2178
  const next = [...remote.data.local?.document.resources ?? []];
@@ -2115,8 +2189,8 @@ function BuilderLibraryAdmin({ ctx, initialData }) {
2115
2189
  return (!query.trim() || haystack.includes(query.toLowerCase().trim())) && (kindFilter === "all" || resource.kind === kindFilter) && (statusFilter === "all" || resource.status === statusFilter);
2116
2190
  });
2117
2191
  const selected = entries.find((entry) => entry.key === selectedKey) ?? visible[0] ?? null;
2118
- if (!data && remote.loading) return /* @__PURE__ */ jsx23(AdminPage, { children: /* @__PURE__ */ jsx23(AdminNote, { children: "Loading Builder Library\u2026" }) });
2119
- if (remote.error || !data) return /* @__PURE__ */ jsx23(AdminPage, { children: /* @__PURE__ */ jsxs21(AdminNote, { children: [
2192
+ if (!data && remote.loading) return /* @__PURE__ */ jsx24(AdminPage, { children: /* @__PURE__ */ jsx24(AdminNote, { children: "Loading Builder Library\u2026" }) });
2193
+ if (remote.error || !data) return /* @__PURE__ */ jsx24(AdminPage, { children: /* @__PURE__ */ jsxs22(AdminNote, { children: [
2120
2194
  "Builder Library could not be loaded: ",
2121
2195
  remote.error ?? "unknown error"
2122
2196
  ] }) });
@@ -2152,170 +2226,170 @@ function BuilderLibraryAdmin({ ctx, initialData }) {
2152
2226
  }
2153
2227
  };
2154
2228
  const scopeValue = selected?.resource.scope.kind === "chapter" ? `chapter:${selected.resource.scope.chapterId}` : selected?.resource.scope.kind ?? "built_not_found";
2155
- return /* @__PURE__ */ jsxs21(AdminPage, { children: [
2156
- /* @__PURE__ */ jsxs21(Panel, { title: /* @__PURE__ */ jsxs21("span", { children: [
2229
+ return /* @__PURE__ */ jsxs22(AdminPage, { children: [
2230
+ /* @__PURE__ */ jsxs22(Panel, { title: /* @__PURE__ */ jsxs22("span", { children: [
2157
2231
  "Builder Library ",
2158
- /* @__PURE__ */ jsx23("span", { className: "muted", children: "\xB7 private" })
2159
- ] }), actions: /* @__PURE__ */ jsxs21("div", { style: ROW, children: [
2160
- /* @__PURE__ */ jsx23("select", { "aria-label": "New resource type", value: newKind, onChange: (event) => setNewKind(event.currentTarget.value), children: KINDS.map((kind) => /* @__PURE__ */ jsx23("option", { value: kind, children: KIND_LABEL[kind] }, kind)) }),
2161
- /* @__PURE__ */ jsx23("button", { className: "btn primary", type: "button", disabled: !data.localAuthoring, onClick: add, children: "Add resource" })
2232
+ /* @__PURE__ */ jsx24("span", { className: "muted", children: "\xB7 private" })
2233
+ ] }), actions: /* @__PURE__ */ jsxs22("div", { style: ROW, children: [
2234
+ /* @__PURE__ */ jsx24("select", { "aria-label": "New resource type", value: newKind, onChange: (event) => setNewKind(event.currentTarget.value), children: KINDS.map((kind) => /* @__PURE__ */ jsx24("option", { value: kind, children: KIND_LABEL[kind] }, kind)) }),
2235
+ /* @__PURE__ */ jsx24("button", { className: "btn primary", type: "button", disabled: !data.localAuthoring, onClick: add, children: "Add resource" })
2162
2236
  ] }), children: [
2163
- /* @__PURE__ */ jsx23("p", { className: "muted", style: { margin: 0 }, children: "Documents, links, and Brand assets used by site-building agents. Nothing here appears on a member page." }),
2164
- /* @__PURE__ */ jsxs21("div", { style: ROW, children: [
2165
- /* @__PURE__ */ jsx23("input", { "aria-label": "Search resources", placeholder: "Search resources", value: query, onInput: (event) => setQuery(event.currentTarget.value), style: { flex: "1 1 220px" } }),
2166
- /* @__PURE__ */ jsxs21("select", { "aria-label": "Filter by type", value: kindFilter, onChange: (event) => setKindFilter(event.currentTarget.value), children: [
2167
- /* @__PURE__ */ jsx23("option", { value: "all", children: "All types" }),
2168
- KINDS.map((kind) => /* @__PURE__ */ jsx23("option", { value: kind, children: KIND_LABEL[kind] }, kind))
2237
+ /* @__PURE__ */ jsx24("p", { className: "muted", style: { margin: 0 }, children: "Documents, links, and Brand assets used by site-building agents. Nothing here appears on a member page." }),
2238
+ /* @__PURE__ */ jsxs22("div", { style: ROW, children: [
2239
+ /* @__PURE__ */ jsx24("input", { "aria-label": "Search resources", placeholder: "Search resources", value: query, onInput: (event) => setQuery(event.currentTarget.value), style: { flex: "1 1 220px" } }),
2240
+ /* @__PURE__ */ jsxs22("select", { "aria-label": "Filter by type", value: kindFilter, onChange: (event) => setKindFilter(event.currentTarget.value), children: [
2241
+ /* @__PURE__ */ jsx24("option", { value: "all", children: "All types" }),
2242
+ KINDS.map((kind) => /* @__PURE__ */ jsx24("option", { value: kind, children: KIND_LABEL[kind] }, kind))
2169
2243
  ] }),
2170
- /* @__PURE__ */ jsxs21("select", { "aria-label": "Filter by status", value: statusFilter, onChange: (event) => setStatusFilter(event.currentTarget.value), children: [
2171
- /* @__PURE__ */ jsx23("option", { value: "all", children: "All statuses" }),
2172
- /* @__PURE__ */ jsx23("option", { value: "draft", children: "Draft" }),
2173
- /* @__PURE__ */ jsx23("option", { value: "published", children: "Published" }),
2174
- /* @__PURE__ */ jsx23("option", { value: "archived", children: "Archived" })
2244
+ /* @__PURE__ */ jsxs22("select", { "aria-label": "Filter by status", value: statusFilter, onChange: (event) => setStatusFilter(event.currentTarget.value), children: [
2245
+ /* @__PURE__ */ jsx24("option", { value: "all", children: "All statuses" }),
2246
+ /* @__PURE__ */ jsx24("option", { value: "draft", children: "Draft" }),
2247
+ /* @__PURE__ */ jsx24("option", { value: "published", children: "Published" }),
2248
+ /* @__PURE__ */ jsx24("option", { value: "archived", children: "Archived" })
2175
2249
  ] })
2176
2250
  ] })
2177
2251
  ] }),
2178
- /* @__PURE__ */ jsxs21("div", { style: GRID, "data-builder-library-cms": true, children: [
2179
- /* @__PURE__ */ jsx23(Panel, { title: `${visible.length} resource${visible.length === 1 ? "" : "s"}`, children: /* @__PURE__ */ jsx23("div", { style: { ...STACK, maxHeight: "70vh", overflow: "auto" }, children: visible.length === 0 ? /* @__PURE__ */ jsx23("p", { className: "muted", children: "No resources match these filters." }) : visible.map((entry) => /* @__PURE__ */ jsxs21("button", { type: "button", style: { ...ITEM, ...selected?.key === entry.key ? { borderColor: "var(--ui-accent)", boxShadow: "0 0 0 1px var(--ui-accent)" } : {} }, onClick: () => setSelectedKey(entry.key), children: [
2180
- /* @__PURE__ */ jsxs21("div", { style: { ...ROW, justifyContent: "space-between" }, children: [
2181
- /* @__PURE__ */ jsx23("strong", { children: entry.resource.title }),
2182
- /* @__PURE__ */ jsx23("span", { className: "badge", children: KIND_LABEL[entry.resource.kind] })
2252
+ /* @__PURE__ */ jsxs22("div", { style: GRID, "data-builder-library-cms": true, children: [
2253
+ /* @__PURE__ */ jsx24(Panel, { title: `${visible.length} resource${visible.length === 1 ? "" : "s"}`, children: /* @__PURE__ */ jsx24("div", { style: { ...STACK, maxHeight: "70vh", overflow: "auto" }, children: visible.length === 0 ? /* @__PURE__ */ jsx24("p", { className: "muted", children: "No resources match these filters." }) : visible.map((entry) => /* @__PURE__ */ jsxs22("button", { type: "button", style: { ...ITEM, ...selected?.key === entry.key ? { borderColor: "var(--ui-accent)", boxShadow: "0 0 0 1px var(--ui-accent)" } : {} }, onClick: () => setSelectedKey(entry.key), children: [
2254
+ /* @__PURE__ */ jsxs22("div", { style: { ...ROW, justifyContent: "space-between" }, children: [
2255
+ /* @__PURE__ */ jsx24("strong", { children: entry.resource.title }),
2256
+ /* @__PURE__ */ jsx24("span", { className: "badge", children: KIND_LABEL[entry.resource.kind] })
2183
2257
  ] }),
2184
- /* @__PURE__ */ jsx23("p", { className: "muted", style: { margin: "6px 0", lineHeight: 1.4 }, children: contentSummary(entry.resource) }),
2185
- /* @__PURE__ */ jsxs21("div", { style: META, children: [
2186
- /* @__PURE__ */ jsx23("span", { children: STATUS_LABEL[entry.resource.status] }),
2187
- /* @__PURE__ */ jsx23("span", { children: "\xB7" }),
2188
- /* @__PURE__ */ jsx23("span", { children: scopeLabel(entry.resource.scope) }),
2189
- /* @__PURE__ */ jsx23("span", { children: "\xB7" }),
2190
- /* @__PURE__ */ jsx23("span", { children: entry.sourceId })
2258
+ /* @__PURE__ */ jsx24("p", { className: "muted", style: { margin: "6px 0", lineHeight: 1.4 }, children: contentSummary(entry.resource) }),
2259
+ /* @__PURE__ */ jsxs22("div", { style: META, children: [
2260
+ /* @__PURE__ */ jsx24("span", { children: STATUS_LABEL[entry.resource.status] }),
2261
+ /* @__PURE__ */ jsx24("span", { children: "\xB7" }),
2262
+ /* @__PURE__ */ jsx24("span", { children: scopeLabel(entry.resource.scope) }),
2263
+ /* @__PURE__ */ jsx24("span", { children: "\xB7" }),
2264
+ /* @__PURE__ */ jsx24("span", { children: entry.sourceId })
2191
2265
  ] })
2192
2266
  ] }, entry.key)) }) }),
2193
- /* @__PURE__ */ jsxs21(Panel, { title: selected ? selected.resource.title : "Select a resource", actions: selected?.local ? /* @__PURE__ */ jsxs21("div", { style: ROW, children: [
2194
- /* @__PURE__ */ jsx23("button", { className: "btn secondary", type: "button", disabled: saving, onClick: () => update({ status: selected.resource.status === "archived" ? "draft" : "archived" }), children: selected.resource.status === "archived" ? "Restore draft" : "Archive" }),
2195
- /* @__PURE__ */ jsx23("button", { className: "btn primary", type: "button", disabled: !data.localAuthoring || saving, onClick: () => void save(), children: saving ? "Saving\u2026" : "Save changes" })
2267
+ /* @__PURE__ */ jsxs22(Panel, { title: selected ? selected.resource.title : "Select a resource", actions: selected?.local ? /* @__PURE__ */ jsxs22("div", { style: ROW, children: [
2268
+ /* @__PURE__ */ jsx24("button", { className: "btn secondary", type: "button", disabled: saving, onClick: () => update({ status: selected.resource.status === "archived" ? "draft" : "archived" }), children: selected.resource.status === "archived" ? "Restore draft" : "Archive" }),
2269
+ /* @__PURE__ */ jsx24("button", { className: "btn primary", type: "button", disabled: !data.localAuthoring || saving, onClick: () => void save(), children: saving ? "Saving\u2026" : "Save changes" })
2196
2270
  ] }) : null, children: [
2197
- !selected ? /* @__PURE__ */ jsx23("p", { className: "muted", children: "Add a resource or choose one from the list." }) : selected.local ? /* @__PURE__ */ jsx23(LocalEditor, { selected: selected.resource, data, scopeValue, saving, update, setResources, setSelectedKey }) : /* @__PURE__ */ jsxs21("div", { style: STACK, children: [
2198
- /* @__PURE__ */ jsxs21("div", { style: META, children: [
2271
+ !selected ? /* @__PURE__ */ jsx24("p", { className: "muted", children: "Add a resource or choose one from the list." }) : selected.local ? /* @__PURE__ */ jsx24(LocalEditor, { selected: selected.resource, data, scopeValue, saving, update, setResources, setSelectedKey }) : /* @__PURE__ */ jsxs22("div", { style: STACK, children: [
2272
+ /* @__PURE__ */ jsxs22("div", { style: META, children: [
2199
2273
  "Read only \xB7 supplied by ",
2200
2274
  selected.sourceId,
2201
2275
  " \xB7 source revision ",
2202
2276
  selected.sourceRevision
2203
2277
  ] }),
2204
- /* @__PURE__ */ jsxs21("div", { children: [
2205
- /* @__PURE__ */ jsx23("span", { className: "badge", children: STATUS_LABEL[selected.resource.status] }),
2278
+ /* @__PURE__ */ jsxs22("div", { children: [
2279
+ /* @__PURE__ */ jsx24("span", { className: "badge", children: STATUS_LABEL[selected.resource.status] }),
2206
2280
  " ",
2207
- /* @__PURE__ */ jsx23("span", { className: "badge", children: scopeLabel(selected.resource.scope) })
2281
+ /* @__PURE__ */ jsx24("span", { className: "badge", children: scopeLabel(selected.resource.scope) })
2208
2282
  ] }),
2209
- /* @__PURE__ */ jsx23(ResourcePreview, { item: selected.resource }),
2210
- data.mode === "hub" && selected.resource.scope.kind === "chapter" ? /* @__PURE__ */ jsx23("button", { className: "btn secondary", type: "button", onClick: () => void promote(selected), children: "Copy to all chapters" }) : null
2283
+ /* @__PURE__ */ jsx24(ResourcePreview, { item: selected.resource }),
2284
+ data.mode === "hub" && selected.resource.scope.kind === "chapter" ? /* @__PURE__ */ jsx24("button", { className: "btn secondary", type: "button", onClick: () => void promote(selected), children: "Copy to all chapters" }) : null
2211
2285
  ] }),
2212
- saveError ? /* @__PURE__ */ jsxs21("div", { className: "notice danger", role: "alert", children: [
2213
- /* @__PURE__ */ jsx23("strong", { children: "Fix these items before saving:" }),
2214
- /* @__PURE__ */ jsx23("ul", { children: saveError.map((error) => /* @__PURE__ */ jsx23("li", { children: error }, error)) })
2286
+ saveError ? /* @__PURE__ */ jsxs22("div", { className: "notice danger", role: "alert", children: [
2287
+ /* @__PURE__ */ jsx24("strong", { children: "Fix these items before saving:" }),
2288
+ /* @__PURE__ */ jsx24("ul", { children: saveError.map((error) => /* @__PURE__ */ jsx24("li", { children: error }, error)) })
2215
2289
  ] }) : null
2216
2290
  ] })
2217
2291
  ] })
2218
2292
  ] });
2219
2293
  }
2220
2294
  function LocalEditor({ selected, data, scopeValue, update, setResources, setSelectedKey }) {
2221
- return /* @__PURE__ */ jsxs21("div", { style: STACK, children: [
2222
- /* @__PURE__ */ jsxs21("div", { style: META, children: [
2295
+ return /* @__PURE__ */ jsxs22("div", { style: STACK, children: [
2296
+ /* @__PURE__ */ jsxs22("div", { style: META, children: [
2223
2297
  "Local \xB7 resource revision ",
2224
2298
  selected.revision,
2225
2299
  " \xB7 library revision ",
2226
2300
  data.local?.revision ?? 0
2227
2301
  ] }),
2228
- /* @__PURE__ */ jsxs21("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }, children: [
2229
- /* @__PURE__ */ jsxs21("label", { className: "field", children: [
2230
- /* @__PURE__ */ jsx23("span", { children: "Title" }),
2231
- /* @__PURE__ */ jsx23("input", { value: selected.title, onInput: (event) => update({ title: event.currentTarget.value }) })
2302
+ /* @__PURE__ */ jsxs22("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }, children: [
2303
+ /* @__PURE__ */ jsxs22("label", { className: "field", children: [
2304
+ /* @__PURE__ */ jsx24("span", { children: "Title" }),
2305
+ /* @__PURE__ */ jsx24("input", { value: selected.title, onInput: (event) => update({ title: event.currentTarget.value }) })
2232
2306
  ] }),
2233
- /* @__PURE__ */ jsxs21("label", { className: "field", children: [
2234
- /* @__PURE__ */ jsx23("span", { children: "ID" }),
2235
- /* @__PURE__ */ jsx23("input", { value: selected.id, onInput: (event) => {
2307
+ /* @__PURE__ */ jsxs22("label", { className: "field", children: [
2308
+ /* @__PURE__ */ jsx24("span", { children: "ID" }),
2309
+ /* @__PURE__ */ jsx24("input", { value: selected.id, onInput: (event) => {
2236
2310
  const id = cleanId(event.currentTarget.value);
2237
2311
  setResources((items) => items.map((item) => item.id === selected.id ? { ...item, id } : item));
2238
2312
  setSelectedKey(localKey(id));
2239
2313
  } })
2240
2314
  ] }),
2241
- /* @__PURE__ */ jsxs21("label", { className: "field", children: [
2242
- /* @__PURE__ */ jsx23("span", { children: "Type" }),
2243
- /* @__PURE__ */ jsx23("select", { value: selected.kind, onChange: (event) => {
2315
+ /* @__PURE__ */ jsxs22("label", { className: "field", children: [
2316
+ /* @__PURE__ */ jsx24("span", { children: "Type" }),
2317
+ /* @__PURE__ */ jsx24("select", { value: selected.kind, onChange: (event) => {
2244
2318
  const kind = event.currentTarget.value;
2245
2319
  update({ kind, bodyMarkdown: kind === "document" || kind === "note" ? selected.bodyMarkdown ?? "Start writing\u2026" : void 0, url: kind === "link" || kind === "inspiration" ? selected.url ?? "https://example.com" : void 0, brandAsset: kind === "image" || kind === "file" ? selected.brandAsset ?? { bookId: "brand-book", assetId: "replace-me" } : void 0 });
2246
- }, children: KINDS.map((kind) => /* @__PURE__ */ jsx23("option", { value: kind, children: KIND_LABEL[kind] }, kind)) })
2320
+ }, children: KINDS.map((kind) => /* @__PURE__ */ jsx24("option", { value: kind, children: KIND_LABEL[kind] }, kind)) })
2247
2321
  ] }),
2248
- /* @__PURE__ */ jsxs21("label", { className: "field", children: [
2249
- /* @__PURE__ */ jsx23("span", { children: "Status" }),
2250
- /* @__PURE__ */ jsxs21("select", { value: selected.status, onChange: (event) => update({ status: event.currentTarget.value }), children: [
2251
- /* @__PURE__ */ jsx23("option", { value: "draft", children: "Draft" }),
2252
- /* @__PURE__ */ jsx23("option", { value: "published", children: "Published" }),
2253
- /* @__PURE__ */ jsx23("option", { value: "archived", children: "Archived" })
2322
+ /* @__PURE__ */ jsxs22("label", { className: "field", children: [
2323
+ /* @__PURE__ */ jsx24("span", { children: "Status" }),
2324
+ /* @__PURE__ */ jsxs22("select", { value: selected.status, onChange: (event) => update({ status: event.currentTarget.value }), children: [
2325
+ /* @__PURE__ */ jsx24("option", { value: "draft", children: "Draft" }),
2326
+ /* @__PURE__ */ jsx24("option", { value: "published", children: "Published" }),
2327
+ /* @__PURE__ */ jsx24("option", { value: "archived", children: "Archived" })
2254
2328
  ] })
2255
2329
  ] }),
2256
- /* @__PURE__ */ jsxs21("label", { className: "field", children: [
2257
- /* @__PURE__ */ jsx23("span", { children: "Visible to" }),
2258
- /* @__PURE__ */ jsxs21("select", { value: scopeValue, onChange: (event) => {
2330
+ /* @__PURE__ */ jsxs22("label", { className: "field", children: [
2331
+ /* @__PURE__ */ jsx24("span", { children: "Visible to" }),
2332
+ /* @__PURE__ */ jsxs22("select", { value: scopeValue, onChange: (event) => {
2259
2333
  const value = event.currentTarget.value;
2260
2334
  update({ scope: value === "global" ? { kind: "global" } : value === "built_not_found" ? { kind: "built_not_found" } : { kind: "chapter", chapterId: value.slice("chapter:".length) } });
2261
2335
  }, children: [
2262
- data.mode === "hub" ? /* @__PURE__ */ jsx23("option", { value: "built_not_found", children: "Built Not Found only" }) : null,
2263
- data.mode === "hub" ? /* @__PURE__ */ jsx23("option", { value: "global", children: "All chapters" }) : null,
2264
- data.chapterTargets.map(({ chapterId }) => /* @__PURE__ */ jsxs21("option", { value: `chapter:${chapterId}`, children: [
2336
+ data.mode === "hub" ? /* @__PURE__ */ jsx24("option", { value: "built_not_found", children: "Built Not Found only" }) : null,
2337
+ data.mode === "hub" ? /* @__PURE__ */ jsx24("option", { value: "global", children: "All chapters" }) : null,
2338
+ data.chapterTargets.map(({ chapterId }) => /* @__PURE__ */ jsxs22("option", { value: `chapter:${chapterId}`, children: [
2265
2339
  "Only ",
2266
2340
  chapterId
2267
2341
  ] }, chapterId))
2268
2342
  ] })
2269
2343
  ] }),
2270
- /* @__PURE__ */ jsxs21("label", { className: "field", children: [
2271
- /* @__PURE__ */ jsx23("span", { children: "Tags" }),
2272
- /* @__PURE__ */ jsx23("input", { value: selected.tags.join(", "), placeholder: "brand, membership", onInput: (event) => update({ tags: event.currentTarget.value.split(",").map((tag) => tag.trim()).filter(Boolean) }) })
2344
+ /* @__PURE__ */ jsxs22("label", { className: "field", children: [
2345
+ /* @__PURE__ */ jsx24("span", { children: "Tags" }),
2346
+ /* @__PURE__ */ jsx24("input", { value: selected.tags.join(", "), placeholder: "brand, membership", onInput: (event) => update({ tags: event.currentTarget.value.split(",").map((tag) => tag.trim()).filter(Boolean) }) })
2273
2347
  ] })
2274
2348
  ] }),
2275
- /* @__PURE__ */ jsxs21("label", { className: "field", children: [
2276
- /* @__PURE__ */ jsx23("span", { children: "Summary" }),
2277
- /* @__PURE__ */ jsx23("textarea", { rows: 2, value: selected.summary ?? "", onInput: (event) => update({ summary: event.currentTarget.value || void 0 }) })
2349
+ /* @__PURE__ */ jsxs22("label", { className: "field", children: [
2350
+ /* @__PURE__ */ jsx24("span", { children: "Summary" }),
2351
+ /* @__PURE__ */ jsx24("textarea", { rows: 2, value: selected.summary ?? "", onInput: (event) => update({ summary: event.currentTarget.value || void 0 }) })
2278
2352
  ] }),
2279
- selected.kind === "document" || selected.kind === "note" ? /* @__PURE__ */ jsxs21("label", { className: "field", children: [
2280
- /* @__PURE__ */ jsx23("span", { children: "Markdown" }),
2281
- /* @__PURE__ */ jsx23("textarea", { rows: 12, value: selected.bodyMarkdown ?? "", onInput: (event) => update({ bodyMarkdown: event.currentTarget.value }) })
2353
+ selected.kind === "document" || selected.kind === "note" ? /* @__PURE__ */ jsxs22("label", { className: "field", children: [
2354
+ /* @__PURE__ */ jsx24("span", { children: "Markdown" }),
2355
+ /* @__PURE__ */ jsx24("textarea", { rows: 12, value: selected.bodyMarkdown ?? "", onInput: (event) => update({ bodyMarkdown: event.currentTarget.value }) })
2282
2356
  ] }) : null,
2283
- selected.kind === "link" || selected.kind === "inspiration" ? /* @__PURE__ */ jsxs21("label", { className: "field", children: [
2284
- /* @__PURE__ */ jsx23("span", { children: "HTTPS URL" }),
2285
- /* @__PURE__ */ jsx23("input", { type: "url", value: selected.url ?? "", onInput: (event) => update({ url: event.currentTarget.value }) })
2357
+ selected.kind === "link" || selected.kind === "inspiration" ? /* @__PURE__ */ jsxs22("label", { className: "field", children: [
2358
+ /* @__PURE__ */ jsx24("span", { children: "HTTPS URL" }),
2359
+ /* @__PURE__ */ jsx24("input", { type: "url", value: selected.url ?? "", onInput: (event) => update({ url: event.currentTarget.value }) })
2286
2360
  ] }) : null,
2287
- selected.kind === "image" || selected.kind === "file" ? /* @__PURE__ */ jsxs21("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }, children: [
2288
- /* @__PURE__ */ jsxs21("label", { className: "field", children: [
2289
- /* @__PURE__ */ jsx23("span", { children: "Brand book ID" }),
2290
- /* @__PURE__ */ jsx23("input", { value: selected.brandAsset?.bookId ?? "", onInput: (event) => update({ brandAsset: { bookId: event.currentTarget.value, assetId: selected.brandAsset?.assetId ?? "", ...selected.brandAsset?.filename ? { filename: selected.brandAsset.filename } : {} } }) })
2361
+ selected.kind === "image" || selected.kind === "file" ? /* @__PURE__ */ jsxs22("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }, children: [
2362
+ /* @__PURE__ */ jsxs22("label", { className: "field", children: [
2363
+ /* @__PURE__ */ jsx24("span", { children: "Brand book ID" }),
2364
+ /* @__PURE__ */ jsx24("input", { value: selected.brandAsset?.bookId ?? "", onInput: (event) => update({ brandAsset: { bookId: event.currentTarget.value, assetId: selected.brandAsset?.assetId ?? "", ...selected.brandAsset?.filename ? { filename: selected.brandAsset.filename } : {} } }) })
2291
2365
  ] }),
2292
- /* @__PURE__ */ jsxs21("label", { className: "field", children: [
2293
- /* @__PURE__ */ jsx23("span", { children: "Asset ID" }),
2294
- /* @__PURE__ */ jsx23("input", { value: selected.brandAsset?.assetId ?? "", onInput: (event) => update({ brandAsset: { bookId: selected.brandAsset?.bookId ?? "", assetId: event.currentTarget.value, ...selected.brandAsset?.filename ? { filename: selected.brandAsset.filename } : {} } }) })
2366
+ /* @__PURE__ */ jsxs22("label", { className: "field", children: [
2367
+ /* @__PURE__ */ jsx24("span", { children: "Asset ID" }),
2368
+ /* @__PURE__ */ jsx24("input", { value: selected.brandAsset?.assetId ?? "", onInput: (event) => update({ brandAsset: { bookId: selected.brandAsset?.bookId ?? "", assetId: event.currentTarget.value, ...selected.brandAsset?.filename ? { filename: selected.brandAsset.filename } : {} } }) })
2295
2369
  ] }),
2296
- /* @__PURE__ */ jsxs21("label", { className: "field", children: [
2297
- /* @__PURE__ */ jsx23("span", { children: "Filename (optional)" }),
2298
- /* @__PURE__ */ jsx23("input", { value: selected.brandAsset?.filename ?? "", onInput: (event) => update({ brandAsset: { bookId: selected.brandAsset?.bookId ?? "", assetId: selected.brandAsset?.assetId ?? "", ...event.currentTarget.value ? { filename: event.currentTarget.value } : {} } }) })
2370
+ /* @__PURE__ */ jsxs22("label", { className: "field", children: [
2371
+ /* @__PURE__ */ jsx24("span", { children: "Filename (optional)" }),
2372
+ /* @__PURE__ */ jsx24("input", { value: selected.brandAsset?.filename ?? "", onInput: (event) => update({ brandAsset: { bookId: selected.brandAsset?.bookId ?? "", assetId: selected.brandAsset?.assetId ?? "", ...event.currentTarget.value ? { filename: event.currentTarget.value } : {} } }) })
2299
2373
  ] })
2300
2374
  ] }) : null,
2301
- /* @__PURE__ */ jsx23(ResourcePreview, { item: selected })
2375
+ /* @__PURE__ */ jsx24(ResourcePreview, { item: selected })
2302
2376
  ] });
2303
2377
  }
2304
2378
  function builderLibrarySection() {
2305
- return { id: "builder-library", label: "Builder Library", render: (ctx) => /* @__PURE__ */ jsx23(BuilderLibraryAdmin, { ctx }) };
2379
+ return { id: "builder-library", label: "Builder Library", render: (ctx) => /* @__PURE__ */ jsx24(BuilderLibraryAdmin, { ctx }) };
2306
2380
  }
2307
2381
 
2308
2382
  // src/ui/admin-email.tsx
2309
- import { useState as useState19 } from "preact/hooks";
2310
- import { Button as Button11, Checkbox as Checkbox2, DataTable as DataTable3, Field as Field9, Input as Input4, Textarea as Textarea4 } from "@odla-ai/ui/components";
2383
+ import { useState as useState21 } from "preact/hooks";
2384
+ import { Button as Button13, Checkbox as Checkbox2, DataTable as DataTable3, Field as Field9, Input as Input4, Textarea as Textarea4 } from "@odla-ai/ui/components";
2311
2385
 
2312
2386
  // src/ui/admin-email-resolution.tsx
2313
- import { useState as useState18 } from "preact/hooks";
2314
- import { Button as Button10, Field as Field8, Input as Input3, Textarea as Textarea3 } from "@odla-ai/ui/components";
2315
- import { jsx as jsx24, jsxs as jsxs22 } from "preact/jsx-runtime";
2387
+ import { useState as useState20 } from "preact/hooks";
2388
+ import { Button as Button12, Field as Field8, Input as Input3, Textarea as Textarea3 } from "@odla-ai/ui/components";
2389
+ import { jsx as jsx25, jsxs as jsxs23 } from "preact/jsx-runtime";
2316
2390
  function EmailDeliveryResolution({ row, ctx, onResolved }) {
2317
- const [open, setOpen] = useState18(false), [reason, setReason] = useState18(""), [messageId, setMessageId] = useState18("");
2318
- const [busy, setBusy] = useState18(false), [note, setNote] = useState18("");
2391
+ const [open, setOpen] = useState20(false), [reason, setReason] = useState20(""), [messageId, setMessageId] = useState20("");
2392
+ const [busy, setBusy] = useState20(false), [note, setNote] = useState20("");
2319
2393
  if (!["sending", "uncertain"].includes(row.deliveryState ?? "") || !row.deliveryAttempt) return null;
2320
2394
  const resolve2 = async (decision) => {
2321
2395
  setBusy(true);
@@ -2339,45 +2413,45 @@ function EmailDeliveryResolution({ row, ctx, onResolved }) {
2339
2413
  setBusy(false);
2340
2414
  }
2341
2415
  };
2342
- if (!open) return /* @__PURE__ */ jsx24(Button10, { mini: true, variant: "secondary", onClick: () => setOpen(true), children: "Review delivery" });
2343
- return /* @__PURE__ */ jsxs22("div", { children: [
2344
- /* @__PURE__ */ jsxs22("p", { children: [
2416
+ if (!open) return /* @__PURE__ */ jsx25(Button12, { mini: true, variant: "secondary", onClick: () => setOpen(true), children: "Review delivery" });
2417
+ return /* @__PURE__ */ jsxs23("div", { children: [
2418
+ /* @__PURE__ */ jsxs23("p", { children: [
2345
2419
  "Attempt ",
2346
2420
  row.deliveryAttempt,
2347
2421
  ": ",
2348
2422
  row.subject,
2349
2423
  ". Check provider evidence, not just whether the message is in an inbox. This action does not send mail."
2350
2424
  ] }),
2351
- /* @__PURE__ */ jsx24(Field8, { label: "Provider evidence", children: /* @__PURE__ */ jsx24(Textarea3, { value: reason, onInput: (e) => setReason(e.target.value) }) }),
2352
- /* @__PURE__ */ jsx24(Field8, { label: "Provider message ID (optional)", children: /* @__PURE__ */ jsx24(Input3, { value: messageId, onInput: (e) => setMessageId(e.target.value) }) }),
2353
- /* @__PURE__ */ jsx24(Button10, { mini: true, disabled: busy || reason.trim().length < 10, onClick: () => void resolve2("confirmed_delivered"), children: "Confirm delivered" }),
2354
- /* @__PURE__ */ jsx24(Button10, { mini: true, variant: "secondary", disabled: busy || reason.trim().length < 10, onClick: () => void resolve2("confirmed_not_delivered"), children: "Confirm not delivered" }),
2355
- /* @__PURE__ */ jsx24(Button10, { mini: true, variant: "secondary", disabled: busy, onClick: () => setOpen(false), children: "Cancel" }),
2356
- note ? /* @__PURE__ */ jsx24("p", { role: "alert", children: note }) : null
2425
+ /* @__PURE__ */ jsx25(Field8, { label: "Provider evidence", children: /* @__PURE__ */ jsx25(Textarea3, { value: reason, onInput: (e) => setReason(e.target.value) }) }),
2426
+ /* @__PURE__ */ jsx25(Field8, { label: "Provider message ID (optional)", children: /* @__PURE__ */ jsx25(Input3, { value: messageId, onInput: (e) => setMessageId(e.target.value) }) }),
2427
+ /* @__PURE__ */ jsx25(Button12, { mini: true, disabled: busy || reason.trim().length < 10, onClick: () => void resolve2("confirmed_delivered"), children: "Confirm delivered" }),
2428
+ /* @__PURE__ */ jsx25(Button12, { mini: true, variant: "secondary", disabled: busy || reason.trim().length < 10, onClick: () => void resolve2("confirmed_not_delivered"), children: "Confirm not delivered" }),
2429
+ /* @__PURE__ */ jsx25(Button12, { mini: true, variant: "secondary", disabled: busy, onClick: () => setOpen(false), children: "Cancel" }),
2430
+ note ? /* @__PURE__ */ jsx25("p", { role: "alert", children: note }) : null
2357
2431
  ] });
2358
2432
  }
2359
2433
 
2360
2434
  // src/ui/admin-email.tsx
2361
- import { jsx as jsx25, jsxs as jsxs23 } from "preact/jsx-runtime";
2435
+ import { jsx as jsx26, jsxs as jsxs24 } from "preact/jsx-runtime";
2362
2436
  var logColumns = (copy, ctx, refresh) => [
2363
2437
  { key: "sentAt", header: copy.sentColumn, cell: (r) => new Date(r.sentAt).toLocaleString(), sortAs: "number", sortValue: (r) => r.sentAt },
2364
2438
  { key: "template", header: copy.templateColumn, cell: (r) => r.template },
2365
2439
  { key: "to", header: copy.toColumn, cell: (r) => r.to },
2366
- { key: "status", header: copy.statusColumn, cell: (r) => /* @__PURE__ */ jsxs23("div", { children: [
2367
- r.deliveryState && r.deliveryState !== "sent" ? /* @__PURE__ */ jsx25("span", { className: "badge", children: r.deliveryState === "retry_ready" ? "Original workflow may retry" : r.deliveryState === "sending" ? "Sending \u2014 unconfirmed" : "Delivery uncertain" }) : r.error ? /* @__PURE__ */ jsx25("span", { className: "badge", children: copy.failed }) : r.transport === "log-only" ? "Logged only \u2014 not sent" : r.redirected ? /* @__PURE__ */ jsx25("span", { className: "badge", children: copy.redirected }) : copy.delivered,
2368
- /* @__PURE__ */ jsx25(EmailDeliveryResolution, { row: r, ctx, onResolved: refresh })
2440
+ { key: "status", header: copy.statusColumn, cell: (r) => /* @__PURE__ */ jsxs24("div", { children: [
2441
+ r.deliveryState && r.deliveryState !== "sent" ? /* @__PURE__ */ jsx26("span", { className: "badge", children: r.deliveryState === "retry_ready" ? "Original workflow may retry" : r.deliveryState === "sending" ? "Sending \u2014 unconfirmed" : "Delivery uncertain" }) : r.error ? /* @__PURE__ */ jsx26("span", { className: "badge", children: copy.failed }) : r.transport === "log-only" ? "Logged only \u2014 not sent" : r.redirected ? /* @__PURE__ */ jsx26("span", { className: "badge", children: copy.redirected }) : copy.delivered,
2442
+ /* @__PURE__ */ jsx26(EmailDeliveryResolution, { row: r, ctx, onResolved: refresh })
2369
2443
  ] }) }
2370
2444
  ];
2371
2445
  function EmailBody({ ctx }) {
2372
2446
  const copy = useChapterCopy().admin.email;
2373
2447
  const cfg = useAdminResource(ctx.getToken, "/api/admin/group/email");
2374
2448
  const log = useAdminResource(ctx.getToken, "/api/admin/email/log");
2375
- const [draft, setDraft] = useState19(null);
2376
- const [busy, setBusy] = useState19(null);
2377
- const [note, setNote] = useState19(null);
2449
+ const [draft, setDraft] = useState21(null);
2450
+ const [busy, setBusy] = useState21(null);
2451
+ const [note, setNote] = useState21(null);
2378
2452
  const data = draft ?? cfg.data;
2379
- if (cfg.loading) return /* @__PURE__ */ jsx25(AdminNote, { children: copy.loading });
2380
- if (cfg.error || !data) return /* @__PURE__ */ jsxs23(AdminNote, { children: [
2453
+ if (cfg.loading) return /* @__PURE__ */ jsx26(AdminNote, { children: copy.loading });
2454
+ if (cfg.error || !data) return /* @__PURE__ */ jsxs24(AdminNote, { children: [
2381
2455
  copy.loadFailed,
2382
2456
  cfg.error ? `: ${cfg.error}` : "",
2383
2457
  "."
@@ -2410,44 +2484,44 @@ function EmailBody({ ctx }) {
2410
2484
  }) : copy.testFailed);
2411
2485
  log.refresh();
2412
2486
  });
2413
- return /* @__PURE__ */ jsxs23(AdminPage, { children: [
2414
- /* @__PURE__ */ jsxs23(
2487
+ return /* @__PURE__ */ jsxs24(AdminPage, { children: [
2488
+ /* @__PURE__ */ jsxs24(
2415
2489
  Panel,
2416
2490
  {
2417
2491
  title: copy.delivery,
2418
- actions: /* @__PURE__ */ jsxs23("span", { className: "muted", children: [
2492
+ actions: /* @__PURE__ */ jsxs24("span", { className: "muted", children: [
2419
2493
  data.envName,
2420
2494
  " \xB7 ",
2421
2495
  data.transport,
2422
2496
  data.fromEmail ? ` \xB7 ${data.fromEmail}` : ""
2423
2497
  ] }),
2424
2498
  children: [
2425
- /* @__PURE__ */ jsx25(Field9, { label: copy.notificationAddress, children: /* @__PURE__ */ jsx25(Input4, { value: data.notificationEmail, onInput: (e) => edit({ notificationEmail: e.target.value }) }) }),
2426
- /* @__PURE__ */ jsx25(Field9, { label: copy.replyTo, children: /* @__PURE__ */ jsx25(Input4, { value: data.replyTo, onInput: (e) => edit({ replyTo: e.target.value }) }) }),
2427
- /* @__PURE__ */ jsx25(Field9, { label: copy.debugInbox, hint: copy.debugInboxHint, children: /* @__PURE__ */ jsx25(Input4, { value: data.debugEmail, onInput: (e) => edit({ debugEmail: e.target.value }) }) })
2499
+ /* @__PURE__ */ jsx26(Field9, { label: copy.notificationAddress, children: /* @__PURE__ */ jsx26(Input4, { value: data.notificationEmail, onInput: (e) => edit({ notificationEmail: e.target.value }) }) }),
2500
+ /* @__PURE__ */ jsx26(Field9, { label: copy.replyTo, children: /* @__PURE__ */ jsx26(Input4, { value: data.replyTo, onInput: (e) => edit({ replyTo: e.target.value }) }) }),
2501
+ /* @__PURE__ */ jsx26(Field9, { label: copy.debugInbox, hint: copy.debugInboxHint, children: /* @__PURE__ */ jsx26(Input4, { value: data.debugEmail, onInput: (e) => edit({ debugEmail: e.target.value }) }) })
2428
2502
  ]
2429
2503
  }
2430
2504
  ),
2431
- Object.entries(data.emailTemplates).map(([key, t]) => /* @__PURE__ */ jsxs23(Panel, { title: key, actions: /* @__PURE__ */ jsx25(Button11, { variant: "secondary", mini: true, disabled: busy === `test:${key}`, onClick: () => void test(key), children: copy.sendTest }), children: [
2432
- /* @__PURE__ */ jsx25(Checkbox2, { label: copy.enabled, checked: t.enabled, onChange: (e) => editTemplate(key, { enabled: e.target.checked }) }),
2433
- /* @__PURE__ */ jsx25(Field9, { label: copy.subject, children: /* @__PURE__ */ jsx25(Input4, { value: t.subject, onInput: (e) => editTemplate(key, { subject: e.target.value }) }) }),
2434
- /* @__PURE__ */ jsx25(Field9, { label: copy.body, children: /* @__PURE__ */ jsx25(Textarea4, { prose: true, rows: 5, value: t.text, onInput: (e) => editTemplate(key, { text: e.target.value }) }) })
2505
+ Object.entries(data.emailTemplates).map(([key, t]) => /* @__PURE__ */ jsxs24(Panel, { title: key, actions: /* @__PURE__ */ jsx26(Button13, { variant: "secondary", mini: true, disabled: busy === `test:${key}`, onClick: () => void test(key), children: copy.sendTest }), children: [
2506
+ /* @__PURE__ */ jsx26(Checkbox2, { label: copy.enabled, checked: t.enabled, onChange: (e) => editTemplate(key, { enabled: e.target.checked }) }),
2507
+ /* @__PURE__ */ jsx26(Field9, { label: copy.subject, children: /* @__PURE__ */ jsx26(Input4, { value: t.subject, onInput: (e) => editTemplate(key, { subject: e.target.value }) }) }),
2508
+ /* @__PURE__ */ jsx26(Field9, { label: copy.body, children: /* @__PURE__ */ jsx26(Textarea4, { prose: true, rows: 5, value: t.text, onInput: (e) => editTemplate(key, { text: e.target.value }) }) })
2435
2509
  ] }, key)),
2436
- /* @__PURE__ */ jsxs23("div", { style: { display: "flex", gap: 12, alignItems: "center" }, children: [
2437
- /* @__PURE__ */ jsx25(Button11, { disabled: !draft || busy === "save", onClick: () => void save(), children: copy.save }),
2438
- note ? /* @__PURE__ */ jsx25("span", { className: "muted", children: note }) : null
2510
+ /* @__PURE__ */ jsxs24("div", { style: { display: "flex", gap: 12, alignItems: "center" }, children: [
2511
+ /* @__PURE__ */ jsx26(Button13, { disabled: !draft || busy === "save", onClick: () => void save(), children: copy.save }),
2512
+ note ? /* @__PURE__ */ jsx26("span", { className: "muted", children: note }) : null
2439
2513
  ] }),
2440
- /* @__PURE__ */ jsx25(Panel, { title: copy.sendLog, children: /* @__PURE__ */ jsx25(DataTable3, { rows: log.data?.sends ?? [], columns: logColumns(copy, ctx, log.refresh), rowKey: (r) => r.id }) })
2514
+ /* @__PURE__ */ jsx26(Panel, { title: copy.sendLog, children: /* @__PURE__ */ jsx26(DataTable3, { rows: log.data?.sends ?? [], columns: logColumns(copy, ctx, log.refresh), rowKey: (r) => r.id }) })
2441
2515
  ] });
2442
2516
  }
2443
2517
  function emailSection(options = {}) {
2444
2518
  const { id = "email", label = "Email" } = options;
2445
- return { id, label, render: (ctx) => /* @__PURE__ */ jsx25(EmailBody, { ctx }) };
2519
+ return { id, label, render: (ctx) => /* @__PURE__ */ jsx26(EmailBody, { ctx }) };
2446
2520
  }
2447
2521
 
2448
2522
  // src/ui/admin-member-content.tsx
2449
- import { useEffect as useEffect10, useState as useState20 } from "preact/hooks";
2450
- import { jsx as jsx26, jsxs as jsxs24 } from "preact/jsx-runtime";
2523
+ import { useEffect as useEffect10, useState as useState22 } from "preact/hooks";
2524
+ import { jsx as jsx27, jsxs as jsxs25 } from "preact/jsx-runtime";
2451
2525
  var emptyDraft = () => ({ pages: [], upsellOverrides: [] });
2452
2526
  function accessLabel(page) {
2453
2527
  return page.audience.kind === "all-members" ? "All members" : `Tiers: ${page.audience.tierIds.join(", ")}`;
@@ -2457,17 +2531,17 @@ function MemberContentAdmin({
2457
2531
  initialData
2458
2532
  }) {
2459
2533
  const resource = useAdminResource(ctx.getToken, "/api/admin/member-content");
2460
- const [draft, setDraft] = useState20(JSON.stringify(initialData?.chapter?.document ?? emptyDraft(), null, 2));
2461
- const [saveError, setSaveError] = useState20(null);
2462
- const [saving, setSaving] = useState20(false);
2534
+ const [draft, setDraft] = useState22(JSON.stringify(initialData?.chapter?.document ?? emptyDraft(), null, 2));
2535
+ const [saveError, setSaveError] = useState22(null);
2536
+ const [saving, setSaving] = useState22(false);
2463
2537
  useEffect10(() => {
2464
2538
  if (!resource.data) return;
2465
2539
  setDraft(JSON.stringify(resource.data.chapter?.document ?? emptyDraft(), null, 2));
2466
2540
  }, [resource.data]);
2467
2541
  const loaded = initialData ?? resource.data;
2468
- if (!loaded && resource.loading) return /* @__PURE__ */ jsx26(AdminPage, { children: /* @__PURE__ */ jsx26(AdminNote, { children: "Loading member content\u2026" }) });
2542
+ if (!loaded && resource.loading) return /* @__PURE__ */ jsx27(AdminPage, { children: /* @__PURE__ */ jsx27(AdminNote, { children: "Loading member content\u2026" }) });
2469
2543
  if (resource.error || !loaded) {
2470
- return /* @__PURE__ */ jsx26(AdminPage, { children: /* @__PURE__ */ jsxs24(AdminNote, { children: [
2544
+ return /* @__PURE__ */ jsx27(AdminPage, { children: /* @__PURE__ */ jsxs25(AdminNote, { children: [
2471
2545
  "Member content could not be loaded: ",
2472
2546
  resource.error ?? "unknown error"
2473
2547
  ] }) });
@@ -2498,35 +2572,35 @@ function MemberContentAdmin({
2498
2572
  setSaving(false);
2499
2573
  }
2500
2574
  };
2501
- return /* @__PURE__ */ jsxs24(AdminPage, { children: [
2502
- /* @__PURE__ */ jsxs24(Panel, { children: [
2503
- /* @__PURE__ */ jsx26("div", { className: "card-label", children: "Member content" }),
2504
- /* @__PURE__ */ jsx26("h2", { children: "One catalog, two clear owners" }),
2505
- /* @__PURE__ */ jsx26("p", { children: "Parent pages are inherited and read-only here. Chapter pages and delegated upsells are edited in the local document. Access uses exact tier IDs; no tier order is assumed." }),
2506
- /* @__PURE__ */ jsxs24("div", { className: "stat-band", children: [
2507
- /* @__PURE__ */ jsxs24("div", { children: [
2508
- /* @__PURE__ */ jsx26("strong", { children: inherited.length }),
2509
- /* @__PURE__ */ jsx26("span", { children: "Inherited pages" })
2575
+ return /* @__PURE__ */ jsxs25(AdminPage, { children: [
2576
+ /* @__PURE__ */ jsxs25(Panel, { children: [
2577
+ /* @__PURE__ */ jsx27("div", { className: "card-label", children: "Member content" }),
2578
+ /* @__PURE__ */ jsx27("h2", { children: "One catalog, two clear owners" }),
2579
+ /* @__PURE__ */ jsx27("p", { children: "Parent pages are inherited and read-only here. Chapter pages and delegated upsells are edited in the local document. Access uses exact tier IDs; no tier order is assumed." }),
2580
+ /* @__PURE__ */ jsxs25("div", { className: "stat-band", children: [
2581
+ /* @__PURE__ */ jsxs25("div", { children: [
2582
+ /* @__PURE__ */ jsx27("strong", { children: inherited.length }),
2583
+ /* @__PURE__ */ jsx27("span", { children: "Inherited pages" })
2510
2584
  ] }),
2511
- /* @__PURE__ */ jsxs24("div", { children: [
2512
- /* @__PURE__ */ jsx26("strong", { children: local.length }),
2513
- /* @__PURE__ */ jsx26("span", { children: "Chapter pages" })
2585
+ /* @__PURE__ */ jsxs25("div", { children: [
2586
+ /* @__PURE__ */ jsx27("strong", { children: local.length }),
2587
+ /* @__PURE__ */ jsx27("span", { children: "Chapter pages" })
2514
2588
  ] }),
2515
- /* @__PURE__ */ jsxs24("div", { children: [
2516
- /* @__PURE__ */ jsx26("strong", { children: data.tiers.length }),
2517
- /* @__PURE__ */ jsx26("span", { children: "Declared tiers" })
2589
+ /* @__PURE__ */ jsxs25("div", { children: [
2590
+ /* @__PURE__ */ jsx27("strong", { children: data.tiers.length }),
2591
+ /* @__PURE__ */ jsx27("span", { children: "Declared tiers" })
2518
2592
  ] })
2519
2593
  ] })
2520
2594
  ] }),
2521
- /* @__PURE__ */ jsxs24(Panel, { children: [
2522
- /* @__PURE__ */ jsx26("div", { className: "card-label", children: "Inherited \xB7 read only" }),
2523
- /* @__PURE__ */ jsxs24("h2", { children: [
2595
+ /* @__PURE__ */ jsxs25(Panel, { children: [
2596
+ /* @__PURE__ */ jsx27("div", { className: "card-label", children: "Inherited \xB7 read only" }),
2597
+ /* @__PURE__ */ jsxs25("h2", { children: [
2524
2598
  "Parent pages ",
2525
2599
  data.parent ? `\xB7 revision ${data.parent.revision}` : ""
2526
2600
  ] }),
2527
- inherited.length === 0 ? /* @__PURE__ */ jsx26(AdminNote, { children: "No Parent pages have been delivered." }) : /* @__PURE__ */ jsx26("div", { className: "data-list", "data-member-content-inherited": true, children: inherited.map((page) => /* @__PURE__ */ jsxs24("article", { className: "card", children: [
2528
- /* @__PURE__ */ jsx26("strong", { children: page.title }),
2529
- /* @__PURE__ */ jsxs24("div", { className: "meeting-note", children: [
2601
+ inherited.length === 0 ? /* @__PURE__ */ jsx27(AdminNote, { children: "No Parent pages have been delivered." }) : /* @__PURE__ */ jsx27("div", { className: "data-list", "data-member-content-inherited": true, children: inherited.map((page) => /* @__PURE__ */ jsxs25("article", { className: "card", children: [
2602
+ /* @__PURE__ */ jsx27("strong", { children: page.title }),
2603
+ /* @__PURE__ */ jsxs25("div", { className: "meeting-note", children: [
2530
2604
  "/",
2531
2605
  page.slug,
2532
2606
  " \xB7 ",
@@ -2534,22 +2608,22 @@ function MemberContentAdmin({
2534
2608
  " \xB7 ",
2535
2609
  accessLabel(page)
2536
2610
  ] }),
2537
- /* @__PURE__ */ jsxs24("div", { className: "meeting-note", children: [
2611
+ /* @__PURE__ */ jsxs25("div", { className: "meeting-note", children: [
2538
2612
  "Upsell: ",
2539
2613
  page.upsell ? `${page.upsell.owner} controlled` : "none"
2540
2614
  ] })
2541
2615
  ] }, page.id)) })
2542
2616
  ] }),
2543
- /* @__PURE__ */ jsxs24(Panel, { children: [
2544
- /* @__PURE__ */ jsx26("div", { className: "card-label", children: "Chapter \xB7 editable" }),
2545
- /* @__PURE__ */ jsxs24("h2", { children: [
2617
+ /* @__PURE__ */ jsxs25(Panel, { children: [
2618
+ /* @__PURE__ */ jsx27("div", { className: "card-label", children: "Chapter \xB7 editable" }),
2619
+ /* @__PURE__ */ jsxs25("h2", { children: [
2546
2620
  "Local document \xB7 revision ",
2547
2621
  data.chapter?.revision ?? 0
2548
2622
  ] }),
2549
- /* @__PURE__ */ jsx26("p", { className: "meeting-note", children: "Use the published MemberContentDocument fields. The server supplies schemaVersion, revision, timestamp, and chapter source; unknown fields and undeclared tiers are rejected." }),
2550
- /* @__PURE__ */ jsxs24("label", { className: "field", children: [
2551
- /* @__PURE__ */ jsx26("span", { children: "Pages and delegated upsells (JSON)" }),
2552
- /* @__PURE__ */ jsx26(
2623
+ /* @__PURE__ */ jsx27("p", { className: "meeting-note", children: "Use the published MemberContentDocument fields. The server supplies schemaVersion, revision, timestamp, and chapter source; unknown fields and undeclared tiers are rejected." }),
2624
+ /* @__PURE__ */ jsxs25("label", { className: "field", children: [
2625
+ /* @__PURE__ */ jsx27("span", { children: "Pages and delegated upsells (JSON)" }),
2626
+ /* @__PURE__ */ jsx27(
2553
2627
  "textarea",
2554
2628
  {
2555
2629
  rows: 24,
@@ -2560,12 +2634,12 @@ function MemberContentAdmin({
2560
2634
  }
2561
2635
  )
2562
2636
  ] }),
2563
- saveError ? /* @__PURE__ */ jsxs24("div", { className: "notice danger", role: "alert", children: [
2564
- /* @__PURE__ */ jsx26("strong", { children: "Fix these items before saving:" }),
2565
- /* @__PURE__ */ jsx26("ul", { children: saveError.map((error) => /* @__PURE__ */ jsx26("li", { children: error }, error)) })
2637
+ saveError ? /* @__PURE__ */ jsxs25("div", { className: "notice danger", role: "alert", children: [
2638
+ /* @__PURE__ */ jsx27("strong", { children: "Fix these items before saving:" }),
2639
+ /* @__PURE__ */ jsx27("ul", { children: saveError.map((error) => /* @__PURE__ */ jsx27("li", { children: error }, error)) })
2566
2640
  ] }) : null,
2567
- /* @__PURE__ */ jsx26("button", { className: "btn primary", type: "button", disabled: !data.localAuthoring || saving, onClick: () => void save(), children: saving ? "Saving\u2026" : "Save chapter content" }),
2568
- !data.localAuthoring ? /* @__PURE__ */ jsx26(AdminNote, { children: "Local authoring is disabled in the checked-in Chapter config." }) : null
2641
+ /* @__PURE__ */ jsx27("button", { className: "btn primary", type: "button", disabled: !data.localAuthoring || saving, onClick: () => void save(), children: saving ? "Saving\u2026" : "Save chapter content" }),
2642
+ !data.localAuthoring ? /* @__PURE__ */ jsx27(AdminNote, { children: "Local authoring is disabled in the checked-in Chapter config." }) : null
2569
2643
  ] })
2570
2644
  ] });
2571
2645
  }
@@ -2573,12 +2647,12 @@ function memberContentSection() {
2573
2647
  return {
2574
2648
  id: "member-content",
2575
2649
  label: "Member content",
2576
- render: (ctx) => /* @__PURE__ */ jsx26(MemberContentAdmin, { ctx })
2650
+ render: (ctx) => /* @__PURE__ */ jsx27(MemberContentAdmin, { ctx })
2577
2651
  };
2578
2652
  }
2579
2653
 
2580
2654
  // src/ui/admin-settings-workspace.tsx
2581
- import { jsx as jsx27 } from "preact/jsx-runtime";
2655
+ import { jsx as jsx28 } from "preact/jsx-runtime";
2582
2656
  var viewContext = (ctx, viewId, active) => {
2583
2657
  const route = { workspaceId: ctx.route.workspaceId, viewId, ...active && ctx.route.recordId ? { recordId: ctx.route.recordId } : {}, ...active && ctx.route.detailTab ? { detailTab: ctx.route.detailTab } : {} };
2584
2658
  const targetFromView = (target) => {
@@ -2596,7 +2670,7 @@ function SettingsWorkspace({ chapter, ctx }) {
2596
2670
  const email = emailSection({ label: copy.workspaces.email });
2597
2671
  const content = memberContentSection();
2598
2672
  const library = builderLibrarySection();
2599
- return /* @__PURE__ */ jsx27(Tabs2, { ariaLabel: copy.workspaces.settingsViewsLabel, value: active, mount: "active", items: [
2673
+ return /* @__PURE__ */ jsx28(Tabs2, { ariaLabel: copy.workspaces.settingsViewsLabel, value: active, mount: "active", items: [
2600
2674
  { value: "calendar", label: copy.workspaces.calendar, href: ctx.href({ viewId: "calendar", recordId: null, detailTab: null }), panel: calendar.render(viewContext(ctx, "calendar", active === "calendar")) },
2601
2675
  { value: "email", label: copy.workspaces.email, href: ctx.href({ viewId: "email", recordId: null, detailTab: null }), panel: email.render(viewContext(ctx, "email", active === "email")) },
2602
2676
  ...chapter.memberContent ? [{ value: "member-content", label: "Member content", href: ctx.href({ viewId: "member-content", recordId: null, detailTab: null }), panel: content.render(viewContext(ctx, "member-content", active === "member-content")) }] : [],
@@ -2607,14 +2681,14 @@ function LeaderSettingsWorkspace({ chapter, ctx }) {
2607
2681
  const email = emailSection({ label: chapter.copy.admin.workspaces.email });
2608
2682
  const library = builderLibrarySection();
2609
2683
  const active = ctx.route.viewId === "builder-library" && chapter.builderLibrary ? "builder-library" : "email";
2610
- return /* @__PURE__ */ jsx27(Tabs2, { ariaLabel: chapter.copy.admin.workspaces.settingsViewsLabel, value: active, mount: "active", items: [
2684
+ return /* @__PURE__ */ jsx28(Tabs2, { ariaLabel: chapter.copy.admin.workspaces.settingsViewsLabel, value: active, mount: "active", items: [
2611
2685
  { value: "email", label: chapter.copy.admin.workspaces.email, href: ctx.href({ viewId: "email", recordId: null, detailTab: null }), panel: email.render(viewContext(ctx, "email", active === "email")) },
2612
2686
  ...chapter.builderLibrary ? [{ value: "builder-library", label: "Builder Library", href: ctx.href({ viewId: "builder-library", recordId: null, detailTab: null }), panel: library.render(viewContext(ctx, "builder-library", active === "builder-library")) }] : []
2613
2687
  ] });
2614
2688
  }
2615
2689
 
2616
2690
  // src/ui/admin-workspaces.tsx
2617
- import { jsx as jsx28 } from "preact/jsx-runtime";
2691
+ import { jsx as jsx29 } from "preact/jsx-runtime";
2618
2692
  var adminViewContext = (ctx, viewId, active) => {
2619
2693
  const route = {
2620
2694
  workspaceId: ctx.route.workspaceId,
@@ -2640,7 +2714,7 @@ function DashboardWorkspace({ chapter, ctx }) {
2640
2714
  const active = ctx.route.viewId === "billing" ? "billing" : "overview";
2641
2715
  const overview = dashboardSection({ id: "overview", label: copy.workspaces.overview });
2642
2716
  const billing = billingSection({ label: copy.workspaces.billing });
2643
- return /* @__PURE__ */ jsx28(
2717
+ return /* @__PURE__ */ jsx29(
2644
2718
  Tabs3,
2645
2719
  {
2646
2720
  ariaLabel: copy.workspaces.dashboardViewsLabel,
@@ -2668,7 +2742,7 @@ function PeopleWorkspace({ chapter, ctx }) {
2668
2742
  const fallback = types[0]?.[0] ?? "person";
2669
2743
  const active = types.some(([type]) => type === ctx.route.viewId) ? ctx.route.viewId : fallback;
2670
2744
  const networkSharing = chapter.network.targets.length > 0;
2671
- return /* @__PURE__ */ jsx28(
2745
+ return /* @__PURE__ */ jsx29(
2672
2746
  Tabs3,
2673
2747
  {
2674
2748
  ariaLabel: chapter.copy.admin.workspaces.collectionsLabel,
@@ -2698,8 +2772,8 @@ function PortfolioWorkspace({ chapter, ctx }) {
2698
2772
  const types = Object.entries(chapter.crm.config.types).filter(([, def]) => def.workspace === "portfolio");
2699
2773
  const fallback = types[0]?.[0] ?? "";
2700
2774
  const active = types.some(([type]) => type === ctx.route.viewId) ? ctx.route.viewId : fallback;
2701
- if (!active) return /* @__PURE__ */ jsx28(LeaderNetworkOverview, { ctx });
2702
- return /* @__PURE__ */ jsx28(
2775
+ if (!active) return /* @__PURE__ */ jsx29(LeaderNetworkOverview, { ctx });
2776
+ return /* @__PURE__ */ jsx29(
2703
2777
  Tabs3,
2704
2778
  {
2705
2779
  ariaLabel: copy.workspaces.portfolioViewsLabel,
@@ -2723,7 +2797,7 @@ function PortfolioWorkspace({ chapter, ctx }) {
2723
2797
  );
2724
2798
  }
2725
2799
  function LeaderDashboardWorkspace({ chapter, ctx }) {
2726
- return /* @__PURE__ */ jsx28(
2800
+ return /* @__PURE__ */ jsx29(
2727
2801
  Tabs3,
2728
2802
  {
2729
2803
  ariaLabel: chapter.copy.admin.workspaces.dashboardViewsLabel,
@@ -2733,7 +2807,7 @@ function LeaderDashboardWorkspace({ chapter, ctx }) {
2733
2807
  value: "overview",
2734
2808
  label: chapter.copy.admin.workspaces.overview,
2735
2809
  href: ctx.href({ viewId: "overview", recordId: null, detailTab: null }),
2736
- panel: /* @__PURE__ */ jsx28(LeaderNetworkOverview, { ctx: adminViewContext(ctx, "overview", true) })
2810
+ panel: /* @__PURE__ */ jsx29(LeaderNetworkOverview, { ctx: adminViewContext(ctx, "overview", true) })
2737
2811
  }]
2738
2812
  }
2739
2813
  );
@@ -2744,7 +2818,7 @@ function defaultAdminWorkspaces(chapter) {
2744
2818
  id: "people",
2745
2819
  label: copy.workspaces.people,
2746
2820
  defaultViewId: Object.keys(chapter.crm.config.types)[0] ?? "person",
2747
- render: (ctx) => /* @__PURE__ */ jsx28(PeopleWorkspace, { chapter, ctx })
2821
+ render: (ctx) => /* @__PURE__ */ jsx29(PeopleWorkspace, { chapter, ctx })
2748
2822
  };
2749
2823
  if (chapter.mode === "hub" && chapter.network.targets.length === 0) return [people];
2750
2824
  if (chapter.mode === "hub") {
@@ -2754,7 +2828,7 @@ function defaultAdminWorkspaces(chapter) {
2754
2828
  id: "dashboard",
2755
2829
  label: copy.workspaces.dashboard,
2756
2830
  defaultViewId: "overview",
2757
- render: (ctx) => /* @__PURE__ */ jsx28(LeaderDashboardWorkspace, { chapter, ctx })
2831
+ render: (ctx) => /* @__PURE__ */ jsx29(LeaderDashboardWorkspace, { chapter, ctx })
2758
2832
  },
2759
2833
  networkRecordsWorkspace(chapter),
2760
2834
  people,
@@ -2762,13 +2836,13 @@ function defaultAdminWorkspaces(chapter) {
2762
2836
  id: "portfolio",
2763
2837
  label: copy.workspaces.portfolio,
2764
2838
  defaultViewId: portfolioTypes[0]?.[0],
2765
- render: (ctx) => /* @__PURE__ */ jsx28(PortfolioWorkspace, { chapter, ctx })
2839
+ render: (ctx) => /* @__PURE__ */ jsx29(PortfolioWorkspace, { chapter, ctx })
2766
2840
  },
2767
2841
  {
2768
2842
  id: "settings",
2769
2843
  label: copy.workspaces.settings,
2770
2844
  defaultViewId: "email",
2771
- render: (ctx) => /* @__PURE__ */ jsx28(LeaderSettingsWorkspace, { chapter, ctx })
2845
+ render: (ctx) => /* @__PURE__ */ jsx29(LeaderSettingsWorkspace, { chapter, ctx })
2772
2846
  }
2773
2847
  ];
2774
2848
  }
@@ -2777,7 +2851,7 @@ function defaultAdminWorkspaces(chapter) {
2777
2851
  id: "dashboard",
2778
2852
  label: copy.workspaces.dashboard,
2779
2853
  defaultViewId: "overview",
2780
- render: (ctx) => /* @__PURE__ */ jsx28(DashboardWorkspace, { chapter, ctx })
2854
+ render: (ctx) => /* @__PURE__ */ jsx29(DashboardWorkspace, { chapter, ctx })
2781
2855
  },
2782
2856
  people,
2783
2857
  admissionGrantsWorkspace(copy.workspaces.admission),
@@ -2785,17 +2859,17 @@ function defaultAdminWorkspaces(chapter) {
2785
2859
  id: "settings",
2786
2860
  label: copy.workspaces.settings,
2787
2861
  defaultViewId: "calendar",
2788
- render: (ctx) => /* @__PURE__ */ jsx28(SettingsWorkspace, { chapter, ctx })
2862
+ render: (ctx) => /* @__PURE__ */ jsx29(SettingsWorkspace, { chapter, ctx })
2789
2863
  }
2790
2864
  ];
2791
2865
  }
2792
2866
 
2793
2867
  // src/ui/admin-frame.tsx
2794
2868
  import { ThemeScope as ThemeScope2 } from "@odla-ai/ui/components";
2795
- import { jsx as jsx29, jsxs as jsxs25 } from "preact/jsx-runtime";
2869
+ import { jsx as jsx30, jsxs as jsxs26 } from "preact/jsx-runtime";
2796
2870
  function AdminTheme(props) {
2797
2871
  const brand = props.chapter?.brand;
2798
- return /* @__PURE__ */ jsx29(ChapterCopyProvider, { copy: props.chapter?.copy, children: /* @__PURE__ */ jsxs25(
2872
+ return /* @__PURE__ */ jsx30(ChapterCopyProvider, { copy: props.chapter?.copy, children: /* @__PURE__ */ jsxs26(
2799
2873
  ThemeScope2,
2800
2874
  {
2801
2875
  ref: props.scopeRef,
@@ -2804,7 +2878,7 @@ function AdminTheme(props) {
2804
2878
  accent: brand?.accent,
2805
2879
  colorScheme: brand?.colorScheme ?? "light",
2806
2880
  children: [
2807
- /* @__PURE__ */ jsx29(BrandStyle, { brand, selector: "[data-chapter-admin]" }),
2881
+ /* @__PURE__ */ jsx30(BrandStyle, { brand, selector: "[data-chapter-admin]" }),
2808
2882
  props.children
2809
2883
  ]
2810
2884
  }
@@ -2824,10 +2898,10 @@ function signInRedirect(basePath, workspaces) {
2824
2898
  }
2825
2899
 
2826
2900
  // src/ui/admin-appearance.ts
2827
- import { useEffect as useEffect11, useState as useState21 } from "preact/hooks";
2901
+ import { useEffect as useEffect11, useState as useState23 } from "preact/hooks";
2828
2902
  import { clerkAppearanceFromTokens } from "@odla-ai/auth-clerk";
2829
2903
  function useScopedClerkAppearance(scope) {
2830
- const [appearance, setAppearance] = useState21();
2904
+ const [appearance, setAppearance] = useState23();
2831
2905
  useEffect11(() => {
2832
2906
  setAppearance(clerkAppearanceFromTokens(scope.current ?? void 0));
2833
2907
  }, [scope]);
@@ -2859,7 +2933,7 @@ async function loadChapterAdminUser(adapter, apiBase, getToken) {
2859
2933
  }
2860
2934
 
2861
2935
  // src/ui/admin.tsx
2862
- import { jsx as jsx30, jsxs as jsxs26 } from "preact/jsx-runtime";
2936
+ import { jsx as jsx31, jsxs as jsxs27 } from "preact/jsx-runtime";
2863
2937
  function Authed(props) {
2864
2938
  const copy = useChapterCopy().admin;
2865
2939
  const {
@@ -2887,7 +2961,7 @@ function Authed(props) {
2887
2961
  }),
2888
2962
  [getToken, crmBasePath]
2889
2963
  );
2890
- const [state, setState] = useState22({ status: "checking" });
2964
+ const [state, setState] = useState24({ status: "checking" });
2891
2965
  useEffect12(() => {
2892
2966
  let live = true;
2893
2967
  void (async () => {
@@ -2907,17 +2981,17 @@ function Authed(props) {
2907
2981
  live = false;
2908
2982
  };
2909
2983
  }, [getToken, apiBase, auth]);
2910
- if (state.status === "checking") return /* @__PURE__ */ jsx30(Gate, { brand, children: /* @__PURE__ */ jsx30("p", { style: S.muted, children: copy.auth.checking }) });
2984
+ if (state.status === "checking") return /* @__PURE__ */ jsx31(Gate, { brand, children: /* @__PURE__ */ jsx31("p", { style: S.muted, children: copy.auth.checking }) });
2911
2985
  if (state.status === "denied") {
2912
- return /* @__PURE__ */ jsx30(Gate, { brand, children: /* @__PURE__ */ jsxs26("div", { className: "card", style: S.card, children: [
2913
- /* @__PURE__ */ jsx30("h2", { style: { marginTop: 0 }, children: copy.auth.notAuthorized }),
2914
- /* @__PURE__ */ jsx30("p", { style: S.muted, children: formatChapterCopy(copy.auth.accountNotAuthorized, {
2986
+ return /* @__PURE__ */ jsx31(Gate, { brand, children: /* @__PURE__ */ jsxs27("div", { className: "card", style: S.card, children: [
2987
+ /* @__PURE__ */ jsx31("h2", { style: { marginTop: 0 }, children: copy.auth.notAuthorized }),
2988
+ /* @__PURE__ */ jsx31("p", { style: S.muted, children: formatChapterCopy(copy.auth.accountNotAuthorized, {
2915
2989
  account: state.email ?? copy.auth.thisAccount
2916
2990
  }) }),
2917
- /* @__PURE__ */ jsx30("button", { className: "btn secondary", onClick: () => signOut(), children: copy.auth.signOut })
2991
+ /* @__PURE__ */ jsx31("button", { className: "btn secondary", onClick: () => signOut(), children: copy.auth.signOut })
2918
2992
  ] }) });
2919
2993
  }
2920
- return /* @__PURE__ */ jsx30(
2994
+ return /* @__PURE__ */ jsx31(
2921
2995
  AdminShell,
2922
2996
  {
2923
2997
  workspaces,
@@ -2959,7 +3033,7 @@ function ChapterAdmin(props) {
2959
3033
  const chrome = props.chrome ?? "embedded";
2960
3034
  const auth = props.auth ?? DEFAULT_ADMIN_AUTH;
2961
3035
  const redirect = signInRedirect(basePath, workspaces);
2962
- const [publishableKey, setPublishableKey] = useState22(void 0);
3036
+ const [publishableKey, setPublishableKey] = useState24(void 0);
2963
3037
  const scopeRef = useRef3(null);
2964
3038
  const appearance = useScopedClerkAppearance(scopeRef);
2965
3039
  useEffect12(() => {
@@ -2971,23 +3045,23 @@ function ChapterAdmin(props) {
2971
3045
  }, [apiBase, auth]);
2972
3046
  let content;
2973
3047
  if (publishableKey === void 0 || publishableKey && !appearance) {
2974
- content = /* @__PURE__ */ jsx30(Gate, { brand, children: /* @__PURE__ */ jsx30("p", { style: S.muted, children: copy.admin.auth.loading }) });
3048
+ content = /* @__PURE__ */ jsx31(Gate, { brand, children: /* @__PURE__ */ jsx31("p", { style: S.muted, children: copy.admin.auth.loading }) });
2975
3049
  } else if (!publishableKey) {
2976
- content = /* @__PURE__ */ jsx30(Gate, { brand, children: /* @__PURE__ */ jsxs26("div", { className: "card", style: S.card, children: [
2977
- /* @__PURE__ */ jsx30("h2", { style: { marginTop: 0 }, children: copy.admin.auth.signInNotConfigured }),
2978
- /* @__PURE__ */ jsx30("p", { style: S.muted, children: copy.admin.auth.missingPublishableKey })
3050
+ content = /* @__PURE__ */ jsx31(Gate, { brand, children: /* @__PURE__ */ jsxs27("div", { className: "card", style: S.card, children: [
3051
+ /* @__PURE__ */ jsx31("h2", { style: { marginTop: 0 }, children: copy.admin.auth.signInNotConfigured }),
3052
+ /* @__PURE__ */ jsx31("p", { style: S.muted, children: copy.admin.auth.missingPublishableKey })
2979
3053
  ] }) });
2980
3054
  } else if (workspaces.length === 0) {
2981
- content = /* @__PURE__ */ jsx30(Gate, { brand, children: /* @__PURE__ */ jsx30("p", { style: S.muted, children: copy.admin.auth.noWorkspaces }) });
3055
+ content = /* @__PURE__ */ jsx31(Gate, { brand, children: /* @__PURE__ */ jsx31("p", { style: S.muted, children: copy.admin.auth.noWorkspaces }) });
2982
3056
  } else {
2983
- content = /* @__PURE__ */ jsxs26(
3057
+ content = /* @__PURE__ */ jsxs27(
2984
3058
  ClerkGate,
2985
3059
  {
2986
3060
  publishableKey,
2987
3061
  appearance,
2988
3062
  afterSignOutUrl: "/",
2989
3063
  children: [
2990
- /* @__PURE__ */ jsx30(SignedOut, { children: /* @__PURE__ */ jsx30(Gate, { brand, tagline: copy.admin.auth.signInTagline, children: /* @__PURE__ */ jsx30(
3064
+ /* @__PURE__ */ jsx31(SignedOut, { children: /* @__PURE__ */ jsx31(Gate, { brand, tagline: copy.admin.auth.signInTagline, children: /* @__PURE__ */ jsx31(
2991
3065
  SignIn,
2992
3066
  {
2993
3067
  routing: "hash",
@@ -2995,7 +3069,7 @@ function ChapterAdmin(props) {
2995
3069
  signUpForceRedirectUrl: redirect
2996
3070
  }
2997
3071
  ) }) }),
2998
- /* @__PURE__ */ jsx30(SignedIn, { children: /* @__PURE__ */ jsx30(
3072
+ /* @__PURE__ */ jsx31(SignedIn, { children: /* @__PURE__ */ jsx31(
2999
3073
  Authed,
3000
3074
  {
3001
3075
  workspaces,
@@ -3016,7 +3090,7 @@ function ChapterAdmin(props) {
3016
3090
  }
3017
3091
  );
3018
3092
  }
3019
- return /* @__PURE__ */ jsx30(AdminTheme, { chapter: props.chapter, scopeRef, children: content });
3093
+ return /* @__PURE__ */ jsx31(AdminTheme, { chapter: props.chapter, scopeRef, children: content });
3020
3094
  }
3021
3095
 
3022
3096
  // src/ui/admin-defaults.ts
@@ -3025,17 +3099,17 @@ function defaultAdminSections(chapter) {
3025
3099
  }
3026
3100
 
3027
3101
  // src/ui/admin-meetings.tsx
3028
- import { useState as useState23 } from "preact/hooks";
3029
- import { Button as Button12 } from "@odla-ai/ui/components";
3030
- import { Fragment as Fragment8, jsx as jsx31, jsxs as jsxs27 } from "preact/jsx-runtime";
3102
+ import { useState as useState25 } from "preact/hooks";
3103
+ import { Button as Button14 } from "@odla-ai/ui/components";
3104
+ import { Fragment as Fragment9, jsx as jsx32, jsxs as jsxs28 } from "preact/jsx-runtime";
3031
3105
  var when2 = (t) => new Date(t).toLocaleString([], { dateStyle: "medium", timeStyle: "short" });
3032
3106
  function MeetingsBody({ ctx }) {
3033
3107
  const copy = useChapterCopy().admin.meetings;
3034
3108
  const { data, loading, error, refresh } = useAdminResource(ctx.getToken, "/api/admin/meetings?all=1");
3035
- const [busy, setBusy] = useState23(null);
3036
- const [note, setNote] = useState23(null);
3037
- if (loading) return /* @__PURE__ */ jsx31(AdminNote, { children: copy.loading });
3038
- if (error || !data) return /* @__PURE__ */ jsxs27(AdminNote, { children: [
3109
+ const [busy, setBusy] = useState25(null);
3110
+ const [note, setNote] = useState25(null);
3111
+ if (loading) return /* @__PURE__ */ jsx32(AdminNote, { children: copy.loading });
3112
+ if (error || !data) return /* @__PURE__ */ jsxs28(AdminNote, { children: [
3039
3113
  copy.loadFailed,
3040
3114
  error ? `: ${error}` : "",
3041
3115
  "."
@@ -3066,43 +3140,43 @@ function MeetingsBody({ ctx }) {
3066
3140
  }
3067
3141
  void run(id, () => adminFetch(ctx.getToken, `/api/admin/meetings/${id}/reschedule`, { method: "POST", body: JSON.stringify({ startAt }) }));
3068
3142
  };
3069
- return /* @__PURE__ */ jsx31(AdminPage, { children: /* @__PURE__ */ jsx31(Panel, { title: /* @__PURE__ */ jsxs27(Fragment8, { children: [
3143
+ return /* @__PURE__ */ jsx32(AdminPage, { children: /* @__PURE__ */ jsx32(Panel, { title: /* @__PURE__ */ jsxs28(Fragment9, { children: [
3070
3144
  copy.agenda,
3071
3145
  " ",
3072
- /* @__PURE__ */ jsxs27("span", { className: "muted", style: { fontWeight: 400 }, children: [
3146
+ /* @__PURE__ */ jsxs28("span", { className: "muted", style: { fontWeight: 400 }, children: [
3073
3147
  "\xB7 ",
3074
3148
  data.timezone
3075
3149
  ] })
3076
- ] }), actions: note ? /* @__PURE__ */ jsx31("span", { className: "muted", children: note }) : void 0, children: data.meetings.length === 0 ? /* @__PURE__ */ jsx31("p", { className: "muted", style: { margin: 0 }, children: copy.empty }) : /* @__PURE__ */ jsx31("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: 12 }, children: data.meetings.map((m) => /* @__PURE__ */ jsxs27("li", { style: { display: "flex", alignItems: "center", gap: 12, flexWrap: "wrap", opacity: m.status === "cancelled" ? 0.55 : 1 }, children: [
3077
- /* @__PURE__ */ jsx31("strong", { style: { minWidth: 170 }, children: when2(m.startAt) }),
3078
- /* @__PURE__ */ jsx31("span", { style: { flex: 1 }, children: m.applicant ? `${m.applicant.name} \xB7 ${m.applicant.email}` : copy.unknown }),
3079
- /* @__PURE__ */ jsx31("span", { className: "badge", children: m.status }),
3080
- m.drift && m.drift !== "none" ? /* @__PURE__ */ jsxs27("span", { className: "badge", children: [
3150
+ ] }), actions: note ? /* @__PURE__ */ jsx32("span", { className: "muted", children: note }) : void 0, children: data.meetings.length === 0 ? /* @__PURE__ */ jsx32("p", { className: "muted", style: { margin: 0 }, children: copy.empty }) : /* @__PURE__ */ jsx32("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: 12 }, children: data.meetings.map((m) => /* @__PURE__ */ jsxs28("li", { style: { display: "flex", alignItems: "center", gap: 12, flexWrap: "wrap", opacity: m.status === "cancelled" ? 0.55 : 1 }, children: [
3151
+ /* @__PURE__ */ jsx32("strong", { style: { minWidth: 170 }, children: when2(m.startAt) }),
3152
+ /* @__PURE__ */ jsx32("span", { style: { flex: 1 }, children: m.applicant ? `${m.applicant.name} \xB7 ${m.applicant.email}` : copy.unknown }),
3153
+ /* @__PURE__ */ jsx32("span", { className: "badge", children: m.status }),
3154
+ m.drift && m.drift !== "none" ? /* @__PURE__ */ jsxs28("span", { className: "badge", children: [
3081
3155
  copy.drift,
3082
3156
  ": ",
3083
3157
  m.drift
3084
3158
  ] }) : null,
3085
- m.meetUrl ? /* @__PURE__ */ jsx31("a", { href: m.meetUrl, target: "_blank", rel: "noreferrer", children: copy.meet }) : null,
3086
- m.status === "scheduled" ? /* @__PURE__ */ jsxs27(Fragment8, { children: [
3087
- /* @__PURE__ */ jsx31(Button12, { variant: "secondary", mini: true, disabled: busy === m.id, onClick: () => reschedule(m.id), children: copy.reschedule }),
3088
- /* @__PURE__ */ jsx31(Button12, { variant: "danger", mini: true, disabled: busy === m.id, onClick: () => cancel(m.id), children: copy.cancel })
3159
+ m.meetUrl ? /* @__PURE__ */ jsx32("a", { href: m.meetUrl, target: "_blank", rel: "noreferrer", children: copy.meet }) : null,
3160
+ m.status === "scheduled" ? /* @__PURE__ */ jsxs28(Fragment9, { children: [
3161
+ /* @__PURE__ */ jsx32(Button14, { variant: "secondary", mini: true, disabled: busy === m.id, onClick: () => reschedule(m.id), children: copy.reschedule }),
3162
+ /* @__PURE__ */ jsx32(Button14, { variant: "danger", mini: true, disabled: busy === m.id, onClick: () => cancel(m.id), children: copy.cancel })
3089
3163
  ] }) : null
3090
3164
  ] }, m.id)) }) }) });
3091
3165
  }
3092
3166
  function meetingsSection(options = {}) {
3093
3167
  const { id = "meetings", label = "Meetings" } = options;
3094
- return { id, label, render: (ctx) => /* @__PURE__ */ jsx31(MeetingsBody, { ctx }) };
3168
+ return { id, label, render: (ctx) => /* @__PURE__ */ jsx32(MeetingsBody, { ctx }) };
3095
3169
  }
3096
3170
 
3097
3171
  // src/ui/admin-network-record-editor.tsx
3098
- import { Button as Button13, Field as Field10, Select as Select6 } from "@odla-ai/ui/components";
3099
- import { useRef as useRef4, useState as useState24 } from "preact/hooks";
3100
- import { Fragment as Fragment9, jsx as jsx32, jsxs as jsxs28 } from "preact/jsx-runtime";
3172
+ import { Button as Button15, Field as Field10, Select as Select6 } from "@odla-ai/ui/components";
3173
+ import { useRef as useRef4, useState as useState26 } from "preact/hooks";
3174
+ import { Fragment as Fragment10, jsx as jsx33, jsxs as jsxs29 } from "preact/jsx-runtime";
3101
3175
  function NetworkRecordEditor(props) {
3102
3176
  const { ctx, record } = props;
3103
- const [stage, setStage] = useState24("");
3104
- const [busy, setBusy] = useState24(false);
3105
- const [error, setError] = useState24(null);
3177
+ const [stage, setStage] = useState26("");
3178
+ const [busy, setBusy] = useState26(false);
3179
+ const [error, setError] = useState26(null);
3106
3180
  const attempt = useRef4(null);
3107
3181
  const pending = record.edit?.pendingAction;
3108
3182
  const superAdmin = ctx.currentUser?.superAdmin === true;
@@ -3135,11 +3209,11 @@ function NetworkRecordEditor(props) {
3135
3209
  setBusy(false);
3136
3210
  }
3137
3211
  };
3138
- return /* @__PURE__ */ jsxs28("div", { style: { display: "grid", gap: 24 }, children: [
3139
- superAdmin && record.edit ? /* @__PURE__ */ jsxs28(Fragment9, { children: [
3140
- /* @__PURE__ */ jsxs28("section", { children: [
3141
- /* @__PURE__ */ jsx32("h3", { children: "Chapter profile" }),
3142
- /* @__PURE__ */ jsx32(
3212
+ return /* @__PURE__ */ jsxs29("div", { style: { display: "grid", gap: 24 }, children: [
3213
+ superAdmin && record.edit ? /* @__PURE__ */ jsxs29(Fragment10, { children: [
3214
+ /* @__PURE__ */ jsxs29("section", { children: [
3215
+ /* @__PURE__ */ jsx33("h3", { children: "Chapter profile" }),
3216
+ /* @__PURE__ */ jsx33(
3143
3217
  OperationalProfileForm,
3144
3218
  {
3145
3219
  fields: record.edit.fields,
@@ -3149,27 +3223,27 @@ function NetworkRecordEditor(props) {
3149
3223
  `${record.id}:${record.revision}`
3150
3224
  )
3151
3225
  ] }),
3152
- /* @__PURE__ */ jsxs28("section", { style: { display: "grid", gap: 12 }, children: [
3153
- /* @__PURE__ */ jsx32("h3", { children: "Membership actions" }),
3154
- pending ? /* @__PURE__ */ jsxs28("p", { children: [
3226
+ /* @__PURE__ */ jsxs29("section", { style: { display: "grid", gap: 12 }, children: [
3227
+ /* @__PURE__ */ jsx33("h3", { children: "Membership actions" }),
3228
+ pending ? /* @__PURE__ */ jsxs29("p", { children: [
3155
3229
  "An application action is pending: ",
3156
3230
  pending.stage.replaceAll("_", " "),
3157
3231
  ". ",
3158
3232
  ownPending ? "Retry reconciles the same operation." : "The original operator must reconcile it."
3159
- ] }) : record.edit.allowedStages.length ? /* @__PURE__ */ jsx32(Field10, { label: "Action", children: /* @__PURE__ */ jsxs28(Select6, { "aria-label": "Action", value: stage, disabled: busy, onChange: (event) => setStage(event.currentTarget.value), children: [
3160
- /* @__PURE__ */ jsx32("option", { value: "", children: "Choose an action" }),
3161
- record.edit.allowedStages.map((action) => /* @__PURE__ */ jsx32("option", { value: action.id, children: action.label }, action.id))
3162
- ] }) }) : /* @__PURE__ */ jsx32("p", { children: "No membership action is currently allowed." }),
3163
- pending || record.edit.allowedStages.length ? /* @__PURE__ */ jsx32("div", { children: /* @__PURE__ */ jsx32(Button13, { disabled: busy || !ownPending || !pending && !stage, onClick: () => void move(), children: busy ? "Applying\u2026" : pending ? "Retry pending action" : "Apply action" }) }) : null,
3164
- error ? /* @__PURE__ */ jsx32("p", { role: "alert", children: error }) : null
3233
+ ] }) : record.edit.allowedStages.length ? /* @__PURE__ */ jsx33(Field10, { label: "Action", children: /* @__PURE__ */ jsxs29(Select6, { "aria-label": "Action", value: stage, disabled: busy, onChange: (event) => setStage(event.currentTarget.value), children: [
3234
+ /* @__PURE__ */ jsx33("option", { value: "", children: "Choose an action" }),
3235
+ record.edit.allowedStages.map((action) => /* @__PURE__ */ jsx33("option", { value: action.id, children: action.label }, action.id))
3236
+ ] }) }) : /* @__PURE__ */ jsx33("p", { children: "No membership action is currently allowed." }),
3237
+ pending || record.edit.allowedStages.length ? /* @__PURE__ */ jsx33("div", { children: /* @__PURE__ */ jsx33(Button15, { disabled: busy || !ownPending || !pending && !stage, onClick: () => void move(), children: busy ? "Applying\u2026" : pending ? "Retry pending action" : "Apply action" }) }) : null,
3238
+ error ? /* @__PURE__ */ jsx33("p", { role: "alert", children: error }) : null
3165
3239
  ] })
3166
3240
  ] }) : null,
3167
- superAdmin && props.admissionGrants ? /* @__PURE__ */ jsxs28("section", { children: [
3168
- /* @__PURE__ */ jsx32("h3", { children: "Next invitation" }),
3169
- /* @__PURE__ */ jsx32("p", { children: "This setting applies to the next eligible signup; it does not replace approval of an existing application." }),
3170
- /* @__PURE__ */ jsx32(LeaderAdmissionAction, { getToken: ctx.getToken, targetId: props.targetId, sourceRecordId: record.id })
3241
+ superAdmin && props.admissionGrants ? /* @__PURE__ */ jsxs29("section", { children: [
3242
+ /* @__PURE__ */ jsx33("h3", { children: "Next invitation" }),
3243
+ /* @__PURE__ */ jsx33("p", { children: "This setting applies to the next eligible signup; it does not replace approval of an existing application." }),
3244
+ /* @__PURE__ */ jsx33(LeaderAdmissionAction, { getToken: ctx.getToken, targetId: props.targetId, sourceRecordId: record.id })
3171
3245
  ] }) : null,
3172
- /* @__PURE__ */ jsx32(
3246
+ /* @__PURE__ */ jsx33(
3173
3247
  NetworkRecordDetail,
3174
3248
  {
3175
3249
  ctx,
@@ -3183,6 +3257,35 @@ function NetworkRecordEditor(props) {
3183
3257
  ] });
3184
3258
  }
3185
3259
 
3260
+ // src/ui/network-seat-billing.tsx
3261
+ import { DataTable as DataTable4 } from "@odla-ai/ui/components";
3262
+ import { jsx as jsx34, jsxs as jsxs30 } from "preact/jsx-runtime";
3263
+ var money3 = (row, cents) => row.currency ? new Intl.NumberFormat("en-US", {
3264
+ style: "currency",
3265
+ currency: row.currency
3266
+ }).format(cents / 100) : "Unknown";
3267
+ var columns2 = [
3268
+ { key: "seatId", header: "Seat", cell: (row) => /* @__PURE__ */ jsx34("code", { children: row.seatId }) },
3269
+ { key: "sourceKey", header: "Chapter / runtime", cell: (row) => row.sourceKey },
3270
+ { key: "status", header: "Payment", cell: (row) => row.status ?? "Unknown" },
3271
+ { key: "amountReceivedCents", header: "Collected", cell: (row) => money3(row, row.amountReceivedCents) },
3272
+ { key: "refundedCents", header: "Refunded", cell: (row) => money3(row, row.refundedCents) },
3273
+ { key: "membershipId", header: "Primary membership", cell: (row) => /* @__PURE__ */ jsx34("code", { children: row.membershipId }) },
3274
+ { key: "paymentIntentId", header: "Stripe payment", cell: (row) => /* @__PURE__ */ jsx34("code", { children: row.paymentIntentId }) },
3275
+ { key: "subscriptionItemId", header: "Renewal item", cell: (row) => row.subscriptionItemId ? /* @__PURE__ */ jsx34("code", { children: row.subscriptionItemId }) : "Awaiting provider linkage" },
3276
+ { key: "currentPeriodEnd", header: "Paid through", cell: (row) => row.currentPeriodEnd ? new Date(row.currentPeriodEnd * 1e3).toLocaleDateString() : "Awaiting provider linkage" }
3277
+ ];
3278
+ function NetworkSeatBilling(props) {
3279
+ const { data, loading, error } = useAdminResource(props.getToken, "/api/admin/network-commercial-read-model");
3280
+ return /* @__PURE__ */ jsxs30(Panel, { title: "Additional membership seats", children: [
3281
+ /* @__PURE__ */ jsx34("p", { children: "Seat payments are included in the network totals. Renewal items share the primary subscription\u2019s term." }),
3282
+ loading ? /* @__PURE__ */ jsx34("p", { children: "Loading seats\u2026" }) : error ? /* @__PURE__ */ jsxs30("p", { role: "alert", children: [
3283
+ "Seats could not be loaded: ",
3284
+ error
3285
+ ] }) : /* @__PURE__ */ jsx34(DataTable4, { rows: data?.seats ?? [], columns: columns2, rowKey: (row) => `${row.sourceKey}:${row.seatId}` })
3286
+ ] });
3287
+ }
3288
+
3186
3289
  export {
3187
3290
  AdminPage,
3188
3291
  Panel,
@@ -3194,6 +3297,7 @@ export {
3194
3297
  adminSectionHref,
3195
3298
  adminFetch,
3196
3299
  useAdminResource,
3300
+ PaymentRecoveryQueue,
3197
3301
  billingSection,
3198
3302
  dashboardSection,
3199
3303
  RecordActions,
@@ -3219,6 +3323,7 @@ export {
3219
3323
  ChapterAdmin,
3220
3324
  defaultAdminSections,
3221
3325
  meetingsSection,
3222
- NetworkRecordEditor
3326
+ NetworkRecordEditor,
3327
+ NetworkSeatBilling
3223
3328
  };
3224
- //# sourceMappingURL=chunk-MQ4OPZCS.js.map
3329
+ //# sourceMappingURL=chunk-KXIGZWG5.js.map