@flamingo-stack/openframe-frontend-core 0.0.561-1852.4997.2 → 0.0.561

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 (146) hide show
  1. package/dist/{chunk-KGFCHGCW.js → chunk-44U25GD5.js} +2 -2
  2. package/dist/{chunk-DCB4EBA5.cjs → chunk-4LHEQMOV.cjs} +3 -3
  3. package/dist/chunk-4LHEQMOV.cjs.map +1 -0
  4. package/dist/{chunk-PYN65LCP.js → chunk-5AEHCGQV.js} +6 -6
  5. package/dist/{chunk-K4UCFJNL.cjs → chunk-AGQ4VTUX.cjs} +29 -29
  6. package/dist/{chunk-K4UCFJNL.cjs.map → chunk-AGQ4VTUX.cjs.map} +1 -1
  7. package/dist/{chunk-HI3A5HFI.js → chunk-B6TM3QAL.js} +4 -4
  8. package/dist/{chunk-NISIZABN.cjs → chunk-CR2CMLTQ.cjs} +4 -4
  9. package/dist/{chunk-NISIZABN.cjs.map → chunk-CR2CMLTQ.cjs.map} +1 -1
  10. package/dist/{chunk-K535WIFS.cjs → chunk-D3OY4CJU.cjs} +3 -3
  11. package/dist/{chunk-K535WIFS.cjs.map → chunk-D3OY4CJU.cjs.map} +1 -1
  12. package/dist/{chunk-RVHAX7VP.cjs → chunk-DAVVVBNL.cjs} +26 -26
  13. package/dist/{chunk-RVHAX7VP.cjs.map → chunk-DAVVVBNL.cjs.map} +1 -1
  14. package/dist/{chunk-V5VJTNOG.cjs → chunk-DHRJFUBR.cjs} +11 -11
  15. package/dist/{chunk-V5VJTNOG.cjs.map → chunk-DHRJFUBR.cjs.map} +1 -1
  16. package/dist/{chunk-LNWLK4TC.cjs → chunk-EK346HD7.cjs} +39 -39
  17. package/dist/{chunk-LNWLK4TC.cjs.map → chunk-EK346HD7.cjs.map} +1 -1
  18. package/dist/{chunk-SKQ7AMUD.cjs → chunk-FSWJCGRJ.cjs} +7 -7
  19. package/dist/{chunk-SKQ7AMUD.cjs.map → chunk-FSWJCGRJ.cjs.map} +1 -1
  20. package/dist/{chunk-3IBCKS3I.js → chunk-GKGQ4DWE.js} +121 -49
  21. package/dist/chunk-GKGQ4DWE.js.map +1 -0
  22. package/dist/{chunk-XTDUFU5O.cjs → chunk-GWRQ5EEI.cjs} +954 -882
  23. package/dist/{chunk-XTDUFU5O.cjs.map → chunk-GWRQ5EEI.cjs.map} +1 -1
  24. package/dist/{chunk-IJ6HBN2J.cjs → chunk-GYC3OTBI.cjs} +9 -9
  25. package/dist/{chunk-IJ6HBN2J.cjs.map → chunk-GYC3OTBI.cjs.map} +1 -1
  26. package/dist/{chunk-SFU6A36Q.js → chunk-JCQUWIPT.js} +3 -3
  27. package/dist/{chunk-NZNKHIFA.js → chunk-KRYLVEXU.js} +2 -2
  28. package/dist/{chunk-LSWJ5QYP.js → chunk-KWNVQZ5Y.js} +4 -4
  29. package/dist/{chunk-ZD5QQJH4.js → chunk-MLSDBNKT.js} +2 -2
  30. package/dist/{chunk-NTTSXF7Z.js → chunk-NGY4KET4.js} +2 -2
  31. package/dist/{chunk-O45VULK4.js → chunk-OCJG3X4U.js} +2 -2
  32. package/dist/{chunk-KKIAKLI6.js → chunk-ONDI64M3.js} +2 -2
  33. package/dist/{chunk-FMQO7OMJ.js → chunk-QGQ26NEE.js} +2 -2
  34. package/dist/{chunk-RSZXB6J2.js → chunk-RDKJCZHY.js} +3 -3
  35. package/dist/chunk-RDKJCZHY.js.map +1 -0
  36. package/dist/{chunk-ELFXMLSX.cjs → chunk-SUPBFRUK.cjs} +5 -5
  37. package/dist/{chunk-ELFXMLSX.cjs.map → chunk-SUPBFRUK.cjs.map} +1 -1
  38. package/dist/{chunk-BODITFZI.cjs → chunk-UJ7MSY6F.cjs} +31 -31
  39. package/dist/{chunk-BODITFZI.cjs.map → chunk-UJ7MSY6F.cjs.map} +1 -1
  40. package/dist/{chunk-INN323YY.cjs → chunk-UV53Z64O.cjs} +14 -14
  41. package/dist/{chunk-INN323YY.cjs.map → chunk-UV53Z64O.cjs.map} +1 -1
  42. package/dist/{chunk-TCQ3VL5R.cjs → chunk-WCM4BGHO.cjs} +97 -97
  43. package/dist/{chunk-TCQ3VL5R.cjs.map → chunk-WCM4BGHO.cjs.map} +1 -1
  44. package/dist/{chunk-DQI2S2SY.js → chunk-YUAKZNK5.js} +6 -6
  45. package/dist/{chunk-5XPYQ7NU.cjs → chunk-ZENRHE55.cjs} +62 -62
  46. package/dist/{chunk-5XPYQ7NU.cjs.map → chunk-ZENRHE55.cjs.map} +1 -1
  47. package/dist/{chunk-CLQ6L4JG.js → chunk-ZJ7RI62F.js} +2 -2
  48. package/dist/components/calendar.cjs +81 -4
  49. package/dist/components/calendar.cjs.map +1 -1
  50. package/dist/components/calendar.js +81 -4
  51. package/dist/components/calendar.js.map +1 -1
  52. package/dist/components/case-studies/index.cjs +9 -9
  53. package/dist/components/case-studies/index.js +3 -3
  54. package/dist/components/chat/index.cjs +3 -3
  55. package/dist/components/chat/index.js +2 -2
  56. package/dist/components/contact/index.cjs +4 -4
  57. package/dist/components/contact/index.js +3 -3
  58. package/dist/components/docs/index.cjs +6 -6
  59. package/dist/components/docs/index.js +5 -5
  60. package/dist/components/embeds/index.cjs +4 -4
  61. package/dist/components/embeds/index.js +3 -3
  62. package/dist/components/faq/index.cjs +4 -4
  63. package/dist/components/faq/index.js +3 -3
  64. package/dist/components/features/index.cjs +5 -3
  65. package/dist/components/features/index.cjs.map +1 -1
  66. package/dist/components/features/index.d.ts +1 -1
  67. package/dist/components/features/index.d.ts.map +1 -1
  68. package/dist/components/features/index.js +4 -2
  69. package/dist/components/features/use-walkthrough-video.d.ts +1 -1
  70. package/dist/components/features/use-walkthrough-video.d.ts.map +1 -1
  71. package/dist/components/features/{floating-walkthrough-video.d.ts → walkthrough-video.d.ts} +61 -7
  72. package/dist/components/features/walkthrough-video.d.ts.map +1 -0
  73. package/dist/components/help-center-pages/index.cjs +23 -23
  74. package/dist/components/help-center-pages/index.js +14 -14
  75. package/dist/components/index.cjs +144 -140
  76. package/dist/components/index.cjs.map +1 -1
  77. package/dist/components/index.js +16 -12
  78. package/dist/components/index.js.map +1 -1
  79. package/dist/components/meeting-scheduler/booking-form.d.ts.map +1 -1
  80. package/dist/components/meeting-scheduler/context-panel.d.ts +24 -6
  81. package/dist/components/meeting-scheduler/context-panel.d.ts.map +1 -1
  82. package/dist/components/meeting-scheduler/index.cjs +529 -425
  83. package/dist/components/meeting-scheduler/index.cjs.map +1 -1
  84. package/dist/components/meeting-scheduler/index.d.ts +54 -1
  85. package/dist/components/meeting-scheduler/index.d.ts.map +1 -1
  86. package/dist/components/meeting-scheduler/index.js +507 -403
  87. package/dist/components/meeting-scheduler/index.js.map +1 -1
  88. package/dist/components/meeting-scheduler/slot-picker.d.ts +35 -31
  89. package/dist/components/meeting-scheduler/slot-picker.d.ts.map +1 -1
  90. package/dist/components/navigation/index.cjs +3 -3
  91. package/dist/components/navigation/index.js +2 -2
  92. package/dist/components/onboarding-guides/index.cjs +6 -6
  93. package/dist/components/onboarding-guides/index.js +5 -5
  94. package/dist/components/related-content/index.cjs +4 -4
  95. package/dist/components/related-content/index.js +3 -3
  96. package/dist/components/tickets/index.cjs +7 -7
  97. package/dist/components/tickets/index.js +6 -6
  98. package/dist/components/ui/date-picker.d.ts +62 -1
  99. package/dist/components/ui/date-picker.d.ts.map +1 -1
  100. package/dist/components/ui/field-wrapper.d.ts +7 -0
  101. package/dist/components/ui/field-wrapper.d.ts.map +1 -1
  102. package/dist/components/ui/file-manager/index.cjs +36 -36
  103. package/dist/components/ui/file-manager/index.js +1 -1
  104. package/dist/components/ui/index.cjs +5 -3
  105. package/dist/components/ui/index.cjs.map +1 -1
  106. package/dist/components/ui/index.js +4 -2
  107. package/dist/hooks/use-meeting-booking.d.ts +31 -8
  108. package/dist/hooks/use-meeting-booking.d.ts.map +1 -1
  109. package/dist/index.cjs +7 -3
  110. package/dist/index.cjs.map +1 -1
  111. package/dist/index.js +6 -2
  112. package/package.json +1 -1
  113. package/src/components/features/{.floating-walkthrough-video.md → .walkthrough-video.md} +8 -5
  114. package/src/components/features/board/types.ts +1 -1
  115. package/src/components/features/index.ts +1 -1
  116. package/src/components/features/use-walkthrough-video.ts +1 -1
  117. package/src/components/features/{floating-walkthrough-video.tsx → walkthrough-video.tsx} +108 -22
  118. package/src/components/meeting-scheduler/booking-form.tsx +60 -51
  119. package/src/components/meeting-scheduler/confirmation.tsx +1 -1
  120. package/src/components/meeting-scheduler/context-panel.tsx +166 -68
  121. package/src/components/meeting-scheduler/index.tsx +227 -81
  122. package/src/components/meeting-scheduler/slot-picker.tsx +275 -127
  123. package/src/components/ui/date-picker.tsx +200 -47
  124. package/src/components/ui/field-wrapper.tsx +9 -2
  125. package/src/hooks/use-meeting-booking.ts +97 -73
  126. package/dist/chunk-3IBCKS3I.js.map +0 -1
  127. package/dist/chunk-7J4DGFHZ.js +0 -88
  128. package/dist/chunk-7J4DGFHZ.js.map +0 -1
  129. package/dist/chunk-DCB4EBA5.cjs.map +0 -1
  130. package/dist/chunk-MKPJYEOR.cjs +0 -88
  131. package/dist/chunk-MKPJYEOR.cjs.map +0 -1
  132. package/dist/chunk-RSZXB6J2.js.map +0 -1
  133. package/dist/components/features/floating-walkthrough-video.d.ts.map +0 -1
  134. /package/dist/{chunk-KGFCHGCW.js.map → chunk-44U25GD5.js.map} +0 -0
  135. /package/dist/{chunk-PYN65LCP.js.map → chunk-5AEHCGQV.js.map} +0 -0
  136. /package/dist/{chunk-HI3A5HFI.js.map → chunk-B6TM3QAL.js.map} +0 -0
  137. /package/dist/{chunk-SFU6A36Q.js.map → chunk-JCQUWIPT.js.map} +0 -0
  138. /package/dist/{chunk-NZNKHIFA.js.map → chunk-KRYLVEXU.js.map} +0 -0
  139. /package/dist/{chunk-LSWJ5QYP.js.map → chunk-KWNVQZ5Y.js.map} +0 -0
  140. /package/dist/{chunk-ZD5QQJH4.js.map → chunk-MLSDBNKT.js.map} +0 -0
  141. /package/dist/{chunk-NTTSXF7Z.js.map → chunk-NGY4KET4.js.map} +0 -0
  142. /package/dist/{chunk-O45VULK4.js.map → chunk-OCJG3X4U.js.map} +0 -0
  143. /package/dist/{chunk-KKIAKLI6.js.map → chunk-ONDI64M3.js.map} +0 -0
  144. /package/dist/{chunk-FMQO7OMJ.js.map → chunk-QGQ26NEE.js.map} +0 -0
  145. /package/dist/{chunk-DQI2S2SY.js.map → chunk-YUAKZNK5.js.map} +0 -0
  146. /package/dist/{chunk-CLQ6L4JG.js.map → chunk-ZJ7RI62F.js.map} +0 -0
