@flamingo-stack/openframe-frontend-core 0.0.594 → 0.0.595-snapshot.20260905150417

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.
Files changed (161) hide show
  1. package/dist/{chunk-HQWZ4IXU.cjs → chunk-3CH6VRJX.cjs} +24 -24
  2. package/dist/{chunk-HQWZ4IXU.cjs.map → chunk-3CH6VRJX.cjs.map} +1 -1
  3. package/dist/{chunk-LKN2KKYZ.js → chunk-4K7TCJ35.js} +6 -59
  4. package/dist/{chunk-LKN2KKYZ.js.map → chunk-4K7TCJ35.js.map} +1 -1
  5. package/dist/{chunk-YLVPQNLO.cjs → chunk-5MSHWXJ5.cjs} +170 -223
  6. package/dist/chunk-5MSHWXJ5.cjs.map +1 -0
  7. package/dist/{chunk-CCLPJSY3.cjs → chunk-73BECFSU.cjs} +15 -15
  8. package/dist/{chunk-CCLPJSY3.cjs.map → chunk-73BECFSU.cjs.map} +1 -1
  9. package/dist/{chunk-F5Q3DTP5.js → chunk-7EUE3YTC.js} +8 -8
  10. package/dist/{chunk-GBIC3VNA.js → chunk-7KGN7DV6.js} +6 -6
  11. package/dist/{chunk-YZLUOZKR.js → chunk-7Q66A4CF.js} +2 -2
  12. package/dist/{chunk-DRZ224RU.js → chunk-ANSZVKI2.js} +8 -8
  13. package/dist/{chunk-N3RHX26N.js → chunk-AZZVSEP5.js} +3 -3
  14. package/dist/{chunk-66I2QUFE.cjs → chunk-B26UT36N.cjs} +6 -6
  15. package/dist/{chunk-66I2QUFE.cjs.map → chunk-B26UT36N.cjs.map} +1 -1
  16. package/dist/{chunk-UBRVIVY4.cjs → chunk-B2CSYMKW.cjs} +298 -285
  17. package/dist/chunk-B2CSYMKW.cjs.map +1 -0
  18. package/dist/{chunk-ZK3AZ5YF.cjs → chunk-BTOL222V.cjs} +11 -11
  19. package/dist/{chunk-ZK3AZ5YF.cjs.map → chunk-BTOL222V.cjs.map} +1 -1
  20. package/dist/{chunk-S7VW4HVL.cjs → chunk-DODE3PD4.cjs} +49 -49
  21. package/dist/{chunk-S7VW4HVL.cjs.map → chunk-DODE3PD4.cjs.map} +1 -1
  22. package/dist/{chunk-ZZHHKE2Q.js → chunk-ECXQX4EP.js} +2 -2
  23. package/dist/{chunk-NEFNARFF.cjs → chunk-EEV7SSBJ.cjs} +30 -30
  24. package/dist/{chunk-NEFNARFF.cjs.map → chunk-EEV7SSBJ.cjs.map} +1 -1
  25. package/dist/{chunk-3OQIZPUX.js → chunk-EO3NEGWB.js} +4 -4
  26. package/dist/{chunk-MOHSA65M.js → chunk-EZM5DNII.js} +2 -2
  27. package/dist/{chunk-IKQVXZB5.js → chunk-GSPS6Y5U.js} +6 -6
  28. package/dist/{chunk-CQ35OMPJ.cjs → chunk-I2BNLWC3.cjs} +3 -3
  29. package/dist/{chunk-CQ35OMPJ.cjs.map → chunk-I2BNLWC3.cjs.map} +1 -1
  30. package/dist/{chunk-HOLK4ZMT.js → chunk-II2GBWNW.js} +4 -4
  31. package/dist/{chunk-PETYVGEQ.cjs → chunk-JKGVXLTT.cjs} +5 -5
  32. package/dist/{chunk-PETYVGEQ.cjs.map → chunk-JKGVXLTT.cjs.map} +1 -1
  33. package/dist/{chunk-5EM6NGBK.cjs → chunk-KOQCA5X5.cjs} +17 -27
  34. package/dist/chunk-KOQCA5X5.cjs.map +1 -0
  35. package/dist/{chunk-ACU7J5BL.cjs → chunk-KPE7OQF6.cjs} +84 -84
  36. package/dist/{chunk-ACU7J5BL.cjs.map → chunk-KPE7OQF6.cjs.map} +1 -1
  37. package/dist/{chunk-C4YJC5X7.cjs → chunk-KRKW63LG.cjs} +9 -9
  38. package/dist/{chunk-C4YJC5X7.cjs.map → chunk-KRKW63LG.cjs.map} +1 -1
  39. package/dist/{chunk-ZEG3ZJPY.cjs → chunk-LE5SZPMN.cjs} +33 -33
  40. package/dist/{chunk-ZEG3ZJPY.cjs.map → chunk-LE5SZPMN.cjs.map} +1 -1
  41. package/dist/{chunk-A5AKGC4S.js → chunk-LPMDCQLL.js} +17 -27
  42. package/dist/chunk-LPMDCQLL.js.map +1 -0
  43. package/dist/{chunk-EWOFXJGH.cjs → chunk-M3OQLL7D.cjs} +63 -63
  44. package/dist/{chunk-EWOFXJGH.cjs.map → chunk-M3OQLL7D.cjs.map} +1 -1
  45. package/dist/{chunk-FKXDDJEQ.cjs → chunk-M4YQUHOR.cjs} +5 -5
  46. package/dist/{chunk-FKXDDJEQ.cjs.map → chunk-M4YQUHOR.cjs.map} +1 -1
  47. package/dist/{chunk-5XQMEDGE.cjs → chunk-OHJ4QOWN.cjs} +12 -12
  48. package/dist/{chunk-5XQMEDGE.cjs.map → chunk-OHJ4QOWN.cjs.map} +1 -1
  49. package/dist/{chunk-Y6I2DGKC.cjs → chunk-OMKI5T2G.cjs} +1 -1
  50. package/dist/chunk-OMKI5T2G.cjs.map +1 -0
  51. package/dist/{chunk-M5HGULIY.js → chunk-OQODJ26H.js} +5 -5
  52. package/dist/{chunk-MEWAFY6X.js → chunk-OT5IQMSI.js} +4 -4
  53. package/dist/{chunk-Y22VQDVW.js → chunk-QB244ZDI.js} +4 -4
  54. package/dist/{chunk-3T7ZP3TL.js → chunk-QL6ECU6Y.js} +3 -3
  55. package/dist/{chunk-3XDPXOMS.js → chunk-R2SZYRB2.js} +7 -7
  56. package/dist/{chunk-QAVT6P5F.cjs → chunk-RFA5T5MW.cjs} +28 -28
  57. package/dist/{chunk-QAVT6P5F.cjs.map → chunk-RFA5T5MW.cjs.map} +1 -1
  58. package/dist/{chunk-BTF3CNDP.js → chunk-ROQO355A.js} +1 -1
  59. package/dist/chunk-ROQO355A.js.map +1 -0
  60. package/dist/{chunk-43ADGEWL.cjs → chunk-UJAMXLA3.cjs} +40 -40
  61. package/dist/{chunk-43ADGEWL.cjs.map → chunk-UJAMXLA3.cjs.map} +1 -1
  62. package/dist/{chunk-KVNA3HU2.js → chunk-XANQTIHS.js} +3 -3
  63. package/dist/{chunk-PMN7WDXI.js → chunk-YUHOKPKS.js} +26 -13
  64. package/dist/chunk-YUHOKPKS.js.map +1 -0
  65. package/dist/components/case-studies/index.cjs +16 -16
  66. package/dist/components/case-studies/index.js +6 -6
  67. package/dist/components/chat/entity-cards/dispatch.d.ts.map +1 -1
  68. package/dist/components/chat/index.cjs +4 -4
  69. package/dist/components/chat/index.js +3 -3
  70. package/dist/components/contact/index.cjs +7 -7
  71. package/dist/components/contact/index.js +6 -6
  72. package/dist/components/docs/index.cjs +10 -10
  73. package/dist/components/docs/index.js +9 -9
  74. package/dist/components/embeds/index.cjs +7 -7
  75. package/dist/components/embeds/index.js +6 -6
  76. package/dist/components/faq/index.cjs +7 -7
  77. package/dist/components/faq/index.js +6 -6
  78. package/dist/components/features/index.cjs +6 -6
  79. package/dist/components/features/index.js +5 -5
  80. package/dist/components/help-center-pages/index.cjs +26 -26
  81. package/dist/components/help-center-pages/index.js +17 -17
  82. package/dist/components/icons/index.cjs +2 -2
  83. package/dist/components/icons/index.js +1 -1
  84. package/dist/components/icons/mlg-logo.d.ts.map +1 -1
  85. package/dist/components/index.cjs +56 -56
  86. package/dist/components/index.js +17 -17
  87. package/dist/components/meeting-scheduler/booking-form.d.ts +49 -5
  88. package/dist/components/meeting-scheduler/booking-form.d.ts.map +1 -1
  89. package/dist/components/meeting-scheduler/context-panel.d.ts +9 -1
  90. package/dist/components/meeting-scheduler/context-panel.d.ts.map +1 -1
  91. package/dist/components/meeting-scheduler/index.cjs +369 -186
  92. package/dist/components/meeting-scheduler/index.cjs.map +1 -1
  93. package/dist/components/meeting-scheduler/index.d.ts +55 -1
  94. package/dist/components/meeting-scheduler/index.d.ts.map +1 -1
  95. package/dist/components/meeting-scheduler/index.js +344 -161
  96. package/dist/components/meeting-scheduler/index.js.map +1 -1
  97. package/dist/components/meeting-scheduler/slot-picker.d.ts +8 -1
  98. package/dist/components/meeting-scheduler/slot-picker.d.ts.map +1 -1
  99. package/dist/components/navigation/index.cjs +9 -9
  100. package/dist/components/navigation/index.js +8 -8
  101. package/dist/components/onboarding-guides/index.cjs +9 -9
  102. package/dist/components/onboarding-guides/index.js +8 -8
  103. package/dist/components/related-content/index.cjs +3 -3
  104. package/dist/components/related-content/index.js +2 -2
  105. package/dist/components/tickets/index.cjs +10 -10
  106. package/dist/components/tickets/index.js +9 -9
  107. package/dist/components/ui/benefit-card.d.ts.map +1 -1
  108. package/dist/components/ui/index.cjs +6 -6
  109. package/dist/components/ui/index.js +5 -5
  110. package/dist/hooks/index.cjs +3 -3
  111. package/dist/hooks/index.js +2 -2
  112. package/dist/index.cjs +10 -10
  113. package/dist/index.js +9 -9
  114. package/dist/schemas/meeting-booking-schema.cjs +19 -4
  115. package/dist/schemas/meeting-booking-schema.cjs.map +1 -1
  116. package/dist/schemas/meeting-booking-schema.d.ts +41 -16
  117. package/dist/schemas/meeting-booking-schema.d.ts.map +1 -1
  118. package/dist/schemas/meeting-booking-schema.js +19 -5
  119. package/dist/schemas/meeting-booking-schema.js.map +1 -1
  120. package/dist/types/index.cjs.map +1 -1
  121. package/dist/types/index.js.map +1 -1
  122. package/dist/utils/index.cjs +18 -40
  123. package/dist/utils/index.cjs.map +1 -1
  124. package/dist/utils/index.js +18 -40
  125. package/dist/utils/index.js.map +1 -1
  126. package/dist/utils/source-icons.d.ts.map +1 -1
  127. package/package.json +1 -1
  128. package/src/components/chat/entity-cards/dispatch.tsx +0 -57
  129. package/src/components/icons/mlg-logo.tsx +1 -7
  130. package/src/components/meeting-scheduler/booking-form.tsx +371 -152
  131. package/src/components/meeting-scheduler/context-panel.tsx +13 -3
  132. package/src/components/meeting-scheduler/index.tsx +316 -69
  133. package/src/components/meeting-scheduler/slot-picker.tsx +17 -1
  134. package/src/components/ui/benefit-card.tsx +30 -9
  135. package/src/schemas/meeting-booking-schema.ts +58 -4
  136. package/src/types/tmcg.ts +0 -2
  137. package/src/utils/format.ts +1 -1
  138. package/src/utils/source-icons.ts +0 -24
  139. package/dist/chunk-5EM6NGBK.cjs.map +0 -1
  140. package/dist/chunk-A5AKGC4S.js.map +0 -1
  141. package/dist/chunk-BTF3CNDP.js.map +0 -1
  142. package/dist/chunk-PMN7WDXI.js.map +0 -1
  143. package/dist/chunk-UBRVIVY4.cjs.map +0 -1
  144. package/dist/chunk-Y6I2DGKC.cjs.map +0 -1
  145. package/dist/chunk-YLVPQNLO.cjs.map +0 -1
  146. /package/dist/{chunk-F5Q3DTP5.js.map → chunk-7EUE3YTC.js.map} +0 -0
  147. /package/dist/{chunk-GBIC3VNA.js.map → chunk-7KGN7DV6.js.map} +0 -0
  148. /package/dist/{chunk-YZLUOZKR.js.map → chunk-7Q66A4CF.js.map} +0 -0
  149. /package/dist/{chunk-DRZ224RU.js.map → chunk-ANSZVKI2.js.map} +0 -0
  150. /package/dist/{chunk-N3RHX26N.js.map → chunk-AZZVSEP5.js.map} +0 -0
  151. /package/dist/{chunk-ZZHHKE2Q.js.map → chunk-ECXQX4EP.js.map} +0 -0
  152. /package/dist/{chunk-3OQIZPUX.js.map → chunk-EO3NEGWB.js.map} +0 -0
  153. /package/dist/{chunk-MOHSA65M.js.map → chunk-EZM5DNII.js.map} +0 -0
  154. /package/dist/{chunk-IKQVXZB5.js.map → chunk-GSPS6Y5U.js.map} +0 -0
  155. /package/dist/{chunk-HOLK4ZMT.js.map → chunk-II2GBWNW.js.map} +0 -0
  156. /package/dist/{chunk-M5HGULIY.js.map → chunk-OQODJ26H.js.map} +0 -0
  157. /package/dist/{chunk-MEWAFY6X.js.map → chunk-OT5IQMSI.js.map} +0 -0
  158. /package/dist/{chunk-Y22VQDVW.js.map → chunk-QB244ZDI.js.map} +0 -0
  159. /package/dist/{chunk-3T7ZP3TL.js.map → chunk-QL6ECU6Y.js.map} +0 -0
  160. /package/dist/{chunk-3XDPXOMS.js.map → chunk-R2SZYRB2.js.map} +0 -0
  161. /package/dist/{chunk-KVNA3HU2.js.map → chunk-XANQTIHS.js.map} +0 -0
