@odla-ai/chapter 0.41.1 → 0.42.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,7 +1,7 @@
1
1
  import {
2
2
  formatChapterCopy,
3
3
  useChapterCopy
4
- } from "./chunk-IAWBE5PX.js";
4
+ } from "./chunk-JXFYOUDL.js";
5
5
  import {
6
6
  collectFormFields
7
7
  } from "./chunk-IVXVECKR.js";
@@ -110,7 +110,7 @@ function SlotPicker(props) {
110
110
  }
111
111
 
112
112
  // src/ui/members.tsx
113
- import { useEffect as useEffect3, useState as useState7 } from "preact/hooks";
113
+ import { useEffect as useEffect3, useState as useState6 } from "preact/hooks";
114
114
 
115
115
  // src/ui/reschedule.tsx
116
116
  import { useState as useState2 } from "preact/hooks";
@@ -195,7 +195,7 @@ function Rescheduler(props) {
195
195
  }
196
196
 
197
197
  // src/ui/member-gifts.tsx
198
- import { useEffect, useRef as useRef2, useState as useState5 } from "preact/hooks";
198
+ import { useEffect, useRef as useRef2, useState as useState4 } from "preact/hooks";
199
199
 
200
200
  // src/ui/gift-offer-cards.tsx
201
201
  import { jsx as jsx3, jsxs as jsxs3 } from "preact/jsx-runtime";
@@ -213,94 +213,9 @@ function GiftOfferCards(props) {
213
213
  ] }, offer.id)) });
214
214
  }
215
215
 
216
- // src/ui/gift-code-redeemer.tsx
217
- import { InlineActionField } from "@odla-ai/ui/components";
218
- import { useState as useState3 } from "preact/hooks";
219
- import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "preact/jsx-runtime";
220
- var GIFT_CODE_REDEEMER_CSS = `
221
- .gift-code-redeemer{container-type:inline-size;display:grid;gap:var(--ui-space-1,.35rem);margin:0}
222
- .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}
223
- .gift-code-redeemer .inline-action-field-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:var(--ui-space-2,.65rem);align-items:stretch}
224
- .gift-code-redeemer .inline-action-field-input,.gift-code-redeemer .inline-action-field-action{min-height:var(--ui-inline-action-control-height,38px)}
225
- .gift-code-redeemer .inline-action-field-input.code{font-family:var(--ui-font-mono,ui-monospace,monospace);font-variant-ligatures:none;letter-spacing:var(--ui-tracking-wide,.04em)}
226
- .gift-code-redeemer .inline-action-field-input:focus-visible{outline:none;border-color:var(--ui-accent,#168c84);box-shadow:var(--ui-focus,0 0 0 3px rgb(22 140 132 / .18))}
227
- .gift-code-redeemer .inline-action-field-action{white-space:nowrap}
228
- .gift-code-redeemer .inline-action-field-status{display:block;min-block-size:1.4em;margin:0;color:var(--ui-text-muted,#66777f);font-size:var(--ui-text-sm,.8rem);line-height:1.4}
229
- .gift-code-redeemer .inline-action-field-status.success{color:var(--ui-good,#1f7a52)}
230
- .gift-code-redeemer .inline-action-field-status.error{color:var(--ui-danger,#b42318)}
231
- @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%}}
232
- `;
233
- function GiftCodeRedeemer({ api, copy, id, onRedeemed }) {
234
- const [code, setCode] = useState3("");
235
- const [loading, setLoading] = useState3(false);
236
- const [message, setMessage] = useState3("");
237
- const [messageTone, setMessageTone] = useState3("neutral");
238
- const normalizedCode = code.trim();
239
- const redeem = async () => {
240
- if (!normalizedCode || loading) return;
241
- setLoading(true);
242
- setMessage("");
243
- setMessageTone("neutral");
244
- try {
245
- await api("/api/gifts/redeem", {
246
- method: "POST",
247
- headers: { "content-type": "application/json" },
248
- body: JSON.stringify({ code: normalizedCode })
249
- });
250
- setCode("");
251
- setMessage(copy.redeemed);
252
- setMessageTone("success");
253
- try {
254
- await onRedeemed?.();
255
- } catch {
256
- }
257
- } catch {
258
- setMessage(copy.redeemFailed);
259
- setMessageTone("error");
260
- } finally {
261
- setLoading(false);
262
- }
263
- };
264
- return /* @__PURE__ */ jsxs4(Fragment2, { children: [
265
- /* @__PURE__ */ jsx4("style", { children: GIFT_CODE_REDEEMER_CSS }),
266
- /* @__PURE__ */ jsx4(
267
- InlineActionField,
268
- {
269
- id,
270
- className: "gift-code-redeemer",
271
- label: copy.code,
272
- value: code,
273
- code: true,
274
- actionLabel: copy.redeem,
275
- loadingLabel: `${copy.redeem}\u2026`,
276
- loading,
277
- actionDisabled: !normalizedCode,
278
- message,
279
- messageTone,
280
- inputProps: {
281
- name: "giftCode",
282
- maxLength: 64,
283
- autoComplete: "one-time-code",
284
- autoCapitalize: "none",
285
- autocorrect: "off",
286
- spellcheck: false
287
- },
288
- onValueChange: (value) => {
289
- setCode(value);
290
- if (message) {
291
- setMessage("");
292
- setMessageTone("neutral");
293
- }
294
- },
295
- onAction: () => void redeem()
296
- }
297
- )
298
- ] });
299
- }
300
-
301
216
  // src/ui/payment-step.tsx
302
- import { useRef, useState as useState4 } from "preact/hooks";
303
- import { jsx as jsx5, jsxs as jsxs5 } from "preact/jsx-runtime";
217
+ import { useRef, useState as useState3 } from "preact/hooks";
218
+ import { jsx as jsx4, jsxs as jsxs4 } from "preact/jsx-runtime";
304
219
  var loader = null;
305
220
  function loadStripe() {
306
221
  const existing = globalThis.Stripe;
@@ -334,9 +249,9 @@ function PaymentStep(props) {
334
249
  simulation
335
250
  } = props;
336
251
  const copy = props.copy ?? inheritedCopy.join.payment;
337
- const [status, setStatus] = useState4("idle");
338
- const [error, setError] = useState4(null);
339
- const [lineItems, setLineItems] = useState4(null);
252
+ const [status, setStatus] = useState3("idle");
253
+ const [error, setError] = useState3(null);
254
+ const [lineItems, setLineItems] = useState3(null);
340
255
  const mountRef = useRef(null);
341
256
  const stripeRef = useRef(null);
342
257
  const elementsRef = useRef(null);
@@ -410,12 +325,12 @@ function PaymentStep(props) {
410
325
  setStatus("ready");
411
326
  }
412
327
  };