@@ -2,13 +2,12 @@
2
2
  "use client";
3
3
 
4
4
 
5
- var _chunkMKPJYEORcjs = require('../../chunk-MKPJYEOR.cjs');
5
+ var _chunkD3OY4CJUcjs = require('../../chunk-D3OY4CJU.cjs');
6
6
 
7
7
 
8
- var _chunkK535WIFScjs = require('../../chunk-K535WIFS.cjs');
8
+ var _chunkCR2CMLTQcjs = require('../../chunk-CR2CMLTQ.cjs');
9
9
 
10
10
 
11
- var _chunkNISIZABNcjs = require('../../chunk-NISIZABN.cjs');
12
11
 
13
12
 
14
13
 
@@ -25,8 +24,7 @@ var _chunkNISIZABNcjs = require('../../chunk-NISIZABN.cjs');
25
24
 
26
25
 
27
26
 
28
-
29
- var _chunkXTDUFU5Ocjs = require('../../chunk-XTDUFU5O.cjs');
27
+ var _chunkGWRQ5EEIcjs = require('../../chunk-GWRQ5EEI.cjs');
30
28
  require('../../chunk-C5RS3QLV.cjs');
31
29
  require('../../chunk-XL4V2PYG.cjs');
32
30
  require('../../chunk-BZFW3FOF.cjs');
@@ -36,9 +34,7 @@ require('../../chunk-BZFW3FOF.cjs');
36
34
  var _chunkNK3M6F5Acjs = require('../../chunk-NK3M6F5A.cjs');
37
35
  require('../../chunk-SSJNN5BS.cjs');
38
36
  require('../../chunk-3M2MFP2Y.cjs');
39
-
40
-
41
- var _chunkUTVOBFXRcjs = require('../../chunk-UTVOBFXR.cjs');
37
+ require('../../chunk-UTVOBFXR.cjs');
42
38
  require('../../chunk-XQFFGR6U.cjs');
43
39
  require('../../chunk-CEAAOVCV.cjs');
44
40
 
@@ -46,7 +42,8 @@ require('../../chunk-CEAAOVCV.cjs');
46
42
 
47
43
 
48
44
 
49
- var _chunkDCB4EBA5cjs = require('../../chunk-DCB4EBA5.cjs');
45
+
46
+ var _chunk4LHEQMOVcjs = require('../../chunk-4LHEQMOV.cjs');
50
47
  require('../../chunk-WZW7C7TF.cjs');
51
48
 
52
49
 
@@ -67,6 +64,7 @@ _chunkKI4EGKNVcjs.init_cn.call(void 0, );
67
64
  var _react = require('react');
68
65
 
69
66
  // src/hooks/use-meeting-booking.ts
67
+ var _reactquery = require('@tanstack/react-query');
70
68
 