@@ -22,13 +22,14 @@ var _chunkO4VZOA2Qcjs = require('../../chunk-O4VZOA2Q.cjs');
22
22
 
23
23
 
24
24
 
25
- var _chunkUBRVIVY4cjs = require('../../chunk-UBRVIVY4.cjs');
25
+
26
+ var _chunkB2CSYMKWcjs = require('../../chunk-B2CSYMKW.cjs');
26
27
  require('../../chunk-GQWM3ECA.cjs');
27
28
  require('../../chunk-TON3YCCW.cjs');
28
29
 
29
30
 
30
31
 
31
- var _chunkFKXDDJEQcjs = require('../../chunk-FKXDDJEQ.cjs');
32
+ var _chunkM4YQUHORcjs = require('../../chunk-M4YQUHOR.cjs');
32
33
  require('../../chunk-D55IENZJ.cjs');
33
34
  require('../../chunk-N6CULJYR.cjs');
34
35
 
@@ -42,10 +43,10 @@ var _chunkH64ZHSYRcjs = require('../../chunk-H64ZHSYR.cjs');
42
43
  var _chunkY7ITKISQcjs = require('../../chunk-Y7ITKISQ.cjs');
43
44
 
44
45
 
45
- var _chunkYLVPQNLOcjs = require('../../chunk-YLVPQNLO.cjs');
46
+ var _chunk5MSHWXJ5cjs = require('../../chunk-5MSHWXJ5.cjs');
46
47
  require('../../chunk-YXWGSDK4.cjs');
47
48
  require('../../chunk-SADRZ4YI.cjs');
48
- require('../../chunk-5EM6NGBK.cjs');
49
+ require('../../chunk-KOQCA5X5.cjs');
49
50
  require('../../chunk-GSQM4PDR.cjs');
50
51
  require('../../chunk-XQFFGR6U.cjs');
51
52
 
@@ -53,7 +54,7 @@ require('../../chunk-XQFFGR6U.cjs');
53
54
 
54
55
 
55
56
 
56
- var _chunkY6I2DGKCcjs = require('../../chunk-Y6I2DGKC.cjs');
57
+ var _chunkOMKI5T2Gcjs = require('../../chunk-OMKI5T2G.cjs');
57
58
  require('../../chunk-WLSFBRT5.cjs');
58
59
  require('../../chunk-YH6IQTPI.cjs');
59
60
  require('../../chunk-63QUMV72.cjs');
@@ -113,7 +114,7 @@ function isValidBcp47Locale(locale) {
113
114
  return false;
114
115
  }
115
116
  }
