/** Standard booking browser program, scoped to one explicit mount. Browser acceptance exercises this emitted JavaScript. */ export declare const bookingJs = "(function initializeBooking() {\n const root = document.querySelector(\"[data-vitris-booking]\");\n if (!root) return;\n const metadata = document.querySelector(\"script[data-vitris-booking-config]\");\n if (!metadata) return;\n root.classList.add(\"vb\");\n const node = (tag, text, className) => {\n const el = document.createElement(tag);\n if (text !== void 0) el.textContent = text;\n if (className) el.className = className;\n const roles={h2:'card-title',legend:'label',dt:'label'};\n if(roles[tag])el.dataset.typeRole=roles[tag];\n if(className?.split(' ').some(c=>['vb-notice','vb-hint','vb-reference'].includes(c)))el.dataset.typeRole='caption';\n if(className?.split(' ').some(c=>['vb-steps','vb-status'].includes(c)))el.dataset.typeRole='label';\n return el;\n };\n const notice = (text) => {\n const el = node(\"p\", text, \"vb-notice\");\n el.setAttribute(\"role\", \"status\");\n return el;\n };\n let connection;\n try {\n connection = JSON.parse(metadata.textContent || \"\");\n if (connection.siteOrigin !== location.origin) throw Error();\n } catch {\n root.append(notice(\"Booking is available on the approved business website. This preview is not connected.\"));\n return;\n }\n let catalog, step = 0, serviceId = \"\", locationId = \"\", providerId = \"\", day = \"\", slot = null, slots = [], revision = 0, busy = false, requestSerial = 0, error = \"\", status = \"\", customer = { name: \"\", email: \"\", phone: \"\" }, accepted = false, challengeToken = \"\", challengeId, receipt, company = \"\", attemptKey = \"\", attemptPayload = \"\", uncertain = false;\n let objectUrl = \"\";\n const api = async (path, data) => {\n const response = await fetch(connection.apiOrigin + \"/api/booking/v1\" + path, { mode: \"cors\", credentials: \"omit\", cache: \"no-store\", referrerPolicy: \"no-referrer\", signal: AbortSignal.timeout(25e3), ...data === void 0 ? {} : { method: \"POST\", headers: { \"content-type\": \"application/json\" }, body: JSON.stringify(data) } });\n const text = await response.text();\n if (text.length > 1e6) throw Error(\"The booking response could not be verified.\");\n let result;\n try {\n result = JSON.parse(text);\n } catch {\n throw Error(\"Booking is temporarily unavailable. Please contact the business.\");\n }\n if (!response.ok) {\n const failure = Object.assign(new Error(typeof result.error === \"string\" ? result.error : \"Booking could not be completed.\"), { status: response.status, code: result.code });\n throw failure;\n }\n return result;\n };\n const service = () => catalog.services.find((s) => s.id === serviceId);\n const place = () => catalog.locations.find((l) => l.id === locationId);\n const dateOf = (at, zone) => {\n const parts = new Intl.DateTimeFormat(\"en-US\", { timeZone: zone, year: \"numeric\", month: \"2-digit\", day: \"2-digit\" }).formatToParts(new Date(at)), get = (key) => parts.find((p) => p.type === key).value;\n return get(\"year\") + \"-\" + get(\"month\") + \"-\" + get(\"day\");\n };\n const addDays = (value, count) => new Date(Date.parse(value + \"T12:00:00Z\") + count * 864e5).toISOString().slice(0, 10);\n const dayStart = (value, zone) => {\n const target = Date.parse(value + \"T00:00:00Z\");\n for (let at = target - 14 * 36e5; at <= target + 14 * 36e5; at += 6e4) if (dateOf(at, zone) === value) return new Date(at).toISOString();\n throw Error(\"This date is unavailable in the selected timezone.\");\n };\n const time = (at, zone) => new Intl.DateTimeFormat(\"en-US\", { timeZone: zone, hour: \"numeric\", minute: \"2-digit\", timeZoneName: \"shortOffset\" }).format(new Date(at));\n const fullDate = (at, zone) => new Intl.DateTimeFormat(\"en-US\", { timeZone: zone, weekday: \"short\", month: \"long\", day: \"numeric\", year: \"numeric\" }).format(new Date(at));\n const price = (value) => {\n if (value.amountMinor === null) return value.label || \"Price agreed with the business\";\n try {\n const options2 = new Intl.NumberFormat(\"en-US\", { style: \"currency\", currency: value.currency }), digits = options2.resolvedOptions().maximumFractionDigits ?? 2;\n return options2.format(value.amountMinor / 10 ** digits);\n } catch {\n return value.label;\n }\n };\n const button = (label, action, primary = false) => {\n const el = node(\"button\", label, primary ? \"vb-primary\" : void 0);\n el.type = \"button\";\n el.dataset.focusKey = label;\n el.disabled = busy;\n el.addEventListener(\"click\", action);\n return el;\n };\n const field = (label, input) => {\n const el = node(\"label\");\n input.dataset.focusKey = label;\n el.append(node(\"span\", label), input);\n return el;\n };\n const detail = (list, label, value) => {\n const row = node(\"div\");\n row.append(node(\"dt\", label), node(\"dd\", value));\n list.append(row);\n };\n const move = (next) => {\n if (busy || uncertain) return;\n step = next;\n error = \"\";\n status = \"\";\n render(true);\n };\n const clearTimes = () => {\n requestSerial++;\n slots = [];\n slot = null;\n revision = 0;\n status = \"\";\n error = \"\";\n attemptKey = \"\";\n accepted = false;\n };\n const options = (select, items, value, all) => {\n if (all) {\n const opt = node(\"option\", all);\n opt.value = \"\";\n select.append(opt);\n }\n for (const item of items) {\n const opt = node(\"option\", item.name);\n opt.value = item.id;\n select.append(opt);\n }\n select.value = value;\n };\n const cleanupChallenge = () => {\n if (challengeId) {\n window.turnstile?.remove(challengeId);\n challengeId = void 0;\n }\n challengeToken = \"\";\n };\n const errorBlock = () => {\n const el = node(\"p\", error, \"vb-error\");\n el.setAttribute(\"role\", \"alert\");\n return el;\n };\n const showSummary = (panel) => {\n const disclosure = node(\"details\");\n disclosure.open = window.matchMedia(\"(min-width:761px)\").matches;\n disclosure.append(node(\"summary\", \"Your appointment\"));\n const list = node(\"dl\"), s = service();\n if (s) {\n detail(list, \"Service\", s.name);\n detail(list, \"Duration\", s.durationMinutes + \" minutes\");\n detail(list, \"Price\", price(s.price));\n detail(list, \"Confirmation\", s.bookingMode === \"approval\" ? \"Business approval required\" : \"Confirmed when booked\");\n }\n if (place()) detail(list, \"Location\", place().name);\n if (slot) {\n detail(list, \"Time\", fullDate(slot.startsAt, place().timezone) + \" \\xB7 \" + time(slot.startsAt, place().timezone));\n detail(list, \"Staff\", catalog.providers.find((p) => p.id === slot.providerId)?.name || \"Available staff\");\n }\n disclosure.append(list);\n panel.append(disclosure);\n };\n const normalizeSelection = () => {\n const s = service();\n if (!s) return;\n const places = catalog.locations.filter((l) => s.locationIds.includes(l.id));\n if (!places.some((p) => p.id === locationId)) locationId = places[0]?.id || \"\";\n const staff = catalog.providers.filter((p) => s.providerIds.includes(p.id) && p.locationIds.includes(locationId));\n if (!catalog.allowProviderChoice || !staff.some((p) => p.id === providerId)) providerId = staff.length === 1 ? staff[0].id : \"\";\n if (!day && place()) day = dateOf(Date.now() + catalog.minNoticeMinutes * 6e4, place().timezone);\n };\n const loadTimes = async (lookAhead = false) => {\n if (busy || uncertain) return;\n busy = true;\n slot = null;\n error = \"\";\n status = \"Checking availability\\u2026\";\n const serial = ++requestSerial;\n render();\n try {\n const zone = place().timezone, params = new URLSearchParams({ serviceId, locationId, startsAt: dayStart(day, zone), endsAt: dayStart(addDays(day, lookAhead ? 6 : 1), zone), ...providerId ? { providerId } : {} });\n const data = await api(\"/availability?\" + params);\n if (serial !== requestSerial) return;\n if (data.schemaVersion !== 1 || data.siteId !== connection.siteId || !Array.isArray(data.slots) || data.slots.length > 500 || !Number.isSafeInteger(data.revision)) throw Error(\"The availability response could not be verified.\");\n if (!data.terms || typeof data.policyText !== \"string\" || !data.location) throw Error(\"This service changed. Reload services before booking.\");\n const old = JSON.stringify(service());\n Object.assign(service(), data.terms);\n Object.assign(place(), data.location);\n if (catalog.policyText !== data.policyText) accepted = false;\n catalog.policyText = data.policyText;\n slots = data.slots;\n revision = data.revision;\n status = slots.length ? `${slots.length} available ${slots.length === 1 ? \"time\" : \"times\"}. ${zone}.` : \"No available times for this date. Try another day.\";\n if (old !== JSON.stringify(service())) status += \" Service details have changed; review the current price and duration.\";\n if (data.truncated) status += \" Showing the first available times; narrow the date or staff selection.\";\n } catch (failure) {\n if (serial === requestSerial) {\n slots = [];\n error = failure instanceof Error ? failure.message : \"Availability could not be loaded.\";\n status = \"\";\n }\n } finally {\n if (serial === requestSerial) {\n busy = false;\n render();\n }\n }\n };\n const mountChallenge = async (container) => {\n if (catalog.challenge.kind === \"local-fixture\") {\n container.append(notice(\"Local simulation: the security challenge is bypassed only for this isolated loopback preview.\"));\n return;\n }\n try {\n const win = window;\n if (!win.turnstile) await new Promise((resolve, reject) => {\n let script = document.querySelector(\"script[data-booking-turnstile]\");\n if (!script) {\n script = node(\"script\");\n script.src = \"https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit\";\n script.async = true;\n script.dataset.bookingTurnstile = \"\";\n document.head.append(script);\n }\n script.addEventListener(\"load\", () => resolve(), { once: true });\n script.addEventListener(\"error\", () => reject(Error(\"The security check could not load. Please retry or contact the business.\")), { once: true });\n });\n if (!container.isConnected || step !== 3) return;\n challengeId = win.turnstile.render(container, { sitekey: catalog.challenge.siteKey, action: \"booking\", callback: (value) => {\n challengeToken = value;\n }, \"expired-callback\": () => {\n challengeToken = \"\";\n }, \"error-callback\": () => {\n challengeToken = \"\";\n } });\n } catch (failure) {\n if (container.isConnected) container.append(errorBlockMessage(failure instanceof Error ? failure.message : \"Security check unavailable.\"));\n }\n };\n const errorBlockMessage = (text) => {\n const el = node(\"p\", text, \"vb-error\");\n el.setAttribute(\"role\", \"alert\");\n return el;\n };\n const submit = async () => {\n if (busy) return;\n if (!accepted) {\n error = \"Accept the booking policy before booking.\";\n render();\n return;\n }\n if (catalog.challenge.kind === \"turnstile\" && !challengeToken) {\n error = \"Complete the security check before booking.\";\n const existing = root.querySelector(\"[role=alert]\");\n if (existing) existing.textContent = error;\n else root.querySelector(\".vb-panel\")?.append(errorBlock());\n return;\n }\n const content = { revision, serviceId, locationId, providerId: slot.providerId, startsAt: slot.startsAt, customer, acceptedPolicy: true };\n const payload = JSON.stringify(content);\n if (!attemptKey || attemptPayload !== payload) {\n attemptKey = crypto.randomUUID();\n attemptPayload = payload;\n }\n busy = true;\n error = \"\";\n status = \"Saving your appointment\\u2026\";\n const token = challengeToken;\n render();\n try {\n const result = await api(\"/appointments\", { ...content, idempotencyKey: attemptKey, challengeToken: token, company });\n if (result.schemaVersion !== 1 || result.siteId !== connection.siteId || ![\"confirmed\", \"pending_approval\"].includes(result.status) || typeof result.reference !== \"string\" || typeof result.calendar?.content !== \"string\") throw Error(\"The booking response could not be verified. Keep this page open and retry the same booking.\");\n receipt = result;\n uncertain = false;\n step = 4;\n status = \"\";\n } catch (failure) {\n const f = failure;\n error = f.message || \"The booking response was interrupted.\";\n status = \"\";\n if (!f.status || f.status >= 500) {\n uncertain = true;\n error += \" Your result may still be pending. Retry this same booking; do not create another appointment.\";\n } else {\n uncertain = false;\n if (f.status === 409) {\n step = 1;\n slot = null;\n slots = [];\n revision = 0;\n attemptKey = \"\";\n accepted = false;\n status = \"Your details are saved. Find available times again.\";\n } else if (f.status === 400 && String(f.code).startsWith(\"challenge\")) {\n challengeToken = \"\";\n }\n }\n } finally {\n busy = false;\n render(true);\n }\n };\n function render(focus = false) {\n const focusKey = document.activeElement?.dataset.focusKey;\n cleanupChallenge();\n root.replaceChildren();\n root.append(notice(catalog.emailMode === \"send\" ? \"TEST BOOKING - Emails use the configured sender and allowed test recipients.\" : catalog.emailMode === \"disabled\" ? \"TEST BOOKING - Customer emails are not enabled. Keep your booking reference.\" : \"TEST BOOKING - This preview stores appointments in the admin calendar. Customer emails are captured, not sent.\"));\n const progress = node(\"ol\", void 0, \"vb-steps\");\n progress.setAttribute(\"aria-label\", \"Booking progress\");\n [\"Service\", \"Time\", \"Your details\", \"Review\", \"Receipt\"].forEach((name, index) => {\n const item = node(\"li\", index + 1 + \". \" + name);\n if (index === step) item.setAttribute(\"aria-current\", \"step\");\n progress.append(item);\n });\n root.append(progress);\n const layout = node(\"div\", void 0, \"vb-layout\"), panel = node(\"section\", void 0, \"vb-panel\"), summary = node(\"aside\", void 0, \"vb-panel vb-summary\");\n summary.setAttribute(\"aria-label\", \"Appointment summary\");\n layout.append(panel, summary);\n root.append(layout);\n showSummary(summary);\n const heading = node(\"h2\", [\"Choose a service\", \"Choose a time\", \"Your details\", \"Review your appointment\", receipt?.status === \"pending_approval\" ? \"Request received\" : \"Appointment confirmed\"][step]);\n heading.tabIndex = -1;\n panel.append(heading);\n if (error) panel.append(errorBlock());\n if (status) {\n const live = node(\"p\", status);\n live.setAttribute(\"role\", \"status\");\n panel.append(live);\n }\n if (step === 0) {\n if (!catalog.services.length) {\n panel.append(node(\"p\", \"No services are available for online booking. Please contact the business.\"));\n return;\n }\n const group = node(\"fieldset\"), legend = node(\"legend\", \"Available services\"), list = node(\"div\", void 0, \"vb-services\");\n group.append(legend, list);\n for (const s of catalog.services) {\n const radio = node(\"input\");\n radio.type = \"radio\";\n radio.name = \"booking-service\";\n radio.dataset.focusKey = \"service-\" + s.id;\n radio.value = s.id;\n radio.checked = s.id === serviceId;\n radio.addEventListener(\"change\", () => {\n serviceId = s.id;\n clearTimes();\n normalizeSelection();\n render();\n });\n const label = node(\"label\", void 0, \"vb-service\"), copy = node(\"span\");\n copy.dataset.typeRole='body';\n copy.append(node(\"strong\", s.name), node(\"small\", s.durationMinutes + \" minutes \\xB7 \" + price(s.price)), node(\"small\", s.bookingMode === \"approval\" ? \"Requires business approval\" : \"Immediate confirmation\"));\n label.append(radio, copy);\n list.append(label);\n }\n panel.append(group, button(\"Choose a time\", () => {\n normalizeSelection();\n move(1);\n }, true));\n } else if (step === 1) {\n const s = service(), grid = node(\"div\", void 0, \"vb-grid\"), places = catalog.locations.filter((l) => s.locationIds.includes(l.id));\n if (places.length > 1) {\n const select = node(\"select\");\n options(select, places, locationId);\n select.disabled = busy || uncertain;\n select.addEventListener(\"change\", () => {\n locationId = select.value;\n day = \"\";\n clearTimes();\n normalizeSelection();\n render();\n });\n grid.append(field(\"Location\", select));\n }\n const staff = catalog.providers.filter((p) => s.providerIds.includes(p.id) && p.locationIds.includes(locationId));\n if (catalog.allowProviderChoice && staff.length > 1) {\n const select = node(\"select\");\n options(select, staff, providerId, \"Any available staff\");\n select.disabled = busy || uncertain;\n select.addEventListener(\"change\", () => {\n providerId = select.value;\n clearTimes();\n render();\n });\n grid.append(field(\"Staff preference\", select));\n }\n const date = node(\"input\");\n date.type = \"date\";\n date.required = true;\n date.value = day;\n date.min = dateOf(Date.now(), place().timezone);\n date.max = dateOf(Date.now() + catalog.horizonDays * 864e5, place().timezone);\n date.disabled = busy || uncertain;\n date.addEventListener(\"change\", () => {\n if (date.value) {\n day = date.value;\n clearTimes();\n render();\n }\n });\n grid.append(field(\"Appointment date\", date));\n panel.append(grid, node(\"p\", \"Times are shown in \" + place().timezone + \". A time is reserved only after booking.\", \"vb-hint\"), button(busy ? \"Checking times\\u2026\" : \"Find available times\", () => {\n void loadTimes();\n }));\n const times = node(\"div\", void 0, \"vb-times\");\n times.setAttribute(\"aria-label\", \"Available times\");\n const seen = /* @__PURE__ */ new Set();\n for (const value of slots) {\n if (!providerId && seen.has(value.startsAt)) continue;\n seen.add(value.startsAt);\n const label = time(value.startsAt, place().timezone), b = button(label, () => {\n slot = value;\n render();\n });\n b.dataset.focusKey = value.startsAt + \"-\" + value.providerId;\n b.setAttribute(\"aria-pressed\", String(slot?.startsAt === value.startsAt && slot.providerId === value.providerId));\n b.setAttribute(\"aria-label\", fullDate(value.startsAt, place().timezone) + \" at \" + label);\n b.append(node(\"small\", fullDate(value.startsAt, place().timezone)));\n times.append(b);\n }\n panel.append(times);\n if (!slots.length && !busy) panel.append(button(\"Look ahead six days\", () => {\n void loadTimes(true);\n }));\n const actions = node(\"div\", void 0, \"vb-actions\"), next = button(\"Continue to your details\", () => move(2), true);\n next.disabled = !slot || busy;\n actions.append(button(\"Back to services\", () => move(0)), next);\n panel.append(actions);\n } else if (step === 2) {\n const form = node(\"form\");\n for (const [key, label, type, autocomplete] of [[\"name\", \"Full name\", \"text\", \"name\"], [\"email\", \"Email address\", \"email\", \"email\"], [\"phone\", \"Phone number (optional)\", \"tel\", \"tel\"]]) {\n const input = node(\"input\");\n input.name = key;\n input.type = type;\n input.autocomplete = autocomplete;\n input.required = key !== \"phone\";\n input.maxLength = key === \"email\" ? 254 : key === \"name\" ? 160 : 40;\n input.value = customer[key];\n input.addEventListener(\"input\", () => {\n customer[key] = input.value;\n });\n form.append(field(label, input));\n }\n const hidden = node(\"div\", void 0, \"vb-honey\");\n hidden.setAttribute(\"aria-hidden\", \"true\");\n const honey = node(\"input\");\n honey.name = \"company\";\n honey.tabIndex = -1;\n honey.autocomplete = \"off\";\n honey.addEventListener(\"input\", () => {\n company = honey.value;\n });\n hidden.append(field(\"Leave this field empty\", honey));\n form.append(hidden, node(\"p\", \"Your details are used to arrange this appointment. See the test email mode above before submitting.\", \"vb-hint\"));\n const actions = node(\"div\", void 0, \"vb-actions\"), next = button(\"Review appointment\", () => {\n }, true);\n next.type = \"submit\";\n actions.append(button(\"Back to times\", () => move(1)), next);\n form.append(actions);\n form.addEventListener(\"submit\", (event) => {\n event.preventDefault();\n if (form.reportValidity()) {\n customer = { name: customer.name.trim(), email: customer.email.trim(), phone: customer.phone.trim() };\n move(3);\n }\n });\n panel.append(form);\n } else if (step === 3) {\n const list = node(\"dl\");\n detail(list, \"Customer\", customer.name);\n detail(list, \"Email\", customer.email);\n if (customer.phone) detail(list, \"Phone\", customer.phone);\n panel.append(list, node(\"h3\", \"Booking policy\"), node(\"p\", catalog.policyText, \"vb-policy\"));\n if(catalog.customerManagement){const m=catalog.customerManagement;panel.append(node(\"p\",\"Online cancellation notice: \"+m.cancellationCutoffMinutes+\" minutes. Online rescheduling notice: \"+m.rescheduleCutoffMinutes+\" minutes. Zero permits changes until the appointment starts.\",\"vb-hint\"));}\n const check = node(\"input\");\n check.type = \"checkbox\";\n check.checked = accepted;\n check.disabled = busy || uncertain;\n check.addEventListener(\"change\", () => {\n accepted = check.checked;\n });\n const label = node(\"label\", void 0, \"vb-check\");\n label.append(check, node(\"span\", \"I have read and accept the booking policy.\"));\n panel.append(label);\n if (!busy) {\n const challenge = node(\"div\");\n panel.append(challenge);\n void mountChallenge(challenge);\n }\n const actions = node(\"div\", void 0, \"vb-actions\");\n if (!uncertain) actions.append(button(\"Back to your details\", () => move(2)));\n actions.append(button(busy ? \"Booking\\u2026\" : uncertain ? \"Retry same booking\" : service().bookingMode === \"approval\" ? \"Request appointment\" : \"Confirm appointment\", () => {\n void submit();\n }, true));\n panel.append(actions);\n } else if (receipt) {\n const pending = receipt.status === \"pending_approval\";\n panel.append(node(\"p\", pending ? \"The business needs to approve your request. Your time is held until the approval deadline. This request is not yet confirmed.\" : \"Your appointment is saved in the business calendar.\", \"vb-status\"));\n const list = node(\"dl\");\n detail(list, \"Service\", receipt.serviceName);\n detail(list, \"When\", fullDate(receipt.startsAt, receipt.timezone) + \" \\xB7 \" + time(receipt.startsAt, receipt.timezone));\n detail(list, \"Location\", receipt.locationName);\n detail(list, \"Staff\", receipt.providerName);\n detail(list, \"Price\", price(receipt.price));\n if (receipt.expiresAt) detail(list, \"Approval deadline\", fullDate(receipt.expiresAt, receipt.timezone) + \" \\xB7 \" + time(receipt.expiresAt, receipt.timezone));\n panel.append(list, node(\"p\", \"Booking reference\", \"vb-hint\"), node(\"p\", receipt.reference, \"vb-reference\"), node(\"p\", \"Keep this reference. \" + (receipt.emailStatus === \"captured\" ? \"Your test email is captured in the admin Customer emails inbox. Its private links can cancel or reschedule this appointment.\" : receipt.emailStatus === \"accepted\" ? \"Your email was accepted by the email provider. Check your inbox for private cancellation and rescheduling links.\" : receipt.emailStatus === \"blocked\" || receipt.emailStatus === \"unknown\" ? \"Your appointment is saved, but the email needs attention. Contact the business if you do not receive it.\" : (catalog.emailMode === \"disabled\" ? \"Customer emails are not enabled. Contact the business for appointment changes.\" : \"Open your appointment email for cancellation and rescheduling links. Email delivery may still be pending.\")) + \"\", \"vb-hint\"));\n if (objectUrl) URL.revokeObjectURL(objectUrl);\n objectUrl = URL.createObjectURL(new Blob([receipt.calendar.content], { type: \"text/calendar;charset=utf-8\" }));\n const link = node(\"a\", \"Download calendar file (.ics)\");\n link.href = objectUrl;\n link.download = \"appointment.ics\";\n panel.append(link, node(\"p\", \"A calendar file adds a copy to your calendar. It does not keep your calendar synchronized.\", \"vb-hint\"));\n }\n if (focus) heading.focus({ preventScroll: false });\n else if (focusKey) root.querySelector('[data-focus-key=\"' + CSS.escape(focusKey) + '\"]')?.focus({ preventScroll: true });\n }\n root.append(notice(\"Loading available services\\u2026\"));\n void api(\"/catalog\").then((data) => {\n if (data.schemaVersion !== 1 || data.siteId !== connection.siteId || data.installationId !== connection.installationId || data.siteOrigin !== connection.siteOrigin || data.mode !== \"test\" || !Array.isArray(data.services) || data.services.length > 128 || !Array.isArray(data.providers) || !Array.isArray(data.locations) || ![\"local-fixture\", \"turnstile\"].includes(data.challenge?.kind)) throw Error(\"This website booking connection could not be verified. Please contact the business.\");\n catalog = data;\n serviceId = new URL(location.href).searchParams.get(\"service\") || data.services[0]?.id || \"\";\n if (!data.services.some((s) => s.id === serviceId)) serviceId = data.services[0]?.id || \"\";\n normalizeSelection();\n render();\n }).catch((failure) => {\n root.replaceChildren(errorBlockMessage(failure instanceof Error ? failure.message : \"Booking is unavailable.\"));\n root.append(button(\"Try loading services again\", () => location.reload()));\n });\n window.addEventListener(\"beforeunload\", (event) => {\n if (uncertain || busy && step === 3) {\n event.preventDefault();\n event.returnValue = \"\";\n }\n });\n})();";