71
69
  var KNOWN_CODES = [
72
70
  "SLOT_TAKEN",
@@ -75,17 +73,17 @@ var KNOWN_CODES = [
75
73
  "TEMPORARILY_UNAVAILABLE",
76
74
  "MEETING_UNAVAILABLE"
77
75
  ];
76
+ var AVAILABILITY_STALE_MS = 3e4;
77
+ function meetingAvailabilityKey(apiBaseUrl, meetingId, monthOffset) {
78
+ return ["meeting-availability", apiBaseUrl, meetingId, monthOffset];
79
+ }
78
80
  function useMeetingBooking(options) {
79
81
  const { meetingId, apiBaseUrl = "", initialAvailability } = options;
80
- const seededFor = _optionalChain([initialAvailability, 'optionalAccess', _3 => _3.meetingId]) === meetingId ? initialAvailability : void 0;
81
- const [availability, setAvailability] = _react.useState.call(void 0, _nullishCoalesce(seededFor, () => ( null)));
82
- const [monthOffset, setMonthOffsetState] = _react.useState.call(void 0, _nullishCoalesce(_optionalChain([seededFor, 'optionalAccess', _4 => _4.monthOffset]), () => ( 0)));
83
- const [isLoadingAvailability, setIsLoadingAvailability] = _react.useState.call(void 0, !seededFor);
84
- const [availabilityError, setAvailabilityError] = _react.useState.call(void 0, null);
85
- const [isSubmitting, setIsSubmitting] = _react.useState.call(void 0, false);
86
- const submittingRef = _react.useRef.call(void 0, false);
82
+ const queryClient = _reactquery.useQueryClient.call(void 0, );
83
+ const seededOffset = _optionalChain([initialAvailability, 'optionalAccess', _2 => _2.meetingId]) === meetingId ? initialAvailability.monthOffset : void 0;
84
+ const [monthOffset, setMonthOffsetState] = _react.useState.call(void 0, _nullishCoalesce(seededOffset, () => ( 0)));
87
85
  const setMonthOffset = _react.useCallback.call(void 0, (offset) => {
88
- setMonthOffsetState(Math.max(0, Math.min(_chunkXTDUFU5Ocjs.MAX_MONTH_OFFSET, offset)));
86
+ setMonthOffsetState(Math.max(0, Math.min(_chunkGWRQ5EEIcjs.MAX_MONTH_OFFSET, offset)));
89
87
  }, []);
90
88
  const prevMeetingIdRef = _react.useRef.call(void 0, meetingId);
91
89
  _react.useLayoutEffect.call(void 0, () => {
@@ -93,48 +91,27 @@ function useMeetingBooking(options) {
93
91
  prevMeetingIdRef.current = meetingId;
94
92
  setMonthOffsetState(0);
95
93
  }, [meetingId]);
96
- _react.useEffect.call(void 0, () => {
97
- const controller = new AbortController();
98
- let active = true;
99
- const load = async () => {
100
- setAvailabilityError(null);
101
- if (!availability || availability.meetingId !== meetingId || availability.monthOffset !== monthOffset) {
102
- setIsLoadingAvailability(true);
103
- }
104
- try {
105
- const params = new URLSearchParams({ meeting: meetingId, monthOffset: String(monthOffset) });
106
- const res = await _chunkNK3M6F5Acjs.contentFetch.call(void 0, `${apiBaseUrl}/api/meetings/availability?${params}`, {
107
- signal: controller.signal
108
- });
109
- if (!res.ok) throw new Error(`availability ${res.status}`);
110
- const data = await res.json();
111
- if (active) setAvailability(data);
112
- } catch (err) {
113
- if (!active || err instanceof DOMException && err.name === "AbortError") return;
114
- setAvailabilityError(err instanceof Error ? err.message : "Failed to load availability");
115
- } finally {
116
- if (active) setIsLoadingAvailability(false);
117
- }
118
- };
119
- void load();
120
- return () => {
121
- active = false;
122
- controller.abort();
123
- };
124
- }, [meetingId, monthOffset, apiBaseUrl]);
125
- const refetchAvailability = _react.useCallback.call(void 0, async () => {
126
- try {
94
+ const seed = _optionalChain([initialAvailability, 'optionalAccess', _3 => _3.meetingId]) === meetingId && initialAvailability.monthOffset === monthOffset ? initialAvailability : void 0;
95
+ const availabilityQuery = _reactquery.useQuery.call(void 0, {
96
+ queryKey: meetingAvailabilityKey(apiBaseUrl, meetingId, monthOffset),
97
+ queryFn: async ({ signal }) => {
127
98
  const params = new URLSearchParams({ meeting: meetingId, monthOffset: String(monthOffset) });
128
- const res = await _chunkNK3M6F5Acjs.contentFetch.call(void 0, `${apiBaseUrl}/api/meetings/availability?${params}`);
129
- if (res.ok) setAvailability(await res.json());
130
- } catch (e) {
131
- }
132
- }, [meetingId, monthOffset, apiBaseUrl]);
133
- const book = _react.useCallback.call(void 0,
134
- async (payload) => {
135
- if (submittingRef.current) return { ok: false, code: "VALIDATION", message: "Already submitting" };
136
- submittingRef.current = true;
137
- setIsSubmitting(true);
99
+ const res = await _chunkNK3M6F5Acjs.contentFetch.call(void 0, `${apiBaseUrl}/api/meetings/availability?${params}`, { signal });
100
+ if (!res.ok) throw new Error(`availability ${res.status}`);
101
+ return await res.json();
102
+ },
103
+ staleTime: AVAILABILITY_STALE_MS,
104
+ initialData: seed,
105
+ // Stamped as infinitely old on purpose: the seed is first-paint
106
+ // scaffolding for a 60-second-volatile resource, not truth, so it paints
107
+ // immediately AND is refetched immediately.
108
+ initialDataUpdatedAt: seed ? 0 : void 0
109
+ });
110
+ const refetchAvailability = _react.useCallback.call(void 0, async () => {
111
+ await queryClient.invalidateQueries({ queryKey: meetingAvailabilityKey(apiBaseUrl, meetingId, monthOffset) }).catch(() => void 0);
112
+ }, [queryClient, apiBaseUrl, meetingId, monthOffset]);
113
+ const bookMutation = _reactquery.useMutation.call(void 0, {
114
+ mutationFn: async (payload) => {
138
115
  try {
139
116
  const res = await _chunkNK3M6F5Acjs.contentFetch.call(void 0, `${apiBaseUrl}/api/meetings/book`, {
140
117
  method: "POST",
@@ -146,24 +123,39 @@ function useMeetingBooking(options) {
146
123
  const rawCode = typeof data.code === "string" ? data.code : "";
147
124
  const code = KNOWN_CODES.includes(rawCode) ? rawCode : "TEMPORARILY_UNAVAILABLE";
148
125
  return { ok: false, code, message: typeof data.error === "string" ? data.error : void 0 };
149
- } catch (e2) {
126
+ } catch (e) {
150
127
  return { ok: false, code: "TEMPORARILY_UNAVAILABLE" };
128
+ }
129
+ },
130
+ // A booking is not a read — never retried, at any layer.
131
+ retry: false
132
+ });
133
+ const submittingRef = _react.useRef.call(void 0, false);
134
+ const { mutateAsync } = bookMutation;
135
+ const book = _react.useCallback.call(void 0,
136
+ async (payload) => {
137
+ if (submittingRef.current) return { ok: false, code: "VALIDATION", message: "Already submitting" };
138
+ submittingRef.current = true;
139
+ try {
140
+ return await mutateAsync(payload);
151
141
  } finally {
152
142
  submittingRef.current = false;
153
- setIsSubmitting(false);
154
143
  }
155
144
  },
156
- [apiBaseUrl]
145
+ [mutateAsync]
157
146
  );
158
147
  return {
159
- availability,
160
- isLoadingAvailability,
161
- availabilityError,
148
+ availability: _nullishCoalesce(availabilityQuery.data, () => ( null)),
149
+ /** No availability for this month yet — the times column has nothing to show. */
150
+ isLoadingAvailability: availabilityQuery.isPending,
151
+ /** ANY request in flight, including a silent revalidation of cached data. */
152
+ isFetchingAvailability: availabilityQuery.isFetching,
153
+ availabilityError: availabilityQuery.error ? availabilityQuery.error.message : null,
162
154
  monthOffset,
163
155
  setMonthOffset,
164
156
  refetchAvailability,
165
157
  book,
166
- isSubmitting
158
+ isSubmitting: bookMutation.isPending
167
159
  };
168
160
  }
169
161
 
@@ -179,14 +171,14 @@ function isValidIanaTimezone(tz) {
179
171
  try {
180
172
  new Intl.DateTimeFormat("en-US", { timeZone: tz });
181
173
  return true;
182
- } catch (e3) {
174
+ } catch (e2) {
183
175
  return false;
184
176
  }
185
177
  }
186
178
  function isValidBcp47Locale(locale) {
187
179
  try {
188
180
  return Intl.getCanonicalLocales(locale).length > 0;
189
- } catch (e4) {
181
+ } catch (e3) {
190
182
  return false;
191
183
  }
192
184
  }
@@ -222,7 +214,7 @@ function makeBookingSchema(formFields, legalConsent) {
222
214
  }
223
215
  answers[field.name] = validator;
224
216
  }
225
- const requiredConsentIds = (_nullishCoalesce(_optionalChain([legalConsent, 'optionalAccess', _5 => _5.communicationConsentCheckboxes]), () => ( []))).filter((c) => c.required).map((c) => c.communicationTypeId);
217
+ const requiredConsentIds = (_nullishCoalesce(_optionalChain([legalConsent, 'optionalAccess', _4 => _4.communicationConsentCheckboxes]), () => ( []))).filter((c) => c.required).map((c) => c.communicationTypeId);
226
218
  const hasRequiredAnswers = formFields.some((f) => isSupportedFormField(f) && f.required);
227
219
  const answersObject = _zod.z.object(answers);
228
220
  return _zod.z.object({
@@ -259,37 +251,47 @@ function makeBookingSchema(formFields, legalConsent) {
259
251
 
260
252
  _chunkKI4EGKNVcjs.init_cn.call(void 0, );
261
253
  var _jsxruntime = require('react/jsx-runtime');
254
+ var PANEL_STACK = "flex flex-col gap-[var(--spacing-system-l)]";
255
+ var IDENTITY_ROW = "flex items-center justify-between gap-[var(--spacing-system-m)] lg:flex-col lg:items-stretch lg:gap-[var(--spacing-system-l)]";
256
+ var STRIP_BODY = "flex flex-col gap-[var(--spacing-system-l)] md:flex-row md:items-start lg:flex-col";
257
+ var STRIP_MAIN = "flex min-w-0 flex-col gap-[var(--spacing-system-l)] md:flex-1";
258
+ var STRIP_ASIDE = "flex flex-col gap-[var(--spacing-system-xxs)] md:w-[280px] md:shrink-0 lg:w-full";
259
+ var BACK_BUTTON_CLASS = "py-0";
260
+ var FIELD_LABEL_CLASS = "text-h4 text-ods-text-primary";
262
261
  function zoneLabel(tz) {
263
262
  try {
264
263
  const parts = new Intl.DateTimeFormat("en-US", {
265
264
  timeZone: tz,
266
265
  timeZoneName: "shortOffset"
267
266
  }).formatToParts(/* @__PURE__ */ new Date());
268
- const offset = _nullishCoalesce(_optionalChain([parts, 'access', _6 => _6.find, 'call', _7 => _7((p) => p.type === "timeZoneName"), 'optionalAccess', _8 => _8.value]), () => ( ""));
267
+ const offset = _nullishCoalesce(_optionalChain([parts, 'access', _5 => _5.find, 'call', _6 => _6((p) => p.type === "timeZoneName"), 'optionalAccess', _7 => _7.value]), () => ( ""));
269
268
  return offset ? `${tz.replace(/_/g, " ")} (${offset})` : tz.replace(/_/g, " ");
270
- } catch (e5) {
269
+ } catch (e4) {
271
270
  return tz.replace(/_/g, " ");
272
271
  }
273
272
  }
274
- function ContextPanelSkeleton({ className }) {
275
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkKI4EGKNVcjs.cn.call(void 0, "flex flex-col gap-[var(--spacing-system-mf)]", className), children: [
276
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-[var(--spacing-system-s)]", children: [
277
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkDCB4EBA5cjs.Skeleton, { className: "h-12 w-12 rounded-full shrink-0" }),
278
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-1 flex-col gap-[var(--spacing-system-xxs)]", children: [
279
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkDCB4EBA5cjs.Skeleton, { className: "h-5 w-32" }),
280
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkDCB4EBA5cjs.Skeleton, { className: "h-4 w-24" })
281
- ] })
282
- ] }),
283
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-[var(--spacing-system-xs)]", children: [
284
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h5 text-ods-text-secondary", children: "Duration" }),
285
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex gap-[var(--spacing-system-xs)]", children: [
286
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkDCB4EBA5cjs.Skeleton, { className: "h-9 w-20" }),
287
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkDCB4EBA5cjs.Skeleton, { className: "h-9 w-20" })
273
+ function ContextPanelSkeleton({
274
+ className,
275
+ onBack,
276
+ backLabel = "Back"
277
+ }) {
278
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkKI4EGKNVcjs.cn.call(void 0, PANEL_STACK, className), children: [
279
+ onBack && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkGWRQ5EEIcjs.BackButton, { label: backLabel, onClick: onBack, className: BACK_BUTTON_CLASS }),
280
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: STRIP_BODY, children: [
281
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: STRIP_MAIN, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: IDENTITY_ROW, children: [
282
+ /* @__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: [
283
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk4LHEQMOVcjs.Skeleton, { className: "h-8 w-8 shrink-0 rounded-full" }),
284
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-1 flex-col gap-[var(--spacing-system-xxs)]", children: [
285
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk4LHEQMOVcjs.Skeleton, { className: "h-5 w-32" }),
286
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk4LHEQMOVcjs.Skeleton, { className: "h-4 w-24" })
287
+ ] })
288
+ ] }),
289
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk4LHEQMOVcjs.Skeleton, { className: "h-4 w-20 shrink-0" })
290
+ ] }) }),
291
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: STRIP_ASIDE, children: [
292
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: FIELD_LABEL_CLASS, children: "Timezone" }),
293
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk4LHEQMOVcjs.Skeleton, { className: "h-12 w-full" })
288
294
  ] })
289
- ] }),
290
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-[var(--spacing-system-xs)]", children: [
291
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h5 text-ods-text-secondary", children: "Timezone" }),
292
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkDCB4EBA5cjs.Skeleton, { className: "h-12 w-full" })
293
295
  ] })
294
296
  ] });
295
297
  }
@@ -302,7 +304,10 @@ function SchedulerContextPanel({
302
304
  onSelectDuration,
303
305
  timezone,
304
306
  onTimezoneChange,
307
+ onBack,
308
+ backLabel = "Back",
305
309
  locked = false,
310
+ showTimezone = true,
306
311
  className
307
312
  }) {
308
313
  const zoneOptions = _react.useMemo.call(void 0, () => {
@@ -311,69 +316,86 @@ function SchedulerContextPanel({
311
316
  try {
312
317
  const intl = Intl;
313
318
  zones = intl.supportedValuesOf ? intl.supportedValuesOf("timeZone") : [timezone];
314
- } catch (e6) {
319
+ } catch (e5) {
315
320
  zones = [timezone];
316
321
  }
317
322
  if (!zones.includes(timezone)) zones = [timezone, ...zones];
318
323
  return zones.map((tz) => ({ value: tz, label: zoneLabel(tz) }));
319
324
  }, [timezone]);
320
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkKI4EGKNVcjs.cn.call(void 0, "flex flex-col gap-[var(--spacing-system-mf)]", className), children: [
321
- 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-s)]", children: [
322
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkXTDUFU5Ocjs.SquareAvatar, { variant: "round", size: "lg", src: _nullishCoalesce(host.avatarUrl, () => ( void 0)), alt: host.name, fallback: host.name }),
323
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col min-w-0", children: [
324
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h4 text-ods-text-primary truncate", children: host.name }),
325
- host.title && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h6 text-ods-text-secondary truncate", children: host.title })
326
- ] })
327
- ] }, host.name)) }),
328
- hosts.length > 3 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-[var(--spacing-system-xs)]", children: [
329
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkXTDUFU5Ocjs.AvatarStack, { people: hosts, max: 4, size: "lg" }),
330
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { className: "text-h6 text-ods-text-secondary", children: [
331
- hosts.length,
332
- " hosts on this calendar"
333
- ] })
334
- ] }),
335
- title && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h3 text-ods-text-primary", children: title }),
336
- description && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h6 text-ods-text-secondary", children: description }),
337
- locked ? (
338
- // Post-selection: selectors are GONE, not disabled the step summary
339
- // owns the chosen time/zone; the panel keeps a single static line.
340
- selectedDurationMs != null && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { className: "text-h6 text-ods-text-secondary", children: [
341
- _chunkXTDUFU5Ocjs.formatDurationCompact.call(void 0, selectedDurationMs / 1e3),
342
- " call"
343
- ] })
344
- ) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
345
- durationsMs.length > 1 ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-[var(--spacing-system-xs)]", children: [
346
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h5 text-ods-text-secondary", children: "Duration" }),
347
- /* @__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,
348
- _chunk7INXXQVKcjs.Button,
349
- {
350
- variant: selectedDurationMs === ms ? void 0 : "outline",
351
- size: "small-legacy",
352
- onClick: () => onSelectDuration(ms),
353
- children: _chunkXTDUFU5Ocjs.formatDurationCompact.call(void 0, ms / 1e3)
354
- },
355
- ms
356
- )) })
357
- ] }) : selectedDurationMs != null && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { className: "text-h6 text-ods-text-secondary", children: [
358
- _chunkXTDUFU5Ocjs.formatDurationCompact.call(void 0, selectedDurationMs / 1e3),
359
- " call"
325
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkKI4EGKNVcjs.cn.call(void 0, PANEL_STACK, className), children: [
326
+ onBack && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkGWRQ5EEIcjs.BackButton, { label: backLabel, onClick: onBack, className: BACK_BUTTON_CLASS }),
327
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: STRIP_BODY, children: [
328
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: STRIP_MAIN, children: [
329
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: IDENTITY_ROW, children: [
330
+ 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: [
331
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
332
+ _chunkGWRQ5EEIcjs.SquareAvatar,
333
+ {
334
+ variant: "round",
335
+ size: "sm",
336
+ src: _nullishCoalesce(host.avatarUrl, () => ( void 0)),
337
+ alt: host.name,
338
+ fallback: host.name
339
+ }
340
+ ),
341
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col min-w-0", children: [
342
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h4 text-ods-text-primary truncate", children: host.name }),
343
+ host.title && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h6 text-ods-text-secondary truncate", children: host.title })
344
+ ] })
345
+ ] }, host.name)) }),
346
+ hosts.length > 3 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-[var(--spacing-system-xs)]", children: [
347
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkGWRQ5EEIcjs.AvatarStack, { people: hosts, max: 4, size: "lg" }),
348
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { className: "text-h6 text-ods-text-secondary", children: [
349
+ hosts.length,
350
+ " hosts on this calendar"
351
+ ] })
352
+ ] }),
353
+ locked || durationsMs.length <= 1 ? (
354
+ // Post-selection, or a link that offers one length: a static line,
355
+ // which is what sits beside the host on the header-strip layouts.
356
+ selectedDurationMs != null && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { className: "shrink-0 text-h6 text-ods-text-secondary", children: [
357
+ _chunkGWRQ5EEIcjs.formatDurationCompact.call(void 0, selectedDurationMs / 1e3),
358
+ " call"
359
+ ] })
360
+ ) : null
361
+ ] }),
362
+ title && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h3 text-ods-text-primary", children: title }),
363
+ description && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h6 text-ods-text-secondary", children: description }),
364
+ !locked && durationsMs.length > 1 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-[var(--spacing-system-xxs)]", children: [
365
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: FIELD_LABEL_CLASS, children: "Duration" }),
366
+ /* @__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,
367
+ _chunk7INXXQVKcjs.Button,
368
+ {
369
+ variant: selectedDurationMs === ms ? void 0 : "outline",
370
+ size: "small-legacy",
371
+ onClick: () => onSelectDuration(ms),
372
+ children: _chunkGWRQ5EEIcjs.formatDurationCompact.call(void 0, ms / 1e3)
373
+ },
374
+ ms
375
+ )) })
376
+ ] })
360
377
  ] }),
361
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-[var(--spacing-system-xs)]", children: [
362
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h5 text-ods-text-secondary", children: "Timezone" }),
378
+ showTimezone && // Once a slot is chosen the picker is desktop-only, which is what all
379
+ // three mocks draw. On the narrow layouts this panel is a strip
380
+ // COMPETING with the form for the screen's height, and the step's own
381
+ // summary line states the zone one row below — so the fact survives,
382
+ // only the control steps aside. The 280px sidebar has the room, so
383
+ // there it stays.
384
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkKI4EGKNVcjs.cn.call(void 0, STRIP_ASIDE, locked && "max-lg:hidden"), children: [
385
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: FIELD_LABEL_CLASS, children: "Timezone" }),
363
386
  timezone ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
364
- _chunkXTDUFU5Ocjs.Autocomplete,
387
+ _chunkGWRQ5EEIcjs.Autocomplete,
365
388
  {
366
389
  value: timezone,
367
390
  onChange: (tz) => {
368
- if (tz) _optionalChain([onTimezoneChange, 'optionalCall', _9 => _9(tz)]);
391
+ if (tz) _optionalChain([onTimezoneChange, 'optionalCall', _8 => _8(tz)]);
369
392
  },
370
393
  options: zoneOptions,
371
394
  placeholder: "Search timezone\u2026",
372
- startAdornment: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkUTVOBFXRcjs.ClockIcon, { className: "size-4 shrink-0 text-ods-text-secondary" }),
373
395
  noOptionsText: "No matching timezone",
374
396
  showClearAll: false
375
397
  }
376
- ) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkDCB4EBA5cjs.Skeleton, { className: "h-12 w-full" })
398
+ ) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk4LHEQMOVcjs.Skeleton, { className: "h-12 w-full" })
377
399
  ] })
378
400
  ] })
379
401
  ] });
@@ -400,38 +422,109 @@ function dateFromDayKey(key) {
400
422
  function timeLabelInZone(ms, timeZone) {
401
423
  return new Intl.DateTimeFormat(void 0, { timeZone, hour: "numeric", minute: "2-digit" }).format(new Date(ms));
402
424
  }
403
- var CALENDAR_MIN_H = "min-h-[20.5rem]";
404
- var WEEKDAY_LABELS = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
425
+ var CALENDAR_W = "md:w-[19rem] md:shrink-0 lg:w-[16rem]";
426
+ var COLUMN_HEADING_CLASS = "shrink-0 text-h4 text-ods-text-primary";
427
+ var COLUMN_STACK = "flex min-h-0 flex-col gap-[var(--spacing-system-xxs)]";
428
+ var SLOT_PICKER_HEADING = "Select Date & Time";
429
+ var CHIP_GRID_CLASS = _chunkKI4EGKNVcjs.cn.call(void 0,
430
+ "grid grid-cols-[repeat(auto-fill,minmax(5.5rem,1fr))] content-start gap-[var(--spacing-system-xs)]",
431
+ "overflow-y-auto",
432
+ // PHONE: a stated window (~3 rows, the mock's 156px) that scrolls, rather
433
+ // than a list that runs the length of the day. Nothing else on the phone
434
+ // card has a height — the design lets each step be as tall as it needs —
435
+ // but a busy day is forty slots, and letting them all through turns a
436
+ // 700px card into a 1500px one and buries whatever the page puts below
437
+ // it. This is the one nested scroller worth having: a small, obviously
438
+ // bounded list with a visible edge, exactly as drawn.
439
+ "max-h-[9.75rem] md:max-h-none",
440
+ // No height of its own, and none borrowed from the calendar either: the card
441
+ // states one height, the panel and this row pass it down, and what is left
442
+ // after the column heading IS the scroll box. A long day scrolls inside it.
443
+ //
444
+ // `min-h-0` is the load-bearing half — a flex item's default
445
+ // `min-height:auto` refuses to shrink below its content, so without it the
446
+ // chips grow the column, then the row, then the card, and `overflow-y-auto`
447
+ // never gets a box smaller than its contents to scroll inside. That is the
448
+ // exact failure that kept this card at 404px when it was told to be 318.
449
+ "flex-1 min-h-0"
450
+ );
451
+ var CHIP_CLASS = "w-full px-[var(--spacing-system-xxs)]";
452
+ var SLOT_ROW_CLASS = _chunkKI4EGKNVcjs.cn.call(void 0,
453
+ "flex min-w-0 flex-col md:flex-row",
454
+ // Default `stretch` at every width, deliberately. Stacked, that is what
455
+ // makes each section span the card — an `items-start` here (it was here, to
456
+ // stop a column growing taller than its month) collapses both sections to
457
+ // their intrinsic WIDTH instead, which on a phone left the calendar and the
458
+ // chips huddled against the left edge with half the card empty. The
459
+ // calendar no longer needs protecting: its height is fixed, not derived.
460
+ "md:min-h-0 md:flex-1 lg:gap-[var(--spacing-system-lf)]"
461
+ );
462
+ var COLUMN_BOX = "p-[var(--spacing-system-l)] lg:p-0";
463
+ var COLUMN_DIVIDER = "border-b border-ods-border md:border-b-0 md:border-r lg:border-0";
405
464
  function monthLabelFor(offset) {
406
465
  const now = /* @__PURE__ */ new Date();
407
466
  const month = new Date(now.getFullYear(), now.getMonth() + offset, 1);
408
467
  return new Intl.DateTimeFormat("en-US", { month: "long", year: "numeric" }).format(month);
409
468
  }
410
- function CalendarSkeleton({ monthOffset = 0 }) {
411
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkKI4EGKNVcjs.cn.call(void 0, "flex flex-col gap-[var(--spacing-system-s)]", CALENDAR_MIN_H), children: [
412
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "relative h-8", children: [
413
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "absolute inset-x-0 top-0 flex h-8 items-center justify-between", children: [
414
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "flex h-8 w-8 items-center justify-center rounded-md border border-ods-border opacity-60", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.ChevronLeft, { className: "h-4 w-4 text-ods-text-muted" }) }),
415
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "flex h-8 w-8 items-center justify-center rounded-md border border-ods-border opacity-60", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.ChevronRight, { className: "h-4 w-4 text-ods-text-muted" }) })
416
- ] }),
417
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex h-8 items-center justify-center", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h6 text-ods-text-primary", children: monthLabelFor(monthOffset) }) })
418
- ] }),
419
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-y-1 py-1", children: [
420
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "grid grid-cols-7", children: WEEKDAY_LABELS.map((d) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex h-9 items-center justify-center text-h6 font-normal text-ods-text-secondary", children: d }, d)) }),
421
- Array.from({ length: 6 }, (_, row) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "grid grid-cols-7", children: Array.from({ length: 7 }, (_2, col) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex h-9 items-center justify-center", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkDCB4EBA5cjs.Skeleton, { className: "h-9 w-9 rounded-md" }) }, col)) }, `w-${row}`))
422
- ] })
423
- ] });
469
+ var DISABLE_EVERY_DAY = () => true;
470
+ var NOOP = () => void 0;
471
+ function DayCalendar({ monthOffset, onMonthOffsetChange, selectedDay, onSelectDay, slotsByDay }) {
472
+ const now = /* @__PURE__ */ new Date();
473
+ const startMonth = new Date(now.getFullYear(), now.getMonth(), 1);
474
+ const endMonth = new Date(now.getFullYear(), now.getMonth() + _chunkGWRQ5EEIcjs.MAX_MONTH_OFFSET + 1, 0);
475
+ const visibleMonth = new Date(now.getFullYear(), now.getMonth() + monthOffset, 1);
476
+ const dayHasNoSlots = _react.useCallback.call(void 0,
477
+ (day) => !_optionalChain([slotsByDay, 'optionalAccess', _9 => _9.has, 'call', _10 => _10(calendarDayKey(day))]),
478
+ [slotsByDay]
479
+ );
480
+ 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,
481
+ _chunkGWRQ5EEIcjs.DatePickerCalendar,
482
+ {
483
+ mode: "single",
484
+ bare: true,
485
+ month: visibleMonth,
486
+ onMonthChange: (month) => {
487
+ const offset = (month.getFullYear() - now.getFullYear()) * 12 + (month.getMonth() - now.getMonth());
488
+ onMonthOffsetChange(Math.max(0, Math.min(_chunkGWRQ5EEIcjs.MAX_MONTH_OFFSET, offset)));
489
+ },
490
+ fromDate: startMonth,
491
+ toDate: endMonth,
492
+ selected: selectedDay ? dateFromDayKey(selectedDay) : void 0,
493
+ onSelect: (value) => {
494
+ const day = value;
495
+ if (!day) return;
496
+ const key = calendarDayKey(day);
497
+ if (_optionalChain([slotsByDay, 'optionalAccess', _11 => _11.has, 'call', _12 => _12(key)])) onSelectDay(key);
498
+ },
499
+ disabledDays: slotsByDay === null ? DISABLE_EVERY_DAY : dayHasNoSlots
500
+ }
501
+ ) });
424
502
  }