116
- function makeBookingSchema(formFields, legalConsent) {
117
+ function buildBookingSchema(formFields, legalConsent, slot) {
117
118
  const answers = {};
118
119
  for (const field of formFields) {
119
120
  if (!isSupportedFormField(field)) continue;
@@ -150,12 +151,12 @@ function makeBookingSchema(formFields, legalConsent) {
150
151
  const answersObject = _zod.z.object(answers);
151
152
  return _zod.z.object({
152
153
  meetingId: _zod.z.string().min(1),
153
- startTimeMs: _zod.z.number().int().positive(),
154
- durationMs: _zod.z.number().int().positive(),
154
+ startTimeMs: slot.startTimeMs,
155
+ durationMs: slot.durationMs,
155
156
  firstName: _zod.z.string().min(1, { message: "First name is required" }).max(255),
156
157
  lastName: _zod.z.string().min(1, { message: "Last name is required" }).max(255),
157
158
  email: _zod.z.string().email({ message: "Please enter a valid email address" }).max(255),
158
- timezone: _zod.z.string().refine(isValidIanaTimezone, { message: "Invalid timezone" }),
159
+ timezone: slot.timezone,
159
160
  locale: _zod.z.string().refine(isValidBcp47Locale, { message: "Invalid locale" }).optional(),
160
161
  // Plain `.optional()` (no `.default()`) so zod's input and output types
161
162
  // match — react-hook-form's zodResolver needs them identical, and the
@@ -177,6 +178,13 @@ function makeBookingSchema(formFields, legalConsent) {
177
178
  }
178
179
  });
179
180
  }
181
+ function makeDeferredBookingSchema(formFields, legalConsent) {
182
+ return buildBookingSchema(formFields, legalConsent, {
183
+ startTimeMs: _zod.z.number().int().positive().nullish(),
184
+ durationMs: _zod.z.number().int().positive().nullish(),
185
+ timezone: _zod.z.string().refine(isValidIanaTimezone, { message: "Invalid timezone" }).nullish()
186
+ });
187
+ }
180
188
 
181
189
  // src/hooks/use-meeting-booking.ts
182
190
  var AVAILABILITY_STALE_MS = 0;
@@ -189,7 +197,7 @@ function useMeetingBooking(options) {
189
197
  const seededOffset = _optionalChain([initialAvailability, 'optionalAccess', _3 => _3.meetingId]) === meetingId ? initialAvailability.monthOffset : void 0;
190
198
  const [monthOffset, setMonthOffsetState] = _react.useState.call(void 0, _nullishCoalesce(seededOffset, () => ( 0)));
191
199
  const setMonthOffset = _react.useCallback.call(void 0, (offset) => {
192
- setMonthOffsetState(Math.max(0, Math.min(_chunkUBRVIVY4cjs.MAX_MONTH_OFFSET, offset)));
200
+ setMonthOffsetState(Math.max(0, Math.min(_chunkB2CSYMKWcjs.MAX_MONTH_OFFSET, offset)));
193
201
  }, []);
194
202
  const prevMeetingIdRef = _react.useRef.call(void 0, meetingId);
195
203
  _react.useLayoutEffect.call(void 0, () => {
@@ -271,12 +279,24 @@ var _zod3 = require('@hookform/resolvers/zod');
271
279
 
272
280
  var _reacthookform = require('react-hook-form');
273
281
  var _jsxruntime = require('react/jsx-runtime');
282
+ var SPAN_CLASS = {
283
+ 1: "md:col-span-1",
284
+ 2: "md:col-span-2",
285
+ 3: "md:col-span-3",
286
+ 4: "md:col-span-4"
287
+ };
288
+ var evenSpan = (count) => Math.min(4, Math.max(1, Math.floor(4 / Math.max(1, count))));
274
289
  function BookingForm({
275
290
  availability,
276
291
  meetingId,
277
292
  startTimeMs,
278
293
  durationMs,
279
294
  timezone,
295
+ deferSlot = false,
296
+ initialValues,
297
+ submitLabel,
298
+ footerNote,
299
+ fieldRows,
280
300
  isSubmitting,
281
301
  onSubmit,
282
302
  honeypotInputProps,
@@ -284,42 +304,67 @@ function BookingForm({
284
304
  }) {
285
305
  const { formFields, legalConsent } = availability;
286
306
  const supportedFields = _react.useMemo.call(void 0, () => formFields.filter(isSupportedFormField), [formFields]);
287
- const schema = _react.useMemo.call(void 0, () => makeBookingSchema(supportedFields, legalConsent), [supportedFields, legalConsent]);
307
+ const schema = _react.useMemo.call(void 0,
308
+ () => makeDeferredBookingSchema(supportedFields, legalConsent),
309
+ [supportedFields, legalConsent]
310
+ );
311
+ const consentDefaults = _react.useMemo.call(void 0,
312
+ () => (_nullishCoalesce(_optionalChain([legalConsent, 'optionalAccess', _5 => _5.communicationConsentCheckboxes]), () => ( []))).map((c) => ({
313
+ communicationTypeId: c.communicationTypeId,
314
+ consented: false
315
+ })),
316
+ [legalConsent]
317
+ );
288
318
  const {
289
319
  register,
290
320
  control,
291
321
  handleSubmit,
322
+ setValue,
292
323
  formState: { errors }
293
324
  } = _reacthookform.useForm.call(void 0, {
294
325
  resolver: _zod3.zodResolver.call(void 0, schema),
295
326
  defaultValues: {
296
327
  meetingId,
297
- startTimeMs,
298
- durationMs,
328
+ // Genuinely OMITTED, not present-as-undefined, when the slot is deferred.
329
+ ...deferSlot ? {} : { startTimeMs, durationMs },
299
330
  timezone,
300
331
  locale: typeof navigator !== "undefined" ? navigator.language : void 0,
301
332
  firstName: "",
302
333
  lastName: "",
303
334
  email: "",
304
335
  formFields: {},
305
- legalConsentResponses: (_nullishCoalesce(_optionalChain([legalConsent, 'optionalAccess', _5 => _5.communicationConsentCheckboxes]), () => ( []))).map((c) => ({
306
- communicationTypeId: c.communicationTypeId,
307
- consented: false
308
- }))
336
+ legalConsentResponses: consentDefaults,
337
+ // A remount (back edge, or an error return) would otherwise lose every
338
+ // answer — `defaultValues` is snapshotted once and never re-read.
339
+ ..._nullishCoalesce(initialValues, () => ( {}))
309
340
  }
310
341
  });
342
+ const priorConsents = _optionalChain([initialValues, 'optionalAccess', _6 => _6.legalConsentResponses]);
343
+ _react.useEffect.call(void 0, () => {
344
+ setValue(
345
+ "legalConsentResponses",
346
+ consentDefaults.map((next) => ({
347
+ ...next,
348
+ consented: _nullishCoalesce(_optionalChain([priorConsents, 'optionalAccess', _7 => _7.find, 'call', _8 => _8((r) => r.communicationTypeId === next.communicationTypeId), 'optionalAccess', _9 => _9.consented]), () => ( false))
349
+ })),
350
+ { shouldDirty: false }
351
+ );
352
+ }, [consentDefaults, priorConsents, setValue]);
311
353
  const submit = handleSubmit(async (data) => {
354
+ if (deferSlot) {
355
+ await onSubmit({ ...data, meetingId });
356
+ return;
357
+ }
312
358
  await onSubmit({ ...data, meetingId, startTimeMs, durationMs, timezone, ...getSignals() });
313
359
  });
314
360
  const fieldError = (name) => {
315
- const err = _optionalChain([errors, 'access', _6 => _6.formFields, 'optionalAccess', _7 => _7[name]]);
316
- return _optionalChain([err, 'optionalAccess', _8 => _8.message]);
361
+ const err = _optionalChain([errors, 'access', _10 => _10.formFields, 'optionalAccess', _11 => _11[name]]);
362
+ return _optionalChain([err, 'optionalAccess', _12 => _12.message]);
317
363
  };
318
364
  const inputClass = "bg-ods-card border-ods-border text-ods-text-primary placeholder-ods-text-secondary px-3 h-11 md:h-12";
319
365
  const FORM_STACK = "flex flex-col gap-[var(--spacing-system-l)]";
320
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "form", { onSubmit: submit, className: FORM_STACK, noValidate: true, children: [
321
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUBRVIVY4cjs.HoneypotField, { ...honeypotInputProps }),
322
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY7ITKISQcjs.FieldWrapper, { label: "Email", htmlFor: "ms-email", error: _optionalChain([errors, 'access', _9 => _9.email, 'optionalAccess', _10 => _10.message]), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
366
+ const builtInFields = {
367
+ email: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY7ITKISQcjs.FieldWrapper, { label: "Email", htmlFor: "ms-email", error: _optionalChain([errors, 'access', _13 => _13.email, 'optionalAccess', _14 => _14.message]), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
323
368
  _chunkY7ITKISQcjs.Input,
324
369
  {
325
370
  id: "ms-email",
@@ -332,129 +377,195 @@ function BookingForm({
332
377
  ...register("email")
333
378
  }
334
379
  ) }),
335
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "grid grid-cols-2 gap-[var(--spacing-system-m)]", children: [
336
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY7ITKISQcjs.FieldWrapper, { label: "First Name", htmlFor: "ms-first-name", error: _optionalChain([errors, 'access', _11 => _11.firstName, 'optionalAccess', _12 => _12.message]), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
337
- _chunkY7ITKISQcjs.Input,
338
- {
339
- id: "ms-first-name",
340
- required: true,
341
- autoComplete: "given-name",
342
- placeholder: "Jane",
343
- "aria-invalid": !!errors.firstName,
344
- className: inputClass,
345
- ...register("firstName")
346
- }
347
- ) }),
348
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY7ITKISQcjs.FieldWrapper, { label: "Last Name", htmlFor: "ms-last-name", error: _optionalChain([errors, 'access', _13 => _13.lastName, 'optionalAccess', _14 => _14.message]), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
349
- _chunkY7ITKISQcjs.Input,
350
- {
351
- id: "ms-last-name",
352
- required: true,
353
- autoComplete: "family-name",
354
- placeholder: "Doe",
355
- "aria-invalid": !!errors.lastName,
356
- className: inputClass,
357
- ...register("lastName")
358
- }
359
- ) })
360
- ] }),
361
- supportedFields.map((field) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
362
- _chunkY7ITKISQcjs.FieldWrapper,
380
+ firstName: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY7ITKISQcjs.FieldWrapper, { label: "First Name", htmlFor: "ms-first-name", error: _optionalChain([errors, 'access', _15 => _15.firstName, 'optionalAccess', _16 => _16.message]), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
381
+ _chunkY7ITKISQcjs.Input,
363
382
  {
364
- label: field.label,
365
- htmlFor: `ms-q-${field.name}`,
366
- error: fieldError(field.name),
367
- children: [
368
- field.type === "textarea" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
369
- _chunkUBRVIVY4cjs.Textarea,
370
- {
371
- id: `ms-q-${field.name}`,
372
- className: "border-ods-border bg-ods-card px-3 text-ods-text-primary placeholder-ods-text-secondary",
373
- ...register(`formFields.${field.name}`)
374
- }
375
- ),
376
- field.type === "text" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
377
- _chunkY7ITKISQcjs.Input,
383
+ id: "ms-first-name",
384
+ required: true,
385
+ autoComplete: "given-name",
386
+ placeholder: "Jane",
387
+ "aria-invalid": !!errors.firstName,
388
+ className: inputClass,
389
+ ...register("firstName")
390
+ }
391
+ ) }),
392
+ lastName: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY7ITKISQcjs.FieldWrapper, { label: "Last Name", htmlFor: "ms-last-name", error: _optionalChain([errors, 'access', _17 => _17.lastName, 'optionalAccess', _18 => _18.message]), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
393
+ _chunkY7ITKISQcjs.Input,
394
+ {
395
+ id: "ms-last-name",
396
+ required: true,
397
+ autoComplete: "family-name",
398
+ placeholder: "Doe",
399
+ "aria-invalid": !!errors.lastName,
400
+ className: inputClass,
401
+ ...register("lastName")
402
+ }
403
+ ) })
404
+ };
405
+ const renderDeclaredField = (field) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkY7ITKISQcjs.FieldWrapper, { label: field.label, htmlFor: `ms-q-${field.name}`, error: fieldError(field.name), children: [
406
+ field.type === "textarea" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
407
+ _chunkB2CSYMKWcjs.Textarea,
408
+ {
409
+ id: `ms-q-${field.name}`,
410
+ className: "border-ods-border bg-ods-card px-3 text-ods-text-primary placeholder-ods-text-secondary",
411
+ ...register(`formFields.${field.name}`)
412
+ }
413
+ ),
414
+ field.type === "text" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
415
+ _chunkY7ITKISQcjs.Input,
416
+ {
417
+ id: `ms-q-${field.name}`,
418
+ className: "h-11 border-ods-border bg-ods-card px-3 text-ods-text-primary placeholder-ods-text-secondary md:h-12",
419
+ ...register(`formFields.${field.name}`)
420
+ }
421
+ ),
422
+ (field.type === "select" || field.type === "radio") && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
423
+ _reacthookform.Controller,
424
+ {
425
+ control,
426
+ name: `formFields.${field.name}`,
427
+ render: ({ field: rhf }) => field.type === "select" ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkB2CSYMKWcjs.Select, { value: _nullishCoalesce(rhf.value, () => ( "")), onValueChange: rhf.onChange, children: [
428
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkB2CSYMKWcjs.SelectTrigger, { id: `ms-q-${field.name}`, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkB2CSYMKWcjs.SelectValue, { placeholder: "Select\u2026" }) }),
429
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkB2CSYMKWcjs.SelectContent, { children: (_nullishCoalesce(field.options, () => ( []))).map((opt) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkB2CSYMKWcjs.SelectItem, { value: opt, children: opt }, opt)) })
430
+ ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkB2CSYMKWcjs.RadioGroup, { value: _nullishCoalesce(rhf.value, () => ( "")), onValueChange: rhf.onChange, children: (_nullishCoalesce(field.options, () => ( []))).map((opt) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-[var(--spacing-system-xs)]", children: [
431
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkB2CSYMKWcjs.RadioGroupItem, { id: `ms-q-${field.name}-${opt}`, value: opt }),
432
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkCHIHYC7Qcjs.Label, { htmlFor: `ms-q-${field.name}-${opt}`, children: opt })
433
+ ] }, opt)) })
434
+ }
435
+ ),
436
+ field.type === "checkbox" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
437
+ _reacthookform.Controller,
438
+ {
439
+ control,
440
+ name: `formFields.${field.name}`,
441
+ render: ({ field: rhf }) => (
442
+ // The question's Label above already carries the text and
443
+ // binds to this id — a second inline label would double the
444
+ // visible text AND the accessible name.
445
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex items-center gap-[var(--spacing-system-xs)]", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
446
+ _chunkY7ITKISQcjs.Checkbox,
378
447
  {
379
448
  id: `ms-q-${field.name}`,
380
- className: "h-11 border-ods-border bg-ods-card px-3 text-ods-text-primary placeholder-ods-text-secondary md:h-12",
381
- ...register(`formFields.${field.name}`)
382
- }
383
- ),
384
- (field.type === "select" || field.type === "radio") && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
385
- _reacthookform.Controller,
386
- {
387
- control,
388
- name: `formFields.${field.name}`,
389
- render: ({ field: rhf }) => field.type === "select" ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkUBRVIVY4cjs.Select, { value: _nullishCoalesce(rhf.value, () => ( "")), onValueChange: rhf.onChange, children: [
390
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUBRVIVY4cjs.SelectTrigger, { id: `ms-q-${field.name}`, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUBRVIVY4cjs.SelectValue, { placeholder: "Select\u2026" }) }),
391
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUBRVIVY4cjs.SelectContent, { children: (_nullishCoalesce(field.options, () => ( []))).map((opt) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUBRVIVY4cjs.SelectItem, { value: opt, children: opt }, opt)) })
392
- ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUBRVIVY4cjs.RadioGroup, { value: _nullishCoalesce(rhf.value, () => ( "")), onValueChange: rhf.onChange, children: (_nullishCoalesce(field.options, () => ( []))).map((opt) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-[var(--spacing-system-xs)]", children: [
393
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUBRVIVY4cjs.RadioGroupItem, { id: `ms-q-${field.name}-${opt}`, value: opt }),
394
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkCHIHYC7Qcjs.Label, { htmlFor: `ms-q-${field.name}-${opt}`, children: opt })
395
- ] }, opt)) })
449
+ checked: Boolean(rhf.value),
450
+ onCheckedChange: (v) => rhf.onChange(v === true)
396
451
  }
