@odla-ai/chapter 0.55.0 → 0.56.1

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.
@@ -294,7 +294,7 @@ function CheckoutSeatChoice(props) {
294
294
  try {
295
295
  await props.onChange(selected ? { recipientName: name, recipientEmail: email } : null);
296
296
  } catch (error2) {
297
- setError(error2 instanceof Error ? error2.message : "Could not update your total. Try again.");
297
+ setError(error2 instanceof Error ? error2.message : "Could not save your selection. Try again.");
298
298
  } finally {
299
299
  setSaving(false);
300
300
  }
@@ -311,7 +311,7 @@ function CheckoutSeatChoice(props) {
311
311
  ] }),
312
312
  selected ? /* @__PURE__ */ jsxs3(Fragment2, { children: [
313
313
  /* @__PURE__ */ jsxs3("label", { children: [
314
- "Recipient name",
314
+ "Full name",
315
315
  /* @__PURE__ */ jsx3(
316
316
  "input",
317
317
  {
@@ -327,7 +327,7 @@ function CheckoutSeatChoice(props) {
327
327
  )
328
328
  ] }),
329
329
  /* @__PURE__ */ jsxs3("label", { children: [
330
- "Recipient email",
330
+ "Email",
331
331
  /* @__PURE__ */ jsx3(
332
332
  "input",
333
333
  {
@@ -342,37 +342,78 @@ function CheckoutSeatChoice(props) {
342
342
  }
343
343
  )
344
344
  ] }),
345
- /* @__PURE__ */ jsx3("p", { children: "This seat belongs to one named person and cannot be reassigned. They must accept and complete their own application and any required interview. It renews and ends with your membership. Contact the chapter if you need a refund." })
345
+ /* @__PURE__ */ jsx3("p", { children: "For one named person, who completes their own application and any required interview. Non-transferable; renews and ends with your membership." })
346
346
  ] }) : /* @__PURE__ */ jsx3("p", { children: "You can add someone from your member page after paying." }),
347
- dirty ? /* @__PURE__ */ jsx3("button", { type: "submit", disabled: saving, children: saving ? "Updating total\u2026" : "Update total" }) : null
347
+ dirty ? /* @__PURE__ */ jsx3("button", { type: "submit", disabled: saving, children: saving ? "Saving\u2026" : amount === 0 ? "Save member details" : "Update total" }) : null
348
348
  ] }),
349
349
  error ? /* @__PURE__ */ jsx3("p", { role: "alert", children: error }) : null
350
350
  ] }) });
351
351
  }
352
352
 
353
+ // src/ui/checkout-seat-review.tsx
354
+ import { jsx as jsx4, jsxs as jsxs4 } from "preact/jsx-runtime";
355
+ function CheckoutSeatReview({ quote, label, locked, onEdit }) {
356
+ if (!quote.namedSeat) return null;
357
+ return /* @__PURE__ */ jsxs4("section", { className: "checkout-seat-review", "aria-label": label, children: [
358
+ /* @__PURE__ */ jsx4("h3", { children: label }),
359
+ /* @__PURE__ */ jsxs4("p", { children: [
360
+ quote.namedSeat.recipientName,
361
+ /* @__PURE__ */ jsx4("br", {}),
362
+ quote.namedSeat.recipientEmail
363
+ ] }),
364
+ !locked ? /* @__PURE__ */ jsx4("button", { type: "button", onClick: onEdit, children: "Edit details" }) : null
365
+ ] });
366
+ }
367
+
353
368
  // src/ui/membership-payment-step.tsx