425
503
  function SlotPickerSkeleton({ monthOffset = 0 }) {
426
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col md:flex-row gap-[var(--spacing-system-lf)]", children: [
427
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunkKI4EGKNVcjs.cn.call(void 0, "shrink-0", CALENDAR_MIN_H), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, CalendarSkeleton, { monthOffset }) }),
428
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex-1 min-w-0 flex flex-col gap-[var(--spacing-system-s)]", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TimeChipsSkeleton, {}) })
504
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: SLOT_ROW_CLASS, children: [
505
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkKI4EGKNVcjs.cn.call(void 0, COLUMN_STACK, COLUMN_BOX, COLUMN_DIVIDER, CALENDAR_W, "md:overflow-y-auto"), children: [
506
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: COLUMN_HEADING_CLASS, children: SLOT_PICKER_HEADING }),
507
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
508
+ DayCalendar,
509
+ {
510
+ monthOffset,
511
+ onMonthOffsetChange: NOOP,
512
+ selectedDay: null,
513
+ onSelectDay: NOOP,
514
+ slotsByDay: null
515
+ }
516
+ )
517
+ ] }),
518
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunkKI4EGKNVcjs.cn.call(void 0, COLUMN_STACK, COLUMN_BOX, "min-w-0 md:flex-1"), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TimeChipsSkeleton, {}) })
429
519
  ] });
430
520
  }
431
521
  function TimeChipsSkeleton() {
432
522
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
433
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkDCB4EBA5cjs.Skeleton, { className: "h-4 md:h-5 w-40" }),
434
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "grid grid-cols-2 sm:grid-cols-3 gap-[var(--spacing-system-xs)] content-start", children: Array.from({ length: 9 }, (_, i) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkDCB4EBA5cjs.Skeleton, { className: "h-10 w-full" }, i)) })
523
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: COLUMN_HEADING_CLASS, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk4LHEQMOVcjs.Skeleton, { className: "inline-block h-4 w-40 align-middle" }) }),
524
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: CHIP_GRID_CLASS, children: Array.from({ length: 16 }, (_, i) => (
525
+ // h-11 md:h-12 — the loaded chip's own default-size height.
526
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk4LHEQMOVcjs.Skeleton, { className: _chunkKI4EGKNVcjs.cn.call(void 0, CHIP_CLASS, "h-11 md:h-12") }, i)
527
+ )) })
435
528
  ] });
436
529
  }