397
- ),
398
- field.type === "checkbox" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
399
- _reacthookform.Controller,
452
+ ) })
453
+ )
454
+ }
455
+ )
456
+ ] }, field.name);
457
+ const declaredByName = new Map(supportedFields.map((f) => [f.name, f]));
458
+ const slotResolves = (name) => Boolean(builtInFields[name] || declaredByName.has(name));
459
+ const slotNode = (name) => {
460
+ const builtIn = builtInFields[name];
461
+ if (builtIn) return builtIn;
462
+ const declared = declaredByName.get(name);
463
+ return declared ? renderDeclaredField(declared) : null;
464
+ };
465
+ const unplacedFields = fieldRows ? supportedFields.filter((f) => !fieldRows.some((row) => row.some((slot) => slot.name === f.name))) : [];
466
+ const placedRows = (_nullishCoalesce(fieldRows, () => ( []))).map((row) => row.filter((slot) => slotResolves(slot.name))).filter((row) => row.length > 0);
467
+ const submitButton = /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
468
+ _chunkCJBSU3XBcjs.Button,
469
+ {
470
+ type: "submit",
471
+ loading: isSubmitting,
472
+ disabled: isSubmitting,
473
+ className: footerNote ? "md:w-60" : void 0,
474
+ children: _nullishCoalesce(submitLabel, () => ( "Confirm Booking"))
475
+ }
476
+ );
477
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "form", { onSubmit: submit, className: FORM_STACK, noValidate: true, children: [
478
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkB2CSYMKWcjs.HoneypotField, { ...honeypotInputProps }),
479
+ fieldRows ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
480
+ placedRows.map((row, rowIndex) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
481
+ "div",
482
+ {
483
+ className: "grid grid-cols-2 gap-[var(--spacing-system-m)] md:grid-cols-4",
484
+ children: row.map((slot) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
485
+ "div",
400
486
  {
401
- control,
402
- name: `formFields.${field.name}`,
403
- render: ({ field: rhf }) => (
404
- // The question's Label above already carries the text and
405
- // binds to this id — a second inline label would double the
406
- // visible text AND the accessible name.
407
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex items-center gap-[var(--spacing-system-xs)]", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
408
- _chunkY7ITKISQcjs.Checkbox,
409
- {
410
- id: `ms-q-${field.name}`,
411
- checked: Boolean(rhf.value),
412
- onCheckedChange: (v) => rhf.onChange(v === true)
413
- }
414
- ) })
415
- )
416
- }
417
- )
418
- ]
419
- },
420
- field.name
421
- )),
487
+ className: _chunk23V5BSHDcjs.cn.call(void 0,
488
+ // A two-field row stays side by side on a phone — the rule
489
+ // the built-in name pair has always followed: two short
490
+ // fields cost one line instead of two on the layout that can
491
+ // least afford them.
492
+ row.length === 2 ? "col-span-1" : "col-span-2",
493
+ SPAN_CLASS[_nullishCoalesce(slot.span, () => ( evenSpan(row.length)))]
494
+ ),
495
+ children: slotNode(slot.name)
496
+ },
497
+ slot.name
498
+ ))
499
+ },
500
+ row.map((s) => s.name).join("|") || rowIndex
501
+ )),
502
+ unplacedFields.map((field) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _react.Fragment, { children: renderDeclaredField(field) }, field.name))
503
+ ] }) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
504
+ builtInFields.email,
505
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "grid grid-cols-2 gap-[var(--spacing-system-m)]", children: [
506
+ builtInFields.firstName,
507
+ builtInFields.lastName
508
+ ] }),
509
+ supportedFields.map((field) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _react.Fragment, { children: renderDeclaredField(field) }, field.name))
510
+ ] }),
422
511
  legalConsent && // Same out-of-flow message as the fields above, so a missed consent
423
512
  // box doesn't shove the submit button down the card. With no error the
424
513
  // wrapper is `display:contents` and the panel below is the flex item,
425
514
  // exactly as it was.
