@odla-ai/chapter 0.62.0 → 0.63.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.
@@ -1,69 +1,20 @@
1
1
  import {
2
2
  DEFAULT_JOIN_COPY,
3
+ dayLabel,
4
+ fmtDate,
5
+ fmtMoney,
3
6
  formatChapterCopy,
7
+ fullLabel,
8
+ groupSlotsByDay,
9
+ timeLabel,
4
10
  useChapterCopy
5
- } from "./chunk-7CVP6VSO.js";
11
+ } from "./chunk-OXYMVK2O.js";
6
12
  import {
7
13
  collectFormFields
8
14
  } from "./chunk-IVXVECKR.js";
9
15
 
10
16
  // src/ui/slot-picker.tsx
11
17
  import { useMemo, useState } from "preact/hooks";
12
-
13
- // src/ui/datetime.ts
14
- function tzShort(tz) {
15
- try {
16
- const parts = new Intl.DateTimeFormat(void 0, { timeZone: tz, timeZoneName: "short" }).formatToParts(
17
- /* @__PURE__ */ new Date()
18
- );
19
- return parts.find((p) => p.type === "timeZoneName")?.value ?? tz;
20
- } catch {
21
- return tz;
22
- }
23
- }
24
- function dayKey(ms, tz) {
25
- return new Date(ms).toLocaleDateString("en-CA", { timeZone: tz });
26
- }
27
- function dayLabel(ms, tz) {
28
- return new Date(ms).toLocaleDateString(void 0, { timeZone: tz, weekday: "short", month: "short", day: "numeric" });
29
- }
30
- function timeLabel(ms, tz) {
31
- return new Date(ms).toLocaleTimeString(void 0, {
32
- timeZone: tz,
33
- hour: "numeric",
34
- minute: "2-digit",
35
- timeZoneName: "short"
36
- });
37
- }
38
- function fullLabel(ms, tz) {
39
- return new Date(ms).toLocaleString(void 0, {
40
- timeZone: tz,
41
- weekday: "long",
42
- month: "long",
43
- day: "numeric",
44
- hour: "numeric",
45
- minute: "2-digit",
46
- timeZoneName: "short"
47
- });
48
- }
49
- function fmtMoney(cents) {
50
- return "$" + Math.round(cents / 100).toLocaleString();
51
- }
52
- function fmtDate(ms) {
53
- return new Date(ms).toLocaleDateString(void 0, { month: "short", day: "numeric", year: "numeric" });
54
- }
55
- function groupSlotsByDay(slots, tz) {
56
- const byDay = /* @__PURE__ */ new Map();
57
- for (const s of slots) {
58
- const k = dayKey(s.startAt, tz);
59
- const bucket = byDay.get(k);
60
- if (bucket) bucket.push(s);
61
- else byDay.set(k, [s]);
62
- }
63
- return byDay;
64
- }
65
-
66
- // src/ui/slot-picker.tsx
67
18
  import { Fragment, jsx, jsxs } from "preact/jsx-runtime";