437
530
  function SlotPicker({
@@ -456,58 +549,70 @@ function SlotPicker({
456
549
  for (const list of map.values()) list.sort((a, b) => a - b);
457
550
  return map;
458
551
  }, [slots, timezone]);
459
- const now = /* @__PURE__ */ new Date();
460
- const startMonth = new Date(now.getFullYear(), now.getMonth(), 1);
461
- const endMonth = new Date(now.getFullYear(), now.getMonth() + _chunkXTDUFU5Ocjs.MAX_MONTH_OFFSET, 1);
462
- const visibleMonth = new Date(now.getFullYear(), now.getMonth() + monthOffset, 1);
552
+ const visibleMonth = _react.useMemo.call(void 0, () => {
553
+ const now = /* @__PURE__ */ new Date();
554
+ return new Date(now.getFullYear(), now.getMonth() + monthOffset, 1);
555
+ }, [monthOffset]);
463
556
  const daySlots = selectedDay ? _nullishCoalesce(slotsByDay.get(selectedDay), () => ( [])) : [];
464
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col md:flex-row gap-[var(--spacing-system-lf)]", children: [
465
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunkKI4EGKNVcjs.cn.call(void 0, "shrink-0", CALENDAR_MIN_H), children: isLoading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, CalendarSkeleton, { monthOffset }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
466
- _chunkMKPJYEORcjs.Calendar,
467
- {
468
- month: visibleMonth,
469
- startMonth,
470
- endMonth,
471
- onMonthChange: (month) => {
472
- const offset = (month.getFullYear() - now.getFullYear()) * 12 + (month.getMonth() - now.getMonth());
473
- onMonthOffsetChange(Math.max(0, Math.min(_chunkXTDUFU5Ocjs.MAX_MONTH_OFFSET, offset)));
474
- },
475
- mode: "single",
476
- required: true,
477
- selected: selectedDay ? dateFromDayKey(selectedDay) : void 0,
478
- onSelect: (day) => {
479
- if (!day) return;
480
- const key = calendarDayKey(day);
481
- if (slotsByDay.has(key)) onSelectDay(key);
482
- },
483
- disabled: (day) => !slotsByDay.has(calendarDayKey(day)),
484
- className: "p-0"
485
- }
486
- ) }),
487
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex-1 min-w-0 flex flex-col gap-[var(--spacing-system-s)]", children: isLoading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TimeChipsSkeleton, {}) : selectedDay ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
488
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h6 text-ods-text-primary", children: new Intl.DateTimeFormat(void 0, {
557
+ const monthPrefix = `${visibleMonth.getFullYear()}-${String(visibleMonth.getMonth() + 1).padStart(2, "0")}`;
558
+ const monthHasSlots = [...slotsByDay.keys()].some((key) => key.startsWith(monthPrefix));
559
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: SLOT_ROW_CLASS, children: [
560
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkKI4EGKNVcjs.cn.call(void 0, COLUMN_STACK, COLUMN_BOX, COLUMN_DIVIDER, CALENDAR_W, "md:overflow-y-auto"), children: [
561
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: COLUMN_HEADING_CLASS, children: SLOT_PICKER_HEADING }),
562
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
563
+ DayCalendar,
564
+ {
565
+ monthOffset,
566
+ onMonthOffsetChange,
567
+ selectedDay,
568
+ onSelectDay,
569
+ slotsByDay: isLoading ? null : slotsByDay
570
+ }
571
+ )
572
+ ] }),
573
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunkKI4EGKNVcjs.cn.call(void 0, COLUMN_STACK, COLUMN_BOX, "min-w-0 md:flex-1"), children: isLoading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TimeChipsSkeleton, {}) : selectedDay ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
574
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: COLUMN_HEADING_CLASS, children: new Intl.DateTimeFormat(void 0, {
489
575
  weekday: "long",
490
576
  month: "long",
491
577
  day: "numeric"
492
578
  }).format(dateFromDayKey(selectedDay)) }),
493
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "grid grid-cols-2 sm:grid-cols-3 gap-[var(--spacing-system-xs)] content-start max-h-80 overflow-y-auto", children: daySlots.map((ms) => {
579
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: CHIP_GRID_CLASS, children: daySlots.map((ms) => {
494
580
  const isSelected = selectedSlot === ms;
495
581
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
496
582
  _chunk7INXXQVKcjs.Button,
497
583
  {
498
584
  variant: isSelected ? void 0 : "outline",
499
- size: "small-legacy",
500
585
  onClick: () => onSelectSlot(ms),
586
+ className: CHIP_CLASS,
501
587
  children: timeLabelInZone(ms, timezone)
502
588
  },
503
589
  ms
504
590
  );
505
591
  }) })
506
- ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h6 text-ods-text-secondary", children: [...slotsByDay.keys()].some(
507
- (k) => k.startsWith(
508
- `${visibleMonth.getFullYear()}-${String(visibleMonth.getMonth() + 1).padStart(2, "0")}`
509
- )
510
- ) ? "Pick a day to see available times." : "No available times this month \u2014 try the next one." }) })
592
+ ] }) : monthHasSlots ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h6 text-ods-text-secondary", children: "Pick a day to see available times." }) : (
593
+ // A fully-booked month used to just SAY "try the next one" and leave
594
+ // the visitor to find the chevron in the other column. The way out
595
+ // of a dead end belongs in the dead end.
596
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col items-start gap-[var(--spacing-system-s)]", children: [
597
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { className: "text-h6 text-ods-text-secondary", children: [
598
+ "No available times in ",
599
+ monthLabelFor(monthOffset),
600
+ "."
601
+ ] }),
602
+ monthOffset < _chunkGWRQ5EEIcjs.MAX_MONTH_OFFSET && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
603
+ _chunk7INXXQVKcjs.Button,
604
+ {
605
+ variant: "outline",
606
+ onClick: () => onMonthOffsetChange(monthOffset + 1),
607
+ rightIcon: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.ChevronRight, { className: "size-5" }),
608
+ children: [
609
+ "Check ",
610
+ monthLabelFor(monthOffset + 1)
611
+ ]
612
+ }
613
+ )
614
+ ] })
615
+ ) })
511
616
  ] });
512
617
  }
513
618
 
@@ -547,7 +652,7 @@ function BookingForm({
547
652
  lastName: "",
548
653
  email: "",
549
654
  formFields: {},
550
- legalConsentResponses: (_nullishCoalesce(_optionalChain([legalConsent, 'optionalAccess', _10 => _10.communicationConsentCheckboxes]), () => ( []))).map((c) => ({
655
+ legalConsentResponses: (_nullishCoalesce(_optionalChain([legalConsent, 'optionalAccess', _13 => _13.communicationConsentCheckboxes]), () => ( []))).map((c) => ({
551
656
  communicationTypeId: c.communicationTypeId,
552
657
  consented: false
553
658
  }))
@@ -557,127 +662,118 @@ function BookingForm({
557
662
  await onSubmit({ ...data, meetingId, startTimeMs, durationMs, timezone, ...getSignals() });
558
663
  });
559
664
  const fieldError = (name) => {
560
- const err = _optionalChain([errors, 'access', _11 => _11.formFields, 'optionalAccess', _12 => _12[name]]);
561
- return _optionalChain([err, 'optionalAccess', _13 => _13.message]);
665
+ const err = _optionalChain([errors, 'access', _14 => _14.formFields, 'optionalAccess', _15 => _15[name]]);
666
+ return _optionalChain([err, 'optionalAccess', _16 => _16.message]);
562
667
  };
563
- const inputClass = "bg-ods-card border-ods-border text-ods-text-primary placeholder-ods-text-secondary px-3 h-12";
564
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "form", { onSubmit: submit, className: "flex flex-col space-y-4 md:space-y-6", noValidate: true, children: [
565
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkXTDUFU5Ocjs.HoneypotField, { ...honeypotInputProps }),
566
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 md:gap-6", children: [
567
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col", children: [
568
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkDCB4EBA5cjs.Label, { htmlFor: "ms-first-name", children: [
569
- "First name",
570
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-ods-accent", children: "*" })
571
- ] }),
572
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
573
- _chunkDCB4EBA5cjs.Input,
574
- {
575
- id: "ms-first-name",
576
- autoComplete: "given-name",
577
- placeholder: "Jane",
578
- "aria-invalid": !!errors.firstName,
579
- className: inputClass,
580
- ...register("firstName")
581
- }
582
- ),
583
- errors.firstName && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-ods-error text-h6 mt-1", children: errors.firstName.message })
584
- ] }),
585
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col", children: [
586
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkDCB4EBA5cjs.Label, { htmlFor: "ms-last-name", children: [
587
- "Last name",
588
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-ods-accent", children: "*" })
589
- ] }),
590
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
591
- _chunkDCB4EBA5cjs.Input,
592
- {
593
- id: "ms-last-name",
594
- autoComplete: "family-name",
595
- placeholder: "Doe",
596
- "aria-invalid": !!errors.lastName,
597
- className: inputClass,
598
- ...register("lastName")
599
- }
600
- ),
601
- errors.lastName && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-ods-error text-h6 mt-1", children: errors.lastName.message })
602
- ] })
603
- ] }),
604
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col", children: [
605
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkDCB4EBA5cjs.Label, { htmlFor: "ms-email", children: [
606
- "Email",
607
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-ods-accent", children: "*" })
608
- ] }),
609
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
610
- _chunkDCB4EBA5cjs.Input,
668
+ const inputClass = "bg-ods-card border-ods-border text-ods-text-primary placeholder-ods-text-secondary px-3 h-11 md:h-12";
669
+ const FORM_STACK = "flex flex-col gap-[var(--spacing-system-l)]";
670
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "form", { onSubmit: submit, className: FORM_STACK, noValidate: true, children: [
671
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkGWRQ5EEIcjs.HoneypotField, { ...honeypotInputProps }),
672
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk4LHEQMOVcjs.FieldWrapper, { label: "Email", htmlFor: "ms-email", error: _optionalChain([errors, 'access', _17 => _17.email, 'optionalAccess', _18 => _18.message]), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
673
+ _chunk4LHEQMOVcjs.Input,
674
+ {
675
+ id: "ms-email",
676
+ type: "email",
677
+ required: true,
678
+ autoComplete: "email",
679
+ placeholder: "jane@company.com",
680
+ "aria-invalid": !!errors.email,
681
+ className: inputClass,
682
+ ...register("email")
683
+ }
684
+ ) }),
685
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "grid grid-cols-2 gap-[var(--spacing-system-m)]", children: [
686
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk4LHEQMOVcjs.FieldWrapper, { label: "First Name", htmlFor: "ms-first-name", error: _optionalChain([errors, 'access', _19 => _19.firstName, 'optionalAccess', _20 => _20.message]), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
687
+ _chunk4LHEQMOVcjs.Input,
611
688
  {
612
- id: "ms-email",
613
- type: "email",
614
- autoComplete: "email",
615
- placeholder: "jane@company.com",
616
- "aria-invalid": !!errors.email,
689
+ id: "ms-first-name",
690
+ required: true,
691
+ autoComplete: "given-name",
692
+ placeholder: "Jane",
693
+ "aria-invalid": !!errors.firstName,
617
694
  className: inputClass,
618
- ...register("email")
695
+ ...register("firstName")
619
696
  }
620
- ),
621
- errors.email && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-ods-error text-h6 mt-1", children: errors.email.message })
622
- ] }),
623
- supportedFields.map((field) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col", children: [
624
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkDCB4EBA5cjs.Label, { htmlFor: `ms-q-${field.name}`, children: [
625
- field.label,
626
- field.required && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-ods-accent", children: "*" })
627
- ] }),
628
- field.type === "textarea" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
629
- _chunkXTDUFU5Ocjs.Textarea,
630
- {
631
- id: `ms-q-${field.name}`,
632
- className: "bg-ods-card border-ods-border text-ods-text-primary placeholder-ods-text-secondary px-3",
633
- ...register(`formFields.${field.name}`)
634
- }
635
- ),
636
- field.type === "text" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
637
- _chunkDCB4EBA5cjs.Input,
697
+ ) }),
698
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk4LHEQMOVcjs.FieldWrapper, { label: "Last Name", htmlFor: "ms-last-name", error: _optionalChain([errors, 'access', _21 => _21.lastName, 'optionalAccess', _22 => _22.message]), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
699
+ _chunk4LHEQMOVcjs.Input,
638
700
  {
639
- id: `ms-q-${field.name}`,
640
- className: "bg-ods-card border-ods-border text-ods-text-primary placeholder-ods-text-secondary px-3 h-12",
641
- ...register(`formFields.${field.name}`)
642
- }
643
- ),
644
- (field.type === "select" || field.type === "radio") && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
645
- _reacthookform.Controller,
646
- {
647
- control,
648
- name: `formFields.${field.name}`,
649
- render: ({ field: rhf }) => field.type === "select" ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkXTDUFU5Ocjs.Select, { value: _nullishCoalesce(rhf.value, () => ( "")), onValueChange: rhf.onChange, children: [
650
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkXTDUFU5Ocjs.SelectTrigger, { id: `ms-q-${field.name}`, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkXTDUFU5Ocjs.SelectValue, { placeholder: "Select\u2026" }) }),
651
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkXTDUFU5Ocjs.SelectContent, { children: (_nullishCoalesce(field.options, () => ( []))).map((opt) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkXTDUFU5Ocjs.SelectItem, { value: opt, children: opt }, opt)) })
652
- ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkXTDUFU5Ocjs.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: [
653
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkXTDUFU5Ocjs.RadioGroupItem, { id: `ms-q-${field.name}-${opt}`, value: opt }),
654
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkDCB4EBA5cjs.Label, { htmlFor: `ms-q-${field.name}-${opt}`, children: opt })
655
- ] }, opt)) })
701
+ id: "ms-last-name",
702
+ required: true,
703
+ autoComplete: "family-name",
704
+ placeholder: "Doe",
705
+ "aria-invalid": !!errors.lastName,
706
+ className: inputClass,
707
+ ...register("lastName")
656
708
  }