426
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY7ITKISQcjs.FieldWrapper, { error: _optionalChain([errors, 'access', _15 => _15.legalConsentResponses, 'optionalAccess', _16 => _16.message]), children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-[var(--spacing-system-xs)] rounded-md border border-ods-border p-[var(--spacing-system-m)]", children: [
427
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary text-h6", children: legalConsent.processingConsentText }),
428
- legalConsent.communicationConsentText && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary text-h6", children: legalConsent.communicationConsentText }),
515
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY7ITKISQcjs.FieldWrapper, { error: _optionalChain([errors, 'access', _19 => _19.legalConsentResponses, 'optionalAccess', _20 => _20.message]), children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-[var(--spacing-system-xs)]", children: [
429
516
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
430
517
  _reacthookform.Controller,
431
518
  {
432
519
  control,
433
520
  name: "legalConsentResponses",
434
- render: ({ field: rhf }) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children: legalConsent.communicationConsentCheckboxes.map((box) => {
521
+ render: ({ field: rhf }) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children: legalConsent.communicationConsentCheckboxes.map((box, index) => {
435
522
  const responses = _nullishCoalesce(rhf.value, () => ( []));
436
523
  const current = responses.find((r) => r.communicationTypeId === box.communicationTypeId);
437
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-[var(--spacing-system-xs)]", children: [
524
+ return (
525
+ // The design system's consent row (`checkbox-block`, the
526
+ // same block the waitlist form uses): box, label, caption
527
+ // in one bordered row. GDPR surface — HubSpot's copy is
528
+ // rendered VERBATIM, never edited. The processing statement
529
+ // rides as the caption of the FIRST row, once: it describes
530
+ // the consent as a whole, not each channel.
438
531
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
439
- _chunkY7ITKISQcjs.Checkbox,
532
+ _chunkB2CSYMKWcjs.CheckboxBlock,
440
533
  {
441
534
  id: `ms-consent-${box.communicationTypeId}`,
442
- checked: _nullishCoalesce(_optionalChain([current, 'optionalAccess', _17 => _17.consented]), () => ( false)),
535
+ checked: _nullishCoalesce(_optionalChain([current, 'optionalAccess', _21 => _21.consented]), () => ( false)),
443
536
  onCheckedChange: (v) => rhf.onChange(
444
537
  responses.map(
445
- (r) => r.communicationTypeId === box.communicationTypeId ? { ...r, consented: v === true } : r
538
+ (r) => r.communicationTypeId === box.communicationTypeId ? { ...r, consented: v } : r
446
539
  )
447
- )
448
- }
449
- ),
450
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkCHIHYC7Qcjs.Label, { htmlFor: `ms-consent-${box.communicationTypeId}`, children: box.label })
451
- ] }, box.communicationTypeId);
540
+ ),
541
+ label: box.label,
542
+ description: index === 0 ? legalConsent.processingConsentText : void 0
543
+ },
544
+ box.communicationTypeId
545
+ )
546
+ );
452
547
  }) })
453
548
  }
454
549
  ),
550
+ legalConsent.communicationConsentText && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary text-h6", children: legalConsent.communicationConsentText }),
455
551
  legalConsent.privacyPolicyText && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary text-h6", children: legalConsent.privacyPolicyText })
456
552
  ] }) }),
457
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkCJBSU3XBcjs.Button, { type: "submit", loading: isSubmitting, disabled: isSubmitting, children: "Confirm Booking" }) })
553
+ footerNote ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center justify-between gap-[var(--spacing-system-m)]", children: [
554
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary text-h6", children: footerNote }),
555
+ submitButton
556
+ ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex", children: submitButton })
557
+ ] });
558
+ }
559
+ function BookingFormSkeleton() {
560
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-1 flex-col gap-[var(--spacing-system-l)] p-[var(--spacing-system-l)] lg:p-0", children: [
561
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "grid grid-cols-1 gap-[var(--spacing-system-m)] md:grid-cols-2", children: [
562
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkCHIHYC7Qcjs.Skeleton, { className: "h-[4.75rem] w-full" }),
563
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkCHIHYC7Qcjs.Skeleton, { className: "h-[4.75rem] w-full" })
564
+ ] }),
565
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkCHIHYC7Qcjs.Skeleton, { className: "h-[4.75rem] w-full" }),
566
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkCHIHYC7Qcjs.Skeleton, { className: "h-[7.75rem] w-full" }),
567
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkCHIHYC7Qcjs.Skeleton, { className: "h-[4.25rem] w-full" }),
568
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex justify-end", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkCHIHYC7Qcjs.Skeleton, { className: "h-12 w-40" }) })
458
569
  ] });
459
570
  }
460
571
 
@@ -477,7 +588,7 @@ function Confirmation({ confirmation, timezone }) {
477
588
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { className: "text-ods-text-secondary text-h6", children: [
478
589
  when,
479
590
  " \xB7 ",
480
- _chunkY6I2DGKCcjs.formatDurationCompact.call(void 0, confirmation.durationMs / 1e3)
591
+ _chunkOMKI5T2Gcjs.formatDurationCompact.call(void 0, confirmation.durationMs / 1e3)
481
592
  ] }),
482
593
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary text-h6", children: "A calendar invite is on its way to your email." })
483
594
  ] });
@@ -499,7 +610,7 @@ function zoneLabel(tz) {
499
610
  timeZone: tz,
500
611
  timeZoneName: "shortOffset"
501
612
  }).formatToParts(/* @__PURE__ */ new Date());
502
- const offset = _nullishCoalesce(_optionalChain([parts, 'access', _18 => _18.find, 'call', _19 => _19((p) => p.type === "timeZoneName"), 'optionalAccess', _20 => _20.value]), () => ( ""));
613
+ const offset = _nullishCoalesce(_optionalChain([parts, 'access', _22 => _22.find, 'call', _23 => _23((p) => p.type === "timeZoneName"), 'optionalAccess', _24 => _24.value]), () => ( ""));
503
614
  return offset ? `${tz.replace(/_/g, " ")} (${offset})` : tz.replace(/_/g, " ");
504
615
  } catch (e4) {
505
616
  return tz.replace(/_/g, " ");
@@ -511,7 +622,7 @@ function ContextPanelSkeleton({
511
622
  backLabel = "Back"
512
623
  }) {
513
624
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, PANEL_STACK, className), children: [
514
- onBack && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUBRVIVY4cjs.BackButton, { label: backLabel, onClick: onBack, className: BACK_BUTTON_CLASS }),
625
+ onBack && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkB2CSYMKWcjs.BackButton, { label: backLabel, onClick: onBack, className: BACK_BUTTON_CLASS }),
515
626
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: STRIP_BODY, children: [
516
627
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: STRIP_MAIN, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: IDENTITY_ROW, children: [
517
628
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex min-w-0 flex-1 items-center gap-[var(--spacing-system-xs)] lg:flex-none", children: [
@@ -542,6 +653,7 @@ function SchedulerContextPanel({
542
653
  onBack,
543
654
  backLabel = "Back",
544
655
  locked = false,
656
+ fixedDuration = false,
545
657
  showTimezone = true,
546
658
  className
547
659
  }) {
@@ -558,13 +670,13 @@ function SchedulerContextPanel({
558
670
  return zones.map((tz) => ({ value: tz, label: zoneLabel(tz) }));
559
671
  }, [timezone]);
560
672
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, PANEL_STACK, className), children: [
561
- onBack && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUBRVIVY4cjs.BackButton, { label: backLabel, onClick: onBack, className: BACK_BUTTON_CLASS }),
673
+ onBack && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkB2CSYMKWcjs.BackButton, { label: backLabel, onClick: onBack, className: BACK_BUTTON_CLASS }),
562
674
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: STRIP_BODY, children: [
563
675
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: STRIP_MAIN, children: [
564
676
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: IDENTITY_ROW, children: [
565
677
  hosts.length > 0 && hosts.length <= 3 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex flex-col gap-[var(--spacing-system-s)]", children: hosts.map((host) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-[var(--spacing-system-xs)]", children: [
566
678
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
567
- _chunkY6I2DGKCcjs.SquareAvatar,
679
+ _chunkOMKI5T2Gcjs.SquareAvatar,
568
680
  {
569
681
  variant: "round",
570
682
  size: "sm",
@@ -579,24 +691,25 @@ function SchedulerContextPanel({
579
691
  ] })
580
692
  ] }, host.name)) }),
581
693
  hosts.length > 3 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-[var(--spacing-system-xs)]", children: [
582
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY6I2DGKCcjs.AvatarStack, { people: hosts, max: 4, size: "lg" }),
694
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkOMKI5T2Gcjs.AvatarStack, { people: hosts, max: 4, size: "lg" }),
583
695
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { className: "text-ods-text-secondary text-h6", children: [
584
696
  hosts.length,
585
697
  " hosts on this calendar"
586
698
  ] })
587
699
  ] }),
588
- locked || durationsMs.length <= 1 ? (
589
- // Post-selection, or a link that offers one length: a static line,
700
+ locked || fixedDuration || durationsMs.length <= 1 ? (
701
+ // Post-selection, a fixed-length flow, or a link that offers one
702
+ // length: a static line,
590
703
  // which is what sits beside the host on the header-strip layouts.
591
704
  selectedDurationMs != null && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { className: "shrink-0 text-ods-text-secondary text-h6", children: [
592
- _chunkY6I2DGKCcjs.formatDurationCompact.call(void 0, selectedDurationMs / 1e3),
705
+ _chunkOMKI5T2Gcjs.formatDurationCompact.call(void 0, selectedDurationMs / 1e3),
593
706
  " call"
594
707
  ] })
595
708
  ) : null
596
709
  ] }),
597
710
  title && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-primary text-h3", children: title }),
598
711
  description && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary text-h6", children: description }),
599
- !locked && durationsMs.length > 1 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-[var(--spacing-system-xxs)]", children: [
712
+ !locked && !fixedDuration && durationsMs.length > 1 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-[var(--spacing-system-xxs)]", children: [
600
713
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: FIELD_LABEL_CLASS, children: "Duration" }),
601
714
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex flex-wrap gap-[var(--spacing-system-xs)]", children: durationsMs.map((ms) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
602
715
  _chunkCJBSU3XBcjs.Button,