354
- import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "preact/jsx-runtime";
369
+ import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs5 } from "preact/jsx-runtime";
355
370
  function MembershipPaymentStep(props) {
356
371
  const inherited = useChapterCopy();
357
372
  const copy = props.copy ?? inherited.join.payment;
358
373
  const [quote, setQuote] = useState4(null);
359
374
  const [locked, setLocked] = useState4(false), [editing, setEditing] = useState4(Boolean(props.initialNamedSeat));
360
- const [seatTerms, setSeatTerms] = useState4(false), [prefillConsumed, setPrefillConsumed] = useState4(false);
375
+ const [prefillConsumed, setPrefillConsumed] = useState4(false);
361
376
  const [error, setError] = useState4(false);
362
377
  const [revision, setRevision] = useState4(0);
378
+ useEffect(() => {
379
+ props.onNamedSeatEditingChange?.(Boolean(props.renderNamedSeatEditor && editing && !locked && quote));
380
+ }, [editing, locked, Boolean(quote), Boolean(props.renderNamedSeatEditor)]);
363
381
  useEffect(() => {
364
382
  let live = true;
365
383
  setQuote(null);
366
384
  setError(false);
367
385
  void fetch(`/api/payments/quote?application=${encodeURIComponent(props.applicationId)}`, { method: "POST", cache: "no-store" }).then(async (response) => {
368
386
  if (!response.ok) throw new Error("quote unavailable");
369
- const value = await response.json();
387
+ let value = await response.json();
370
388
  value.checkoutStarted = response.headers.get("x-chapter-checkout-started") === "true";
371
389
  if (value.applicationId !== props.applicationId || !/^[a-f0-9]{64}$/.test(value.digest) || !/^[a-z]{3}$/.test(value.currency) || !Number.isSafeInteger(value.lineItems?.dueTodayCents) || value.lineItems.dueTodayCents <= 0 || typeof value.refundPolicyText !== "string") throw new Error("invalid quote");
390
+ if (!live) return;
391
+ if (props.renderNamedSeatEditor && props.initialNamedSeat && !prefillConsumed && !value.namedSeat && !value.checkoutStarted && value.seatOffer) {
392
+ const saved = await fetch(`/api/payments/quote?application=${encodeURIComponent(props.applicationId)}`, {
393
+ method: "POST",
394
+ cache: "no-store",
395
+ headers: { "content-type": "application/json" },
396
+ body: JSON.stringify({ namedSeat: props.initialNamedSeat })
397
+ });
398
+ if (!saved.ok) {
399
+ if (saved.status === 409) {
400
+ if (live) setRevision((current) => current + 1);
401
+ return;
402
+ }
403
+ if (live) {
404
+ setQuote(value);
405
+ setEditing(true);
406
+ setError(true);
407
+ }
408
+ return;
409
+ }
410
+ value = await saved.json();
411
+ if (value.applicationId !== props.applicationId || !/^[a-f0-9]{64}$/.test(value.digest) || !value.namedSeat) throw new Error("invalid quote");
412
+ if (live) setPrefillConsumed(true);
413
+ }
372
414
  if (live) {
373
415
  setQuote(value);
374
416
  setLocked(Boolean(value.checkoutStarted));
375
- setSeatTerms(Boolean(value.checkoutStarted));
376
417
  setEditing(Boolean(props.initialNamedSeat && !prefillConsumed && !value.namedSeat && !value.checkoutStarted && value.seatOffer));
377
418
  }
378
419
  }).catch(() => {
@@ -386,10 +427,10 @@ function MembershipPaymentStep(props) {
386
427
  setQuote(null);
387
428
  setRevision((value) => value + 1);
388
429
  };
389
- if (!quote || quote.applicationId !== props.applicationId) return /* @__PURE__ */ jsxs4("div", { className: "join-pay", role: "status", children: [
390
- props.merchantDisclosureText ? /* @__PURE__ */ jsx4("p", { className: "compliance-merchant", children: props.merchantDisclosureText }) : null,
391
- /* @__PURE__ */ jsx4("p", { children: error ? copy.setupFailed : copy.preparing }),
392
- error ? /* @__PURE__ */ jsx4("button", { type: "button", onClick: refresh, children: "Reload payment terms" }) : null
430
+ if (!quote || quote.applicationId !== props.applicationId) return /* @__PURE__ */ jsxs5("div", { className: "join-pay", role: "status", children: [
431
+ props.merchantDisclosureText ? /* @__PURE__ */ jsx5("p", { className: "compliance-merchant", children: props.merchantDisclosureText }) : null,
432
+ /* @__PURE__ */ jsx5("p", { children: error ? copy.setupFailed : copy.preparing }),
433
+ error ? /* @__PURE__ */ jsx5("button", { type: "button", onClick: refresh, children: "Reload payment terms" }) : null
393
434
  ] });
394
435
  const startCheckout = async () => {
395
436
  setLocked(true);
@@ -419,17 +460,39 @@ function MembershipPaymentStep(props) {
419
460
  });
420
461
  if (!response.ok) {
421
462
  if (response.status === 409) refresh();
422
- throw new Error(response.status === 400 ? "Enter a different recipient's name and valid email." : "Could not update your total. Reload payment terms and try again.");
463
+ throw new Error(response.status === 400 ? "Enter a different recipient's name and valid email." : "Could not save your selection. Reload payment terms and try again.");
423
464
  }
424
465
  const value = await response.json();
425
466
  if (value.applicationId !== props.applicationId || !/^[a-f0-9]{64}$/.test(value.digest)) throw new Error(copy.setupFailed);
426
467
  setQuote(value);
427
468
  setEditing(false);
428
- setSeatTerms(false);
469
+ setError(false);
429
470
  setPrefillConsumed(true);
430
471
  };
431
- return /* @__PURE__ */ jsxs4(Fragment3, { children: [
432
- quote.seatOffer ? /* @__PURE__ */ jsx4(
472
+ const pickLater = !quote.namedSeat && quote.seatOffer?.amountCents === 0;
473
+ if (props.renderNamedSeatEditor && editing && !locked && quote.seatOffer) return /* @__PURE__ */ jsxs5(Fragment3, { children: [
474
+ error ? /* @__PURE__ */ jsx5("p", { role: "alert", children: "Enter a different recipient's full name and valid email to continue." }) : null,
475
+ props.renderNamedSeatEditor({
476
+ selection: quote.namedSeat ?? (!prefillConsumed ? props.initialNamedSeat : void 0) ?? null,
477
+ offer: { ...quote.seatOffer, currency: quote.currency, interval: quote.interval },
478
+ save: changeSeat,
479
+ cancel: () => {
480
+ setEditing(false);
481
+ setError(false);
482
+ setPrefillConsumed(true);
483
+ }
484
+ })
485
+ ] });
486
+ return /* @__PURE__ */ jsxs5(Fragment3, { children: [
487
+ props.renderNamedSeatEditor ? /* @__PURE__ */ jsx5(
488
+ CheckoutSeatReview,
489
+ {
490
+ quote,
491
+ label: props.namedSeatLabel ?? "Additional member",
492
+ locked,
493
+ onEdit: () => setEditing(true)
494
+ }
495
+ ) : quote.seatOffer ? /* @__PURE__ */ jsx5(
433
496
  CheckoutSeatChoice,
434
497
  {
435
498
  quote,
@@ -440,47 +503,52 @@ function MembershipPaymentStep(props) {
440
503
  },
441
504
  quote.digest
442
505
  ) : null,
443
- /* @__PURE__ */ jsxs4("section", { className: "payment-quote", "aria-label": "Membership price", children: [
444
- /* @__PURE__ */ jsx4("h3", { children: quote.tierName }),
445
- quote.founding ? /* @__PURE__ */ jsx4("p", { className: "payment-founding", role: "note", "aria-label": "Founding member", children: copy.foundingMember }) : null,
506
+ /* @__PURE__ */ jsxs5("section", { className: "payment-quote", "aria-label": "Membership price", children: [
507
+ /* @__PURE__ */ jsx5("h3", { children: quote.tierName }),
508
+ quote.founding ? /* @__PURE__ */ jsx5("p", { className: "payment-founding", role: "note", "aria-label": "Founding member", children: copy.foundingMember }) : null,
446
509
  props.renderPriceLines ? props.renderPriceLines({
447
510
  ...quote.lineItems,
448
511
  ...quote.founding ? { founding: quote.founding } : {},
512
+ ...pickLater ? { namedSeatPickLater: true } : {},
449
513
  ...quote.presentation ? { presentation: quote.presentation } : {}
450
- }) : /* @__PURE__ */ jsxs4("dl", { children: [
451
- quote.lineItems.discountCents > 0 && !quote.founding && quote.presentation ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
452
- /* @__PURE__ */ jsx4("dt", { children: copy.standardRate }),
453
- /* @__PURE__ */ jsxs4("dd", { children: [
514
+ }) : /* @__PURE__ */ jsxs5("dl", { children: [
515
+ quote.lineItems.discountCents > 0 && !quote.founding && quote.presentation ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
516
+ /* @__PURE__ */ jsx5("dt", { children: copy.standardRate }),
517
+ /* @__PURE__ */ jsxs5("dd", { children: [
454
518
  amount(quote.lineItems.standardCents),
455
519
  " per ",
456
520
  quote.interval
457
521
  ] }),
458
- /* @__PURE__ */ jsx4("dt", { children: copy.yourRate }),
459
- /* @__PURE__ */ jsxs4("dd", { children: [
522
+ /* @__PURE__ */ jsx5("dt", { children: copy.yourRate }),
523
+ /* @__PURE__ */ jsxs5("dd", { children: [
460
524
  amount(quote.lineItems.dueTodayCents - (quote.lineItems.namedSeatCents ?? 0)),
461
525
  " per ",
462
526
  quote.interval
463
527
  ] })
464
- ] }) : /* @__PURE__ */ jsxs4(Fragment3, { children: [
465
- /* @__PURE__ */ jsx4("dt", { children: "Membership price" }),
466
- /* @__PURE__ */ jsxs4("dd", { children: [
528
+ ] }) : /* @__PURE__ */ jsxs5(Fragment3, { children: [
529
+ /* @__PURE__ */ jsx5("dt", { children: "Membership price" }),
530
+ /* @__PURE__ */ jsxs5("dd", { children: [
467
531
  amount(quote.lineItems.standardCents),
468
532
  " per ",
469
533
  quote.interval
470
534
  ] }),
471
- quote.lineItems.discountCents > 0 ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
472
- /* @__PURE__ */ jsx4("dt", { children: quote.founding ? copy.foundingDiscount : "Discount" }),
473
- /* @__PURE__ */ jsx4("dd", { children: amount(quote.lineItems.discountCents) })
535
+ quote.lineItems.discountCents > 0 ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
536
+ /* @__PURE__ */ jsx5("dt", { children: quote.founding ? copy.foundingDiscount : "Discount" }),
537
+ /* @__PURE__ */ jsx5("dd", { children: amount(quote.lineItems.discountCents) })
474
538
  ] }) : null
475
539
  ] }),
476
- quote.namedSeat ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
477
- /* @__PURE__ */ jsx4("dt", { children: "Additional member" }),
478
- /* @__PURE__ */ jsx4("dd", { children: quote.lineItems.namedSeatCents === 0 ? "Included" : amount(quote.lineItems.namedSeatCents) })
540
+ quote.namedSeat ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
541
+ /* @__PURE__ */ jsx5("dt", { children: "Additional member" }),
542
+ /* @__PURE__ */ jsx5("dd", { children: quote.lineItems.namedSeatCents === 0 ? "Included" : amount(quote.lineItems.namedSeatCents) })
479
543
  ] }) : null,
480
- /* @__PURE__ */ jsx4("dt", { children: "Due today" }),
481
- /* @__PURE__ */ jsx4("dd", { children: amount(quote.lineItems.dueTodayCents) })
544
+ pickLater ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
545
+ /* @__PURE__ */ jsx5("dt", { children: "Additional member" }),
546
+ /* @__PURE__ */ jsx5("dd", { children: "Pick later" })
547
+ ] }) : null,
548
+ /* @__PURE__ */ jsx5("dt", { children: "Due today" }),
549
+ /* @__PURE__ */ jsx5("dd", { children: amount(quote.lineItems.dueTodayCents) })
482
550
  ] }),
483
- quote.namedSeat ? /* @__PURE__ */ jsxs4("p", { children: [
551
+ quote.namedSeat && !props.renderNamedSeatEditor ? /* @__PURE__ */ jsxs5("p", { children: [
484
552
  "For ",
485
553
  quote.namedSeat.recipientName,
486
554
  " \xB7 ",
@@ -488,8 +556,8 @@ function MembershipPaymentStep(props) {
488
556
  ".",
489
557
  props.renderPriceLines ? ` Additional member: ${quote.lineItems.namedSeatCents === 0 ? "included" : amount(quote.lineItems.namedSeatCents)} in the total above.` : ""
490
558
  ] }) : null,
491
- quote.commercial ? /* @__PURE__ */ jsxs4("div", { role: "note", "aria-label": "Renewal terms", children: [
492
- quote.commercial.initialTermEndsAt !== void 0 ? /* @__PURE__ */ jsxs4("p", { children: [
559
+ quote.commercial ? /* @__PURE__ */ jsxs5("div", { role: "note", "aria-label": "Renewal terms", children: [
560
+ quote.commercial.initialTermEndsAt !== void 0 ? /* @__PURE__ */ jsxs5("p", { children: [
493
561
  "First renewal: ",
494
562
  new Intl.DateTimeFormat("en-US", {
495
563
  dateStyle: "long",
@@ -497,46 +565,39 @@ function MembershipPaymentStep(props) {
497
565
  }).format(quote.commercial.initialTermEndsAt),
498
566
  "."
499
567
  ] }) : null,
500
- /* @__PURE__ */ jsxs4("p", { children: [
568
+ /* @__PURE__ */ jsxs5("p", { children: [
501
569
  "Renews automatically at ",
502
570
  amount(quote.commercial.renewalCents),
503
571
  " per ",
504
572
  quote.interval,
505
573
  " unless canceled before renewal."
506
574
  ] }),
507
- quote.commercial.discountDuration === "first_term" ? /* @__PURE__ */ jsx4("p", { children: "The discount applies to your first paid term only." }) : null,
508
- quote.commercial.discountDuration === "while_active" ? /* @__PURE__ */ jsx4("p", { children: "The discounted rate continues while this membership stays active." }) : null
575
+ quote.commercial.discountDuration === "first_term" ? /* @__PURE__ */ jsx5("p", { children: "The discount applies to your first paid term only." }) : null,
576
+ quote.commercial.discountDuration === "while_active" ? /* @__PURE__ */ jsx5("p", { children: "The discounted rate continues while this membership stays active." }) : null
509
577
  ] }) : null,
510
- quote.trustCopy ? /* @__PURE__ */ jsx4("p", { className: "pay-trust", children: quote.trustCopy }) : null
578
+ quote.trustCopy ? /* @__PURE__ */ jsx5("p", { className: "pay-trust", children: quote.trustCopy }) : null
511
579
  ] }),
512
- quote.namedSeat && !editing ? /* @__PURE__ */ jsxs4("label", { className: "journey-consent", children: [
513
- /* @__PURE__ */ jsx4(
514
- "input",
515
- {
516
- type: "checkbox",
517
- checked: seatTerms,
518
- disabled: locked,
519
- onChange: (event) => setSeatTerms(event.currentTarget.checked)
520
- }
521
- ),
522
- "I agree to the additional-member terms and renewal with my membership."
580
+ quote.namedSeat && props.renderNamedSeatEditor ? /* @__PURE__ */ jsxs5("details", { className: "checkout-seat-terms", children: [
581
+ /* @__PURE__ */ jsx5("summary", { children: "Additional-member terms" }),
582
+ /* @__PURE__ */ jsx5("p", { children: "For one named person, who completes their own application and any required interview. Non-transferable; renews and ends with your membership." })
523
583
  ] }) : null,
524
- !editing && (!quote.namedSeat || seatTerms) ? /* @__PURE__ */ jsx4(
584
+ !editing ? /* @__PURE__ */ jsx5(
525
585
  PaymentStep,
526
586
  {
527
587
  ...props,
528
588
  refundPolicyText: quote.refundPolicyText,
529
589
  merchantDisclosureText: quote.merchantDisclosureText,
590
+ copy: { ...copy, consent: quote.namedSeat ? "I agree to the refund policy, renewal terms, and additional-member terms above." : "I agree to the refund policy and renewal terms above." },
530
591
  renderPriceLines: void 0,
531
592
  startCheckout
532
593
  },
533
594
  quote.digest
534
- ) : editing ? /* @__PURE__ */ jsx4("p", { role: "status", children: "Update the total to continue to payment." }) : null
595
+ ) : /* @__PURE__ */ jsx5("p", { role: "status", children: "Save your member selection to continue to payment." })
535
596
  ] });
536
597
  }
537
598
 
538
599
  // src/ui/journey-frame.tsx
539
- import { jsx as jsx5, jsxs as jsxs5 } from "preact/jsx-runtime";
600
+ import { jsx as jsx6, jsxs as jsxs6 } from "preact/jsx-runtime";
540
601
  var styles = `
541
602
  .chapter-journey{color:var(--ui-text,#202827);font-family:var(--ui-font-sans,inherit);line-height:1.65;max-width:46rem;margin-inline:auto;min-width:0}
542
603
  .chapter-journey *{box-sizing:border-box}
@@ -544,7 +605,7 @@ var styles = `
544
605
  .chapter-journey :where(h2,h3){font-family:var(--ui-font-display,inherit);line-height:1.2;letter-spacing:-.025em;text-transform:none}
545
606
  .chapter-journey h2{font-size:clamp(1.6rem,3vw,2.15rem)}
546
607
  .chapter-journey h3{font-size:1.3rem}
547
- .chapter-journey :where(.card,.join-form,.payment-quote,.join-book){padding:clamp(1.25rem,4vw,2.4rem);border:1px solid var(--ui-border,#dfe3df);border-radius:var(--ui-radius-lg,16px);background:var(--ui-surface,#fff);margin-block:1.2rem}
608
+ .chapter-journey :where(.card,.join-form,.payment-quote,.join-book,.checkout-seat-review){padding:clamp(1.25rem,4vw,2.4rem);border:1px solid var(--ui-border,#dfe3df);border-radius:var(--ui-radius-lg,16px);background:var(--ui-surface,#fff);margin-block:1.2rem}
548
609
  .chapter-journey :where(.card-label,.journey-eyebrow){font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ui-text-muted,#536360);margin-bottom:.7rem;font-weight:600}
549
610
  .chapter-journey :where(form,.journey-fields){display:grid;gap:1.25rem}
550
611
  .chapter-journey :where(label){display:block;font-size:.95rem;font-weight:500;letter-spacing:normal;text-transform:none;line-height:1.55}
@@ -568,17 +629,19 @@ var styles = `
568
629
  .chapter-journey :where(.pay-status,.meeting-note,.slots-status){color:var(--ui-text-muted,#536360)}
569
630
  .chapter-journey .journey-actions{display:flex;gap:.75rem;flex-wrap:wrap;margin-top:1.25rem}
570
631
  .chapter-journey fieldset{min-width:0;border:0;padding:0;margin:0}
632
+ .chapter-journey .checkout-seat-terms{margin-block:1rem}
633
+ .chapter-journey .checkout-seat-terms summary{cursor:pointer}
571
634
  @media(max-width:520px){.chapter-journey .journey-actions>*{width:100%}.chapter-journey .journey-summary{grid-template-columns:1fr}.chapter-journey .journey-summary dd{text-align:left}.chapter-journey :where(.card,.join-form,.payment-quote,.join-book){padding:1.25rem}}
572
635
  `;
573
636
  function JourneyFrame({ children }) {
574
- return /* @__PURE__ */ jsxs5("div", { className: "chapter-journey", children: [
575
- /* @__PURE__ */ jsx5("style", { children: styles }),
637
+ return /* @__PURE__ */ jsxs6("div", { className: "chapter-journey", children: [
638
+ /* @__PURE__ */ jsx6("style", { children: styles }),
576
639
  children
577
640
  ] });
578
641
  }
579
642
 
580
643
  // src/ui/member-restart.tsx
581
- import { jsx as jsx6, jsxs as jsxs6 } from "preact/jsx-runtime";
644
+ import { jsx as jsx7, jsxs as jsxs7 } from "preact/jsx-runtime";
582
645
  function MemberRestart(props) {
583
646
  const [id, setId] = useState5(props.applicationId);
584
647
  const [busy, setBusy] = useState5(false);
@@ -623,22 +686,22 @@ function MemberRestart(props) {
623
686
  setBusy(false);
624
687
  }
625
688
  };
626
- return /* @__PURE__ */ jsx6(JourneyFrame, { children: /* @__PURE__ */ jsxs6("section", { className: "card", "aria-label": "Restart membership", children: [
627
- /* @__PURE__ */ jsx6("p", { className: "card-label", children: "Welcome back" }),
628
- /* @__PURE__ */ jsx6("h2", { children: "Restart your membership" }),
629
- /* @__PURE__ */ jsx6("p", { children: "Your account is ready, and your previous approval still counts. No new application or interview is needed." }),
630
- /* @__PURE__ */ jsxs6("dl", { className: "journey-summary", children: [
631
- /* @__PURE__ */ jsx6("dt", { children: "Name" }),
632
- /* @__PURE__ */ jsx6("dd", { children: [props.application.firstName, props.application.lastName].filter(Boolean).join(" ") }),
633
- /* @__PURE__ */ jsx6("dt", { children: "Email" }),
634
- /* @__PURE__ */ jsx6("dd", { children: props.application.email })
689
+ return /* @__PURE__ */ jsx7(JourneyFrame, { children: /* @__PURE__ */ jsxs7("section", { className: "card", "aria-label": "Restart membership", children: [
690
+ /* @__PURE__ */ jsx7("p", { className: "card-label", children: "Welcome back" }),
691
+ /* @__PURE__ */ jsx7("h2", { children: "Restart your membership" }),
692
+ /* @__PURE__ */ jsx7("p", { children: "Your account is ready, and your previous approval still counts. No new application or interview is needed." }),
693
+ /* @__PURE__ */ jsxs7("dl", { className: "journey-summary", children: [
694
+ /* @__PURE__ */ jsx7("dt", { children: "Name" }),
695
+ /* @__PURE__ */ jsx7("dd", { children: [props.application.firstName, props.application.lastName].filter(Boolean).join(" ") }),
696
+ /* @__PURE__ */ jsx7("dt", { children: "Email" }),
697
+ /* @__PURE__ */ jsx7("dd", { children: props.application.email })
635
698
  ] }),
636
- paid ? /* @__PURE__ */ jsxs6("div", { role: "status", children: [
637
- /* @__PURE__ */ jsx6("h3", { children: "Confirming your membership" }),
638
- /* @__PURE__ */ jsx6("p", { children: "We\u2019re waiting for payment confirmation. Your membership will open here as soon as it arrives." }),
639
- !checking ? /* @__PURE__ */ jsx6("button", { type: "button", onClick: () => setRevision((value) => value + 1), children: "Check membership" }) : null
640
- ] }) : id ? /* @__PURE__ */ jsx6(MembershipPaymentStep, { applicationId: id, refundPolicyText: "", onPaid: () => setPaid(true) }) : /* @__PURE__ */ jsx6("button", { type: "button", disabled: busy, onClick: () => void start(), children: busy ? "Preparing your membership\u2026" : "Review membership and payment" }),
641
- error ? /* @__PURE__ */ jsx6("p", { role: "alert", children: error }) : null
699
+ paid ? /* @__PURE__ */ jsxs7("div", { role: "status", children: [
700
+ /* @__PURE__ */ jsx7("h3", { children: "Confirming your membership" }),
701
+ /* @__PURE__ */ jsx7("p", { children: "We\u2019re waiting for payment confirmation. Your membership will open here as soon as it arrives." }),
702
+ !checking ? /* @__PURE__ */ jsx7("button", { type: "button", onClick: () => setRevision((value) => value + 1), children: "Check membership" }) : null
703
+ ] }) : id ? /* @__PURE__ */ jsx7(MembershipPaymentStep, { applicationId: id, refundPolicyText: "", onPaid: () => setPaid(true) }) : /* @__PURE__ */ jsx7("button", { type: "button", disabled: busy, onClick: () => void start(), children: busy ? "Preparing your membership\u2026" : "Review membership and payment" }),
704
+ error ? /* @__PURE__ */ jsx7("p", { role: "alert", children: error }) : null
642
705
  ] }) });
643
706
  }
644
707
 
@@ -647,7 +710,7 @@ import { useEffect as useEffect6, useState as useState10 } from "preact/hooks";
647
710
 
648
711
  // src/ui/reschedule.tsx
649
712
  import { useState as useState6 } from "preact/hooks";
650
- import { jsx as jsx7, jsxs as jsxs7 } from "preact/jsx-runtime";
713
+ import { jsx as jsx8, jsxs as jsxs8 } from "preact/jsx-runtime";
651
714
  function Rescheduler(props) {
652
715
  const inheritedCopy = useChapterCopy();
653
716
  const copy = props.copy ?? inheritedCopy.members.reschedule;
@@ -689,7 +752,7 @@ function Rescheduler(props) {
689
752
  }
690
753
  };
691
754
  if (!open) {
692
- return /* @__PURE__ */ jsx7("p", { className: "meeting-note", children: /* @__PURE__ */ jsx7(
755
+ return /* @__PURE__ */ jsx8("p", { className: "meeting-note", children: /* @__PURE__ */ jsx8(
693
756
  "a",
694
757
  {
695
758
  href: "#",
@@ -701,8 +764,8 @@ function Rescheduler(props) {
701
764
  }
702
765
  ) });
703
766
  }
704
- return /* @__PURE__ */ jsxs7("div", { className: "msched", children: [
705
- slots === null ? /* @__PURE__ */ jsx7("p", { className: "meeting-note", children: copy.loading }) : slots.length === 0 ? /* @__PURE__ */ jsx7("p", { className: "meeting-note", children: msg ?? copy.noTimes }) : /* @__PURE__ */ jsx7(
767
+ return /* @__PURE__ */ jsxs8("div", { className: "msched", children: [
768
+ slots === null ? /* @__PURE__ */ jsx8("p", { className: "meeting-note", children: copy.loading }) : slots.length === 0 ? /* @__PURE__ */ jsx8("p", { className: "meeting-note", children: msg ?? copy.noTimes }) : /* @__PURE__ */ jsx8(
706
769
  SlotPicker,
707
770
  {
708
771
  slots,
@@ -711,9 +774,9 @@ function Rescheduler(props) {
711
774
  onPick: (s) => void pick(s)
712
775
  }
713
776
  ),
714
- busy ? /* @__PURE__ */ jsx7("p", { className: "meeting-note", children: copy.rescheduling }) : null,
715
- msg && slots && slots.length > 0 ? /* @__PURE__ */ jsx7("p", { className: "meeting-note error", children: msg }) : null,
716
- /* @__PURE__ */ jsx7("p", { className: "meeting-note", children: /* @__PURE__ */ jsx7(
777
+ busy ? /* @__PURE__ */ jsx8("p", { className: "meeting-note", children: copy.rescheduling }) : null,
778
+ msg && slots && slots.length > 0 ? /* @__PURE__ */ jsx8("p", { className: "meeting-note error", children: msg }) : null,
779
+ /* @__PURE__ */ jsx8("p", { className: "meeting-note", children: /* @__PURE__ */ jsx8(
717
780
  "a",
718
781
  {
719
782
  href: "#",
@@ -731,23 +794,23 @@ function Rescheduler(props) {
731
794
  import { useEffect as useEffect3, useRef as useRef2, useState as useState7 } from "preact/hooks";
732
795
 
733
796
  // src/ui/gift-offer-cards.tsx
734
- import { jsx as jsx8, jsxs as jsxs8 } from "preact/jsx-runtime";
797
+ import { jsx as jsx9, jsxs as jsxs9 } from "preact/jsx-runtime";
735
798
  var price = (cents, currency) => currency === "usd" ? fmtMoney(cents) : new Intl.NumberFormat(void 0, { style: "currency", currency: currency.toUpperCase() }).format(cents / 100);
736
799
  function GiftOfferCards(props) {
737
800
  const mode = props.mode ?? "preview";
738
- return /* @__PURE__ */ jsx8("section", { className: "chapter-gift-offers", "aria-label": props.ariaLabel ?? "Gift options", children: props.offers.map((offer) => /* @__PURE__ */ jsxs8("article", { className: "card chapter-gift-offer", "data-offer-id": offer.id, children: [
739
- /* @__PURE__ */ jsx8("div", { className: "card-label", children: offer.title }),
740
- /* @__PURE__ */ jsx8("p", { children: offer.description }),
741
- /* @__PURE__ */ jsxs8("p", { className: "meeting-date", children: [
801
+ return /* @__PURE__ */ jsx9("section", { className: "chapter-gift-offers", "aria-label": props.ariaLabel ?? "Gift options", children: props.offers.map((offer) => /* @__PURE__ */ jsxs9("article", { className: "card chapter-gift-offer", "data-offer-id": offer.id, children: [
802
+ /* @__PURE__ */ jsx9("div", { className: "card-label", children: offer.title }),
803
+ /* @__PURE__ */ jsx9("p", { children: offer.description }),
804
+ /* @__PURE__ */ jsxs9("p", { className: "meeting-date", children: [
742
805
  price(offer.priceCents, offer.currency),
743
806
  offer.billingMode === "subscription" ? " recurring" : ""
744
807
  ] }),
745
- mode === "select" ? /* @__PURE__ */ jsx8("button", { type: "button", className: "btn secondary", "aria-pressed": props.selectedOfferId === offer.id, onClick: () => props.onSelect?.(offer.id), children: offer.ctaLabel }) : /* @__PURE__ */ jsx8("span", { className: "btn secondary", "aria-disabled": "true", children: offer.ctaLabel })
808
+ mode === "select" ? /* @__PURE__ */ jsx9("button", { type: "button", className: "btn secondary", "aria-pressed": props.selectedOfferId === offer.id, onClick: () => props.onSelect?.(offer.id), children: offer.ctaLabel }) : /* @__PURE__ */ jsx9("span", { className: "btn secondary", "aria-disabled": "true", children: offer.ctaLabel })
746
809
  ] }, offer.id)) });
747
810
  }
748
811
 
749
812
  // src/ui/member-gifts.tsx
750
- import { jsx as jsx9, jsxs as jsxs9 } from "preact/jsx-runtime";
813
+ import { jsx as jsx10, jsxs as jsxs10 } from "preact/jsx-runtime";
751
814
  function GiftPurchases(props) {
752
815
  const [data, setData] = useState7(null);
753
816
  const [selected, setSelected] = useState7(null);
@@ -770,16 +833,16 @@ function GiftPurchases(props) {
770
833
  if (!data) return null;
771
834
  if (data.offers.length === 0 && data.claims.length === 0) return null;
772
835
  const offer = data.offers.find((item) => item.id === selected);
773
- return /* @__PURE__ */ jsxs9("section", { className: "member-gifts", children: [
774
- data.offers.length ? /* @__PURE__ */ jsxs9("div", { className: "card", children: [
775
- /* @__PURE__ */ jsx9("div", { className: "card-label", children: props.copy.title }),
776
- /* @__PURE__ */ jsx9("p", { children: props.copy.body }),
777
- /* @__PURE__ */ jsx9(GiftOfferCards, { offers: data.offers, mode: "select", selectedOfferId: selected, onSelect: (id) => {
836
+ return /* @__PURE__ */ jsxs10("section", { className: "member-gifts", children: [
837
+ data.offers.length ? /* @__PURE__ */ jsxs10("div", { className: "card", children: [
838
+ /* @__PURE__ */ jsx10("div", { className: "card-label", children: props.copy.title }),
839
+ /* @__PURE__ */ jsx10("p", { children: props.copy.body }),
840
+ /* @__PURE__ */ jsx10(GiftOfferCards, { offers: data.offers, mode: "select", selectedOfferId: selected, onSelect: (id) => {
778
841
  setSelected(id);
779
842
  setCode("");
780
843
  purchaseId.current = crypto.randomUUID();
781
844
  } }),
782
- offer ? /* @__PURE__ */ jsx9(
845
+ offer ? /* @__PURE__ */ jsx10(
783
846
  PaymentStep,
784
847
  {
785
848
  applicationId: purchaseId.current,
@@ -799,19 +862,19 @@ function GiftPurchases(props) {
799
862
  }
800
863
  }
801
864
  ) : null,
802
- code ? /* @__PURE__ */ jsxs9("div", { className: "gift-code-once", children: [
803
- /* @__PURE__ */ jsx9("output", { children: code }),
804
- /* @__PURE__ */ jsx9("p", { children: props.copy.saveCode })
865
+ code ? /* @__PURE__ */ jsxs10("div", { className: "gift-code-once", children: [
866
+ /* @__PURE__ */ jsx10("output", { children: code }),
867
+ /* @__PURE__ */ jsx10("p", { children: props.copy.saveCode })
805
868
  ] }) : null
806
869
  ] }) : null,
807
- /* @__PURE__ */ jsxs9("div", { className: "card", children: [
808
- /* @__PURE__ */ jsx9("div", { className: "card-label", children: props.copy.purchases }),
809
- data.claims.length ? data.claims.map((claim) => /* @__PURE__ */ jsxs9("div", { className: "member-row", children: [
810
- /* @__PURE__ */ jsx9("span", { children: claim.offerId }),
811
- /* @__PURE__ */ jsx9("span", { children: props.copy[claim.status] }),
812
- claim.status === "pending" ? /* @__PURE__ */ jsx9("button", { className: "btn secondary mini", onClick: () => void rotate(claim.id), children: props.copy.rotate }) : null
813
- ] }, claim.id)) : /* @__PURE__ */ jsx9("p", { children: props.copy.noPurchases }),
814
- message ? /* @__PURE__ */ jsx9("p", { role: "status", children: message }) : null
870
+ /* @__PURE__ */ jsxs10("div", { className: "card", children: [
871
+ /* @__PURE__ */ jsx10("div", { className: "card-label", children: props.copy.purchases }),
872
+ data.claims.length ? data.claims.map((claim) => /* @__PURE__ */ jsxs10("div", { className: "member-row", children: [
873
+ /* @__PURE__ */ jsx10("span", { children: claim.offerId }),
874
+ /* @__PURE__ */ jsx10("span", { children: props.copy[claim.status] }),
875
+ claim.status === "pending" ? /* @__PURE__ */ jsx10("button", { className: "btn secondary mini", onClick: () => void rotate(claim.id), children: props.copy.rotate }) : null
876
+ ] }, claim.id)) : /* @__PURE__ */ jsx10("p", { children: props.copy.noPurchases }),
877
+ message ? /* @__PURE__ */ jsx10("p", { role: "status", children: message }) : null
815
878
  ] })
816
879
  ] });
817
880
  }
@@ -819,7 +882,7 @@ var MemberGifts = GiftPurchases;
819
882
 
820
883
  // src/ui/member-named-seat.tsx
821
884
  import { useEffect as useEffect4, useState as useState8 } from "preact/hooks";
822
- import { Fragment as Fragment4, jsx as jsx10, jsxs as jsxs10 } from "preact/jsx-runtime";
885
+ import { Fragment as Fragment4, jsx as jsx11, jsxs as jsxs11 } from "preact/jsx-runtime";
823
886
  var NAMED_SEAT_RECIPIENT_WORDS = {
824
887
  payment_pending: "payment in progress",
825
888
  invited: "invited, waiting for them to accept",
@@ -832,7 +895,7 @@ var NAMED_SEAT_RECIPIENT_WORDS = {
832
895
  var day = (at) => new Date(at).toLocaleDateString("en-US", { timeZone: "UTC" });
833
896
  function NamedSeatRecipientLine({ seat }) {
834
897
  const words = NAMED_SEAT_RECIPIENT_WORDS[seat.recipientState] ?? seat.status.replaceAll("_", " ");
835
- return /* @__PURE__ */ jsxs10("p", { className: "member-named-seat-recipient", children: [
898
+ return /* @__PURE__ */ jsxs11("p", { className: "member-named-seat-recipient", children: [
836
899
  seat.recipientName,
837
900
  " \xB7 ",
838
901
  seat.recipientEmail,
@@ -881,13 +944,13 @@ function NamedSeatPurchase({ api }) {
881
944
  }
882
945
  };
883
946
  const money = data ? new Intl.NumberFormat("en-US", { style: "currency", currency: data.currency }).format(data.amountCents / 100) : "";
884
- return /* @__PURE__ */ jsx10(JourneyFrame, { children: /* @__PURE__ */ jsxs10("section", { className: "card member-named-seat", "aria-label": "Named additional seat", children: [
885
- /* @__PURE__ */ jsx10("h2", { children: "Named additional seat" }),
886
- error ? /* @__PURE__ */ jsx10("p", { role: "alert", children: error }) : null,
887
- data ? /* @__PURE__ */ jsxs10(Fragment4, { children: [
888
- data.seat ? /* @__PURE__ */ jsx10(NamedSeatRecipientLine, { seat: data.seat }) : null,
889
- data.eligible ? /* @__PURE__ */ jsxs10(Fragment4, { children: [
890
- /* @__PURE__ */ jsxs10("p", { children: [
947
+ return /* @__PURE__ */ jsx11(JourneyFrame, { children: /* @__PURE__ */ jsxs11("section", { className: "card member-named-seat", "aria-label": "Named additional seat", children: [
948
+ /* @__PURE__ */ jsx11("h2", { children: "Named additional seat" }),
949
+ error ? /* @__PURE__ */ jsx11("p", { role: "alert", children: error }) : null,
950
+ data ? /* @__PURE__ */ jsxs11(Fragment4, { children: [
951
+ data.seat ? /* @__PURE__ */ jsx11(NamedSeatRecipientLine, { seat: data.seat }) : null,
952
+ data.eligible ? /* @__PURE__ */ jsxs11(Fragment4, { children: [
953
+ /* @__PURE__ */ jsxs11("p", { children: [
891
954
  data.included ? "Included with your membership at no charge." : `${money} paid in full now.`,
892
955
  " This seat ",
893
956
  data.autoRenew ? "renews with your primary membership" : "ends with your primary membership",
@@ -898,39 +961,39 @@ function NamedSeatPurchase({ api }) {
898
961
  " ",
899
962
  "It belongs to one named person and cannot be reassigned."
900
963
  ] }),
901
- /* @__PURE__ */ jsx10("p", { children: "The recipient must accept and complete their own application and any required interview. The seat stays open for them while your membership is paid; it is not refunded automatically. Contact the chapter if you need a refund." }),
902
- !reviewing ? /* @__PURE__ */ jsxs10("form", { onSubmit: (event) => {
964
+ /* @__PURE__ */ jsx11("p", { children: "The recipient must accept and complete their own application and any required interview. The seat stays open for them while your membership is paid; it is not refunded automatically. Contact the chapter if you need a refund." }),
965
+ !reviewing ? /* @__PURE__ */ jsxs11("form", { onSubmit: (event) => {
903
966
  event.preventDefault();
904
967
  setReviewing(true);
905
968
  setTerms(false);
906
969
  }, children: [
907
- /* @__PURE__ */ jsxs10("label", { children: [
970
+ /* @__PURE__ */ jsxs11("label", { children: [
908
971
  "Recipient name",
909
- /* @__PURE__ */ jsx10("input", { required: true, maxLength: 160, value: name, disabled: Boolean(data.seat), onInput: (event) => setName(event.currentTarget.value) })
972
+ /* @__PURE__ */ jsx11("input", { required: true, maxLength: 160, value: name, disabled: Boolean(data.seat), onInput: (event) => setName(event.currentTarget.value) })
910
973
  ] }),
911
- /* @__PURE__ */ jsxs10("label", { children: [
974
+ /* @__PURE__ */ jsxs11("label", { children: [
912
975
  "Recipient email",
913
- /* @__PURE__ */ jsx10("input", { required: true, type: "email", maxLength: 254, value: email, disabled: Boolean(data.seat), onInput: (event) => setEmail(event.currentTarget.value) })
976
+ /* @__PURE__ */ jsx11("input", { required: true, type: "email", maxLength: 254, value: email, disabled: Boolean(data.seat), onInput: (event) => setEmail(event.currentTarget.value) })
914
977
  ] }),
915
- /* @__PURE__ */ jsx10("button", { className: "btn primary", type: "submit", children: "Review named seat" })
916
- ] }) : /* @__PURE__ */ jsxs10(Fragment4, { children: [
917
- /* @__PURE__ */ jsxs10("p", { children: [
978
+ /* @__PURE__ */ jsx11("button", { className: "btn primary", type: "submit", children: "Review named seat" })
979
+ ] }) : /* @__PURE__ */ jsxs11(Fragment4, { children: [
980
+ /* @__PURE__ */ jsxs11("p", { children: [
918
981
  "For ",
919
982
  name,
920
983
  " \xB7 ",
921
984
  email
922
985
  ] }),
923
- /* @__PURE__ */ jsx10("button", { className: "btn secondary", type: "button", onClick: () => {
986
+ /* @__PURE__ */ jsx11("button", { className: "btn secondary", type: "button", onClick: () => {
924
987
  setReviewing(false);
925
988
  setTerms(false);
926
989
  void load();
927
990
  }, children: "Back to recipient" }),
928
- /* @__PURE__ */ jsxs10("label", { className: "journey-consent", children: [
929
- /* @__PURE__ */ jsx10("input", { type: "checkbox", checked: terms, onChange: (event) => setTerms(event.currentTarget.checked) }),
930
- /* @__PURE__ */ jsx10("span", { children: data.included ? "I agree to the seat terms and the refund policy; the seat is included with my membership and follows its renewal." : data.autoRenew ? "I agree to the full initial payment and automatic renewal with my membership; I can cancel renewal." : "I agree to the full initial payment and the displayed end date, with no automatic renewal while my membership renewal is canceled." })
991
+ /* @__PURE__ */ jsxs11("label", { className: "journey-consent", children: [
992
+ /* @__PURE__ */ jsx11("input", { type: "checkbox", checked: terms, onChange: (event) => setTerms(event.currentTarget.checked) }),
993
+ /* @__PURE__ */ jsx11("span", { children: data.included ? "I agree to the seat terms and the refund policy; the seat is included with my membership and follows its renewal." : data.autoRenew ? "I agree to the full initial payment and automatic renewal with my membership; I can cancel renewal." : "I agree to the full initial payment and the displayed end date, with no automatic renewal while my membership renewal is canceled." })
931
994
  ] }),
932
- terms && data.included ? /* @__PURE__ */ jsx10("button", { className: "btn primary", type: "button", disabled: granting, onClick: () => void grant(), children: granting ? "Sending the invitation\u2026" : "Send the invitation" }) : null,
933
- terms && !data.included ? /* @__PURE__ */ jsx10(
995
+ terms && data.included ? /* @__PURE__ */ jsx11("button", { className: "btn primary", type: "button", disabled: granting, onClick: () => void grant(), children: granting ? "Sending the invitation\u2026" : "Send the invitation" }) : null,
996
+ terms && !data.included ? /* @__PURE__ */ jsx11(
934
997
  PaymentStep,
935
998
  {
936
999
  applicationId: data.membershipId,
@@ -945,17 +1008,17 @@ function NamedSeatPurchase({ api }) {
945
1008
  }
946
1009
  ) : null
947
1010
  ] })
948
- ] }) : !data.seat ? /* @__PURE__ */ jsx10("p", { children: data.purchaseWindowed === false ? "An additional seat can be purchased for as long as your membership stays paid." : `Additional seats can be purchased until ${day(data.purchaseEndsAt)}.` }) : null,
949
- pending ? /* @__PURE__ */ jsx10("p", { role: "status", children: "Payment confirmation is being reconciled. The recipient\u2019s access begins only after their own acceptance and approval." }) : null
950
- ] }) : !error ? /* @__PURE__ */ jsx10("p", { children: "Loading your seat terms\u2026" }) : null,
951
- /* @__PURE__ */ jsx10("button", { className: "btn secondary", onClick: () => void load(), children: "Refresh seat status" })
1011
+ ] }) : !data.seat ? /* @__PURE__ */ jsx11("p", { children: data.purchaseWindowed === false ? "An additional seat can be purchased for as long as your membership stays paid." : `Additional seats can be purchased until ${day(data.purchaseEndsAt)}.` }) : null,
1012
+ pending ? /* @__PURE__ */ jsx11("p", { role: "status", children: "Payment confirmation is being reconciled. The recipient\u2019s access begins only after their own acceptance and approval." }) : null
1013
+ ] }) : !error ? /* @__PURE__ */ jsx11("p", { children: "Loading your seat terms\u2026" }) : null,
1014
+ /* @__PURE__ */ jsx11("button", { className: "btn secondary", onClick: () => void load(), children: "Refresh seat status" })
952
1015
  ] }) });
953
1016
  }
954
1017
 
955
1018
  // src/ui/member-content.tsx
956
1019
  import { useEffect as useEffect5, useMemo as useMemo2, useState as useState9 } from "preact/hooks";
957
1020
  import { Markdown } from "@odla-ai/ui/components";
958
- import { Fragment as Fragment5, jsx as jsx11, jsxs as jsxs11 } from "preact/jsx-runtime";
1021
+ import { Fragment as Fragment5, jsx as jsx12, jsxs as jsxs12 } from "preact/jsx-runtime";
959
1022
  var pageLabel = (page) => `${page.title}${page.access === "locked" ? " \xB7 Locked" : ""}`;
960
1023
  function MemberContentArea(props) {
961
1024
  const {
@@ -963,8 +1026,8 @@ function MemberContentArea(props) {
963
1026
  path = "/api/member-content",
964
1027
  upsellHref,
965
1028
  onUpsell,
966
- loadingContent = /* @__PURE__ */ jsx11("p", { className: "meeting-note", children: "Loading member pages\u2026" }),
967
- emptyContent = /* @__PURE__ */ jsx11("p", { className: "meeting-note", children: "No member pages have been published yet." })
1029
+ loadingContent = /* @__PURE__ */ jsx12("p", { className: "meeting-note", children: "Loading member pages\u2026" }),
1030
+ emptyContent = /* @__PURE__ */ jsx12("p", { className: "meeting-note", children: "No member pages have been published yet." })
968
1031
  } = props;
969
1032
  const [data, setData] = useState9(props.initialData ?? null);
970
1033
  const [error, setError] = useState9(null);
@@ -993,18 +1056,18 @@ function MemberContentArea(props) {
993
1056
  }
994
1057
  return [...result.entries()];
995
1058
  }, [data]);
996
- if (error) return /* @__PURE__ */ jsxs11("p", { className: "meeting-note", role: "alert", children: [
1059
+ if (error) return /* @__PURE__ */ jsxs12("p", { className: "meeting-note", role: "alert", children: [
997
1060
  "Member pages could not be loaded: ",
998
1061
  error
999
1062
  ] });
1000
- if (!data) return /* @__PURE__ */ jsx11(Fragment5, { children: loadingContent });
1001
- if (data.pages.length === 0) return /* @__PURE__ */ jsx11(Fragment5, { children: emptyContent });
1063
+ if (!data) return /* @__PURE__ */ jsx12(Fragment5, { children: loadingContent });
1064
+ if (data.pages.length === 0) return /* @__PURE__ */ jsx12(Fragment5, { children: emptyContent });
1002
1065
  const selected = data.pages.find((page) => page.id === selectedId) ?? data.pages[0];
1003
1066
  const href = selected.upsell && upsellHref ? upsellHref(selected.upsell.tierId, selected) : void 0;
1004
- return /* @__PURE__ */ jsxs11("div", { className: "chapter-member-content", "data-member-content": true, children: [
1005
- /* @__PURE__ */ jsx11("nav", { className: "chapter-member-content-nav", "aria-label": "Member pages", children: sections.map(([section, pages]) => /* @__PURE__ */ jsxs11("section", { className: "chapter-member-content-section", children: [
1006
- /* @__PURE__ */ jsx11("h2", { children: section }),
1007
- /* @__PURE__ */ jsx11("ul", { children: pages.map((page) => /* @__PURE__ */ jsx11("li", { "data-parent-page": page.navigation.parentId ?? void 0, children: /* @__PURE__ */ jsx11(
1067
+ return /* @__PURE__ */ jsxs12("div", { className: "chapter-member-content", "data-member-content": true, children: [
1068
+ /* @__PURE__ */ jsx12("nav", { className: "chapter-member-content-nav", "aria-label": "Member pages", children: sections.map(([section, pages]) => /* @__PURE__ */ jsxs12("section", { className: "chapter-member-content-section", children: [
1069
+ /* @__PURE__ */ jsx12("h2", { children: section }),
1070
+ /* @__PURE__ */ jsx12("ul", { children: pages.map((page) => /* @__PURE__ */ jsx12("li", { "data-parent-page": page.navigation.parentId ?? void 0, children: /* @__PURE__ */ jsx12(
1008
1071
  "button",
1009
1072
  {
1010
1073
  type: "button",
@@ -1014,23 +1077,23 @@ function MemberContentArea(props) {
1014
1077
  }
1015
1078
  ) }, page.id)) })
1016
1079
  ] }, section)) }),
1017
- /* @__PURE__ */ jsxs11("article", { className: "chapter-member-content-page", "data-access": selected.access, children: [
1018
- /* @__PURE__ */ jsxs11("header", { children: [
1019
- /* @__PURE__ */ jsxs11("div", { className: "card-label", children: [
1080
+ /* @__PURE__ */ jsxs12("article", { className: "chapter-member-content-page", "data-access": selected.access, children: [
1081
+ /* @__PURE__ */ jsxs12("header", { children: [
1082
+ /* @__PURE__ */ jsxs12("div", { className: "card-label", children: [
1020
1083
  selected.source.type === "parent" ? "Parent" : "Chapter",
1021
1084
  " \xB7 ",
1022
1085
  selected.access
1023
1086
  ] }),
1024
- /* @__PURE__ */ jsx11("h1", { children: selected.title }),
1025
- selected.summary ? /* @__PURE__ */ jsx11("p", { children: selected.summary }) : null
1087
+ /* @__PURE__ */ jsx12("h1", { children: selected.title }),
1088
+ selected.summary ? /* @__PURE__ */ jsx12("p", { children: selected.summary }) : null
1026
1089
  ] }),
1027
- selected.access === "allowed" && selected.bodyMarkdown ? /* @__PURE__ */ jsx11(Markdown, { source: selected.bodyMarkdown }) : /* @__PURE__ */ jsxs11("div", { className: "chapter-member-content-locked", children: [
1028
- selected.teaserMarkdown ? /* @__PURE__ */ jsx11(Markdown, { source: selected.teaserMarkdown }) : /* @__PURE__ */ jsx11("p", { children: "This page is not included in your current membership." }),
1029
- selected.upsell ? /* @__PURE__ */ jsxs11("aside", { className: "chapter-member-content-upsell", "aria-label": selected.upsell.label ?? "Membership option", children: [
1030
- /* @__PURE__ */ jsx11("h2", { children: selected.upsell.label ?? selected.upsell.tierName }),
1031
- /* @__PURE__ */ jsx11("p", { children: fmtMoney(selected.upsell.priceCents) }),
1032
- selected.upsell.bodyMarkdown ? /* @__PURE__ */ jsx11(Markdown, { source: selected.upsell.bodyMarkdown }) : null,
1033
- href ? /* @__PURE__ */ jsx11("a", { className: "btn primary", href, children: selected.upsell.ctaLabel ?? `Explore ${selected.upsell.tierName}` }) : onUpsell ? /* @__PURE__ */ jsx11("button", { className: "btn primary", type: "button", onClick: () => onUpsell(selected.upsell.tierId, selected), children: selected.upsell.ctaLabel ?? `Explore ${selected.upsell.tierName}` }) : null
1090
+ selected.access === "allowed" && selected.bodyMarkdown ? /* @__PURE__ */ jsx12(Markdown, { source: selected.bodyMarkdown }) : /* @__PURE__ */ jsxs12("div", { className: "chapter-member-content-locked", children: [
1091
+ selected.teaserMarkdown ? /* @__PURE__ */ jsx12(Markdown, { source: selected.teaserMarkdown }) : /* @__PURE__ */ jsx12("p", { children: "This page is not included in your current membership." }),
1092
+ selected.upsell ? /* @__PURE__ */ jsxs12("aside", { className: "chapter-member-content-upsell", "aria-label": selected.upsell.label ?? "Membership option", children: [
1093
+ /* @__PURE__ */ jsx12("h2", { children: selected.upsell.label ?? selected.upsell.tierName }),
1094
+ /* @__PURE__ */ jsx12("p", { children: fmtMoney(selected.upsell.priceCents) }),
1095
+ selected.upsell.bodyMarkdown ? /* @__PURE__ */ jsx12(Markdown, { source: selected.upsell.bodyMarkdown }) : null,
1096
+ href ? /* @__PURE__ */ jsx12("a", { className: "btn primary", href, children: selected.upsell.ctaLabel ?? `Explore ${selected.upsell.tierName}` }) : onUpsell ? /* @__PURE__ */ jsx12("button", { className: "btn primary", type: "button", onClick: () => onUpsell(selected.upsell.tierId, selected), children: selected.upsell.ctaLabel ?? `Explore ${selected.upsell.tierName}` }) : null
1034
1097
  ] }) : null
1035
1098
  ] })
1036
1099
  ] })
@@ -1038,12 +1101,12 @@ function MemberContentArea(props) {
1038
1101
  }
1039
1102
 
1040
1103
  // src/ui/members.tsx
1041
- import { Fragment as Fragment6, jsx as jsx12, jsxs as jsxs12 } from "preact/jsx-runtime";
1104
+ import { Fragment as Fragment6, jsx as jsx13, jsxs as jsxs13 } from "preact/jsx-runtime";
1042
1105
  function card(copy, kicker, body) {
1043
- return /* @__PURE__ */ jsxs12("div", { className: "card", children: [
1044
- /* @__PURE__ */ jsx12("div", { className: "card-label", children: copy.provisional.cardLabel }),
1045
- /* @__PURE__ */ jsxs12("div", { className: "meeting-block", children: [
1046
- /* @__PURE__ */ jsx12("div", { className: "meeting-kicker", children: kicker }),
1106
+ return /* @__PURE__ */ jsxs13("div", { className: "card", children: [
1107
+ /* @__PURE__ */ jsx13("div", { className: "card-label", children: copy.provisional.cardLabel }),
1108
+ /* @__PURE__ */ jsxs13("div", { className: "meeting-block", children: [
1109
+ /* @__PURE__ */ jsx13("div", { className: "meeting-kicker", children: kicker }),
1047
1110
  body
1048
1111
  ] })
1049
1112
  ] });
@@ -1054,9 +1117,9 @@ function ProvisionalCard(props) {
1054
1117
  return card(
1055
1118
  copy,
1056
1119
  copy.provisional.applicationNeeded,
1057
- /* @__PURE__ */ jsxs12(Fragment6, { children: [
1058
- /* @__PURE__ */ jsx12("div", { className: "meeting-note", children: copy.provisional.applicationNeededBody }),
1059
- /* @__PURE__ */ jsx12("a", { className: "apply-link", href: applyHref, children: copy.provisional.apply })
1120
+ /* @__PURE__ */ jsxs13(Fragment6, { children: [
1121
+ /* @__PURE__ */ jsx13("div", { className: "meeting-note", children: copy.provisional.applicationNeededBody }),
1122
+ /* @__PURE__ */ jsx13("a", { className: "apply-link", href: applyHref, children: copy.provisional.apply })
1060
1123
  ] })
1061
1124
  );
1062
1125
  }
@@ -1064,19 +1127,19 @@ function ProvisionalCard(props) {
1064
1127
  return card(
1065
1128
  copy,
1066
1129
  copy.provisional.refunded,
1067
- /* @__PURE__ */ jsx12("div", { className: "meeting-note", children: copy.provisional.refundedBody })
1130
+ /* @__PURE__ */ jsx13("div", { className: "meeting-note", children: copy.provisional.refundedBody })
1068
1131
  );
1069
1132
  }
1070
- const membership = application.paid ? /* @__PURE__ */ jsx12("div", { className: "meeting-note", children: application.renewalAt ? formatChapterCopy(copy.provisional.renews, { date: fmtDate(application.renewalAt) }) : copy.provisional.active }) : null;
1133
+ const membership = application.paid ? /* @__PURE__ */ jsx13("div", { className: "meeting-note", children: application.renewalAt ? formatChapterCopy(copy.provisional.renews, { date: fmtDate(application.renewalAt) }) : copy.provisional.active }) : null;
1071
1134
  if (application.meetingAt) {
1072
1135
  return card(
1073
1136
  copy,
1074
1137
  copy.provisional.introductionCall,
1075
- /* @__PURE__ */ jsxs12(Fragment6, { children: [
1076
- /* @__PURE__ */ jsx12("div", { className: "meeting-date", children: fullLabel(application.meetingAt, application.timezone) }),
1077
- /* @__PURE__ */ jsx12("div", { className: "meeting-note", children: copy.provisional.calendarInvite }),
1078
- application.meetUrl ? /* @__PURE__ */ jsx12("div", { className: "meeting-note", children: /* @__PURE__ */ jsx12("a", { href: application.meetUrl, target: "_blank", rel: "noopener", children: copy.provisional.joinCall }) }) : null,
1079
- /* @__PURE__ */ jsx12(
1138
+ /* @__PURE__ */ jsxs13(Fragment6, { children: [
1139
+ /* @__PURE__ */ jsx13("div", { className: "meeting-date", children: fullLabel(application.meetingAt, application.timezone) }),
1140
+ /* @__PURE__ */ jsx13("div", { className: "meeting-note", children: copy.provisional.calendarInvite }),
1141
+ application.meetUrl ? /* @__PURE__ */ jsx13("div", { className: "meeting-note", children: /* @__PURE__ */ jsx13("a", { href: application.meetUrl, target: "_blank", rel: "noopener", children: copy.provisional.joinCall }) }) : null,
1142
+ /* @__PURE__ */ jsx13(
1080
1143
  Rescheduler,
1081
1144
  {
1082
1145
  api,
@@ -1093,9 +1156,9 @@ function ProvisionalCard(props) {
1093
1156
  return card(
1094
1157
  copy,
1095
1158
  copy.provisional.bookCall,
1096
- /* @__PURE__ */ jsxs12(Fragment6, { children: [
1097
- /* @__PURE__ */ jsx12("div", { className: "meeting-note", children: copy.provisional.bookCallBody }),
1098
- /* @__PURE__ */ jsx12(
1159
+ /* @__PURE__ */ jsxs13(Fragment6, { children: [
1160
+ /* @__PURE__ */ jsx13("div", { className: "meeting-note", children: copy.provisional.bookCallBody }),
1161
+ /* @__PURE__ */ jsx13(
1099
1162
  Rescheduler,
1100
1163
  {
1101
1164
  api,
@@ -1134,22 +1197,22 @@ function MembersArea(props) {
1134
1197
  useEffect6(() => {
1135
1198
  void reload();
1136
1199
  }, []);
1137
- if (error) return /* @__PURE__ */ jsx12("p", { className: "meeting-note", children: copy.loadFailed });
1138
- if (!me) return /* @__PURE__ */ jsx12("p", { className: "meeting-note", children: inheritedCopy.common.loading });
1200
+ if (error) return /* @__PURE__ */ jsx13("p", { className: "meeting-note", children: copy.loadFailed });
1201
+ if (!me) return /* @__PURE__ */ jsx13("p", { className: "meeting-note", children: inheritedCopy.common.loading });
1139
1202
  const role = me.role || "provisional";
1140
- return /* @__PURE__ */ jsxs12(Fragment6, { children: [
1141
- /* @__PURE__ */ jsxs12("div", { className: "card", children: [
1142
- /* @__PURE__ */ jsxs12("div", { className: "member-row", children: [
1143
- /* @__PURE__ */ jsx12("span", { className: "member-email", children: me.email }),
1144
- /* @__PURE__ */ jsx12("span", { className: "role-badge " + role, children: role })
1203
+ return /* @__PURE__ */ jsxs13(Fragment6, { children: [
1204
+ /* @__PURE__ */ jsxs13("div", { className: "card", children: [
1205
+ /* @__PURE__ */ jsxs13("div", { className: "member-row", children: [
1206
+ /* @__PURE__ */ jsx13("span", { className: "member-email", children: me.email }),
1207
+ /* @__PURE__ */ jsx13("span", { className: "role-badge " + role, children: role })
1145
1208
  ] }),
1146
- /* @__PURE__ */ jsxs12("div", { className: "account-actions", children: [
1147
- /* @__PURE__ */ jsx12("button", { className: "btn secondary mini", onClick: signOut, children: copy.account.signOut }),
1148
- me.authorized || me.superAdmin ? /* @__PURE__ */ jsx12("a", { className: "admin-console-link", href: adminHref, children: copy.account.adminConsole }) : null
1209
+ /* @__PURE__ */ jsxs13("div", { className: "account-actions", children: [
1210
+ /* @__PURE__ */ jsx13("button", { className: "btn secondary mini", onClick: signOut, children: copy.account.signOut }),
1211
+ me.authorized || me.superAdmin ? /* @__PURE__ */ jsx13("a", { className: "admin-console-link", href: adminHref, children: copy.account.adminConsole }) : null
1149
1212
  ] })
1150
1213
  ] }),
1151
- me.memberAccess !== true && me.membershipRestart?.eligible && me.application ? /* @__PURE__ */ jsx12(MemberRestart, { api, application: me.application, applicationId: me.membershipRestart.applicationId, onComplete: reload }) : me.memberAccess !== true ? (() => {
1152
- const defaultContent = /* @__PURE__ */ jsx12(
1214
+ me.memberAccess !== true && me.membershipRestart?.eligible && me.application ? /* @__PURE__ */ jsx13(MemberRestart, { api, application: me.application, applicationId: me.membershipRestart.applicationId, onComplete: reload }) : me.memberAccess !== true ? (() => {
1215
+ const defaultContent = /* @__PURE__ */ jsx13(
1153
1216
  ProvisionalCard,
1154
1217
  {
1155
1218
  api,
@@ -1166,24 +1229,24 @@ function MembersArea(props) {
1166
1229
  reload,
1167
1230
  defaultContent
1168
1231
  }) ?? defaultContent;
1169
- })() : memberContent ?? (memberPages ? /* @__PURE__ */ jsx12(
1232
+ })() : memberContent ?? (memberPages ? /* @__PURE__ */ jsx13(
1170
1233
  MemberContentArea,
1171
1234
  {
1172
1235
  api,
1173
1236
  ...memberPages === true ? {} : memberPages
1174
1237
  }
1175
- ) : /* @__PURE__ */ jsx12("div", { className: "card", children: /* @__PURE__ */ jsx12("div", { className: "card-label", children: copy.full.welcome }) })),
1176
- /* @__PURE__ */ jsx12(GiftPurchases, { api, copy: copy.gifts, paymentCopy: inheritedCopy.join.payment }),
1177
- me.namedSeatsEnabled ? /* @__PURE__ */ jsx12(NamedSeatPurchase, { api }) : null
1238
+ ) : /* @__PURE__ */ jsx13("div", { className: "card", children: /* @__PURE__ */ jsx13("div", { className: "card-label", children: copy.full.welcome }) })),
1239
+ /* @__PURE__ */ jsx13(GiftPurchases, { api, copy: copy.gifts, paymentCopy: inheritedCopy.join.payment }),
1240
+ me.namedSeatsEnabled ? /* @__PURE__ */ jsx13(NamedSeatPurchase, { api }) : null
1178
1241
  ] });
1179
1242
  }
1180
1243
 
1181
1244
  // src/ui/join.tsx
1182
- import { useEffect as useEffect10, useRef as useRef3, useState as useState17 } from "preact/hooks";
1245
+ import { useEffect as useEffect11, useRef as useRef3, useState as useState18 } from "preact/hooks";
1183
1246
 
1184
1247
  // src/ui/join-booking.tsx
1185
1248
  import { useEffect as useEffect7, useState as useState11 } from "preact/hooks";
1186
- import { jsx as jsx13, jsxs as jsxs13 } from "preact/jsx-runtime";
1249
+ import { jsx as jsx14, jsxs as jsxs14 } from "preact/jsx-runtime";
1187
1250
  function JoinBooking(props) {
1188
1251
  const { applicationId, copy, onBooked, simulation } = props;
1189
1252
  const [state, setState] = useState11(null);
@@ -1246,11 +1309,11 @@ function JoinBooking(props) {
1246
1309
  setBusy(false);
1247
1310
  }
1248
1311
  };
1249
- if (!state) return /* @__PURE__ */ jsx13("p", { className: "slots-status", children: msg ?? copy.loading });
1250
- return /* @__PURE__ */ jsxs13("div", { className: "join-book", children: [
1251
- /* @__PURE__ */ jsx13("h2", { children: copy.title ?? DEFAULT_JOIN_COPY.booking.title }),
1252
- /* @__PURE__ */ jsx13("p", { children: copy.intro ?? DEFAULT_JOIN_COPY.booking.intro }),
1253
- /* @__PURE__ */ jsx13(
1312
+ if (!state) return /* @__PURE__ */ jsx14("p", { className: "slots-status", children: msg ?? copy.loading });
1313
+ return /* @__PURE__ */ jsxs14("div", { className: "join-book", children: [
1314
+ /* @__PURE__ */ jsx14("h2", { children: copy.title ?? DEFAULT_JOIN_COPY.booking.title }),
1315
+ /* @__PURE__ */ jsx14("p", { children: copy.intro ?? DEFAULT_JOIN_COPY.booking.intro }),
1316
+ /* @__PURE__ */ jsx14(
1254
1317
  SlotPicker,
1255
1318
  {
1256
1319
  slots: state.slots,
@@ -1260,26 +1323,26 @@ function JoinBooking(props) {
1260
1323
  onDayChange: () => setSelected(null)
1261
1324
  }
1262
1325
  ),
1263
- /* @__PURE__ */ jsxs13("div", { className: "slot-confirm", hidden: !selected, children: [
1264
- /* @__PURE__ */ jsx13("button", { className: "submit-btn", disabled: busy, onClick: () => void book(), children: busy ? copy.booking : copy.book }),
1265
- msg ? /* @__PURE__ */ jsx13("p", { className: "step2-note", children: msg }) : null
1326
+ /* @__PURE__ */ jsxs14("div", { className: "slot-confirm", hidden: !selected, children: [
1327
+ /* @__PURE__ */ jsx14("button", { className: "submit-btn", disabled: busy, onClick: () => void book(), children: busy ? copy.booking : copy.book }),
1328
+ msg ? /* @__PURE__ */ jsx14("p", { className: "step2-note", children: msg }) : null
1266
1329
  ] })
1267
1330
  ] });
1268
1331
  }
1269
1332
 
1270
1333
  // src/ui/join-accepted.tsx
1271
- import { jsx as jsx14, jsxs as jsxs14 } from "preact/jsx-runtime";
1334
+ import { jsx as jsx15, jsxs as jsxs15 } from "preact/jsx-runtime";
1272
1335
  function JoinAccepted(props) {
1273
- return /* @__PURE__ */ jsxs14("div", { className: "join-done card", children: [
1274
- /* @__PURE__ */ jsx14("div", { className: "card-label", children: props.copy.accepted.label }),
1275
- /* @__PURE__ */ jsx14("p", { className: "meeting-note", children: props.copy.accepted.body }),
1276
- /* @__PURE__ */ jsx14("a", { className: "apply-link", href: props.membersHref, children: props.copy.done.memberArea })
1336
+ return /* @__PURE__ */ jsxs15("div", { className: "join-done card", children: [
1337
+ /* @__PURE__ */ jsx15("div", { className: "card-label", children: props.copy.accepted.label }),
1338
+ /* @__PURE__ */ jsx15("p", { className: "meeting-note", children: props.copy.accepted.body }),
1339
+ /* @__PURE__ */ jsx15("a", { className: "apply-link", href: props.membersHref, children: props.copy.done.memberArea })
1277
1340
  ] });
1278
1341
  }
1279
1342
 
1280
1343
  // src/ui/gift-claim-card.tsx
1281
1344
  import { useState as useState12 } from "preact/hooks";
1282
- import { Fragment as Fragment7, jsx as jsx15, jsxs as jsxs15 } from "preact/jsx-runtime";
1345
+ import { Fragment as Fragment7, jsx as jsx16, jsxs as jsxs16 } from "preact/jsx-runtime";
1283
1346
  function GiftClaimCard(props) {
1284
1347
  const [code, setCode] = useState12(props.initialCode ?? "");
1285
1348
  const [error, setError] = useState12(false);
@@ -1295,21 +1358,21 @@ function GiftClaimCard(props) {
1295
1358
  if (response.ok && body.code) setCode(body.code);
1296
1359
  else setError(true);
1297
1360
  };
1298
- return /* @__PURE__ */ jsxs15("div", { className: "join-done card", children: [
1299
- /* @__PURE__ */ jsx15("div", { className: "card-label", children: props.copy.label }),
1300
- /* @__PURE__ */ jsx15("p", { className: "meeting-note", children: props.copy.body }),
1301
- code ? /* @__PURE__ */ jsxs15(Fragment7, { children: [
1302
- /* @__PURE__ */ jsx15("output", { className: "gift-code", children: code }),
1303
- /* @__PURE__ */ jsx15("p", { children: props.copy.save })
1361
+ return /* @__PURE__ */ jsxs16("div", { className: "join-done card", children: [
1362
+ /* @__PURE__ */ jsx16("div", { className: "card-label", children: props.copy.label }),
1363
+ /* @__PURE__ */ jsx16("p", { className: "meeting-note", children: props.copy.body }),
1364
+ code ? /* @__PURE__ */ jsxs16(Fragment7, { children: [
1365
+ /* @__PURE__ */ jsx16("output", { className: "gift-code", children: code }),
1366
+ /* @__PURE__ */ jsx16("p", { children: props.copy.save })
1304
1367
  ] }) : null,
1305
- !code && props.claimId ? /* @__PURE__ */ jsx15("button", { type: "button", className: "btn secondary", onClick: () => void rotate(), children: props.copy.rotate }) : null,
1306
- error ? /* @__PURE__ */ jsx15("p", { role: "alert", children: props.copy.rotateFailed }) : null
1368
+ !code && props.claimId ? /* @__PURE__ */ jsx16("button", { type: "button", className: "btn secondary", onClick: () => void rotate(), children: props.copy.rotate }) : null,
1369
+ error ? /* @__PURE__ */ jsx16("p", { role: "alert", children: props.copy.rotateFailed }) : null
1307
1370
  ] });
1308
1371
  }
1309
1372
 
1310
1373
  // src/ui/join-tiers.tsx
1311
1374
  import { useState as useState13 } from "preact/hooks";
1312
- import { Fragment as Fragment8, jsx as jsx16, jsxs as jsxs16 } from "preact/jsx-runtime";
1375
+ import { Fragment as Fragment8, jsx as jsx17, jsxs as jsxs17 } from "preact/jsx-runtime";
1313
1376
  var joinTierMoney = (cents, currency = "usd") => new Intl.NumberFormat("en-US", { style: "currency", currency }).format(cents / 100);
1314
1377
  function useTierSelection(tiers, initialTierId) {
1315
1378
  const [selectedTierId, setSelectedTierId] = useState13(() => {
@@ -1318,7 +1381,7 @@ function useTierSelection(tiers, initialTierId) {
1318
1381
  return tiers.length === 1 ? tiers[0].id : null;
1319
1382
  });
1320
1383
  return {
1321
- tiers,
1384
+ tiers: [...tiers].sort((a, b) => Number(b.id === selectedTierId) - Number(a.id === selectedTierId)),
1322
1385
  selected: tiers.find((tier) => tier.id === selectedTierId) ?? null,
1323
1386
  selectedTierId,
1324
1387
  selectTier: (tierId) => {
@@ -1327,10 +1390,10 @@ function useTierSelection(tiers, initialTierId) {
1327
1390
  };
1328
1391
  }
1329
1392
  function TierPlaceholder(context) {
1330
- return /* @__PURE__ */ jsxs16("fieldset", { "data-chapter-placeholder": "tiers", children: [
1331
- /* @__PURE__ */ jsx16("legend", { children: "Membership (placeholder \u2014 pass renderTiers to style this)" }),
1332
- context.tiers.map((tier) => /* @__PURE__ */ jsxs16("label", { children: [
1333
- /* @__PURE__ */ jsx16(
1393
+ return /* @__PURE__ */ jsxs17("fieldset", { "data-chapter-placeholder": "tiers", children: [
1394
+ /* @__PURE__ */ jsx17("legend", { children: "Membership (placeholder \u2014 pass renderTiers to style this)" }),
1395
+ context.tiers.map((tier) => /* @__PURE__ */ jsxs17("label", { children: [
1396
+ /* @__PURE__ */ jsx17(
1334
1397
  "input",
1335
1398
  {
1336
1399
  type: "radio",
@@ -1341,13 +1404,13 @@ function TierPlaceholder(context) {
1341
1404
  }
1342
1405
  ),
1343
1406
  tier.name,
1344
- tier.founding ? /* @__PURE__ */ jsxs16(Fragment8, { children: [
1407
+ tier.founding ? /* @__PURE__ */ jsxs17(Fragment8, { children: [
1345
1408
  " \u2014 ",
1346
1409
  joinTierMoney(tier.founding.dueTodayCents),
1347
1410
  " founding member rate (list ",
1348
1411
  joinTierMoney(tier.priceCents),
1349
1412
  ")"
1350
- ] }) : tier.free ? " \u2014 free" : /* @__PURE__ */ jsxs16(Fragment8, { children: [
1413
+ ] }) : tier.free ? " \u2014 free" : /* @__PURE__ */ jsxs17(Fragment8, { children: [
1351
1414
  " \u2014 ",
1352
1415
  joinTierMoney(tier.priceCents)
1353
1416
  ] })
@@ -1359,19 +1422,19 @@ function tierNeedsPayment(selected, paymentsReady) {
1359
1422
  }
1360
1423
 
1361
1424
  // src/ui/join-application-form.tsx
1362
- import { jsx as jsx17, jsxs as jsxs17 } from "preact/jsx-runtime";
1425
+ import { jsx as jsx18, jsxs as jsxs18 } from "preact/jsx-runtime";
1363
1426
  function JoinApplicationForm({ props, copy, invitation, requestedSeat, tierSelection, giftOfferId, selectGift, submitting, error, submit }) {
1364
1427
  const disabled = submitting || props.submitDisabled === true;
1365
- return /* @__PURE__ */ jsxs17("form", { className: "join-form", onSubmit: (event) => void submit(event), children: [
1366
- !requestedSeat && (props.config.giftOffers?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs17("fieldset", { children: [
1367
- /* @__PURE__ */ jsx17("legend", { children: copy.gift.optionsLabel }),
1368
- /* @__PURE__ */ jsx17("button", { type: "button", className: "btn secondary", "aria-pressed": !giftOfferId, onClick: () => selectGift(null), children: copy.gift.chooseSelf }),
1369
- /* @__PURE__ */ jsx17(GiftOfferCards, { offers: props.config.giftOffers ?? [], mode: "select", selectedOfferId: giftOfferId, onSelect: selectGift })
1428
+ return /* @__PURE__ */ jsxs18("form", { className: "join-form", onSubmit: (event) => void submit(event), children: [
1429
+ !requestedSeat && (props.config.giftOffers?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs18("fieldset", { children: [
1430
+ /* @__PURE__ */ jsx18("legend", { children: copy.gift.optionsLabel }),
1431
+ /* @__PURE__ */ jsx18("button", { type: "button", className: "btn secondary", "aria-pressed": !giftOfferId, onClick: () => selectGift(null), children: copy.gift.chooseSelf }),
1432
+ /* @__PURE__ */ jsx18(GiftOfferCards, { offers: props.config.giftOffers ?? [], mode: "select", selectedOfferId: giftOfferId, onSelect: selectGift })
1370
1433
  ] }) : null,
1371
1434
  !requestedSeat && (props.config.tiers?.length ?? 0) > 1 ? props.renderTiers?.(tierSelection) ?? TierPlaceholder(tierSelection) : null,
1372
1435
  typeof props.children === "function" ? props.children({ invitation }) : props.children,
1373
- error ? /* @__PURE__ */ jsx17("p", { className: "join-error", role: "alert", children: error }) : null,
1374
- props.renderSubmit?.({ submitting, disabled }) ?? /* @__PURE__ */ jsx17("button", { className: "submit-btn", type: "submit", disabled, children: submitting ? copy.form.submitting : copy.form.submit })
1436
+ error ? /* @__PURE__ */ jsx18("p", { className: "join-error", role: "alert", children: error }) : null,
1437
+ props.renderSubmit?.({ submitting, disabled }) ?? /* @__PURE__ */ jsx18("button", { className: "submit-btn", type: "submit", disabled, children: submitting ? copy.form.submitting : copy.form.submit })
1375
1438
  ] });
1376
1439
  }
1377
1440
 
@@ -1397,7 +1460,7 @@ function joinStateFromApplicationResponse(data, fallbackNeedsPayment, submittedG
1397
1460
  // src/ui/gift-code-redeemer.tsx
1398
1461
  import { InlineActionField } from "@odla-ai/ui/components";
1399
1462
  import { useState as useState14 } from "preact/hooks";
1400
- import { Fragment as Fragment9, jsx as jsx18, jsxs as jsxs18 } from "preact/jsx-runtime";
1463
+ import { Fragment as Fragment9, jsx as jsx19, jsxs as jsxs19 } from "preact/jsx-runtime";
1401
1464
  var GIFT_CODE_REDEEMER_CSS = `
1402
1465
  .gift-code-redeemer{container-type:inline-size;display:grid;gap:var(--ui-space-1,.35rem);margin:0}
1403
1466
  .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}
@@ -1442,9 +1505,9 @@ function GiftCodeRedeemer({ api, applicationId, copy, id, onRedeemed }) {
1442
1505
  setLoading(false);
1443
1506
  }
1444
1507
  };
1445
- return /* @__PURE__ */ jsxs18(Fragment9, { children: [
1446
- /* @__PURE__ */ jsx18("style", { children: GIFT_CODE_REDEEMER_CSS }),
1447
- /* @__PURE__ */ jsx18(
1508
+ return /* @__PURE__ */ jsxs19(Fragment9, { children: [
1509
+ /* @__PURE__ */ jsx19("style", { children: GIFT_CODE_REDEEMER_CSS }),
1510
+ /* @__PURE__ */ jsx19(
1448
1511
  InlineActionField,
1449
1512
  {
1450
1513
  id,
@@ -1500,12 +1563,12 @@ async function loadJoinResume(applicationId, fetcher = fetch) {
1500
1563
  }
1501
1564
 
1502
1565
  // src/ui/join-gift-claim.tsx
1503
- import { jsx as jsx19, jsxs as jsxs19 } from "preact/jsx-runtime";
1566
+ import { jsx as jsx20, jsxs as jsxs20 } from "preact/jsx-runtime";
1504
1567
  function JoinGiftClaim(props) {
1505
- return /* @__PURE__ */ jsxs19("section", { className: "join-gift-claim card", children: [
1506
- /* @__PURE__ */ jsx19("div", { className: "card-label", children: props.copy.claimTitle }),
1507
- /* @__PURE__ */ jsx19("p", { children: props.copy.claimBody }),
1508
- /* @__PURE__ */ jsx19(
1568
+ return /* @__PURE__ */ jsxs20("section", { className: "join-gift-claim card", children: [
1569
+ /* @__PURE__ */ jsx20("div", { className: "card-label", children: props.copy.claimTitle }),
1570
+ /* @__PURE__ */ jsx20("p", { children: props.copy.claimBody }),
1571
+ /* @__PURE__ */ jsx20(
1509
1572
  GiftCodeRedeemer,
1510
1573
  {
1511
1574
  api: props.api,
@@ -1530,20 +1593,20 @@ function JoinGiftClaim(props) {
1530
1593
 
1531
1594
  // src/ui/join-named-seat.tsx
1532
1595
  import { useState as useState15 } from "preact/hooks";
1533
- import { jsx as jsx20, jsxs as jsxs20 } from "preact/jsx-runtime";
1596
+ import { jsx as jsx21, jsxs as jsxs21 } from "preact/jsx-runtime";
1534
1597
  function JoinNamedSeat(props) {
1535
1598
  const seatId = props.seatId ?? "";
1536
1599
  const inherited = useChapterCopy(), copy = props.copy ?? inherited.join.namedSeat;
1537
1600
  const [accepted, setAccepted] = useState15(false), [busy, setBusy] = useState15(false), [error, setError] = useState15("");
1538
- return /* @__PURE__ */ jsxs20("section", { className: "join-named-seat card", children: [
1539
- /* @__PURE__ */ jsx20("h2", { children: copy.title }),
1540
- /* @__PURE__ */ jsx20("p", { children: copy.body }),
1541
- /* @__PURE__ */ jsxs20("label", { className: "journey-consent", children: [
1542
- /* @__PURE__ */ jsx20("input", { type: "checkbox", checked: accepted, disabled: busy, onChange: (event) => setAccepted(event.currentTarget.checked) }),
1543
- /* @__PURE__ */ jsx20("span", { children: copy.consent })
1601
+ return /* @__PURE__ */ jsxs21("section", { className: "join-named-seat card", children: [
1602
+ /* @__PURE__ */ jsx21("h2", { children: copy.title }),
1603
+ /* @__PURE__ */ jsx21("p", { children: copy.body }),
1604
+ /* @__PURE__ */ jsxs21("label", { className: "journey-consent", children: [
1605
+ /* @__PURE__ */ jsx21("input", { type: "checkbox", checked: accepted, disabled: busy, onChange: (event) => setAccepted(event.currentTarget.checked) }),
1606
+ /* @__PURE__ */ jsx21("span", { children: copy.consent })
1544
1607
  ] }),
1545
- error ? /* @__PURE__ */ jsx20("p", { role: "alert", children: error }) : null,
1546
- /* @__PURE__ */ jsx20("button", { type: "button", className: "btn btn-primary", disabled: busy || !accepted || !seatId.trim(), onClick: async () => {
1608
+ error ? /* @__PURE__ */ jsx21("p", { role: "alert", children: error }) : null,
1609
+ /* @__PURE__ */ jsx21("button", { type: "button", className: "btn btn-primary", disabled: busy || !accepted || !seatId.trim(), onClick: async () => {
1547
1610
  setBusy(true);
1548
1611
  setError("");
1549
1612
  try {
@@ -1564,7 +1627,7 @@ function JoinNamedSeat(props) {
1564
1627
 
1565
1628
  // src/ui/join-invitation.tsx
1566
1629
  import { useEffect as useEffect8, useState as useState16 } from "preact/hooks";
1567
- import { jsx as jsx21, jsxs as jsxs21 } from "preact/jsx-runtime";
1630
+ import { jsx as jsx22, jsxs as jsxs22 } from "preact/jsx-runtime";
1568
1631
  function useJoinInvitation(seatId, api, fallback) {
1569
1632
  const [invitation, setInvitation] = useState16(null);
1570
1633
  const [error, setError] = useState16("");
@@ -1591,12 +1654,22 @@ function useJoinInvitation(seatId, api, fallback) {
1591
1654
  return { invitation: invitation?.seatId === seatId ? invitation : null, error, retry: () => setRevision((value) => value + 1) };
1592
1655
  }
1593
1656
  function JoinInvitationNotice(props) {
1594
- return /* @__PURE__ */ jsxs21("aside", { className: "journey-invitation", "aria-label": props.copy.title, children: [
1595
- /* @__PURE__ */ jsx21("p", { children: /* @__PURE__ */ jsx21("strong", { children: formatChapterCopy(props.copy.from, { purchaserName: props.invitation.purchaserName }) }) }),
1596
- /* @__PURE__ */ jsx21("p", { children: formatChapterCopy(props.copy.prepaid, { tierName: props.tierName }) })
1657
+ return /* @__PURE__ */ jsxs22("aside", { className: "journey-invitation", "aria-label": props.copy.title, children: [
1658
+ /* @__PURE__ */ jsx22("p", { children: /* @__PURE__ */ jsx22("strong", { children: formatChapterCopy(props.copy.from, { purchaserName: props.invitation.purchaserName }) }) }),
1659
+ /* @__PURE__ */ jsx22("p", { children: formatChapterCopy(props.copy.prepaid, { tierName: props.tierName }) })
1597
1660
  ] });
1598
1661
  }
1599
1662
 
1663
+ // src/ui/join-simulation.ts
1664
+ function joinSimulationPayment(simulation, priceCents) {
1665
+ if (!simulation) return void 0;
1666
+ return simulation.payment ?? { lineItems: {
1667
+ standardCents: priceCents,
1668
+ discountCents: 0,
1669
+ dueTodayCents: priceCents
1670
+ } };
1671
+ }
1672
+
1600
1673
  // src/ui/join-pending.ts
1601
1674
  import { useEffect as useEffect9 } from "preact/hooks";
1602
1675
  function useJoinPending(state, loadResume, setState) {
@@ -1622,10 +1695,100 @@ function useJoinPending(state, loadResume, setState) {
1622
1695
  }, [state, loadResume]);
1623
1696
  }
1624
1697
 
1698
+ // src/ui/payment-receipt.tsx
1699
+ import { useEffect as useEffect10, useState as useState17 } from "preact/hooks";
1700
+ import { Fragment as Fragment10, jsx as jsx23, jsxs as jsxs23 } from "preact/jsx-runtime";
1701
+ function PaymentReceiptCard({ applicationId }) {
1702
+ const [receipt, setReceipt] = useState17(null);
1703
+ const [error, setError] = useState17("");
1704
+ const [revision, setRevision] = useState17(0);
1705
+ const [emailState, setEmailState] = useState17("idle");
1706
+ const [previewEmail, setPreviewEmail] = useState17(false);
1707
+ const endpoint = `/api/payments/receipt?application=${encodeURIComponent(applicationId)}`;
1708
+ useEffect10(() => {
1709
+ let live = true, timer;
1710
+ setReceipt(null);
1711
+ setError("");
1712
+ setEmailState("idle");
1713
+ const read = async () => {
1714
+ try {
1715
+ const response = await fetch(endpoint, { cache: "no-store" });
1716
+ if (!live || response.status === 404) return;
1717
+ if (response.status === 202) {
1718
+ timer = setTimeout(() => void read(), 2e3);
1719
+ return;
1720
+ }
1721
+ if (!response.ok) throw new Error();
1722
+ const data = await response.json();
1723
+ if (live) setReceipt(data.receipt);
1724
+ } catch {
1725
+ if (live) setError("Your receipt is temporarily unavailable.");
1726
+ }
1727
+ };
1728
+ void read();
1729
+ return () => {
1730
+ live = false;
1731
+ if (timer) clearTimeout(timer);
1732
+ };
1733
+ }, [endpoint, revision]);
1734
+ if (!receipt) return error ? /* @__PURE__ */ jsxs23("section", { "aria-label": "Payment receipt", children: [
1735
+ /* @__PURE__ */ jsx23("p", { role: "status", children: error }),
1736
+ /* @__PURE__ */ jsx23("button", { type: "button", onClick: () => setRevision((value) => value + 1), children: "Reload receipt" })
1737
+ ] }) : null;
1738
+ const money = (cents) => new Intl.NumberFormat("en-US", { style: "currency", currency: receipt.currency }).format(cents / 100);
1739
+ const email = async () => {
1740
+ setEmailState("sending");
1741
+ setError("");
1742
+ try {
1743
+ const response = await fetch(endpoint, { method: "POST" });
1744
+ if (!response.ok) throw new Error();
1745
+ const result = await response.json();
1746
+ setPreviewEmail(result.preview === true);
1747
+ setEmailState("sent");
1748
+ } catch {
1749
+ setEmailState("idle");
1750
+ setError("We could not confirm email delivery. You can print or save your receipt.");
1751
+ }
1752
+ };
1753
+ return /* @__PURE__ */ jsxs23("section", { className: "payment-receipt card", "aria-label": "Payment receipt", children: [
1754
+ /* @__PURE__ */ jsx23("h2", { children: "Payment received" }),
1755
+ /* @__PURE__ */ jsx23("p", { children: receipt.tierName }),
1756
+ /* @__PURE__ */ jsxs23("dl", { className: "journey-summary", children: [
1757
+ /* @__PURE__ */ jsx23("dt", { children: "Membership" }),
1758
+ /* @__PURE__ */ jsx23("dd", { children: money(receipt.membershipCents) }),
1759
+ receipt.namedSeat ? /* @__PURE__ */ jsxs23(Fragment10, { children: [
1760
+ /* @__PURE__ */ jsxs23("dt", { children: [
1761
+ "Additional member \u2014 ",
1762
+ receipt.namedSeat.recipientName
1763
+ ] }),
1764
+ /* @__PURE__ */ jsxs23("dd", { children: [
1765
+ receipt.namedSeat.amountCents === 0 ? "Included \u2014 " : "",
1766
+ money(receipt.namedSeat.amountCents)
1767
+ ] })
1768
+ ] }) : null,
1769
+ /* @__PURE__ */ jsx23("dt", { children: "Total paid" }),
1770
+ /* @__PURE__ */ jsx23("dd", { children: money(receipt.totalCents) })
1771
+ ] }),
1772
+ /* @__PURE__ */ jsxs23("div", { className: "journey-actions", children: [
1773
+ /* @__PURE__ */ jsx23("a", { className: "apply-link journey-secondary", href: `${endpoint}&format=html`, target: "_blank", rel: "noopener noreferrer", children: "Print / save receipt" }),
1774
+ /* @__PURE__ */ jsx23("button", { type: "button", disabled: emailState !== "idle", onClick: () => void email(), children: emailState === "sending" ? "Sending\u2026" : emailState === "sent" ? "Receipt emailed" : "Email me my receipt" })
1775
+ ] }),
1776
+ emailState === "sent" ? /* @__PURE__ */ jsx23("p", { role: "status", children: previewEmail ? "Test receipt sent to the configured test inbox." : "Sent to the email used for your payment." }) : null,
1777
+ error ? /* @__PURE__ */ jsx23("p", { role: "alert", children: error }) : null
1778
+ ] });
1779
+ }
1780
+
1781
+ // src/ui/join-recipient.ts
1782
+ function validJoinRecipient(recipient) {
1783
+ if (!recipient) return true;
1784
+ const name = recipient.recipientName.trim(), email = recipient.recipientEmail.trim();
1785
+ return name.length >= 2 && name.length <= 160 && !/[\u0000-\u001f\u007f]/.test(name) && email.length <= 254 && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
1786
+ }
1787
+
1625
1788
  // src/ui/join.tsx
1626
- import { Fragment as Fragment10, jsx as jsx22, jsxs as jsxs22 } from "preact/jsx-runtime";
1789
+ import { Fragment as Fragment11, jsx as jsx24, jsxs as jsxs24 } from "preact/jsx-runtime";
1627
1790
  function JoinIsland(props) {
1628
- return /* @__PURE__ */ jsx22(JourneyFrame, { children: /* @__PURE__ */ jsx22(JoinFlow, { ...props }) });
1791
+ return /* @__PURE__ */ jsx24(JourneyFrame, { children: /* @__PURE__ */ jsx24(JoinFlow, { ...props }) });
1629
1792
  }
1630
1793
  function JoinFlow(props) {
1631
1794
  const inheritedCopy = useChapterCopy();
@@ -1646,20 +1809,15 @@ function JoinFlow(props) {
1646
1809
  const invitation = invitationState.invitation;
1647
1810
  const selectedTierId = invitation?.skuId ?? tierSelection.selectedTierId;
1648
1811
  const selectedTier = tiers.find((tier) => tier.id === selectedTierId) ?? tierSelection.selected;
1649
- const [state, setState] = useState17(requestedSeat ? { step: "form" } : props.initialState ?? { step: "form" });
1650
- const [error, setError] = useState17(null);
1651
- const [submitting, setSubmitting] = useState17(false);
1652
- const [giftOfferId, setGiftOfferId] = useState17(props.initialGiftOfferId ?? null);
1653
- const simulatedPayment = props.simulation ? props.simulation.payment ?? {
1654
- lineItems: {
1655
- standardCents: selectedTier?.priceCents ?? 0,
1656
- discountCents: 0,
1657
- dueTodayCents: selectedTier?.priceCents ?? 0
1658
- }
1659
- } : void 0;
1812
+ const [state, setState] = useState18(requestedSeat ? { step: "form" } : props.initialState ?? { step: "form" });
1813
+ const [error, setError] = useState18(null);
1814
+ const [submitting, setSubmitting] = useState18(false);
1815
+ const [editingNamedSeat, setEditingNamedSeat] = useState18(false);
1816
+ const [giftOfferId, setGiftOfferId] = useState18(props.initialGiftOfferId ?? null);
1817
+ const simulatedPayment = joinSimulationPayment(props.simulation, selectedTier?.priceCents ?? 0);
1660
1818
  const simulatedBooking = props.simulation ? props.simulation.booking ?? { slots: [], timezone: "UTC" } : void 0;
1661
1819
  const submissionId = useRef3(null);
1662
- useEffect10(() => {
1820
+ useEffect11(() => {
1663
1821
  if (props.simulation) return;
1664
1822
  const resolver = requestedSeat ? () => invitation?.applicationId ? loadJoinResume(invitation.applicationId) : Promise.resolve(null) : props.loadResume ?? (() => {
1665
1823
  if (typeof window === "undefined") return Promise.resolve(null);
@@ -1680,6 +1838,10 @@ function JoinFlow(props) {
1680
1838
  const submit = async (e) => {
1681
1839
  e.preventDefault();
1682
1840
  if (submitting || props.submitDisabled === true || requestedSeat && !invitation) return;
1841
+ if (!validJoinRecipient(props.payment?.initialNamedSeat)) {
1842
+ setError("Enter your family member's full name and valid email before continuing.");
1843
+ return;
1844
+ }
1683
1845
  setSubmitting(true);
1684
1846
  setError(null);
1685
1847
  try {
@@ -1728,13 +1890,13 @@ function JoinFlow(props) {
1728
1890
  setSubmitting(false);
1729
1891
  }
1730
1892
  };
1731
- if (requestedSeat && !invitation) return /* @__PURE__ */ jsxs22("section", { className: "card", "aria-live": "polite", children: [
1732
- /* @__PURE__ */ jsx22("h2", { children: seatCopy.title }),
1733
- /* @__PURE__ */ jsx22("p", { role: invitationState.error ? "alert" : "status", children: invitationState.error || seatCopy.loading }),
1734
- invitationState.error ? /* @__PURE__ */ jsx22("button", { type: "button", onClick: invitationState.retry, children: seatCopy.retry }) : null
1893
+ if (requestedSeat && !invitation) return /* @__PURE__ */ jsxs24("section", { className: "card", "aria-live": "polite", children: [
1894
+ /* @__PURE__ */ jsx24("h2", { children: seatCopy.title }),
1895
+ /* @__PURE__ */ jsx24("p", { role: invitationState.error ? "alert" : "status", children: invitationState.error || seatCopy.loading }),
1896
+ invitationState.error ? /* @__PURE__ */ jsx24("button", { type: "button", onClick: invitationState.retry, children: seatCopy.retry }) : null
1735
1897
  ] });
1736
- const header = /* @__PURE__ */ jsxs22(Fragment10, { children: [
1737
- invitation ? /* @__PURE__ */ jsx22(
1898
+ const header = /* @__PURE__ */ jsxs24(Fragment11, { children: [
1899
+ invitation ? /* @__PURE__ */ jsx24(
1738
1900
  JoinInvitationNotice,
1739
1901
  {
1740
1902
  invitation,
@@ -1744,50 +1906,52 @@ function JoinFlow(props) {
1744
1906
  ) : null,
1745
1907
  renderStepHeader?.({
1746
1908
  state,
1909
+ editingNamedSeat: state.step === "payment" && editingNamedSeat,
1747
1910
  ...invitation ? { invitation } : {},
1748
1911
  ..."applicationId" in state ? { applicationId: state.applicationId } : {}
1749
- })
1912
+ }),
1913
+ !props.simulation && !requestedSeat && ["paymentPending", "booking", "accepted", "done"].includes(state.step) && "applicationId" in state ? /* @__PURE__ */ jsx24(PaymentReceiptCard, { applicationId: state.applicationId }) : null
1750
1914
  ] });
1751
1915
  if (state.step === "closed") {
1752
- return /* @__PURE__ */ jsxs22(Fragment10, { children: [
1916
+ return /* @__PURE__ */ jsxs24(Fragment11, { children: [
1753
1917
  header,
1754
- /* @__PURE__ */ jsxs22("section", { className: "card", "aria-label": "Application closed", children: [
1755
- /* @__PURE__ */ jsx22("h2", { children: "This application is closed" }),
1756
- /* @__PURE__ */ jsx22("p", { children: "This link cannot resume payment or booking. Sign in to view your application status, or contact the chapter if you need help." }),
1757
- /* @__PURE__ */ jsx22("a", { className: "apply-link", href: membersHref, children: copy.done.memberArea })
1918
+ /* @__PURE__ */ jsxs24("section", { className: "card", "aria-label": "Application closed", children: [
1919
+ /* @__PURE__ */ jsx24("h2", { children: "This application is closed" }),
1920
+ /* @__PURE__ */ jsx24("p", { children: "This link cannot resume payment or booking. Sign in to view your application status, or contact the chapter if you need help." }),
1921
+ /* @__PURE__ */ jsx24("a", { className: "apply-link", href: membersHref, children: copy.done.memberArea })
1758
1922
  ] })
1759
1923
  ] });
1760
1924
  }
1761
1925
  if (state.step === "done") {
1762
- const body = renderDone?.({ ...state, membersHref }) ?? /* @__PURE__ */ jsxs22("div", { className: "join-done card", children: [
1763
- /* @__PURE__ */ jsx22("div", { className: "card-label", children: copy.done.label }),
1764
- /* @__PURE__ */ jsx22("p", { className: "meeting-date", children: fullLabel(state.booked.startAt, state.booked.timezone) }),
1765
- /* @__PURE__ */ jsx22("p", { className: "meeting-note", children: copy.done.calendarInvite }),
1766
- /* @__PURE__ */ jsx22("a", { className: "apply-link", href: membersHref, children: copy.done.memberArea })
1926
+ const body = renderDone?.({ ...state, membersHref }) ?? /* @__PURE__ */ jsxs24("div", { className: "join-done card", children: [
1927
+ /* @__PURE__ */ jsx24("div", { className: "card-label", children: copy.done.label }),
1928
+ /* @__PURE__ */ jsx24("p", { className: "meeting-date", children: fullLabel(state.booked.startAt, state.booked.timezone) }),
1929
+ /* @__PURE__ */ jsx24("p", { className: "meeting-note", children: copy.done.calendarInvite }),
1930
+ /* @__PURE__ */ jsx24("a", { className: "apply-link", href: membersHref, children: copy.done.memberArea })
1767
1931
  ] });
1768
- return /* @__PURE__ */ jsxs22(Fragment10, { children: [
1932
+ return /* @__PURE__ */ jsxs24(Fragment11, { children: [
1769
1933
  header,
1770
1934
  body
1771
1935
  ] });
1772
1936
  }
1773
1937
  if (state.step === "accepted") {
1774
- const body = renderAccepted?.({ ...state, membersHref }) ?? /* @__PURE__ */ jsx22(JoinAccepted, { copy, membersHref });
1775
- return /* @__PURE__ */ jsxs22(Fragment10, { children: [
1938
+ const body = renderAccepted?.({ ...state, membersHref }) ?? /* @__PURE__ */ jsx24(JoinAccepted, { copy, membersHref });
1939
+ return /* @__PURE__ */ jsxs24(Fragment11, { children: [
1776
1940
  header,
1777
1941
  body
1778
1942
  ] });
1779
1943
  }
1780
1944
  if (state.step === "gift") {
1781
- const body = renderGift?.(state) ?? /* @__PURE__ */ jsx22(GiftClaimCard, { applicationId: state.applicationId, claimId: state.claimId, initialCode: state.code, copy: copy.gift });
1782
- return /* @__PURE__ */ jsxs22(Fragment10, { children: [
1945
+ const body = renderGift?.(state) ?? /* @__PURE__ */ jsx24(GiftClaimCard, { applicationId: state.applicationId, claimId: state.claimId, initialCode: state.code, copy: copy.gift });
1946
+ return /* @__PURE__ */ jsxs24(Fragment11, { children: [
1783
1947
  header,
1784
1948
  body
1785
1949
  ] });
1786
1950
  }
1787
1951
  if (state.step === "booking") {
1788
- return /* @__PURE__ */ jsxs22(Fragment10, { children: [
1952
+ return /* @__PURE__ */ jsxs24(Fragment11, { children: [
1789
1953
  header,
1790
- /* @__PURE__ */ jsx22(
1954
+ /* @__PURE__ */ jsx24(
1791
1955
  JoinBooking,
1792
1956
  {
1793
1957
  applicationId: state.applicationId,
@@ -1802,9 +1966,9 @@ function JoinFlow(props) {
1802
1966
  }
1803
1967
  if (state.step === "payment") {
1804
1968
  if (props.namedSeatClaimApi && props.initialNamedSeatId && !props.simulation && !state.giftPurchase) {
1805
- return /* @__PURE__ */ jsxs22(Fragment10, { children: [
1969
+ return /* @__PURE__ */ jsxs24(Fragment11, { children: [
1806
1970
  header,
1807
- /* @__PURE__ */ jsx22(
1971
+ /* @__PURE__ */ jsx24(
1808
1972
  JoinNamedSeat,
1809
1973
  {
1810
1974
  api: props.namedSeatClaimApi,
@@ -1817,9 +1981,9 @@ function JoinFlow(props) {
1817
1981
  ] });
1818
1982
  }
1819
1983
  const Payment = state.giftPurchase || props.simulation ? PaymentStep : MembershipPaymentStep;
1820
- return /* @__PURE__ */ jsxs22(Fragment10, { children: [
1984
+ return /* @__PURE__ */ jsxs24(Fragment11, { children: [
1821
1985
  header,
1822
- props.giftClaimApi && !state.giftPurchase ? /* @__PURE__ */ jsx22(
1986
+ props.giftClaimApi && !state.giftPurchase ? /* @__PURE__ */ jsx24(
1823
1987
  JoinGiftClaim,
1824
1988
  {
1825
1989
  api: props.giftClaimApi,
@@ -1830,17 +1994,15 @@ function JoinFlow(props) {
1830
1994
  onError: () => setError(copy.form.unexpectedFailure)
1831
1995
  }
1832
1996
  ) : null,
1833
- /* @__PURE__ */ jsx22(
1997
+ /* @__PURE__ */ jsx24(
1834
1998
  Payment,
1835
1999
  {
1836
2000
  applicationId: state.applicationId,
1837
2001
  refundPolicyText: config.refundPolicyText ?? "",
1838
2002
  merchantDisclosureText: config.merchantDisclosureText,
1839
2003
  copy: copy.payment,
1840
- appearance: props.payment?.appearance,
1841
- initialNamedSeat: props.payment?.initialNamedSeat,
1842
- fonts: props.payment?.fonts,
1843
- renderPriceLines: props.payment?.renderPriceLines,
2004
+ ...props.payment,
2005
+ onNamedSeatEditingChange: setEditingNamedSeat,
1844
2006
  simulation: simulatedPayment,
1845
2007
  onPaid: (result) => {
1846
2008
  if (props.simulation) {
@@ -1860,9 +2022,9 @@ function JoinFlow(props) {
1860
2022
  }
1861
2023
  if (state.step === "paymentPending") {
1862
2024
  if (props.namedSeatClaimApi && props.initialNamedSeatId && !props.simulation) {
1863
- return /* @__PURE__ */ jsxs22(Fragment10, { children: [
2025
+ return /* @__PURE__ */ jsxs24(Fragment11, { children: [
1864
2026
  header,
1865
- /* @__PURE__ */ jsx22(
2027
+ /* @__PURE__ */ jsx24(
1866
2028
  JoinNamedSeat,
1867
2029
  {
1868
2030
  api: props.namedSeatClaimApi,
@@ -1874,14 +2036,14 @@ function JoinFlow(props) {
1874
2036
  )
1875
2037
  ] });
1876
2038
  }
1877
- return /* @__PURE__ */ jsxs22(Fragment10, { children: [
2039
+ return /* @__PURE__ */ jsxs24(Fragment11, { children: [
1878
2040
  header,
1879
- /* @__PURE__ */ jsx22("p", { className: "pay-status", role: "status", children: copy.payment.pending })
2041
+ /* @__PURE__ */ jsx24("p", { className: "pay-status", role: "status", children: copy.payment.pending })
1880
2042
  ] });
1881
2043
  }
1882
- return /* @__PURE__ */ jsxs22(Fragment10, { children: [
2044
+ return /* @__PURE__ */ jsxs24(Fragment11, { children: [
1883
2045
  header,
1884
- /* @__PURE__ */ jsx22(
2046
+ /* @__PURE__ */ jsx24(
1885
2047
  JoinApplicationForm,
1886
2048
  {
1887
2049
  props,
@@ -2071,7 +2233,7 @@ function membershipPageDocument(input, options = {}) {
2071
2233
  }
2072
2234
 
2073
2235
  // src/ui/membership-cards.tsx
2074
- import { jsx as jsx23, jsxs as jsxs23 } from "preact/jsx-runtime";
2236
+ import { jsx as jsx25, jsxs as jsxs25 } from "preact/jsx-runtime";
2075
2237
  var MEMBERSHIP_CARD_TOKEN_DEFAULTS = Object.freeze({
2076
2238
  "--ui-membership-grid-gap": "1.4rem",
2077
2239
  "--ui-membership-card-padding": "2rem 1.7rem 1.8rem",
@@ -2140,67 +2302,67 @@ function membershipApplicationHref(applicationPath, tierId) {
2140
2302
  }
2141
2303
  function TierAction(props) {
2142
2304
  if (props.mode === "select") {
2143
- return /* @__PURE__ */ jsxs23("button", { type: "button", className: "chapter-membership-action", "aria-current": props.selected ? "true" : void 0, onClick: () => props.onSelectTier?.(props.tierId), children: [
2305
+ return /* @__PURE__ */ jsxs25("button", { type: "button", className: "chapter-membership-action", "aria-current": props.selected ? "true" : void 0, onClick: () => props.onSelectTier?.(props.tierId), children: [
2144
2306
  props.label,
2145
- /* @__PURE__ */ jsx23("span", { "aria-hidden": "true", children: "\u2192" })
2307
+ /* @__PURE__ */ jsx25("span", { "aria-hidden": "true", children: "\u2192" })
2146
2308
  ] });
2147
2309
  }
2148
2310
  if (props.mode === "preview") {
2149
- return /* @__PURE__ */ jsxs23("span", { className: "chapter-membership-action", "aria-disabled": "true", children: [
2311
+ return /* @__PURE__ */ jsxs25("span", { className: "chapter-membership-action", "aria-disabled": "true", children: [
2150
2312
  props.label,
2151
- /* @__PURE__ */ jsx23("span", { "aria-hidden": "true", children: "\u2192" })
2313
+ /* @__PURE__ */ jsx25("span", { "aria-hidden": "true", children: "\u2192" })
2152
2314
  ] });
2153
2315
  }
2154
- return /* @__PURE__ */ jsxs23("a", { className: "chapter-membership-action", href: membershipApplicationHref(props.applicationPath, props.tierId), children: [
2316
+ return /* @__PURE__ */ jsxs25("a", { className: "chapter-membership-action", href: membershipApplicationHref(props.applicationPath, props.tierId), children: [
2155
2317
  props.label,
2156
- /* @__PURE__ */ jsx23("span", { "aria-hidden": "true", children: "\u2192" })
2318
+ /* @__PURE__ */ jsx25("span", { "aria-hidden": "true", children: "\u2192" })
2157
2319
  ] });
2158
2320
  }
2159
2321
  function TierCard(props) {
2160
2322
  const { tier, presentation } = props;
2161
2323
  const summary = presentation.summaryMarkdown ?? tier.blurb;
2162
2324
  const action = presentation.ctaLabel ?? (tier.free ? "Join for free" : `Choose ${tier.name}`);
2163
- return /* @__PURE__ */ jsxs23("article", { className: "chapter-membership-card", "data-tier-id": tier.id, "data-variant": presentation.variant ?? "standard", children: [
2164
- presentation.badge ? /* @__PURE__ */ jsx23("div", { className: "chapter-membership-badge", children: presentation.badge }) : null,
2165
- /* @__PURE__ */ jsx23("h3", { className: "chapter-membership-name", children: tier.name }),
2166
- /* @__PURE__ */ jsxs23("div", { className: "chapter-membership-offer", "data-with-capacity": presentation.capacity ? "true" : void 0, children: [
2167
- presentation.capacity ? /* @__PURE__ */ jsxs23("div", { className: "chapter-membership-capacity", "aria-label": `${presentation.capacity.total} ${presentation.capacity.label ?? "available"}`, children: [
2168
- /* @__PURE__ */ jsx23("strong", { children: presentation.capacity.total.toLocaleString("en-US") }),
2169
- /* @__PURE__ */ jsx23("small", { children: presentation.capacity.label ?? "available" })
2325
+ return /* @__PURE__ */ jsxs25("article", { className: "chapter-membership-card", "data-tier-id": tier.id, "data-variant": presentation.variant ?? "standard", children: [
2326
+ presentation.badge ? /* @__PURE__ */ jsx25("div", { className: "chapter-membership-badge", children: presentation.badge }) : null,
2327
+ /* @__PURE__ */ jsx25("h3", { className: "chapter-membership-name", children: tier.name }),
2328
+ /* @__PURE__ */ jsxs25("div", { className: "chapter-membership-offer", "data-with-capacity": presentation.capacity ? "true" : void 0, children: [
2329
+ presentation.capacity ? /* @__PURE__ */ jsxs25("div", { className: "chapter-membership-capacity", "aria-label": `${presentation.capacity.total} ${presentation.capacity.label ?? "available"}`, children: [
2330
+ /* @__PURE__ */ jsx25("strong", { children: presentation.capacity.total.toLocaleString("en-US") }),
2331
+ /* @__PURE__ */ jsx25("small", { children: presentation.capacity.label ?? "available" })
2170
2332
  ] }) : null,
2171
- /* @__PURE__ */ jsxs23("div", { className: "chapter-membership-price-stack", children: [
2172
- presentation.priceEyebrow ? /* @__PURE__ */ jsx23("p", { className: "chapter-membership-price-eyebrow", children: presentation.priceEyebrow }) : tier.founding ? /* @__PURE__ */ jsx23("p", { className: "chapter-membership-price-eyebrow", children: "Founding member rate" }) : null,
2173
- /* @__PURE__ */ jsxs23("div", { className: "chapter-membership-price-row", children: [
2174
- tier.founding ? /* @__PURE__ */ jsx23("span", { className: "chapter-membership-compare", children: fmtMoney(tier.priceCents) }) : presentation.compareAtPriceCents !== void 0 ? /* @__PURE__ */ jsx23("span", { className: "chapter-membership-compare", children: fmtMoney(presentation.compareAtPriceCents) }) : null,
2175
- /* @__PURE__ */ jsx23("span", { className: "chapter-membership-price", children: tier.free ? "Free" : fmtMoney(tier.founding ? tier.founding.dueTodayCents : tier.priceCents) }),
2176
- !tier.free && presentation.billingLabel ? /* @__PURE__ */ jsx23("span", { className: "chapter-membership-billing", children: presentation.billingLabel }) : null
2333
+ /* @__PURE__ */ jsxs25("div", { className: "chapter-membership-price-stack", children: [
2334
+ presentation.priceEyebrow ? /* @__PURE__ */ jsx25("p", { className: "chapter-membership-price-eyebrow", children: presentation.priceEyebrow }) : tier.founding ? /* @__PURE__ */ jsx25("p", { className: "chapter-membership-price-eyebrow", children: "Founding member rate" }) : null,
2335
+ /* @__PURE__ */ jsxs25("div", { className: "chapter-membership-price-row", children: [
2336
+ tier.founding ? /* @__PURE__ */ jsx25("span", { className: "chapter-membership-compare", children: fmtMoney(tier.priceCents) }) : presentation.compareAtPriceCents !== void 0 ? /* @__PURE__ */ jsx25("span", { className: "chapter-membership-compare", children: fmtMoney(presentation.compareAtPriceCents) }) : null,
2337
+ /* @__PURE__ */ jsx25("span", { className: "chapter-membership-price", children: tier.free ? "Free" : fmtMoney(tier.founding ? tier.founding.dueTodayCents : tier.priceCents) }),
2338
+ !tier.free && presentation.billingLabel ? /* @__PURE__ */ jsx25("span", { className: "chapter-membership-billing", children: presentation.billingLabel }) : null
2177
2339
  ] })
2178
2340
  ] })
2179
2341
  ] }),
2180
- presentation.priceNoteMarkdown ? /* @__PURE__ */ jsx23(Markdown2, { className: "chapter-membership-price-note", source: presentation.priceNoteMarkdown }) : null,
2181
- summary ? /* @__PURE__ */ jsx23(Markdown2, { className: "chapter-membership-summary", source: summary }) : null,
2182
- presentation.benefits?.length ? /* @__PURE__ */ jsx23("ul", { className: "chapter-membership-benefits", children: presentation.benefits.map((benefit, index) => /* @__PURE__ */ jsxs23("li", { children: [
2183
- /* @__PURE__ */ jsx23("span", { className: "chapter-membership-check", "aria-hidden": "true", children: "\u2713" }),
2184
- /* @__PURE__ */ jsx23(Markdown2, { className: "chapter-membership-benefit", source: benefit })
2342
+ presentation.priceNoteMarkdown ? /* @__PURE__ */ jsx25(Markdown2, { className: "chapter-membership-price-note", source: presentation.priceNoteMarkdown }) : null,
2343
+ summary ? /* @__PURE__ */ jsx25(Markdown2, { className: "chapter-membership-summary", source: summary }) : null,
2344
+ presentation.benefits?.length ? /* @__PURE__ */ jsx25("ul", { className: "chapter-membership-benefits", children: presentation.benefits.map((benefit, index) => /* @__PURE__ */ jsxs25("li", { children: [
2345
+ /* @__PURE__ */ jsx25("span", { className: "chapter-membership-check", "aria-hidden": "true", children: "\u2713" }),
2346
+ /* @__PURE__ */ jsx25(Markdown2, { className: "chapter-membership-benefit", source: benefit })
2185
2347
  ] }, `${tier.id}-benefit-${index}`)) }) : null,
2186
- presentation.callout ? /* @__PURE__ */ jsxs23("aside", { className: "chapter-membership-callout", children: [
2187
- presentation.callout.label ? /* @__PURE__ */ jsx23("p", { className: "chapter-membership-callout-label", children: presentation.callout.label }) : null,
2188
- /* @__PURE__ */ jsx23(Markdown2, { source: presentation.callout.bodyMarkdown })
2348
+ presentation.callout ? /* @__PURE__ */ jsxs25("aside", { className: "chapter-membership-callout", children: [
2349
+ presentation.callout.label ? /* @__PURE__ */ jsx25("p", { className: "chapter-membership-callout-label", children: presentation.callout.label }) : null,
2350
+ /* @__PURE__ */ jsx25(Markdown2, { source: presentation.callout.bodyMarkdown })
2189
2351
  ] }) : null,
2190
- /* @__PURE__ */ jsx23(TierAction, { tierId: tier.id, label: action, mode: props.mode, selected: props.selected, applicationPath: props.applicationPath, onSelectTier: props.onSelectTier })
2352
+ /* @__PURE__ */ jsx25(TierAction, { tierId: tier.id, label: action, mode: props.mode, selected: props.selected, applicationPath: props.applicationPath, onSelectTier: props.onSelectTier })
2191
2353
  ] });
2192
2354
  }
2193
2355
  function MembershipCards(props) {
2194
2356
  const document2 = membershipPageDocument(props.document, { tiers: props.tiers });
2195
2357
  const byId = new Map(props.tiers.map((tier) => [tier.id, tier]));
2196
2358
  const mode = props.mode ?? "link";
2197
- return /* @__PURE__ */ jsxs23("section", { className: ["chapter-membership", props.className].filter(Boolean).join(" "), "data-chapter-membership": MEMBERSHIP_PAGE_RENDERER, "aria-label": props.ariaLabel ?? "Membership options", children: [
2198
- /* @__PURE__ */ jsx23("style", { children: MEMBERSHIP_CARDS_CSS }),
2199
- /* @__PURE__ */ jsx23("div", { className: "chapter-membership-grid", style: { "--chapter-membership-columns": String(Math.min(document2.tiers.length, 3)) }, children: document2.tiers.map((presentation) => {
2359
+ return /* @__PURE__ */ jsxs25("section", { className: ["chapter-membership", props.className].filter(Boolean).join(" "), "data-chapter-membership": MEMBERSHIP_PAGE_RENDERER, "aria-label": props.ariaLabel ?? "Membership options", children: [
2360
+ /* @__PURE__ */ jsx25("style", { children: MEMBERSHIP_CARDS_CSS }),
2361
+ /* @__PURE__ */ jsx25("div", { className: "chapter-membership-grid", style: { "--chapter-membership-columns": String(Math.min(document2.tiers.length, 3)) }, children: document2.tiers.map((presentation) => {
2200
2362
  const tier = byId.get(presentation.tierId);
2201
- return /* @__PURE__ */ jsx23(TierCard, { tier, presentation, mode, selected: props.selectedTierId === tier.id, applicationPath: props.applicationPath, onSelectTier: props.onSelectTier }, tier.id);
2363
+ return /* @__PURE__ */ jsx25(TierCard, { tier, presentation, mode, selected: props.selectedTierId === tier.id, applicationPath: props.applicationPath, onSelectTier: props.onSelectTier }, tier.id);
2202
2364
  }) }),
2203
- document2.footnoteMarkdown ? /* @__PURE__ */ jsx23(Markdown2, { className: "chapter-membership-footnote", source: document2.footnoteMarkdown }) : null
2365
+ document2.footnoteMarkdown ? /* @__PURE__ */ jsx25(Markdown2, { className: "chapter-membership-footnote", source: document2.footnoteMarkdown }) : null
2204
2366
  ] });
2205
2367
  }
2206
2368
 
@@ -2236,4 +2398,4 @@ export {
2236
2398
  membershipApplicationHref,
2237
2399
  MembershipCards
2238
2400
  };
2239
- //# sourceMappingURL=chunk-VEOGTSVX.js.map
2401
+ //# sourceMappingURL=chunk-NK267YQZ.js.map