657
- ),
658
- field.type === "checkbox" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
659
- _reacthookform.Controller,
660
- {
661
- control,
662
- name: `formFields.${field.name}`,
663
- render: ({ field: rhf }) => (
664
- // The question's Label above already carries the text and
665
- // binds to this id — a second inline label would double the
666
- // visible text AND the accessible name.
667
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex items-center gap-[var(--spacing-system-xs)]", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
668
- _chunkDCB4EBA5cjs.Checkbox,
669
- {
670
- id: `ms-q-${field.name}`,
671
- checked: Boolean(rhf.value),
672
- onCheckedChange: (v) => rhf.onChange(v === true)
673
- }
674
- ) })
709
+ ) })
710
+ ] }),
711
+ supportedFields.map((field) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
712
+ _chunk4LHEQMOVcjs.FieldWrapper,
713
+ {
714
+ label: field.label,
715
+ htmlFor: `ms-q-${field.name}`,
716
+ error: fieldError(field.name),
717
+ children: [
718
+ field.type === "textarea" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
719
+ _chunkGWRQ5EEIcjs.Textarea,
720
+ {
721
+ id: `ms-q-${field.name}`,
722
+ className: "bg-ods-card border-ods-border text-ods-text-primary placeholder-ods-text-secondary px-3",
723
+ ...register(`formFields.${field.name}`)
724
+ }
725
+ ),
726
+ field.type === "text" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
727
+ _chunk4LHEQMOVcjs.Input,
728
+ {
729
+ id: `ms-q-${field.name}`,
730
+ className: "bg-ods-card border-ods-border text-ods-text-primary placeholder-ods-text-secondary px-3 h-11 md:h-12",
731
+ ...register(`formFields.${field.name}`)
732
+ }
733
+ ),
734
+ (field.type === "select" || field.type === "radio") && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
735
+ _reacthookform.Controller,
736
+ {
737
+ control,
738
+ name: `formFields.${field.name}`,
739
+ render: ({ field: rhf }) => field.type === "select" ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkGWRQ5EEIcjs.Select, { value: _nullishCoalesce(rhf.value, () => ( "")), onValueChange: rhf.onChange, children: [
740
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkGWRQ5EEIcjs.SelectTrigger, { id: `ms-q-${field.name}`, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkGWRQ5EEIcjs.SelectValue, { placeholder: "Select\u2026" }) }),
741
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkGWRQ5EEIcjs.SelectContent, { children: (_nullishCoalesce(field.options, () => ( []))).map((opt) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkGWRQ5EEIcjs.SelectItem, { value: opt, children: opt }, opt)) })
742
+ ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkGWRQ5EEIcjs.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: [
743
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkGWRQ5EEIcjs.RadioGroupItem, { id: `ms-q-${field.name}-${opt}`, value: opt }),
744
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk4LHEQMOVcjs.Label, { htmlFor: `ms-q-${field.name}-${opt}`, children: opt })
745
+ ] }, opt)) })
746
+ }
747
+ ),
748
+ field.type === "checkbox" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
749
+ _reacthookform.Controller,
750
+ {
751
+ control,
752
+ name: `formFields.${field.name}`,
753
+ render: ({ field: rhf }) => (
754
+ // The question's Label above already carries the text and
755
+ // binds to this id — a second inline label would double the
756
+ // visible text AND the accessible name.
757
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex items-center gap-[var(--spacing-system-xs)]", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
758
+ _chunk4LHEQMOVcjs.Checkbox,
759
+ {
760
+ id: `ms-q-${field.name}`,
761
+ checked: Boolean(rhf.value),
762
+ onCheckedChange: (v) => rhf.onChange(v === true)
763
+ }
764
+ ) })
765
+ )
766
+ }
675
767
  )
676
- }
677
- ),
678
- fieldError(field.name) && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-ods-error text-h6 mt-1", children: fieldError(field.name) })
679
- ] }, field.name)),
680
- legalConsent && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-[var(--spacing-system-xs)] border border-ods-border rounded-md p-[var(--spacing-system-md)]", children: [
768
+ ]
769
+ },
770
+ field.name
771
+ )),
772
+ legalConsent && // Same out-of-flow message as the fields above, so a missed consent
773
+ // box doesn't shove the submit button down the card. With no error the
774
+ // wrapper is `display:contents` and the panel below is the flex item,
775
+ // exactly as it was.
776
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk4LHEQMOVcjs.FieldWrapper, { error: _optionalChain([errors, 'access', _23 => _23.legalConsentResponses, 'optionalAccess', _24 => _24.message]), children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-[var(--spacing-system-xs)] border border-ods-border rounded-md p-[var(--spacing-system-m)]", children: [
681
777
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h6 text-ods-text-secondary", children: legalConsent.processingConsentText }),
682
778
  legalConsent.communicationConsentText && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h6 text-ods-text-secondary", children: legalConsent.communicationConsentText }),
683
779
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
@@ -690,10 +786,10 @@ function BookingForm({
690
786
  const current = responses.find((r) => r.communicationTypeId === box.communicationTypeId);
691
787
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-[var(--spacing-system-xs)]", children: [
692
788
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
693
- _chunkDCB4EBA5cjs.Checkbox,
789
+ _chunk4LHEQMOVcjs.Checkbox,
694
790
  {
695
791
  id: `ms-consent-${box.communicationTypeId}`,
696
- checked: _nullishCoalesce(_optionalChain([current, 'optionalAccess', _14 => _14.consented]), () => ( false)),
792
+ checked: _nullishCoalesce(_optionalChain([current, 'optionalAccess', _25 => _25.consented]), () => ( false)),
697
793
  onCheckedChange: (v) => rhf.onChange(
698
794
  responses.map(
699
795
  (r) => r.communicationTypeId === box.communicationTypeId ? { ...r, consented: v === true } : r
@@ -701,18 +797,14 @@ function BookingForm({
701
797
  )
702
798
  }
703
799
  ),
704
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkDCB4EBA5cjs.Label, { htmlFor: `ms-consent-${box.communicationTypeId}`, children: [
705
- box.label,
706
- box.required ? " *" : ""
707
- ] })
800
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk4LHEQMOVcjs.Label, { htmlFor: `ms-consent-${box.communicationTypeId}`, children: box.label })
708
801
  ] }, box.communicationTypeId);
709
802
  }) })
710
803
  }
711
804
  ),
712
- legalConsent.privacyPolicyText && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h6 text-ods-text-secondary", children: legalConsent.privacyPolicyText }),
713
- errors.legalConsentResponses && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h6 text-ods-error", children: errors.legalConsentResponses.message })
714
- ] }),
715
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk7INXXQVKcjs.Button, { type: "submit", loading: isSubmitting, disabled: isSubmitting, className: "w-full md:w-auto", children: "Confirm booking" }) })
805
+ legalConsent.privacyPolicyText && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h6 text-ods-text-secondary", children: legalConsent.privacyPolicyText })
806
+ ] }) }),
807
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk7INXXQVKcjs.Button, { type: "submit", loading: isSubmitting, disabled: isSubmitting, children: "Confirm Booking" }) })
716
808
  ] });
717
809
  }
718
810
 
@@ -728,14 +820,14 @@ function Confirmation({ confirmation, timezone }) {
728
820
  minute: "2-digit",
729
821
  timeZoneName: "short"
730
822
  }).format(new Date(confirmation.startTimeMs));
731
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-1 flex-col items-center justify-center gap-[var(--spacing-system-md)] text-center", children: [
823
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-1 flex-col items-center justify-center gap-[var(--spacing-system-m)] text-center", children: [
732
824
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h1", role: "img", "aria-label": "Celebration", children: "\u{1F389}" }),
733
825
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { className: "text-h3 text-ods-text-primary", children: "You're booked" }),
734
826
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h5 text-ods-text-primary", children: confirmation.title }),
735
827
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { className: "text-h6 text-ods-text-secondary", children: [
736
828
  when,
737
829
  " \xB7 ",
738
- _chunkXTDUFU5Ocjs.formatDurationCompact.call(void 0, confirmation.durationMs / 1e3)
830
+ _chunkGWRQ5EEIcjs.formatDurationCompact.call(void 0, confirmation.durationMs / 1e3)
739
831
  ] }),
740
832
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h6 text-ods-text-secondary", children: "A calendar invite is on its way to your email." })
741
833
  ] });
@@ -761,7 +853,7 @@ function useNextAvailableLabel(ms) {
761
853
  minute: "2-digit"
762
854
  }).format(new Date(ms))
763
855
  );
764
- } catch (e7) {
856
+ } catch (e6) {
765
857
  setLabel(null);
766
858
  }
767
859
  }, [ms]);
@@ -775,7 +867,7 @@ function DirectoryRow({
775
867
  const nextLabel = useNextAvailableLabel(link.nextAvailableMs);
776
868
  const subtitle = [
777
869
  link.description,
778
- link.durationsMinutes.length > 0 ? link.durationsMinutes.map((m) => _chunkXTDUFU5Ocjs.formatDurationCompact.call(void 0, m * 60)).join(" / ") : null,
870
+ link.durationsMinutes.length > 0 ? link.durationsMinutes.map((m) => _chunkGWRQ5EEIcjs.formatDurationCompact.call(void 0, m * 60)).join(" / ") : null,
779
871
  link.kind === "team" ? "Team" : null
780
872
  ].filter(Boolean).join(" \u2022 ");
781
873
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
@@ -789,8 +881,8 @@ function DirectoryRow({
789
881
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h3 text-ods-text-primary truncate", children: link.title }),
790
882
  subtitle && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h6 text-ods-text-secondary truncate", children: subtitle })
791
883
  ] }),
792
- audienceLabel && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkXTDUFU5Ocjs.StatusBadge, { text: `For ${audienceLabel}`, singleLine: true, className: "shrink-0 hidden sm:inline-flex" }),
793
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkXTDUFU5Ocjs.AvatarStack, { people: link.hosts, max: 3, size: "md", className: "flex shrink-0" }),
884
+ audienceLabel && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkGWRQ5EEIcjs.StatusBadge, { text: `For ${audienceLabel}`, singleLine: true, className: "shrink-0 hidden sm:inline-flex" }),
885
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkGWRQ5EEIcjs.AvatarStack, { people: link.hosts, max: 3, size: "md", className: "flex shrink-0" }),
794
886
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "hidden md:flex w-44 shrink-0 flex-col items-end justify-center", children: [
795
887
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h6 text-ods-text-secondary", children: "Next available" }),
796
888
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h6 text-ods-text-primary min-h-5", children: link.nextAvailableMs == null ? "No times published" : _nullishCoalesce(nextLabel, () => ( " ")) })
@@ -803,16 +895,16 @@ function DirectoryRow({
803
895
  function MeetingSchedulerDirectoryRowSkeleton() {
804
896
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex w-full items-center gap-4 px-4 py-3 min-h-20 rounded-lg border border-ods-border bg-ods-card", children: [
805
897
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex min-w-0 flex-1 flex-col justify-center gap-1", children: [
806
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkDCB4EBA5cjs.Skeleton, { className: "h-5 w-1/2" }),
807
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkDCB4EBA5cjs.Skeleton, { className: "h-4 w-1/3" })
898
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk4LHEQMOVcjs.Skeleton, { className: "h-5 w-1/2" }),
899
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk4LHEQMOVcjs.Skeleton, { className: "h-4 w-1/3" })
808
900
  ] }),