@@ -604,7 +717,7 @@ function SchedulerContextPanel({
604
717
  variant: selectedDurationMs === ms ? void 0 : "outline",
605
718
  size: "small-legacy",
606
719
  onClick: () => onSelectDuration(ms),
607
- children: _chunkY6I2DGKCcjs.formatDurationCompact.call(void 0, ms / 1e3)
720
+ children: _chunkOMKI5T2Gcjs.formatDurationCompact.call(void 0, ms / 1e3)
608
721
  },
609
722
  ms
610
723
  )) })
@@ -619,11 +732,11 @@ function SchedulerContextPanel({
619
732
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, STRIP_ASIDE, locked && "max-lg:hidden"), children: [
620
733
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: FIELD_LABEL_CLASS, children: "Timezone" }),
621
734
  timezone ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
622
- _chunkUBRVIVY4cjs.Autocomplete,
735
+ _chunkB2CSYMKWcjs.Autocomplete,
623
736
  {
624
737
  value: timezone,
625
738
  onChange: (tz) => {
626
- if (tz) _optionalChain([onTimezoneChange, 'optionalCall', _21 => _21(tz)]);
739
+ if (tz) _optionalChain([onTimezoneChange, 'optionalCall', _25 => _25(tz)]);
627
740
  },
628
741
  options: zoneOptions,
629
742
  placeholder: "Search timezone\u2026",
@@ -705,18 +818,18 @@ var NOOP = () => void 0;
705
818
  function DayCalendar({ monthOffset, onMonthOffsetChange, selectedDay, onSelectDay, slotsByDay }) {
706
819
  const now = /* @__PURE__ */ new Date();
707
820
  const startMonth = new Date(now.getFullYear(), now.getMonth(), 1);
708
- const endMonth = new Date(now.getFullYear(), now.getMonth() + _chunkUBRVIVY4cjs.MAX_MONTH_OFFSET + 1, 0);
821
+ const endMonth = new Date(now.getFullYear(), now.getMonth() + _chunkB2CSYMKWcjs.MAX_MONTH_OFFSET + 1, 0);
709
822
  const visibleMonth = new Date(now.getFullYear(), now.getMonth() + monthOffset, 1);
710
- const dayHasNoSlots = _react.useCallback.call(void 0, (day) => !_optionalChain([slotsByDay, 'optionalAccess', _22 => _22.has, 'call', _23 => _23(calendarDayKey(day))]), [slotsByDay]);
823
+ const dayHasNoSlots = _react.useCallback.call(void 0, (day) => !_optionalChain([slotsByDay, 'optionalAccess', _26 => _26.has, 'call', _27 => _27(calendarDayKey(day))]), [slotsByDay]);
711
824
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex min-h-0 flex-1 flex-col", "aria-busy": slotsByDay === null, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
712
- _chunkUBRVIVY4cjs.DatePickerCalendar,
825
+ _chunkB2CSYMKWcjs.DatePickerCalendar,
713
826
  {
714
827
  mode: "single",
715
828
  bare: true,
716
829
  month: visibleMonth,
717
830
  onMonthChange: (month) => {
718
831
  const offset = (month.getFullYear() - now.getFullYear()) * 12 + (month.getMonth() - now.getMonth());
719
- onMonthOffsetChange(Math.max(0, Math.min(_chunkUBRVIVY4cjs.MAX_MONTH_OFFSET, offset)));
832
+ onMonthOffsetChange(Math.max(0, Math.min(_chunkB2CSYMKWcjs.MAX_MONTH_OFFSET, offset)));
720
833
  },
721
834
  fromDate: startMonth,
722
835
  toDate: endMonth,
@@ -725,7 +838,7 @@ function DayCalendar({ monthOffset, onMonthOffsetChange, selectedDay, onSelectDa
725
838
  const day = value;
726
839
  if (!day) return;
727
840
  const key = calendarDayKey(day);
728
- if (_optionalChain([slotsByDay, 'optionalAccess', _24 => _24.has, 'call', _25 => _25(key)])) onSelectDay(key);
841
+ if (_optionalChain([slotsByDay, 'optionalAccess', _28 => _28.has, 'call', _29 => _29(key)])) onSelectDay(key);
729
842
  },
730
843
  disabledDays: slotsByDay === null ? DISABLE_EVERY_DAY : dayHasNoSlots
731
844
  }
@@ -767,7 +880,8 @@ function SlotPicker({
767
880
  onSelectSlot,
768
881
  selectedDay,
769
882
  onSelectDay,
770
- isLoading = false
883
+ isLoading = false,
884
+ isSubmitting = false
771
885
  }) {
772
886
  const slotsByDay = _react.useMemo.call(void 0, () => {
773
887
  const map = /* @__PURE__ */ new Map();
@@ -813,7 +927,12 @@ function SlotPicker({
813
927
  _chunkCJBSU3XBcjs.Button,
814
928
  {
815
929
  variant: isSelected ? void 0 : "outline",
816
- onClick: () => onSelectSlot(ms),
930
+ disabled: isSubmitting,
931
+ loading: isSubmitting && isSelected,
932
+ onClick: () => {
933
+ if (isSubmitting) return;
934
+ onSelectSlot(ms);
935
+ },
817
936
  className: CHIP_CLASS,
818
937
  children: timeLabelInZone(ms, timezone)
819
938
  },
@@ -830,7 +949,7 @@ function SlotPicker({
830
949
  monthLabelFor(monthOffset),
831
950
  "."
832
951
  ] }),
833
- monthOffset < _chunkUBRVIVY4cjs.MAX_MONTH_OFFSET && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
952
+ monthOffset < _chunkB2CSYMKWcjs.MAX_MONTH_OFFSET && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
834
953
  _chunkCJBSU3XBcjs.Button,
835
954
  {
836
955
  variant: "outline",
@@ -852,7 +971,7 @@ function SlotPicker({
852
971
 
853
972
 
854
973
  function useNextAvailableLabel(ms) {
855
- const hydrated = _chunkYLVPQNLOcjs.useIsHydrated.call(void 0, );
974
+ const hydrated = _chunk5MSHWXJ5cjs.useIsHydrated.call(void 0, );
856
975
  return _react.useMemo.call(void 0, () => {
857
976
  if (!hydrated || ms == null) return null;
858
977
  try {
@@ -876,7 +995,7 @@ function DirectoryRow({
876
995
  const nextLabel = useNextAvailableLabel(link.nextAvailableMs);
877
996
  const subtitle = [
878
997
  link.description,
879
- link.durationsMinutes.length > 0 ? link.durationsMinutes.map((m) => _chunkY6I2DGKCcjs.formatDurationCompact.call(void 0, m * 60)).join(" / ") : null,
998
+ link.durationsMinutes.length > 0 ? link.durationsMinutes.map((m) => _chunkOMKI5T2Gcjs.formatDurationCompact.call(void 0, m * 60)).join(" / ") : null,
880
999
  link.kind === "team" ? "Team" : null
881
1000
  ].filter(Boolean).join(" \u2022 ");
882
1001
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
@@ -890,8 +1009,8 @@ function DirectoryRow({
890
1009
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "truncate text-ods-text-primary text-h3", children: link.title }),
891
1010
  subtitle && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "truncate text-ods-text-secondary text-h6", children: subtitle })
892
1011
  ] }),
893
- audienceLabel && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY6I2DGKCcjs.StatusBadge, { text: `For ${audienceLabel}`, singleLine: true, className: "hidden shrink-0 sm:inline-flex" }),
894
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY6I2DGKCcjs.AvatarStack, { people: link.hosts, max: 3, size: "md", className: "flex shrink-0" }),
1012
+ audienceLabel && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkOMKI5T2Gcjs.StatusBadge, { text: `For ${audienceLabel}`, singleLine: true, className: "hidden shrink-0 sm:inline-flex" }),
1013
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkOMKI5T2Gcjs.AvatarStack, { people: link.hosts, max: 3, size: "md", className: "flex shrink-0" }),
895
1014
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "hidden w-44 shrink-0 flex-col items-end justify-center md:flex", children: [
896
1015
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary text-h6", children: "Next available" }),
897
1016
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "min-h-5 text-ods-text-primary text-h6", children: link.nextAvailableMs == null ? "No times published" : _nullishCoalesce(nextLabel, () => ( " ")) })
@@ -957,7 +1076,7 @@ function MeetingSchedulerDirectory({
957
1076
  };
958
1077
  }, [initialData, includeAll, apiBaseUrl]);
959
1078
  const rows = _react.useMemo.call(void 0, () => {
960
- const purposes = _nullishCoalesce(_optionalChain([data, 'optionalAccess', _26 => _26.purposes]), () => ( []));
1079
+ const purposes = _nullishCoalesce(_optionalChain([data, 'optionalAccess', _30 => _30.purposes]), () => ( []));
961
1080
  return purposes.flatMap((p) => p.links.map((link) => ({ link, audienceLabel: p.label })));
962
1081
  }, [data]);
963
1082
  const totalPages = _chunkH64ZHSYRcjs.pageCount.call(void 0, rows.length, pageSize);
@@ -1019,16 +1138,18 @@ var CONTEXT_PANEL_CLASS = "p-[var(--spacing-system-l)] shrink-0 lg:w-[280px] bor
1019
1138
  var ACTION_PANEL_CLASS = "flex-1 min-w-0 flex flex-col md:min-h-0 lg:p-[var(--spacing-system-l)]";
1020
1139
  var PANEL_STEP_CLASS = "p-[var(--spacing-system-l)] md:min-h-0 md:overflow-y-auto lg:p-0";
1021
1140
  var MEETING_SCHEDULER_H = "md:h-[34.375rem] lg:h-[23.75rem]";
1141
+ var MEETING_SCHEDULER_DETAILS_FIRST_H = "md:h-[39.875rem]";
1022
1142
  var CARD_CLASS = _chunk23V5BSHDcjs.cn.call(void 0,
1023
1143
  "overflow-hidden rounded-md border border-ods-border bg-ods-card",
1024
- "md:flex md:flex-col",
1025
- MEETING_SCHEDULER_H
1144
+ "md:flex md:flex-col"
1145
+ // The height is NOT baked in any more: it is chosen per flow at each render
1146
+ // site (`flowHeight`), because details-first needs a taller box and both
1147
+ // constants are module scope.
1026
1148
  );
1027
1149
  var CARD_INNER_CLASS = "flex flex-col md:min-h-0 md:flex-1 lg:h-full lg:flex-row";
1028
1150
  var CARD_DEGRADED_CLASS = _chunk23V5BSHDcjs.cn.call(void 0,
1029
1151
  "flex flex-col items-start gap-[var(--spacing-system-m)] rounded-md border border-ods-border bg-ods-card p-[var(--spacing-system-lf)]",
1030
- "md:justify-center md:overflow-y-auto",
1031
- MEETING_SCHEDULER_H
1152
+ "md:justify-center md:overflow-y-auto"
1032
1153
  );
1033
1154
  function isNativelyBookable(availability) {
1034
1155
  if (!availability.formFields.every(isSupportedFormField)) return false;
@@ -1050,7 +1171,9 @@ function HubSpotMeetingScheduler({
1050
1171
  fallbackUrl,
1051
1172
  onBack,
1052
1173
  onBooked,
1053
- className
1174
+ className,
1175
+ flow = "slot-first",
1176
+ detailsForm: DetailsForm = BookingForm
1054
1177
  }) {
1055
1178
  const {
1056
1179
  availability,
@@ -1063,7 +1186,8 @@ function HubSpotMeetingScheduler({
1063
1186
  book,
1064
1187
  isSubmitting
1065
1188
  } = useMeetingBooking({ meetingId, apiBaseUrl, initialAvailability });
1066
- const hydrated = _chunkYLVPQNLOcjs.useIsHydrated.call(void 0, );
1189
+ const detailsFirst = flow === "details-first";
1190
+ const hydrated = _chunk5MSHWXJ5cjs.useIsHydrated.call(void 0, );
1067
1191
  const [pickedTimezone, setTimezone] = _react.useState.call(void 0, null);
1068
1192
  const resolvedLocalTimezone = _react.useMemo.call(void 0, () => {
1069
1193
  if (!hydrated) return null;
@@ -1074,30 +1198,33 @@ function HubSpotMeetingScheduler({
1074
1198
  }
1075
1199
  }, [hydrated]);
1076
1200
  const timezone = _nullishCoalesce(_nullishCoalesce(pickedTimezone, () => ( displayTimezone)), () => ( resolvedLocalTimezone));
1077
- const [step, setStep] = _react.useState.call(void 0, "slot");
1201
+ const [step, setStep] = _react.useState.call(void 0, detailsFirst ? "details" : "slot");
1202
+ const [stash, setStash] = _react.useState.call(void 0, null);
1203
+ const formOnly = detailsFirst && step === "details";
1078
1204
  const [pickedDurationMs, setDurationMs] = _react.useState.call(void 0, null);
1079
1205
  const [pickedDay, setSelectedDay] = _react.useState.call(void 0, null);
1080
1206
  const [selectedSlot, setSelectedSlot] = _react.useState.call(void 0, null);
1081
1207
  const [confirmation, setConfirmation] = _react.useState.call(void 0, null);
1082
1208
  const [bookingError, setBookingError] = _react.useState.call(void 0, null);
1083
- const { honeypotInputProps, getSignals, resetSignals } = _chunkFKXDDJEQcjs.useHumanitySignals.call(void 0, );
1084
- const { toast } = _chunkFKXDDJEQcjs.useToast.call(void 0, );
1209
+ const { honeypotInputProps, getSignals, resetSignals } = _chunkM4YQUHORcjs.useHumanitySignals.call(void 0, );
1210
+ const { toast } = _chunkM4YQUHORcjs.useToast.call(void 0, );
1085
1211
  const autoAdvanceCount = _react.useRef.call(void 0, 0);
1086
1212
  const [machineFor, setMachineFor] = _react.useState.call(void 0, meetingId);
1087
1213
  if (machineFor !== meetingId) {
1088
1214
  setMachineFor(meetingId);
1089
- setStep("slot");
1215
+ setStep(detailsFirst ? "details" : "slot");
1090
1216
  setDurationMs(null);
1091
1217
  setSelectedDay(null);
1092
1218
  setSelectedSlot(null);
1093
1219
  setConfirmation(null);
1094
1220
  setBookingError(null);
1221
+ setStash(null);
1095
1222
  }
1096
1223
  _react.useEffect.call(void 0, () => {
1097
1224
  autoAdvanceCount.current = 0;
1098
1225
  }, [meetingId]);
1099
- const durations = _react.useMemo.call(void 0, () => _nullishCoalesce(_optionalChain([availability, 'optionalAccess', _27 => _27.durationsMs]), () => ( [])), [_optionalChain([availability, 'optionalAccess', _28 => _28.durationsMs])]);
1100
- const shownHosts = _nullishCoalesce(_nullishCoalesce(hosts, () => ( _optionalChain([availability, 'optionalAccess', _29 => _29.hosts]))), () => ( []));
1226
+ const durations = _react.useMemo.call(void 0, () => _nullishCoalesce(_optionalChain([availability, 'optionalAccess', _31 => _31.durationsMs]), () => ( [])), [_optionalChain([availability, 'optionalAccess', _32 => _32.durationsMs])]);
1227
+ const shownHosts = _nullishCoalesce(_nullishCoalesce(hosts, () => ( _optionalChain([availability, 'optionalAccess', _33 => _33.hosts]))), () => ( []));
1101
1228
  const durationMs = _nullishCoalesce(_nullishCoalesce(pickedDurationMs, () => ( durations[0])), () => ( null));
1102
1229
  const slots = _react.useMemo.call(void 0, () => {
1103
1230
  if (!availability || durationMs == null) return [];
@@ -1126,14 +1253,34 @@ function HubSpotMeetingScheduler({
1126
1253
  setStep("slot");
1127
1254
  setBookingError(null);
1128
1255
  }, []);
1256
+ const backToDetails = _react.useCallback.call(void 0, () => {
1257
+ setStep("details");
1258
+ setBookingError(null);
1259
+ }, []);
1260
+ const stashDetails = _react.useCallback.call(void 0,
1261
+ (payload) => {
1262
+ setBookingError(null);
1263
+ setStash({ payload, signals: getSignals() });
1264
+ setStep("slot");
1265
+ autoAdvanceCount.current = 0;
1266
+ void refetchAvailability();
1267
+ return Promise.resolve();
1268
+ },
1269
+ [getSignals, refetchAvailability]
1270
+ );
1129
1271
  const handleSubmit = _react.useCallback.call(void 0,
1130
1272
  async (payload) => {
1273
+ const priorError = bookingError;
1131
1274
  setBookingError(null);
1132
1275
  const result = await book(payload);
1276
+ if (!result.ok && result.message === "Already submitting") {
1277
+ setBookingError(priorError);
1278
+ return;
1279
+ }
1133
1280
  if (result.ok && result.confirmation) {
1134
1281
  setConfirmation(result.confirmation);
1135
1282
  setStep("confirmed");
1136
- _optionalChain([onBooked, 'optionalCall', _30 => _30(result.confirmation)]);
1283
+ _optionalChain([onBooked, 'optionalCall', _34 => _34(result.confirmation)]);
1137
1284
  return;
1138
1285
  }
1139
1286
  const code = _nullishCoalesce(result.code, () => ( "TEMPORARILY_UNAVAILABLE"));
@@ -1141,8 +1288,10 @@ function HubSpotMeetingScheduler({
1141
1288
  if (code === "SLOT_TAKEN") {
1142
1289
  setSelectedSlot(null);
1143
1290
  setStep("slot");
1144
- resetSignals();
1291
+ if (!detailsFirst) resetSignals();
1145
1292
  void refetchAvailability();
1293
+ } else if (detailsFirst && (code === "VALIDATION" || code === "INVALID_EMAIL")) {
1294
+ setStep("details");
1146
1295
  } else {
1147
1296
  toast({
1148
1297
  variant: "error",
@@ -1151,29 +1300,31 @@ function HubSpotMeetingScheduler({
1151
1300
  });
1152
1301
  }
1153
1302
  },
1154
- [book, onBooked, refetchAvailability, resetSignals, toast]
1303
+ [book, bookingError, detailsFirst, onBooked, refetchAvailability, resetSignals, toast]
1155
1304
  );
1156
1305
  const escapeHatch = fallbackUrl ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkCJBSU3XBcjs.Button, { variant: "outline", size: "small-legacy", href: fallbackUrl, openInNewTab: true, children: "Open in HubSpot" }) : null;
1306
+ const flowHeight = detailsFirst ? MEETING_SCHEDULER_DETAILS_FIRST_H : MEETING_SCHEDULER_H;
1307
+ const unseededDetailsFirstFailure = detailsFirst && step === "details" && !availability && !initialAvailability && !hydrated;
1308
+ const degradedCard = /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, CARD_DEGRADED_CLASS, flowHeight, className), children: [
1309
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary text-h6", children: "We couldn't load available call times. Please try again shortly." }),
1310
+ escapeHatch
1311
+ ] });
1312
+ if (unseededDetailsFirstFailure) return degradedCard;
1157
1313
  if (isLoadingAvailability && !availability) {
1158
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, CARD_CLASS, className), children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: CARD_INNER_CLASS, children: [
1159
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ContextPanelSkeleton, { onBack, className: CONTEXT_PANEL_CLASS }),
1160
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: ACTION_PANEL_CLASS, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SlotPickerSkeleton, { monthOffset }) })
1314
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, CARD_CLASS, flowHeight, formOnly && "bg-ods-bg", className), children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: CARD_INNER_CLASS, children: [
1315
+ !formOnly && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ContextPanelSkeleton, { onBack, className: CONTEXT_PANEL_CLASS }),
1316
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: ACTION_PANEL_CLASS, children: detailsFirst && step === "details" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BookingFormSkeleton, {}) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SlotPickerSkeleton, { monthOffset }) })
1161
1317
  ] }) });