68
19
  var DEFAULT_CLASSES = {
69
20
  days: "slot-days",
@@ -867,7 +818,7 @@ function MemberRestart(props) {
867
818
  }
868
819
 
869
820
  // src/ui/members.tsx
870
- import { useEffect as useEffect8, useState as useState15 } from "preact/hooks";
821
+ import { useEffect as useEffect11, useState as useState18 } from "preact/hooks";
871
822
 
872
823
  // src/ui/reschedule.tsx
873
824
  import { useState as useState8 } from "preact/hooks";
@@ -1365,14 +1316,14 @@ function MemberContentArea(props) {
1365
1316
  var placeholderBadge = (page) => page.placeholder?.badge ?? (page.placeholder?.availableYear ? `Coming in ${page.placeholder.availableYear}` : "Coming soon");
1366
1317
  function MemberPlaceholderBody({ page }) {
1367
1318
  return /* @__PURE__ */ jsxs15("div", { className: "chapter-member-placeholder", "data-placeholder": true, children: [
1368
- /* @__PURE__ */ jsx16("span", { className: "pill", children: placeholderBadge(page) }),
1319
+ /* @__PURE__ */ jsx16("div", { className: "card-label", children: placeholderBadge(page) }),
1369
1320
  page.bodyMarkdown ? /* @__PURE__ */ jsx16(Markdown, { source: page.bodyMarkdown }) : null,
1370
- page.placeholder?.actionLabel ? /* @__PURE__ */ jsx16("button", { className: "btn", type: "button", disabled: true, children: page.placeholder.actionLabel }) : null
1321
+ page.placeholder?.actionLabel ? /* @__PURE__ */ jsx16("button", { className: "btn secondary", type: "button", disabled: true, children: page.placeholder.actionLabel }) : null
1371
1322
  ] });
1372
1323
  }
1373
1324
 
1374
1325
  // src/ui/member-portal.tsx
1375
- import { useEffect as useEffect7, useMemo as useMemo3, useState as useState14 } from "preact/hooks";
1326
+ import { useEffect as useEffect10, useMemo as useMemo3, useState as useState17 } from "preact/hooks";
1376
1327
 
1377
1328
  // src/ui/member-portal-nav.tsx
1378
1329
  import { ThemeScope } from "@odla-ai/ui/components";
@@ -1421,12 +1372,12 @@ function PortalIcon({ name, size = 18, label }) {
1421
1372
  // src/ui/member-portal-routing.ts
1422
1373
  var PROFILE_SEGMENT = "profile";
1423
1374
  var trimSlashes = (value) => value.replace(/^\/+|\/+$/g, "");
1424
- function routeFromLocation(location, routing) {
1375
+ function routeFromLocation(location2, routing) {
1425
1376
  let segment = "";
1426
- if (routing.mode === "hash") segment = trimSlashes(decodeURIComponent(location.hash.replace(/^#/, "")));
1377
+ if (routing.mode === "hash") segment = trimSlashes(decodeURIComponent(location2.hash.replace(/^#/, "")));
1427
1378
  else {
1428
1379
  const base = `/${trimSlashes(routing.basePath)}`;
1429
- const path = location.pathname;
1380
+ const path = location2.pathname;
1430
1381
  if (path === base || path.startsWith(`${base}/`)) segment = trimSlashes(decodeURIComponent(path.slice(base.length)));
1431
1382
  }
1432
1383
  if (!segment) return { kind: "home" };
@@ -1525,7 +1476,8 @@ import { Markdown as Markdown2 } from "@odla-ai/ui/components";
1525
1476
  import { Fragment as Fragment6, jsx as jsx19, jsxs as jsxs17 } from "preact/jsx-runtime";
1526
1477
  var upsellOf = (page, ctx) => {
1527
1478
  const tierName = page.upsell?.tierName;
1528
- const href = page.upsell && ctx.upsellHref ? ctx.upsellHref(page.upsell.tierId, page) : void 0;
1479
+ const tierId = page.upsell?.tierId ?? (page.audience.kind === "tiers" ? page.audience.tierIds[0] : void 0);
1480
+ const href = tierId && ctx.upsellHref ? ctx.upsellHref(tierId, page) : void 0;
1529
1481
  return { tierName, href, cta: page.upsell?.ctaLabel ?? ctx.copy.pages.upgrade };
1530
1482
  };
1531
1483
  function LockedPill({ page, ctx }) {
@@ -1807,6 +1759,8 @@ var MEMBER_PORTAL_CSS = `
1807
1759
  .chapter-portal-account button.chapter-portal-link,.chapter-portal-account a{display:inline;padding:0;border:0;background:none;color:var(--ui-text,#fff);font:inherit;text-decoration:underline;cursor:pointer}
1808
1760
  .chapter-portal-avatar{display:inline-grid;place-items:center;flex:none;width:28px;height:28px;border-radius:50%;overflow:hidden;background:var(--ui-accent-soft,rgba(124,184,63,.2));color:var(--ui-text,inherit);font-size:.72rem;font-weight:700;letter-spacing:.04em}
1809
1761
  .chapter-portal-avatar img{width:100%;height:100%;object-fit:cover}
1762
+ .chapter-portal-avatar.chapter-portal-profile-photo{width:96px;height:96px;font-size:1.6rem}
1763
+ .chapter-portal-locked-wrap{position:relative}
1810
1764
  .chapter-portal-main{min-width:0;padding:clamp(1rem,3vw,2.5rem);display:flex;flex-direction:column;gap:1.5rem}
1811
1765
  .chapter-portal-top{display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap}
1812
1766
  .chapter-portal-top h1{margin:0;font-family:var(--ui-font-display,inherit);font-weight:400;font-size:clamp(1.8rem,4vw,2.4rem);line-height:1.1}
@@ -1830,6 +1784,25 @@ var MEMBER_PORTAL_CSS = `
1830
1784
  .chapter-portal-btn:disabled{opacity:.5;cursor:not-allowed}
1831
1785
  .chapter-portal-btns{display:flex;flex-wrap:wrap;gap:.6rem}
1832
1786
  .chapter-portal :where(button,a,input,textarea,select):focus-visible{outline:3px solid var(--ui-focus,var(--ui-accent,#7cb83f));outline-offset:2px}
1787
+ .chapter-portal-modal-back{position:fixed;inset:0;z-index:50;display:grid;place-items:center;padding:1rem;background:color-mix(in srgb,var(--ui-text,#2f3e34) 45%,transparent)}
1788
+ .chapter-portal-modal{position:relative;width:min(100%,46rem);max-height:90vh;overflow:auto}
1789
+ .chapter-portal-modal-x{position:absolute;top:.75rem;right:.75rem;width:40px;height:40px;border:0;border-radius:50%;background:transparent;color:inherit;cursor:pointer}
1790
+ .chapter-portal-link-box{display:flex;align-items:center;justify-content:space-between;gap:.75rem;flex-wrap:wrap;margin:.75rem 0;padding:.5rem .5rem .5rem 1rem;border:1px solid var(--ui-border,#e2dccf);border-radius:999px;background:var(--ui-bg,#f4efe6)}
1791
+ .chapter-portal-link-box code{overflow-wrap:anywhere;font-size:.9rem}
1792
+ .chapter-portal-tally{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:.75rem}
1793
+ .chapter-portal-tally[data-tiles="2"]{grid-template-columns:repeat(2,minmax(0,1fr))}
1794
+ .chapter-portal-tally>div{display:flex;flex-direction:column;padding:.9rem;border:1px solid var(--ui-border,#e2dccf);border-radius:var(--ui-radius-sm,10px)}
1795
+ .chapter-portal-tally b{font-family:var(--ui-font-numeral,var(--ui-font-display,inherit));font-size:1.8rem;font-weight:400}
1796
+ .chapter-portal-tally span{font-size:.8rem;color:var(--ui-text-muted,#7e8e84)}
1797
+ .chapter-portal-fallback{margin-top:1rem;padding:1rem;border:1px dashed var(--ui-border-strong,#aeb9b5);border-radius:var(--ui-radius-sm,10px)}
1798
+ .chapter-portal-material{display:flex;align-items:center;gap:.6rem;flex-wrap:wrap;padding:.35rem 0;list-style:none}
1799
+ .chapter-portal-material small{color:var(--ui-text-muted,#7e8e84)}
1800
+ .chapter-portal-material a{margin-left:auto}
1801
+ .chapter-portal details{border-top:1px solid var(--ui-border,#e2dccf);padding:.75rem 0}
1802
+ .chapter-portal summary{cursor:pointer}
1803
+ .chapter-portal dl{display:grid;grid-template-columns:auto 1fr;gap:.3rem 1rem;margin:.75rem 0}
1804
+ .chapter-portal dt{color:var(--ui-text-muted,#7e8e84)}
1805
+ .chapter-portal dd{margin:0}
1833
1806
  .chapter-portal-mobile{display:none}
1834
1807
  @media (max-width:860px){
1835
1808
  .chapter-portal{grid-template-columns:minmax(0,1fr)}
@@ -1839,23 +1812,388 @@ var MEMBER_PORTAL_CSS = `
1839
1812
  .chapter-portal-burger{display:inline-grid;place-items:center;width:44px;height:44px;border:0;border-radius:8px;background:transparent;color:inherit;cursor:pointer}
1840
1813
  .chapter-portal-mobile-menu{display:flex;flex-direction:column;gap:1rem;padding:0 1rem 1.25rem}
1841
1814
  .chapter-portal-mobile .chapter-portal-brand{font-size:1.15rem;padding:0}
1815
+ .chapter-portal-modal-back{place-items:end stretch;padding:0}
1816
+ .chapter-portal-modal{width:100%;border-radius:var(--ui-radius-lg,14px) var(--ui-radius-lg,14px) 0 0}
1842
1817
  }
1843
1818
  `;
1844
1819
 
1820
+ // src/ui/member-course-page.tsx
1821
+ import { useEffect as useEffect7, useState as useState14 } from "preact/hooks";
1822
+ import { Markdown as Markdown3 } from "@odla-ai/ui/components";
1823
+ import { Fragment as Fragment8, jsx as jsx21, jsxs as jsxs19 } from "preact/jsx-runtime";
1824
+ function useCourse(ctx, courseId) {
1825
+ const [view, setView] = useState14(null);
1826
+ const [error, setError] = useState14(null);
1827
+ const [busy, setBusy] = useState14(false);
1828
+ useEffect7(() => {
1829
+ if (!courseId) return;
1830
+ let live = true;
1831
+ void ctx.api(`/api/member/courses/${encodeURIComponent(courseId)}`).then((v) => live && setView(v)).catch(() => live && setError(ctx.copy.course.failed));
1832
+ return () => {
1833
+ live = false;
1834
+ };
1835
+ }, [courseId]);
1836
+ const act = async (action) => {
1837
+ setBusy(true);
1838
+ setError(null);
1839
+ try {
1840
+ setView(await ctx.api(`/api/member/courses/${encodeURIComponent(courseId)}/${action}`, { method: "POST" }));
1841
+ } catch {
1842
+ setError(ctx.copy.course.failed);
1843
+ } finally {
1844
+ setBusy(false);
1845
+ }
1846
+ };
1847
+ return { view, error, busy, act };
1848
+ }
1849
+ function seatLine(view, copy) {
1850
+ if (view.enrollment?.status === "enrolled") return copy.invitesOnWay;
1851
+ if (view.enrollment?.status === "waitlisted") return formatChapterCopy(copy.onWaitlist, { position: String(view.enrollment.waitlistPosition ?? "") });
1852
+ if (view.course.status === "closed") return copy.closed;
1853
+ return formatChapterCopy(copy.seatsOpen, { left: String(view.course.seatsLeft), capacity: String(view.course.capacity) });
1854
+ }
1855
+ function SeatActions({ ctx, course, details }) {
1856
+ const copy = ctx.copy.course;
1857
+ const view = course.view;
1858
+ const status = view.enrollment?.status;
1859
+ const confirmThen = (action) => {
1860
+ if (window.confirm(copy.confirmGiveUp)) void course.act(action);
1861
+ };
1862
+ return /* @__PURE__ */ jsxs19("div", { className: "chapter-portal-btns", children: [
1863
+ status === "enrolled" ? /* @__PURE__ */ jsx21("span", { className: "chapter-portal-pill", children: copy.youreIn }) : null,
1864
+ status === "enrolled" && view.meetUrl ? /* @__PURE__ */ jsx21("a", { className: "chapter-portal-btn", href: view.meetUrl, target: "_blank", rel: "noopener", children: copy.openMeet }) : null,
1865
+ status === "enrolled" ? /* @__PURE__ */ jsx21("button", { type: "button", className: "chapter-portal-btn", "data-variant": "ghost", disabled: course.busy, onClick: () => confirmThen("withdraw"), children: copy.giveUp }) : null,
1866
+ status === "waitlisted" ? /* @__PURE__ */ jsx21("button", { type: "button", className: "chapter-portal-btn", "data-variant": "ghost", disabled: course.busy, onClick: () => void course.act("withdraw"), children: copy.leaveWaitlist }) : null,
1867
+ !status && view.course.status !== "closed" ? /* @__PURE__ */ jsx21("button", { type: "button", className: "chapter-portal-btn", disabled: course.busy, onClick: () => void course.act("enroll"), children: view.course.status === "full" ? copy.joinWaitlist : copy.reserve }) : null,
1868
+ details ? /* @__PURE__ */ jsx21("button", { type: "button", className: "chapter-portal-btn", "data-variant": "ghost", onClick: details, children: status === "enrolled" ? copy.courseDetails : copy.seeDetails }) : null
1869
+ ] });
1870
+ }
1871
+ var MaterialItem = ({ item, kind, ctx, enrolled }) => /* @__PURE__ */ jsxs19("li", { className: "chapter-portal-material", children: [
1872
+ kind ? /* @__PURE__ */ jsx21("span", { className: "chapter-portal-pill", children: ctx.copy.course[kind] }) : null,
1873
+ /* @__PURE__ */ jsxs19("span", { children: [
1874
+ item.label,
1875
+ item.meta ? /* @__PURE__ */ jsxs19("small", { children: [
1876
+ " \xB7 ",
1877
+ item.meta
1878
+ ] }) : null
1879
+ ] }),
1880
+ enrolled && item.url ? /* @__PURE__ */ jsx21("a", { href: item.url, target: "_blank", rel: "noopener", children: ctx.copy.course.open }) : null
1881
+ ] });
1882
+ function CoursePage({ page, ctx }) {
1883
+ const course = useCourse(ctx, page.feature?.ref);
1884
+ const copy = ctx.copy.course;
1885
+ if (!course.view) return /* @__PURE__ */ jsx21("p", { children: course.error ?? ctx.copy.shell.loading });
1886
+ const { course: c } = course.view;
1887
+ const enrolled = course.view.enrollment?.status === "enrolled";
1888
+ return /* @__PURE__ */ jsxs19("div", { className: "chapter-portal-stack", "data-course-page": true, children: [
1889
+ /* @__PURE__ */ jsxs19("div", { className: "chapter-portal-card ui-invert", style: { display: "grid", gap: "1.25rem", gridTemplateColumns: "repeat(auto-fit,minmax(min(100%,18rem),1fr))" }, children: [
1890
+ /* @__PURE__ */ jsxs19("div", { children: [
1891
+ /* @__PURE__ */ jsx21("h1", { style: { fontFamily: "var(--ui-font-display,inherit)", fontWeight: 400, margin: 0 }, children: c.title }),
1892
+ c.content.basedOn ? /* @__PURE__ */ jsx21("p", { style: { fontStyle: "italic" }, children: c.content.basedOn }) : null,
1893
+ c.content.short ? /* @__PURE__ */ jsx21("p", { children: c.content.short }) : null
1894
+ ] }),
1895
+ /* @__PURE__ */ jsxs19("div", { className: "chapter-portal-card", "data-seat-box": true, children: [
1896
+ !course.view.enrollment ? /* @__PURE__ */ jsx21("div", { className: "chapter-portal-group-label", style: { padding: 0 }, children: copy.reserveYourSeat }) : null,
1897
+ /* @__PURE__ */ jsxs19("dl", { children: [
1898
+ c.content.when ? /* @__PURE__ */ jsxs19(Fragment8, { children: [
1899
+ /* @__PURE__ */ jsx21("dt", { children: copy.when }),
1900
+ /* @__PURE__ */ jsx21("dd", { children: c.content.when })
1901
+ ] }) : null,
1902
+ c.content.dates ?? c.content.start ? /* @__PURE__ */ jsxs19(Fragment8, { children: [
1903
+ /* @__PURE__ */ jsx21("dt", { children: copy.dates }),
1904
+ /* @__PURE__ */ jsx21("dd", { children: c.content.dates ?? c.content.start })
1905
+ ] }) : null,
1906
+ /* @__PURE__ */ jsx21("dt", { children: copy.where }),
1907
+ /* @__PURE__ */ jsx21("dd", { children: copy.googleMeet }),
1908
+ /* @__PURE__ */ jsx21("dt", { children: copy.seats }),
1909
+ /* @__PURE__ */ jsx21("dd", { children: seatLine(course.view, copy) })
1910
+ ] }),
1911
+ /* @__PURE__ */ jsx21(SeatActions, { ctx, course }),
1912
+ !course.view.enrollment ? /* @__PURE__ */ jsx21("p", { style: { color: "var(--ui-text-muted)" }, children: copy.inviteEvery }) : null,
1913
+ course.error ? /* @__PURE__ */ jsx21("p", { role: "alert", children: course.error }) : null
1914
+ ] })
1915
+ ] }),
1916
+ c.guides.length ? /* @__PURE__ */ jsxs19("div", { className: "chapter-portal-card", children: [
1917
+ /* @__PURE__ */ jsx21("h2", { children: copy.guidesTitle }),
1918
+ /* @__PURE__ */ jsx21("div", { className: "chapter-portal-tiles", children: c.guides.map((guide) => /* @__PURE__ */ jsxs19("div", { children: [
1919
+ guide.photoUrl ? /* @__PURE__ */ jsx21("img", { src: guide.photoUrl, alt: guide.name, style: { width: 72, height: 72, borderRadius: "50%", objectFit: "cover" } }) : null,
1920
+ /* @__PURE__ */ jsx21("h3", { children: guide.name }),
1921
+ guide.role ? /* @__PURE__ */ jsx21("div", { style: { color: "var(--ui-text-muted)" }, children: guide.role }) : null,
1922
+ guide.bio ? /* @__PURE__ */ jsx21("p", { children: guide.bio }) : null
1923
+ ] }, guide.name)) })
1924
+ ] }) : null,
1925
+ /* @__PURE__ */ jsxs19("div", { className: "chapter-portal-card", "data-sessions": true, children: [
1926
+ /* @__PURE__ */ jsx21("h2", { children: copy.sessionsTitle }),
1927
+ /* @__PURE__ */ jsx21("p", { style: { color: "var(--ui-text-muted)" }, children: enrolled ? copy.materialsOpen : copy.materialsLocked }),
1928
+ c.sessions.map((session, index) => /* @__PURE__ */ jsxs19("details", { open: enrolled && index === 0, children: [
1929
+ /* @__PURE__ */ jsxs19("summary", { children: [
1930
+ /* @__PURE__ */ jsx21("strong", { children: session.date }),
1931
+ " \xB7 ",
1932
+ session.topic,
1933
+ session.materials.length ? /* @__PURE__ */ jsxs19("small", { children: [
1934
+ " \xB7 ",
1935
+ formatChapterCopy(copy.items, { count: String(session.materials.length) })
1936
+ ] }) : null
1937
+ ] }),
1938
+ session.description ? /* @__PURE__ */ jsx21("p", { children: session.description }) : null,
1939
+ /* @__PURE__ */ jsx21("ul", { children: session.materials.map((item) => /* @__PURE__ */ jsx21(MaterialItem, { item, kind: item.kind, ctx, enrolled }, item.label)) })
1940
+ ] }, session.startsAt))
1941
+ ] }),
1942
+ /* @__PURE__ */ jsxs19("div", { className: "chapter-portal-tiles", children: [
1943
+ c.content.outcomes?.length ? /* @__PURE__ */ jsxs19("div", { className: "chapter-portal-card", children: [
1944
+ /* @__PURE__ */ jsx21("h2", { children: copy.outcomesTitle }),
1945
+ /* @__PURE__ */ jsx21("ul", { children: c.content.outcomes.map((o) => /* @__PURE__ */ jsx21("li", { children: o }, o)) })
1946
+ ] }) : null,
1947
+ c.toolkit.length || c.content.time ? /* @__PURE__ */ jsxs19("div", { className: "chapter-portal-card", children: [
1948
+ /* @__PURE__ */ jsx21("h2", { children: copy.toolkitTitle }),
1949
+ /* @__PURE__ */ jsx21("ul", { children: c.toolkit.map((item) => /* @__PURE__ */ jsx21(MaterialItem, { item, ctx, enrolled }, item.label)) }),
1950
+ c.content.time ? /* @__PURE__ */ jsxs19(Fragment8, { children: [
1951
+ /* @__PURE__ */ jsx21("h2", { children: copy.timeTitle }),
1952
+ /* @__PURE__ */ jsx21("p", { children: c.content.time })
1953
+ ] }) : null
1954
+ ] }) : null
1955
+ ] }),
1956
+ c.content.partnerMarkdown ? /* @__PURE__ */ jsx21("div", { className: "chapter-portal-card", children: /* @__PURE__ */ jsx21(Markdown3, { source: c.content.partnerMarkdown }) }) : null
1957
+ ] });
1958
+ }
1959
+ function CourseHomePanel({ page, ctx }) {
1960
+ const locked = page.access === "locked";
1961
+ const course = useCourse(ctx, locked ? void 0 : page.feature?.ref);
1962
+ const view = course.view;
1963
+ return /* @__PURE__ */ jsxs19("div", { className: "chapter-portal-card", "data-course-panel": true, children: [
1964
+ /* @__PURE__ */ jsx21("div", { className: "chapter-portal-group-label", style: { padding: 0 }, children: ctx.copy.course.eyebrow }),
1965
+ /* @__PURE__ */ jsx21("h2", { children: view?.course.title ?? page.title }),
1966
+ view?.course.content.basedOn ? /* @__PURE__ */ jsx21("p", { style: { fontStyle: "italic" }, children: view.course.content.basedOn }) : null,
1967
+ /* @__PURE__ */ jsx21("p", { children: view?.course.content.short ?? page.summary }),
1968
+ view ? /* @__PURE__ */ jsxs19(Fragment8, { children: [
1969
+ /* @__PURE__ */ jsx21("p", { children: [view.course.content.when, view.course.content.start].filter(Boolean).join(" \xB7 ") }),
1970
+ /* @__PURE__ */ jsx21("p", { children: /* @__PURE__ */ jsx21("strong", { children: seatLine(view, ctx.copy.course) }) }),
1971
+ /* @__PURE__ */ jsx21(SeatActions, { ctx, course, details: () => ctx.navigate({ kind: "page", slug: page.slug }) })
1972
+ ] }) : null
1973
+ ] });
1974
+ }
1975
+
1976
+ // src/ui/member-share-page.tsx
1977
+ import { useEffect as useEffect9, useState as useState16 } from "preact/hooks";
1978
+
1979
+ // src/ui/member-share.ts
1980
+ import { useEffect as useEffect8, useState as useState15 } from "preact/hooks";
1981
+ var articleFor = (word) => /^[aeiou]/i.test(word.trim()) ? "an" : "a";
1982
+ function shareVars(me, referrals) {
1983
+ const tierName = me.tier?.name ?? "";
1984
+ return {
1985
+ tierName,
1986
+ article: articleFor(tierName),
1987
+ inviteUrl: referrals?.link ?? "",
1988
+ firstName: me.firstName ?? me.displayName.split(/\s+/)[0] ?? "",
1989
+ location: me.location ?? "",
1990
+ credit: referrals?.credit ? fmtMoney(referrals.credit.perFriendCents).replace(/\.00$/, "") : ""
1991
+ };
1992
+ }
1993
+ var fill = (template, vars) => formatChapterCopy(template, vars);
1994
+ var linkedinShareUrl = (post, link) => `https://www.linkedin.com/feed/?shareActive=true&text=${encodeURIComponent(`${post}
1995
+
1996
+
1997
+ ${link}`).replace(/'/g, "%27")}`;
1998
+ var mailtoHref = (subject, body) => `mailto:?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;
1999
+ var smsHref = (body, ios) => `${ios ? "sms:&body=" : "sms:?body="}${encodeURIComponent(body)}`;
2000
+ var isIOS = (nav) => /iPad|iPhone|iPod/.test(nav.userAgent) || nav.platform === "MacIntel" && (nav.maxTouchPoints ?? 0) > 1;
2001
+ function useMemberReferrals(api) {
2002
+ const [state, setState] = useState15({ data: null, failed: false });
2003
+ useEffect8(() => {
2004
+ let live = true;
2005
+ void api("/api/member/referrals").then((data) => live && setState({ data, failed: false })).catch(() => live && setState({ data: null, failed: true }));
2006
+ return () => {
2007
+ live = false;
2008
+ };
2009
+ }, [api]);
2010
+ return state;
2011
+ }
2012
+ async function copyText(text, copy) {
2013
+ try {
2014
+ await navigator.clipboard.writeText(text);
2015
+ return copy.copied;
2016
+ } catch {
2017
+ return copy.copyBlocked;
2018
+ }
2019
+ }
2020
+
2021
+ // src/ui/member-share-page.tsx
2022
+ import { Fragment as Fragment9, jsx as jsx22, jsxs as jsxs20 } from "preact/jsx-runtime";
2023
+ function CopyButton({ text, label, ctx, variant }) {
2024
+ const [shown, setShown] = useState16(label);
2025
+ return /* @__PURE__ */ jsx22("button", { type: "button", className: "chapter-portal-btn", "data-variant": variant, onClick: () => void copyText(text, ctx.copy.share).then((result) => {
2026
+ setShown(result);
2027
+ setTimeout(() => setShown(label), 2e3);
2028
+ }), children: shown });
2029
+ }
2030
+ function HowDialog({ ctx, vars, onClose, example }) {
2031
+ const copy = ctx.copy.share;
2032
+ useEffect9(() => {
2033
+ const onKey = (event) => {
2034
+ if (event.key === "Escape") onClose();
2035
+ };
2036
+ document.addEventListener("keydown", onKey);
2037
+ return () => document.removeEventListener("keydown", onKey);
2038
+ }, []);
2039
+ return /* @__PURE__ */ jsx22("div", { className: "chapter-portal-modal-back", "data-portal-dialog": true, onClick: (event) => {
2040
+ if (event.target === event.currentTarget) onClose();
2041
+ }, children: /* @__PURE__ */ jsxs20("div", { className: "chapter-portal-modal chapter-portal-card", role: "dialog", "aria-modal": "true", "aria-labelledby": "chapter-portal-how-title", children: [
2042
+ /* @__PURE__ */ jsx22("button", { type: "button", className: "chapter-portal-modal-x", "aria-label": copy.close, onClick: onClose, children: /* @__PURE__ */ jsx22(PortalIcon, { name: "close", size: 20 }) }),
2043
+ /* @__PURE__ */ jsx22("div", { className: "chapter-portal-group-label", style: { padding: 0 }, children: copy.stepsEyebrow }),
2044
+ /* @__PURE__ */ jsx22("h2", { id: "chapter-portal-how-title", children: copy.officialTitle }),
2045
+ /* @__PURE__ */ jsx22("ol", { children: copy.steps.map((step) => /* @__PURE__ */ jsx22("li", { children: fill(step, vars) }, step)) }),
2046
+ /* @__PURE__ */ jsxs20("div", { className: "chapter-portal-btns", children: [
2047
+ /* @__PURE__ */ jsx22("a", { className: "chapter-portal-btn", href: "https://www.linkedin.com/in/me/", target: "_blank", rel: "noopener", children: copy.openLinkedIn }),
2048
+ /* @__PURE__ */ jsx22(CopyButton, { text: fill(copy.linkedinDescription, vars), label: copy.copyDescription, ctx, variant: "ghost" })
2049
+ ] }),
2050
+ example
2051
+ ] }) });
2052
+ }
2053
+ function OfficialCard({ ctx, referrals, example }) {
2054
+ const [open, setOpen] = useState16(false);
2055
+ const copy = ctx.copy.share;
2056
+ return /* @__PURE__ */ jsxs20("div", { className: "chapter-portal-card", "data-official": true, children: [
2057
+ /* @__PURE__ */ jsx22("h2", { children: copy.officialTitle }),
2058
+ /* @__PURE__ */ jsx22("p", { children: copy.officialBody }),
2059
+ /* @__PURE__ */ jsx22("button", { type: "button", className: "chapter-portal-btn", onClick: () => setOpen(true), children: copy.showMeHow }),
2060
+ open ? /* @__PURE__ */ jsx22(HowDialog, { ctx, vars: shareVars(ctx.me, referrals), onClose: () => setOpen(false), example }) : null
2061
+ ] });
2062
+ }
2063
+ function PostCard({ ctx, referrals }) {
2064
+ const copy = ctx.copy.share;
2065
+ const vars = shareVars(ctx.me, referrals);
2066
+ const post = fill(copy.linkedinPost, vars);
2067
+ return /* @__PURE__ */ jsxs20("div", { className: "chapter-portal-card", "data-post": true, children: [
2068
+ /* @__PURE__ */ jsx22("h2", { children: copy.postTitle }),
2069
+ /* @__PURE__ */ jsx22("p", { children: copy.postBody }),
2070
+ /* @__PURE__ */ jsx22("a", { className: "chapter-portal-btn", href: linkedinShareUrl(post, vars.inviteUrl), target: "_blank", rel: "noopener", children: copy.shareOnLinkedIn }),
2071
+ /* @__PURE__ */ jsxs20("details", { children: [
2072
+ /* @__PURE__ */ jsx22("summary", { children: copy.previewPost }),
2073
+ /* @__PURE__ */ jsx22("p", { children: post }),
2074
+ /* @__PURE__ */ jsx22("p", { children: vars.inviteUrl })
2075
+ ] })
2076
+ ] });
2077
+ }
2078
+ function InviteLinkCard({ ctx, referrals }) {
2079
+ const copy = ctx.copy.share;
2080
+ const vars = shareVars(ctx.me, referrals);
2081
+ const [fallback, setFallback] = useState16(null);
2082
+ const ios = typeof navigator !== "undefined" && isIOS(navigator);
2083
+ const email = fill(copy.emailBody, vars), text = fill(copy.textBody, vars);
2084
+ const tryOpen = (kind) => setTimeout(() => {
2085
+ if (!document.hidden) setFallback(kind);
2086
+ }, 900);
2087
+ return /* @__PURE__ */ jsxs20("div", { className: "chapter-portal-card", "data-invite-link": true, children: [
2088
+ /* @__PURE__ */ jsx22("h2", { children: copy.linkTitle }),
2089
+ /* @__PURE__ */ jsxs20("p", { children: [
2090
+ copy.linkBody,
2091
+ referrals?.credit ? /* @__PURE__ */ jsxs20(Fragment9, { children: [
2092
+ " ",
2093
+ /* @__PURE__ */ jsx22("strong", { children: fill(copy.linkCredit, vars) })
2094
+ ] }) : null
2095
+ ] }),
2096
+ /* @__PURE__ */ jsxs20("div", { className: "chapter-portal-link-box", children: [
2097
+ /* @__PURE__ */ jsx22("code", { children: referrals ? referrals.link.replace(/^https?:\/\//, "") : "\u2026" }),
2098
+ referrals ? /* @__PURE__ */ jsx22(CopyButton, { text: referrals.link, label: copy.copyLink, ctx }) : null
2099
+ ] }),
2100
+ /* @__PURE__ */ jsxs20("div", { className: "chapter-portal-btns", children: [
2101
+ /* @__PURE__ */ jsx22("a", { className: "chapter-portal-btn", "data-variant": "ghost", href: mailtoHref(copy.emailSubject, email), onClick: () => tryOpen("email"), children: copy.emailInvite }),
2102
+ /* @__PURE__ */ jsx22("a", { className: "chapter-portal-btn", "data-variant": "ghost", href: smsHref(text, ios), onClick: () => tryOpen("text"), children: copy.textInvite })
2103
+ ] }),
2104
+ fallback ? /* @__PURE__ */ jsxs20("div", { className: "chapter-portal-fallback", "data-fallback": fallback, children: [
2105
+ /* @__PURE__ */ jsx22("p", { children: fallback === "email" ? copy.fallbackEmail : copy.fallbackText }),
2106
+ /* @__PURE__ */ jsx22("pre", { style: { whiteSpace: "pre-wrap" }, children: fallback === "email" ? `${copy.emailSubject}
2107
+
2108
+ ${email}` : text }),
2109
+ /* @__PURE__ */ jsxs20("div", { className: "chapter-portal-btns", children: [
2110
+ /* @__PURE__ */ jsx22(CopyButton, { text: fallback === "email" ? email : text, label: copy.copyMessage, ctx }),
2111
+ /* @__PURE__ */ jsx22("button", { type: "button", className: "chapter-portal-btn", "data-variant": "ghost", onClick: () => setFallback(null), children: copy.close })
2112
+ ] })
2113
+ ] }) : null,
2114
+ /* @__PURE__ */ jsx22("p", { style: { color: "var(--ui-text-muted)" }, children: copy.inviteNote })
2115
+ ] });
2116
+ }
2117
+ function ReferralsCard({ ctx, referrals }) {
2118
+ const copy = ctx.copy.share;
2119
+ if (!referrals) return null;
2120
+ const vars = shareVars(ctx.me, referrals);
2121
+ const tile = (value, label) => /* @__PURE__ */ jsxs20("div", { children: [
2122
+ /* @__PURE__ */ jsx22("b", { children: value }),
2123
+ /* @__PURE__ */ jsx22("span", { children: label })
2124
+ ] });
2125
+ return /* @__PURE__ */ jsxs20("div", { className: "chapter-portal-card", "data-referrals": true, children: [
2126
+ /* @__PURE__ */ jsxs20("div", { className: "chapter-portal-top", children: [
2127
+ /* @__PURE__ */ jsx22("h2", { children: copy.referralsTitle }),
2128
+ /* @__PURE__ */ jsx22("button", { type: "button", className: "chapter-portal-btn", "data-variant": "ghost", onClick: () => {
2129
+ const share = ctx.content.pages.find((page) => page.kind === "feature" && page.feature?.name === "share");
2130
+ if (share) ctx.navigate({ kind: "page", slug: share.slug });
2131
+ }, children: copy.inviteFriend })
2132
+ ] }),
2133
+ /* @__PURE__ */ jsxs20("p", { children: [
2134
+ copy.referralsBody,
2135
+ referrals.credit ? /* @__PURE__ */ jsxs20(Fragment9, { children: [
2136
+ " ",
2137
+ fill(copy.referralsCredit, vars)
2138
+ ] }) : null
2139
+ ] }),
2140
+ /* @__PURE__ */ jsxs20("div", { className: "chapter-portal-tally", "data-tiles": referrals.credit ? 3 : 2, children: [
2141
+ tile(String(referrals.joined.count), copy.joined),
2142
+ tile(String(referrals.inProcess), copy.inProcess),
2143
+ referrals.credit ? tile(fmtMoney(referrals.credit.offNextYearCents).replace(/\.00$/, ""), copy.offNextYear) : null
2144
+ ] }),
2145
+ referrals.joined.names.length ? /* @__PURE__ */ jsx22("p", { children: fill(copy.joinedWith, { names: referrals.joined.names.join(", ") }) }) : null
2146
+ ] });
2147
+ }
2148
+ function SharePage({ page, ctx, example }) {
2149
+ const { data } = useMemberReferrals(ctx.api);
2150
+ return /* @__PURE__ */ jsxs20("div", { className: "chapter-portal-stack", "data-share-page": true, children: [
2151
+ /* @__PURE__ */ jsxs20("div", { children: [
2152
+ /* @__PURE__ */ jsx22("div", { className: "chapter-portal-group-label", style: { padding: 0 }, children: ctx.copy.share.eyebrow }),
2153
+ /* @__PURE__ */ jsx22("h1", { style: { margin: ".3rem 0", fontFamily: "var(--ui-font-display,inherit)", fontWeight: 400 }, children: page.title }),
2154
+ /* @__PURE__ */ jsx22("p", { style: { maxWidth: "40rem", color: "var(--ui-text-muted)" }, children: page.summary ?? ctx.copy.share.intro })
2155
+ ] }),
2156
+ /* @__PURE__ */ jsx22(OfficialCard, { ctx, referrals: data, example }),
2157
+ /* @__PURE__ */ jsxs20("div", { className: "chapter-portal-tiles", children: [
2158
+ /* @__PURE__ */ jsx22(PostCard, { ctx, referrals: data }),
2159
+ /* @__PURE__ */ jsx22(InviteLinkCard, { ctx, referrals: data })
2160
+ ] })
2161
+ ] });
2162
+ }
2163
+ function ShareHome({ ctx }) {
2164
+ const { data } = useMemberReferrals(ctx.api);
2165
+ return /* @__PURE__ */ jsxs20("section", { className: "chapter-portal-stack", "data-share-home": true, children: [
2166
+ /* @__PURE__ */ jsx22("h2", { style: { fontFamily: "var(--ui-font-display,inherit)", fontWeight: 400, margin: 0 }, children: ctx.copy.share.eyebrow }),
2167
+ /* @__PURE__ */ jsx22(OfficialCard, { ctx, referrals: data }),
2168
+ /* @__PURE__ */ jsxs20("div", { className: "chapter-portal-tiles", children: [
2169
+ /* @__PURE__ */ jsx22(PostCard, { ctx, referrals: data }),
2170
+ /* @__PURE__ */ jsx22(InviteLinkCard, { ctx, referrals: data })
2171
+ ] })
2172
+ ] });
2173
+ }
2174
+ function ProfileReferrals({ ctx }) {
2175
+ const { data } = useMemberReferrals(ctx.api);
2176
+ return /* @__PURE__ */ jsx22(ReferralsCard, { ctx, referrals: data });
2177
+ }
2178
+
1845
2179
  // src/ui/member-portal-features.tsx
1846
- var PACKAGED_PORTAL_FEATURES = {};
2180
+ import { jsx as jsx23 } from "preact/jsx-runtime";
2181
+ var PACKAGED_PORTAL_FEATURES = {
2182
+ course: { page: (page, ctx) => /* @__PURE__ */ jsx23(CoursePage, { page, ctx }), home: (page, ctx) => /* @__PURE__ */ jsx23(CourseHomePanel, { page, ctx }) },
2183
+ share: { page: (page, ctx) => /* @__PURE__ */ jsx23(SharePage, { page, ctx }), home: (_page, ctx) => /* @__PURE__ */ jsx23(ShareHome, { ctx }) }
2184
+ };
1847
2185
 
1848
2186
  // src/ui/member-portal.tsx
1849
- import { jsx as jsx21, jsxs as jsxs19 } from "preact/jsx-runtime";
2187
+ import { jsx as jsx24, jsxs as jsxs21 } from "preact/jsx-runtime";
1850
2188
  var EMPTY = { pages: [], sections: [], viewer: { tierId: null, admin: false }, revisions: { parent: null, chapter: null } };
1851
2189
  function MemberPortal(props) {
1852
2190
  const inherited = useChapterCopy();
1853
2191
  const copy = props.copy ?? inherited.portal;
1854
2192
  const routing = { mode: props.routing?.mode ?? "hash", basePath: props.routing?.basePath ?? "/members" };
1855
- const [content, setContent] = useState14(props.initialContent ?? null);
1856
- const [route, setRoute] = useState14(props.initialRoute ?? { kind: "home" });
1857
- const [menuOpen, setMenuOpen] = useState14(false);
1858
- useEffect7(() => {
2193
+ const [content, setContent] = useState17(props.initialContent ?? null);
2194
+ const [route, setRoute] = useState17(props.initialRoute ?? { kind: "home" });
2195
+ const [menuOpen, setMenuOpen] = useState17(false);
2196
+ useEffect10(() => {
1859
2197
  if (props.initialContent) return;
1860
2198
  let live = true;
1861
2199
  void props.api("/api/member-content").then((value) => live && setContent(value)).catch(() => live && setContent(EMPTY));
@@ -1863,7 +2201,7 @@ function MemberPortal(props) {
1863
2201
  live = false;
1864
2202
  };
1865
2203
  }, [props.api, props.initialContent]);
1866
- useEffect7(() => {
2204
+ useEffect10(() => {
1867
2205
  if (typeof window === "undefined" || props.initialRoute) return;
1868
2206
  const sync = () => setRoute(routeFromLocation(window.location, routing));
1869
2207
  sync();
@@ -1883,9 +2221,9 @@ function MemberPortal(props) {
1883
2221
  }
1884
2222
  };
1885
2223
  const features = useMemo3(() => ({ ...PACKAGED_PORTAL_FEATURES, ...props.features }), [props.features]);
1886
- if (!content) return /* @__PURE__ */ jsxs19("div", { className: "chapter-portal", children: [
1887
- /* @__PURE__ */ jsx21("style", { children: MEMBER_PORTAL_CSS }),
1888
- /* @__PURE__ */ jsx21("p", { children: copy.shell.loading })
2224
+ if (!content) return /* @__PURE__ */ jsxs21("div", { className: "chapter-portal", children: [
2225
+ /* @__PURE__ */ jsx24("style", { children: MEMBER_PORTAL_CSS }),
2226
+ /* @__PURE__ */ jsx24("p", { children: copy.shell.loading })
1889
2227
  ] });
1890
2228
  const ctx = {
1891
2229
  api: props.api,
@@ -1901,12 +2239,13 @@ function MemberPortal(props) {
1901
2239
  };
1902
2240
  const page = route.kind === "page" ? content.pages.find((candidate) => candidate.slug === route.slug) : void 0;
1903
2241
  const slots = typeof props.home === "function" ? {} : props.home ?? {};
1904
- const home = /* @__PURE__ */ jsx21(DefaultHome, { ctx, features, slots });
1905
- const body = route.kind === "home" ? typeof props.home === "function" ? props.home(ctx, home) : home : route.kind === "profile" ? /* @__PURE__ */ jsx21(MemberProfilePage, { ctx, middle: props.profile?.middle?.(ctx), extras: props.profile?.extras }) : page ? /* @__PURE__ */ jsx21(PortalPage, { page, ctx, features }) : /* @__PURE__ */ jsx21("div", { className: "chapter-portal-card", children: copy.shell.notFound });
2242
+ const shareAllowed = content.pages.some((candidate) => candidate.kind === "feature" && candidate.feature?.name === "share" && candidate.access === "allowed");
2243
+ const home = /* @__PURE__ */ jsx24(DefaultHome, { ctx, features, slots });
2244
+ const body = route.kind === "home" ? typeof props.home === "function" ? props.home(ctx, home) : home : route.kind === "profile" ? /* @__PURE__ */ jsx24(MemberProfilePage, { ctx, middle: props.profile?.middle ? props.profile.middle(ctx) : shareAllowed ? /* @__PURE__ */ jsx24(ProfileReferrals, { ctx }) : null, extras: props.profile?.extras }) : page ? /* @__PURE__ */ jsx24(PortalPage, { page, ctx, features }) : /* @__PURE__ */ jsx24("div", { className: "chapter-portal-card", children: copy.shell.notFound });
1906
2245
  const admin = props.me.authorized || props.me.superAdmin ? props.adminHref ?? "/admin/" : void 0;
1907
- return /* @__PURE__ */ jsxs19("div", { className: "chapter-portal", "data-member-portal": true, "data-route": route.kind, children: [
1908
- /* @__PURE__ */ jsx21("style", { children: MEMBER_PORTAL_CSS }),
1909
- /* @__PURE__ */ jsx21(
2246
+ return /* @__PURE__ */ jsxs21("div", { className: "chapter-portal", "data-member-portal": true, "data-route": route.kind, children: [
2247
+ /* @__PURE__ */ jsx24("style", { children: MEMBER_PORTAL_CSS }),
2248
+ /* @__PURE__ */ jsx24(
1910
2249
  PortalNav,
1911
2250
  {
1912
2251
  content,
@@ -1923,12 +2262,12 @@ function MemberPortal(props) {
1923
2262
  onToggleMenu: () => setMenuOpen(!menuOpen)
1924
2263
  }
1925
2264
  ),
1926
- /* @__PURE__ */ jsxs19("main", { className: "chapter-portal-main", children: [
1927
- /* @__PURE__ */ jsxs19("div", { className: "chapter-portal-top", children: [
1928
- route.kind === "home" ? /* @__PURE__ */ jsx21("h1", { children: copy.shell.welcomeBack }) : /* @__PURE__ */ jsx21("button", { type: "button", className: "chapter-portal-back", onClick: () => navigate({ kind: "home" }), children: copy.shell.backHome }),
1929
- /* @__PURE__ */ jsxs19("div", { className: "chapter-portal-top-right", children: [
1930
- ctx.me.tier ? /* @__PURE__ */ jsx21("span", { className: "chapter-portal-pill", children: ctx.me.tier.name }) : null,
1931
- /* @__PURE__ */ jsx21(
2265
+ /* @__PURE__ */ jsxs21("main", { className: "chapter-portal-main", children: [
2266
+ /* @__PURE__ */ jsxs21("div", { className: "chapter-portal-top", children: [
2267
+ route.kind === "home" ? /* @__PURE__ */ jsx24("h1", { children: copy.shell.welcomeBack }) : /* @__PURE__ */ jsx24("button", { type: "button", className: "chapter-portal-back", onClick: () => navigate({ kind: "home" }), children: copy.shell.backHome }),
2268
+ /* @__PURE__ */ jsxs21("div", { className: "chapter-portal-top-right", children: [
2269
+ ctx.me.tier ? /* @__PURE__ */ jsx24("span", { className: "chapter-portal-pill", children: ctx.me.tier.name }) : null,
2270
+ /* @__PURE__ */ jsx24(
1932
2271
  "button",
1933
2272
  {
1934
2273
  type: "button",
@@ -1937,7 +2276,7 @@ function MemberPortal(props) {
1937
2276
  title: copy.shell.yourProfile,
1938
2277
  "aria-current": route.kind === "profile" ? "page" : void 0,
1939
2278
  onClick: () => navigate({ kind: "profile" }),
1940
- children: /* @__PURE__ */ jsx21(PortalAvatar, { me: ctx.me })
2279
+ children: /* @__PURE__ */ jsx24(PortalAvatar, { me: ctx.me })
1941
2280
  }
1942
2281
  )
1943
2282
  ] })
@@ -1948,12 +2287,12 @@ function MemberPortal(props) {
1948
2287
  }
1949
2288
 
1950
2289
  // src/ui/members.tsx
1951
- import { Fragment as Fragment8, jsx as jsx22, jsxs as jsxs20 } from "preact/jsx-runtime";
2290
+ import { Fragment as Fragment10, jsx as jsx25, jsxs as jsxs22 } from "preact/jsx-runtime";
1952
2291
  function card(copy, kicker, body) {
1953
- return /* @__PURE__ */ jsxs20("div", { className: "card", children: [
1954
- /* @__PURE__ */ jsx22("div", { className: "card-label", children: copy.provisional.cardLabel }),
1955
- /* @__PURE__ */ jsxs20("div", { className: "meeting-block", children: [
1956
- /* @__PURE__ */ jsx22("div", { className: "meeting-kicker", children: kicker }),
2292
+ return /* @__PURE__ */ jsxs22("div", { className: "card", children: [
2293
+ /* @__PURE__ */ jsx25("div", { className: "card-label", children: copy.provisional.cardLabel }),
2294
+ /* @__PURE__ */ jsxs22("div", { className: "meeting-block", children: [
2295
+ /* @__PURE__ */ jsx25("div", { className: "meeting-kicker", children: kicker }),
1957
2296
  body
1958
2297
  ] })
1959
2298
  ] });
@@ -1964,32 +2303,32 @@ function ProvisionalCard(props) {
1964
2303
  return card(
1965
2304
  copy,
1966
2305
  copy.provisional.applicationNeeded,
1967
- /* @__PURE__ */ jsxs20(Fragment8, { children: [
1968
- /* @__PURE__ */ jsx22("div", { className: "meeting-note", children: copy.provisional.applicationNeededBody }),
1969
- /* @__PURE__ */ jsx22("a", { className: "apply-link", href: applyHref, children: copy.provisional.apply })
2306
+ /* @__PURE__ */ jsxs22(Fragment10, { children: [
2307
+ /* @__PURE__ */ jsx25("div", { className: "meeting-note", children: copy.provisional.applicationNeededBody }),
2308
+ /* @__PURE__ */ jsx25("a", { className: "apply-link", href: applyHref, children: copy.provisional.apply })
1970
2309
  ] })
1971
2310
  );
1972
2311
  }
1973
2312
  if (application.status === "declined") {
1974
- return card(copy, copy.provisional.declined, /* @__PURE__ */ jsx22("div", { className: "meeting-note", children: copy.provisional.declinedBody }));
2313
+ return card(copy, copy.provisional.declined, /* @__PURE__ */ jsx25("div", { className: "meeting-note", children: copy.provisional.declinedBody }));
1975
2314
  }
1976
2315
  if (application.status === "refunded") {
1977
2316
  return card(
1978
2317
  copy,
1979
2318
  copy.provisional.refunded,
1980
- /* @__PURE__ */ jsx22("div", { className: "meeting-note", children: copy.provisional.refundedBody })
2319
+ /* @__PURE__ */ jsx25("div", { className: "meeting-note", children: copy.provisional.refundedBody })
1981
2320
  );
1982
2321
  }
1983
- const membership = application.paid ? /* @__PURE__ */ jsx22("div", { className: "meeting-note", children: application.renewalAt ? formatChapterCopy(copy.provisional.renews, { date: fmtDate(application.renewalAt) }) : copy.provisional.active }) : null;
2322
+ const membership = application.paid ? /* @__PURE__ */ jsx25("div", { className: "meeting-note", children: application.renewalAt ? formatChapterCopy(copy.provisional.renews, { date: fmtDate(application.renewalAt) }) : copy.provisional.active }) : null;
1984
2323
  if (application.meetingAt) {
1985
2324
  return card(
1986
2325
  copy,
1987
2326
  copy.provisional.introductionCall,
1988
- /* @__PURE__ */ jsxs20(Fragment8, { children: [
1989
- /* @__PURE__ */ jsx22("div", { className: "meeting-date", children: fullLabel(application.meetingAt, application.timezone) }),
1990
- /* @__PURE__ */ jsx22("div", { className: "meeting-note", children: copy.provisional.calendarInvite }),
1991
- application.meetUrl ? /* @__PURE__ */ jsx22("div", { className: "meeting-note", children: /* @__PURE__ */ jsx22("a", { href: application.meetUrl, target: "_blank", rel: "noopener", children: copy.provisional.joinCall }) }) : null,
1992
- /* @__PURE__ */ jsx22(
2327
+ /* @__PURE__ */ jsxs22(Fragment10, { children: [
2328
+ /* @__PURE__ */ jsx25("div", { className: "meeting-date", children: fullLabel(application.meetingAt, application.timezone) }),
2329
+ /* @__PURE__ */ jsx25("div", { className: "meeting-note", children: copy.provisional.calendarInvite }),
2330
+ application.meetUrl ? /* @__PURE__ */ jsx25("div", { className: "meeting-note", children: /* @__PURE__ */ jsx25("a", { href: application.meetUrl, target: "_blank", rel: "noopener", children: copy.provisional.joinCall }) }) : null,
2331
+ /* @__PURE__ */ jsx25(
1993
2332
  Rescheduler,
1994
2333
  {
1995
2334
  api,
@@ -2006,9 +2345,9 @@ function ProvisionalCard(props) {
2006
2345
  return card(
2007
2346
  copy,
2008
2347
  copy.provisional.bookCall,
2009
- /* @__PURE__ */ jsxs20(Fragment8, { children: [
2010
- /* @__PURE__ */ jsx22("div", { className: "meeting-note", children: copy.provisional.bookCallBody }),
2011
- /* @__PURE__ */ jsx22(
2348
+ /* @__PURE__ */ jsxs22(Fragment10, { children: [
2349
+ /* @__PURE__ */ jsx25("div", { className: "meeting-note", children: copy.provisional.bookCallBody }),
2350
+ /* @__PURE__ */ jsx25(
2012
2351
  Rescheduler,
2013
2352
  {
2014
2353
  api,
@@ -2035,8 +2374,8 @@ function MembersArea(props) {
2035
2374
  renderProvisional
2036
2375
  } = props;
2037
2376
  const copy = props.copy ?? inheritedCopy.members;
2038
- const [me, setMe] = useState15(null);
2039
- const [error, setError] = useState15(false);
2377
+ const [me, setMe] = useState18(null);
2378
+ const [error, setError] = useState18(false);
2040
2379
  const reload = async () => {
2041
2380
  try {
2042
2381
  setMe(await api("/api/me"));
@@ -2044,14 +2383,14 @@ function MembersArea(props) {
2044
2383
  setError(true);
2045
2384
  }
2046
2385
  };
2047
- useEffect8(() => {
2386
+ useEffect11(() => {
2048
2387
  void reload();
2049
2388
  }, []);
2050
- if (error) return /* @__PURE__ */ jsx22("p", { className: "meeting-note", children: copy.loadFailed });
2051
- if (!me) return /* @__PURE__ */ jsx22("p", { className: "meeting-note", children: inheritedCopy.common.loading });
2389
+ if (error) return /* @__PURE__ */ jsx25("p", { className: "meeting-note", children: copy.loadFailed });
2390
+ if (!me) return /* @__PURE__ */ jsx25("p", { className: "meeting-note", children: inheritedCopy.common.loading });
2052
2391
  if (props.portal && me.memberAccess === true && me.portal) {
2053
- const gifts = /* @__PURE__ */ jsx22(GiftPurchases, { api, copy: copy.gifts, paymentCopy: inheritedCopy.join.payment });
2054
- return /* @__PURE__ */ jsx22(
2392
+ const gifts = /* @__PURE__ */ jsx25(GiftPurchases, { api, copy: copy.gifts, paymentCopy: inheritedCopy.join.payment });
2393
+ return /* @__PURE__ */ jsx25(
2055
2394
  MemberPortal,
2056
2395
  {
2057
2396
  ...props.portal,
@@ -2060,28 +2399,28 @@ function MembersArea(props) {
2060
2399
  signOut,
2061
2400
  reloadMe: reload,
2062
2401
  adminHref: props.portal.adminHref ?? adminHref,
2063
- profile: { ...props.portal.profile, extras: /* @__PURE__ */ jsxs20(Fragment8, { children: [
2402
+ profile: { ...props.portal.profile, extras: /* @__PURE__ */ jsxs22(Fragment10, { children: [
2064
2403
  props.portal.profile?.extras,
2065
2404
  gifts,
2066
- me.namedSeatsEnabled ? /* @__PURE__ */ jsx22(NamedSeatPurchase, { api }) : null
2405
+ me.namedSeatsEnabled ? /* @__PURE__ */ jsx25(NamedSeatPurchase, { api }) : null
2067
2406
  ] }) }
2068
2407
  }
2069
2408
  );
2070
2409
  }
2071
2410
  const role = me.role || "provisional";
2072
- return /* @__PURE__ */ jsxs20(Fragment8, { children: [
2073
- /* @__PURE__ */ jsxs20("div", { className: "card", children: [
2074
- /* @__PURE__ */ jsxs20("div", { className: "member-row", children: [
2075
- /* @__PURE__ */ jsx22("span", { className: "member-email", children: me.email }),
2076
- /* @__PURE__ */ jsx22("span", { className: "role-badge " + role, children: role })
2411
+ return /* @__PURE__ */ jsxs22(Fragment10, { children: [
2412
+ /* @__PURE__ */ jsxs22("div", { className: "card", children: [
2413
+ /* @__PURE__ */ jsxs22("div", { className: "member-row", children: [
2414
+ /* @__PURE__ */ jsx25("span", { className: "member-email", children: me.email }),
2415
+ /* @__PURE__ */ jsx25("span", { className: "role-badge " + role, children: role })
2077
2416
  ] }),
2078
- /* @__PURE__ */ jsxs20("div", { className: "account-actions", children: [
2079
- /* @__PURE__ */ jsx22("button", { className: "btn secondary mini", onClick: signOut, children: copy.account.signOut }),
2080
- me.authorized || me.superAdmin ? /* @__PURE__ */ jsx22("a", { className: "admin-console-link", href: adminHref, children: copy.account.adminConsole }) : null
2417
+ /* @__PURE__ */ jsxs22("div", { className: "account-actions", children: [
2418
+ /* @__PURE__ */ jsx25("button", { className: "btn secondary mini", onClick: signOut, children: copy.account.signOut }),
2419
+ me.authorized || me.superAdmin ? /* @__PURE__ */ jsx25("a", { className: "admin-console-link", href: adminHref, children: copy.account.adminConsole }) : null
2081
2420
  ] })
2082
2421
  ] }),
2083
- me.memberAccess !== true && me.membershipRestart?.eligible && me.application ? /* @__PURE__ */ jsx22(MemberRestart, { api, application: me.application, applicationId: me.membershipRestart.applicationId, onComplete: reload }) : me.memberAccess !== true ? (() => {
2084
- const defaultContent = /* @__PURE__ */ jsx22(
2422
+ me.memberAccess !== true && me.membershipRestart?.eligible && me.application ? /* @__PURE__ */ jsx25(MemberRestart, { api, application: me.application, applicationId: me.membershipRestart.applicationId, onComplete: reload }) : me.memberAccess !== true ? (() => {
2423
+ const defaultContent = /* @__PURE__ */ jsx25(
2085
2424
  ProvisionalCard,
2086
2425
  {
2087
2426
  api,
@@ -2098,27 +2437,34 @@ function MembersArea(props) {
2098
2437
  reload,
2099
2438
  defaultContent
2100
2439
  }) ?? defaultContent;
2101
- })() : memberContent ?? (memberPages ? /* @__PURE__ */ jsx22(
2440
+ })() : memberContent ?? (memberPages ? /* @__PURE__ */ jsx25(
2102
2441
  MemberContentArea,
2103
2442
  {
2104
2443
  api,
2105
2444
  ...memberPages === true ? {} : memberPages
2106
2445
  }
2107
- ) : /* @__PURE__ */ jsx22("div", { className: "card", children: /* @__PURE__ */ jsx22("div", { className: "card-label", children: copy.full.welcome }) })),
2108
- /* @__PURE__ */ jsx22(GiftPurchases, { api, copy: copy.gifts, paymentCopy: inheritedCopy.join.payment }),
2109
- me.namedSeatsEnabled ? /* @__PURE__ */ jsx22(NamedSeatPurchase, { api }) : null
2446
+ ) : /* @__PURE__ */ jsx25("div", { className: "card", children: /* @__PURE__ */ jsx25("div", { className: "card-label", children: copy.full.welcome }) })),
2447
+ /* @__PURE__ */ jsx25(GiftPurchases, { api, copy: copy.gifts, paymentCopy: inheritedCopy.join.payment }),
2448
+ me.namedSeatsEnabled ? /* @__PURE__ */ jsx25(NamedSeatPurchase, { api }) : null
2110
2449
  ] });
2111
2450
  }
2112
2451
 
2452
+ // src/ui/join-referral.ts
2453
+ var CODE = /^[23456789abcdefghjkmnpqrstuvwxyz]{5,8}$/;
2454
+ function referralFromLocation(search = typeof location === "undefined" ? "" : location.search) {
2455
+ const code = new URLSearchParams(search).get("ref")?.trim().toLowerCase() ?? "";
2456
+ return CODE.test(code) ? { referralCode: code } : {};
2457
+ }
2458
+
2113
2459
  // src/ui/join.tsx
2114
- import { useEffect as useEffect13, useRef as useRef8, useState as useState23 } from "preact/hooks";
2460
+ import { useEffect as useEffect16, useRef as useRef8, useState as useState26 } from "preact/hooks";
2115
2461
 
2116
2462
  // src/ui/join-booking.tsx
2117
- import { useEffect as useEffect9, useRef as useRef6, useState as useState16 } from "preact/hooks";
2118
- import { jsx as jsx23, jsxs as jsxs21 } from "preact/jsx-runtime";
2463
+ import { useEffect as useEffect12, useRef as useRef6, useState as useState19 } from "preact/hooks";
2464
+ import { jsx as jsx26, jsxs as jsxs23 } from "preact/jsx-runtime";
2119
2465
  function useJoinSlotsPreload(active) {
2120
2466
  const preload = useRef6(null);
2121
- useEffect9(() => {
2467
+ useEffect12(() => {
2122
2468
  if (!active || preload.current) return;
2123
2469
  preload.current = Promise.resolve().then(() => fetch("/api/schedule/slots"));
2124
2470
  preload.current.catch(() => {
@@ -2129,11 +2475,11 @@ function useJoinSlotsPreload(active) {
2129
2475
  }
2130
2476
  function JoinBooking(props) {
2131
2477
  const { applicationId, copy, onBooked, simulation } = props;
2132
- const [state, setState] = useState16(null);
2133
- const [msg, setMsg] = useState16(null);
2134
- const [busy, setBusy] = useState16(false);
2135
- const [day2, setDay] = useState16(null);
2136
- const [selected, setSelected] = useState16(null);
2478
+ const [state, setState] = useState19(null);
2479
+ const [msg, setMsg] = useState19(null);
2480
+ const [busy, setBusy] = useState19(false);
2481
+ const [day2, setDay] = useState19(null);
2482
+ const [selected, setSelected] = useState19(null);
2137
2483
  const load = async (preloaded) => {
2138
2484
  setMsg(null);
2139
2485
  try {
@@ -2158,7 +2504,7 @@ function JoinBooking(props) {
2158
2504
  setMsg(copy.loadFailed);
2159
2505
  }
2160
2506
  };
2161
- useEffect9(() => {
2507
+ useEffect12(() => {
2162
2508
  void load(props.preload);
2163
2509
  }, [simulation]);
2164
2510
  const book = async () => {
@@ -2190,17 +2536,17 @@ function JoinBooking(props) {
2190
2536
  setBusy(false);
2191
2537
  }
2192
2538
  };
2193
- if (!state) return /* @__PURE__ */ jsx23("p", { className: "slots-status", children: msg ?? copy.loading });
2539
+ if (!state) return /* @__PURE__ */ jsx26("p", { className: "slots-status", children: msg ?? copy.loading });
2194
2540
  const hint = !day2 ? copy.pickDate ?? DEFAULT_JOIN_COPY.booking.pickDate : !selected ? copy.pickTime ?? DEFAULT_JOIN_COPY.booking.pickTime : null;
2195
- return /* @__PURE__ */ jsxs21("div", { className: "join-book", children: [
2196
- /* @__PURE__ */ jsx23("h2", { children: copy.title ?? DEFAULT_JOIN_COPY.booking.title }),
2197
- /* @__PURE__ */ jsx23("p", { children: copy.intro ?? DEFAULT_JOIN_COPY.booking.intro }),
2198
- /* @__PURE__ */ jsxs21("div", { className: "slot-confirm", children: [
2199
- /* @__PURE__ */ jsx23("button", { className: "submit-btn", type: "button", disabled: busy || !selected, onClick: () => void book(), children: busy ? copy.booking : copy.book }),
2200
- hint ? /* @__PURE__ */ jsx23("p", { className: "slot-hint", role: "status", children: hint }) : null,
2201
- msg ? /* @__PURE__ */ jsx23("p", { className: "step2-note", role: "alert", children: msg }) : null
2541
+ return /* @__PURE__ */ jsxs23("div", { className: "join-book", children: [
2542
+ /* @__PURE__ */ jsx26("h2", { children: copy.title ?? DEFAULT_JOIN_COPY.booking.title }),
2543
+ /* @__PURE__ */ jsx26("p", { children: copy.intro ?? DEFAULT_JOIN_COPY.booking.intro }),
2544
+ /* @__PURE__ */ jsxs23("div", { className: "slot-confirm", children: [
2545
+ /* @__PURE__ */ jsx26("button", { className: "submit-btn", type: "button", disabled: busy || !selected, onClick: () => void book(), children: busy ? copy.booking : copy.book }),
2546
+ hint ? /* @__PURE__ */ jsx26("p", { className: "slot-hint", role: "status", children: hint }) : null,
2547
+ msg ? /* @__PURE__ */ jsx26("p", { className: "step2-note", role: "alert", children: msg }) : null
2202
2548
  ] }),
2203
- /* @__PURE__ */ jsx23(
2549
+ /* @__PURE__ */ jsx26(
2204
2550
  SlotPicker,
2205
2551
  {
2206
2552
  slots: state.slots,
@@ -2218,21 +2564,21 @@ function JoinBooking(props) {
2218
2564
  }
2219
2565
 
2220
2566
  // src/ui/join-accepted.tsx
2221
- import { jsx as jsx24, jsxs as jsxs22 } from "preact/jsx-runtime";
2567
+ import { jsx as jsx27, jsxs as jsxs24 } from "preact/jsx-runtime";
2222
2568
  function JoinAccepted(props) {
2223
- return /* @__PURE__ */ jsxs22("div", { className: "join-done card", children: [
2224
- /* @__PURE__ */ jsx24("div", { className: "card-label", children: props.copy.accepted.label }),
2225
- /* @__PURE__ */ jsx24("p", { className: "meeting-note", children: props.copy.accepted.body }),
2226
- /* @__PURE__ */ jsx24("a", { className: "apply-link", href: props.membersHref, children: props.copy.done.memberArea })
2569
+ return /* @__PURE__ */ jsxs24("div", { className: "join-done card", children: [
2570
+ /* @__PURE__ */ jsx27("div", { className: "card-label", children: props.copy.accepted.label }),
2571
+ /* @__PURE__ */ jsx27("p", { className: "meeting-note", children: props.copy.accepted.body }),
2572
+ /* @__PURE__ */ jsx27("a", { className: "apply-link", href: props.membersHref, children: props.copy.done.memberArea })
2227
2573
  ] });
2228
2574
  }
2229
2575
 
2230
2576
  // src/ui/gift-claim-card.tsx
2231
- import { useState as useState17 } from "preact/hooks";
2232
- import { Fragment as Fragment9, jsx as jsx25, jsxs as jsxs23 } from "preact/jsx-runtime";
2577
+ import { useState as useState20 } from "preact/hooks";
2578
+ import { Fragment as Fragment11, jsx as jsx28, jsxs as jsxs25 } from "preact/jsx-runtime";
2233
2579
  function GiftClaimCard(props) {
2234
- const [code, setCode] = useState17(props.initialCode ?? "");
2235
- const [error, setError] = useState17(false);
2580
+ const [code, setCode] = useState20(props.initialCode ?? "");
2581
+ const [error, setError] = useState20(false);
2236
2582
  const rotate = async () => {
2237
2583
  if (!props.claimId) return;
2238
2584
  setError(false);
@@ -2245,15 +2591,15 @@ function GiftClaimCard(props) {
2245
2591
  if (response.ok && body.code) setCode(body.code);
2246
2592
  else setError(true);
2247
2593
  };
2248
- return /* @__PURE__ */ jsxs23("div", { className: "join-done card", children: [
2249
- /* @__PURE__ */ jsx25("div", { className: "card-label", children: props.copy.label }),
2250
- /* @__PURE__ */ jsx25("p", { className: "meeting-note", children: props.copy.body }),
2251
- code ? /* @__PURE__ */ jsxs23(Fragment9, { children: [
2252
- /* @__PURE__ */ jsx25("output", { className: "gift-code", children: code }),
2253
- /* @__PURE__ */ jsx25("p", { children: props.copy.save })
2594
+ return /* @__PURE__ */ jsxs25("div", { className: "join-done card", children: [
2595
+ /* @__PURE__ */ jsx28("div", { className: "card-label", children: props.copy.label }),
2596
+ /* @__PURE__ */ jsx28("p", { className: "meeting-note", children: props.copy.body }),
2597
+ code ? /* @__PURE__ */ jsxs25(Fragment11, { children: [
2598
+ /* @__PURE__ */ jsx28("output", { className: "gift-code", children: code }),
2599
+ /* @__PURE__ */ jsx28("p", { children: props.copy.save })
2254
2600
  ] }) : null,
2255
- !code && props.claimId ? /* @__PURE__ */ jsx25("button", { type: "button", className: "btn secondary", onClick: () => void rotate(), children: props.copy.rotate }) : null,
2256
- error ? /* @__PURE__ */ jsx25("p", { role: "alert", children: props.copy.rotateFailed }) : null
2601
+ !code && props.claimId ? /* @__PURE__ */ jsx28("button", { type: "button", className: "btn secondary", onClick: () => void rotate(), children: props.copy.rotate }) : null,
2602
+ error ? /* @__PURE__ */ jsx28("p", { role: "alert", children: props.copy.rotateFailed }) : null
2257
2603
  ] });
2258
2604
  }
2259
2605
 
@@ -2261,11 +2607,11 @@ function GiftClaimCard(props) {
2261
2607
  import { useRef as useRef7 } from "preact/hooks";
2262
2608
 
2263
2609
  // src/ui/join-tiers.tsx
2264
- import { useState as useState18 } from "preact/hooks";
2265
- import { Fragment as Fragment10, jsx as jsx26, jsxs as jsxs24 } from "preact/jsx-runtime";
2610
+ import { useState as useState21 } from "preact/hooks";
2611
+ import { Fragment as Fragment12, jsx as jsx29, jsxs as jsxs26 } from "preact/jsx-runtime";
2266
2612
  var joinTierMoney = (cents, currency = "usd") => new Intl.NumberFormat("en-US", { style: "currency", currency }).format(cents / 100);
2267
2613
  function useTierSelection(tiers, initialTierId) {
2268
- const [selectedTierId, setSelectedTierId] = useState18(() => {
2614
+ const [selectedTierId, setSelectedTierId] = useState21(() => {
2269
2615
  const preset = tiers.find((tier) => tier.id === initialTierId);
2270
2616
  if (preset) return preset.id;
2271
2617
  return tiers.length === 1 ? tiers[0].id : null;
@@ -2280,10 +2626,10 @@ function useTierSelection(tiers, initialTierId) {
2280
2626
  };
2281
2627
  }
2282
2628
  function TierPlaceholder(context) {
2283
- return /* @__PURE__ */ jsxs24("fieldset", { "data-chapter-placeholder": "tiers", children: [
2284
- /* @__PURE__ */ jsx26("legend", { children: "Membership (placeholder \u2014 pass renderTiers to style this)" }),
2285
- context.tiers.map((tier) => /* @__PURE__ */ jsxs24("label", { children: [
2286
- /* @__PURE__ */ jsx26(
2629
+ return /* @__PURE__ */ jsxs26("fieldset", { "data-chapter-placeholder": "tiers", children: [
2630
+ /* @__PURE__ */ jsx29("legend", { children: "Membership (placeholder \u2014 pass renderTiers to style this)" }),
2631
+ context.tiers.map((tier) => /* @__PURE__ */ jsxs26("label", { children: [
2632
+ /* @__PURE__ */ jsx29(
2287
2633
  "input",
2288
2634
  {
2289
2635
  type: "radio",
@@ -2294,13 +2640,13 @@ function TierPlaceholder(context) {
2294
2640
  }
2295
2641
  ),
2296
2642
  tier.name,
2297
- tier.founding ? /* @__PURE__ */ jsxs24(Fragment10, { children: [
2643
+ tier.founding ? /* @__PURE__ */ jsxs26(Fragment12, { children: [
2298
2644
  " \u2014 ",
2299
2645
  joinTierMoney(tier.founding.dueTodayCents),
2300
2646
  " founding member rate (list ",
2301
2647
  joinTierMoney(tier.priceCents),
2302
2648
  ")"
2303
- ] }) : tier.free ? " \u2014 free" : /* @__PURE__ */ jsxs24(Fragment10, { children: [
2649
+ ] }) : tier.free ? " \u2014 free" : /* @__PURE__ */ jsxs26(Fragment12, { children: [
2304
2650
  " \u2014 ",
2305
2651
  joinTierMoney(tier.priceCents)
2306
2652
  ] })
@@ -2312,12 +2658,12 @@ function tierNeedsPayment(selected, paymentsReady) {
2312
2658
  }
2313
2659
 
2314
2660
  // src/ui/join-application-form.tsx
2315
- import { jsx as jsx27, jsxs as jsxs25 } from "preact/jsx-runtime";
2661
+ import { jsx as jsx30, jsxs as jsxs27 } from "preact/jsx-runtime";
2316
2662
  function JoinApplicationForm({ props, copy, invitation, requestedSeat, tierSelection, giftOfferId, selectGift, submitting, error, submit }) {
2317
2663
  const form = useRef7(null);
2318
2664
  const ready = useFormReadiness(form);
2319
2665
  const disabled = submitting || props.submitDisabled === true || !ready || !validJoinRecipient(props.payment?.initialNamedSeat);
2320
- return /* @__PURE__ */ jsxs25("form", { ref: form, className: "join-form", onSubmit: (event) => {
2666
+ return /* @__PURE__ */ jsxs27("form", { ref: form, className: "join-form", onSubmit: (event) => {
2321
2667
  if (!isFormReady(event.currentTarget)) {
2322
2668
  event.preventDefault();
2323
2669
  event.currentTarget.reportValidity();
@@ -2325,15 +2671,15 @@ function JoinApplicationForm({ props, copy, invitation, requestedSeat, tierSelec
2325
2671
  }
2326
2672
  void submit(event);
2327
2673
  }, children: [
2328
- !requestedSeat && (props.config.giftOffers?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs25("fieldset", { children: [
2329
- /* @__PURE__ */ jsx27("legend", { children: copy.gift.optionsLabel }),
2330
- /* @__PURE__ */ jsx27("button", { type: "button", className: "btn secondary", "aria-pressed": !giftOfferId, onClick: () => selectGift(null), children: copy.gift.chooseSelf }),
2331
- /* @__PURE__ */ jsx27(GiftOfferCards, { offers: props.config.giftOffers ?? [], mode: "select", selectedOfferId: giftOfferId, onSelect: selectGift })
2674
+ !requestedSeat && (props.config.giftOffers?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs27("fieldset", { children: [
2675
+ /* @__PURE__ */ jsx30("legend", { children: copy.gift.optionsLabel }),
2676
+ /* @__PURE__ */ jsx30("button", { type: "button", className: "btn secondary", "aria-pressed": !giftOfferId, onClick: () => selectGift(null), children: copy.gift.chooseSelf }),
2677
+ /* @__PURE__ */ jsx30(GiftOfferCards, { offers: props.config.giftOffers ?? [], mode: "select", selectedOfferId: giftOfferId, onSelect: selectGift })
2332
2678
  ] }) : null,
2333
2679
  !requestedSeat && (props.config.tiers?.length ?? 0) > 1 ? props.renderTiers?.(tierSelection) ?? TierPlaceholder(tierSelection) : null,
2334
2680
  typeof props.children === "function" ? props.children({ invitation }) : props.children,
2335
- error ? /* @__PURE__ */ jsx27("p", { className: "join-error", role: "alert", children: error }) : null,
2336
- props.renderSubmit?.({ submitting, disabled }) ?? /* @__PURE__ */ jsx27(JoinSubmitButton, { disabled, children: submitting ? copy.form.submitting : copy.form.submit })
2681
+ error ? /* @__PURE__ */ jsx30("p", { className: "join-error", role: "alert", children: error }) : null,
2682
+ props.renderSubmit?.({ submitting, disabled }) ?? /* @__PURE__ */ jsx30(JoinSubmitButton, { disabled, children: submitting ? copy.form.submitting : copy.form.submit })
2337
2683
  ] });
2338
2684
  }
2339
2685
 
@@ -2358,8 +2704,8 @@ function joinStateFromApplicationResponse(data, fallbackNeedsPayment, submittedG
2358
2704
 
2359
2705
  // src/ui/gift-code-redeemer.tsx
2360
2706
  import { InlineActionField } from "@odla-ai/ui/components";
2361
- import { useState as useState19 } from "preact/hooks";
2362
- import { Fragment as Fragment11, jsx as jsx28, jsxs as jsxs26 } from "preact/jsx-runtime";
2707
+ import { useState as useState22 } from "preact/hooks";
2708
+ import { Fragment as Fragment13, jsx as jsx31, jsxs as jsxs28 } from "preact/jsx-runtime";
2363
2709
  var GIFT_CODE_REDEEMER_CSS = `
2364
2710
  .gift-code-redeemer{container-type:inline-size;display:grid;gap:var(--ui-space-1,.35rem);margin:0}
2365
2711
  .gift-code-redeemer .inline-action-field-label{display:block;color:var(--ui-text-muted,#66777f);font-size:var(--ui-text-xs,.72rem);font-weight:var(--ui-weight-strong,700);letter-spacing:var(--ui-tracking-caps,.08em);text-transform:uppercase}
@@ -2374,10 +2720,10 @@ var GIFT_CODE_REDEEMER_CSS = `
2374
2720
  @container (max-width:26rem){.gift-code-redeemer .inline-action-field-row{grid-template-columns:minmax(0,1fr)}.gift-code-redeemer .inline-action-field-action{width:100%}}
2375
2721
  `;
2376
2722
  function GiftCodeRedeemer({ api, applicationId, copy, id, onRedeemed }) {
2377
- const [code, setCode] = useState19("");
2378
- const [loading, setLoading] = useState19(false);
2379
- const [message, setMessage] = useState19("");
2380
- const [messageTone, setMessageTone] = useState19("neutral");
2723
+ const [code, setCode] = useState22("");
2724
+ const [loading, setLoading] = useState22(false);
2725
+ const [message, setMessage] = useState22("");
2726
+ const [messageTone, setMessageTone] = useState22("neutral");
2381
2727
  const normalizedCode = code.trim();
2382
2728
  const redeem = async () => {
2383
2729
  if (!normalizedCode || loading) return;
@@ -2404,9 +2750,9 @@ function GiftCodeRedeemer({ api, applicationId, copy, id, onRedeemed }) {
2404
2750
  setLoading(false);
2405
2751
  }
2406
2752
  };
2407
- return /* @__PURE__ */ jsxs26(Fragment11, { children: [
2408
- /* @__PURE__ */ jsx28("style", { children: GIFT_CODE_REDEEMER_CSS }),
2409
- /* @__PURE__ */ jsx28(
2753
+ return /* @__PURE__ */ jsxs28(Fragment13, { children: [
2754
+ /* @__PURE__ */ jsx31("style", { children: GIFT_CODE_REDEEMER_CSS }),
2755
+ /* @__PURE__ */ jsx31(
2410
2756
  InlineActionField,
2411
2757
  {
2412
2758
  id,
@@ -2462,12 +2808,12 @@ async function loadJoinResume(applicationId, fetcher = fetch) {
2462
2808
  }
2463
2809
 
2464
2810
  // src/ui/join-gift-claim.tsx
2465
- import { jsx as jsx29, jsxs as jsxs27 } from "preact/jsx-runtime";
2811
+ import { jsx as jsx32, jsxs as jsxs29 } from "preact/jsx-runtime";
2466
2812
  function JoinGiftClaim(props) {
2467
- return /* @__PURE__ */ jsxs27("section", { className: "join-gift-claim card", children: [
2468
- /* @__PURE__ */ jsx29("div", { className: "card-label", children: props.copy.claimTitle }),
2469
- /* @__PURE__ */ jsx29("p", { children: props.copy.claimBody }),
2470
- /* @__PURE__ */ jsx29(
2813
+ return /* @__PURE__ */ jsxs29("section", { className: "join-gift-claim card", children: [
2814
+ /* @__PURE__ */ jsx32("div", { className: "card-label", children: props.copy.claimTitle }),
2815
+ /* @__PURE__ */ jsx32("p", { children: props.copy.claimBody }),
2816
+ /* @__PURE__ */ jsx32(
2471
2817
  GiftCodeRedeemer,
2472
2818
  {
2473
2819
  api: props.api,
@@ -2491,21 +2837,21 @@ function JoinGiftClaim(props) {
2491
2837
  }
2492
2838
 
2493
2839
  // src/ui/join-named-seat.tsx
2494
- import { useState as useState20 } from "preact/hooks";
2495
- import { jsx as jsx30, jsxs as jsxs28 } from "preact/jsx-runtime";
2840
+ import { useState as useState23 } from "preact/hooks";
2841
+ import { jsx as jsx33, jsxs as jsxs30 } from "preact/jsx-runtime";
2496
2842
  function JoinNamedSeat(props) {
2497
2843
  const seatId = props.seatId ?? "";
2498
2844
  const inherited = useChapterCopy(), copy = props.copy ?? inherited.join.namedSeat;
2499
- const [accepted, setAccepted] = useState20(false), [busy, setBusy] = useState20(false), [error, setError] = useState20("");
2500
- return /* @__PURE__ */ jsxs28("section", { className: "join-named-seat card", children: [
2501
- /* @__PURE__ */ jsx30("h2", { children: copy.title }),
2502
- /* @__PURE__ */ jsx30("p", { children: copy.body }),
2503
- /* @__PURE__ */ jsxs28("label", { className: "journey-consent", children: [
2504
- /* @__PURE__ */ jsx30("input", { type: "checkbox", checked: accepted, disabled: busy, onChange: (event) => setAccepted(event.currentTarget.checked) }),
2505
- /* @__PURE__ */ jsx30("span", { children: copy.consent })
2845
+ const [accepted, setAccepted] = useState23(false), [busy, setBusy] = useState23(false), [error, setError] = useState23("");
2846
+ return /* @__PURE__ */ jsxs30("section", { className: "join-named-seat card", children: [
2847
+ /* @__PURE__ */ jsx33("h2", { children: copy.title }),
2848
+ /* @__PURE__ */ jsx33("p", { children: copy.body }),
2849
+ /* @__PURE__ */ jsxs30("label", { className: "journey-consent", children: [
2850
+ /* @__PURE__ */ jsx33("input", { type: "checkbox", checked: accepted, disabled: busy, onChange: (event) => setAccepted(event.currentTarget.checked) }),
2851
+ /* @__PURE__ */ jsx33("span", { children: copy.consent })
2506
2852
  ] }),
2507
- error ? /* @__PURE__ */ jsx30("p", { role: "alert", children: error }) : null,
2508
- /* @__PURE__ */ jsx30("button", { type: "button", className: "btn btn-primary", disabled: busy || !accepted || !seatId.trim(), onClick: async () => {
2853
+ error ? /* @__PURE__ */ jsx33("p", { role: "alert", children: error }) : null,
2854
+ /* @__PURE__ */ jsx33("button", { type: "button", className: "btn btn-primary", disabled: busy || !accepted || !seatId.trim(), onClick: async () => {
2509
2855
  setBusy(true);
2510
2856
  setError("");
2511
2857
  try {
@@ -2525,13 +2871,13 @@ function JoinNamedSeat(props) {
2525
2871
  }
2526
2872
 
2527
2873
  // src/ui/join-invitation.tsx
2528
- import { useEffect as useEffect10, useState as useState21 } from "preact/hooks";
2529
- import { jsx as jsx31, jsxs as jsxs29 } from "preact/jsx-runtime";
2874
+ import { useEffect as useEffect13, useState as useState24 } from "preact/hooks";
2875
+ import { jsx as jsx34, jsxs as jsxs31 } from "preact/jsx-runtime";
2530
2876
  function useJoinInvitation(seatId, api, fallback) {
2531
- const [invitation, setInvitation] = useState21(null);
2532
- const [error, setError] = useState21("");
2533
- const [revision, setRevision] = useState21(0);
2534
- useEffect10(() => {
2877
+ const [invitation, setInvitation] = useState24(null);
2878
+ const [error, setError] = useState24("");
2879
+ const [revision, setRevision] = useState24(0);
2880
+ useEffect13(() => {
2535
2881
  let live = true;
2536
2882
  setInvitation(null);
2537
2883
  setError("");
@@ -2553,9 +2899,9 @@ function useJoinInvitation(seatId, api, fallback) {
2553
2899
  return { invitation: invitation?.seatId === seatId ? invitation : null, error, retry: () => setRevision((value) => value + 1) };
2554
2900
  }
2555
2901
  function JoinInvitationNotice(props) {
2556
- return /* @__PURE__ */ jsxs29("aside", { className: "journey-invitation", "aria-label": props.copy.title, children: [
2557
- /* @__PURE__ */ jsx31("p", { children: /* @__PURE__ */ jsx31("strong", { children: formatChapterCopy(props.copy.from, { purchaserName: props.invitation.purchaserName }) }) }),
2558
- /* @__PURE__ */ jsx31("p", { children: formatChapterCopy(props.copy.prepaid, { tierName: props.tierName }) })
2902
+ return /* @__PURE__ */ jsxs31("aside", { className: "journey-invitation", "aria-label": props.copy.title, children: [
2903
+ /* @__PURE__ */ jsx34("p", { children: /* @__PURE__ */ jsx34("strong", { children: formatChapterCopy(props.copy.from, { purchaserName: props.invitation.purchaserName }) }) }),
2904
+ /* @__PURE__ */ jsx34("p", { children: formatChapterCopy(props.copy.prepaid, { tierName: props.tierName }) })
2559
2905
  ] });
2560
2906
  }
2561
2907
 
@@ -2570,9 +2916,9 @@ function joinSimulationPayment(simulation, priceCents) {
2570
2916
  }
2571
2917
 
2572
2918
  // src/ui/join-pending.ts
2573
- import { useEffect as useEffect11 } from "preact/hooks";
2919
+ import { useEffect as useEffect14 } from "preact/hooks";
2574
2920
  function useJoinPending(state, loadResume, setState) {
2575
- useEffect11(() => {
2921
+ useEffect14(() => {
2576
2922
  if (state.step !== "paymentPending") return;
2577
2923
  let live = true;
2578
2924
  let timer;
@@ -2595,16 +2941,16 @@ function useJoinPending(state, loadResume, setState) {
2595
2941
  }
2596
2942
 
2597
2943
  // src/ui/payment-receipt.tsx
2598
- import { useEffect as useEffect12, useState as useState22 } from "preact/hooks";
2599
- import { Fragment as Fragment12, jsx as jsx32, jsxs as jsxs30 } from "preact/jsx-runtime";
2944
+ import { useEffect as useEffect15, useState as useState25 } from "preact/hooks";
2945
+ import { Fragment as Fragment14, jsx as jsx35, jsxs as jsxs32 } from "preact/jsx-runtime";
2600
2946
  function PaymentReceiptCard({ applicationId }) {
2601
- const [receipt, setReceipt] = useState22(null);
2602
- const [error, setError] = useState22("");
2603
- const [revision, setRevision] = useState22(0);
2604
- const [emailState, setEmailState] = useState22("idle");
2605
- const [previewEmail, setPreviewEmail] = useState22(false);
2947
+ const [receipt, setReceipt] = useState25(null);
2948
+ const [error, setError] = useState25("");
2949
+ const [revision, setRevision] = useState25(0);
2950
+ const [emailState, setEmailState] = useState25("idle");
2951
+ const [previewEmail, setPreviewEmail] = useState25(false);
2606
2952
  const endpoint = `/api/payments/receipt?application=${encodeURIComponent(applicationId)}`;
2607
- useEffect12(() => {
2953
+ useEffect15(() => {
2608
2954
  let live = true, timer;
2609
2955
  setReceipt(null);
2610
2956
  setError("");
@@ -2630,9 +2976,9 @@ function PaymentReceiptCard({ applicationId }) {
2630
2976
  if (timer) clearTimeout(timer);
2631
2977
  };
2632
2978
  }, [endpoint, revision]);
2633
- if (!receipt) return error ? /* @__PURE__ */ jsxs30("section", { "aria-label": "Payment receipt", children: [
2634
- /* @__PURE__ */ jsx32("p", { role: "status", children: error }),
2635
- /* @__PURE__ */ jsx32("button", { type: "button", onClick: () => setRevision((value) => value + 1), children: "Reload receipt" })
2979
+ if (!receipt) return error ? /* @__PURE__ */ jsxs32("section", { "aria-label": "Payment receipt", children: [
2980
+ /* @__PURE__ */ jsx35("p", { role: "status", children: error }),
2981
+ /* @__PURE__ */ jsx35("button", { type: "button", onClick: () => setRevision((value) => value + 1), children: "Reload receipt" })
2636
2982
  ] }) : null;
2637
2983
  const money = (cents) => new Intl.NumberFormat("en-US", { style: "currency", currency: receipt.currency }).format(cents / 100);
2638
2984
  const email = async () => {
@@ -2649,38 +2995,38 @@ function PaymentReceiptCard({ applicationId }) {
2649
2995
  setError("We could not confirm email delivery. You can print or save your receipt.");
2650
2996
  }
2651
2997
  };
2652
- return /* @__PURE__ */ jsxs30("section", { className: "payment-receipt card", "aria-label": "Payment receipt", children: [
2653
- /* @__PURE__ */ jsx32("h2", { children: "Payment received" }),
2654
- /* @__PURE__ */ jsx32("p", { children: receipt.tierName }),
2655
- /* @__PURE__ */ jsxs30("dl", { className: "journey-summary", children: [
2656
- /* @__PURE__ */ jsx32("dt", { children: "Membership" }),
2657
- /* @__PURE__ */ jsx32("dd", { children: money(receipt.membershipCents) }),
2658
- receipt.namedSeat ? /* @__PURE__ */ jsxs30(Fragment12, { children: [
2659
- /* @__PURE__ */ jsxs30("dt", { children: [
2998
+ return /* @__PURE__ */ jsxs32("section", { className: "payment-receipt card", "aria-label": "Payment receipt", children: [
2999
+ /* @__PURE__ */ jsx35("h2", { children: "Payment received" }),
3000
+ /* @__PURE__ */ jsx35("p", { children: receipt.tierName }),
3001
+ /* @__PURE__ */ jsxs32("dl", { className: "journey-summary", children: [
3002
+ /* @__PURE__ */ jsx35("dt", { children: "Membership" }),
3003
+ /* @__PURE__ */ jsx35("dd", { children: money(receipt.membershipCents) }),
3004
+ receipt.namedSeat ? /* @__PURE__ */ jsxs32(Fragment14, { children: [
3005
+ /* @__PURE__ */ jsxs32("dt", { children: [
2660
3006
  "Additional member \u2014 ",
2661
3007
  receipt.namedSeat.recipientName
2662
3008
  ] }),
2663
- /* @__PURE__ */ jsxs30("dd", { children: [
3009
+ /* @__PURE__ */ jsxs32("dd", { children: [
2664
3010
  receipt.namedSeat.amountCents === 0 ? "Included \u2014 " : "",
2665
3011
  money(receipt.namedSeat.amountCents)
2666
3012
  ] })
2667
3013
  ] }) : null,
2668
- /* @__PURE__ */ jsx32("dt", { children: "Total paid" }),
2669
- /* @__PURE__ */ jsx32("dd", { children: money(receipt.totalCents) })
3014
+ /* @__PURE__ */ jsx35("dt", { children: "Total paid" }),
3015
+ /* @__PURE__ */ jsx35("dd", { children: money(receipt.totalCents) })
2670
3016
  ] }),
2671
- /* @__PURE__ */ jsxs30("div", { className: "journey-actions", children: [
2672
- /* @__PURE__ */ jsx32("a", { className: "apply-link journey-secondary", href: `${endpoint}&format=html`, target: "_blank", rel: "noopener noreferrer", children: "Print / save receipt" }),
2673
- /* @__PURE__ */ jsx32("button", { type: "button", disabled: emailState !== "idle", onClick: () => void email(), children: emailState === "sending" ? "Sending\u2026" : emailState === "sent" ? "Receipt emailed" : "Email me my receipt" })
3017
+ /* @__PURE__ */ jsxs32("div", { className: "journey-actions", children: [
3018
+ /* @__PURE__ */ jsx35("a", { className: "apply-link journey-secondary", href: `${endpoint}&format=html`, target: "_blank", rel: "noopener noreferrer", children: "Print / save receipt" }),
3019
+ /* @__PURE__ */ jsx35("button", { type: "button", disabled: emailState !== "idle", onClick: () => void email(), children: emailState === "sending" ? "Sending\u2026" : emailState === "sent" ? "Receipt emailed" : "Email me my receipt" })
2674
3020
  ] }),
2675
- emailState === "sent" ? /* @__PURE__ */ jsx32("p", { role: "status", children: previewEmail ? "Test receipt sent to the configured test inbox." : "Sent to the email used for your payment." }) : null,
2676
- error ? /* @__PURE__ */ jsx32("p", { role: "alert", children: error }) : null
3021
+ emailState === "sent" ? /* @__PURE__ */ jsx35("p", { role: "status", children: previewEmail ? "Test receipt sent to the configured test inbox." : "Sent to the email used for your payment." }) : null,
3022
+ error ? /* @__PURE__ */ jsx35("p", { role: "alert", children: error }) : null
2677
3023
  ] });
2678
3024
  }
2679
3025
 
2680
3026
  // src/ui/join.tsx
2681
- import { Fragment as Fragment13, jsx as jsx33, jsxs as jsxs31 } from "preact/jsx-runtime";
3027
+ import { Fragment as Fragment15, jsx as jsx36, jsxs as jsxs33 } from "preact/jsx-runtime";
2682
3028
  function JoinIsland(props) {
2683
- return /* @__PURE__ */ jsx33(JourneyFrame, { children: /* @__PURE__ */ jsx33(JoinFlow, { ...props }) });
3029
+ return /* @__PURE__ */ jsx36(JourneyFrame, { children: /* @__PURE__ */ jsx36(JoinFlow, { ...props }) });
2684
3030
  }
2685
3031
  function JoinFlow(props) {
2686
3032
  const inheritedCopy = useChapterCopy();
@@ -2701,16 +3047,16 @@ function JoinFlow(props) {
2701
3047
  const invitation = invitationState.invitation;
2702
3048
  const selectedTierId = invitation?.skuId ?? tierSelection.selectedTierId;
2703
3049
  const selectedTier = tiers.find((tier) => tier.id === selectedTierId) ?? tierSelection.selected;
2704
- const [state, setState] = useState23(requestedSeat ? { step: "form" } : props.initialState ?? { step: "form" });
2705
- const [error, setError] = useState23(null);
2706
- const [submitting, setSubmitting] = useState23(false);
2707
- const [editingNamedSeat, setEditingNamedSeat] = useState23(false);
2708
- const [giftOfferId, setGiftOfferId] = useState23(props.initialGiftOfferId ?? null);
3050
+ const [state, setState] = useState26(requestedSeat ? { step: "form" } : props.initialState ?? { step: "form" });
3051
+ const [error, setError] = useState26(null);
3052
+ const [submitting, setSubmitting] = useState26(false);
3053
+ const [editingNamedSeat, setEditingNamedSeat] = useState26(false);
3054
+ const [giftOfferId, setGiftOfferId] = useState26(props.initialGiftOfferId ?? null);
2709
3055
  const simulatedPayment = joinSimulationPayment(props.simulation, selectedTier?.priceCents ?? 0);
2710
3056
  const simulatedBooking = props.simulation ? props.simulation.booking ?? { slots: [], timezone: "UTC" } : void 0;
2711
3057
  const submissionId = useRef8(null);
2712
3058
  const slotsPreload = useJoinSlotsPreload(!props.simulation && ["payment", "paymentPending"].includes(state.step));
2713
- useEffect13(() => {
3059
+ useEffect16(() => {
2714
3060
  if (props.simulation) return;
2715
3061
  const resolver = requestedSeat ? () => invitation?.applicationId ? loadJoinResume(invitation.applicationId) : Promise.resolve(null) : props.loadResume ?? (() => {
2716
3062
  if (typeof window === "undefined") return Promise.resolve(null);
@@ -2739,7 +3085,7 @@ function JoinFlow(props) {
2739
3085
  setError(null);
2740
3086
  try {
2741
3087
  const fields = collectFormFields(new FormData(e.currentTarget));
2742
- fields.submissionId = submissionId.current ??= crypto.randomUUID();
3088
+ Object.assign(fields, { submissionId: submissionId.current ??= crypto.randomUUID() }, invitation ? {} : referralFromLocation());
2743
3089
  if (invitation) {
2744
3090
  fields.namedSeatId = invitation.seatId;
2745
3091
  fields.tierId = invitation.skuId;
@@ -2783,13 +3129,13 @@ function JoinFlow(props) {
2783
3129
  setSubmitting(false);
2784
3130
  }
2785
3131
  };
2786
- if (requestedSeat && !invitation) return /* @__PURE__ */ jsxs31("section", { className: "card", "aria-live": "polite", children: [
2787
- /* @__PURE__ */ jsx33("h2", { children: seatCopy.title }),
2788
- /* @__PURE__ */ jsx33("p", { role: invitationState.error ? "alert" : "status", children: invitationState.error || seatCopy.loading }),
2789
- invitationState.error ? /* @__PURE__ */ jsx33("button", { type: "button", onClick: invitationState.retry, children: seatCopy.retry }) : null
3132
+ if (requestedSeat && !invitation) return /* @__PURE__ */ jsxs33("section", { className: "card", "aria-live": "polite", children: [
3133
+ /* @__PURE__ */ jsx36("h2", { children: seatCopy.title }),
3134
+ /* @__PURE__ */ jsx36("p", { role: invitationState.error ? "alert" : "status", children: invitationState.error || seatCopy.loading }),
3135
+ invitationState.error ? /* @__PURE__ */ jsx36("button", { type: "button", onClick: invitationState.retry, children: seatCopy.retry }) : null
2790
3136
  ] });
2791
- const header = /* @__PURE__ */ jsxs31(Fragment13, { children: [
2792
- invitation ? /* @__PURE__ */ jsx33(
3137
+ const header = /* @__PURE__ */ jsxs33(Fragment15, { children: [
3138
+ invitation ? /* @__PURE__ */ jsx36(
2793
3139
  JoinInvitationNotice,
2794
3140
  {
2795
3141
  invitation,
@@ -2804,49 +3150,49 @@ function JoinFlow(props) {
2804
3150
  ..."applicationId" in state ? { applicationId: state.applicationId } : {}
2805
3151
  })
2806
3152
  ] });
2807
- const receipt = !props.simulation && !requestedSeat && ["paymentPending", "booking", "accepted", "done"].includes(state.step) && "applicationId" in state ? /* @__PURE__ */ jsx33(PaymentReceiptCard, { applicationId: state.applicationId }) : null;
3153
+ const receipt = !props.simulation && !requestedSeat && ["paymentPending", "booking", "accepted", "done"].includes(state.step) && "applicationId" in state ? /* @__PURE__ */ jsx36(PaymentReceiptCard, { applicationId: state.applicationId }) : null;
2808
3154
  if (state.step === "closed") {
2809
- return /* @__PURE__ */ jsxs31(Fragment13, { children: [
3155
+ return /* @__PURE__ */ jsxs33(Fragment15, { children: [
2810
3156
  header,
2811
- /* @__PURE__ */ jsxs31("section", { className: "card", "aria-label": "Application closed", children: [
2812
- /* @__PURE__ */ jsx33("h2", { children: "This application is closed" }),
2813
- /* @__PURE__ */ jsx33("p", { children: "This link cannot resume payment or booking. Sign in to view your application status, or contact the chapter if you need help." }),
2814
- /* @__PURE__ */ jsx33("a", { className: "apply-link", href: membersHref, children: copy.done.memberArea })
3157
+ /* @__PURE__ */ jsxs33("section", { className: "card", "aria-label": "Application closed", children: [
3158
+ /* @__PURE__ */ jsx36("h2", { children: "This application is closed" }),
3159
+ /* @__PURE__ */ jsx36("p", { children: "This link cannot resume payment or booking. Sign in to view your application status, or contact the chapter if you need help." }),
3160
+ /* @__PURE__ */ jsx36("a", { className: "apply-link", href: membersHref, children: copy.done.memberArea })
2815
3161
  ] })
2816
3162
  ] });
2817
3163
  }
2818
3164
  if (state.step === "done") {
2819
- const body = renderDone?.({ ...state, membersHref }) ?? /* @__PURE__ */ jsxs31("div", { className: "join-done card", children: [
2820
- /* @__PURE__ */ jsx33("div", { className: "card-label", children: copy.done.label }),
2821
- /* @__PURE__ */ jsx33("p", { className: "meeting-date", children: fullLabel(state.booked.startAt, state.booked.timezone) }),
2822
- /* @__PURE__ */ jsx33("p", { className: "meeting-note", children: copy.done.calendarInvite }),
2823
- /* @__PURE__ */ jsx33("a", { className: "apply-link", href: membersHref, children: copy.done.memberArea })
3165
+ const body = renderDone?.({ ...state, membersHref }) ?? /* @__PURE__ */ jsxs33("div", { className: "join-done card", children: [
3166
+ /* @__PURE__ */ jsx36("div", { className: "card-label", children: copy.done.label }),
3167
+ /* @__PURE__ */ jsx36("p", { className: "meeting-date", children: fullLabel(state.booked.startAt, state.booked.timezone) }),
3168
+ /* @__PURE__ */ jsx36("p", { className: "meeting-note", children: copy.done.calendarInvite }),
3169
+ /* @__PURE__ */ jsx36("a", { className: "apply-link", href: membersHref, children: copy.done.memberArea })
2824
3170
  ] });
2825
- return /* @__PURE__ */ jsxs31(Fragment13, { children: [
3171
+ return /* @__PURE__ */ jsxs33(Fragment15, { children: [
2826
3172
  header,
2827
3173
  body,
2828
3174
  receipt
2829
3175
  ] });
2830
3176
  }
2831
3177
  if (state.step === "accepted") {
2832
- const body = renderAccepted?.({ ...state, membersHref }) ?? /* @__PURE__ */ jsx33(JoinAccepted, { copy, membersHref });
2833
- return /* @__PURE__ */ jsxs31(Fragment13, { children: [
3178
+ const body = renderAccepted?.({ ...state, membersHref }) ?? /* @__PURE__ */ jsx36(JoinAccepted, { copy, membersHref });
3179
+ return /* @__PURE__ */ jsxs33(Fragment15, { children: [
2834
3180
  header,
2835
3181
  body,
2836
3182
  receipt
2837
3183
  ] });
2838
3184
  }
2839
3185
  if (state.step === "gift") {
2840
- const body = renderGift?.(state) ?? /* @__PURE__ */ jsx33(GiftClaimCard, { applicationId: state.applicationId, claimId: state.claimId, initialCode: state.code, copy: copy.gift });
2841
- return /* @__PURE__ */ jsxs31(Fragment13, { children: [
3186
+ const body = renderGift?.(state) ?? /* @__PURE__ */ jsx36(GiftClaimCard, { applicationId: state.applicationId, claimId: state.claimId, initialCode: state.code, copy: copy.gift });
3187
+ return /* @__PURE__ */ jsxs33(Fragment15, { children: [
2842
3188
  header,
2843
3189
  body
2844
3190
  ] });
2845
3191
  }
2846
3192
  if (state.step === "booking") {
2847
- return /* @__PURE__ */ jsxs31(Fragment13, { children: [
3193
+ return /* @__PURE__ */ jsxs33(Fragment15, { children: [
2848
3194
  header,
2849
- /* @__PURE__ */ jsx33(
3195
+ /* @__PURE__ */ jsx36(
2850
3196
  JoinBooking,
2851
3197
  {
2852
3198
  applicationId: state.applicationId,
@@ -2863,9 +3209,9 @@ function JoinFlow(props) {
2863
3209
  }
2864
3210
  if (state.step === "payment") {
2865
3211
  if (props.namedSeatClaimApi && props.initialNamedSeatId && !props.simulation && !state.giftPurchase) {
2866
- return /* @__PURE__ */ jsxs31(Fragment13, { children: [
3212
+ return /* @__PURE__ */ jsxs33(Fragment15, { children: [
2867
3213
  header,
2868
- /* @__PURE__ */ jsx33(
3214
+ /* @__PURE__ */ jsx36(
2869
3215
  JoinNamedSeat,
2870
3216
  {
2871
3217
  api: props.namedSeatClaimApi,
@@ -2878,9 +3224,9 @@ function JoinFlow(props) {
2878
3224
  ] });
2879
3225
  }
2880
3226
  const Payment = state.giftPurchase || props.simulation ? PaymentStep : MembershipPaymentStep;
2881
- return /* @__PURE__ */ jsxs31(Fragment13, { children: [
3227
+ return /* @__PURE__ */ jsxs33(Fragment15, { children: [
2882
3228
  header,
2883
- props.giftClaimApi && !state.giftPurchase ? /* @__PURE__ */ jsx33(
3229
+ props.giftClaimApi && !state.giftPurchase ? /* @__PURE__ */ jsx36(
2884
3230
  JoinGiftClaim,
2885
3231
  {
2886
3232
  api: props.giftClaimApi,
@@ -2891,7 +3237,7 @@ function JoinFlow(props) {
2891
3237
  onError: () => setError(copy.form.unexpectedFailure)
2892
3238
  }
2893
3239
  ) : null,
2894
- /* @__PURE__ */ jsx33(
3240
+ /* @__PURE__ */ jsx36(
2895
3241
  Payment,
2896
3242
  {
2897
3243
  applicationId: state.applicationId,
@@ -2919,9 +3265,9 @@ function JoinFlow(props) {
2919
3265
  }
2920
3266
  if (state.step === "paymentPending") {
2921
3267
  if (props.namedSeatClaimApi && props.initialNamedSeatId && !props.simulation) {
2922
- return /* @__PURE__ */ jsxs31(Fragment13, { children: [
3268
+ return /* @__PURE__ */ jsxs33(Fragment15, { children: [
2923
3269
  header,
2924
- /* @__PURE__ */ jsx33(
3270
+ /* @__PURE__ */ jsx36(
2925
3271
  JoinNamedSeat,
2926
3272
  {
2927
3273
  api: props.namedSeatClaimApi,
@@ -2933,15 +3279,15 @@ function JoinFlow(props) {
2933
3279
  )
2934
3280
  ] });
2935
3281
  }
2936
- return /* @__PURE__ */ jsxs31(Fragment13, { children: [
3282
+ return /* @__PURE__ */ jsxs33(Fragment15, { children: [
2937
3283
  header,
2938
- /* @__PURE__ */ jsx33("p", { className: "pay-status", role: "status", children: copy.payment.pending }),
3284
+ /* @__PURE__ */ jsx36("p", { className: "pay-status", role: "status", children: copy.payment.pending }),
2939
3285
  receipt
2940
3286
  ] });
2941
3287
  }
2942
- return /* @__PURE__ */ jsxs31(Fragment13, { children: [
3288
+ return /* @__PURE__ */ jsxs33(Fragment15, { children: [
2943
3289
  header,
2944
- /* @__PURE__ */ jsx33(
3290
+ /* @__PURE__ */ jsx36(
2945
3291
  JoinApplicationForm,
2946
3292
  {
2947
3293
  props,
@@ -2960,7 +3306,7 @@ function JoinFlow(props) {
2960
3306
  }
2961
3307
 
2962
3308
  // src/ui/membership-cards.tsx
2963
- import { Markdown as Markdown3 } from "@odla-ai/ui/components";
3309
+ import { Markdown as Markdown4 } from "@odla-ai/ui/components";
2964
3310
 
2965
3311
  // src/membership-page.ts
2966
3312
  var MEMBERSHIP_PAGE_RENDERER = "membership-cards-v1";
@@ -3131,7 +3477,7 @@ function membershipPageDocument(input, options = {}) {
3131
3477
  }
3132
3478
 
3133
3479
  // src/ui/membership-cards.tsx
3134
- import { jsx as jsx34, jsxs as jsxs32 } from "preact/jsx-runtime";
3480
+ import { jsx as jsx37, jsxs as jsxs34 } from "preact/jsx-runtime";
3135
3481
  var MEMBERSHIP_CARD_TOKEN_DEFAULTS = Object.freeze({
3136
3482
  "--ui-membership-grid-gap": "1.4rem",
3137
3483
  "--ui-membership-card-padding": "2rem 1.7rem 1.8rem",
@@ -3200,79 +3546,71 @@ function membershipApplicationHref(applicationPath, tierId) {
3200
3546
  }
3201
3547
  function TierAction(props) {
3202
3548
  if (props.mode === "select") {
3203
- return /* @__PURE__ */ jsxs32("button", { type: "button", className: "chapter-membership-action", "aria-current": props.selected ? "true" : void 0, onClick: () => props.onSelectTier?.(props.tierId), children: [
3549
+ return /* @__PURE__ */ jsxs34("button", { type: "button", className: "chapter-membership-action", "aria-current": props.selected ? "true" : void 0, onClick: () => props.onSelectTier?.(props.tierId), children: [
3204
3550
  props.label,
3205
- /* @__PURE__ */ jsx34("span", { "aria-hidden": "true", children: "\u2192" })
3551
+ /* @__PURE__ */ jsx37("span", { "aria-hidden": "true", children: "\u2192" })
3206
3552
  ] });
3207
3553
  }
3208
3554
  if (props.mode === "preview") {
3209
- return /* @__PURE__ */ jsxs32("span", { className: "chapter-membership-action", "aria-disabled": "true", children: [
3555
+ return /* @__PURE__ */ jsxs34("span", { className: "chapter-membership-action", "aria-disabled": "true", children: [
3210
3556
  props.label,
3211
- /* @__PURE__ */ jsx34("span", { "aria-hidden": "true", children: "\u2192" })
3557
+ /* @__PURE__ */ jsx37("span", { "aria-hidden": "true", children: "\u2192" })
3212
3558
  ] });
3213
3559
  }
3214
- return /* @__PURE__ */ jsxs32("a", { className: "chapter-membership-action", href: membershipApplicationHref(props.applicationPath, props.tierId), children: [
3560
+ return /* @__PURE__ */ jsxs34("a", { className: "chapter-membership-action", href: membershipApplicationHref(props.applicationPath, props.tierId), children: [
3215
3561
  props.label,
3216
- /* @__PURE__ */ jsx34("span", { "aria-hidden": "true", children: "\u2192" })
3562
+ /* @__PURE__ */ jsx37("span", { "aria-hidden": "true", children: "\u2192" })
3217
3563
  ] });
3218
3564
  }
3219
3565
  function TierCard(props) {
3220
3566
  const { tier, presentation } = props;
3221
3567
  const summary = presentation.summaryMarkdown ?? tier.blurb;
3222
3568
  const action = presentation.ctaLabel ?? (tier.free ? "Join for free" : `Choose ${tier.name}`);
3223
- return /* @__PURE__ */ jsxs32("article", { className: "chapter-membership-card", "data-tier-id": tier.id, "data-variant": presentation.variant ?? "standard", children: [
3224
- presentation.badge ? /* @__PURE__ */ jsx34("div", { className: "chapter-membership-badge", children: presentation.badge }) : null,
3225
- /* @__PURE__ */ jsx34("h3", { className: "chapter-membership-name", children: tier.name }),
3226
- /* @__PURE__ */ jsxs32("div", { className: "chapter-membership-offer", "data-with-capacity": presentation.capacity ? "true" : void 0, children: [
3227
- presentation.capacity ? /* @__PURE__ */ jsxs32("div", { className: "chapter-membership-capacity", "aria-label": `${presentation.capacity.total} ${presentation.capacity.label ?? "available"}`, children: [
3228
- /* @__PURE__ */ jsx34("strong", { children: presentation.capacity.total.toLocaleString("en-US") }),
3229
- /* @__PURE__ */ jsx34("small", { children: presentation.capacity.label ?? "available" })
3569
+ return /* @__PURE__ */ jsxs34("article", { className: "chapter-membership-card", "data-tier-id": tier.id, "data-variant": presentation.variant ?? "standard", children: [
3570
+ presentation.badge ? /* @__PURE__ */ jsx37("div", { className: "chapter-membership-badge", children: presentation.badge }) : null,
3571
+ /* @__PURE__ */ jsx37("h3", { className: "chapter-membership-name", children: tier.name }),
3572
+ /* @__PURE__ */ jsxs34("div", { className: "chapter-membership-offer", "data-with-capacity": presentation.capacity ? "true" : void 0, children: [
3573
+ presentation.capacity ? /* @__PURE__ */ jsxs34("div", { className: "chapter-membership-capacity", "aria-label": `${presentation.capacity.total} ${presentation.capacity.label ?? "available"}`, children: [
3574
+ /* @__PURE__ */ jsx37("strong", { children: presentation.capacity.total.toLocaleString("en-US") }),
3575
+ /* @__PURE__ */ jsx37("small", { children: presentation.capacity.label ?? "available" })
3230
3576
  ] }) : null,
3231
- /* @__PURE__ */ jsxs32("div", { className: "chapter-membership-price-stack", children: [
3232
- presentation.priceEyebrow ? /* @__PURE__ */ jsx34("p", { className: "chapter-membership-price-eyebrow", children: presentation.priceEyebrow }) : tier.founding ? /* @__PURE__ */ jsx34("p", { className: "chapter-membership-price-eyebrow", children: "Founding member rate" }) : null,
3233
- /* @__PURE__ */ jsxs32("div", { className: "chapter-membership-price-row", children: [
3234
- tier.founding ? /* @__PURE__ */ jsx34("span", { className: "chapter-membership-compare", children: fmtMoney(tier.priceCents) }) : presentation.compareAtPriceCents !== void 0 ? /* @__PURE__ */ jsx34("span", { className: "chapter-membership-compare", children: fmtMoney(presentation.compareAtPriceCents) }) : null,
3235
- /* @__PURE__ */ jsx34("span", { className: "chapter-membership-price", children: tier.free ? "Free" : fmtMoney(tier.founding ? tier.founding.dueTodayCents : tier.priceCents) }),
3236
- !tier.free && presentation.billingLabel ? /* @__PURE__ */ jsx34("span", { className: "chapter-membership-billing", children: presentation.billingLabel }) : null
3577
+ /* @__PURE__ */ jsxs34("div", { className: "chapter-membership-price-stack", children: [
3578
+ presentation.priceEyebrow ? /* @__PURE__ */ jsx37("p", { className: "chapter-membership-price-eyebrow", children: presentation.priceEyebrow }) : tier.founding ? /* @__PURE__ */ jsx37("p", { className: "chapter-membership-price-eyebrow", children: "Founding member rate" }) : null,
3579
+ /* @__PURE__ */ jsxs34("div", { className: "chapter-membership-price-row", children: [
3580
+ tier.founding ? /* @__PURE__ */ jsx37("span", { className: "chapter-membership-compare", children: fmtMoney(tier.priceCents) }) : presentation.compareAtPriceCents !== void 0 ? /* @__PURE__ */ jsx37("span", { className: "chapter-membership-compare", children: fmtMoney(presentation.compareAtPriceCents) }) : null,
3581
+ /* @__PURE__ */ jsx37("span", { className: "chapter-membership-price", children: tier.free ? "Free" : fmtMoney(tier.founding ? tier.founding.dueTodayCents : tier.priceCents) }),
3582
+ !tier.free && presentation.billingLabel ? /* @__PURE__ */ jsx37("span", { className: "chapter-membership-billing", children: presentation.billingLabel }) : null
3237
3583
  ] })
3238
3584
  ] })
3239
3585
  ] }),
3240
- presentation.priceNoteMarkdown ? /* @__PURE__ */ jsx34(Markdown3, { className: "chapter-membership-price-note", source: presentation.priceNoteMarkdown }) : null,
3241
- summary ? /* @__PURE__ */ jsx34(Markdown3, { className: "chapter-membership-summary", source: summary }) : null,
3242
- presentation.benefits?.length ? /* @__PURE__ */ jsx34("ul", { className: "chapter-membership-benefits", children: presentation.benefits.map((benefit, index) => /* @__PURE__ */ jsxs32("li", { children: [
3243
- /* @__PURE__ */ jsx34("span", { className: "chapter-membership-check", "aria-hidden": "true", children: "\u2713" }),
3244
- /* @__PURE__ */ jsx34(Markdown3, { className: "chapter-membership-benefit", source: benefit })
3586
+ presentation.priceNoteMarkdown ? /* @__PURE__ */ jsx37(Markdown4, { className: "chapter-membership-price-note", source: presentation.priceNoteMarkdown }) : null,
3587
+ summary ? /* @__PURE__ */ jsx37(Markdown4, { className: "chapter-membership-summary", source: summary }) : null,
3588
+ presentation.benefits?.length ? /* @__PURE__ */ jsx37("ul", { className: "chapter-membership-benefits", children: presentation.benefits.map((benefit, index) => /* @__PURE__ */ jsxs34("li", { children: [
3589
+ /* @__PURE__ */ jsx37("span", { className: "chapter-membership-check", "aria-hidden": "true", children: "\u2713" }),
3590
+ /* @__PURE__ */ jsx37(Markdown4, { className: "chapter-membership-benefit", source: benefit })
3245
3591
  ] }, `${tier.id}-benefit-${index}`)) }) : null,
3246
- presentation.callout ? /* @__PURE__ */ jsxs32("aside", { className: "chapter-membership-callout", children: [
3247
- presentation.callout.label ? /* @__PURE__ */ jsx34("p", { className: "chapter-membership-callout-label", children: presentation.callout.label }) : null,
3248
- /* @__PURE__ */ jsx34(Markdown3, { source: presentation.callout.bodyMarkdown })
3592
+ presentation.callout ? /* @__PURE__ */ jsxs34("aside", { className: "chapter-membership-callout", children: [
3593
+ presentation.callout.label ? /* @__PURE__ */ jsx37("p", { className: "chapter-membership-callout-label", children: presentation.callout.label }) : null,
3594
+ /* @__PURE__ */ jsx37(Markdown4, { source: presentation.callout.bodyMarkdown })
3249
3595
  ] }) : null,
3250
- /* @__PURE__ */ jsx34(TierAction, { tierId: tier.id, label: action, mode: props.mode, selected: props.selected, applicationPath: props.applicationPath, onSelectTier: props.onSelectTier })
3596
+ /* @__PURE__ */ jsx37(TierAction, { tierId: tier.id, label: action, mode: props.mode, selected: props.selected, applicationPath: props.applicationPath, onSelectTier: props.onSelectTier })
3251
3597
  ] });
3252
3598
  }
3253
3599
  function MembershipCards(props) {
3254
3600
  const document2 = membershipPageDocument(props.document, { tiers: props.tiers });
3255
3601
  const byId = new Map(props.tiers.map((tier) => [tier.id, tier]));
3256
3602
  const mode = props.mode ?? "link";
3257
- return /* @__PURE__ */ jsxs32("section", { className: ["chapter-membership", props.className].filter(Boolean).join(" "), "data-chapter-membership": MEMBERSHIP_PAGE_RENDERER, "aria-label": props.ariaLabel ?? "Membership options", children: [
3258
- /* @__PURE__ */ jsx34("style", { children: MEMBERSHIP_CARDS_CSS }),
3259
- /* @__PURE__ */ jsx34("div", { className: "chapter-membership-grid", style: { "--chapter-membership-columns": String(Math.min(document2.tiers.length, 3)) }, children: document2.tiers.map((presentation) => {
3603
+ return /* @__PURE__ */ jsxs34("section", { className: ["chapter-membership", props.className].filter(Boolean).join(" "), "data-chapter-membership": MEMBERSHIP_PAGE_RENDERER, "aria-label": props.ariaLabel ?? "Membership options", children: [
3604
+ /* @__PURE__ */ jsx37("style", { children: MEMBERSHIP_CARDS_CSS }),
3605
+ /* @__PURE__ */ jsx37("div", { className: "chapter-membership-grid", style: { "--chapter-membership-columns": String(Math.min(document2.tiers.length, 3)) }, children: document2.tiers.map((presentation) => {
3260
3606
  const tier = byId.get(presentation.tierId);
3261
- return /* @__PURE__ */ jsx34(TierCard, { tier, presentation, mode, selected: props.selectedTierId === tier.id, applicationPath: props.applicationPath, onSelectTier: props.onSelectTier }, tier.id);
3607
+ return /* @__PURE__ */ jsx37(TierCard, { tier, presentation, mode, selected: props.selectedTierId === tier.id, applicationPath: props.applicationPath, onSelectTier: props.onSelectTier }, tier.id);
3262
3608
  }) }),
3263
- document2.footnoteMarkdown ? /* @__PURE__ */ jsx34(Markdown3, { className: "chapter-membership-footnote", source: document2.footnoteMarkdown }) : null
3609
+ document2.footnoteMarkdown ? /* @__PURE__ */ jsx37(Markdown4, { className: "chapter-membership-footnote", source: document2.footnoteMarkdown }) : null
3264
3610
  ] });
3265
3611
  }
3266
3612
 
3267
3613
  export {
3268
- tzShort,
3269
- dayKey,
3270
- dayLabel,
3271
- timeLabel,
3272
- fullLabel,
3273
- fmtMoney,
3274
- fmtDate,
3275
- groupSlotsByDay,
3276
3614
  SlotPicker,
3277
3615
  ADDITIONAL_MEMBER_COPY,
3278
3616
  additionalMemberSelection,
@@ -3315,9 +3653,30 @@ export {
3315
3653
  startingPrompts,
3316
3654
  choosePrompt,
3317
3655
  MemberProfilePage,
3656
+ useCourse,
3657
+ seatLine,
3658
+ SeatActions,
3659
+ CoursePage,
3660
+ CourseHomePanel,
3661
+ articleFor,
3662
+ shareVars,
3663
+ linkedinShareUrl,
3664
+ mailtoHref,
3665
+ smsHref,
3666
+ isIOS,
3667
+ useMemberReferrals,
3668
+ CopyButton,
3669
+ OfficialCard,
3670
+ PostCard,
3671
+ InviteLinkCard,
3672
+ ReferralsCard,
3673
+ SharePage,
3674
+ ShareHome,
3675
+ ProfileReferrals,
3318
3676
  PACKAGED_PORTAL_FEATURES,
3319
3677
  MemberPortal,
3320
3678
  MembersArea,
3679
+ referralFromLocation,
3321
3680
  useTierSelection,
3322
3681
  TierPlaceholder,
3323
3682
  tierNeedsPayment,
@@ -3328,4 +3687,4 @@ export {
3328
3687
  membershipApplicationHref,
3329
3688
  MembershipCards
3330
3689
  };
3331
- //# sourceMappingURL=chunk-ZIYK3OV2.js.map
3690
+ //# sourceMappingURL=chunk-QPFJBHHK.js.map