809
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkDCB4EBA5cjs.Skeleton, { className: "hidden sm:block h-6 w-28 shrink-0" }),
810
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkDCB4EBA5cjs.Skeleton, { className: "h-10 w-10 shrink-0 rounded-full" }),
901
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk4LHEQMOVcjs.Skeleton, { className: "hidden sm:block h-6 w-28 shrink-0" }),
902
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk4LHEQMOVcjs.Skeleton, { className: "h-10 w-10 shrink-0 rounded-full" }),
811
903
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "hidden md:flex w-44 shrink-0 flex-col items-end gap-1", children: [
812
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkDCB4EBA5cjs.Skeleton, { className: "h-4 w-24" }),
813
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkDCB4EBA5cjs.Skeleton, { className: "h-5 w-32" })
904
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk4LHEQMOVcjs.Skeleton, { className: "h-4 w-24" }),
905
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk4LHEQMOVcjs.Skeleton, { className: "h-5 w-32" })
814
906
  ] }),
815
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkDCB4EBA5cjs.Skeleton, { className: "size-12 shrink-0 rounded-md" })
907
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk4LHEQMOVcjs.Skeleton, { className: "size-12 shrink-0 rounded-md" })
816
908
  ] });
817
909
  }
818
910
  var PAGINATION_SLOT_H = "h-[4.5rem]";
@@ -856,7 +948,7 @@ function MeetingSchedulerDirectory({
856
948
  };
857
949
  }, [initialData, includeAll, apiBaseUrl]);
858
950
  const rows = _react.useMemo.call(void 0, () => {
859
- const purposes = _nullishCoalesce(_optionalChain([data, 'optionalAccess', _15 => _15.purposes]), () => ( []));
951
+ const purposes = _nullishCoalesce(_optionalChain([data, 'optionalAccess', _26 => _26.purposes]), () => ( []));
860
952
  return purposes.flatMap((p) => p.links.map((link) => ({ link, audienceLabel: p.label })));
861
953
  }, [data]);
862
954
  const totalPages = Math.max(1, Math.ceil(rows.length / pageSize));
@@ -865,12 +957,12 @@ function MeetingSchedulerDirectory({
865
957
  if (isLoading && !data) {
866
958
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkKI4EGKNVcjs.cn.call(void 0, "flex flex-col", className), children: [
867
959
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex w-full flex-col gap-4", style: { minHeight: rowsMinHeight }, children: Array.from({ length: pageSize }, (_, i) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, MeetingSchedulerDirectoryRowSkeleton, {}, i)) }),
868
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunkKI4EGKNVcjs.cn.call(void 0, "mt-8 flex w-full items-center justify-center", PAGINATION_SLOT_H), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkDCB4EBA5cjs.Skeleton, { className: "h-10 w-64" }) })
960
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunkKI4EGKNVcjs.cn.call(void 0, "mt-8 flex w-full items-center justify-center", PAGINATION_SLOT_H), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk4LHEQMOVcjs.Skeleton, { className: "h-10 w-64" }) })
869
961
  ] });
870
962
  }