1162
1318
  }
1163
- if (availabilityError || !availability) {
1164
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, CARD_DEGRADED_CLASS, className), children: [
1165
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary text-h6", children: "We couldn't load available call times. Please try again shortly." }),
1166
- escapeHatch
1167
- ] });
1168
- }
1319
+ if (availabilityError || !availability) return degradedCard;
1169
1320
  if (!isNativelyBookable(availability)) {
1170
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, CARD_DEGRADED_CLASS, className), children: [
1321
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, CARD_DEGRADED_CLASS, flowHeight, className), children: [
1171
1322
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary text-h6", children: "This meeting type is booked directly on HubSpot." }),
1172
1323
  escapeHatch
1173
1324
  ] });
1174
1325
  }
1175
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, CARD_CLASS, className), children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: CARD_INNER_CLASS, children: [
1176
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1326
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, CARD_CLASS, flowHeight, formOnly && "bg-ods-bg", className), children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: CARD_INNER_CLASS, children: [
1327
+ !formOnly && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1177
1328
  SchedulerContextPanel,
1178
1329
  {
1179
1330
  hosts: shownHosts,
@@ -1185,18 +1336,24 @@ function HubSpotMeetingScheduler({
1185
1336
  setDurationMs(ms);
1186
1337
  setSelectedDay(null);
1187
1338
  setSelectedSlot(null);
1188
- if (step === "details") setStep("slot");
1339
+ if (!detailsFirst && step === "details") setStep("slot");
1189
1340
  },
1190
1341
  timezone,
1191
1342
  onTimezoneChange: setTimezone,
1192
- onBack: step === "details" ? backToSlot : onBack,
1193
- locked: step !== "slot",
1343
+ onBack: detailsFirst ? step === "slot" ? backToDetails : onBack : step === "details" ? backToSlot : onBack,
1344
+ locked: detailsFirst ? step === "confirmed" || isSubmitting : step !== "slot",
1194
1345
  showTimezone: step !== "confirmed",
1346
+ fixedDuration: detailsFirst,
1195
1347
  className: CONTEXT_PANEL_CLASS
1196
1348
  }
1197
1349
  ),
1198
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: ACTION_PANEL_CLASS, children: step === "confirmed" && confirmation && timezone ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, "flex flex-1 flex-col", PANEL_STEP_CLASS), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Confirmation, { confirmation, timezone }) }) : step === "details" && durationMs != null && selectedSlot != null && timezone ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, "flex flex-1 flex-col gap-[var(--spacing-system-m)]", PANEL_STEP_CLASS), children: [
1199
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { className: "text-ods-text-primary text-h4", children: [
1350
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: ACTION_PANEL_CLASS, children: step === "confirmed" && confirmation && timezone ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, "flex flex-1 flex-col", PANEL_STEP_CLASS), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Confirmation, { confirmation, timezone }) }) : step === "details" && (detailsFirst ? (
1351
+ // The form is step ONE here: no slot yet, and `timezone` is null
1352
+ // on the server render, so neither may gate the PANEL. A link
1353
+ // publishing no durations has no form worth showing.
1354
+ durations.length > 0
1355
+ ) : durationMs != null && selectedSlot != null && timezone) ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunk23V5BSHDcjs.cn.call(void 0, "flex flex-1 flex-col gap-[var(--spacing-system-m)]", PANEL_STEP_CLASS), children: [
1356
+ selectedSlot != null && durationMs != null && timezone != null && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { className: "text-ods-text-primary text-h4", children: [
1200
1357
  new Intl.DateTimeFormat(void 0, {
1201
1358
  timeZone: timezone,
1202
1359
  weekday: "long",
@@ -1208,29 +1365,33 @@ function HubSpotMeetingScheduler({
1208
1365
  }).format(new Date(selectedSlot)),
1209
1366
  " ",
1210
1367
  "\xB7 ",
1211
- _chunkY6I2DGKCcjs.formatDurationCompact.call(void 0, durationMs / 1e3)
1368
+ _chunkOMKI5T2Gcjs.formatDurationCompact.call(void 0, durationMs / 1e3)
1212
1369
  ] }),
1213
1370
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1214
- BookingForm,
1371
+ DetailsForm,
1215
1372
  {
1216
1373
  availability,
1217
1374
  meetingId,
1218
- startTimeMs: selectedSlot,
1219
- durationMs,
1375
+ startTimeMs: _nullishCoalesce(selectedSlot, () => ( void 0)),
1376
+ durationMs: _nullishCoalesce(durationMs, () => ( void 0)),
1220
1377
  timezone,
1378
+ deferSlot: detailsFirst,
1379
+ submitLabel: detailsFirst ? "Continue" : void 0,
1380
+ footerNote: detailsFirst ? "Next step: pick a slot that works. Calendar invite lands right after." : void 0,
1381
+ initialValues: detailsFirst ? _optionalChain([stash, 'optionalAccess', _35 => _35.payload]) : void 0,
1221
1382
  isSubmitting,
1222
- onSubmit: handleSubmit,
1383
+ onSubmit: detailsFirst ? stashDetails : handleSubmit,
1223
1384
  honeypotInputProps,
1224
1385
  getSignals
1225
1386
  }
1226
1387
  )
1227
1388
  ] }) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-[var(--spacing-system-m)] md:min-h-0 md:flex-1", children: [