413
- return /* @__PURE__ */ jsxs5("div", { className: "join-pay", children: [
414
- /* @__PURE__ */ jsxs5("div", { className: "compliance-box", children: [
415
- merchantDisclosureText ? /* @__PURE__ */ jsx5("p", { className: "compliance-merchant", children: merchantDisclosureText }) : null,
416
- /* @__PURE__ */ jsx5("p", { className: "compliance-policy", children: refundPolicyText }),
417
- /* @__PURE__ */ jsxs5("label", { className: "compliance-check", children: [
418
- /* @__PURE__ */ jsx5(
328
+ return /* @__PURE__ */ jsxs4("div", { className: "join-pay", children: [
329
+ /* @__PURE__ */ jsxs4("div", { className: "compliance-box", children: [
330
+ merchantDisclosureText ? /* @__PURE__ */ jsx4("p", { className: "compliance-merchant", children: merchantDisclosureText }) : null,
331
+ /* @__PURE__ */ jsx4("p", { className: "compliance-policy", children: refundPolicyText }),
332
+ /* @__PURE__ */ jsxs4("label", { className: "compliance-check", children: [
333
+ /* @__PURE__ */ jsx4(
419
334
  "input",
420
335
  {
421
336
  type: "checkbox",
@@ -425,41 +340,41 @@ function PaymentStep(props) {
425
340
  }
426
341
  }
427
342
  ),
428
- copy.consent ? /* @__PURE__ */ jsx5("span", { children: copy.consent }) : null
343
+ copy.consent ? /* @__PURE__ */ jsx4("span", { children: copy.consent }) : null
429
344
  ] })
430
345
  ] }),
431
- status === "loading" ? /* @__PURE__ */ jsx5("p", { className: "pay-status", children: copy.preparing }) : null,
346
+ status === "loading" ? /* @__PURE__ */ jsx4("p", { className: "pay-status", children: copy.preparing }) : null,
432
347
  lineItems && renderPriceLines ? renderPriceLines(lineItems) : null,
433
348
  children,
434
- simulation && (status === "ready" || status === "confirming") ? /* @__PURE__ */ jsxs5("fieldset", { className: "join-pay-simulation", children: [
435
- /* @__PURE__ */ jsx5("legend", { children: "Payment details" }),
436
- /* @__PURE__ */ jsxs5("label", { children: [
349
+ simulation && (status === "ready" || status === "confirming") ? /* @__PURE__ */ jsxs4("fieldset", { className: "join-pay-simulation", children: [
350
+ /* @__PURE__ */ jsx4("legend", { children: "Payment details" }),
351
+ /* @__PURE__ */ jsxs4("label", { children: [
437
352
  "Card number",
438
- /* @__PURE__ */ jsx5("input", { name: "simulationCardNumber", inputMode: "numeric", autoComplete: "off", defaultValue: "4242 4242 4242 4242" })
353
+ /* @__PURE__ */ jsx4("input", { name: "simulationCardNumber", inputMode: "numeric", autoComplete: "off", defaultValue: "4242 4242 4242 4242" })
439
354
  ] }),
440
- /* @__PURE__ */ jsxs5("label", { children: [
355
+ /* @__PURE__ */ jsxs4("label", { children: [
441
356
  "Expiration",
442
- /* @__PURE__ */ jsx5("input", { name: "simulationCardExpiry", inputMode: "numeric", autoComplete: "off", defaultValue: "12 / 34" })
357
+ /* @__PURE__ */ jsx4("input", { name: "simulationCardExpiry", inputMode: "numeric", autoComplete: "off", defaultValue: "12 / 34" })
443
358
  ] }),
444
- /* @__PURE__ */ jsxs5("label", { children: [
359
+ /* @__PURE__ */ jsxs4("label", { children: [
445
360
  "Security code",
446
- /* @__PURE__ */ jsx5("input", { name: "simulationCardCvc", inputMode: "numeric", autoComplete: "off", defaultValue: "123" })
361
+ /* @__PURE__ */ jsx4("input", { name: "simulationCardCvc", inputMode: "numeric", autoComplete: "off", defaultValue: "123" })
447
362
  ] }),
448
- /* @__PURE__ */ jsx5("p", { children: "This is a simulation. No card data is sent and no charge is created." })
363
+ /* @__PURE__ */ jsx4("p", { children: "This is a simulation. No card data is sent and no charge is created." })
449
364
  ] }) : null,
450
- /* @__PURE__ */ jsx5("div", { ref: mountRef, hidden: status === "idle" || status === "loading" }),
451
- status === "ready" || status === "confirming" ? /* @__PURE__ */ jsx5("button", { className: "submit-btn", disabled: status === "confirming", onClick: () => void pay(), children: status === "confirming" ? copy.processing : copy.payAndContinue }) : null,
452
- error ? /* @__PURE__ */ jsx5("p", { className: "pay-error", children: error }) : null
365
+ /* @__PURE__ */ jsx4("div", { ref: mountRef, hidden: status === "idle" || status === "loading" }),
366
+ status === "ready" || status === "confirming" ? /* @__PURE__ */ jsx4("button", { className: "submit-btn", disabled: status === "confirming", onClick: () => void pay(), children: status === "confirming" ? copy.processing : copy.payAndContinue }) : null,
367
+ error ? /* @__PURE__ */ jsx4("p", { className: "pay-error", children: error }) : null
453
368
  ] });
454
369
  }
455
370
 
456
371
  // src/ui/member-gifts.tsx
457
- import { jsx as jsx6, jsxs as jsxs6 } from "preact/jsx-runtime";
458
- function MemberGifts(props) {
459
- const [data, setData] = useState5(null);
460
- const [selected, setSelected] = useState5(null);
461
- const [code, setCode] = useState5("");
462
- const [message, setMessage] = useState5("");
372
+ import { jsx as jsx5, jsxs as jsxs5 } from "preact/jsx-runtime";
373
+ function GiftPurchases(props) {
374
+ const [data, setData] = useState4(null);
375
+ const [selected, setSelected] = useState4(null);
376
+ const [code, setCode] = useState4("");
377
+ const [message, setMessage] = useState4("");
463
378
  const purchaseId = useRef2(crypto.randomUUID());
464
379
  const load = async () => setData(await props.api("/api/gifts"));
465
380
  useEffect(() => {
@@ -475,17 +390,18 @@ function MemberGifts(props) {
475
390
  }
476
391
  };
477
392
  if (!data) return null;
393
+ if (data.offers.length === 0 && data.claims.length === 0) return null;
478
394
  const offer = data.offers.find((item) => item.id === selected);
479
- return /* @__PURE__ */ jsxs6("section", { className: "member-gifts", children: [
480
- /* @__PURE__ */ jsxs6("div", { className: "card", children: [
481
- /* @__PURE__ */ jsx6("div", { className: "card-label", children: props.copy.title }),
482
- /* @__PURE__ */ jsx6("p", { children: props.copy.body }),
483
- data.offers.length ? /* @__PURE__ */ jsx6(GiftOfferCards, { offers: data.offers, mode: "select", selectedOfferId: selected, onSelect: (id) => {
395
+ return /* @__PURE__ */ jsxs5("section", { className: "member-gifts", children: [
396
+ data.offers.length ? /* @__PURE__ */ jsxs5("div", { className: "card", children: [
397
+ /* @__PURE__ */ jsx5("div", { className: "card-label", children: props.copy.title }),
398
+ /* @__PURE__ */ jsx5("p", { children: props.copy.body }),
399
+ /* @__PURE__ */ jsx5(GiftOfferCards, { offers: data.offers, mode: "select", selectedOfferId: selected, onSelect: (id) => {
484
400
  setSelected(id);
485
401
  setCode("");
486
402
  purchaseId.current = crypto.randomUUID();
487
- } }) : /* @__PURE__ */ jsx6("p", { children: props.copy.noneAvailable }),
488
- offer ? /* @__PURE__ */ jsx6(
403
+ } }),
404
+ offer ? /* @__PURE__ */ jsx5(
489
405
  PaymentStep,
490
406
  {
491
407
  applicationId: purchaseId.current,
@@ -505,31 +421,28 @@ function MemberGifts(props) {
505
421
  }
506
422
  }
507
423
  ) : null,
508
- code ? /* @__PURE__ */ jsxs6("div", { className: "gift-code-once", children: [
509
- /* @__PURE__ */ jsx6("output", { children: code }),
510
- /* @__PURE__ */ jsx6("p", { children: props.copy.saveCode })
424
+ code ? /* @__PURE__ */ jsxs5("div", { className: "gift-code-once", children: [
425
+ /* @__PURE__ */ jsx5("output", { children: code }),
426
+ /* @__PURE__ */ jsx5("p", { children: props.copy.saveCode })
511
427
  ] }) : null
512
- ] }),
513
- /* @__PURE__ */ jsxs6("div", { className: "card", children: [
514
- /* @__PURE__ */ jsx6("div", { className: "card-label", children: props.copy.purchases }),
515
- data.claims.length ? data.claims.map((claim) => /* @__PURE__ */ jsxs6("div", { className: "member-row", children: [
516
- /* @__PURE__ */ jsx6("span", { children: claim.offerId }),
517
- /* @__PURE__ */ jsx6("span", { children: props.copy[claim.status] }),
518
- claim.status === "pending" ? /* @__PURE__ */ jsx6("button", { className: "btn secondary mini", onClick: () => void rotate(claim.id), children: props.copy.rotate }) : null
519
- ] }, claim.id)) : /* @__PURE__ */ jsx6("p", { children: props.copy.noPurchases })
520
- ] }),
521
- /* @__PURE__ */ jsxs6("div", { className: "card", children: [
522
- /* @__PURE__ */ jsx6("div", { className: "card-label", children: props.copy.redeemTitle }),
523
- /* @__PURE__ */ jsx6(GiftCodeRedeemer, { api: props.api, copy: props.copy, onRedeemed: load }),
524
- message ? /* @__PURE__ */ jsx6("p", { role: "status", children: message }) : null
428
+ ] }) : null,
429
+ /* @__PURE__ */ jsxs5("div", { className: "card", children: [
430
+ /* @__PURE__ */ jsx5("div", { className: "card-label", children: props.copy.purchases }),
431
+ data.claims.length ? data.claims.map((claim) => /* @__PURE__ */ jsxs5("div", { className: "member-row", children: [
432
+ /* @__PURE__ */ jsx5("span", { children: claim.offerId }),
433
+ /* @__PURE__ */ jsx5("span", { children: props.copy[claim.status] }),
434
+ claim.status === "pending" ? /* @__PURE__ */ jsx5("button", { className: "btn secondary mini", onClick: () => void rotate(claim.id), children: props.copy.rotate }) : null
435
+ ] }, claim.id)) : /* @__PURE__ */ jsx5("p", { children: props.copy.noPurchases }),
436
+ message ? /* @__PURE__ */ jsx5("p", { role: "status", children: message }) : null
525
437
  ] })
526
438
  ] });
527
439
  }
440
+ var MemberGifts = GiftPurchases;
528
441
 
529
442
  // src/ui/member-content.tsx
530
- import { useEffect as useEffect2, useMemo as useMemo2, useState as useState6 } from "preact/hooks";
443
+ import { useEffect as useEffect2, useMemo as useMemo2, useState as useState5 } from "preact/hooks";
531
444
  import { Markdown } from "@odla-ai/ui/components";
532
- import { Fragment as Fragment3, jsx as jsx7, jsxs as jsxs7 } from "preact/jsx-runtime";
445
+ import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs6 } from "preact/jsx-runtime";
533
446
  var pageLabel = (page) => `${page.title}${page.access === "locked" ? " \xB7 Locked" : ""}`;
534
447
  function MemberContentArea(props) {
535
448
  const {
@@ -537,12 +450,12 @@ function MemberContentArea(props) {
537
450
  path = "/api/member-content",
538
451
  upsellHref,
539
452
  onUpsell,
540
- loadingContent = /* @__PURE__ */ jsx7("p", { className: "meeting-note", children: "Loading member pages\u2026" }),
541
- emptyContent = /* @__PURE__ */ jsx7("p", { className: "meeting-note", children: "No member pages have been published yet." })
453
+ loadingContent = /* @__PURE__ */ jsx6("p", { className: "meeting-note", children: "Loading member pages\u2026" }),
454
+ emptyContent = /* @__PURE__ */ jsx6("p", { className: "meeting-note", children: "No member pages have been published yet." })
542
455
  } = props;
543
- const [data, setData] = useState6(props.initialData ?? null);
544
- const [error, setError] = useState6(null);
545
- const [selectedId, setSelectedId] = useState6(
456
+ const [data, setData] = useState5(props.initialData ?? null);
457
+ const [error, setError] = useState5(null);
458
+ const [selectedId, setSelectedId] = useState5(
546
459
  props.initialPageId ?? props.initialData?.pages[0]?.id ?? ""
547
460
  );
548
461
  useEffect2(() => {
@@ -567,18 +480,18 @@ function MemberContentArea(props) {
567
480
  }
568
481
  return [...result.entries()];
569
482
  }, [data]);
570
- if (error) return /* @__PURE__ */ jsxs7("p", { className: "meeting-note", role: "alert", children: [
483
+ if (error) return /* @__PURE__ */ jsxs6("p", { className: "meeting-note", role: "alert", children: [
571
484
  "Member pages could not be loaded: ",
572
485
  error
573
486
  ] });
574
- if (!data) return /* @__PURE__ */ jsx7(Fragment3, { children: loadingContent });
575
- if (data.pages.length === 0) return /* @__PURE__ */ jsx7(Fragment3, { children: emptyContent });
487
+ if (!data) return /* @__PURE__ */ jsx6(Fragment2, { children: loadingContent });
488
+ if (data.pages.length === 0) return /* @__PURE__ */ jsx6(Fragment2, { children: emptyContent });
576
489
  const selected = data.pages.find((page) => page.id === selectedId) ?? data.pages[0];
577
490
  const href = selected.upsell && upsellHref ? upsellHref(selected.upsell.tierId, selected) : void 0;
578
- return /* @__PURE__ */ jsxs7("div", { className: "chapter-member-content", "data-member-content": true, children: [
579
- /* @__PURE__ */ jsx7("nav", { className: "chapter-member-content-nav", "aria-label": "Member pages", children: sections.map(([section, pages]) => /* @__PURE__ */ jsxs7("section", { className: "chapter-member-content-section", children: [
580
- /* @__PURE__ */ jsx7("h2", { children: section }),
581
- /* @__PURE__ */ jsx7("ul", { children: pages.map((page) => /* @__PURE__ */ jsx7("li", { "data-parent-page": page.navigation.parentId ?? void 0, children: /* @__PURE__ */ jsx7(
491
+ return /* @__PURE__ */ jsxs6("div", { className: "chapter-member-content", "data-member-content": true, children: [
492
+ /* @__PURE__ */ jsx6("nav", { className: "chapter-member-content-nav", "aria-label": "Member pages", children: sections.map(([section, pages]) => /* @__PURE__ */ jsxs6("section", { className: "chapter-member-content-section", children: [
493
+ /* @__PURE__ */ jsx6("h2", { children: section }),
494
+ /* @__PURE__ */ jsx6("ul", { children: pages.map((page) => /* @__PURE__ */ jsx6("li", { "data-parent-page": page.navigation.parentId ?? void 0, children: /* @__PURE__ */ jsx6(
582
495
  "button",
583
496
  {
584
497
  type: "button",
@@ -588,23 +501,23 @@ function MemberContentArea(props) {
588
501
  }
589
502
  ) }, page.id)) })
590
503
  ] }, section)) }),
591
- /* @__PURE__ */ jsxs7("article", { className: "chapter-member-content-page", "data-access": selected.access, children: [
592
- /* @__PURE__ */ jsxs7("header", { children: [
593
- /* @__PURE__ */ jsxs7("div", { className: "card-label", children: [
504
+ /* @__PURE__ */ jsxs6("article", { className: "chapter-member-content-page", "data-access": selected.access, children: [
505
+ /* @__PURE__ */ jsxs6("header", { children: [
506
+ /* @__PURE__ */ jsxs6("div", { className: "card-label", children: [
594
507
  selected.source.type === "parent" ? "Parent" : "Chapter",
595
508
  " \xB7 ",
596
509
  selected.access
597
510
  ] }),
598
- /* @__PURE__ */ jsx7("h1", { children: selected.title }),
599
- selected.summary ? /* @__PURE__ */ jsx7("p", { children: selected.summary }) : null
511
+ /* @__PURE__ */ jsx6("h1", { children: selected.title }),
512
+ selected.summary ? /* @__PURE__ */ jsx6("p", { children: selected.summary }) : null
600
513
  ] }),
601
- selected.access === "allowed" && selected.bodyMarkdown ? /* @__PURE__ */ jsx7(Markdown, { source: selected.bodyMarkdown }) : /* @__PURE__ */ jsxs7("div", { className: "chapter-member-content-locked", children: [
602
- selected.teaserMarkdown ? /* @__PURE__ */ jsx7(Markdown, { source: selected.teaserMarkdown }) : /* @__PURE__ */ jsx7("p", { children: "This page is not included in your current membership." }),
603
- selected.upsell ? /* @__PURE__ */ jsxs7("aside", { className: "chapter-member-content-upsell", "aria-label": selected.upsell.label ?? "Membership option", children: [
604
- /* @__PURE__ */ jsx7("h2", { children: selected.upsell.label ?? selected.upsell.tierName }),
605
- /* @__PURE__ */ jsx7("p", { children: fmtMoney(selected.upsell.priceCents) }),
606
- selected.upsell.bodyMarkdown ? /* @__PURE__ */ jsx7(Markdown, { source: selected.upsell.bodyMarkdown }) : null,
607
- href ? /* @__PURE__ */ jsx7("a", { className: "btn primary", href, children: selected.upsell.ctaLabel ?? `Explore ${selected.upsell.tierName}` }) : onUpsell ? /* @__PURE__ */ jsx7("button", { className: "btn primary", type: "button", onClick: () => onUpsell(selected.upsell.tierId, selected), children: selected.upsell.ctaLabel ?? `Explore ${selected.upsell.tierName}` }) : null
514
+ selected.access === "allowed" && selected.bodyMarkdown ? /* @__PURE__ */ jsx6(Markdown, { source: selected.bodyMarkdown }) : /* @__PURE__ */ jsxs6("div", { className: "chapter-member-content-locked", children: [
515
+ selected.teaserMarkdown ? /* @__PURE__ */ jsx6(Markdown, { source: selected.teaserMarkdown }) : /* @__PURE__ */ jsx6("p", { children: "This page is not included in your current membership." }),
516
+ selected.upsell ? /* @__PURE__ */ jsxs6("aside", { className: "chapter-member-content-upsell", "aria-label": selected.upsell.label ?? "Membership option", children: [
517
+ /* @__PURE__ */ jsx6("h2", { children: selected.upsell.label ?? selected.upsell.tierName }),
518
+ /* @__PURE__ */ jsx6("p", { children: fmtMoney(selected.upsell.priceCents) }),
519
+ selected.upsell.bodyMarkdown ? /* @__PURE__ */ jsx6(Markdown, { source: selected.upsell.bodyMarkdown }) : null,
520
+ href ? /* @__PURE__ */ jsx6("a", { className: "btn primary", href, children: selected.upsell.ctaLabel ?? `Explore ${selected.upsell.tierName}` }) : onUpsell ? /* @__PURE__ */ jsx6("button", { className: "btn primary", type: "button", onClick: () => onUpsell(selected.upsell.tierId, selected), children: selected.upsell.ctaLabel ?? `Explore ${selected.upsell.tierName}` }) : null
608
521
  ] }) : null
609
522
  ] })
610
523
  ] })
@@ -612,12 +525,12 @@ function MemberContentArea(props) {
612
525
  }
613
526
 
614
527
  // src/ui/members.tsx
615
- import { Fragment as Fragment4, jsx as jsx8, jsxs as jsxs8 } from "preact/jsx-runtime";
528
+ import { Fragment as Fragment3, jsx as jsx7, jsxs as jsxs7 } from "preact/jsx-runtime";
616
529
  function card(copy, kicker, body) {
617
- return /* @__PURE__ */ jsxs8("div", { className: "card", children: [
618
- /* @__PURE__ */ jsx8("div", { className: "card-label", children: copy.provisional.cardLabel }),
619
- /* @__PURE__ */ jsxs8("div", { className: "meeting-block", children: [
620
- /* @__PURE__ */ jsx8("div", { className: "meeting-kicker", children: kicker }),
530
+ return /* @__PURE__ */ jsxs7("div", { className: "card", children: [
531
+ /* @__PURE__ */ jsx7("div", { className: "card-label", children: copy.provisional.cardLabel }),
532
+ /* @__PURE__ */ jsxs7("div", { className: "meeting-block", children: [
533
+ /* @__PURE__ */ jsx7("div", { className: "meeting-kicker", children: kicker }),
621
534
  body
622
535
  ] })
623
536
  ] });
@@ -628,9 +541,9 @@ function ProvisionalCard(props) {
628
541
  return card(
629
542
  copy,
630
543
  copy.provisional.applicationNeeded,
631
- /* @__PURE__ */ jsxs8(Fragment4, { children: [
632
- /* @__PURE__ */ jsx8("div", { className: "meeting-note", children: copy.provisional.applicationNeededBody }),
633
- /* @__PURE__ */ jsx8("a", { className: "apply-link", href: applyHref, children: copy.provisional.apply })
544
+ /* @__PURE__ */ jsxs7(Fragment3, { children: [
545
+ /* @__PURE__ */ jsx7("div", { className: "meeting-note", children: copy.provisional.applicationNeededBody }),
546
+ /* @__PURE__ */ jsx7("a", { className: "apply-link", href: applyHref, children: copy.provisional.apply })
634
547
  ] })
635
548
  );
636
549
  }
@@ -638,19 +551,19 @@ function ProvisionalCard(props) {
638
551
  return card(
639
552
  copy,
640
553
  copy.provisional.refunded,
641
- /* @__PURE__ */ jsx8("div", { className: "meeting-note", children: copy.provisional.refundedBody })
554
+ /* @__PURE__ */ jsx7("div", { className: "meeting-note", children: copy.provisional.refundedBody })
642
555
  );
643
556
  }
644
- const membership = application.paid ? /* @__PURE__ */ jsx8("div", { className: "meeting-note", children: application.renewalAt ? formatChapterCopy(copy.provisional.renews, { date: fmtDate(application.renewalAt) }) : copy.provisional.active }) : null;
557
+ const membership = application.paid ? /* @__PURE__ */ jsx7("div", { className: "meeting-note", children: application.renewalAt ? formatChapterCopy(copy.provisional.renews, { date: fmtDate(application.renewalAt) }) : copy.provisional.active }) : null;
645
558
  if (application.meetingAt) {
646
559
  return card(
647
560
  copy,
648
561
  copy.provisional.introductionCall,
649
- /* @__PURE__ */ jsxs8(Fragment4, { children: [
650
- /* @__PURE__ */ jsx8("div", { className: "meeting-date", children: fullLabel(application.meetingAt, application.timezone) }),
651
- /* @__PURE__ */ jsx8("div", { className: "meeting-note", children: copy.provisional.calendarInvite }),
652
- application.meetUrl ? /* @__PURE__ */ jsx8("div", { className: "meeting-note", children: /* @__PURE__ */ jsx8("a", { href: application.meetUrl, target: "_blank", rel: "noopener", children: copy.provisional.joinCall }) }) : null,
653
- /* @__PURE__ */ jsx8(
562
+ /* @__PURE__ */ jsxs7(Fragment3, { children: [
563
+ /* @__PURE__ */ jsx7("div", { className: "meeting-date", children: fullLabel(application.meetingAt, application.timezone) }),
564
+ /* @__PURE__ */ jsx7("div", { className: "meeting-note", children: copy.provisional.calendarInvite }),
565
+ application.meetUrl ? /* @__PURE__ */ jsx7("div", { className: "meeting-note", children: /* @__PURE__ */ jsx7("a", { href: application.meetUrl, target: "_blank", rel: "noopener", children: copy.provisional.joinCall }) }) : null,
566
+ /* @__PURE__ */ jsx7(
654
567
  Rescheduler,
655
568
  {
656
569
  api,
@@ -667,9 +580,9 @@ function ProvisionalCard(props) {
667
580
  return card(
668
581
  copy,
669
582
  copy.provisional.bookCall,
670
- /* @__PURE__ */ jsxs8(Fragment4, { children: [
671
- /* @__PURE__ */ jsx8("div", { className: "meeting-note", children: copy.provisional.bookCallBody }),
672
- /* @__PURE__ */ jsx8(
583
+ /* @__PURE__ */ jsxs7(Fragment3, { children: [
584
+ /* @__PURE__ */ jsx7("div", { className: "meeting-note", children: copy.provisional.bookCallBody }),
585
+ /* @__PURE__ */ jsx7(
673
586
  Rescheduler,
674
587
  {
675
588
  api,
@@ -696,8 +609,8 @@ function MembersArea(props) {
696
609
  renderProvisional
697
610
  } = props;
698
611
  const copy = props.copy ?? inheritedCopy.members;
699
- const [me, setMe] = useState7(null);
700
- const [error, setError] = useState7(false);
612
+ const [me, setMe] = useState6(null);
613
+ const [error, setError] = useState6(false);
701
614
  const reload = async () => {
702
615
  try {
703
616
  setMe(await api("/api/me"));
@@ -708,22 +621,22 @@ function MembersArea(props) {
708
621
  useEffect3(() => {
709
622
  void reload();
710
623
  }, []);
711
- if (error) return /* @__PURE__ */ jsx8("p", { className: "meeting-note", children: copy.loadFailed });
712
- if (!me) return /* @__PURE__ */ jsx8("p", { className: "meeting-note", children: inheritedCopy.common.loading });
624
+ if (error) return /* @__PURE__ */ jsx7("p", { className: "meeting-note", children: copy.loadFailed });
625
+ if (!me) return /* @__PURE__ */ jsx7("p", { className: "meeting-note", children: inheritedCopy.common.loading });
713
626
  const role = me.role || "provisional";
714
- return /* @__PURE__ */ jsxs8(Fragment4, { children: [
715
- /* @__PURE__ */ jsxs8("div", { className: "card", children: [
716
- /* @__PURE__ */ jsxs8("div", { className: "member-row", children: [
717
- /* @__PURE__ */ jsx8("span", { className: "member-email", children: me.email }),
718
- /* @__PURE__ */ jsx8("span", { className: "role-badge " + role, children: role })
627
+ return /* @__PURE__ */ jsxs7(Fragment3, { children: [
628
+ /* @__PURE__ */ jsxs7("div", { className: "card", children: [
629
+ /* @__PURE__ */ jsxs7("div", { className: "member-row", children: [
630
+ /* @__PURE__ */ jsx7("span", { className: "member-email", children: me.email }),
631
+ /* @__PURE__ */ jsx7("span", { className: "role-badge " + role, children: role })
719
632
  ] }),
720
- /* @__PURE__ */ jsxs8("div", { className: "account-actions", children: [
721
- /* @__PURE__ */ jsx8("button", { className: "btn secondary mini", onClick: signOut, children: copy.account.signOut }),
722
- role === "admin" ? /* @__PURE__ */ jsx8("a", { className: "admin-console-link", href: adminHref, children: copy.account.adminConsole }) : null
633
+ /* @__PURE__ */ jsxs7("div", { className: "account-actions", children: [
634
+ /* @__PURE__ */ jsx7("button", { className: "btn secondary mini", onClick: signOut, children: copy.account.signOut }),
635
+ role === "admin" ? /* @__PURE__ */ jsx7("a", { className: "admin-console-link", href: adminHref, children: copy.account.adminConsole }) : null
723
636
  ] })
724
637
  ] }),
725
638
  role === "provisional" ? (() => {
726
- const defaultContent = /* @__PURE__ */ jsx8(
639
+ const defaultContent = /* @__PURE__ */ jsx7(
727
640
  ProvisionalCard,
728
641
  {
729
642
  api,
@@ -740,14 +653,14 @@ function MembersArea(props) {
740
653
  reload,
741
654
  defaultContent
742
655
  }) ?? defaultContent;
743
- })() : memberContent ?? (memberPages ? /* @__PURE__ */ jsx8(
656
+ })() : memberContent ?? (memberPages ? /* @__PURE__ */ jsx7(
744
657
  MemberContentArea,
745
658
  {
746
659
  api,
747
660
  ...memberPages === true ? {} : memberPages
748
661
  }
749
- ) : /* @__PURE__ */ jsx8("div", { className: "card", children: /* @__PURE__ */ jsx8("div", { className: "card-label", children: copy.full.welcome }) })),
750
- /* @__PURE__ */ jsx8(MemberGifts, { api, copy: copy.gifts, paymentCopy: inheritedCopy.join.payment })
662
+ ) : /* @__PURE__ */ jsx7("div", { className: "card", children: /* @__PURE__ */ jsx7("div", { className: "card-label", children: copy.full.welcome }) })),
663
+ /* @__PURE__ */ jsx7(GiftPurchases, { api, copy: copy.gifts, paymentCopy: inheritedCopy.join.payment })
751
664
  ] });
752
665
  }
753
666
 
@@ -755,14 +668,14 @@ function MembersArea(props) {
755
668
  import { useEffect as useEffect5, useRef as useRef3, useState as useState11 } from "preact/hooks";
756
669
 
757
670
  // src/ui/join-booking.tsx
758
- import { useEffect as useEffect4, useState as useState8 } from "preact/hooks";
759
- import { jsx as jsx9, jsxs as jsxs9 } from "preact/jsx-runtime";
671
+ import { useEffect as useEffect4, useState as useState7 } from "preact/hooks";
672
+ import { jsx as jsx8, jsxs as jsxs8 } from "preact/jsx-runtime";
760
673
  function JoinBooking(props) {
761
674
  const { applicationId, copy, onBooked, simulation } = props;
762
- const [state, setState] = useState8(null);
763
- const [msg, setMsg] = useState8(null);
764
- const [busy, setBusy] = useState8(false);
765
- const [selected, setSelected] = useState8(null);
675
+ const [state, setState] = useState7(null);
676
+ const [msg, setMsg] = useState7(null);
677
+ const [busy, setBusy] = useState7(false);
678
+ const [selected, setSelected] = useState7(null);
766
679
  const load = async () => {
767
680
  setMsg(null);
768
681
  try {
@@ -819,9 +732,9 @@ function JoinBooking(props) {
819
732
  setBusy(false);
820
733
  }
821
734
  };
822
- if (!state) return /* @__PURE__ */ jsx9("p", { className: "slots-status", children: msg ?? copy.loading });
823
- return /* @__PURE__ */ jsxs9("div", { className: "join-book", children: [
824
- /* @__PURE__ */ jsx9(
735
+ if (!state) return /* @__PURE__ */ jsx8("p", { className: "slots-status", children: msg ?? copy.loading });
736
+ return /* @__PURE__ */ jsxs8("div", { className: "join-book", children: [
737
+ /* @__PURE__ */ jsx8(
825
738
  SlotPicker,
826
739
  {
827
740
  slots: state.slots,
@@ -831,29 +744,29 @@ function JoinBooking(props) {
831
744
  onDayChange: () => setSelected(null)
832
745
  }
833
746
  ),
834
- /* @__PURE__ */ jsxs9("div", { className: "slot-confirm", hidden: !selected, children: [
835
- /* @__PURE__ */ jsx9("button", { className: "submit-btn", disabled: busy, onClick: () => void book(), children: busy ? copy.booking : copy.book }),
836
- msg ? /* @__PURE__ */ jsx9("p", { className: "step2-note", children: msg }) : null
747
+ /* @__PURE__ */ jsxs8("div", { className: "slot-confirm", hidden: !selected, children: [
748
+ /* @__PURE__ */ jsx8("button", { className: "submit-btn", disabled: busy, onClick: () => void book(), children: busy ? copy.booking : copy.book }),
749
+ msg ? /* @__PURE__ */ jsx8("p", { className: "step2-note", children: msg }) : null
837
750
  ] })
838
751
  ] });
839
752
  }
840
753
 
841
754
  // src/ui/join-accepted.tsx
842
- import { jsx as jsx10, jsxs as jsxs10 } from "preact/jsx-runtime";
755
+ import { jsx as jsx9, jsxs as jsxs9 } from "preact/jsx-runtime";
843
756
  function JoinAccepted(props) {
844
- return /* @__PURE__ */ jsxs10("div", { className: "join-done card", children: [
845
- /* @__PURE__ */ jsx10("div", { className: "card-label", children: props.copy.accepted.label }),
846
- /* @__PURE__ */ jsx10("p", { className: "meeting-note", children: props.copy.accepted.body }),
847
- /* @__PURE__ */ jsx10("a", { className: "apply-link", href: props.membersHref, children: props.copy.done.memberArea })
757
+ return /* @__PURE__ */ jsxs9("div", { className: "join-done card", children: [
758
+ /* @__PURE__ */ jsx9("div", { className: "card-label", children: props.copy.accepted.label }),
759
+ /* @__PURE__ */ jsx9("p", { className: "meeting-note", children: props.copy.accepted.body }),
760
+ /* @__PURE__ */ jsx9("a", { className: "apply-link", href: props.membersHref, children: props.copy.done.memberArea })
848
761
  ] });
849
762
  }
850
763
 
851
764
  // src/ui/gift-claim-card.tsx
852
- import { useState as useState9 } from "preact/hooks";
853
- import { Fragment as Fragment5, jsx as jsx11, jsxs as jsxs11 } from "preact/jsx-runtime";
765
+ import { useState as useState8 } from "preact/hooks";
766
+ import { Fragment as Fragment4, jsx as jsx10, jsxs as jsxs10 } from "preact/jsx-runtime";
854
767
  function GiftClaimCard(props) {
855
- const [code, setCode] = useState9(props.initialCode ?? "");
856
- const [error, setError] = useState9(false);
768
+ const [code, setCode] = useState8(props.initialCode ?? "");
769
+ const [error, setError] = useState8(false);
857
770
  const rotate = async () => {
858
771
  if (!props.claimId) return;
859
772
  setError(false);
@@ -866,21 +779,166 @@ function GiftClaimCard(props) {
866
779
  if (response.ok && body.code) setCode(body.code);
867
780
  else setError(true);
868
781
  };
869
- return /* @__PURE__ */ jsxs11("div", { className: "join-done card", children: [
870
- /* @__PURE__ */ jsx11("div", { className: "card-label", children: props.copy.label }),
871
- /* @__PURE__ */ jsx11("p", { className: "meeting-note", children: props.copy.body }),
872
- code ? /* @__PURE__ */ jsxs11(Fragment5, { children: [
873
- /* @__PURE__ */ jsx11("output", { className: "gift-code", children: code }),
874
- /* @__PURE__ */ jsx11("p", { children: props.copy.save })
782
+ return /* @__PURE__ */ jsxs10("div", { className: "join-done card", children: [
783
+ /* @__PURE__ */ jsx10("div", { className: "card-label", children: props.copy.label }),
784
+ /* @__PURE__ */ jsx10("p", { className: "meeting-note", children: props.copy.body }),
785
+ code ? /* @__PURE__ */ jsxs10(Fragment4, { children: [
786
+ /* @__PURE__ */ jsx10("output", { className: "gift-code", children: code }),
787
+ /* @__PURE__ */ jsx10("p", { children: props.copy.save })
875
788
  ] }) : null,
876
- !code && props.claimId ? /* @__PURE__ */ jsx11("button", { type: "button", className: "btn secondary", onClick: () => void rotate(), children: props.copy.rotate }) : null,
877
- error ? /* @__PURE__ */ jsx11("p", { role: "alert", children: props.copy.rotateFailed }) : null
789
+ !code && props.claimId ? /* @__PURE__ */ jsx10("button", { type: "button", className: "btn secondary", onClick: () => void rotate(), children: props.copy.rotate }) : null,
790
+ error ? /* @__PURE__ */ jsx10("p", { role: "alert", children: props.copy.rotateFailed }) : null
791
+ ] });
792
+ }
793
+
794
+ // src/ui/join-application-response.ts
795
+ function joinStateFromApplicationResponse(data, fallbackNeedsPayment, submittedGiftPurchase) {
796
+ if (!data.id) return null;
797
+ if (data.state === "accepted") return { step: "accepted", applicationId: data.id };
798
+ if (data.state === "paymentPending") return { step: "paymentPending", applicationId: data.id };
799
+ if (data.state === "booking") return { step: "booking", applicationId: data.id };
800
+ if (data.state === "payment") return {
801
+ step: "payment",
802
+ applicationId: data.id,
803
+ ...data.giftPurchase || submittedGiftPurchase ? { giftPurchase: true } : {}
804
+ };
805
+ return fallbackNeedsPayment ? { step: "payment", applicationId: data.id, ...submittedGiftPurchase ? { giftPurchase: true } : {} } : { step: "booking", applicationId: data.id };
806
+ }
807
+
808
+ // src/ui/gift-code-redeemer.tsx
809
+ import { InlineActionField } from "@odla-ai/ui/components";
810
+ import { useState as useState9 } from "preact/hooks";
811
+ import { Fragment as Fragment5, jsx as jsx11, jsxs as jsxs11 } from "preact/jsx-runtime";
812
+ var GIFT_CODE_REDEEMER_CSS = `
813
+ .gift-code-redeemer{container-type:inline-size;display:grid;gap:var(--ui-space-1,.35rem);margin:0}
814
+ .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}
815
+ .gift-code-redeemer .inline-action-field-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:var(--ui-space-2,.65rem);align-items:stretch}
816
+ .gift-code-redeemer .inline-action-field-input,.gift-code-redeemer .inline-action-field-action{min-height:var(--ui-inline-action-control-height,38px)}
817
+ .gift-code-redeemer .inline-action-field-input.code{font-family:var(--ui-font-mono,ui-monospace,monospace);font-variant-ligatures:none;letter-spacing:var(--ui-tracking-wide,.04em)}
818
+ .gift-code-redeemer .inline-action-field-input:focus-visible{outline:none;border-color:var(--ui-accent,#168c84);box-shadow:var(--ui-focus,0 0 0 3px rgb(22 140 132 / .18))}
819
+ .gift-code-redeemer .inline-action-field-action{white-space:nowrap}
820
+ .gift-code-redeemer .inline-action-field-status{display:block;min-block-size:1.4em;margin:0;color:var(--ui-text-muted,#66777f);font-size:var(--ui-text-sm,.8rem);line-height:1.4}
821
+ .gift-code-redeemer .inline-action-field-status.success{color:var(--ui-good,#1f7a52)}
822
+ .gift-code-redeemer .inline-action-field-status.error{color:var(--ui-danger,#b42318)}
823
+ @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%}}
824
+ `;
825
+ function GiftCodeRedeemer({ api, applicationId, copy, id, onRedeemed }) {
826
+ const [code, setCode] = useState9("");
827
+ const [loading, setLoading] = useState9(false);
828
+ const [message, setMessage] = useState9("");
829
+ const [messageTone, setMessageTone] = useState9("neutral");
830
+ const normalizedCode = code.trim();
831
+ const redeem = async () => {
832
+ if (!normalizedCode || loading) return;
833
+ setLoading(true);
834
+ setMessage("");
835
+ setMessageTone("neutral");
836
+ try {
837
+ const result = await api("/api/gifts/redeem", {
838
+ method: "POST",
839
+ headers: { "content-type": "application/json" },
840
+ body: JSON.stringify({ code: normalizedCode, applicationId })
841
+ });
842
+ setCode("");
843
+ setMessage(copy.redeemed);
844
+ setMessageTone("success");
845
+ try {
846
+ await onRedeemed?.(result);
847
+ } catch {
848
+ }
849
+ } catch {
850
+ setMessage(copy.redeemFailed);
851
+ setMessageTone("error");
852
+ } finally {
853
+ setLoading(false);
854
+ }
855
+ };
856
+ return /* @__PURE__ */ jsxs11(Fragment5, { children: [
857
+ /* @__PURE__ */ jsx11("style", { children: GIFT_CODE_REDEEMER_CSS }),
858
+ /* @__PURE__ */ jsx11(
859
+ InlineActionField,
860
+ {
861
+ id,
862
+ className: "gift-code-redeemer",
863
+ label: copy.code,
864
+ value: code,
865
+ code: true,
866
+ actionLabel: copy.redeem,
867
+ loadingLabel: `${copy.redeem}\u2026`,
868
+ loading,
869
+ actionDisabled: !normalizedCode,
870
+ message,
871
+ messageTone,
872
+ inputProps: {
873
+ name: "giftCode",
874
+ maxLength: 64,
875
+ autoComplete: "one-time-code",
876
+ autoCapitalize: "none",
877
+ autocorrect: "off",
878
+ spellcheck: false
879
+ },
880
+ onValueChange: (value) => {
881
+ setCode(value);
882
+ if (message) {
883
+ setMessage("");
884
+ setMessageTone("neutral");
885
+ }
886
+ },
887
+ onAction: () => void redeem()
888
+ }
889
+ )
890
+ ] });
891
+ }
892
+
893
+ // src/ui/join-resume.ts
894
+ async function loadJoinResume(applicationId, fetcher = fetch) {
895
+ const res = await fetcher(`/api/join/resume?application=${encodeURIComponent(applicationId)}`);
896
+ const data = await res.json();
897
+ if (!res.ok) throw new Error(data.error ?? "The application could not be resumed.");
898
+ if (data.state === "done" && data.booked) return { step: "done", applicationId: data.applicationId, booked: data.booked };
899
+ if (data.state === "paymentPending") return { step: "paymentPending", applicationId: data.applicationId };
900
+ if (data.state === "booking") return { step: "booking", applicationId: data.applicationId };
901
+ if (data.state === "accepted") return { step: "accepted", applicationId: data.applicationId };
902
+ if (data.state === "gift") return { step: "gift", applicationId: data.applicationId, ...data.claimId ? { claimId: data.claimId } : {} };
903
+ return {
904
+ step: "payment",
905
+ applicationId: data.applicationId,
906
+ ...data.giftPurchase ? { giftPurchase: true } : {}
907
+ };
908
+ }
909
+
910
+ // src/ui/join-gift-claim.tsx
911
+ import { jsx as jsx12, jsxs as jsxs12 } from "preact/jsx-runtime";
912
+ function JoinGiftClaim(props) {
913
+ return /* @__PURE__ */ jsxs12("section", { className: "join-gift-claim card", children: [
914
+ /* @__PURE__ */ jsx12("div", { className: "card-label", children: props.copy.claimTitle }),
915
+ /* @__PURE__ */ jsx12("p", { children: props.copy.claimBody }),
916
+ /* @__PURE__ */ jsx12(
917
+ GiftCodeRedeemer,
918
+ {
919
+ api: props.api,
920
+ applicationId: props.applicationId,
921
+ copy: props.copy,
922
+ onRedeemed: async (result) => {
923
+ if (result.state === "booking" || result.state === "accepted") {
924
+ props.onState({ step: result.state, applicationId: result.applicationId });
925
+ return;
926
+ }
927
+ try {
928
+ const resumed = props.loadResume ? await props.loadResume() : await loadJoinResume(result.applicationId);
929
+ if (resumed) props.onState(resumed);
930
+ } catch {
931
+ props.onError();
932
+ }
933
+ }
934
+ }
935
+ )
878
936
  ] });
879
937
  }
880
938
 
881
939
  // src/ui/join-tiers.tsx
882
940
  import { useState as useState10 } from "preact/hooks";
883
- import { jsx as jsx12, jsxs as jsxs12 } from "preact/jsx-runtime";
941
+ import { jsx as jsx13, jsxs as jsxs13 } from "preact/jsx-runtime";
884
942
  function useTierSelection(tiers, initialTierId) {
885
943
  const [selectedTierId, setSelectedTierId] = useState10(() => {
886
944
  const preset = tiers.find((tier) => tier.id === initialTierId);
@@ -897,10 +955,10 @@ function useTierSelection(tiers, initialTierId) {
897
955
  };
898
956
  }
899
957
  function TierPlaceholder(context) {
900
- return /* @__PURE__ */ jsxs12("fieldset", { "data-chapter-placeholder": "tiers", children: [
901
- /* @__PURE__ */ jsx12("legend", { children: "Membership (placeholder \u2014 pass renderTiers to style this)" }),
902
- context.tiers.map((tier) => /* @__PURE__ */ jsxs12("label", { children: [
903
- /* @__PURE__ */ jsx12(
958
+ return /* @__PURE__ */ jsxs13("fieldset", { "data-chapter-placeholder": "tiers", children: [
959
+ /* @__PURE__ */ jsx13("legend", { children: "Membership (placeholder \u2014 pass renderTiers to style this)" }),
960
+ context.tiers.map((tier) => /* @__PURE__ */ jsxs13("label", { children: [
961
+ /* @__PURE__ */ jsx13(
904
962
  "input",
905
963
  {
906
964
  type: "radio",
@@ -918,21 +976,8 @@ function tierNeedsPayment(selected, paymentsReady) {
918
976
  return selected ? !selected.free && paymentsReady : paymentsReady;
919
977
  }
920
978
 
921
- // src/ui/join-resume.ts
922
- async function loadJoinResume(applicationId, fetcher = fetch) {
923
- const res = await fetcher(`/api/join/resume?application=${encodeURIComponent(applicationId)}`);
924
- const data = await res.json();
925
- if (!res.ok) throw new Error(data.error ?? "The application could not be resumed.");
926
- if (data.state === "done" && data.booked) return { step: "done", applicationId: data.applicationId, booked: data.booked };
927
- if (data.state === "paymentPending") return { step: "paymentPending", applicationId: data.applicationId };
928
- if (data.state === "booking") return { step: "booking", applicationId: data.applicationId };
929
- if (data.state === "accepted") return { step: "accepted", applicationId: data.applicationId };
930
- if (data.state === "gift") return { step: "gift", applicationId: data.applicationId, ...data.claimId ? { claimId: data.claimId } : {} };
931
- return { step: "payment", applicationId: data.applicationId };
932
- }
933
-
934
979
  // src/ui/join.tsx
935
- import { Fragment as Fragment6, jsx as jsx13, jsxs as jsxs13 } from "preact/jsx-runtime";
980
+ import { Fragment as Fragment6, jsx as jsx14, jsxs as jsxs14 } from "preact/jsx-runtime";
936
981
  function JoinIsland(props) {
937
982
  const inheritedCopy = useChapterCopy();
938
983
  const {
@@ -1025,22 +1070,11 @@ function JoinIsland(props) {
1025
1070
  });
1026
1071
  const data = await res.json();
1027
1072
  if (!res.ok || !data.id) throw new Error(data.error ?? copy.form.submitFailed);
1028
- if (data.state === "accepted") {
1029
- setState({ step: "accepted", applicationId: data.id });
1030
- return;
1031
- }
1032
- if (data.state === "paymentPending") {
1033
- setState({ step: "paymentPending", applicationId: data.id });
1034
- return;
1035
- }
1036
- if (data.state === "payment" || data.state === "booking") {
1037
- setState({ step: data.state, applicationId: data.id });
1038
- return;
1039
- }
1040
- setState({
1041
- step: tierNeedsPayment(selectedTier, config.paymentsReady) ? "payment" : "booking",
1042
- applicationId: data.id
1043
- });
1073
+ setState(joinStateFromApplicationResponse(
1074
+ data,
1075
+ tierNeedsPayment(selectedTier, config.paymentsReady),
1076
+ Boolean(giftOfferId)
1077
+ ));
1044
1078
  } catch (err) {
1045
1079
  setError(err instanceof Error ? err.message : copy.form.unexpectedFailure);
1046
1080
  } finally {
@@ -1052,35 +1086,35 @@ function JoinIsland(props) {
1052
1086
  ..."applicationId" in state ? { applicationId: state.applicationId } : {}
1053
1087
  });
1054
1088
  if (state.step === "done") {
1055
- const body = renderDone?.({ ...state, membersHref }) ?? /* @__PURE__ */ jsxs13("div", { className: "join-done card", children: [
1056
- /* @__PURE__ */ jsx13("div", { className: "card-label", children: copy.done.label }),
1057
- /* @__PURE__ */ jsx13("p", { className: "meeting-date", children: fullLabel(state.booked.startAt, state.booked.timezone) }),
1058
- /* @__PURE__ */ jsx13("p", { className: "meeting-note", children: copy.done.calendarInvite }),
1059
- /* @__PURE__ */ jsx13("a", { className: "apply-link", href: membersHref, children: copy.done.memberArea })
1089
+ const body = renderDone?.({ ...state, membersHref }) ?? /* @__PURE__ */ jsxs14("div", { className: "join-done card", children: [
1090
+ /* @__PURE__ */ jsx14("div", { className: "card-label", children: copy.done.label }),
1091
+ /* @__PURE__ */ jsx14("p", { className: "meeting-date", children: fullLabel(state.booked.startAt, state.booked.timezone) }),
1092
+ /* @__PURE__ */ jsx14("p", { className: "meeting-note", children: copy.done.calendarInvite }),
1093
+ /* @__PURE__ */ jsx14("a", { className: "apply-link", href: membersHref, children: copy.done.memberArea })
1060
1094
  ] });
1061
- return /* @__PURE__ */ jsxs13(Fragment6, { children: [
1095
+ return /* @__PURE__ */ jsxs14(Fragment6, { children: [
1062
1096
  header,
1063
1097
  body
1064
1098
  ] });
1065
1099
  }
1066
1100
  if (state.step === "accepted") {
1067
- const body = renderAccepted?.({ ...state, membersHref }) ?? /* @__PURE__ */ jsx13(JoinAccepted, { copy, membersHref });
1068
- return /* @__PURE__ */ jsxs13(Fragment6, { children: [
1101
+ const body = renderAccepted?.({ ...state, membersHref }) ?? /* @__PURE__ */ jsx14(JoinAccepted, { copy, membersHref });
1102
+ return /* @__PURE__ */ jsxs14(Fragment6, { children: [
1069
1103
  header,
1070
1104
  body
1071
1105
  ] });
1072
1106
  }
1073
1107
  if (state.step === "gift") {
1074
- const body = renderGift?.(state) ?? /* @__PURE__ */ jsx13(GiftClaimCard, { applicationId: state.applicationId, claimId: state.claimId, initialCode: state.code, copy: copy.gift });
1075
- return /* @__PURE__ */ jsxs13(Fragment6, { children: [
1108
+ const body = renderGift?.(state) ?? /* @__PURE__ */ jsx14(GiftClaimCard, { applicationId: state.applicationId, claimId: state.claimId, initialCode: state.code, copy: copy.gift });
1109
+ return /* @__PURE__ */ jsxs14(Fragment6, { children: [
1076
1110
  header,
1077
1111
  body
1078
1112
  ] });
1079
1113
  }
1080
1114
  if (state.step === "booking") {
1081
- return /* @__PURE__ */ jsxs13(Fragment6, { children: [
1115
+ return /* @__PURE__ */ jsxs14(Fragment6, { children: [
1082
1116
  header,
1083
- /* @__PURE__ */ jsx13(
1117
+ /* @__PURE__ */ jsx14(
1084
1118
  JoinBooking,
1085
1119
  {
1086
1120
  applicationId: state.applicationId,
@@ -1094,9 +1128,20 @@ function JoinIsland(props) {
1094
1128
  ] });
1095
1129
  }
1096
1130
  if (state.step === "payment") {
1097
- return /* @__PURE__ */ jsxs13(Fragment6, { children: [
1131
+ return /* @__PURE__ */ jsxs14(Fragment6, { children: [
1098
1132
  header,
1099
- /* @__PURE__ */ jsx13(
1133
+ props.giftClaimApi && !state.giftPurchase ? /* @__PURE__ */ jsx14(
1134
+ JoinGiftClaim,
1135
+ {
1136
+ api: props.giftClaimApi,
1137
+ applicationId: state.applicationId,
1138
+ copy: copy.gift,
1139
+ loadResume: props.loadResume,
1140
+ onState: setState,
1141
+ onError: () => setError(copy.form.unexpectedFailure)
1142
+ }
1143
+ ) : null,
1144
+ /* @__PURE__ */ jsx14(
1100
1145
  PaymentStep,
1101
1146
  {
1102
1147
  applicationId: state.applicationId,
@@ -1124,25 +1169,25 @@ function JoinIsland(props) {
1124
1169
  ] });
1125
1170
  }
1126
1171
  if (state.step === "paymentPending") {
1127
- return /* @__PURE__ */ jsxs13(Fragment6, { children: [
1172
+ return /* @__PURE__ */ jsxs14(Fragment6, { children: [
1128
1173
  header,
1129
- /* @__PURE__ */ jsx13("p", { className: "pay-status", role: "status", children: copy.payment.pending })
1174
+ /* @__PURE__ */ jsx14("p", { className: "pay-status", role: "status", children: copy.payment.pending })
1130
1175
  ] });
1131
1176
  }
1132
1177
  const submitDisabled = submitting || props.submitDisabled === true;
1133
1178
  const tierChooser = tiers.length > 1 ? props.renderTiers?.(tierSelection) ?? TierPlaceholder(tierSelection) : null;
1134
- return /* @__PURE__ */ jsxs13(Fragment6, { children: [
1179
+ return /* @__PURE__ */ jsxs14(Fragment6, { children: [
1135
1180
  header,
1136
- /* @__PURE__ */ jsxs13("form", { className: "join-form", onSubmit: (e) => void submit(e), children: [
1137
- (config.giftOffers?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs13("fieldset", { children: [
1138
- /* @__PURE__ */ jsx13("legend", { children: copy.gift.optionsLabel }),
1139
- /* @__PURE__ */ jsx13("button", { type: "button", className: "btn secondary", "aria-pressed": !giftOfferId, onClick: () => setGiftOfferId(null), children: copy.gift.chooseSelf }),
1140
- /* @__PURE__ */ jsx13(GiftOfferCards, { offers: config.giftOffers ?? [], mode: "select", selectedOfferId: giftOfferId, onSelect: setGiftOfferId })
1181
+ /* @__PURE__ */ jsxs14("form", { className: "join-form", onSubmit: (e) => void submit(e), children: [
1182
+ (config.giftOffers?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs14("fieldset", { children: [
1183
+ /* @__PURE__ */ jsx14("legend", { children: copy.gift.optionsLabel }),
1184
+ /* @__PURE__ */ jsx14("button", { type: "button", className: "btn secondary", "aria-pressed": !giftOfferId, onClick: () => setGiftOfferId(null), children: copy.gift.chooseSelf }),
1185
+ /* @__PURE__ */ jsx14(GiftOfferCards, { offers: config.giftOffers ?? [], mode: "select", selectedOfferId: giftOfferId, onSelect: setGiftOfferId })
1141
1186
  ] }) : null,
1142
1187
  tierChooser,
1143
1188
  children,
1144
- error ? /* @__PURE__ */ jsx13("p", { className: "join-error", children: error }) : null,
1145
- renderSubmit?.({ submitting, disabled: submitDisabled }) ?? /* @__PURE__ */ jsx13("button", { className: "submit-btn", type: "submit", disabled: submitDisabled, children: submitting ? copy.form.submitting : copy.form.submit })
1189
+ error ? /* @__PURE__ */ jsx14("p", { className: "join-error", children: error }) : null,
1190
+ renderSubmit?.({ submitting, disabled: submitDisabled }) ?? /* @__PURE__ */ jsx14("button", { className: "submit-btn", type: "submit", disabled: submitDisabled, children: submitting ? copy.form.submitting : copy.form.submit })
1146
1191
  ] })
1147
1192
  ] });
1148
1193
  }
@@ -1319,7 +1364,7 @@ function membershipPageDocument(input, options = {}) {
1319
1364
  }
1320
1365
 
1321
1366
  // src/ui/membership-cards.tsx
1322
- import { jsx as jsx14, jsxs as jsxs14 } from "preact/jsx-runtime";
1367
+ import { jsx as jsx15, jsxs as jsxs15 } from "preact/jsx-runtime";
1323
1368
  var MEMBERSHIP_CARD_TOKEN_DEFAULTS = Object.freeze({
1324
1369
  "--ui-membership-grid-gap": "1.4rem",
1325
1370
  "--ui-membership-card-padding": "2rem 1.7rem 1.8rem",
@@ -1388,67 +1433,67 @@ function membershipApplicationHref(applicationPath, tierId) {
1388
1433
  }
1389
1434
  function TierAction(props) {
1390
1435
  if (props.mode === "select") {
1391
- return /* @__PURE__ */ jsxs14("button", { type: "button", className: "chapter-membership-action", "aria-current": props.selected ? "true" : void 0, onClick: () => props.onSelectTier?.(props.tierId), children: [
1436
+ return /* @__PURE__ */ jsxs15("button", { type: "button", className: "chapter-membership-action", "aria-current": props.selected ? "true" : void 0, onClick: () => props.onSelectTier?.(props.tierId), children: [
1392
1437
  props.label,
1393
- /* @__PURE__ */ jsx14("span", { "aria-hidden": "true", children: "\u2192" })
1438
+ /* @__PURE__ */ jsx15("span", { "aria-hidden": "true", children: "\u2192" })
1394
1439
  ] });
1395
1440
  }
1396
1441
  if (props.mode === "preview") {
1397
- return /* @__PURE__ */ jsxs14("span", { className: "chapter-membership-action", "aria-disabled": "true", children: [
1442
+ return /* @__PURE__ */ jsxs15("span", { className: "chapter-membership-action", "aria-disabled": "true", children: [
1398
1443
  props.label,
1399
- /* @__PURE__ */ jsx14("span", { "aria-hidden": "true", children: "\u2192" })
1444
+ /* @__PURE__ */ jsx15("span", { "aria-hidden": "true", children: "\u2192" })
1400
1445
  ] });
1401
1446
  }
1402
- return /* @__PURE__ */ jsxs14("a", { className: "chapter-membership-action", href: membershipApplicationHref(props.applicationPath, props.tierId), children: [
1447
+ return /* @__PURE__ */ jsxs15("a", { className: "chapter-membership-action", href: membershipApplicationHref(props.applicationPath, props.tierId), children: [
1403
1448
  props.label,
1404
- /* @__PURE__ */ jsx14("span", { "aria-hidden": "true", children: "\u2192" })
1449
+ /* @__PURE__ */ jsx15("span", { "aria-hidden": "true", children: "\u2192" })
1405
1450
  ] });
1406
1451
  }
1407
1452
  function TierCard(props) {
1408
1453
  const { tier, presentation } = props;
1409
1454
  const summary = presentation.summaryMarkdown ?? tier.blurb;
1410
1455
  const action = presentation.ctaLabel ?? (tier.free ? "Join for free" : `Choose ${tier.name}`);
1411
- return /* @__PURE__ */ jsxs14("article", { className: "chapter-membership-card", "data-tier-id": tier.id, "data-variant": presentation.variant ?? "standard", children: [
1412
- presentation.badge ? /* @__PURE__ */ jsx14("div", { className: "chapter-membership-badge", children: presentation.badge }) : null,
1413
- /* @__PURE__ */ jsx14("h3", { className: "chapter-membership-name", children: tier.name }),
1414
- /* @__PURE__ */ jsxs14("div", { className: "chapter-membership-offer", "data-with-capacity": presentation.capacity ? "true" : void 0, children: [
1415
- presentation.capacity ? /* @__PURE__ */ jsxs14("div", { className: "chapter-membership-capacity", "aria-label": `${presentation.capacity.total} ${presentation.capacity.label ?? "available"}`, children: [
1416
- /* @__PURE__ */ jsx14("strong", { children: presentation.capacity.total.toLocaleString("en-US") }),
1417
- /* @__PURE__ */ jsx14("small", { children: presentation.capacity.label ?? "available" })
1456
+ return /* @__PURE__ */ jsxs15("article", { className: "chapter-membership-card", "data-tier-id": tier.id, "data-variant": presentation.variant ?? "standard", children: [
1457
+ presentation.badge ? /* @__PURE__ */ jsx15("div", { className: "chapter-membership-badge", children: presentation.badge }) : null,
1458
+ /* @__PURE__ */ jsx15("h3", { className: "chapter-membership-name", children: tier.name }),
1459
+ /* @__PURE__ */ jsxs15("div", { className: "chapter-membership-offer", "data-with-capacity": presentation.capacity ? "true" : void 0, children: [
1460
+ presentation.capacity ? /* @__PURE__ */ jsxs15("div", { className: "chapter-membership-capacity", "aria-label": `${presentation.capacity.total} ${presentation.capacity.label ?? "available"}`, children: [
1461
+ /* @__PURE__ */ jsx15("strong", { children: presentation.capacity.total.toLocaleString("en-US") }),
1462
+ /* @__PURE__ */ jsx15("small", { children: presentation.capacity.label ?? "available" })
1418
1463
  ] }) : null,
1419
- /* @__PURE__ */ jsxs14("div", { className: "chapter-membership-price-stack", children: [
1420
- presentation.priceEyebrow ? /* @__PURE__ */ jsx14("p", { className: "chapter-membership-price-eyebrow", children: presentation.priceEyebrow }) : null,
1421
- /* @__PURE__ */ jsxs14("div", { className: "chapter-membership-price-row", children: [
1422
- presentation.compareAtPriceCents !== void 0 ? /* @__PURE__ */ jsx14("span", { className: "chapter-membership-compare", children: fmtMoney(presentation.compareAtPriceCents) }) : null,
1423
- /* @__PURE__ */ jsx14("span", { className: "chapter-membership-price", children: tier.free ? "Free" : fmtMoney(tier.priceCents) }),
1424
- !tier.free && presentation.billingLabel ? /* @__PURE__ */ jsx14("span", { className: "chapter-membership-billing", children: presentation.billingLabel }) : null
1464
+ /* @__PURE__ */ jsxs15("div", { className: "chapter-membership-price-stack", children: [
1465
+ presentation.priceEyebrow ? /* @__PURE__ */ jsx15("p", { className: "chapter-membership-price-eyebrow", children: presentation.priceEyebrow }) : null,
1466
+ /* @__PURE__ */ jsxs15("div", { className: "chapter-membership-price-row", children: [
1467
+ presentation.compareAtPriceCents !== void 0 ? /* @__PURE__ */ jsx15("span", { className: "chapter-membership-compare", children: fmtMoney(presentation.compareAtPriceCents) }) : null,
1468
+ /* @__PURE__ */ jsx15("span", { className: "chapter-membership-price", children: tier.free ? "Free" : fmtMoney(tier.priceCents) }),
1469
+ !tier.free && presentation.billingLabel ? /* @__PURE__ */ jsx15("span", { className: "chapter-membership-billing", children: presentation.billingLabel }) : null
1425
1470
  ] })
1426
1471
  ] })
1427
1472
  ] }),
1428
- presentation.priceNoteMarkdown ? /* @__PURE__ */ jsx14(Markdown2, { className: "chapter-membership-price-note", source: presentation.priceNoteMarkdown }) : null,
1429
- summary ? /* @__PURE__ */ jsx14(Markdown2, { className: "chapter-membership-summary", source: summary }) : null,
1430
- presentation.benefits?.length ? /* @__PURE__ */ jsx14("ul", { className: "chapter-membership-benefits", children: presentation.benefits.map((benefit, index) => /* @__PURE__ */ jsxs14("li", { children: [
1431
- /* @__PURE__ */ jsx14("span", { className: "chapter-membership-check", "aria-hidden": "true", children: "\u2713" }),
1432
- /* @__PURE__ */ jsx14(Markdown2, { className: "chapter-membership-benefit", source: benefit })
1473
+ presentation.priceNoteMarkdown ? /* @__PURE__ */ jsx15(Markdown2, { className: "chapter-membership-price-note", source: presentation.priceNoteMarkdown }) : null,
1474
+ summary ? /* @__PURE__ */ jsx15(Markdown2, { className: "chapter-membership-summary", source: summary }) : null,
1475
+ presentation.benefits?.length ? /* @__PURE__ */ jsx15("ul", { className: "chapter-membership-benefits", children: presentation.benefits.map((benefit, index) => /* @__PURE__ */ jsxs15("li", { children: [
1476
+ /* @__PURE__ */ jsx15("span", { className: "chapter-membership-check", "aria-hidden": "true", children: "\u2713" }),
1477
+ /* @__PURE__ */ jsx15(Markdown2, { className: "chapter-membership-benefit", source: benefit })
1433
1478
  ] }, `${tier.id}-benefit-${index}`)) }) : null,
1434
- presentation.callout ? /* @__PURE__ */ jsxs14("aside", { className: "chapter-membership-callout", children: [
1435
- presentation.callout.label ? /* @__PURE__ */ jsx14("p", { className: "chapter-membership-callout-label", children: presentation.callout.label }) : null,
1436
- /* @__PURE__ */ jsx14(Markdown2, { source: presentation.callout.bodyMarkdown })
1479
+ presentation.callout ? /* @__PURE__ */ jsxs15("aside", { className: "chapter-membership-callout", children: [
1480
+ presentation.callout.label ? /* @__PURE__ */ jsx15("p", { className: "chapter-membership-callout-label", children: presentation.callout.label }) : null,
1481
+ /* @__PURE__ */ jsx15(Markdown2, { source: presentation.callout.bodyMarkdown })
1437
1482
  ] }) : null,
1438
- /* @__PURE__ */ jsx14(TierAction, { tierId: tier.id, label: action, mode: props.mode, selected: props.selected, applicationPath: props.applicationPath, onSelectTier: props.onSelectTier })
1483
+ /* @__PURE__ */ jsx15(TierAction, { tierId: tier.id, label: action, mode: props.mode, selected: props.selected, applicationPath: props.applicationPath, onSelectTier: props.onSelectTier })
1439
1484
  ] });
1440
1485
  }
1441
1486
  function MembershipCards(props) {
1442
1487
  const document2 = membershipPageDocument(props.document, { tiers: props.tiers });
1443
1488
  const byId = new Map(props.tiers.map((tier) => [tier.id, tier]));
1444
1489
  const mode = props.mode ?? "link";
1445
- return /* @__PURE__ */ jsxs14("section", { className: ["chapter-membership", props.className].filter(Boolean).join(" "), "data-chapter-membership": MEMBERSHIP_PAGE_RENDERER, "aria-label": props.ariaLabel ?? "Membership options", children: [
1446
- /* @__PURE__ */ jsx14("style", { children: MEMBERSHIP_CARDS_CSS }),
1447
- /* @__PURE__ */ jsx14("div", { className: "chapter-membership-grid", style: { "--chapter-membership-columns": String(Math.min(document2.tiers.length, 3)) }, children: document2.tiers.map((presentation) => {
1490
+ return /* @__PURE__ */ jsxs15("section", { className: ["chapter-membership", props.className].filter(Boolean).join(" "), "data-chapter-membership": MEMBERSHIP_PAGE_RENDERER, "aria-label": props.ariaLabel ?? "Membership options", children: [
1491
+ /* @__PURE__ */ jsx15("style", { children: MEMBERSHIP_CARDS_CSS }),
1492
+ /* @__PURE__ */ jsx15("div", { className: "chapter-membership-grid", style: { "--chapter-membership-columns": String(Math.min(document2.tiers.length, 3)) }, children: document2.tiers.map((presentation) => {
1448
1493
  const tier = byId.get(presentation.tierId);
1449
- return /* @__PURE__ */ jsx14(TierCard, { tier, presentation, mode, selected: props.selectedTierId === tier.id, applicationPath: props.applicationPath, onSelectTier: props.onSelectTier }, tier.id);
1494
+ return /* @__PURE__ */ jsx15(TierCard, { tier, presentation, mode, selected: props.selectedTierId === tier.id, applicationPath: props.applicationPath, onSelectTier: props.onSelectTier }, tier.id);
1450
1495
  }) }),
1451
- document2.footnoteMarkdown ? /* @__PURE__ */ jsx14(Markdown2, { className: "chapter-membership-footnote", source: document2.footnoteMarkdown }) : null
1496
+ document2.footnoteMarkdown ? /* @__PURE__ */ jsx15(Markdown2, { className: "chapter-membership-footnote", source: document2.footnoteMarkdown }) : null
1452
1497
  ] });
1453
1498
  }
1454
1499
 
@@ -1464,18 +1509,19 @@ export {
1464
1509
  SlotPicker,
1465
1510
  Rescheduler,
1466
1511
  GiftOfferCards,
1467
- GiftCodeRedeemer,
1468
1512
  PaymentStep,
1513
+ GiftPurchases,
1469
1514
  MemberGifts,
1470
1515
  MemberContentArea,
1471
1516
  MembersArea,
1517
+ GiftCodeRedeemer,
1518
+ loadJoinResume,
1472
1519
  useTierSelection,
1473
1520
  TierPlaceholder,
1474
1521
  tierNeedsPayment,
1475
- loadJoinResume,
1476
1522
  JoinIsland,
1477
1523
  MEMBERSHIP_CARD_TOKEN_DEFAULTS,
1478
1524
  membershipApplicationHref,
1479
1525
  MembershipCards
1480
1526
  };
1481
- //# sourceMappingURL=chunk-PCRYLPMQ.js.map
1527
+ //# sourceMappingURL=chunk-S7CND3R5.js.map