871
963
  if (error) {
872
964
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunkKI4EGKNVcjs.cn.call(void 0, "flex flex-col justify-center", className), style: { minHeight: rowsMinHeight + 104 }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
873
- _chunkNISIZABNcjs.EmptyState,
965
+ _chunkCR2CMLTQcjs.EmptyState,
874
966
  {
875
967
  type: "generic",
876
968
  title: "We couldn't load available call times",
@@ -881,7 +973,7 @@ function MeetingSchedulerDirectory({
881
973
  }
882
974
  if (rows.length === 0) {
883
975
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunkKI4EGKNVcjs.cn.call(void 0, "flex flex-col justify-center", className), style: { minHeight: rowsMinHeight + 104 }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
884
- _chunkNISIZABNcjs.EmptyState,
976
+ _chunkCR2CMLTQcjs.EmptyState,
885
977
  {
886
978
  type: "generic",
887
979
  title: "No call times are published right now",
@@ -893,7 +985,7 @@ function MeetingSchedulerDirectory({
893
985
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkKI4EGKNVcjs.cn.call(void 0, "flex flex-col", className), children: [
894
986
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex w-full flex-col gap-4", style: { minHeight: rowsMinHeight }, children: pageRows.map(({ link, audienceLabel }) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DirectoryRow, { link, audienceLabel, bookingBasePath }, link.id)) }),
895
987
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunkKI4EGKNVcjs.cn.call(void 0, "mt-8 flex w-full items-center justify-center", PAGINATION_SLOT_H), children: totalPages > 1 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
896
- _chunkK535WIFScjs.PersistentPaginationWrapper,
988
+ _chunkD3OY4CJUcjs.PersistentPaginationWrapper,
897
989
  {
898
990
  isLoading,
899
991
  currentPage: page,
@@ -907,6 +999,21 @@ function MeetingSchedulerDirectory({
907
999
 
908
1000
  // src/components/meeting-scheduler/index.tsx
909
1001
 
1002
+ var CONTEXT_PANEL_CLASS = "p-[var(--spacing-system-l)] shrink-0 lg:w-[280px] border-b lg:border-b-0 lg:border-r border-ods-border lg:min-h-0 lg:overflow-y-auto";
1003
+ var ACTION_PANEL_CLASS = "flex-1 min-w-0 flex flex-col md:min-h-0 lg:p-[var(--spacing-system-l)]";
1004
+ var PANEL_STEP_CLASS = "p-[var(--spacing-system-l)] md:min-h-0 md:overflow-y-auto lg:p-0";
1005
+ var MEETING_SCHEDULER_H = "md:h-[34.375rem] lg:h-[23.75rem]";
1006
+ var CARD_CLASS = _chunkKI4EGKNVcjs.cn.call(void 0,
1007
+ "rounded-md border border-ods-border bg-ods-card overflow-hidden",
1008
+ "md:flex md:flex-col",
1009
+ MEETING_SCHEDULER_H
1010
+ );
1011
+ var CARD_INNER_CLASS = "flex flex-col md:min-h-0 md:flex-1 lg:h-full lg:flex-row";
1012
+ var CARD_DEGRADED_CLASS = _chunkKI4EGKNVcjs.cn.call(void 0,
1013
+ "rounded-md border border-ods-border bg-ods-card p-[var(--spacing-system-lf)] flex flex-col items-start gap-[var(--spacing-system-m)]",
1014
+ "md:justify-center md:overflow-y-auto",
1015
+ MEETING_SCHEDULER_H
1016
+ );
910
1017
  function isNativelyBookable(availability) {
911
1018
  if (!availability.formFields.every(isSupportedFormField)) return false;
912
1019
  const consent = availability.legalConsent;
@@ -925,12 +1032,14 @@ function HubSpotMeetingScheduler({
925
1032
  hosts,
926
1033
  displayTimezone,
927
1034
  fallbackUrl,
1035
+ onBack,
928
1036
  onBooked,
929
1037
  className
930
1038
  }) {
931
1039
  const {
932
1040
  availability,
933
1041
  isLoadingAvailability,
1042
+ isFetchingAvailability,
934
1043
  availabilityError,
935
1044
  monthOffset,
936
1045
  setMonthOffset,
@@ -943,7 +1052,7 @@ function HubSpotMeetingScheduler({
943
1052
  if (displayTimezone) return;
944
1053
  try {
945
1054
  setTimezone(Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC");
946
- } catch (e8) {
1055
+ } catch (e7) {
947
1056
  setTimezone("UTC");
948
1057
  }
949
1058
  }, [displayTimezone]);
@@ -963,8 +1072,8 @@ function HubSpotMeetingScheduler({
963
1072
  setBookingError(null);
964
1073
  autoAdvanceCount.current = 0;
965
1074
  }, [meetingId]);
966
- const durations = _nullishCoalesce(_optionalChain([availability, 'optionalAccess', _16 => _16.durationsMs]), () => ( []));
967
- const shownHosts = _nullishCoalesce(_nullishCoalesce(hosts, () => ( _optionalChain([availability, 'optionalAccess', _17 => _17.hosts]))), () => ( []));
1075
+ const durations = _nullishCoalesce(_optionalChain([availability, 'optionalAccess', _27 => _27.durationsMs]), () => ( []));
1076
+ const shownHosts = _nullishCoalesce(_nullishCoalesce(hosts, () => ( _optionalChain([availability, 'optionalAccess', _28 => _28.hosts]))), () => ( []));
968
1077
  _react.useEffect.call(void 0, () => {
969
1078
  if (durationMs == null && durations.length > 0) setDurationMs(durations[0]);
970
1079
  }, [durationMs, durations]);
@@ -988,11 +1097,15 @@ function HubSpotMeetingScheduler({
988
1097
  }, [step, timezone, slots, selectedDay, monthOffset]);
989
1098
  const autoAdvanceCount = _react.useRef.call(void 0, 0);
990
1099
  _react.useEffect.call(void 0, () => {
991
- if (step === "slot" && availability && !isLoadingAvailability && durationMs != null && slots.length === 0 && availability.hasMore && autoAdvanceCount.current < 3) {
1100
+ if (step === "slot" && availability && !isFetchingAvailability && durationMs != null && slots.length === 0 && availability.hasMore && autoAdvanceCount.current < 3) {
992
1101
  autoAdvanceCount.current += 1;
993
1102
  setMonthOffset(monthOffset + 1);
994
1103
  }
995
- }, [step, availability, isLoadingAvailability, durationMs, slots, monthOffset, setMonthOffset]);
1104
+ }, [step, availability, isFetchingAvailability, durationMs, slots, monthOffset, setMonthOffset]);
1105
+ const backToSlot = _react.useCallback.call(void 0, () => {
1106
+ setStep("slot");
1107
+ setBookingError(null);
1108
+ }, []);
996
1109
  const handleSubmit = _react.useCallback.call(void 0,
997
1110
  async (payload) => {
998
1111
  setBookingError(null);
@@ -1000,7 +1113,7 @@ function HubSpotMeetingScheduler({
1000
1113
  if (result.ok && result.confirmation) {
1001
1114
  setConfirmation(result.confirmation);
1002
1115
  setStep("confirmed");
1003
- _optionalChain([onBooked, 'optionalCall', _18 => _18(result.confirmation)]);
1116
+ _optionalChain([onBooked, 'optionalCall', _29 => _29(result.confirmation)]);
1004
1117
  return;
1005
1118
  }
1006
1119
  const code = _nullishCoalesce(result.code, () => ( "TEMPORARILY_UNAVAILABLE"));
@@ -1016,22 +1129,16 @@ function HubSpotMeetingScheduler({
1016
1129
  );
1017
1130
  const escapeHatch = fallbackUrl ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk7INXXQVKcjs.Button, { variant: "outline", size: "small-legacy", href: fallbackUrl, openInNewTab: true, children: "Open in HubSpot" }) : null;
1018
1131
  if (isLoadingAvailability && !availability) {
1019
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunkKI4EGKNVcjs.cn.call(void 0, "rounded-md border border-ods-border bg-ods-card overflow-hidden", className), children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col md:flex-row", children: [
1020
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ContextPanelSkeleton, { className: "p-[var(--spacing-system-lf)] md:w-80 md:shrink-0 border-b md:border-b-0 md:border-r border-ods-border" }),
1021
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex-1 min-w-0 p-[var(--spacing-system-lf)] md:min-h-[32rem] flex flex-col gap-[var(--spacing-system-md)]", children: [
1022
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h5 text-ods-text-secondary", children: "Select a date & time" }),
1023
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SlotPickerSkeleton, {})
1024
- ] })
1132
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunkKI4EGKNVcjs.cn.call(void 0, CARD_CLASS, className), children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: CARD_INNER_CLASS, children: [
1133
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ContextPanelSkeleton, { onBack, className: CONTEXT_PANEL_CLASS }),
1134
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: ACTION_PANEL_CLASS, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SlotPickerSkeleton, { monthOffset }) })
1025
1135
  ] }) });
1026
1136
  }
1027
1137
  if (availabilityError || !availability) {
1028
1138
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1029
1139
  "div",
1030
1140
  {
1031
- className: _chunkKI4EGKNVcjs.cn.call(void 0,
1032
- "rounded-md border border-ods-border bg-ods-card p-[var(--spacing-system-lf)] flex flex-col items-start gap-[var(--spacing-system-md)]",
1033
- className
1034
- ),
1141
+ className: _chunkKI4EGKNVcjs.cn.call(void 0, CARD_DEGRADED_CLASS, className),
1035
1142
  children: [
1036
1143
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h6 text-ods-text-secondary", children: "We couldn't load available call times. Please try again shortly." }),
1037
1144
  escapeHatch
@@ -1043,10 +1150,7 @@ function HubSpotMeetingScheduler({
1043
1150
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1044
1151
  "div",
1045
1152
  {
1046
- className: _chunkKI4EGKNVcjs.cn.call(void 0,
1047
- "rounded-md border border-ods-border bg-ods-card p-[var(--spacing-system-lf)] flex flex-col items-start gap-[var(--spacing-system-md)]",
1048
- className
1049
- ),
1153
+ className: _chunkKI4EGKNVcjs.cn.call(void 0, CARD_DEGRADED_CLASS, className),
1050
1154
  children: [
1051
1155
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h6 text-ods-text-secondary", children: "This meeting type is booked directly on HubSpot." }),
1052
1156
  escapeHatch
@@ -1054,7 +1158,7 @@ function HubSpotMeetingScheduler({
1054
1158
  }
1055
1159
  );
1056
1160
  }
1057
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunkKI4EGKNVcjs.cn.call(void 0, "rounded-md border border-ods-border bg-ods-card overflow-hidden", className), children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col md:flex-row", children: [
1161
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunkKI4EGKNVcjs.cn.call(void 0, CARD_CLASS, className), children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: CARD_INNER_CLASS, children: [
1058
1162
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1059
1163
  SchedulerContextPanel,
1060
1164
  {
@@ -1071,86 +1175,85 @@ function HubSpotMeetingScheduler({
1071
1175
  },
1072
1176
  timezone,
1073
1177
  onTimezoneChange: setTimezone,
1178
+ onBack: step === "details" ? backToSlot : onBack,
1074
1179
  locked: step !== "slot",
1075
- className: "p-[var(--spacing-system-lf)] md:w-80 md:shrink-0 border-b md:border-b-0 md:border-r border-ods-border"
1180
+ showTimezone: step !== "confirmed",
1181
+ className: CONTEXT_PANEL_CLASS
1076
1182
  }
1077
1183
  ),
1078
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex-1 min-w-0 p-[var(--spacing-system-lf)] md:min-h-[32rem] flex flex-col", children: step === "confirmed" && confirmation && timezone ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Confirmation, { confirmation, timezone }) : step === "details" && durationMs != null && selectedSlot != null && timezone ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-1 flex-col gap-[var(--spacing-system-md)]", children: [
1184
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: ACTION_PANEL_CLASS, children: step === "confirmed" && confirmation && timezone ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunkKI4EGKNVcjs.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: _chunkKI4EGKNVcjs.cn.call(void 0, "flex flex-1 flex-col gap-[var(--spacing-system-m)]", PANEL_STEP_CLASS), children: [
1185
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { className: "text-h4 text-ods-text-primary", children: [
1186
+ new Intl.DateTimeFormat(void 0, {
1187
+ timeZone: timezone,
1188
+ weekday: "long",
1189
+ month: "long",
1190
+ day: "numeric",
1191
+ hour: "numeric",
1192
+ minute: "2-digit",
1193
+ timeZoneName: "short"
1194
+ }).format(new Date(selectedSlot)),
1195
+ " ",
1196
+ "\xB7 ",
1197
+ _chunkGWRQ5EEIcjs.formatDurationCompact.call(void 0, durationMs / 1e3)
1198
+ ] }),
1199
+ bookingError && bookingError !== "SLOT_TAKEN" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col items-start gap-[var(--spacing-system-xs)]", children: [
1200
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h6 text-ods-error", children: bookingError === "TEMPORARILY_UNAVAILABLE" ? "Scheduling is briefly unavailable \u2014 please try again in a minute." : bookingError === "MEETING_UNAVAILABLE" ? "This meeting type has reached its booking limit for today \u2014 try another time or contact us." : bookingError === "LINK_GONE" ? "This meeting type is no longer available." : "Please double-check your details and try again." }),
1201
+ escapeHatch
1202
+ ] }),
1079
1203
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1080
- _chunkXTDUFU5Ocjs.BackButton,
1204
+ BookingForm,
1081
1205
  {
1082
- label: "Back",
1083
- onClick: () => {
1084
- setStep("slot");
1085
- setBookingError(null);
1086
- }
1206
+ availability,
1207
+ meetingId,
1208
+ startTimeMs: selectedSlot,
1209
+ durationMs,
1210
+ timezone,
1211
+ isSubmitting,
1212
+ onSubmit: handleSubmit,
1213
+ honeypotInputProps,
1214
+ getSignals
1087
1215
  }
1088
- ),
1089
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-1 flex-col justify-center gap-[var(--spacing-system-md)]", children: [
1090
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { className: "text-h4 text-ods-text-primary", children: [
1091
- new Intl.DateTimeFormat(void 0, {
1092
- timeZone: timezone,
1093
- weekday: "long",
1094
- month: "long",
1095
- day: "numeric",
1096
- hour: "numeric",
1097
- minute: "2-digit",
1098
- timeZoneName: "short"
1099
- }).format(new Date(selectedSlot)),
1100
- " ",
1101
- "\xB7 ",
1102
- _chunkXTDUFU5Ocjs.formatDurationCompact.call(void 0, durationMs / 1e3)
1103
- ] }),
1104
- bookingError && bookingError !== "SLOT_TAKEN" && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col items-start gap-[var(--spacing-system-xs)]", children: [
1105
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h6 text-ods-error", children: bookingError === "TEMPORARILY_UNAVAILABLE" ? "Scheduling is briefly unavailable \u2014 please try again in a minute." : bookingError === "MEETING_UNAVAILABLE" ? "This meeting type has reached its booking limit for today \u2014 try another time or contact us." : bookingError === "LINK_GONE" ? "This meeting type is no longer available." : "Please double-check your details and try again." }),
1106
- escapeHatch
1107
- ] }),
1216
+ )
1217
+ ] }) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-[var(--spacing-system-m)] md:min-h-0 md:flex-1", children: [
1218
+ bookingError === "SLOT_TAKEN" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "px-[var(--spacing-system-l)] pt-[var(--spacing-system-l)] text-h6 text-ods-error lg:p-0", children: "That time is no longer available \u2014 if you just submitted, check your email for a confirmation before rebooking." }),
1219
+ timezone && durationMs != null ? (
1220
+ // The picker owns BOTH the loading and the empty month now —
1221
+ // it keeps the calendar up either way, so there is no branch
1222
+ // here that can take it off screen mid-flow.
1108
1223
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1109
- BookingForm,
1224
+ SlotPicker,
1110
1225
  {
1111
- availability,
1112
- meetingId,
1113
- startTimeMs: selectedSlot,
1114
- durationMs,
1226
+ slots,
1115
1227
  timezone,
1116
- isSubmitting,
1117
- onSubmit: handleSubmit,
1118
- honeypotInputProps,
1119
- getSignals
1228
+ monthOffset,
1229
+ onMonthOffsetChange: (o) => {
1230
+ setSelectedDay(null);
1231
+ setSelectedSlot(null);
1232
+ setMonthOffset(o);
1233
+ },
1234
+ selectedSlot,
1235
+ onSelectSlot: (ms) => {
1236
+ setSelectedSlot(ms);
1237
+ setStep("details");
1238
+ },
1239
+ selectedDay,
1240
+ onSelectDay: setSelectedDay,
1241
+ isLoading: isLoadingAvailability
1120
1242
  }
1121
1243
  )
1122
- ] })
1123
- ] }) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-[var(--spacing-system-md)]", children: [
1124
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h5 text-ods-text-secondary", children: "Select a date & time" }),
1125
- bookingError === "SLOT_TAKEN" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h6 text-ods-error", children: "That time is no longer available \u2014 if you just submitted, check your email for a confirmation before rebooking." }),
1126
- timezone && durationMs != null ? slots.length > 0 || isLoadingAvailability ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1127
- SlotPicker,
1128
- {
1129
- slots,
1130
- timezone,
1131
- monthOffset,
1132
- onMonthOffsetChange: (o) => {
1133
- setSelectedDay(null);
1134
- setSelectedSlot(null);
1135
- setMonthOffset(o);
1136
- },
1137
- selectedSlot,
1138
- onSelectSlot: (ms) => {
1139
- setSelectedSlot(ms);
1140
- setStep("details");
1141
- },
1142
- selectedDay,
1143
- onSelectDay: setSelectedDay,
1144
- isLoading: isLoadingAvailability
1145
- }
1146
- ) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col items-start gap-[var(--spacing-system-md)]", children: [
1147
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h6 text-ods-text-secondary", children: isLoadingAvailability ? "Checking more dates\u2026" : "No call times are published right now." }),
1148
- !isLoadingAvailability && escapeHatch
1149
- ] }) : (
1244
+ ) : durations.length === 0 && !isFetchingAvailability ? (
1245
+ // The LINK publishes nothing at all a different thing from a
1246
+ // fully-booked month, and the only case the escape hatch is
1247
+ // the right answer to.
1248
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col items-start gap-[var(--spacing-system-m)]", children: [
1249
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-h6 text-ods-text-secondary", children: "No call times are published right now." }),
1250
+ escapeHatch
1251
+ ] })
1252
+ ) : (
1150
1253
  // Pre-mount timezone-resolution window (every SSR load hits
1151
- // this for one frame-batch) — SAME per-region skeletons, no
1152
- // bare rectangle, no shift when the real picker swaps in.
1153
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SlotPickerSkeleton, {})
1254
+ // this for one frame-batch) — same layout, real calendar, so
1255
+ // nothing shifts when the picker takes over.
1256
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SlotPickerSkeleton, { monthOffset })
1154
1257
  )
1155
1258
  ] }) })
1156
1259
  ] }) });
@@ -1159,5 +1262,6 @@ function HubSpotMeetingScheduler({
1159
1262
 
1160
1263
 
1161
1264
 
1162
- exports.HubSpotMeetingScheduler = HubSpotMeetingScheduler; exports.MeetingSchedulerDirectory = MeetingSchedulerDirectory; exports.MeetingSchedulerDirectoryRowSkeleton = MeetingSchedulerDirectoryRowSkeleton;
1265
+
1266
+ exports.HubSpotMeetingScheduler = HubSpotMeetingScheduler; exports.MEETING_SCHEDULER_H = MEETING_SCHEDULER_H; exports.MeetingSchedulerDirectory = MeetingSchedulerDirectory; exports.MeetingSchedulerDirectoryRowSkeleton = MeetingSchedulerDirectoryRowSkeleton;
1163
1267
  //# sourceMappingURL=index.cjs.map