1228
1389
  bookingError === "SLOT_TAKEN" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1229
- _chunkUBRVIVY4cjs.Alert,
1390
+ _chunkB2CSYMKWcjs.Alert,
1230
1391
  {
1231
1392
  variant: "warning",
1232
1393
  className: "mx-[var(--spacing-system-l)] mt-[var(--spacing-system-l)] w-auto lg:m-0 lg:w-full",
1233
- children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUBRVIVY4cjs.AlertDescription, { children: "That time was just taken \u2014 pick another slot below. (If you already submitted, check your email for a confirmation before rebooking.)" })
1394
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkB2CSYMKWcjs.AlertDescription, { children: "That time was just taken \u2014 pick another slot below. (If you already submitted, check your email for a confirmation before rebooking.)" })
1234
1395
  }
1235
1396
  ),
1236
1397
  timezone && durationMs != null ? (
@@ -1250,12 +1411,31 @@ function HubSpotMeetingScheduler({
1250
1411
  },
1251
1412
  selectedSlot,
1252
1413
  onSelectSlot: (ms) => {
1414
+ if (!detailsFirst) {
1415
+ setSelectedSlot(ms);
1416
+ setStep("details");
1417
+ return;
1418
+ }
1419
+ if (isSubmitting || !stash) return;
1253
1420
  setSelectedSlot(ms);
1254
- setStep("details");
1421
+ void handleSubmit({
1422
+ ...stash.payload,
1423
+ ...stash.signals,
1424
+ meetingId,
1425
+ // `ms`, NOT `selectedSlot` — the setState above has not
1426
+ // committed inside this handler, so state holds null on
1427
+ // the first booking and the PREVIOUS slot on a retry.
1428
+ startTimeMs: ms,
1429
+ // Live values: both stay editable after Continue, so the
1430
+ // copies frozen at that point can be stale.
1431
+ durationMs,
1432
+ timezone
1433
+ });
1255
1434
  },
1256
1435
  selectedDay,
1257
1436
  onSelectDay: setSelectedDay,
1258
- isLoading: isLoadingAvailability
1437
+ isLoading: isLoadingAvailability,
1438
+ isSubmitting: detailsFirst ? isSubmitting : void 0
1259
1439
  }
1260
1440
  )
1261
1441
  ) : durations.length === 0 && !isFetchingAvailability ? (
@@ -1280,5 +1460,8 @@ function HubSpotMeetingScheduler({
1280
1460
 
1281
1461
 
1282
1462
 
1283
- exports.HubSpotMeetingScheduler = HubSpotMeetingScheduler; exports.MEETING_SCHEDULER_H = MEETING_SCHEDULER_H; exports.MeetingSchedulerDirectory = MeetingSchedulerDirectory; exports.MeetingSchedulerDirectoryRowSkeleton = MeetingSchedulerDirectoryRowSkeleton;
1463
+
1464
+
1465
+
1466
+ exports.BookingForm = BookingForm; exports.BookingFormSkeleton = BookingFormSkeleton; exports.HubSpotMeetingScheduler = HubSpotMeetingScheduler; exports.MEETING_SCHEDULER_DETAILS_FIRST_H = MEETING_SCHEDULER_DETAILS_FIRST_H; exports.MEETING_SCHEDULER_H = MEETING_SCHEDULER_H; exports.MeetingSchedulerDirectory = MeetingSchedulerDirectory; exports.MeetingSchedulerDirectoryRowSkeleton = MeetingSchedulerDirectoryRowSkeleton;
1284
1467
  //# sourceMappingURL=index.cjs.map