@alfadocs/ui-kit-debug 1.88.0 → 1.89.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/dist/_chunks/{booking-DjQuhfN7.js → booking-C0FoW8Yx.js} +2 -1
  2. package/dist/_chunks/booking-C0FoW8Yx.js.map +1 -0
  3. package/dist/_chunks/{header-settings-CifwJEKB.js → header-settings-BVhjndtV.js} +188 -168
  4. package/dist/_chunks/header-settings-BVhjndtV.js.map +1 -0
  5. package/dist/_chunks/{locale-picker-QbT1p60X.js → locale-picker-DVvinQXU.js} +339 -310
  6. package/dist/_chunks/locale-picker-DVvinQXU.js.map +1 -0
  7. package/dist/_chunks/{marketplace-app-shell-vON3WhD0.js → marketplace-app-shell-x_abo_ye.js} +2 -2
  8. package/dist/_chunks/{marketplace-app-shell-vON3WhD0.js.map → marketplace-app-shell-x_abo_ye.js.map} +1 -1
  9. package/dist/_chunks/{patient-search-Dy0sxcwv.js → patient-search-BPjP2__L.js} +15 -13
  10. package/dist/_chunks/patient-search-BPjP2__L.js.map +1 -0
  11. package/dist/agent-catalog.json +4 -4
  12. package/dist/agent-i18n/en.json +3 -3
  13. package/dist/components/booking/details-form.d.ts.map +1 -1
  14. package/dist/components/booking/index.js +1 -1
  15. package/dist/components/header-settings/header-settings.d.ts +14 -0
  16. package/dist/components/header-settings/header-settings.d.ts.map +1 -1
  17. package/dist/components/header-settings/index.js +1 -1
  18. package/dist/components/locale-picker/index.js +4 -3
  19. package/dist/components/locale-picker/locale-picker.d.ts +31 -1
  20. package/dist/components/locale-picker/locale-picker.d.ts.map +1 -1
  21. package/dist/components/patient-search/index.js +1 -1
  22. package/dist/components/patient-search/patient-search.d.ts.map +1 -1
  23. package/dist/index.js +3 -3
  24. package/dist/patterns/marketplace-app-shell/index.js +1 -1
  25. package/package.json +1 -1
  26. package/dist/_chunks/booking-DjQuhfN7.js.map +0 -1
  27. package/dist/_chunks/header-settings-CifwJEKB.js.map +0 -1
  28. package/dist/_chunks/locale-picker-QbT1p60X.js.map +0 -1
  29. package/dist/_chunks/patient-search-Dy0sxcwv.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"booking-C0FoW8Yx.js","sources":["../../node_modules/lucide-react/dist/esm/icons/activity.mjs","../../node_modules/lucide-react/dist/esm/icons/bone.mjs","../../node_modules/lucide-react/dist/esm/icons/brain.mjs","../../node_modules/lucide-react/dist/esm/icons/calendar-range.mjs","../../node_modules/lucide-react/dist/esm/icons/ear.mjs","../../node_modules/lucide-react/dist/esm/icons/microscope.mjs","../../node_modules/lucide-react/dist/esm/icons/pill.mjs","../../node_modules/lucide-react/dist/esm/icons/scissors.mjs","../../node_modules/lucide-react/dist/esm/icons/smile.mjs","../../node_modules/lucide-react/dist/esm/icons/sunset.mjs","../../node_modules/lucide-react/dist/esm/icons/syringe.mjs","../../node_modules/date-fns/subMonths.js","../../src/components/booking/booking.agent.ts","../../src/components/booking/booking-types.ts","../../src/components/booking/cascade.ts","../../src/components/booking/linkify.ts","../../src/components/booking/details-form.tsx","../../src/components/booking/step-focus.ts","../../src/components/booking/code-step.tsx","../../src/components/booking/payment.ts","../../src/components/booking/use-booking-payment.ts","../../src/components/booking/reserved.tsx","../../src/components/booking/handover.ts","../../src/components/booking/booking.tsx"],"sourcesContent":["/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2\",\n key: \"169zse\"\n }\n ]\n];\nconst Activity = createLucideIcon(\"activity\", __iconNode);\n\nexport { __iconNode, Activity as default };\n//# sourceMappingURL=activity.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M17 10c.7-.7 1.69 0 2.5 0a2.5 2.5 0 1 0 0-5 .5.5 0 0 1-.5-.5 2.5 2.5 0 1 0-5 0c0 .81.7 1.8 0 2.5l-7 7c-.7.7-1.69 0-2.5 0a2.5 2.5 0 0 0 0 5c.28 0 .5.22.5.5a2.5 2.5 0 1 0 5 0c0-.81-.7-1.8 0-2.5Z\",\n key: \"w610uw\"\n }\n ]\n];\nconst Bone = createLucideIcon(\"bone\", __iconNode);\n\nexport { __iconNode, Bone as default };\n//# sourceMappingURL=bone.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M12 18V5\", key: \"adv99a\" }],\n [\"path\", { d: \"M15 13a4.17 4.17 0 0 1-3-4 4.17 4.17 0 0 1-3 4\", key: \"1e3is1\" }],\n [\"path\", { d: \"M17.598 6.5A3 3 0 1 0 12 5a3 3 0 1 0-5.598 1.5\", key: \"1gqd8o\" }],\n [\"path\", { d: \"M17.997 5.125a4 4 0 0 1 2.526 5.77\", key: \"iwvgf7\" }],\n [\"path\", { d: \"M18 18a4 4 0 0 0 2-7.464\", key: \"efp6ie\" }],\n [\"path\", { d: \"M19.967 17.483A4 4 0 1 1 12 18a4 4 0 1 1-7.967-.517\", key: \"1gq6am\" }],\n [\"path\", { d: \"M6 18a4 4 0 0 1-2-7.464\", key: \"k1g0md\" }],\n [\"path\", { d: \"M6.003 5.125a4 4 0 0 0-2.526 5.77\", key: \"q97ue3\" }]\n];\nconst Brain = createLucideIcon(\"brain\", __iconNode);\n\nexport { __iconNode, Brain as default };\n//# sourceMappingURL=brain.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"rect\", { width: \"18\", height: \"18\", x: \"3\", y: \"4\", rx: \"2\", key: \"1hopcy\" }],\n [\"path\", { d: \"M16 2v4\", key: \"4m81vk\" }],\n [\"path\", { d: \"M3 10h18\", key: \"8toen8\" }],\n [\"path\", { d: \"M8 2v4\", key: \"1cmpym\" }],\n [\"path\", { d: \"M17 14h-6\", key: \"bkmgh3\" }],\n [\"path\", { d: \"M13 18H7\", key: \"bb0bb7\" }],\n [\"path\", { d: \"M7 14h.01\", key: \"1qa3f1\" }],\n [\"path\", { d: \"M17 18h.01\", key: \"1bdyru\" }]\n];\nconst CalendarRange = createLucideIcon(\"calendar-range\", __iconNode);\n\nexport { __iconNode, CalendarRange as default };\n//# sourceMappingURL=calendar-range.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M6 8.5a6.5 6.5 0 1 1 13 0c0 6-6 6-6 10a3.5 3.5 0 1 1-7 0\", key: \"1dfaln\" }],\n [\"path\", { d: \"M15 8.5a2.5 2.5 0 0 0-5 0v1a2 2 0 1 1 0 4\", key: \"1qnva7\" }]\n];\nconst Ear = createLucideIcon(\"ear\", __iconNode);\n\nexport { __iconNode, Ear as default };\n//# sourceMappingURL=ear.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M6 18h8\", key: \"1borvv\" }],\n [\"path\", { d: \"M3 22h18\", key: \"8prr45\" }],\n [\"path\", { d: \"M14 22a7 7 0 1 0 0-14h-1\", key: \"1jwaiy\" }],\n [\"path\", { d: \"M9 14h2\", key: \"197e7h\" }],\n [\"path\", { d: \"M9 12a2 2 0 0 1-2-2V6h6v4a2 2 0 0 1-2 2Z\", key: \"1bmzmy\" }],\n [\"path\", { d: \"M12 6V3a1 1 0 0 0-1-1H9a1 1 0 0 0-1 1v3\", key: \"1drr47\" }]\n];\nconst Microscope = createLucideIcon(\"microscope\", __iconNode);\n\nexport { __iconNode, Microscope as default };\n//# sourceMappingURL=microscope.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n { d: \"m10.5 20.5 10-10a4.95 4.95 0 1 0-7-7l-10 10a4.95 4.95 0 1 0 7 7Z\", key: \"wa1lgi\" }\n ],\n [\"path\", { d: \"m8.5 8.5 7 7\", key: \"rvfmvr\" }]\n];\nconst Pill = createLucideIcon(\"pill\", __iconNode);\n\nexport { __iconNode, Pill as default };\n//# sourceMappingURL=pill.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"circle\", { cx: \"6\", cy: \"6\", r: \"3\", key: \"1lh9wr\" }],\n [\"path\", { d: \"M8.12 8.12 12 12\", key: \"1alkpv\" }],\n [\"path\", { d: \"M20 4 8.12 15.88\", key: \"xgtan2\" }],\n [\"circle\", { cx: \"6\", cy: \"18\", r: \"3\", key: \"fqmcym\" }],\n [\"path\", { d: \"M14.8 14.8 20 20\", key: \"ptml3r\" }]\n];\nconst Scissors = createLucideIcon(\"scissors\", __iconNode);\n\nexport { __iconNode, Scissors as default };\n//# sourceMappingURL=scissors.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"path\", { d: \"M8 14s1.5 2 4 2 4-2 4-2\", key: \"1y1vjs\" }],\n [\"line\", { x1: \"9\", x2: \"9.01\", y1: \"9\", y2: \"9\", key: \"yxxnd0\" }],\n [\"line\", { x1: \"15\", x2: \"15.01\", y1: \"9\", y2: \"9\", key: \"1p4y9e\" }]\n];\nconst Smile = createLucideIcon(\"smile\", __iconNode);\n\nexport { __iconNode, Smile as default };\n//# sourceMappingURL=smile.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M12 10V2\", key: \"16sf7g\" }],\n [\"path\", { d: \"m4.93 10.93 1.41 1.41\", key: \"2a7f42\" }],\n [\"path\", { d: \"M2 18h2\", key: \"j10viu\" }],\n [\"path\", { d: \"M20 18h2\", key: \"wocana\" }],\n [\"path\", { d: \"m19.07 10.93-1.41 1.41\", key: \"15zs5n\" }],\n [\"path\", { d: \"M22 22H2\", key: \"19qnx5\" }],\n [\"path\", { d: \"m16 6-4 4-4-4\", key: \"6wukr\" }],\n [\"path\", { d: \"M16 18a4 4 0 0 0-8 0\", key: \"1lzouq\" }]\n];\nconst Sunset = createLucideIcon(\"sunset\", __iconNode);\n\nexport { __iconNode, Sunset as default };\n//# sourceMappingURL=sunset.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"m18 2 4 4\", key: \"22kx64\" }],\n [\"path\", { d: \"m17 7 3-3\", key: \"1w1zoj\" }],\n [\"path\", { d: \"M19 9 8.7 19.3c-1 1-2.5 1-3.4 0l-.6-.6c-1-1-1-2.5 0-3.4L15 5\", key: \"1exhtz\" }],\n [\"path\", { d: \"m9 11 4 4\", key: \"rovt3i\" }],\n [\"path\", { d: \"m5 19-3 3\", key: \"59f2uf\" }],\n [\"path\", { d: \"m14 4 6 6\", key: \"yqp9t2\" }]\n];\nconst Syringe = createLucideIcon(\"syringe\", __iconNode);\n\nexport { __iconNode, Syringe as default };\n//# sourceMappingURL=syringe.mjs.map\n","import { addMonths } from \"./addMonths.js\";\n\n/**\n * The subMonths function options.\n */\n\n/**\n * @name subMonths\n * @category Month Helpers\n * @summary Subtract the specified number of months from the given date.\n *\n * @description\n * Subtract the specified number of months from the given date.\n *\n * @typeParam DateType - The `Date` type, the function operates on. Gets inferred from passed arguments. Allows to use extensions like [`UTCDate`](https://github.com/date-fns/utc).\n * @typeParam ResultDate - The result `Date` type, it is the type returned from the context function if it is passed, or inferred from the arguments.\n *\n * @param date - The date to be changed\n * @param amount - The amount of months to be subtracted.\n * @param options - An object with options\n *\n * @returns The new date with the months subtracted\n *\n * @example\n * // Subtract 5 months from 1 February 2015:\n * const result = subMonths(new Date(2015, 1, 1), 5)\n * //=> Mon Sep 01 2014 00:00:00\n */\nexport function subMonths(date, amount, options) {\n return addMonths(date, -amount, options);\n}\n\n// Fallback for modularized imports:\nexport default subMonths;\n","/* -------------------------------------------------------------------- */\n/* Agent adapter — Booking (0.26.0). */\n/* */\n/* The Booking component consolidates the seven-step patient booking */\n/* flow into a single component. The adapter exposes variant + step */\n/* navigation. The booking value itself is owned by the consumer and */\n/* flows through `value` / `onChange` — never read here (PHI: patient */\n/* identity + contact stays on the page). */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { BookingHandle } from './booking-types';\n\nexport const bookingAgent: AgentAdapter<BookingHandle> = {\n id: 'booking',\n // `view_change` removed (0.69): the layout `variant` is a fixed prop — the\n // handle exposes only `getVariant` (state), no action mutates it. The flow's\n // only navigation is step-to-step (`goto_step` → `navigate`).\n capabilities: ['navigate'],\n state: {\n variant: {\n type: 'string',\n descriptionKey: 'ui.agent.booking.state.variant',\n description:\n 'Active variant — one of `inline-list`, `accordion`, `calendar`, `flexible`, `progress`.',\n read: (handle) => handle.getVariant(),\n },\n currentStep: {\n type: 'number',\n descriptionKey: 'ui.agent.booking.state.currentStep',\n description:\n 'The step the flow is on: 1 insurance, 2 specialty, 3 service, 4 provider, 5 date, 6 time, 7 patient details, payment or optional SMS code verification, 8 confirmation after all required steps succeed, including the \"Time reserved\" view that opens a host address after a short delay. Read this back after `goto_step` to see where the clamp landed.',\n read: (handle) => handle.getCurrentStep(),\n },\n },\n actions: {\n reset: {\n // destructive: clears the whole in-progress booking value (patient\n // identity, contact, slot choice) — irreversibly loses user input.\n safety: 'destructive',\n idempotent: true,\n descriptionKey: 'ui.agent.booking.actions.reset',\n description:\n 'Clear the booking value back to an empty state. Use to abandon an in-progress flow.',\n errors: [\n 'Refused while a payment session is open (step 7): the consumer must cancel the hold first.',\n 'Refused while SMS code verification is pending (step 7): the locked form and code box stay, and the submitted booking remains active. The host owns cancellation.',\n ],\n invoke: (handle) => {\n handle.reset();\n },\n },\n goto_step: {\n safety: 'read',\n argsType: '{ step: 1 | 2 | 3 | 4 | 5 | 6 | 7 }',\n argsSchema: {\n type: 'object',\n properties: {\n step: {\n type: 'integer',\n enum: [1, 2, 3, 4, 5, 6, 7],\n description: 'Target step (1-7).',\n },\n },\n required: ['step'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.booking.actions.gotoStep',\n description:\n 'Jump to the given step. A step that is hidden for this practice, or that sits ahead of the first incomplete step, clamps to that first incomplete step — read `currentStep` back to see where it landed.',\n errors: [\n 'Navigation stays on step 7 while payment or SMS code verification is pending.',\n 'Requested step is not yet reachable — clamped to the first incomplete step.',\n 'Requested step is hidden for this practice (e.g. insurance outside Germany, or provider choice turned off) — clamped to the first incomplete step.',\n ],\n examples: [{ args: { step: 1 }, note: 'Return to the first step.' }],\n invoke: (handle, args: { step: 1 | 2 | 3 | 4 | 5 | 6 | 7 }) => {\n handle.goToStep(args.step);\n },\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'booking',\n description:\n 'Marks the Booking root region. The host prop hideEmail (boolean, default false) hides the email field, skips its validation and omits email from submission. The host prop emailOptional (boolean, default false) keeps email visible and optional unless used for confirmation. Email is marked and validated as required when selected in the channel picker or singleConfirmationChannel radio, or when the effective confirmation channel is email. With a hidden picker, the form and success screen use the sole enabled channel, or email when multiple channels are enabled. This includes payment and blocked-payment flows, which omit stored selections from submission. Omitting confirmationChannels also defaults to email. Selecting SMS without email makes the field optional again. The optional/required marker updates visually when the channel changes, with no announcement of that change. Validation updates immediately using the existing email error. With emailOptional, surrounding spaces are trimmed before validation, even when email is required for confirmation. Optional blank values are omitted from submission; filled values are sent trimmed. hideEmail takes precedence over emailOptional. Neither prop changes confirmation channels; pair with confirmationChannels [\"sms\"] for SMS-only confirmation with no channel picker. The optional codeStep prop adds SMS verification after submission and before any payment: the submitted form stays in place but locked (controls disabled, text still readable, not hidden), the code box opens below it, and a Change button, for the patient only (no agent action unlocks it), unlocks the form for a new booking request (the host keeps the earlier request until it expires; the kit cannot cancel it). With payment, a correct code opens the payment stage, and the step remains 7 until payment succeeds; without payment it remains 7 until verification succeeds. It then becomes 8. Patient contact details and verification codes are never exposed through this adapter.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n },\n};\n","/* -------------------------------------------------------------------- */\n/* Booking — public type surface (0.26.0). */\n/* */\n/* Re-exported from `booking.tsx`. Lives in its own module so */\n/* `cascade.ts` can import the types without a circular dependency on */\n/* the main component file. */\n/* -------------------------------------------------------------------- */\n\nimport type { ComponentPropsWithoutRef, ReactNode } from 'react';\n\n/* -------------------------------------------------------------------- */\n/* Variant */\n/* -------------------------------------------------------------------- */\n\nexport type BookingVariant =\n | 'inline-list'\n | 'accordion'\n | 'calendar'\n | 'flexible'\n | 'progress';\n\n/* -------------------------------------------------------------------- */\n/* Domain shapes */\n/* -------------------------------------------------------------------- */\n\nexport type InsuranceType = 'private' | 'public';\n\n/** Channels the patient can pick to receive the confirmation link. */\nexport type ConfirmationChannel = 'email' | 'whatsapp' | 'sms';\n\n/** Fixed order — email first, then WhatsApp, then SMS. */\nexport const CONFIRMATION_CHANNEL_ORDER: readonly ConfirmationChannel[] = [\n 'email',\n 'whatsapp',\n 'sms',\n] as const;\n\nexport interface BookingSpecialty {\n id: string;\n label: string;\n /** Optional ordering hint; falls back to array order. */\n sequenceNumber?: number;\n /** Restrict to operators-on-page when lockedOperatorId is set. */\n operatorIds?: string[];\n}\n\n/**\n * One appointment payment, in currency minor units. Set it only when the\n * platform AppointmentBookingReason.requireAdvancePayment is true.\n */\nexport interface BookingServicePayment {\n /** No platform field: the consumer derives it, e.g. deposit when advanceAmount < price. */\n kind: 'full' | 'deposit';\n /** Platform advanceAmount (euros) x 100. NOT price, which only feeds priceLabel. */\n amountCents: number;\n /** Defaults to EUR, the only currency production charges. */\n currencyCode?: string;\n}\n\nexport interface BookingResolvedPayment extends BookingServicePayment {\n serviceId: string;\n currencyCode: string;\n}\n\nexport interface BookingPaymentSession {\n /** Opaque hold identity. Keep Stripe credentials in the consumer, keyed by this id. */\n id: string;\n payment: BookingResolvedPayment;\n}\n\nexport interface BookingSubmitResult {\n paymentSession: BookingPaymentSession;\n}\n\nexport type BookingPaymentState =\n | { sessionId: string; status: 'ready' | 'cancelled' }\n | {\n sessionId: string;\n status: 'paid';\n /**\n * An http(s) address to open after payment. Booking then shows\n * \"Time reserved\" and opens it (see `handoverDelayMs`). Without it the\n * paid receipt shows as before.\n */\n redirectUrl?: string;\n }\n | { sessionId: string; status: 'processing'; phase: 'payment' | 'completion' }\n | {\n sessionId: string;\n status: 'failed';\n phase: 'payment' | 'completion';\n error?: ReactNode;\n };\n\nexport interface BookingPaymentRenderContext {\n session: BookingPaymentSession;\n payment: BookingResolvedPayment;\n state: BookingPaymentState;\n /**\n * The billing details the patient gave on the details form, when\n * `billingInDetails` is set. Pass it to `PaymentForm` as\n * `billingDetails`: the payment step then shows card fields only and\n * Stripe still receives the name and address.\n */\n billing?: BookingBillingDetails;\n}\n\nexport interface BookingService {\n id: string;\n label: string;\n /** Minutes — required for slot fetching. */\n durationMin: number;\n /**\n * Pre-formatted price label (e.g. \"€ 80\", \"da € 60\"). When present, the\n * service picker shows the price INSTEAD of the duration — durations vary\n * case by case and set the wrong expectation, while price is what patients\n * compare. With no price the picker falls back to the duration, unless\n * Booking's `showServiceDuration` is false. `durationMin` keeps driving\n * slot fetching either way. Currency\n * and number formatting are the consumer's domain — the kit renders the\n * string verbatim. Added in 1.6.0.\n */\n priceLabel?: string;\n /**\n * Mandatory online payment for this service only. Never inferred from\n * priceLabel. The service picker shows it on a line under the service\n * name; the chip keeps showing `priceLabel`, or a full payment's amount\n * when there is no `priceLabel`.\n */\n payment?: BookingServicePayment;\n /** Required when useSpecialties is true. */\n specialtyId?: string;\n /** Operators who can perform this service. */\n operatorIds?: string[];\n /**\n * Practice-authored plain text the patient must read and accept before\n * the booking can be submitted (the platform's\n * `criticalInformationToAccept` on a booking reason). When present, the\n * details step renders it above the consents with a required checkbox;\n * when absent, the step adds nothing. Always rendered as text, never as\n * HTML: a practice cannot inject markup through it.\n */\n criticalInformationToAccept?: string;\n}\n\n/**\n * The practice's own privacy notice or terms checkbox, shown on the\n * details step after the AlfaDocs privacy and terms boxes. Mirrors the\n * practice API's `practiceConsent: { label, url, required }` (HTP-6560),\n * which is `null` when the practice has not set one.\n */\nexport interface BookingPracticeConsent {\n /**\n * Practice-authored checkbox text. Rendered as plain text, never as\n * HTML. A blank label shows nothing, as if `practiceConsent` were unset.\n */\n label: string;\n /**\n * The practice's notice or terms page. When it is an `http(s)` URL the\n * label links to it in a new tab; any other value leaves the label as\n * plain text.\n */\n url?: string | null;\n /**\n * `true`: the box carries the required asterisk and submit stays\n * disabled until it is ticked. `false`: the box is optional.\n */\n required: boolean;\n}\n\nexport interface BookingOperator {\n id: string;\n name: string;\n specialtyIds?: string[];\n appointmentBookingReasonIds?: string[];\n}\n\nexport interface BookingSlot {\n /** Opaque unique key within `availableSlots[date]`. */\n key: string;\n /** Actual service booked when serviceIds contains several search alternatives. */\n serviceId?: string;\n /** HH:mm 24h — used for display. */\n time: string;\n available: boolean;\n /** Opaque passthrough so the consumer can resolve operatorId / chairId\n * / dateTime when `onSubmit` fires. */\n meta?: Record<string, unknown>;\n}\n\n/**\n * Where a paid booking's receipt is addressed, collected on the details\n * form when `billingInDetails` is set and the chosen service has a\n * `payment`. The same shape as PaymentForm's `PaymentFormBillingDetails`,\n * so the host can pass it straight to Stripe as the payment's billing\n * details. No platform column holds it today (`stripe_payment` has none),\n * so a host that needs it later must store it itself. `name` is the\n * patient's first and last name: it is filled in when the form is\n * submitted, and is '' in the controlled value before that. The fiscal\n * code travels separately as `codiceFiscale` (platform\n * `DoctorAppointment.bookingItalianFiscalCode`).\n */\nexport interface BookingBillingDetails {\n name: string;\n address: {\n line1: string;\n line2: string | null;\n city: string;\n /** Province code for Italy (e.g. \"MI\"). '' for any other country:\n * the form asks for a province in Italy only. */\n state: string;\n postalCode: string;\n /** ISO 3166-1 alpha-2, upper case (e.g. \"IT\"). */\n country: string;\n };\n}\n\nexport interface BookingDetails {\n firstName: string;\n lastName: string;\n /**\n * Required by default. Omitted when `hideEmail` is true, or when blank\n * with `emailOptional` and confirmation uses another channel.\n * Filled values are trimmed when submitted.\n */\n email?: string;\n mobilePhone: string;\n privacyConsent: boolean;\n termsConsent: boolean;\n /**\n * `true` once the patient has ticked the acceptance box for the selected\n * service's `criticalInformationToAccept`. Present in the submit payload\n * only when the service carries that text; omitted otherwise.\n */\n criticalInformationAccepted?: boolean;\n /**\n * The patient's answer to the practice's own checkbox (`practiceConsent`\n * on `BookingProps`). Present in the submit payload, `true` or `false`,\n * whenever that checkbox is shown; omitted when the practice has none.\n */\n practiceConsentAccepted?: boolean;\n /** Included only when the patient accepts this service's payment quote. */\n paymentAccepted?: boolean;\n // Opt-in fields — typed optional, required only when their `require*`\n // prop is true on `BookingProps`.\n codiceFiscale?: string;\n dateOfBirth?: string;\n insuranceNumber?: string;\n // Optional, gated by `show*` props.\n note?: string;\n returningPatient?: boolean;\n /**\n * Channels the patient picked for the confirmation link. Guaranteed to\n * be a non-empty subset of the practice's enabled `confirmationChannels`\n * when present. Omitted when only one channel is enabled (implicit —\n * backend infers from the practice config).\n */\n confirmationChannels?: ConfirmationChannel[];\n /**\n * The billing address, present only when `billingInDetails` is set and\n * the service is paid. See `BookingBillingDetails`.\n */\n billing?: BookingBillingDetails;\n}\n\nexport interface BookingValue {\n insuranceType?: InsuranceType;\n specialtyId?: string;\n /**\n * Multi-select form of `specialtyId` — set this instead of (or alongside)\n * `specialtyId` when `specialtyPickerStyle='multi-select'`. The cascade\n * reads this array first and treats services / operators / slots as a\n * union of the selected specialties. When both are set, the array wins.\n * Added in 0.34.0.\n */\n specialtyIds?: string[];\n serviceId?: string;\n /**\n * Multi-select form of `serviceId` — see `specialtyIds`. Set when\n * `servicePickerStyle='multi-select'`. Union semantics. Added in 0.34.0.\n */\n serviceIds?: string[];\n /** May be the literal `'all'` sentinel to mean \"no operator preference\". */\n operatorId?: string;\n /**\n * Multi-select form of `operatorId` — see `specialtyIds`. Set when\n * `operatorPickerStyle='multi-select'`. The kit doesn't filter slots by\n * operator itself (the consumer owns slot resolution), but consumers\n * using multi-select operator typically filter `availableSlots` to the\n * union of `operatorIds` before passing the data in. Added in 0.34.0.\n */\n operatorIds?: string[];\n /** YYYY-MM-DD. */\n date?: string;\n /** Opaque key from `availableSlots[date]`. */\n slotKey?: string;\n /** Partial details — fully populated when the user is ready to submit. */\n details?: Partial<BookingDetails>;\n}\n\n/* -------------------------------------------------------------------- */\n/* Submit payload — fully resolved. */\n/* -------------------------------------------------------------------- */\n\nexport interface BookingSubmitPayload {\n slot: BookingSlot;\n value: BookingValue;\n /** Fully populated + validated (privacy + terms ticked, required fields filled). */\n details: BookingDetails;\n payment?: BookingResolvedPayment;\n}\n\n/* -------------------------------------------------------------------- */\n/* Async validator return shape */\n/* -------------------------------------------------------------------- */\n\nexport interface BookingValidationResult {\n valid: boolean;\n /** Optional localised hint shown next to the field on failure. */\n hint?: string;\n}\n\nexport type BookingValidator = (\n value: string,\n) => Promise<BookingValidationResult>;\n\n/* -------------------------------------------------------------------- */\n/* Imperative handle */\n/* -------------------------------------------------------------------- */\n\nexport interface BookingHandle {\n getVariant: () => BookingVariant;\n /**\n * The step the flow is on — 1-7 while the cascade is in progress, and 8\n * once the confirmation view is showing. Payment and optional SMS code\n * verification remain in step 7 until they succeed.\n *\n * This is the read-back for `goToStep`: it reports the **cursor**, which\n * can sit behind the cascade's frontier after a backwards edit. It is\n * therefore NOT always the number `onStepChange` emits — that callback\n * reports the frontier (the first incomplete step), so moving the cursor\n * back to step 3 with everything filled makes this return `3` while\n * `onStepChange` stays silent on `7`.\n */\n getCurrentStep: () => 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;\n /** Clear `value` back to an empty state via `onChange`. */\n reset: () => void;\n /**\n * Jump to a specific step. A step that is not in the visible ladder, or\n * that sits ahead of the first incomplete step, clamps to that first\n * incomplete step rather than stranding the cursor.\n */\n goToStep: (step: 1 | 2 | 3 | 4 | 5 | 6 | 7) => void;\n}\n\n/**\n * Opt into SMS verification after submission and before any required payment.\n * The submitted form stays in place, locked, with the code box below it. A\n * \"Change\" button unlocks the form; the next submit calls `onSubmit` again as\n * a new booking request. The host's earlier request stays held on the\n * platform until it expires: the kit cannot cancel it. With a payment, a\n * correct code opens the payment stage; the code is never asked after paying.\n */\nexport interface BookingCodeStep {\n /** Number of characters, default 5. OTPInput clamps this to 3–10. */\n length?: number;\n /** Resolve ok only after the host has verified the code and confirmed the booking. */\n onVerify: (code: string) => Promise<\n | {\n ok: true;\n /**\n * An http(s) address to open after the code. Booking then shows\n * \"Time reserved\" and opens it (see `handoverDelayMs`). Ignored when\n * a payment follows. Without it the confirmation view shows as before.\n */\n redirectUrl?: string;\n }\n | { ok: false; reason: 'wrong' | 'expired' | 'too-many-attempts' }\n >;\n /** Send a new SMS code. Only a successful resend restarts the countdown. */\n onResend: () => Promise<void>;\n /** Wait before resending, in seconds. Default 60; zero allows an immediate resend. */\n resendSeconds?: number;\n /** Optional masked mobile number shown in the instructions. */\n phoneHint?: string;\n}\n\n/* -------------------------------------------------------------------- */\n/* Component props */\n/* -------------------------------------------------------------------- */\n\nexport interface BookingProps extends Omit<\n ComponentPropsWithoutRef<'div'>,\n 'aria-label' | 'onChange' | 'onSubmit'\n> {\n variant?: BookingVariant;\n\n // Policy\n country?: string;\n useSpecialties?: boolean;\n allowOperatorSelection?: boolean;\n /** Pins step 4 to this operator. */\n lockedOperatorId?: string;\n /**\n * Default: false. When true, the operators offered for a service are the\n * ones linked to that service, even when specialties are on. The specialty\n * only groups services.\n */\n operatorsByService?: boolean;\n\n // Data (any may be empty — the cascade handles it)\n specialties?: BookingSpecialty[];\n services: BookingService[];\n operators?: BookingOperator[];\n availableDates: string[];\n availableSlots: Record<string, BookingSlot[]>;\n /** Server-side hint of the next free date when the current window is empty. */\n nextAvailableDate?: string;\n\n // Step 7 controls (all opt-in, default false)\n /**\n * Hide the email field and skip its validation. Default: false.\n * Submission omits email, including any email in the controlled value.\n * Takes precedence over `emailOptional`.\n * Pair with `confirmationChannels={['sms']}` for SMS-only confirmation.\n * This prop does not change the enabled confirmation channels.\n */\n hideEmail?: boolean;\n /**\n * Keep email visible but optional unless used for confirmation. Default: false.\n * Email remains required when selected in the picker or radio, or when\n * the resolved channels contain only email (including the omitted-prop default).\n * Otherwise, blank or whitespace-only values are omitted from submission.\n * Filled values must match the existing email format and are submitted trimmed.\n * `hideEmail` takes precedence. This does not change confirmation channels;\n * pair with `confirmationChannels={['sms']}` for SMS-only confirmation.\n */\n emailOptional?: boolean;\n requireCodiceFiscale?: boolean;\n requireDateOfBirth?: boolean;\n requireInsuranceNumber?: boolean;\n showNote?: boolean;\n showReturningPatientFlag?: boolean;\n privacyPolicyUrl?: string;\n termsUrl?: string;\n /**\n * The practice's own privacy notice or terms checkbox, after the AlfaDocs\n * ones. Omit it, or pass `null` as the practice API does, to show nothing.\n * The answer arrives as `details.practiceConsentAccepted`.\n */\n practiceConsent?: BookingPracticeConsent | null;\n paymentTermsUrl?: string;\n /**\n * Ask for the billing address on the details form when the chosen\n * service has a `payment`, so `onSubmit` carries everything the host\n * needs to open the hold and the payment in one call. The card step then\n * needs no address. The fiscal code is still asked only with\n * `requireCodiceFiscale`; it then sits inside the billing block. Off (the\n * default), billing stays in the card step (PaymentForm\n * `requireBillingAddress`).\n * @default false\n */\n billingInDetails?: boolean;\n /**\n * How the \"online payment required\" notice on the details form looks.\n * `highlighted` is a tinted card with a card icon and the amount beside\n * the heading. `plain` is the grey card, the default before 1.55.0. The\n * wording and the acceptance box are the same in both.\n * @default 'highlighted'\n */\n paymentNoticeStyle?: 'plain' | 'highlighted';\n /**\n * Wait before opening a `redirectUrl`, in milliseconds. Not under\n * motion: the redirect happens after this delay with reduced motion too.\n * @default 3000\n */\n handoverDelayMs?: number;\n /**\n * Opens a `redirectUrl`. Defaults to `window.location.assign`. Pass one to\n * route inside an app, or to stub navigation in tests and stories.\n */\n onNavigate?: (url: string) => void;\n /** Publish paid only after the server verifies payment AND saves the appointment. */\n paymentState?: BookingPaymentState;\n /** Render PaymentForm here. The consumer owns Stripe credentials and completion calls. */\n renderPayment?: (context: BookingPaymentRenderContext) => ReactNode;\n /**\n * Completion retry only: never render card entry or start another payment here.\n * Supply it with renderPayment; without it a failed completion shows only the error.\n */\n renderPaymentCompletion?: (context: BookingPaymentRenderContext) => ReactNode;\n\n // Validation hooks (consumer-injected)\n validateCodiceFiscale?: BookingValidator;\n validateInsuranceNumber?: BookingValidator;\n\n // Auto-select policy\n /** Default: false. Specialty auto-select on length=1 is always on. */\n autoSelectSingleService?: boolean;\n\n // Confirmation-channel delivery\n /**\n * Channels the practice has enabled. The picker renders one checkbox\n * per channel; when length === 1, the picker is hidden and the single\n * channel is implicit. Defaults to `['email']` when omitted.\n */\n confirmationChannels?: ConfirmationChannel[];\n /**\n * Pre-checked channels. Intersected with `confirmationChannels` for\n * safety. When omitted, the kit applies a smart default (always email;\n * +whatsapp when mobile is plausibly filled; +sms when whatsapp isn't\n * available).\n */\n defaultConfirmationChannels?: ConfirmationChannel[];\n /**\n * The patient picks exactly one channel (a radio group) instead of any\n * number (checkboxes), and the link goes only there. The default is the\n * first channel of `defaultConfirmationChannels` the practice enabled,\n * else the first enabled channel. Use it when the channel matters to the\n * host: a link sent only by SMS proves the patient holds the phone.\n */\n singleConfirmationChannel?: boolean;\n\n // State\n value: BookingValue;\n onChange: (next: BookingValue) => void;\n onSubmit: (\n payload: BookingSubmitPayload,\n ) => void | BookingSubmitResult | Promise<void | BookingSubmitResult>;\n /** Optional SMS code step. Omit to retain the existing confirmation-link flow. */\n codeStep?: BookingCodeStep;\n\n // UX\n /**\n * Calendar/date-strip shimmer — set true while `availableDates` is being\n * fetched. When omitted, the kit falls back to `loadingSlots` for the\n * calendar shimmer (the long-standing behaviour). Split from\n * `loadingSlots` in 0.33.9 so consumers using a two-query pattern\n * (\"which days have availability\" + per-day slot fetch) can shimmer\n * the calendar independently of the slot list — without this split a\n * per-day slot fetch re-shimmers the whole calendar on every date click.\n */\n loadingDates?: boolean;\n /**\n * Slot-list shimmer — set true while `availableSlots[value.date]` is\n * being fetched. Drives the `<GroupedTimeSlots>` and the calendar-\n * variant time-slot list. When `loadingDates` is omitted, this flag\n * also drives the calendar shimmer (backward-compat fallback).\n */\n loadingSlots?: boolean;\n submitting?: boolean;\n /**\n * @default 'flat'\n * `'elevated'` wraps the kit-rendered surface in the equivalent of\n * `Card variant=\"elevated\"` (same tokens, same padding). Use to drop\n * the consumer-side Card wrap.\n */\n surface?: 'flat' | 'elevated';\n /**\n * Fires whenever the displayed step changes — steps 1..7 from the\n * cascade engine + step `8` when the success view mounts. Useful for\n * analytics events that aren't already kit-internal, custom focus\n * management, or page-title updates. The kit also auto-scrolls the\n * success container into view on the 1..7 → 8 transition; consumers\n * don't need to do that themselves.\n */\n onStepChange?: (step: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8) => void;\n /**\n * Fires when the patient picks a date in the calendar — sugar for\n * consumers using a two-query pattern who need to kick off the\n * per-day slot fetch on date click. Consumers can already detect\n * a date change by diffing `value.date` inside `onChange`; this\n * callback just spares them that diff. Fires AFTER the kit has\n * applied the date change through `onChange` — `value.date` will\n * reflect the new ISO when this fires.\n */\n onDateSelect?: (iso: string) => void;\n /**\n * Fires when the visible 4-day window starts or shifts. Used by\n * two-query consumers to lazy-fetch `dailySlots/{date}` for the\n * newly-visible days. Receives the inclusive ISO date strings of\n * the first and last visible day in the window. Fires on mount\n * (with the resolved initial window) and on every prev/next\n * arrow click, internal jump-to-next-available action, and\n * automatic re-sync triggered by `availableDates` arriving.\n *\n * Only fires when `datePickerStyle='four-day-grid'` — the\n * month-calendar picker has no \"window\" concept; consumers using\n * that style fetch availability per visible month and don't need\n * this signal.\n */\n onWindowChange?: (startIso: string, endIso: string) => void;\n /**\n * @default 'select'\n * UI rendered for the Specialty step. Independent of layout `variant`.\n *\n * - `'select'` (default): the kit's `<Select>` dropdown — current behaviour.\n * - `'combobox'`: single-select `<Combobox>` with type-ahead search.\n * Pays off for long specialty lists (>10 entries).\n * - `'multi-select'`: multi-select `<MultiSelect>` with chip-rendered\n * selections. Writes to `value.specialtyIds` (array). The cascade reads\n * the array as a union — services / operators / slots are filtered\n * by ANY of the selected specialties. Added in 0.34.0.\n */\n specialtyPickerStyle?: 'select' | 'combobox' | 'multi-select';\n /**\n * @default 'cards' for `variant='inline-list'`, `'select'` for others\n * UI rendered for the Service step. Independent of layout `variant`.\n *\n * - `'cards'`: visual card grid (the long-standing `ServiceCardGroup`\n * used by inline-list). Card layout, one row per service with icon,\n * label, and price or duration.\n * - `'select'`: compact `<Select>` dropdown (default for the chrome-\n * denser variants — calendar / flexible / accordion / progress).\n * - `'combobox'`: single-select `<Combobox>` with type-ahead search.\n * - `'multi-select'`: multi-select `<MultiSelect>` writing to\n * `value.serviceIds`. Cascade reads as union — operators / slots are\n * filtered by ANY of the selected services. Added in 0.34.0.\n */\n servicePickerStyle?: 'select' | 'combobox' | 'multi-select' | 'cards';\n /**\n * @default true\n * Whether the service picker shows a service's duration. A service with\n * no price shows its minutes in place of one; set this to false and it\n * shows its name only, in every `servicePickerStyle`, and its accessible\n * name does not mention minutes either. Priced services are unchanged:\n * they never show a duration. `durationMin` stays required and keeps\n * driving slot fetching. Added in 1.54.1.\n */\n showServiceDuration?: boolean;\n /**\n * @default 'select'\n * UI rendered for the Operator step. Independent of layout `variant`.\n *\n * - `'select'` (default): `<Select>` dropdown including the implicit\n * `'all'` \"any operator\" sentinel.\n * - `'combobox'`: single-select `<Combobox>` with type-ahead search.\n * - `'multi-select'`: multi-select `<MultiSelect>` writing to\n * `value.operatorIds`. The kit doesn't filter slots by operator\n * itself — the consumer owns slot resolution — but consumers using\n * multi-select operator typically filter `availableSlots` to the\n * union of selected operators before passing the data in. Added\n * in 0.34.0.\n */\n operatorPickerStyle?: 'select' | 'combobox' | 'multi-select';\n /**\n * @default 'month-calendar'\n * Selects the date + slot picker rendered inside the cascade's date\n * and slot steps. Independent of the layout `variant`:\n *\n * - `'month-calendar'` (default): the 6×7 `<MonthGrid>` followed by\n * the morning/afternoon/evening `<GroupedTimeSlots>`. Two-step flow\n * — patient picks a date, slots reveal underneath.\n *\n * - `'four-day-grid'`: a 4-column day-strip (`<SlotGrid>`) with ±4-day\n * arrow nav and per-day vertical slot tiles. One-step flow —\n * patient picks a slot directly; clicking a slot atomically sets\n * both `value.date` and `value.slotKey`. The cascade's separate\n * \"slot\" step is suppressed because the slots are inline with the\n * date strip.\n *\n * The data contract is unchanged — `availableDates`, `availableSlots`,\n * `loadingDates`, `loadingSlots`, `onDateSelect` all behave the same\n * way for both styles. Defaults to `'month-calendar'` so existing\n * consumers see no behavioural change.\n */\n datePickerStyle?: 'month-calendar' | 'four-day-grid';\n /**\n * Surface a submit-failure message inside the form (Alert variant=destructive\n * above the submit button). The consumer owns the state — set it after an\n * `onSubmit` rejection, clear it when retrying or on a field edit. When set,\n * the kit's normal \"form stays mounted on rejected promise\" behaviour is\n * unchanged; this just gives the failure a sanctioned slot to render.\n */\n submitError?: ReactNode;\n /**\n * @default 'live'\n * In `'demo'` mode the kit's step-8 success view swaps its description to\n * a localised \"This was a demo — no confirmation was sent.\" so the copy\n * stays honest when no real API call was made.\n */\n mode?: 'live' | 'demo';\n /**\n * @default true\n * Render a \"Modify booking\" button on the step-8 success view that returns\n * to step 7 without clearing `value`/`details`. Practices that want a\n * one-shot booking flow can hide this.\n */\n showModifyOnSuccess?: boolean;\n emptyServicesSlot?: ReactNode;\n onboardingIncompleteSlot?: ReactNode;\n\n // a11y\n 'aria-label'?: string;\n id?: string;\n}\n","/* -------------------------------------------------------------------- */\n/* Booking cascade engine — pure functions, no React. */\n/* */\n/* The seven-step state machine that drives every variant. Visibility */\n/* gates, downstream filtering, auto-skip rules, and reset semantics */\n/* live here so each variant only renders a phase of the cascade — it */\n/* doesn't re-implement the logic. The booking-website's legacy */\n/* `useBookingState.js` is the behavioural source-of-truth; the */\n/* mapping is documented inline at each gate. */\n/* -------------------------------------------------------------------- */\n\nimport type {\n BookingOperator,\n BookingService,\n BookingSlot,\n BookingSpecialty,\n BookingValue,\n ConfirmationChannel,\n InsuranceType,\n} from './booking-types';\nimport { CONFIRMATION_CHANNEL_ORDER } from './booking-types';\n\n/**\n * Sentinel for the operator filter's \"All operators\" pseudo-option. Mirrors\n * `OPERATORS_ALL = '0'` in the legacy `useBookingState.js`, but the kit\n * uses `'all'` as the well-known string so consumers can't accidentally\n * collide with a real operator id of `'0'`.\n */\nexport const OPERATORS_ALL = 'all' as const;\n\nconst COUNTRY_GERMANY = 'de';\n\n/* -------------------------------------------------------------------- */\n/* Inputs / outputs */\n/* -------------------------------------------------------------------- */\n\nexport interface CascadePolicy {\n /** ISO 3166-1 alpha-2 country code. Currently only `'de'` toggles a gate. */\n country?: string;\n useSpecialties?: boolean;\n allowOperatorSelection?: boolean;\n /** When set, locks step 4 to this operator id and hides the picker. */\n lockedOperatorId?: string;\n /** Defaults to `false`. When true, single-service lists auto-pre-fill. */\n autoSelectSingleService?: boolean;\n /**\n * Defaults to `false`. When true, the operators offered come from the\n * chosen service (`appointmentBookingReasonIds`) even when specialties are\n * on; the specialty only groups services. Added in 1.40.0.\n */\n operatorsByService?: boolean;\n}\n\nexport interface CascadeInputs extends CascadePolicy {\n specialties: BookingSpecialty[];\n services: BookingService[];\n operators: BookingOperator[];\n availableDates: string[];\n availableSlots: Record<string, BookingSlot[]>;\n value: BookingValue;\n}\n\nexport interface CascadeGates {\n insurance: boolean;\n specialty: boolean;\n service: boolean;\n operator: boolean;\n date: boolean;\n slot: boolean;\n details: boolean;\n /** True when a service is picked but no eligible operators can perform it. */\n onboardingIncomplete: boolean;\n}\n\nexport interface CascadeFiltered {\n specialties: BookingSpecialty[];\n services: BookingService[];\n /**\n * Eligible operators for the active specialty (when `useSpecialties=true`)\n * OR the active service. Excludes the \"All operators\" sentinel — that's\n * always prepended in the UI layer.\n */\n operators: BookingOperator[];\n}\n\n/** Step number — 1-indexed, matches the docs / a11y order. */\nexport type CascadeStep = 1 | 2 | 3 | 4 | 5 | 6 | 7;\n\nexport interface CascadeOutputs {\n gates: CascadeGates;\n filtered: CascadeFiltered;\n /** Current step: the first visible step that has an unfulfilled requirement. */\n currentStep: CascadeStep;\n /** Total visible steps (1..7 minus any auto-skipped). */\n totalSteps: number;\n /** Ordered list of the visible step indices, used by variants that show a stepper. */\n visibleSteps: CascadeStep[];\n /** Whether every required step is satisfied — the submit button is gated on this. */\n isReadyToSubmit: boolean;\n /** Selected service's duration, if any — needed for slot fetching. */\n durationMin?: number;\n /** Selected slot resolved from `value.date` + `value.slotKey`. */\n selectedSlot?: BookingSlot;\n}\n\n/* -------------------------------------------------------------------- */\n/* Filtering helpers */\n/* -------------------------------------------------------------------- */\n\nfunction filterSpecialties(inputs: CascadeInputs): BookingSpecialty[] {\n const locked = inputs.lockedOperatorId;\n // With `operatorsByService`, a locked operator keeps every specialty that\n // groups at least one service they perform, even outside their own.\n const list = !locked\n ? inputs.specialties\n : inputs.operatorsByService\n ? inputs.specialties.filter((sp) =>\n inputs.services.some(\n (sv) =>\n sv.specialtyId === sp.id && sv.operatorIds?.includes(locked),\n ),\n )\n : inputs.specialties.filter((s) => s.operatorIds?.includes(locked));\n // Stable copy + sort by `sequenceNumber` (falsy → bottom).\n return [...list].sort((a, b) => {\n const aSeq = a.sequenceNumber ?? Number.POSITIVE_INFINITY;\n const bSeq = b.sequenceNumber ?? Number.POSITIVE_INFINITY;\n return aSeq - bSeq;\n });\n}\n\nfunction filterServices(inputs: CascadeInputs): BookingService[] {\n let list = inputs.services;\n if (inputs.lockedOperatorId) {\n list = list.filter((s) =>\n s.operatorIds?.includes(inputs.lockedOperatorId as string),\n );\n }\n // Mirror the `gates.specialty` auto-on rule — see computeGates().\n const useSpecialtiesResolved =\n inputs.useSpecialties === undefined\n ? inputs.specialties.length > 0\n : inputs.useSpecialties;\n if (useSpecialtiesResolved) {\n // 0.34.0: read array form first (`specialtyIds` for multi-select);\n // fall back to single `specialtyId`. Union semantics — show any\n // service matching ANY of the selected specialties.\n const specialtyIds = resolveSpecialtyIds(inputs.value);\n if (specialtyIds.length > 0) {\n list = list.filter(\n (s) =>\n s.specialtyId !== undefined && specialtyIds.includes(s.specialtyId),\n );\n }\n }\n return list;\n}\n\nfunction eligibleOperators(inputs: CascadeInputs): BookingOperator[] {\n // Mirror the gates.specialty auto-on rule.\n const useSpecialtiesResolved =\n inputs.useSpecialties === undefined\n ? inputs.specialties.length > 0\n : inputs.useSpecialties;\n // Eligibility follows the selected service's reverse-link when specialties\n // are off, or when `operatorsByService` says it wins over the specialty.\n // Otherwise it follows the specialty. Both are unions over the array form\n // (0.34.0), falling back to the single field.\n const serviceIds = resolveServiceIds(inputs.value);\n if (\n (!useSpecialtiesResolved || inputs.operatorsByService) &&\n serviceIds.length > 0\n ) {\n return inputs.operators.filter((op) =>\n op.appointmentBookingReasonIds?.some((rid) => serviceIds.includes(rid)),\n );\n }\n if (useSpecialtiesResolved) {\n const specialtyIds = resolveSpecialtyIds(inputs.value);\n if (specialtyIds.length > 0) {\n return inputs.operators.filter((op) =>\n op.specialtyIds?.some((sid) => specialtyIds.includes(sid)),\n );\n }\n }\n return [];\n}\n\n/* -------------------------------------------------------------------- */\n/* Gates */\n/* -------------------------------------------------------------------- */\n\nfunction computeGates(\n inputs: CascadeInputs,\n filtered: CascadeFiltered,\n): CascadeGates {\n const insuranceVisible = inputs.country === COUNTRY_GERMANY;\n // Insurance gate is satisfied either if it's not visible or the user has\n // picked one of the two values.\n const insuranceSatisfied =\n !insuranceVisible || inputs.value.insuranceType !== undefined;\n\n // Specialty visibility — 0.30.4: auto-on when `specialties` has items.\n // - `useSpecialties === true` → visible (legacy explicit opt-in)\n // - `useSpecialties === false` → hidden (explicit opt-out)\n // - `useSpecialties === undefined` (default) → visible iff `specialties`\n // has items. Previously the default `false` meant the step never\n // rendered unless the consumer explicitly opted in, which silently\n // dropped the step in every variant for the common case where the\n // consumer passed `specialties` data but not the boolean.\n const useSpecialtiesResolved =\n inputs.useSpecialties === undefined\n ? inputs.specialties.length > 0\n : inputs.useSpecialties;\n const specialtyVisible = useSpecialtiesResolved && insuranceSatisfied;\n // 0.34.0: array-or-single semantics — a step is \"satisfied\" when\n // EITHER the single field is set OR the array field has at least\n // one entry. Same applies to service / operator picks below.\n const specialtyPicked = resolveSpecialtyIds(inputs.value).length > 0;\n const specialtySatisfied = !specialtyVisible || specialtyPicked;\n\n const serviceVisible = specialtySatisfied;\n const servicePicked = resolveServiceIds(inputs.value).length > 0;\n const serviceSatisfied = !serviceVisible || servicePicked;\n\n // Operator: visible only when the user can pick from >1 eligible.\n const eligibleOps = filtered.operators;\n const operatorVisible =\n Boolean(inputs.allowOperatorSelection) &&\n serviceSatisfied &&\n servicePicked &&\n !inputs.lockedOperatorId &&\n eligibleOps.length > 1;\n // operator is always \"satisfied\" because the \"All operators\" sentinel is\n // the implicit default — patients who don't pick still flow through.\n const operatorSatisfied = true;\n void operatorSatisfied;\n\n const dateVisible = serviceSatisfied && servicePicked;\n const dateSatisfied = !dateVisible || inputs.value.date !== undefined;\n\n const slotVisible = dateSatisfied && inputs.value.date !== undefined;\n const slotSatisfied = !slotVisible || inputs.value.slotKey !== undefined;\n\n const detailsVisible = slotSatisfied && inputs.value.slotKey !== undefined;\n\n const onboardingIncomplete = servicePicked && eligibleOps.length === 0;\n\n return {\n insurance: insuranceVisible,\n specialty: specialtyVisible,\n service: serviceVisible,\n operator: operatorVisible,\n date: dateVisible,\n slot: slotVisible,\n details: detailsVisible,\n onboardingIncomplete,\n };\n}\n\n/* -------------------------------------------------------------------- */\n/* Step number derivation */\n/* -------------------------------------------------------------------- */\n\nfunction deriveStep(\n inputs: CascadeInputs,\n gates: CascadeGates,\n): { currentStep: CascadeStep; visibleSteps: CascadeStep[] } {\n const visible: CascadeStep[] = [];\n if (gates.insurance) visible.push(1);\n if (gates.specialty) visible.push(2);\n visible.push(3); // service is always required\n if (gates.operator) visible.push(4);\n visible.push(5); // date is always required (after service)\n visible.push(6); // slot is always required\n visible.push(7); // details is always required (the final submit step)\n\n const firstIncomplete = visible.find(\n (s) => !stepIsFulfilled(s, inputs.value),\n );\n return {\n currentStep: firstIncomplete ?? 7,\n visibleSteps: visible,\n };\n}\n\n/**\n * Whether `step` holds an answer the cascade can move past. The one check\n * shared by `deriveStep` and every variant body, so the two cannot drift.\n */\nexport function stepIsFulfilled(\n step: CascadeStep,\n value: BookingValue,\n): boolean {\n switch (step) {\n case 1:\n return value.insuranceType !== undefined;\n // 0.34.0: array-or-single — satisfied when EITHER form is present.\n case 2:\n return resolveSpecialtyIds(value).length > 0;\n case 3:\n return resolveServiceIds(value).length > 0;\n // Always satisfied, like its gate: \"no preference\" is a valid answer,\n // whether it is the `'all'` sentinel or an empty multi-select.\n case 4:\n return true;\n case 5:\n return value.date !== undefined;\n case 6:\n return value.slotKey !== undefined;\n // Details fulfilment is owned by the form's own validation.\n case 7:\n return false;\n }\n}\n\n/* -------------------------------------------------------------------- */\n/* Main derive */\n/* -------------------------------------------------------------------- */\n\nexport function deriveCascade(inputs: CascadeInputs): CascadeOutputs {\n const filtered: CascadeFiltered = {\n specialties: filterSpecialties(inputs),\n services: filterServices(inputs),\n operators: eligibleOperators(inputs),\n };\n const gates = computeGates(inputs, filtered);\n const { currentStep, visibleSteps } = deriveStep(inputs, gates);\n\n // Look up the selected slot for variant bodies that want to render it\n // (e.g. the \"Confirm at HH:mm on DATE\" summary line above the details\n // form). Cheaper to do here than make each variant re-search.\n let selectedSlot: BookingSlot | undefined;\n if (inputs.value.date && inputs.value.slotKey) {\n const day = inputs.availableSlots[inputs.value.date];\n if (day) selectedSlot = day.find((s) => s.key === inputs.value.slotKey);\n }\n\n // 0.34.0: when multi-select is active we resolve to \"first picked\" for\n // the duration-min / selected-service indicator. The submit payload\n // carries the full value (including arrays) so the consumer can fan\n // out per service / operator if needed.\n const serviceIds = resolveServiceIds(inputs.value);\n const selectedService =\n serviceIds.length > 0\n ? inputs.services.find((s) => s.id === serviceIds[0])\n : undefined;\n\n const specialtyPickedFinal = resolveSpecialtyIds(inputs.value).length > 0;\n\n const isReadyToSubmit =\n serviceIds.length > 0 &&\n inputs.value.date !== undefined &&\n inputs.value.slotKey !== undefined &&\n (!gates.insurance || inputs.value.insuranceType !== undefined) &&\n (!gates.specialty || specialtyPickedFinal);\n\n return {\n gates,\n filtered,\n currentStep,\n totalSteps: visibleSteps.length,\n visibleSteps,\n isReadyToSubmit,\n durationMin: selectedService?.durationMin,\n selectedSlot,\n };\n}\n\n/* -------------------------------------------------------------------- */\n/* Reset helpers — pure, return next value */\n/* */\n/* Every cascade change clears downstream selections so the user never */\n/* lands on a fulfilled-but-inconsistent state. */\n/* -------------------------------------------------------------------- */\n\nexport function resetOnInsuranceChange(\n value: BookingValue,\n next: InsuranceType | undefined,\n): BookingValue {\n return {\n ...value,\n insuranceType: next,\n specialtyId: undefined,\n serviceId: undefined,\n operatorId: undefined,\n date: undefined,\n slotKey: undefined,\n details: undefined,\n };\n}\n\nexport function resetOnSpecialtyChange(\n value: BookingValue,\n next: string | undefined,\n): BookingValue {\n return {\n ...value,\n specialtyId: next,\n specialtyIds: undefined,\n serviceId: undefined,\n serviceIds: undefined,\n operatorId: undefined,\n operatorIds: undefined,\n date: undefined,\n slotKey: undefined,\n details: undefined,\n };\n}\n\n/**\n * Multi-select counterpart to `resetOnSpecialtyChange`. Writes the\n * `specialtyIds` array form and clears any single-form `specialtyId`\n * so the cascade reads the array. Added in 0.34.0.\n */\nexport function resetOnSpecialtyIdsChange(\n value: BookingValue,\n next: string[] | undefined,\n): BookingValue {\n return {\n ...value,\n specialtyId: undefined,\n specialtyIds: next,\n serviceId: undefined,\n serviceIds: undefined,\n operatorId: undefined,\n operatorIds: undefined,\n date: undefined,\n slotKey: undefined,\n details: undefined,\n };\n}\n\nexport function resetOnServiceChange(\n value: BookingValue,\n next: string | undefined,\n): BookingValue {\n return {\n ...value,\n serviceId: next,\n serviceIds: undefined,\n // Default the operator to the \"All operators\" sentinel so a patient\n // who doesn't care about picking lands on a satisfied step 4 without\n // any further input.\n operatorId: next ? OPERATORS_ALL : undefined,\n operatorIds: undefined,\n date: undefined,\n slotKey: undefined,\n details: undefined,\n };\n}\n\n/** Multi-select counterpart to `resetOnServiceChange`. Added in 0.34.0. */\nexport function resetOnServiceIdsChange(\n value: BookingValue,\n next: string[] | undefined,\n): BookingValue {\n const hasAny = !!next && next.length > 0;\n return {\n ...value,\n serviceId: undefined,\n serviceIds: next,\n operatorId: hasAny ? OPERATORS_ALL : undefined,\n operatorIds: undefined,\n date: undefined,\n slotKey: undefined,\n details: undefined,\n };\n}\n\nexport function resetOnOperatorChange(\n value: BookingValue,\n next: string | undefined,\n): BookingValue {\n return {\n ...value,\n operatorId: next,\n operatorIds: undefined,\n date: undefined,\n slotKey: undefined,\n details: undefined,\n };\n}\n\n/** Multi-select counterpart to `resetOnOperatorChange`. Added in 0.34.0. */\nexport function resetOnOperatorIdsChange(\n value: BookingValue,\n next: string[] | undefined,\n): BookingValue {\n return {\n ...value,\n operatorId: undefined,\n operatorIds: next,\n date: undefined,\n slotKey: undefined,\n details: undefined,\n };\n}\n\n/* -------------------------------------------------------------------- */\n/* Multi-select resolution helpers — 0.34.0 */\n/* */\n/* The cascade reads the array form of each step's value first, falling */\n/* back to the single-string form. This lets the picker style switch at */\n/* runtime without rewriting the entire cascade. */\n/* -------------------------------------------------------------------- */\n\n/** Returns the effective specialty selection as an array. Empty when nothing picked. */\nexport function resolveSpecialtyIds(value: BookingValue): string[] {\n if (value.specialtyIds && value.specialtyIds.length > 0) {\n return value.specialtyIds;\n }\n if (value.specialtyId) return [value.specialtyId];\n return [];\n}\n\n/** Returns the effective service selection as an array. Empty when nothing picked. */\nexport function resolveServiceIds(value: BookingValue): string[] {\n if (value.serviceIds && value.serviceIds.length > 0) {\n return value.serviceIds;\n }\n if (value.serviceId) return [value.serviceId];\n return [];\n}\n\n/** Returns the effective operator selection as an array. Empty when nothing picked. */\nexport function resolveOperatorIds(value: BookingValue): string[] {\n if (value.operatorIds && value.operatorIds.length > 0) {\n return value.operatorIds;\n }\n if (value.operatorId) return [value.operatorId];\n return [];\n}\n\nexport function resetOnDateChange(\n value: BookingValue,\n next: string | undefined,\n): BookingValue {\n return {\n ...value,\n date: next,\n slotKey: undefined,\n // Keep details — date/slot changes shouldn't wipe the patient form\n // since the user has already filled some fields.\n };\n}\n\nexport function resetOnSlotChange(\n value: BookingValue,\n next: string | undefined,\n): BookingValue {\n return {\n ...value,\n slotKey: next,\n };\n}\n\n/* -------------------------------------------------------------------- */\n/* Auto-pre-select normalisation */\n/* */\n/* Called once on mount (and whenever the inputs that trigger them */\n/* arrive — e.g. when `specialties` populates from a fetch). Returns the */\n/* value possibly mutated with the auto-picked fields. Callers should */\n/* compare the result to the input and fire `onChange` once if they */\n/* differ so the consumer sees the normalised value. */\n/* -------------------------------------------------------------------- */\n\nexport function applyAutoSelects(\n value: BookingValue,\n inputs: CascadePolicy & {\n specialties: BookingSpecialty[];\n services: BookingService[];\n },\n): BookingValue {\n let next = value;\n\n // Rule 1: locked operator pins step 4.\n if (inputs.lockedOperatorId && next.operatorId !== inputs.lockedOperatorId) {\n next = { ...next, operatorId: inputs.lockedOperatorId };\n }\n\n // Rule 2: single specialty auto-skips step 2. Skipped when the consumer\n // is operating in multi-select mode (specialtyIds is set) — the patient\n // is explicitly picking, don't override.\n const useSpecialtiesResolved =\n inputs.useSpecialties === undefined\n ? inputs.specialties.length > 0\n : inputs.useSpecialties;\n if (\n useSpecialtiesResolved &&\n inputs.specialties.length === 1 &&\n next.specialtyId === undefined &&\n next.specialtyIds === undefined\n ) {\n next = { ...next, specialtyId: inputs.specialties[0].id };\n }\n\n // Rule 3: single resolved service auto-fills step 3 — only when explicitly\n // opted into. The spec says specialty auto-select is always on, but\n // service auto-select is opt-in because UX teams may want explicit\n // confirmation. Skipped when serviceIds is set (multi-select).\n if (inputs.autoSelectSingleService) {\n const specialtyIds = resolveSpecialtyIds(next);\n const resolvedServices =\n specialtyIds.length > 0\n ? inputs.services.filter(\n (s) => s.specialtyId && specialtyIds.includes(s.specialtyId),\n )\n : inputs.services;\n if (\n resolvedServices.length === 1 &&\n next.serviceId === undefined &&\n next.serviceIds === undefined\n ) {\n next = { ...next, serviceId: resolvedServices[0].id };\n // Mirror resetOnServiceChange's operator default.\n if (next.operatorId === undefined && next.operatorIds === undefined) {\n next = { ...next, operatorId: OPERATORS_ALL };\n }\n }\n }\n\n return next;\n}\n\n/* -------------------------------------------------------------------- */\n/* Helpers exposed for the variants (and tests). */\n/* -------------------------------------------------------------------- */\n\n/** Resolve the active operator id, treating the `'all'` sentinel as `undefined`. */\nexport function resolveOperatorId(value: BookingValue): string | undefined {\n if (!value.operatorId) return undefined;\n if (value.operatorId === OPERATORS_ALL) return undefined;\n return value.operatorId;\n}\n\n/* -------------------------------------------------------------------- */\n/* Confirmation channels — smart default + ordering */\n/* -------------------------------------------------------------------- */\n\n/**\n * Naïve E.164-ish check for the smart-default heuristic. Doesn't validate\n * the phone fully — just confirms the patient has typed *something* that\n * looks like a phone number, so we can decide whether to pre-tick WhatsApp.\n */\nfunction looksLikePhone(value: string | undefined): boolean {\n if (!value) return false;\n const trimmed = value.trim();\n // Require a leading \"+\" or country code-style digits + at least 8 chars.\n return /^\\+?\\d[\\d\\s\\-()]{6,}$/.test(trimmed);\n}\n\n/**\n * Resolve the effective list of enabled channels. Falls back to `['email']`\n * when the consumer omits the prop, preserving the pre-amendment behaviour.\n */\nexport function resolveConfirmationChannels(\n enabled: ConfirmationChannel[] | undefined,\n): ConfirmationChannel[] {\n const list = enabled && enabled.length > 0 ? enabled : ['email'];\n // Canonical order: email → whatsapp → sms.\n const set = new Set(list);\n return CONFIRMATION_CHANNEL_ORDER.filter((c) => set.has(c));\n}\n\n/** Use the selection when present, otherwise the sole enabled channel or email.\n * `enabled` must be resolved with `resolveConfirmationChannels` first. */\nexport function resolveEffectiveConfirmationChannels(\n enabled: ConfirmationChannel[],\n selection: ConfirmationChannel[] | undefined,\n): ConfirmationChannel[] {\n return selection ?? (enabled.length === 1 ? enabled : ['email']);\n}\n\n/**\n * Compute the channels to pre-check. Result is intersected with `enabled`\n * for safety so a channel the practice didn't enable never gets ticked.\n *\n * Rules (per spec):\n * 1. Always include 'email'.\n * 2. Include 'whatsapp' if enabled AND mobile looks plausible.\n * 3. Include 'sms' ONLY when whatsapp is NOT in `enabled`.\n * 4. If the consumer passes `override`, honour it verbatim (still\n * intersected with `enabled` for safety).\n */\nexport function defaultConfirmationSelection(\n enabled: ConfirmationChannel[] | undefined,\n mobile: string | undefined,\n override?: ConfirmationChannel[],\n): ConfirmationChannel[] {\n const resolvedEnabled = resolveConfirmationChannels(enabled);\n const enabledSet = new Set(resolvedEnabled);\n\n if (override) {\n return CONFIRMATION_CHANNEL_ORDER.filter(\n (c) => override.includes(c) && enabledSet.has(c),\n );\n }\n\n const out: ConfirmationChannel[] = [];\n if (enabledSet.has('email')) out.push('email');\n\n const mobilePlausible = looksLikePhone(mobile);\n const hasWhatsApp = enabledSet.has('whatsapp');\n if (hasWhatsApp && mobilePlausible) out.push('whatsapp');\n // SMS is pre-checked whenever WhatsApp is not in the enabled set —\n // the spec doesn't gate this on a mobile-present check (matches rule 3).\n if (!hasWhatsApp && enabledSet.has('sms')) out.push('sms');\n\n // Final canonical order pass.\n const outSet = new Set(out);\n return CONFIRMATION_CHANNEL_ORDER.filter((c) => outSet.has(c));\n}\n","/* -------------------------------------------------------------------- */\n/* linkifyText — practice-authored plain text → text and link segments. */\n/* */\n/* Used for a booking reason's `criticalInformationToAccept`. The string */\n/* is never parsed as HTML: markup typed into it stays literal text, and */\n/* only `http://` / `https://` URLs become links. Every other scheme */\n/* (`javascript:`, `data:`, `mailto:` …) stays text because the pattern */\n/* can only start a match on `http`. */\n/* -------------------------------------------------------------------- */\n\nexport type LinkifySegment =\n | { kind: 'text'; text: string }\n | { kind: 'link'; text: string; href: string };\n\n// Stops at whitespace, at the characters that commonly wrap a URL in prose\n// (`<https://…>`, `\"https://…\"`), and at the punctuation Arabic, Chinese\n// and Japanese text puts straight after a URL with no space: Arabic ، ؛ ؟ ۔\n// (U+060C, U+061B, U+061F, U+06D4), general punctuation (U+2000–206F, incl.\n// … and zero-width spaces), CJK punctuation (U+3000–303F, incl. 。、「」)\n// and full-width forms (U+FF00–FFEF, incl. , ) !). Without this,\n// `https://example.com。` would link to another host, because URL parsing\n// reads `。` as a dot. Letters in those scripts are not stops here, so an\n// internationalised address such as `https://例子.测试/` still links; see\n// `cutAtScriptSwitch` for prose written straight after a URL.\n//\n// A URL also ends where a second one starts right after punctuation, as in\n// `https://a.test/x,https://b.test/y`, so the two become two links.\nconst URL_PATTERN =\n /https?:\\/\\/(?:(?![.,;:!?'»›]https?:\\/\\/)[^\\s<>\"\\u060C\\u061B\\u061F\\u06D4\\u2000-\\u206F\\u3000-\\u303F\\uFF00-\\uFFEF])+/gi;\n\n// Sentence punctuation that follows a URL in prose rather than ending it.\nconst TRAILING_PUNCTUATION = new Set([\n '.',\n ',',\n ';',\n ':',\n '!',\n '?',\n \"'\",\n '»',\n '›',\n]);\n\nconst OPENERS: Record<string, string> = { ')': '(', ']': '[', '}': '{' };\n\nconst count = (text: string, char: string) => text.split(char).length - 1;\n\n/**\n * Trims what prose puts after a URL: a full stop, a comma, or a closing\n * bracket that has no opening partner inside the URL. A balanced one, as\n * in `https://en.wikipedia.org/wiki/Foo_(bar)`, stays. One pass from the\n * end, so a long run of brackets costs linear time.\n */\nfunction trimUrl(raw: string): string {\n const surplus: Record<string, number> = {};\n for (const [closer, opener] of Object.entries(OPENERS)) {\n surplus[closer] = count(raw, closer) - count(raw, opener);\n }\n let end = raw.length;\n while (end > 0) {\n const last = raw[end - 1];\n if (TRAILING_PUNCTUATION.has(last)) {\n end -= 1;\n } else if (last in surplus && surplus[last] > 0) {\n surplus[last] -= 1;\n end -= 1;\n } else {\n break;\n }\n }\n return raw.slice(0, end);\n}\n\n// Letters of scripts that run on after a URL with no space: Arabic,\n// Japanese kana, CJK ideographs and Hangul.\nconst NON_LATIN_LETTER =\n /[\\u0600-\\u06FF\\u3040-\\u30FF\\u3400-\\u9FFF\\uAC00-\\uD7AF]/;\nconst ASCII_ALNUM = /[A-Za-z0-9]/;\n\n/**\n * Ends an all-Latin URL where such a letter follows a Latin letter or\n * digit, as in `https://example.com/privacyをお読みください`: that is prose\n * starting, not the address going on. Only the first such letter counts.\n * Once one appears after `/`, `.` or `://`, the address is itself\n * internationalised (`https://例子.测试/`, `https://例子123测试.com/`) and\n * no later switch cuts it.\n */\nfunction cutAtScriptSwitch(raw: string): string {\n const first = raw.search(NON_LATIN_LETTER);\n return first > 0 && ASCII_ALNUM.test(raw[first - 1])\n ? raw.slice(0, first)\n : raw;\n}\n\nfunction isHttpUrl(candidate: string): boolean {\n try {\n const { protocol, hostname } = new URL(candidate);\n return (protocol === 'http:' || protocol === 'https:') && hostname !== '';\n } catch {\n return false;\n }\n}\n\n/** Splits `text` into literal text and http(s) link segments, in order. */\nexport function linkifyText(text: string): LinkifySegment[] {\n const segments: LinkifySegment[] = [];\n let cursor = 0;\n const pushText = (value: string) => {\n if (value === '') return;\n const previous = segments[segments.length - 1];\n if (previous?.kind === 'text') previous.text += value;\n else segments.push({ kind: 'text', text: value });\n };\n for (const match of text.matchAll(URL_PATTERN)) {\n const start = match.index ?? 0;\n const url = trimUrl(cutAtScriptSwitch(match[0]));\n if (!isHttpUrl(url)) continue;\n pushText(text.slice(cursor, start));\n segments.push({ kind: 'link', text: url, href: url });\n cursor = start + url.length;\n }\n pushText(text.slice(cursor));\n return segments;\n}\n","import {\n Fragment,\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type FormEvent,\n type ReactNode,\n} from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Trans } from 'react-i18next';\nimport { cva } from 'class-variance-authority';\nimport { CreditCard } from 'lucide-react';\nimport { Alert } from '../alert/alert';\nimport { Button } from '../button/button';\nimport { Checkbox } from '../checkbox/checkbox';\nimport { CheckboxGroup } from '../checkbox-group/checkbox-group';\nimport { Radio } from '../radio-group/radio';\nimport { RadioGroup } from '../radio-group/radio-group';\nimport { DatePicker } from '../date-picker/date-picker';\nimport { EmailInput } from '../email-input/email-input';\nimport { FormField } from '../form-field/form-field';\nimport { PhoneInput } from '../phone-input/phone-input';\nimport { TextArea } from '../text-area/text-area';\nimport { TextInput } from '../text-input/text-input';\nimport { AddressFields } from '../address-fields/address-fields';\nimport type { StructuredAddress } from '../address-autocomplete';\nimport { Spinner } from '../spinner/spinner';\nimport { formatPrice } from '../_shared/format-price';\nimport {\n defaultConfirmationSelection,\n resolveConfirmationChannels,\n resolveEffectiveConfirmationChannels,\n} from './cascade';\nimport { linkifyText } from './linkify';\nimport type {\n BookingBillingDetails,\n BookingDetails,\n BookingPracticeConsent,\n BookingResolvedPayment,\n BookingValidator,\n ConfirmationChannel,\n} from './booking-types';\n\n/* -------------------------------------------------------------------- */\n/* BookingDetailsForm — step 7 of the cascade. */\n/* */\n/* Captures the patient's identity + contact + consents before submit. */\n/* The form's `onChange` fires per-field so the parent value can persist */\n/* a partial across step navigation; the parent's `onSubmit` is called */\n/* with the full `BookingDetails` payload only when every required field */\n/* + both consents validate. */\n/* -------------------------------------------------------------------- */\n\nconst NOTE_MAX_LENGTH = 500;\nconst CF_REGEX = /^[A-Z0-9]{16}$/;\nconst EMAIL_REGEX = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\nconst VALIDATE_DEBOUNCE_MS = 300;\n\n// Inline links in the consents and the information to accept. Text colour\n// plus underline: `--primary` falls below AA on the dark themes, and\n// `--link` below the accessible themes' 7:1 on the elevated card.\nconst CONSENT_LINK_CLASSES =\n 'ds:rounded-[var(--radius-sm)] ds:underline ds:text-[var(--foreground)] ds:focus-visible:outline-solid ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-[var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]';\n\n// Only http(s) URLs reach an `href`: `javascript:` / `data:` URIs and\n// relative paths are dropped, and the text around them stays plain.\nconst safeHttpUrl = (url: string | null | undefined) =>\n url && /^https?:\\/\\//i.test(url) ? url : undefined;\n\n/* The billing address as AddressFields edits it, and back. The country\n starts on the practice's own when the patient has not chosen one. */\nconst toStructured = (\n billing: BookingBillingDetails | undefined,\n fallbackCountry: string,\n): StructuredAddress => ({\n street: billing?.address.line1 ?? '',\n city: billing?.address.city ?? '',\n postcode: billing?.address.postalCode ?? '',\n province: billing?.address.state ?? '',\n // The practice's country only until the patient has an address at all.\n country: (billing ? billing.address.country : fallbackCountry).toLowerCase(),\n formatted: '',\n});\nconst fromStructured = (\n address: StructuredAddress,\n name: string,\n /** The form has no second line: one the host gave is carried through\n * for as long as its street stands. */\n line2: string | null = null,\n): BookingBillingDetails => ({\n name,\n address: {\n line1: address.street,\n line2,\n city: address.city,\n state: address.province,\n postalCode: address.postcode,\n country: address.country.toUpperCase(),\n },\n});\n/* The payment notice: the tinted card with an icon and the amount, or the\n plain grey card, which a host can still ask for. */\nconst paymentNoticeVariants = cva('ds:flex ds:flex-col ds:border', {\n variants: {\n noticeStyle: {\n plain:\n 'ds:gap-[var(--spacing-xs)] ds:rounded-[var(--radius-md)] ds:border-[var(--border)] ds:bg-[var(--muted)] ds:p-[var(--spacing-sm)]',\n highlighted:\n 'ds:gap-[var(--spacing-sm)] ds:rounded-[var(--radius-lg)] ds:border-[color-mix(in_srgb,var(--primary)_30%,var(--border))] ds:bg-[color-mix(in_srgb,var(--primary)_8%,var(--card))] ds:p-[var(--spacing-md)]',\n },\n },\n defaultVariants: { noticeStyle: 'highlighted' },\n});\n/* Floated to the top of the billing country list. */\nconst BILLING_COUNTRIES = ['it', 'ch', 'de', 'at', 'fr', 'sm'];\n/* The `touched` key of each billing field. */\nconst BILLING_FIELDS = {\n country: 'billing.country',\n street: 'billing.street',\n city: 'billing.city',\n postcode: 'billing.postcode',\n province: 'billing.province',\n} as const;\nconst ITALIAN_POSTCODE = /^\\d{5}$/;\n/* Street, city, postcode and country always. For Italy, also a province\n and a five-digit CAP, the rule the postcode field itself shows. */\nconst billingComplete = (billing: BookingBillingDetails | undefined) => {\n if (!billing) return false;\n const { line1, city, postalCode, country, state } = billing.address;\n if (!line1.trim() || !city.trim() || !postalCode.trim() || !country.trim())\n return false;\n if (country.toUpperCase() !== 'IT') return true;\n return Boolean(state.trim()) && ITALIAN_POSTCODE.test(postalCode.trim());\n};\n/* What the host receives: trimmed, with the country in upper case. */\nconst normaliseBilling = (\n billing: BookingBillingDetails,\n name: string,\n): BookingBillingDetails => ({\n name,\n address: {\n line1: billing.address.line1.trim(),\n line2: billing.address.line2?.trim() || null,\n city: billing.address.city.trim(),\n state: billing.address.state.trim(),\n postalCode: billing.address.postalCode.trim(),\n country: billing.address.country.trim().toUpperCase(),\n },\n});\n\n/* -------------------------------------------------------------------- */\n/* Props */\n/* -------------------------------------------------------------------- */\n\nexport interface BookingDetailsFormProps {\n value: Partial<BookingDetails>;\n onChange: (next: Partial<BookingDetails>) => void;\n onSubmit: (details: BookingDetails) => void | Promise<void>;\n\n // Opt-in fields\n /** Hide email, skip its validation and omit it from submission. Default: false. */\n hideEmail?: boolean;\n /** Keep email optional unless used for confirmation; `hideEmail` wins. Default: false. */\n emailOptional?: boolean;\n requireCodiceFiscale?: boolean;\n requireDateOfBirth?: boolean;\n /** When `true` AND `insuranceType === 'public'`, render the Versichertennummer field. */\n requireInsuranceNumber?: boolean;\n insuranceType?: 'private' | 'public';\n showNote?: boolean;\n showReturningPatientFlag?: boolean;\n\n // Consent labels\n privacyPolicyUrl?: string;\n termsUrl?: string;\n /**\n * The practice's own privacy notice or terms checkbox, rendered after the\n * AlfaDocs ones. `null`, `undefined` or a blank label render nothing.\n */\n practiceConsent?: BookingPracticeConsent | null;\n payment?: BookingResolvedPayment;\n paymentTermsUrl?: string;\n /** Prevent submit when the selected service's payment cannot be resolved. */\n paymentBlocked?: boolean;\n /** Collect the billing address here for a paid service. The fiscal code,\n * when `requireCodiceFiscale` asks for one, moves into the same block. */\n billingInDetails?: boolean;\n /** How the payment notice looks. See `BookingProps.paymentNoticeStyle`. */\n paymentNoticeStyle?: 'plain' | 'highlighted';\n\n /**\n * The selected service's `criticalInformationToAccept`. When set (and not\n * blank), a \"Before you book\" block renders above the consents and the\n * patient must tick its checkbox before submit enables. Rendered as\n * plain text — never parsed as HTML — except that `http(s)` URLs in it\n * become links.\n */\n criticalInformationToAccept?: string;\n\n // Validation hooks\n validateCodiceFiscale?: BookingValidator;\n validateInsuranceNumber?: BookingValidator;\n\n // UX\n submitting?: boolean;\n /** Optional summary node rendered above the form (e.g. confirm-time chip). */\n summarySlot?: ReactNode;\n\n // Phone country default — propagated from the practice country code so\n // the country prefix selector starts on the right option.\n defaultPhoneCountry?: string;\n\n // Confirmation-channel picker (sub-section of step 7)\n /**\n * Channels the practice has enabled. When omitted, defaults to\n * `['email']` (picker hidden — single implicit channel). When the\n * resolved list has length 1 the picker stays hidden.\n */\n confirmationChannels?: ConfirmationChannel[];\n /** Pre-checked channels override; falls back to a smart default. */\n defaultConfirmationChannels?: ConfirmationChannel[];\n /** One channel only, picked with radios. See `BookingProps`. */\n singleConfirmationChannel?: boolean;\n /**\n * Render an error Alert above the submit button. Set after an\n * `onSubmit` rejection, clear before retrying. The kit doesn't\n * disable the submit button while this is set — the patient can\n * re-submit immediately.\n */\n submitError?: ReactNode;\n /** Read-only review while a code step is open: no alert, hint or submit button. */\n locked?: boolean;\n}\n\n/* -------------------------------------------------------------------- */\n/* Component */\n/* -------------------------------------------------------------------- */\n\ninterface AsyncStatus {\n state: 'idle' | 'pending' | 'valid' | 'invalid';\n hint?: string;\n value?: string;\n}\n\nconst idleStatus: AsyncStatus = { state: 'idle' };\n\n/* The fields a refused submit reveals at once, each with its own message:\n the patient's own, then the billing block's by their `touched` key. */\nconst SUBMIT_REVEALED = [\n 'firstName',\n 'lastName',\n 'email',\n 'mobilePhone',\n 'codiceFiscale',\n 'dateOfBirth',\n 'insuranceNumber',\n BILLING_FIELDS.country,\n BILLING_FIELDS.street,\n BILLING_FIELDS.city,\n BILLING_FIELDS.postcode,\n BILLING_FIELDS.province,\n] as const;\ntype RevealedField = (typeof SUBMIT_REVEALED)[number];\nconst NONE_QUIET: ReadonlySet<RevealedField> = new Set();\n\nexport const BookingDetailsForm = forwardRef<\n HTMLFormElement,\n BookingDetailsFormProps\n>(\n (\n {\n value,\n onChange,\n onSubmit,\n hideEmail = false,\n emailOptional = false,\n requireCodiceFiscale = false,\n requireDateOfBirth = false,\n requireInsuranceNumber = false,\n insuranceType,\n showNote = false,\n showReturningPatientFlag = false,\n privacyPolicyUrl,\n termsUrl,\n practiceConsent,\n payment,\n paymentTermsUrl,\n paymentBlocked = false,\n billingInDetails = false,\n paymentNoticeStyle = 'highlighted',\n criticalInformationToAccept,\n validateCodiceFiscale,\n validateInsuranceNumber,\n submitting = false,\n locked = false,\n summarySlot,\n defaultPhoneCountry,\n confirmationChannels,\n defaultConfirmationChannels,\n singleConfirmationChannel = false,\n submitError,\n },\n ref,\n ) => {\n const { t, i18n } = useTranslation('ui');\n const formId = useId();\n const formElement = useRef<HTMLFormElement | null>(null);\n const setFormElement = useCallback(\n (node: HTMLFormElement | null) => {\n formElement.current = node;\n if (typeof ref === 'function') ref(node);\n else if (ref) ref.current = node;\n },\n [ref],\n );\n /* A submit that was refused moves focus to the first thing missing: a\n field in error, or a required box not yet ticked. */\n const [revealTick, setRevealTick] = useState(0);\n useEffect(() => {\n if (revealTick === 0) return;\n const gaps = formElement.current?.querySelectorAll<HTMLElement>(\n '[aria-invalid=\"true\"], [role=\"checkbox\"][aria-required=\"true\"][aria-checked=\"false\"], [data-unanswered] [role=\"checkbox\"]',\n );\n // A group can be marked invalid without taking focus itself: the\n // first gap that accepts focus wins.\n for (const gap of gaps ?? []) {\n gap.focus();\n if (document.activeElement === gap) return;\n }\n }, [revealTick]);\n const inFlight = useRef(false);\n const [pending, setPending] = useState(false);\n const [submissionFailed, setSubmissionFailed] = useState(false);\n const busy = submitting || pending;\n\n // Async-validation state per field.\n const [cfStatus, setCfStatus] = useState<AsyncStatus>(idleStatus);\n const [insuranceStatus, setInsuranceStatus] =\n useState<AsyncStatus>(idleStatus);\n\n // Show-validation-error toggle — flips on first blur / submit attempt\n // so the inline errors don't shout at the user mid-typing.\n const [touched, setTouched] = useState<Record<string, boolean>>({});\n const markTouched = useCallback(\n (field: string) => setTouched((t) => ({ ...t, [field]: true })),\n [],\n );\n /* The messages a refused submit revealed. They stay quiet: focus goes\n to the first gap, whose message is read with it, and the rest wait to\n be reached instead of all being announced at once. A field leaves the\n set once its message goes, so a later mistake there is announced. */\n const [quiet, setQuiet] = useState(NONE_QUIET);\n\n // Per-field debounce timers for the async validators.\n const cfTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const insuranceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(\n null,\n );\n\n useEffect(\n () => () => {\n if (cfTimerRef.current) clearTimeout(cfTimerRef.current);\n if (insuranceTimerRef.current) clearTimeout(insuranceTimerRef.current);\n },\n [],\n );\n\n /* -------------------------- Mutators ---------------------------- */\n\n const update = useCallback(\n (patch: Partial<BookingDetails>) => {\n // A failure alert describes the attempt just made, not an edited one.\n setSubmissionFailed(false);\n onChange({ ...value, ...patch });\n },\n [value, onChange],\n );\n\n const paymentKey = payment\n ? JSON.stringify([\n payment.serviceId,\n payment.kind,\n payment.amountCents,\n payment.currencyCode,\n paymentTermsUrl,\n ])\n : undefined;\n const [acceptedPaymentKey, setAcceptedPaymentKey] = useState(() =>\n value.paymentAccepted ? paymentKey : undefined,\n );\n const previousPaymentKey = useRef(paymentKey);\n const paymentAccepted = Boolean(\n payment && value.paymentAccepted && acceptedPaymentKey === paymentKey,\n );\n useEffect(() => {\n if (previousPaymentKey.current === paymentKey) return;\n previousPaymentKey.current = paymentKey;\n setAcceptedPaymentKey(undefined);\n if (value.paymentAccepted !== undefined) {\n update({ paymentAccepted: payment ? false : undefined });\n }\n }, [paymentKey, payment, update, value.paymentAccepted]);\n\n // The practice's own box. A blank label shows nothing, as the practice\n // API does for empty text; the type check covers an untyped host\n // passing `label: null`.\n const practiceConsentShown =\n typeof practiceConsent?.label === 'string' &&\n practiceConsent.label.trim() !== '';\n // A tick belongs to the exact text, link and flag it was given for. The\n // server stores that snapshot, so a changed notice needs a fresh tick,\n // as a changed payment quote does above.\n const practiceConsentKey =\n practiceConsent && practiceConsentShown\n ? JSON.stringify([\n practiceConsent.label,\n practiceConsent.url ?? null,\n practiceConsent.required,\n ])\n : undefined;\n const [acceptedPracticeConsentKey, setAcceptedPracticeConsentKey] =\n useState(() =>\n value.practiceConsentAccepted ? practiceConsentKey : undefined,\n );\n const previousPracticeConsentKey = useRef(practiceConsentKey);\n const practiceConsentAccepted = Boolean(\n practiceConsentKey !== undefined &&\n value.practiceConsentAccepted &&\n acceptedPracticeConsentKey === practiceConsentKey,\n );\n useEffect(() => {\n if (previousPracticeConsentKey.current === practiceConsentKey) return;\n previousPracticeConsentKey.current = practiceConsentKey;\n setAcceptedPracticeConsentKey(undefined);\n if (value.practiceConsentAccepted !== undefined) {\n update({ practiceConsentAccepted: undefined });\n }\n }, [practiceConsentKey, update, value.practiceConsentAccepted]);\n const paymentAmount = payment\n ? formatPrice(payment.amountCents, payment.currencyCode, i18n.language)\n : '';\n const safePaymentTermsUrl = safeHttpUrl(paymentTermsUrl);\n\n /* A paid service with billingInDetails asks for the receipt's address\n here, so the host can open the hold and the payment in one call. The\n fiscal code stays the host's call (requireCodiceFiscale): when it is\n asked, it moves into the billing block, so it is asked once. */\n const collectBilling =\n billingInDetails && Boolean(payment) && !paymentBlocked;\n const cfRequired = requireCodiceFiscale;\n const billingCountry = (defaultPhoneCountry || 'it').toLowerCase();\n const billingValid = !collectBilling || billingComplete(value.billing);\n const billingAddress = toStructured(value.billing, billingCountry);\n // Only Italy has a province list; elsewhere the field is left out.\n const billingInItaly = billingAddress.country === 'it';\n const billingRef = useRef<HTMLDivElement>(null);\n /* The form has no second-line field, so a second line the host gave is\n remembered with the street it came with: it leaves when the patient\n writes another street and comes back if they restore the first one.\n A host that clears it on the same street has taken it away. */\n const secondLineRef = useRef<{ street: string; line2: string } | null>(\n null,\n );\n const billingLine1 = value.billing?.address.line1.trim();\n const billingLine2 = value.billing?.address.line2?.trim() || null;\n useEffect(() => {\n if (billingLine1 !== undefined && billingLine2) {\n secondLineRef.current = { street: billingLine1, line2: billingLine2 };\n } else if (\n billingLine1 === undefined ||\n billingLine1 === secondLineRef.current?.street\n ) {\n secondLineRef.current = null;\n }\n }, [billingLine1, billingLine2]);\n const billingError = (\n key: keyof typeof BILLING_FIELDS,\n ): string | undefined =>\n // Nothing for a block not shown, nor for a province outside Italy.\n !collectBilling ||\n !touched[BILLING_FIELDS[key]] ||\n (key === 'province' && !billingInItaly)\n ? undefined\n : !billingAddress[key].trim()\n ? t('booking.details.fieldRequired')\n : // The one format the block itself checks: an Italian CAP.\n key === 'postcode' &&\n billingInItaly &&\n !ITALIAN_POSTCODE.test(billingAddress.postcode.trim())\n ? t('inputs.postalCode.invalid')\n : undefined;\n /* Once focus moves past the block, every gap in it is shown: the\n submit button is disabled while one is left, and says nothing. */\n const markBillingTouched = useCallback(\n () =>\n setTouched((current) =>\n current[BILLING_FIELDS.province]\n ? current\n : {\n ...current,\n codiceFiscale: true,\n ...Object.fromEntries(\n Object.values(BILLING_FIELDS).map((key) => [key, true]),\n ),\n },\n ),\n [],\n );\n\n /* -------------------- Confirmation-channel picker ---------------- */\n\n const resolvedEnabledChannels = useMemo(\n () => resolveConfirmationChannels(confirmationChannels),\n [confirmationChannels],\n );\n const pickerVisible =\n !payment && !paymentBlocked && resolvedEnabledChannels.length >= 2;\n\n // Smart-default the selection once on mount (and whenever the inputs\n // that drive it change — `mobilePhone` toggles WhatsApp eligibility).\n // We only seed when the parent value is undefined so the patient's own\n // changes win.\n const seededRef = useRef(false);\n useEffect(() => {\n // Preserve the patient's choices for a later non-payment service;\n // payment submissions omit them and never request confirmation links.\n if (payment || paymentBlocked) return;\n if (!pickerVisible) {\n // Implicit single channel — strip any stale selection.\n if (value.confirmationChannels !== undefined) {\n update({ confirmationChannels: undefined });\n }\n return;\n }\n if (value.confirmationChannels !== undefined) {\n seededRef.current = true;\n // One channel only: keep the first of a selection made with checkboxes.\n if (\n singleConfirmationChannel &&\n value.confirmationChannels.length > 1\n ) {\n update({\n confirmationChannels: value.confirmationChannels.slice(0, 1),\n });\n }\n return;\n }\n const seed = singleConfirmationChannel\n ? [\n defaultConfirmationChannels?.find((c) =>\n resolvedEnabledChannels.includes(c),\n ) ?? resolvedEnabledChannels[0],\n ]\n : defaultConfirmationSelection(\n resolvedEnabledChannels,\n value.mobilePhone,\n defaultConfirmationChannels,\n );\n seededRef.current = true;\n update({ confirmationChannels: seed });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n pickerVisible,\n payment,\n paymentBlocked,\n resolvedEnabledChannels,\n value.mobilePhone,\n defaultConfirmationChannels,\n singleConfirmationChannel,\n ]);\n\n const selectedChannels = useMemo<ConfirmationChannel[]>(\n () => value.confirmationChannels ?? [],\n [value.confirmationChannels],\n );\n const noChannelsSelected = pickerVisible && selectedChannels.length === 0;\n // Hidden pickers omit the selection from submission, even if stored.\n const effectiveChannels = resolveEffectiveConfirmationChannels(\n resolvedEnabledChannels,\n pickerVisible ? selectedChannels : undefined,\n );\n // Email delivery needs an address, including the implicit email default.\n const emailRequired = !emailOptional || effectiveChannels.includes('email');\n\n /* -------------------------- CF async ---------------------------- */\n\n /* The validators are read through refs: a host that passes an inline\n function gives a new one on every render, and restarting on that\n would re-validate the fiscal code each time another field changes. */\n const validateCodiceFiscaleRef = useRef(validateCodiceFiscale);\n const validateInsuranceNumberRef = useRef(validateInsuranceNumber);\n useEffect(() => {\n validateCodiceFiscaleRef.current = validateCodiceFiscale;\n validateInsuranceNumberRef.current = validateInsuranceNumber;\n }, [validateCodiceFiscale, validateInsuranceNumber]);\n const hasCfValidator = Boolean(validateCodiceFiscale);\n const hasInsuranceValidator = Boolean(validateInsuranceNumber);\n\n useEffect(() => {\n const cf = value.codiceFiscale;\n if (!cfRequired || !hasCfValidator || !cf) {\n setCfStatus(idleStatus);\n return;\n }\n if (!CF_REGEX.test(cf)) {\n // Don't fire the async validator until the format is plausible.\n setCfStatus({\n state: 'invalid',\n hint: t('booking.details.codiceFiscale.invalidFormat'),\n });\n return;\n }\n setCfStatus({ state: 'pending' });\n let active = true;\n if (cfTimerRef.current) clearTimeout(cfTimerRef.current);\n cfTimerRef.current = setTimeout(async () => {\n try {\n const validate = validateCodiceFiscaleRef.current;\n if (!validate) return;\n const res = await validate(cf);\n if (active) {\n setCfStatus({\n state: res.valid ? 'valid' : 'invalid',\n hint: res.hint,\n value: cf,\n });\n }\n } catch {\n if (active) {\n setCfStatus({\n state: 'invalid',\n hint: t('booking.details.codiceFiscale.unavailable'),\n value: cf,\n });\n }\n }\n }, VALIDATE_DEBOUNCE_MS);\n return () => {\n active = false;\n if (cfTimerRef.current) clearTimeout(cfTimerRef.current);\n };\n }, [cfRequired, hasCfValidator, value.codiceFiscale, t]);\n\n /* ----------------------- Insurance async ------------------------ */\n\n const insuranceShown = requireInsuranceNumber && insuranceType === 'public';\n useEffect(() => {\n const n = value.insuranceNumber;\n if (!insuranceShown || !hasInsuranceValidator || !n) {\n setInsuranceStatus(idleStatus);\n return;\n }\n setInsuranceStatus({ state: 'pending' });\n if (insuranceTimerRef.current) clearTimeout(insuranceTimerRef.current);\n insuranceTimerRef.current = setTimeout(() => {\n const validate = validateInsuranceNumberRef.current;\n if (!validate) return;\n validate(n)\n .then((res) =>\n setInsuranceStatus(\n res.valid\n ? { state: 'valid' }\n : { state: 'invalid', hint: res.hint },\n ),\n )\n .catch(() =>\n setInsuranceStatus({\n state: 'invalid',\n hint: t('booking.details.insuranceNumber.unavailable'),\n }),\n );\n }, VALIDATE_DEBOUNCE_MS);\n }, [insuranceShown, hasInsuranceValidator, value.insuranceNumber, t]);\n\n /* ------------------------- Validation --------------------------- */\n\n const emailValid = useMemo(() => {\n if (hideEmail) return true;\n const email = emailOptional ? value.email?.trim() : value.email;\n if (!emailRequired && !email) return true;\n return Boolean(email && EMAIL_REGEX.test(email));\n }, [hideEmail, emailOptional, emailRequired, value.email]);\n const phoneValid = useMemo(\n () => Boolean(value.mobilePhone && value.mobilePhone.length >= 6),\n [value.mobilePhone],\n );\n\n const requiredFieldsValid = useMemo(() => {\n if (!value.firstName?.trim()) return false;\n if (!value.lastName?.trim()) return false;\n if (!emailValid) return false;\n if (!phoneValid) return false;\n if (\n cfRequired &&\n (cfStatus.state !== 'valid' || cfStatus.value !== value.codiceFiscale)\n )\n return false;\n if (!billingValid) return false;\n if (requireDateOfBirth && !value.dateOfBirth) return false;\n if (insuranceShown && insuranceStatus.state !== 'valid') return false;\n return true;\n }, [\n value.firstName,\n value.lastName,\n emailValid,\n phoneValid,\n cfRequired,\n billingValid,\n cfStatus.state,\n cfStatus.value,\n value.codiceFiscale,\n requireDateOfBirth,\n value.dateOfBirth,\n insuranceShown,\n insuranceStatus.state,\n ]);\n\n // Blank text adds no step — only a non-empty string gates submit.\n const criticalInformation = criticalInformationToAccept?.trim()\n ? criticalInformationToAccept\n : undefined;\n const criticalInformationRequired = criticalInformation !== undefined;\n const criticalInformationTicked =\n !criticalInformationRequired ||\n Boolean(value.criticalInformationAccepted);\n const practiceConsentTicked =\n !practiceConsentShown ||\n !practiceConsent?.required ||\n practiceConsentAccepted;\n const consentsTicked = Boolean(\n value.privacyConsent &&\n value.termsConsent &&\n criticalInformationTicked &&\n practiceConsentTicked,\n );\n const channelsSatisfied = !pickerVisible || selectedChannels.length > 0;\n const canSubmit =\n requiredFieldsValid &&\n consentsTicked &&\n channelsSatisfied &&\n (!payment || paymentAccepted) &&\n !paymentBlocked &&\n !busy;\n // The button looks unavailable only because of something the patient\n // can still do.\n const waitingOnPatient = !canSubmit && !busy && !paymentBlocked;\n const submitHintId = `${formId}-submit-hint`;\n\n /* Each field's message, once it is due. */\n const fieldErrors: Record<RevealedField, string | undefined> = {\n firstName:\n touched.firstName && !value.firstName?.trim()\n ? t('booking.details.firstName.required')\n : undefined,\n lastName:\n touched.lastName && !value.lastName?.trim()\n ? t('booking.details.lastName.required')\n : undefined,\n email:\n !hideEmail && touched.email && !emailValid\n ? t('booking.details.email.invalid')\n : undefined,\n mobilePhone:\n touched.mobilePhone && !phoneValid\n ? t('booking.details.mobilePhone.invalid')\n : undefined,\n codiceFiscale:\n touched.codiceFiscale && cfStatus.state === 'invalid'\n ? (cfStatus.hint ?? t('booking.details.codiceFiscale.invalid'))\n : touched.codiceFiscale && !value.codiceFiscale\n ? t('booking.details.fieldRequired')\n : undefined,\n dateOfBirth:\n touched.dateOfBirth && !value.dateOfBirth\n ? t('booking.details.dateOfBirth.required')\n : undefined,\n insuranceNumber:\n touched.insuranceNumber && insuranceStatus.state === 'invalid'\n ? (insuranceStatus.hint ??\n t('booking.details.insuranceNumber.invalid'))\n : undefined,\n [BILLING_FIELDS.country]: billingError('country'),\n [BILLING_FIELDS.street]: billingError('street'),\n [BILLING_FIELDS.city]: billingError('city'),\n [BILLING_FIELDS.postcode]: billingError('postcode'),\n [BILLING_FIELDS.province]: billingError('province'),\n };\n // A quiet field whose message has gone leaves the set. Done while\n // rendering, so the same commit that removes the message also frees\n // the field.\n const stillQuiet = SUBMIT_REVEALED.filter(\n (field) => quiet.has(field) && fieldErrors[field] !== undefined,\n );\n if (stillQuiet.length !== quiet.size) setQuiet(new Set(stillQuiet));\n const announce = (field: RevealedField) => !quiet.has(field);\n\n /* --------------------------- Submit ----------------------------- */\n\n const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {\n e.preventDefault();\n if (!busy && !inFlight.current && !canSubmit) {\n // Every message not yet shown appears now, quietly: see `quiet`.\n setQuiet(\n new Set(\n SUBMIT_REVEALED.filter(\n (field) => quiet.has(field) || !fieldErrors[field],\n ),\n ),\n );\n }\n // Surface every validation error on submit attempt.\n setTouched({\n firstName: true,\n lastName: true,\n email: !hideEmail,\n mobilePhone: true,\n codiceFiscale: true,\n dateOfBirth: true,\n insuranceNumber: true,\n ...Object.fromEntries(\n Object.values(BILLING_FIELDS).map((key) => [key, true]),\n ),\n });\n if (busy || inFlight.current) return;\n if (!canSubmit) {\n // The button looks disabled but still answers: show what is missing.\n setRevealTick((tick) => tick + 1);\n return;\n }\n const payload: BookingDetails = {\n firstName: value.firstName!.trim(),\n lastName: value.lastName!.trim(),\n ...(!hideEmail && value.email?.trim()\n ? { email: value.email.trim() }\n : {}),\n mobilePhone: value.mobilePhone!,\n privacyConsent: true,\n termsConsent: true,\n // Only present when the service carried text to accept — a\n // reason without it leaves the key out of the payload entirely.\n ...(criticalInformationRequired\n ? { criticalInformationAccepted: true }\n : {}),\n // Sent whenever the practice's box is shown, ticked or not, so the\n // server can record the answer; left out when there is no box.\n ...(practiceConsentShown ? { practiceConsentAccepted } : {}),\n ...(payment ? { paymentAccepted: true } : {}),\n codiceFiscale: value.codiceFiscale,\n dateOfBirth: value.dateOfBirth,\n insuranceNumber: value.insuranceNumber,\n note: value.note,\n returningPatient: value.returningPatient,\n // Only include when the picker was visible; otherwise the single\n // implicit channel is inferred backend-side from the practice\n // config.\n confirmationChannels: pickerVisible ? selectedChannels : undefined,\n ...(collectBilling && value.billing\n ? {\n billing: normaliseBilling(\n value.billing,\n `${value.firstName!.trim()} ${value.lastName!.trim()}`,\n ),\n }\n : {}),\n };\n inFlight.current = true;\n setPending(true);\n setSubmissionFailed(false);\n try {\n await onSubmit(payload);\n } catch {\n // The form owns this event promise. Keep details mounted for retry.\n setSubmissionFailed(true);\n } finally {\n inFlight.current = false;\n setPending(false);\n }\n };\n\n /* The fiscal code field: with the identity fields, or in the billing\n block when billing is collected here. */\n const codiceFiscaleField = (\n <FormField\n label={t('booking.details.codiceFiscale.label')}\n required\n description={\n cfStatus.state === 'pending'\n ? t('booking.details.codiceFiscale.checking')\n : t('booking.details.codiceFiscale.helper')\n }\n error={fieldErrors.codiceFiscale}\n announceError={announce('codiceFiscale')}\n >\n <TextInput\n value={value.codiceFiscale ?? ''}\n maxLength={16}\n onChange={(e) =>\n update({\n codiceFiscale: e.target.value.slice(0, 16).toUpperCase(),\n })\n }\n onBlur={() => markTouched('codiceFiscale')}\n />\n </FormField>\n );\n\n /* ---------------------- Consent label JSX ----------------------- */\n\n // Translated label with an embedded link to the policy URL. Uses\n // <Trans> so the link target is bound at render rather than baked\n // into the localised string.\n const renderConsentLabel = (\n i18nKey: string,\n url: string | undefined,\n ): ReactNode => {\n // Strip the link if the URL isn't http(s) — guards against\n // `javascript:` / `data:` URIs reaching the rendered `href`.\n const safeUrl = safeHttpUrl(url);\n if (!safeUrl) {\n return t(i18nKey);\n }\n return (\n <Trans\n ns=\"ui\"\n i18nKey={i18nKey}\n components={{\n // The `<Trans>` runtime injects link text from the i18n\n // string. The anchor renders empty at static-analysis time,\n // so `jsx-a11y/anchor-has-content` would false-flag — silence\n // it; the runtime content is the localised policy / terms\n // label.\n policyLink: (\n // eslint-disable-next-line jsx-a11y/anchor-has-content\n <a\n href={safeUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={CONSENT_LINK_CLASSES}\n />\n ),\n }}\n />\n );\n };\n\n return (\n <form\n ref={setFormElement}\n id={formId}\n noValidate\n onSubmit={handleSubmit}\n onFocus={(event) => {\n const block = billingRef.current;\n // A list opened from a field lives outside the form: not \"past\".\n if (!block || !event.currentTarget.contains(event.target)) return;\n if (\n !block.contains(event.target) &&\n block.compareDocumentPosition(event.target) &\n Node.DOCUMENT_POSITION_FOLLOWING\n )\n markBillingTouched();\n }}\n aria-busy={busy || undefined}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\"\n >\n {summarySlot}\n\n {/* Identity */}\n <div className=\"ds:grid ds:grid-cols-1 ds:gap-[var(--spacing-sm)] ds:sm:grid-cols-2\">\n <FormField\n label={t('booking.details.firstName.label')}\n required\n error={fieldErrors.firstName}\n announceError={announce('firstName')}\n >\n <TextInput\n autoComplete=\"given-name\"\n value={value.firstName ?? ''}\n onChange={(e) => update({ firstName: e.target.value })}\n onBlur={() => markTouched('firstName')}\n />\n </FormField>\n <FormField\n label={t('booking.details.lastName.label')}\n required\n error={fieldErrors.lastName}\n announceError={announce('lastName')}\n >\n <TextInput\n autoComplete=\"family-name\"\n value={value.lastName ?? ''}\n onChange={(e) => update({ lastName: e.target.value })}\n onBlur={() => markTouched('lastName')}\n />\n </FormField>\n </div>\n\n {/* Contact */}\n <div\n className={`ds:grid ds:grid-cols-1 ds:gap-[var(--spacing-sm)]${\n hideEmail ? '' : ' ds:sm:grid-cols-2'\n }`}\n >\n {!hideEmail && (\n <FormField\n label={t('booking.details.email.label')}\n {...(emailRequired ? { required: true } : { optional: true })}\n error={fieldErrors.email}\n announceError={announce('email')}\n >\n <EmailInput\n // The form owns trimming and channel-dependent validation.\n disableBuiltInValidation={emailOptional}\n value={value.email ?? ''}\n onChange={(e) => update({ email: e.target.value })}\n onBlur={() => markTouched('email')}\n />\n </FormField>\n )}\n <FormField\n label={t('booking.details.mobilePhone.label')}\n required\n error={fieldErrors.mobilePhone}\n announceError={announce('mobilePhone')}\n >\n <PhoneInput\n value={value.mobilePhone ?? ''}\n defaultCountry={\n defaultPhoneCountry?.toUpperCase() as\n | 'IT'\n | 'DE'\n | 'GB'\n | undefined\n }\n onChange={(e164) => {\n update({ mobilePhone: e164 });\n markTouched('mobilePhone');\n }}\n />\n </FormField>\n </div>\n\n {/* Optional identity fields. With billing on this form, the fiscal\n code moves into the billing block below. */}\n {(cfRequired && !collectBilling) || requireDateOfBirth ? (\n <div className=\"ds:grid ds:grid-cols-1 ds:gap-[var(--spacing-sm)] ds:sm:grid-cols-2\">\n {cfRequired && !collectBilling ? codiceFiscaleField : null}\n {requireDateOfBirth ? (\n <FormField\n label={t('booking.details.dateOfBirth.label')}\n required\n error={fieldErrors.dateOfBirth}\n announceError={announce('dateOfBirth')}\n >\n <DatePicker\n value={\n value.dateOfBirth ? new Date(value.dateOfBirth) : undefined\n }\n onChange={(next: Date | undefined) => {\n update({\n dateOfBirth: next\n ? next.toISOString().slice(0, 10)\n : undefined,\n });\n markTouched('dateOfBirth');\n }}\n />\n </FormField>\n ) : null}\n </div>\n ) : null}\n\n {insuranceShown ? (\n <FormField\n label={t('booking.details.insuranceNumber.label')}\n required\n description={\n insuranceStatus.state === 'pending'\n ? t('booking.details.insuranceNumber.checking')\n : undefined\n }\n error={fieldErrors.insuranceNumber}\n announceError={announce('insuranceNumber')}\n >\n <TextInput\n value={value.insuranceNumber ?? ''}\n onChange={(e) => update({ insuranceNumber: e.target.value })}\n onBlur={() => markTouched('insuranceNumber')}\n />\n </FormField>\n ) : null}\n\n {collectBilling ? (\n <div\n ref={billingRef}\n data-component=\"booking-billing\"\n role=\"group\"\n aria-labelledby={`${formId}-billing-heading`}\n aria-describedby={`${formId}-billing-intro`}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)] ds:rounded-[var(--radius-md)] ds:border ds:border-[var(--border)] ds:p-[var(--spacing-sm)]\"\n onBlur={(event) => {\n // Text fields show their own gap on leaving them. The two\n // pickers lose focus to their own list, so they wait for\n // focus to move past the block.\n const field = (event.target as HTMLElement)\n .closest('[data-address-field]')\n ?.getAttribute('data-address-field');\n if (\n field === 'street' ||\n field === 'city' ||\n field === 'postcode'\n )\n markTouched(BILLING_FIELDS[field]);\n }}\n >\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\">\n <h3\n id={`${formId}-billing-heading`}\n className=\"type-label ds:m-0 ds:font-[var(--font-weight-semibold)] ds:text-[var(--foreground)]\"\n >\n {t('booking.details.billing.heading')}\n </h3>\n <p\n id={`${formId}-billing-intro`}\n className=\"type-body-sm ds:m-0 ds:text-[color:var(--muted-foreground)]\"\n >\n {t('booking.details.billing.intro')}\n </p>\n </div>\n {cfRequired ? codiceFiscaleField : null}\n <AddressFields\n value={billingAddress}\n onChange={(next) =>\n // The name is set from the patient's own on submit.\n update({\n billing: fromStructured(\n next,\n '',\n // A second line belongs to its street: it goes when the\n // patient writes another, and returns with the first.\n next.street.trim() === secondLineRef.current?.street\n ? secondLineRef.current.line2\n : null,\n ),\n })\n }\n popularCountries={BILLING_COUNTRIES}\n layout=\"grid\"\n fields={\n billingInItaly ? undefined : ['street', 'city', 'postcode']\n }\n required={\n billingInItaly\n ? ['country', 'street', 'city', 'postcode', 'province']\n : ['country', 'street', 'city', 'postcode']\n }\n errors={{\n country: fieldErrors[BILLING_FIELDS.country],\n street: fieldErrors[BILLING_FIELDS.street],\n city: fieldErrors[BILLING_FIELDS.city],\n postcode: fieldErrors[BILLING_FIELDS.postcode],\n province: fieldErrors[BILLING_FIELDS.province],\n }}\n announceErrors={{\n country: announce(BILLING_FIELDS.country),\n street: announce(BILLING_FIELDS.street),\n city: announce(BILLING_FIELDS.city),\n postcode: announce(BILLING_FIELDS.postcode),\n province: announce(BILLING_FIELDS.province),\n }}\n />\n </div>\n ) : null}\n\n {showNote ? (\n <FormField\n label={t('booking.details.note.label')}\n optional\n description={t('booking.details.note.helper', {\n max: NOTE_MAX_LENGTH,\n })}\n >\n <TextArea\n value={value.note ?? ''}\n maxLength={NOTE_MAX_LENGTH}\n rows={3}\n onChange={(e) => update({ note: e.target.value })}\n />\n </FormField>\n ) : null}\n\n {showReturningPatientFlag ? (\n <Checkbox\n checked={Boolean(value.returningPatient)}\n onCheckedChange={(checked) =>\n update({ returningPatient: checked === true })\n }\n label={t('booking.details.returningPatient.label')}\n />\n ) : null}\n\n {/* Practice-authored information the patient must accept before\n booking. Rendered as a text node on purpose — the string comes\n from the practice, so it must never reach the DOM as HTML. */}\n {criticalInformation !== undefined ? (\n <div\n data-component=\"booking-critical-information\"\n role=\"group\"\n aria-labelledby={`${formId}-critical-information-heading`}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)] ds:rounded-[var(--radius-md)] ds:border ds:border-[var(--border)] ds:bg-[var(--muted)] ds:p-[var(--spacing-sm)]\"\n >\n <h3\n id={`${formId}-critical-information-heading`}\n className=\"type-label ds:font-[var(--font-weight-semibold)] ds:text-[var(--foreground)] ds:m-0\"\n >\n {t('booking.details.criticalInformation.heading')}\n </h3>\n <p\n dir=\"auto\"\n className=\"type-body-sm ds:m-0 ds:whitespace-pre-wrap ds:break-words ds:text-[var(--foreground)]\"\n >\n {linkifyText(criticalInformation).map((segment, index) =>\n segment.kind === 'link' ? (\n <a\n key={index}\n href={segment.href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n // A URL reads left to right whatever the text around it.\n dir=\"ltr\"\n className={CONSENT_LINK_CLASSES}\n >\n {segment.text}\n </a>\n ) : (\n <Fragment key={index}>{segment.text}</Fragment>\n ),\n )}\n </p>\n <Checkbox\n checked={Boolean(value.criticalInformationAccepted)}\n onCheckedChange={(checked) =>\n update({ criticalInformationAccepted: checked === true })\n }\n aria-required={true}\n label={\n <>\n {t('booking.details.criticalInformation.accept')}\n <span\n aria-hidden=\"true\"\n className=\"ds:text-[var(--destructive)] ds:ms-[var(--spacing-2xs)]\"\n >\n *\n </span>\n </>\n }\n />\n </div>\n ) : null}\n\n {payment ? (\n <div\n data-component=\"booking-payment-notice\"\n role=\"group\"\n aria-labelledby={`${formId}-payment-heading`}\n data-notice-style={paymentNoticeStyle}\n className={paymentNoticeVariants({\n noticeStyle: paymentNoticeStyle,\n })}\n >\n {paymentNoticeStyle === 'highlighted' ? (\n <div className=\"ds:flex ds:items-center ds:gap-[var(--spacing-sm)]\">\n <span className=\"ds:flex ds:size-9 ds:shrink-0 ds:items-center ds:justify-center ds:rounded-full ds:bg-[var(--primary)] ds:text-[var(--primary-foreground)]\">\n <CreditCard aria-hidden=\"true\" className=\"ds:size-5\" />\n </span>\n <h3\n id={`${formId}-payment-heading`}\n className=\"type-title-item ds:m-0 ds:flex-1\"\n >\n {t('booking.payment.noticeTitle')}\n </h3>\n {/* The sentence below says the amount to screen readers. */}\n <span\n aria-hidden=\"true\"\n className=\"type-title-card ds:shrink-0 ds:text-[var(--foreground)]\"\n >\n {paymentAmount}\n </span>\n </div>\n ) : (\n <h3\n id={`${formId}-payment-heading`}\n className=\"type-label ds:m-0\"\n >\n {t('booking.payment.noticeTitle')}\n </h3>\n )}\n <p className=\"type-body-sm ds:m-0\">\n {t('booking.payment.noticeBody', { amount: paymentAmount })}\n </p>\n {safePaymentTermsUrl ? (\n <a\n href={safePaymentTermsUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"type-body-sm ds:inline-flex ds:items-center ds:self-start ds:min-h-[var(--min-target-size)] ds:rounded-[var(--radius-sm)] ds:underline ds:text-[var(--foreground)] ds:focus-visible:outline-solid ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-[var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]\"\n >\n {t('booking.payment.terms')}\n </a>\n ) : null}\n <Checkbox\n checked={paymentAccepted}\n onCheckedChange={(checked) => {\n setAcceptedPaymentKey(\n checked === true ? paymentKey : undefined,\n );\n update({ paymentAccepted: checked === true });\n }}\n aria-required={true}\n label={\n <>\n {t('booking.payment.accept', { amount: paymentAmount })}\n <span\n aria-hidden=\"true\"\n className=\"ds:text-[var(--destructive)] ds:ms-[var(--spacing-2xs)]\"\n >\n *\n </span>\n </>\n }\n />\n </div>\n ) : null}\n\n {/* Consents — AlfaDocs privacy + T&C, both required for submit, then\n the practice's own box when it has one. */}\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <Checkbox\n checked={Boolean(value.privacyConsent)}\n onCheckedChange={(checked) =>\n update({ privacyConsent: checked === true })\n }\n aria-required={true}\n label={\n <>\n {renderConsentLabel(\n 'booking.details.consent.privacy.label',\n privacyPolicyUrl,\n )}\n <span\n aria-hidden=\"true\"\n className=\"ds:text-[var(--destructive)] ds:ms-[var(--spacing-2xs)]\"\n >\n *\n </span>\n </>\n }\n />\n <Checkbox\n checked={Boolean(value.termsConsent)}\n onCheckedChange={(checked) =>\n update({ termsConsent: checked === true })\n }\n aria-required={true}\n label={\n <>\n {renderConsentLabel(\n 'booking.details.consent.terms.label',\n termsUrl,\n )}\n <span\n aria-hidden=\"true\"\n className=\"ds:text-[var(--destructive)] ds:ms-[var(--spacing-2xs)]\"\n >\n *\n </span>\n </>\n }\n />\n {practiceConsent && practiceConsentShown ? (\n <Checkbox\n checked={practiceConsentAccepted}\n onCheckedChange={(checked) => {\n setAcceptedPracticeConsentKey(\n checked === true ? practiceConsentKey : undefined,\n );\n update({ practiceConsentAccepted: checked === true });\n }}\n aria-required={practiceConsent.required || undefined}\n label={\n <>\n {/* Practice-authored text: a text node, never markup, in\n the direction it was typed in. */}\n {safeHttpUrl(practiceConsent.url) ? (\n <a\n dir=\"auto\"\n href={safeHttpUrl(practiceConsent.url)}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={CONSENT_LINK_CLASSES}\n >\n {practiceConsent.label}\n </a>\n ) : (\n <span dir=\"auto\">{practiceConsent.label}</span>\n )}\n {practiceConsent.required ? (\n <span\n aria-hidden=\"true\"\n className=\"ds:text-[var(--destructive)] ds:ms-[var(--spacing-2xs)]\"\n >\n *\n </span>\n ) : null}\n </>\n }\n />\n ) : null}\n </div>\n\n {pickerVisible ? (\n <div\n data-component=\"booking-confirmation-channels\"\n // Marks the group for the refused-submit focus: one is needed.\n data-unanswered={noChannelsSelected || undefined}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\"\n >\n {singleConfirmationChannel ? (\n <RadioGroup\n // Two or three short choices sit on one line.\n variant=\"horizontal\"\n label={t('booking.confirmation.heading')}\n value={selectedChannels[0] ?? ''}\n onValueChange={(next) =>\n update({\n confirmationChannels: [next as ConfirmationChannel],\n })\n }\n error={\n noChannelsSelected\n ? t('booking.confirmation.atLeastOne')\n : undefined\n }\n >\n {resolvedEnabledChannels.map((c) => (\n <Radio\n key={c}\n value={c}\n label={t(`booking.confirmation.channel.${c}`)}\n />\n ))}\n </RadioGroup>\n ) : (\n <CheckboxGroup\n label={t('booking.confirmation.heading')}\n helperText={t('booking.confirmation.helper')}\n value={selectedChannels}\n onChange={(next) =>\n update({\n confirmationChannels: next as ConfirmationChannel[],\n })\n }\n orientation=\"vertical\"\n options={resolvedEnabledChannels.map((c) => ({\n value: c,\n label: t(`booking.confirmation.channel.${c}`),\n }))}\n error={\n noChannelsSelected\n ? t('booking.confirmation.atLeastOne')\n : undefined\n }\n />\n )}\n </div>\n ) : null}\n\n {!locked && (submitError || submissionFailed || paymentBlocked) ? (\n <Alert variant=\"error\">\n <Alert.Description>\n {submitError ??\n t(\n paymentBlocked\n ? 'booking.payment.unavailable'\n : 'booking.payment.submitFailed',\n )}\n </Alert.Description>\n </Alert>\n ) : null}\n\n {locked ? null : (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n {/* Says why the button looks unavailable, before it is pressed.\n Not while sending, nor when the payment cannot be taken: the\n alert above says that. */}\n {waitingOnPatient ? (\n <p\n id={submitHintId}\n data-slot=\"submit-hint\"\n className=\"type-body-sm ds:m-0 ds:text-[var(--muted-foreground)]\"\n >\n {t('booking.details.submitHint')}\n </p>\n ) : null}\n <Button\n intent=\"primary\"\n size=\"md\"\n type=\"submit\"\n // Off only while nothing the patient does can help. Otherwise it\n // stays reachable and a press shows what is missing.\n disabled={busy || paymentBlocked}\n aria-disabled={!canSubmit || undefined}\n aria-describedby={waitingOnPatient ? submitHintId : undefined}\n startIcon={\n busy ? <Spinner variant=\"pulse\" size=\"sm\" /> : undefined\n }\n >\n {payment\n ? t('booking.payment.submit', { amount: paymentAmount })\n : t('booking.details.submit')}\n </Button>\n </div>\n )}\n </form>\n );\n },\n);\n\nBookingDetailsForm.displayName = 'BookingDetailsForm';\n","/**\n * `:focus-visible` matches a programmatic focus when the patient was already\n * driving by keyboard, so without an explicit ring the browser draws its own\n * default outline around the whole panel — a different shape and colour in\n * each of the four themes. Paint the kit's ring instead: it also makes the\n * repaired focus visible, which is the point of moving it.\n */\nexport const stepRegionFocusClasses = [\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)]',\n 'ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)]',\n 'ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-visible:outline-[CanvasText]',\n].join(' ');\n\n/**\n * True when movement should be instant: the patient asked for reduced motion,\n * or the theme turned animation off (`.theme-accessible`, a zero\n * `--animation-duration`).\n */\nexport function motionIsOff(root: HTMLElement | null): boolean {\n if (typeof window === 'undefined') return false;\n if (\n typeof window.matchMedia === 'function' &&\n window.matchMedia('(prefers-reduced-motion: reduce)').matches\n )\n return true;\n if (!root) return false;\n if (root.closest('.theme-accessible')) return true;\n const duration = getComputedStyle(root).getPropertyValue(\n '--animation-duration',\n );\n return duration.trim() !== '' && parseFloat(duration) === 0;\n}\n\n/**\n * Brings `element` into view with one smooth scroll, and only when part of it\n * is hidden: a step that is already on screen does not move. The page's\n * scroll padding (a sticky PublicHeader sets it) and the booking's own\n * `scroll-margin-top` both narrow the area it must sit in, for the visibility\n * check and the scroll alike. Instant when motion is off. Returns whether it\n * scrolled.\n */\nexport function glideIntoView(\n element: HTMLElement | null,\n block: ScrollLogicalPosition,\n): boolean {\n if (!element || typeof element.scrollIntoView !== 'function') return false;\n const style = getComputedStyle(element);\n // The page scrolls the document; a `scroll-padding` of `auto` reads as 0.\n const page = getComputedStyle(document.documentElement);\n const top =\n (parseFloat(style.scrollMarginTop) || 0) +\n (parseFloat(page.scrollPaddingTop) || 0);\n const bottom =\n (parseFloat(style.scrollMarginBottom) || 0) +\n (parseFloat(page.scrollPaddingBottom) || 0);\n const box = element.getBoundingClientRect();\n if (box.top >= top && box.bottom <= window.innerHeight - bottom) return false;\n try {\n element.scrollIntoView({\n behavior: motionIsOff(element) ? 'auto' : 'smooth',\n block,\n });\n } catch {\n // Older browsers may reject the options form: a plain scroll still helps.\n element.scrollIntoView();\n }\n return true;\n}\n\n/**\n * Runs `done` once the page has stopped scrolling, or after `maxMs` where the\n * browser sends no `scrollend`. Returns a cancel function.\n */\nexport function afterScrollSettles(done: () => void, maxMs = 1000): () => void {\n let finished = false;\n const finish = () => {\n if (finished) return;\n finished = true;\n window.removeEventListener('scrollend', finish);\n clearTimeout(timer);\n done();\n };\n const timer = setTimeout(finish, maxMs);\n window.addEventListener('scrollend', finish);\n return () => {\n finished = true;\n window.removeEventListener('scrollend', finish);\n clearTimeout(timer);\n };\n}\n","import { useEffect, useId, useRef, useState } from 'react';\nimport { useTranslation, Trans } from 'react-i18next';\nimport { Alert } from '../alert/alert';\nimport { Button } from '../button/button';\nimport { Card } from '../card/card';\nimport { FormField } from '../form-field/form-field';\nimport { OTPInput, type OTPInputHandle } from '../otp-input/otp-input';\nimport type { BookingCodeStep } from './booking-types';\nimport { glideIntoView, stepRegionFocusClasses } from './step-focus';\n\ntype CodeError = 'wrong' | 'expired' | 'too-many-attempts';\n\n/** Submit-phase UI. The host owns code generation, validation and SMS delivery. */\nexport function BookingCodeVerification({\n length = 5,\n onVerify,\n onResend,\n resendSeconds = 60,\n phoneHint,\n onVerified,\n onBusyChange,\n}: BookingCodeStep & {\n onVerified: (redirectUrl?: string) => void;\n /** Reports a running verify or resend, so the host form can hold \"Change\". */\n onBusyChange?: (busy: boolean) => void;\n}) {\n const { t, i18n } = useTranslation('ui');\n const headingId = useId();\n const instructionId = useId();\n const headingRef = useRef<HTMLHeadingElement>(null);\n const sectionRef = useRef<HTMLElement>(null);\n const inputRef = useRef<OTPInputHandle>(null);\n const resendRef = useRef<HTMLButtonElement>(null);\n const mounted = useRef(false);\n const inFlight = useRef(false);\n const [busy, setBusy] = useState<'verify' | 'resend' | null>(null);\n const [resent, setResent] = useState(false);\n const [codeError, setCodeError] = useState<CodeError | null>(null);\n const [requestError, setRequestError] = useState<'verify' | 'resend' | null>(\n null,\n );\n // Remounting resets both the code and OTPInput's roving focus to box one.\n const [inputVersion, setInputVersion] = useState(0);\n const waitSeconds = Number.isFinite(resendSeconds)\n ? Math.max(0, Math.ceil(resendSeconds))\n : 60;\n const [deadline, setDeadline] = useState(\n () => Date.now() + waitSeconds * 1000,\n );\n const [secondsLeft, setSecondsLeft] = useState(waitSeconds);\n const locked = codeError === 'too-many-attempts';\n\n useEffect(() => {\n onBusyChange?.(Boolean(busy));\n }, [busy, onBusyChange]);\n\n useEffect(() => {\n mounted.current = true;\n return () => {\n mounted.current = false;\n };\n }, []);\n\n useEffect(() => {\n // Focus without a scroll jump, then glide the box to the middle of the\n // screen only if part of it is hidden, so it never sits on the edge.\n inputRef.current?.focus({ preventScroll: true });\n glideIntoView(sectionRef.current, 'center');\n }, [inputVersion]);\n\n useEffect(() => {\n if (busy || (!locked && requestError !== 'resend')) return;\n // Only restore focus that was lost, never take it from elsewhere.\n const active = document.activeElement;\n const section = headingRef.current?.closest('section');\n if (active && active !== document.body && !section?.contains(active))\n return;\n // Wait for controls to be enabled again before restoring focus.\n if (resendRef.current && !resendRef.current.disabled)\n resendRef.current.focus();\n else headingRef.current?.focus();\n }, [busy, locked, requestError]);\n\n useEffect(() => {\n if (secondsLeft === 0) return;\n const timer = setTimeout(() => {\n // Use elapsed time so a background tab cannot extend the waiting period.\n setSecondsLeft(Math.max(0, Math.ceil((deadline - Date.now()) / 1000)));\n }, 1000);\n return () => clearTimeout(timer);\n }, [deadline, secondsLeft]);\n\n const verify = async (code: string) => {\n if (inFlight.current || locked) return;\n inFlight.current = true;\n setBusy('verify');\n setResent(false);\n setCodeError(null);\n setRequestError(null);\n try {\n const result = await onVerify(code);\n if (!mounted.current) return;\n if (result.ok) {\n onVerified(result.redirectUrl);\n } else {\n setCodeError(result.reason);\n if (result.reason !== 'too-many-attempts')\n setInputVersion((version) => version + 1);\n }\n } catch {\n if (!mounted.current) return;\n setRequestError('verify');\n setInputVersion((version) => version + 1);\n } finally {\n inFlight.current = false;\n if (mounted.current) setBusy(null);\n }\n };\n\n const resend = async () => {\n if (inFlight.current || Date.now() < deadline) return;\n inFlight.current = true;\n setBusy('resend');\n setResent(false);\n setRequestError(null);\n try {\n await onResend();\n if (!mounted.current) return;\n setDeadline(Date.now() + waitSeconds * 1000);\n setSecondsLeft(waitSeconds);\n setCodeError(null);\n setResent(true);\n setInputVersion((version) => version + 1);\n } catch {\n if (mounted.current) setRequestError('resend');\n } finally {\n inFlight.current = false;\n if (mounted.current) setBusy(null);\n }\n };\n\n const codeMessage =\n codeError === 'wrong'\n ? t('booking.code.wrong')\n : codeError === 'expired'\n ? t('booking.code.expired')\n : locked\n ? t('booking.code.tooManyAttempts')\n : undefined;\n\n // Raised above the locked form and centred, like the \"Orario riservato\"\n // card that replaces it.\n return (\n <Card variant=\"elevated\" asChild>\n <section\n ref={sectionRef}\n aria-labelledby={headingId}\n data-component=\"booking-code-step\"\n className=\"ds:items-center ds:gap-[var(--spacing-md)] ds:p-[var(--spacing-md)] ds:text-center\"\n >\n <h3\n ref={headingRef}\n id={headingId}\n tabIndex={-1}\n className={`type-title-card ds:m-0 ${stepRegionFocusClasses}`}\n >\n {t('booking.code.heading')}\n </h3>\n <p id={instructionId} className=\"type-body ds:m-0\">\n {phoneHint ? (\n <Trans\n t={t}\n ns=\"ui\"\n i18nKey=\"booking.code.instructionWithPhone\"\n values={{ phone: phoneHint }}\n components={{ phone: <bdi /> }}\n />\n ) : (\n t('booking.code.instruction')\n )}\n </p>\n <FormField label={t('booking.code.label')} error={codeMessage}>\n <div dir=\"ltr\">\n <OTPInput\n key={inputVersion}\n ref={inputRef}\n length={length}\n mode=\"alphanumeric\"\n aria-describedby={instructionId}\n disabled={Boolean(busy) || locked}\n onComplete={verify}\n />\n </div>\n </FormField>\n {requestError ? (\n <Alert variant=\"error\" className=\"ds:self-stretch ds:text-start\">\n <Alert.Description>\n {requestError === 'verify'\n ? t('booking.code.verifyFailed')\n : t('booking.code.resendFailed')}\n </Alert.Description>\n </Alert>\n ) : null}\n <p role=\"status\" className=\"type-body ds:m-0\">\n {busy === 'verify'\n ? t('booking.code.verifying')\n : resent\n ? t('booking.code.resent')\n : null}\n </p>\n <Button\n ref={resendRef}\n type=\"button\"\n intent=\"secondary\"\n disabled={secondsLeft > 0 || Boolean(busy)}\n loading={busy === 'resend'}\n onClick={resend}\n >\n {secondsLeft > 0\n ? t('booking.code.resendCountdown', {\n seconds: new Intl.NumberFormat(i18n.language).format(\n secondsLeft,\n ),\n })\n : t('booking.code.resend')}\n </Button>\n </section>\n </Card>\n );\n}\n","import type {\n BookingResolvedPayment,\n BookingService,\n BookingSlot,\n} from './booking-types';\n\nexport function resolveServicePayment(\n service: BookingService,\n): BookingResolvedPayment | undefined {\n const payment = service.payment;\n if (!payment) return undefined;\n const currencyCode = (payment.currencyCode ?? 'EUR').toUpperCase();\n if (\n !Number.isSafeInteger(payment.amountCents) ||\n payment.amountCents <= 0 ||\n !['full', 'deposit'].includes(payment.kind) ||\n !/^[A-Z]{3}$/.test(currencyCode)\n )\n return undefined;\n return {\n serviceId: service.id,\n kind: payment.kind,\n amountCents: payment.amountCents,\n currencyCode,\n };\n}\n\n/**\n * What one service shows in the service picker, before translation.\n *\n * `price` is the chip at the row's end: the service's price, as for every\n * service. It is `priceLabel`; with none, a full payment's amount, since that\n * IS the price; a deposit is never the price, so then there is no chip.\n *\n * `payment` is the line under the service name: the payment the service\n * requires, or 'unavailable' when its payment data cannot be charged.\n */\nexport interface ServicePickerParts {\n price?: { label: string } | { amount: BookingResolvedPayment };\n payment?: BookingResolvedPayment | 'unavailable';\n}\n\nexport function servicePickerParts(\n service: BookingService,\n): ServicePickerParts {\n // A blank label counts as none, so the chip and the accessible name agree.\n const priceLabel = service.priceLabel?.trim()\n ? service.priceLabel\n : undefined;\n const price = priceLabel ? { label: priceLabel } : undefined;\n if (!service.payment) return { price };\n const payment = resolveServicePayment(service);\n if (!payment) return { price, payment: 'unavailable' };\n return {\n price: price ?? (payment.kind === 'full' ? { amount: payment } : undefined),\n payment,\n };\n}\n\n/** Selected services are search alternatives, never a shopping basket. */\nexport function resolveBookingPayment(\n services: BookingService[],\n serviceIds: string[],\n slot?: BookingSlot,\n): { payment?: BookingResolvedPayment; blocked: boolean } {\n const selected = services.filter((service) =>\n serviceIds.includes(service.id),\n );\n const actualId =\n slot?.serviceId ?? (serviceIds.length === 1 ? serviceIds[0] : undefined);\n if (actualId) {\n const actual = selected.find((service) => service.id === actualId);\n if (!actual) return { blocked: true };\n const payment = resolveServicePayment(actual);\n return { payment, blocked: Boolean(actual.payment && !payment) };\n }\n return { blocked: selected.some((service) => Boolean(service.payment)) };\n}\n\nexport function paymentIdentity(payment?: BookingResolvedPayment): string {\n return payment\n ? JSON.stringify([\n payment.serviceId,\n payment.kind,\n payment.amountCents,\n payment.currencyCode,\n ])\n : '';\n}\n","import { useEffect, useMemo, useRef, useState } from 'react';\nimport type {\n BookingCodeStep,\n BookingDetails,\n BookingPaymentSession,\n BookingProps,\n BookingSubmitPayload,\n BookingSlot,\n} from './booking-types';\nimport { paymentIdentity, resolveBookingPayment } from './payment';\nimport { resolveOperatorId, resolveServiceIds } from './cascade';\n\ntype Submission = {\n status: 'idle' | 'submitting' | 'payment' | 'code' | 'success' | 'error';\n snapshot?: BookingSubmitPayload;\n session?: BookingPaymentSession;\n cancelled?: boolean;\n codeStep?: BookingCodeStep;\n codeVerified?: boolean;\n /** Address to open from the \"Time reserved\" view, as the host gave it. */\n redirectUrl?: string;\n};\n\nexport function useBookingPayment({\n services,\n value,\n availableSlots,\n onSubmit,\n onChange,\n paymentState,\n submitting,\n paymentTermsUrl,\n renderPayment,\n codeStep,\n}: Pick<\n BookingProps,\n | 'services'\n | 'value'\n | 'availableSlots'\n | 'onSubmit'\n | 'onChange'\n | 'paymentState'\n | 'submitting'\n | 'paymentTermsUrl'\n | 'renderPayment'\n | 'codeStep'\n>) {\n const selection = JSON.stringify([\n value.insuranceType,\n value.specialtyId,\n value.specialtyIds,\n resolveServiceIds(value),\n value.operatorId,\n value.operatorIds,\n value.date,\n value.slotKey,\n ]);\n const heldSlot = useRef<{ selection: string; slot: BookingSlot } | undefined>(\n undefined,\n );\n const listedSlot = value.date\n ? availableSlots[value.date]?.find((item) => item.key === value.slotKey)\n : undefined;\n // Availability can disappear because this very request holds the slot.\n const slot =\n listedSlot ??\n (heldSlot.current?.selection === selection\n ? heldSlot.current.slot\n : undefined);\n const resolution = resolveBookingPayment(\n services,\n resolveServiceIds(value),\n slot,\n );\n const blocked =\n resolution.blocked || Boolean(resolution.payment && !renderPayment);\n const signature = JSON.stringify([\n selection,\n slot?.serviceId,\n paymentIdentity(resolution.payment),\n paymentTermsUrl,\n blocked,\n ]);\n // Acceptance is a boolean in value.details, and the details form can remount\n // (a date change unmounts it) and trust it again. Bind it to the quote here.\n // Terms are part of what was accepted, as in the form's own acceptance key.\n const quoteIdentity = resolution.payment\n ? JSON.stringify([paymentIdentity(resolution.payment), paymentTermsUrl])\n : '';\n const acceptedQuote = useRef<string | undefined>(undefined);\n const accepted = Boolean(value.details?.paymentAccepted);\n useEffect(() => {\n if (!accepted) acceptedQuote.current = undefined;\n else if (!quoteIdentity) return;\n else if (acceptedQuote.current === undefined)\n acceptedQuote.current = quoteIdentity;\n else if (acceptedQuote.current !== quoteIdentity) {\n acceptedQuote.current = undefined;\n onChange({\n ...value,\n details: { ...value.details, paymentAccepted: false },\n });\n }\n }, [accepted, quoteIdentity, onChange, value]);\n const currentSignature = useRef(signature);\n currentSignature.current = signature;\n const [submission, setSubmission] = useState<Submission>({ status: 'idle' });\n const generation = useRef(0);\n const inFlight = useRef(false);\n const mounted = useRef(true);\n const terminal = useRef(false);\n const completionSession = useRef<string | undefined>(undefined);\n const sessionScope = useRef(signature);\n useEffect(() => {\n mounted.current = true;\n return () => {\n mounted.current = false;\n generation.current += 1;\n };\n }, []);\n // A returned hold carries its own quote and id; a later live quote or\n // selection change must not orphan it. Only pending requests are dropped.\n const held =\n submission.status === 'payment' ||\n submission.status === 'code' ||\n submission.status === 'success';\n useEffect(() => {\n if (sessionScope.current === signature || terminal.current || held) return;\n sessionScope.current = signature;\n generation.current += 1;\n inFlight.current = false;\n setSubmission({ status: 'idle' });\n }, [signature, held]);\n\n const activeSession =\n held || sessionScope.current === signature ? submission.session : undefined;\n const reportedState = useMemo(\n () =>\n activeSession && paymentState?.sessionId === activeSession.id\n ? paymentState\n : activeSession\n ? { sessionId: activeSession.id, status: 'ready' as const }\n : undefined,\n [activeSession, paymentState],\n );\n if (\n activeSession &&\n reportedState &&\n 'phase' in reportedState &&\n reportedState.phase === 'completion'\n )\n completionSession.current = activeSession.id;\n const state = useMemo(\n () =>\n activeSession &&\n completionSession.current === activeSession.id &&\n reportedState &&\n reportedState.status !== 'paid' &&\n (!('phase' in reportedState) || reportedState.phase !== 'completion')\n ? {\n sessionId: activeSession.id,\n status: 'processing' as const,\n phase: 'completion' as const,\n }\n : reportedState,\n [activeSession, reportedState],\n );\n useEffect(() => {\n if (!activeSession || !state || terminal.current) return;\n if (state.status === 'paid') {\n // Payment is the last stage. A code step never follows it.\n if (submission.status !== 'payment') return;\n terminal.current = true;\n setSubmission((previous) => ({\n ...previous,\n status: 'success',\n redirectUrl: state.redirectUrl,\n }));\n } else if (state.status === 'cancelled') {\n generation.current += 1;\n inFlight.current = false;\n // The released hold no longer vouches for a slot that left availability.\n heldSlot.current = undefined;\n onChange({\n ...value,\n details: { ...value.details, paymentAccepted: false },\n });\n setSubmission({ status: 'idle', cancelled: true });\n }\n }, [activeSession, state, onChange, value, submission.status]);\n\n const reset = () => {\n generation.current += 1;\n inFlight.current = false;\n terminal.current = false;\n completionSession.current = undefined;\n heldSlot.current = undefined;\n sessionScope.current = currentSignature.current;\n setSubmission({ status: 'idle' });\n };\n const submit = async (details: BookingDetails) => {\n if (\n !slot?.available ||\n blocked ||\n submitting ||\n inFlight.current ||\n submission.status === 'payment' ||\n submission.status === 'code' ||\n terminal.current\n )\n return;\n if (resolution.payment && !details.paymentAccepted) return;\n inFlight.current = true;\n // Keep the submitted code configuration even if the host later drops it.\n const submittedCodeStep = codeStep ? { ...codeStep } : undefined;\n heldSlot.current = { selection, slot: { ...slot } };\n const attempt = ++generation.current;\n const scope = signature;\n sessionScope.current = scope;\n // Freeze the submitted selection. Later consumer renders cannot rewrite a receipt.\n const payload: BookingSubmitPayload = {\n slot: { ...slot, meta: slot.meta ? { ...slot.meta } : undefined },\n value: {\n ...value,\n serviceIds: value.serviceIds?.slice(),\n specialtyIds: value.specialtyIds?.slice(),\n operatorIds: value.operatorIds?.slice(),\n operatorId: resolveOperatorId(value) ?? value.operatorId,\n details: { ...details },\n },\n details: {\n ...details,\n confirmationChannels: details.confirmationChannels?.slice(),\n },\n ...(resolution.payment ? { payment: { ...resolution.payment } } : {}),\n };\n const current = () =>\n mounted.current &&\n generation.current === attempt &&\n currentSignature.current === scope;\n setSubmission({ status: 'submitting' });\n let held = false;\n try {\n const result = await onSubmit(payload);\n if (!current()) return;\n if (payload.payment) {\n const session = result?.paymentSession;\n if (\n !session?.id?.trim() ||\n paymentIdentity(session.payment) !== paymentIdentity(payload.payment)\n ) {\n setSubmission({ status: 'error' });\n return;\n }\n held = true;\n // With a code step the patient confirms the phone first, then pays.\n setSubmission({\n status: submittedCodeStep ? 'code' : 'payment',\n snapshot: payload,\n session: { id: session.id, payment: { ...session.payment } },\n codeStep: submittedCodeStep,\n });\n } else if (result?.paymentSession) {\n // A newly required payment needs fresh patient review and acceptance.\n setSubmission({ status: 'error' });\n } else {\n terminal.current = true;\n setSubmission({\n status: submittedCodeStep ? 'code' : 'success',\n snapshot: payload,\n codeStep: submittedCodeStep,\n });\n }\n } catch {\n if (current()) setSubmission({ status: 'error' });\n } finally {\n if (current() && !held) inFlight.current = false;\n }\n };\n return {\n ...submission,\n payment: resolution.payment,\n blocked,\n state,\n activeSession,\n submit,\n reset,\n completeCode: (redirectUrl?: string) => {\n setSubmission((previous) =>\n previous.status !== 'code'\n ? previous\n : previous.session\n ? { ...previous, status: 'payment', codeVerified: true }\n : {\n ...previous,\n status: 'success',\n codeVerified: true,\n redirectUrl,\n },\n );\n },\n };\n}\n","import {\n useEffect,\n useId,\n useLayoutEffect,\n useRef,\n useState,\n type ReactNode,\n} from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Button } from '../button/button';\nimport { motionIsOff } from './step-focus';\n\ninterface BookingReservedProps {\n /** An address already checked with `safeHandoverUrl`. */\n url: string;\n delayMs: number;\n /** Replaces `window.location.assign`. */\n onNavigate?: (url: string) => void;\n /** Short date, already formatted for the locale. */\n date?: string;\n /** Clock time, already formatted for the locale. */\n time: string;\n /** Service and professional, already joined. */\n details?: ReactNode;\n /** True when focus is inside Booking, or a removed control dropped it. */\n shouldTakeFocus: (root: HTMLElement) => boolean;\n}\n\n// A bar moving for over 5 s needs a pause control (WCAG 2.2.2).\nconst MAX_BAR_MS = 5000;\nconst checkClasses =\n 'ds:[stroke-dasharray:1] ds:[stroke-dashoffset:1] ds:animate-[stepper-icon-draw_calc(var(--animation-duration)*3)_var(--ease-out)_forwards]';\nconst barClasses =\n 'ds:block ds:[block-size:100%] ds:rounded-full ds:bg-[var(--primary)] ds:animate-[reserved-bar-fill_linear_forwards] ds:[animation-duration:var(--handover-ms)]';\n\n/**\n * \"Time reserved\": shown after a correct SMS code or a verified payment when\n * the host gave an address. Opens it after `delayMs`, or at once from the\n * button.\n */\nexport function BookingReserved({\n url,\n delayMs,\n onNavigate,\n date,\n time,\n details,\n shouldTakeFocus,\n}: BookingReservedProps) {\n const { t } = useTranslation('ui');\n const rootRef = useRef<HTMLDivElement>(null);\n const headingRef = useRef<HTMLHeadingElement>(null);\n const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n const messageId = useId();\n const goRef = useRef<HTMLButtonElement>(null);\n const [stayed, setStayed] = useState(false);\n const [still, setStill] = useState(() => motionIsOff(null));\n\n const open = () => {\n clearTimeout(timer.current);\n try {\n if (onNavigate) onNavigate(url);\n else window.location.assign(url);\n } catch {\n // Blocked: the button stays and the patient can try again.\n }\n };\n const stay = () => {\n clearTimeout(timer.current);\n setStayed(true);\n goRef.current?.focus({ preventScroll: true });\n };\n const openRef = useRef(open);\n openRef.current = open;\n\n // Before paint, so the bar never flashes under the accessible theme.\n useLayoutEffect(() => {\n setStill(motionIsOff(rootRef.current));\n }, []);\n\n useEffect(() => {\n const heading = headingRef.current;\n if (heading && rootRef.current && shouldTakeFocus(rootRef.current)) {\n // No scroll here: Booking glides the whole card into view on this step.\n heading.focus({ preventScroll: true });\n }\n // Mount only: a later render must not take focus again.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n timer.current = setTimeout(() => openRef.current(), delayMs);\n return () => clearTimeout(timer.current);\n }, [url, delayMs]);\n\n return (\n <div\n ref={rootRef}\n data-component=\"booking-reserved\"\n className=\"ds:flex ds:flex-col ds:items-center ds:gap-[var(--spacing-md)] ds:text-center\"\n >\n <span\n aria-hidden=\"true\"\n className=\"ds:flex ds:size-[var(--spacing-2xl)] ds:items-center ds:justify-center ds:rounded-full ds:bg-[color-mix(in_srgb,var(--success)_10%,transparent)] ds:text-[var(--success)]\"\n >\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"3\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"ds:size-[var(--spacing-lg)]\"\n >\n <path pathLength=\"1\" d=\"M5 12l5 5L20 7\" className={checkClasses} />\n </svg>\n </span>\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n {/* Focus lands here so a screen reader reads the result. A heading\n is not a control, so no ring: after a typed code the browser\n would draw one for every patient. */}\n <h3\n ref={headingRef}\n tabIndex={-1}\n aria-describedby={messageId}\n className=\"type-title-card ds:m-0 ds:outline-none\"\n >\n {t('booking.reserved.heading')}\n </h3>\n <p className=\"type-body ds:m-0 ds:text-[var(--foreground)]\">\n {date ? t('booking.reserved.when', { date, time }) : time}\n </p>\n {details ? (\n <p className=\"type-body ds:m-0 ds:text-[var(--muted-foreground)]\">\n {details}\n </p>\n ) : null}\n </div>\n <p id={messageId} role=\"status\" className=\"type-body ds:m-0\">\n {stayed\n ? t('booking.reserved.stayed')\n : t('booking.reserved.redirecting')}\n </p>\n {still || stayed || delayMs > MAX_BAR_MS ? null : (\n // Decorative: the sentence above already says a redirect is coming,\n // and a progressbar with no value to read would only add noise.\n <div\n aria-hidden=\"true\"\n data-slot=\"booking-reserved-bar\"\n className=\"ds:[block-size:var(--spacing-xs)] ds:[inline-size:100%] ds:[max-inline-size:calc(var(--spacing-2xl)*5)] ds:overflow-hidden ds:rounded-full ds:bg-[var(--secondary)]\"\n >\n <span\n className={barClasses}\n // eslint-disable-next-line react/forbid-dom-props -- custom property setter, see 23-constraints (sanctioned inline styles)\n style={{ ['--handover-ms' as string]: `${delayMs}ms` }}\n />\n </div>\n )}\n <Button\n ref={goRef}\n type=\"button\"\n intent=\"secondary\"\n size=\"lg\"\n onClick={open}\n >\n {t('booking.reserved.goNow')}\n </Button>\n {stayed ? null : (\n <Button type=\"button\" intent=\"ghost\" size=\"md\" onClick={stay}>\n {t('booking.reserved.stay')}\n </Button>\n )}\n </div>\n );\n}\n","import { isSafeHref } from '../_shared/safe-href';\n\n/** Wait before the \"Time reserved\" view opens the host's address. */\nexport const DEFAULT_HANDOVER_DELAY_MS = 3000;\n\n/**\n * The address to open after a verified booking, or undefined when it must\n * not be used. Only a full http(s) address passes: a relative path,\n * `javascript:`, `data:` or `mailto:` never does. The URL parser strips the\n * whitespace and line breaks a browser would ignore, so they cannot hide a\n * scheme.\n */\nexport function safeHandoverUrl(url: string | undefined): string | undefined {\n if (typeof url !== 'string') return undefined;\n const trimmed = url.trim();\n try {\n const { protocol } = new URL(trimmed);\n return (protocol === 'https:' || protocol === 'http:') &&\n isSafeHref(trimmed)\n ? trimmed\n : undefined;\n } catch {\n return undefined;\n }\n}\n\n/** setTimeout fires at once above this. */\nconst MAX_TIMEOUT_MS = 2 ** 31 - 1;\n\nexport function resolveHandoverDelay(delayMs: number | undefined): number {\n return typeof delayMs === 'number' && Number.isFinite(delayMs) && delayMs >= 0\n ? Math.min(delayMs, MAX_TIMEOUT_MS)\n : DEFAULT_HANDOVER_DELAY_MS;\n}\n","import {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useImperativeHandle,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type KeyboardEvent,\n type ReactNode,\n} from 'react';\nimport { cva } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport {\n Activity,\n Baby,\n Bone,\n Brain,\n CalendarRange,\n ChevronDown,\n ChevronLeft,\n ChevronRight,\n ClipboardCheck,\n Ear,\n Eye,\n HeartPulse,\n Microscope,\n Moon,\n Pill,\n ScanLine,\n Scissors,\n Smile,\n Astroid,\n Stethoscope,\n Sun,\n Sunset,\n Syringe,\n type LucideIcon,\n} from 'lucide-react';\nimport {\n addDays,\n addMonths,\n endOfMonth,\n format as fnsFormat,\n isAfter,\n isBefore,\n isSameDay,\n isSameMonth,\n parseISO,\n startOfDay,\n startOfMonth,\n subDays,\n subMonths,\n} from 'date-fns';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { bookingAgent } from './booking.agent';\nimport {\n OPERATORS_ALL,\n applyAutoSelects,\n deriveCascade,\n resetOnDateChange,\n resetOnInsuranceChange,\n resetOnOperatorChange,\n resetOnOperatorIdsChange,\n resetOnServiceChange,\n resetOnServiceIdsChange,\n resetOnSlotChange,\n resetOnSpecialtyChange,\n resetOnSpecialtyIdsChange,\n resolveConfirmationChannels,\n resolveEffectiveConfirmationChannels,\n resolveOperatorId,\n resolveOperatorIds,\n resolveServiceIds,\n resolveSpecialtyIds,\n stepIsFulfilled,\n type CascadeOutputs,\n type CascadeStep,\n} from './cascade';\nimport { BookingDetailsForm } from './details-form';\nimport { BookingCodeVerification } from './code-step';\nimport {\n afterScrollSettles,\n glideIntoView,\n stepRegionFocusClasses,\n} from './step-focus';\nimport { servicePickerParts } from './payment';\nimport { useBookingPayment } from './use-booking-payment';\nimport { BookingReserved } from './reserved';\nimport { resolveHandoverDelay, safeHandoverUrl } from './handover';\nimport { formatPrice } from '../_shared/format-price';\nimport type {\n BookingDetails,\n BookingHandle,\n BookingOperator,\n BookingResolvedPayment,\n BookingProps,\n BookingService,\n BookingSlot,\n BookingSpecialty,\n BookingValue,\n BookingVariant,\n InsuranceType,\n} from './booking-types';\nimport { Alert } from '../alert/alert';\nimport { Badge } from '../badge/badge';\nimport { Button } from '../button/button';\nimport { IconButton } from '../button/icon-button';\nimport { Select, type SelectOption } from '../select/select';\nimport { Combobox } from '../combobox/combobox';\nimport { MultiSelect } from '../multi-select/multi-select';\nimport type { OptionShape } from '../_shared/option';\nimport {\n optionDescriptionVariants,\n type OptionDescriptionTone,\n} from '../_shared/option-row';\nimport { Skeleton } from '../skeleton/skeleton';\nimport { Spinner } from '../spinner/spinner';\nimport { EmptyState } from '../empty-state/empty-state';\nimport { StepperAccordion } from '../stepper-accordion/stepper-accordion';\nimport { StepperProgress } from '../stepper-progress/stepper-progress';\nimport type { StepStatus } from '../_shared/stepper';\nimport {\n SlotGrid,\n type SlotGridDay,\n type SlotGridSlot,\n} from '../slot-grid/slot-grid';\n\n/* -------------------------------------------------------------------- */\n/* Re-exports */\n/* */\n/* Public types live in `booking-types.ts` so the cascade engine can */\n/* import them without a circular dep. Re-exported here so consumers */\n/* keep importing from `@alfadocs/ui-kit/booking`. */\n/* -------------------------------------------------------------------- */\n\nexport type {\n BookingCodeStep,\n BookingPaymentSession,\n BookingPaymentState,\n BookingPaymentRenderContext,\n BookingSubmitResult,\n BookingServicePayment,\n BookingResolvedPayment,\n BookingBillingDetails,\n BookingDetails,\n BookingHandle,\n BookingOperator,\n BookingPracticeConsent,\n BookingProps,\n BookingService,\n BookingSlot,\n BookingSpecialty,\n BookingSubmitPayload,\n BookingValidationResult,\n BookingValidator,\n BookingValue,\n BookingVariant,\n ConfirmationChannel,\n InsuranceType,\n} from './booking-types';\nexport { CONFIRMATION_CHANNEL_ORDER } from './booking-types';\nexport { OPERATORS_ALL } from './cascade';\n\n/* -------------------------------------------------------------------- */\n/* Root variant CVA */\n/* -------------------------------------------------------------------- */\n\nconst rootVariants = cva(\n // --booking-held-height: see the step-8 effects (runtime-measured height).\n 'ds:flex ds:w-full ds:flex-col ds:text-[var(--foreground)] ds:[min-block-size:var(--booking-held-height,auto)]',\n {\n variants: {\n variant: {\n 'inline-list': 'ds:gap-[var(--spacing-md)]',\n accordion: 'ds:gap-[var(--spacing-md)]',\n calendar: 'ds:gap-[var(--spacing-md)]',\n flexible: 'ds:gap-[var(--spacing-lg)]',\n progress: 'ds:gap-[var(--spacing-sm)]',\n },\n // `surface=\"elevated\"` matches `Card variant=\"elevated\"` — same\n // tokens, same padding, same boundary behaviour — so consumers can\n // drop their own Card wraps without a double-card look. Default\n // `'flat'` preserves 0.30.x rendering.\n surface: {\n flat: '',\n elevated: [\n 'ds:rounded-[var(--radius-lg)]',\n 'ds:bg-[var(--card)] ds:text-[var(--card-foreground)]',\n 'ds:border ds:border-[color:var(--card-border)]',\n 'ds:shadow-[var(--shadow-card)]',\n 'ds:p-[var(--spacing-md)]',\n ].join(' '),\n },\n },\n defaultVariants: { variant: 'inline-list', surface: 'flat' },\n },\n);\n\n/* -------------------------------------------------------------------- */\n/* Icon inference (kept from 0.25.x — services don't carry an explicit */\n/* icon prop, so we fall back to a keyword-matched Lucide icon). */\n/* -------------------------------------------------------------------- */\n\ntype IconRule = readonly [RegExp, LucideIcon];\n\nconst SERVICE_ICON_RULES: readonly IconRule[] = [\n [\n /\\b(estetic|aesthetic|botox|filler|mesoterap|chirurgia\\s*plastic)/i,\n Syringe,\n ],\n [/\\b(cardio|ecg|elettrocardio|ecocardio|cuore|heart)/i, HeartPulse],\n [/\\b(dent|odonto|tooth|teeth|pulizia|igien|smile)/i, Smile],\n [/\\b(oftalmo|ocul|ophthal|vision|occhi|eye)/i, Eye],\n [/\\b(otorin|udito|orecchi|hearing|ear)/i, Ear],\n [/\\b(neuro|brain|cervello)/i, Brain],\n [/\\b(pediatr|child|bambin)/i, Baby],\n [/\\b(ortop|ortho|osteo|skeleton|ossa|bone)/i, Bone],\n [/\\b(lab|analis|test|sang|esami)/i, Microscope],\n [/\\b(farmaco|pharm|pillol|refill)/i, Pill],\n [/\\b(chirurg|surg|intervent|operat)/i, Scissors],\n [/\\b(scan|rx|x-?ray|raggi|imag|radio|risonan|ecograf|ultras)/i, ScanLine],\n [/\\b(vacc|inject|inie|punto)/i, Syringe],\n [/\\b(derma|skin|pelle)/i, Astroid],\n [/\\b(prima\\s*visit|first\\s*visit|consult|consulto|valutaz)/i, ClipboardCheck],\n [/\\b(general|medicin|family|control|check[-\\s]?up)/i, Activity],\n];\n\nfunction pickIcon(text: string): LucideIcon | null {\n for (const [pattern, Icon] of SERVICE_ICON_RULES) {\n if (pattern.test(text)) return Icon;\n }\n return null;\n}\n\nfunction inferServiceIcon(service: BookingService): ReactNode {\n const Icon = pickIcon(service.label) ?? Stethoscope;\n return <Icon aria-hidden=\"true\" className=\"ds:size-5\" />;\n}\n\n/** A service's picker text, translated. */\ninterface ServiceRowText {\n /** The chip at the row's end: the service's price. */\n price?: string;\n /** The line under the service name: the payment the service requires. */\n payment?: string;\n /** 'error' when that payment cannot be taken. */\n paymentTone: OptionDescriptionTone;\n}\n\n/**\n * Translates {@link servicePickerParts} for every picker style, so the\n * cards, the lists and their accessible names say the same thing. The chip\n * holds the price only, never the payment sentence: a sentence in an\n * uppercase, unwrapping chip squeezed the service name out of the row\n * (HTP-6478).\n */\nfunction useServiceRowText(): (service: BookingService) => ServiceRowText {\n const { t, i18n } = useTranslation('ui');\n return (service) => {\n const parts = servicePickerParts(service);\n const amountOf = (payment: BookingResolvedPayment) =>\n formatPrice(payment.amountCents, payment.currencyCode, i18n.language);\n const price = parts.price\n ? 'label' in parts.price\n ? parts.price.label\n : amountOf(parts.price.amount)\n : undefined;\n if (parts.payment === 'unavailable') {\n return {\n price,\n payment: t('booking.payment.unavailable'),\n paymentTone: 'error',\n };\n }\n return {\n price,\n payment: parts.payment\n ? t(`booking.payment.${parts.payment.kind}`, {\n amount: amountOf(parts.payment),\n })\n : undefined,\n paymentTone: 'default',\n };\n };\n}\n\n/* -------------------------------------------------------------------- */\n/* Shared helpers */\n/* -------------------------------------------------------------------- */\n\nfunction isoOf(date: Date): string {\n return fnsFormat(date, 'yyyy-MM-dd');\n}\n\n/* -------------------------------------------------------------------- */\n/* MonthGrid — inline 6×7 calendar with roving tabindex */\n/* -------------------------------------------------------------------- */\n\ninterface MonthGridProps {\n availableDates: string[];\n selectedDate?: string;\n onSelectDate: (iso: string) => void;\n locale: string;\n loading?: boolean;\n}\n\nconst monthCellBase = [\n 'ds:relative ds:flex ds:items-center ds:justify-center',\n 'ds:min-h-[var(--min-target-size)] ds:min-w-[var(--min-target-size)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:text-[length:var(--font-size-sm)]',\n 'ds:transition-colors ds:duration-[var(--animation-duration)]',\n 'ds:motion-reduce:transition-none',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-visible:outline-[CanvasText]',\n].join(' ');\n\nconst monthCellVariants = cva(monthCellBase, {\n variants: {\n state: {\n available:\n 'ds:cursor-pointer ds:text-[var(--foreground)] ds:hover:bg-[var(--muted)]/30',\n unavailable: 'ds:cursor-not-allowed ds:text-[var(--muted-foreground)]/60',\n selected:\n 'ds:bg-[var(--primary)] ds:text-[var(--primary-foreground)] ds:font-[var(--font-weight-semibold)]',\n outside: 'ds:text-[var(--muted-foreground)]/40',\n },\n },\n defaultVariants: { state: 'unavailable' },\n});\n\nfunction MonthGrid({\n availableDates,\n selectedDate,\n onSelectDate,\n locale,\n loading,\n}: MonthGridProps) {\n const { t } = useTranslation('ui');\n\n const initialMonth = useMemo<Date>(() => {\n if (selectedDate) return startOfMonth(parseISO(selectedDate));\n if (availableDates.length > 0) {\n return startOfMonth(parseISO(availableDates[0]));\n }\n return startOfMonth(new Date());\n }, [selectedDate, availableDates]);\n\n const [viewMonth, setViewMonth] = useState<Date>(initialMonth);\n const [focusDate, setFocusDate] = useState<Date | null>(null);\n\n const cells = useMemo(() => {\n const monthStart = startOfMonth(viewMonth);\n const monthEnd = endOfMonth(viewMonth);\n const startWeekday = monthStart.getDay();\n const totalDays = monthEnd.getDate();\n const grid: Date[] = [];\n for (let i = startWeekday; i > 0; i -= 1) {\n const d = new Date(monthStart);\n d.setDate(monthStart.getDate() - i);\n grid.push(d);\n }\n for (let i = 0; i < totalDays; i += 1) {\n const d = new Date(monthStart);\n d.setDate(monthStart.getDate() + i);\n grid.push(d);\n }\n while (grid.length < 42) {\n const last = grid[grid.length - 1];\n const d = new Date(last);\n d.setDate(last.getDate() + 1);\n grid.push(d);\n }\n return grid;\n }, [viewMonth]);\n\n const monthLabel = useMemo(() => {\n try {\n return new Intl.DateTimeFormat(locale, {\n month: 'long',\n year: 'numeric',\n }).format(viewMonth);\n } catch {\n return fnsFormat(viewMonth, 'MMMM yyyy');\n }\n }, [viewMonth, locale]);\n\n const weekdayLabels = useMemo(() => {\n const base = new Date(2024, 0, 7);\n return Array.from({ length: 7 }, (_, i) => {\n const d = new Date(base);\n d.setDate(base.getDate() + i);\n try {\n return new Intl.DateTimeFormat(locale, { weekday: 'short' }).format(d);\n } catch {\n return fnsFormat(d, 'EEE');\n }\n });\n }, [locale]);\n\n const availableSet = useMemo(() => new Set(availableDates), [availableDates]);\n const isAvailable = useCallback(\n (date: Date) => availableSet.has(isoOf(date)),\n [availableSet],\n );\n\n const rovingDate = useMemo<Date | null>(() => {\n if (focusDate) return focusDate;\n if (selectedDate) return parseISO(selectedDate);\n const firstAvailable = cells.find(\n (d) => isSameMonth(d, viewMonth) && isAvailable(d),\n );\n if (firstAvailable) return firstAvailable;\n return cells.find((d) => isSameMonth(d, viewMonth)) ?? null;\n }, [focusDate, selectedDate, cells, viewMonth, isAvailable]);\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLButtonElement>, current: Date) => {\n let next: Date | null = null;\n switch (event.key) {\n case 'ArrowLeft':\n next = new Date(current);\n next.setDate(current.getDate() - 1);\n break;\n case 'ArrowRight':\n next = new Date(current);\n next.setDate(current.getDate() + 1);\n break;\n case 'ArrowUp':\n next = new Date(current);\n next.setDate(current.getDate() - 7);\n break;\n case 'ArrowDown':\n next = new Date(current);\n next.setDate(current.getDate() + 7);\n break;\n case 'Home':\n next = new Date(current);\n next.setDate(current.getDate() - current.getDay());\n break;\n case 'End':\n next = new Date(current);\n next.setDate(current.getDate() + (6 - current.getDay()));\n break;\n case 'Enter':\n case ' ': {\n event.preventDefault();\n if (isAvailable(current)) onSelectDate(isoOf(current));\n return;\n }\n default:\n return;\n }\n if (!next) return;\n event.preventDefault();\n if (!isSameMonth(next, viewMonth)) {\n setViewMonth(startOfMonth(next));\n }\n setFocusDate(next);\n },\n [isAvailable, onSelectDate, viewMonth],\n );\n\n if (loading) {\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n aria-label={t('common.loading')}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n <Skeleton variant=\"text\" width=\"40%\" />\n <div className=\"ds:grid ds:grid-cols-7 ds:gap-[var(--spacing-2xs)]\">\n {Array.from({ length: 42 }, (_, i) => (\n <Skeleton key={`mg-skel-${i}`} variant=\"rounded\" height=\"2.5rem\" />\n ))}\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n <div className=\"ds:flex ds:items-center ds:justify-between ds:gap-[var(--spacing-sm)]\">\n <IconButton\n icon={<ChevronLeft />}\n aria-label={t('booking.previousMonth')}\n size=\"sm\"\n intent=\"ghost\"\n flipIconInRtl\n onClick={() => {\n setViewMonth((m) => subMonths(m, 1));\n setFocusDate(null);\n }}\n />\n <span\n className=\"type-label ds:font-[var(--font-weight-semibold)] ds:text-[var(--foreground)]\"\n aria-live=\"polite\"\n >\n {monthLabel}\n </span>\n <IconButton\n icon={<ChevronRight />}\n aria-label={t('booking.nextMonth')}\n size=\"sm\"\n intent=\"ghost\"\n flipIconInRtl\n onClick={() => {\n setViewMonth((m) => addMonths(m, 1));\n setFocusDate(null);\n }}\n />\n </div>\n <div\n role=\"grid\"\n aria-label={t('booking.monthGridLabel')}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\"\n >\n <div\n role=\"row\"\n className=\"ds:grid ds:grid-cols-7 ds:gap-[var(--spacing-2xs)]\"\n >\n {weekdayLabels.map((label, i) => (\n <div\n key={`wd-${i}`}\n role=\"columnheader\"\n className=\"type-meta ds:text-center ds:text-[var(--muted-foreground)] ds:font-[var(--font-weight-medium)]\"\n >\n {label}\n </div>\n ))}\n </div>\n {Array.from({ length: 6 }, (_, rowIndex) => (\n <div\n key={`mg-row-${rowIndex}`}\n role=\"row\"\n className=\"ds:grid ds:grid-cols-7 ds:gap-[var(--spacing-2xs)]\"\n >\n {cells\n .slice(rowIndex * 7, rowIndex * 7 + 7)\n .map((date, colIndex) => {\n const i = rowIndex * 7 + colIndex;\n const inMonth = isSameMonth(date, viewMonth);\n const available = inMonth && isAvailable(date);\n const isSelected = selectedDate\n ? isSameDay(date, parseISO(selectedDate))\n : false;\n const state:\n | 'available'\n | 'unavailable'\n | 'selected'\n | 'outside' = !inMonth\n ? 'outside'\n : isSelected\n ? 'selected'\n : available\n ? 'available'\n : 'unavailable';\n const isRoving = rovingDate\n ? isSameDay(rovingDate, date)\n : false;\n const dayLabel = (() => {\n try {\n return new Intl.DateTimeFormat(locale, {\n dateStyle: 'full',\n }).format(date);\n } catch {\n return fnsFormat(date, 'PPP');\n }\n })();\n return (\n <button\n key={`mg-cell-${i}`}\n type=\"button\"\n role=\"gridcell\"\n aria-label={dayLabel}\n aria-selected={isSelected || undefined}\n aria-disabled={!available || undefined}\n tabIndex={isRoving ? 0 : -1}\n disabled={!available}\n onClick={() => {\n if (available) onSelectDate(isoOf(date));\n }}\n onKeyDown={(e) => handleKeyDown(e, date)}\n className={monthCellVariants({ state })}\n >\n <span aria-hidden=\"true\">{date.getDate()}</span>\n </button>\n );\n })}\n </div>\n ))}\n </div>\n </div>\n );\n}\n\n/* -------------------------------------------------------------------- */\n/* ServiceCardGroup — hand-rolled radiogroup for service selection. */\n/* */\n/* Used by the `inline-list` variant where services render as full-row */\n/* cards with the inferred icon. Other variants use a Select dropdown */\n/* via `ServiceStep` below. */\n/* -------------------------------------------------------------------- */\n\nconst serviceCardVariants = cva(\n [\n 'ds:relative ds:flex ds:w-full ds:items-center ds:gap-[var(--spacing-md)]',\n 'ds:min-h-[var(--min-target-size)]',\n 'ds:rounded-[var(--radius-md)]',\n 'ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)]',\n 'ds:pt-[var(--spacing-sm)] ds:pb-[var(--spacing-sm)]',\n 'ds:text-start',\n 'ds:transition-[background-color,box-shadow]',\n 'ds:duration-[var(--animation-duration)]',\n 'ds:motion-reduce:transition-none',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:[outline:1px_solid_CanvasText]',\n 'ds:cursor-pointer',\n ].join(' '),\n {\n variants: {\n state: {\n idle: 'ds:bg-[var(--card)] ds:shadow-[var(--shadow-sm)] ds:hover:shadow-[var(--shadow-md)]',\n selected:\n 'ds:bg-[color-mix(in_srgb,var(--primary)_8%,var(--card))] ds:shadow-[var(--shadow-sm)]',\n },\n },\n defaultVariants: { state: 'idle' },\n },\n);\n\ninterface ServiceCardGroupProps {\n services: BookingService[];\n selectedServiceId?: string;\n onSelect: (id: string) => void;\n /** False: a service with no price shows its name only, never its minutes. */\n showDuration: boolean;\n}\n\nfunction ServiceCardGroup({\n services,\n selectedServiceId,\n onSelect,\n showDuration,\n}: ServiceCardGroupProps) {\n const { t } = useTranslation('ui');\n const rowText = useServiceRowText();\n const groupId = useId();\n\n const [focusIndex, setFocusIndex] = useState<number>(() => {\n if (selectedServiceId) {\n const i = services.findIndex((s) => s.id === selectedServiceId);\n if (i >= 0) return i;\n }\n return 0;\n });\n\n const cardRefs = useRef<Map<number, HTMLButtonElement>>(new Map());\n const focusAt = useCallback((index: number) => {\n cardRefs.current.get(index)?.focus();\n }, []);\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLButtonElement>, index: number, id: string) => {\n const total = services.length;\n if (total === 0) return;\n switch (event.key) {\n case 'ArrowDown':\n case 'ArrowRight': {\n event.preventDefault();\n const next = (index + 1) % total;\n setFocusIndex(next);\n focusAt(next);\n break;\n }\n case 'ArrowUp':\n case 'ArrowLeft': {\n event.preventDefault();\n const prev = (index - 1 + total) % total;\n setFocusIndex(prev);\n focusAt(prev);\n break;\n }\n case 'Home': {\n event.preventDefault();\n setFocusIndex(0);\n focusAt(0);\n break;\n }\n case 'End': {\n event.preventDefault();\n const last = total - 1;\n setFocusIndex(last);\n focusAt(last);\n break;\n }\n case 'Enter':\n case ' ': {\n event.preventDefault();\n onSelect(id);\n break;\n }\n default:\n break;\n }\n },\n [services.length, focusAt, onSelect],\n );\n\n if (services.length === 0) {\n return null;\n }\n\n return (\n <div\n role=\"radiogroup\"\n aria-label={t('booking.serviceListLabel')}\n id={groupId}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n {services.map((service, index) => {\n const isSelected = selectedServiceId === service.id;\n const isFocused = focusIndex === index;\n const { price, payment, paymentTone } = rowText(service);\n // The name says everything the card shows, in reading order: the\n // service, its price, then the payment it requires.\n const ariaLabel = price\n ? payment\n ? t('booking.serviceCardLabelPayment', {\n label: service.label,\n price,\n payment,\n })\n : t('booking.serviceCardLabelPrice', {\n label: service.label,\n price,\n })\n : payment\n ? t('booking.serviceCardLabelPaymentNoPrice', {\n label: service.label,\n payment,\n })\n : showDuration\n ? t('booking.serviceCardLabel', {\n label: service.label,\n duration: service.durationMin,\n })\n : service.label;\n const iconNode = inferServiceIcon(service);\n return (\n <button\n key={service.id}\n ref={(node) => {\n if (node) cardRefs.current.set(index, node);\n else cardRefs.current.delete(index);\n }}\n type=\"button\"\n role=\"radio\"\n aria-checked={isSelected}\n aria-label={ariaLabel}\n tabIndex={isFocused ? 0 : -1}\n onClick={() => onSelect(service.id)}\n onFocus={() => setFocusIndex(index)}\n onKeyDown={(e) => handleKeyDown(e, index, service.id)}\n className={serviceCardVariants({\n state: isSelected ? 'selected' : 'idle',\n })}\n >\n <span\n aria-hidden=\"true\"\n className=\"ds:flex ds:size-10 ds:shrink-0 ds:items-center ds:justify-center ds:rounded-[var(--radius-sm)] ds:bg-[var(--primary)]/10 ds:text-[var(--primary)]\"\n >\n {iconNode}\n </span>\n <span className=\"ds:flex ds:min-w-0 ds:flex-1 ds:flex-col ds:gap-[var(--spacing-2xs)]\">\n {/* The practice's service name keeps the direction it was\n typed in, not the page's. */}\n <span\n dir=\"auto\"\n className=\"type-label ds:font-[var(--font-weight-semibold)] ds:text-[var(--foreground)] ds:break-words\"\n >\n {service.label}\n </span>\n {/* The payment a service requires reads under its name, and\n wraps. Otherwise only the duration fallback stays here: a\n price leaves the column so it can pin to the end of the\n card, see below. */}\n {payment ? (\n <span\n className={optionDescriptionVariants({ tone: paymentTone })}\n >\n {payment}\n </span>\n ) : price || !showDuration ? null : (\n <span className=\"type-meta ds:text-[var(--muted-foreground)]\">\n {t('booking.serviceSummary', {\n minutes: service.durationMin,\n })}\n </span>\n )}\n </span>\n {/* The price is the figure a patient compares between\n services, so it gets a chip at a fixed inline-end\n position rather than trailing a name of variable\n length.\n\n `aria-hidden` because the button's own `aria-label`\n already carries the price, making the chip redundant to\n assistive tech. Note `aria-label` REPLACES the subtree in\n name computation, so this is belt-and-braces for verbose\n and browse modes rather than the only thing preventing a\n double announcement. The pairing is load-bearing in the\n other direction though: both this chip and that label are\n gated on the same `price` const, so the price can never be\n hidden here without also being present there. */}\n {price ? (\n <span\n aria-hidden=\"true\"\n className=\"ds:inline-flex ds:shrink-0 ds:items-center ds:ms-auto\"\n >\n <Badge variant=\"accentSoft\" size=\"lg\">\n {price}\n </Badge>\n </span>\n ) : null}\n </button>\n );\n })}\n </div>\n );\n}\n\n/* -------------------------------------------------------------------- */\n/* GroupedTimeSlots — calendar variant's morning/afternoon/evening slots */\n/* -------------------------------------------------------------------- */\n\nconst slotChipVariants = cva(\n [\n 'ds:inline-flex ds:items-center ds:justify-center ds:gap-[var(--spacing-2xs)]',\n 'ds:min-h-[var(--min-target-size)]',\n 'ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)]',\n 'ds:pt-[var(--spacing-2xs)] ds:pb-[var(--spacing-2xs)]',\n 'ds:rounded-[var(--radius-md)]',\n 'ds:text-[length:var(--font-size-sm)] ds:font-[var(--font-weight-medium)]',\n 'ds:transition-[background-color,color,box-shadow] ds:duration-[var(--animation-duration)]',\n 'ds:motion-reduce:transition-none',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[color:var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:disabled:cursor-not-allowed ds:disabled:opacity-50',\n 'ds:forced-colors:[border:1px_solid_ButtonText] ds:forced-colors:text-[ButtonText]',\n ].join(' '),\n {\n variants: {\n state: {\n idle: 'ds:bg-[color:var(--card)] ds:text-[color:var(--foreground)] ds:shadow-[var(--shadow-sm)] ds:hover:enabled:bg-[color:var(--muted)]/40 ds:hover:enabled:shadow-[var(--shadow-md)]',\n selected:\n 'ds:bg-[color:var(--primary)] ds:text-[color:var(--primary-foreground)] ds:shadow-[var(--shadow-sm)]',\n unavailable:\n 'ds:[outline:1px_dashed_color:var(--border)] ds:[outline-offset:-1px] ds:bg-transparent ds:text-[color:var(--muted-foreground)]',\n },\n },\n defaultVariants: { state: 'idle' },\n },\n);\n\ntype TimeOfDay = 'morning' | 'afternoon' | 'evening';\n\nfunction bucketForTime(time: string): TimeOfDay {\n const [hh] = time.split(':').map((s) => parseInt(s, 10));\n const hour = Number.isFinite(hh) ? hh : 0;\n if (hour < 12) return 'morning';\n if (hour < 17) return 'afternoon';\n return 'evening';\n}\n\n/**\n * A slot's `HH:mm` in the reader's locale, formatted as SlotGrid does\n * (`2:30 PM` in English, `14:30` in Italian). Falls back to the raw\n * value when the date is missing or the pair does not parse.\n */\nfunction formatClockTime(\n date: string | undefined,\n time: string,\n locale: string,\n): string {\n if (!date) return time;\n try {\n return new Intl.DateTimeFormat(locale, {\n hour: 'numeric',\n minute: '2-digit',\n }).format(new Date(`${date}T${time}:00`));\n } catch {\n return time;\n }\n}\n\nconst BUCKET_ICONS: Record<TimeOfDay, LucideIcon> = {\n morning: Sun,\n afternoon: Sunset,\n evening: Moon,\n};\n\ninterface GroupedTimeSlotsProps {\n date: string;\n slots: BookingSlot[];\n selectedSlotKey?: string;\n onSelect: (slot: BookingSlot) => void;\n loading?: boolean;\n locale: string;\n}\n\nfunction GroupedTimeSlots({\n date,\n slots,\n selectedSlotKey,\n onSelect,\n loading,\n locale,\n}: GroupedTimeSlotsProps) {\n const { t } = useTranslation('ui');\n\n const dateLabel = useMemo(() => {\n try {\n return new Intl.DateTimeFormat(locale, {\n weekday: 'long',\n day: 'numeric',\n month: 'long',\n }).format(parseISO(date));\n } catch {\n return date;\n }\n }, [date, locale]);\n\n const groups = useMemo(() => {\n const result: Record<TimeOfDay, BookingSlot[]> = {\n morning: [],\n afternoon: [],\n evening: [],\n };\n for (const slot of slots) {\n result[bucketForTime(slot.time)].push(slot);\n }\n return result;\n }, [slots]);\n\n const availableCount = slots.filter((s) => s.available).length;\n const order: TimeOfDay[] = ['morning', 'afternoon', 'evening'];\n\n if (loading) {\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n <Skeleton variant=\"text\" width=\"60%\" />\n {[0, 1].map((row) => (\n <div\n key={row}\n className=\"ds:grid ds:grid-cols-3 ds:gap-[var(--spacing-xs)]\"\n >\n {[0, 1, 2].map((c) => (\n <Skeleton key={c} variant=\"rounded\" height=\"44px\" />\n ))}\n </div>\n ))}\n </div>\n );\n }\n\n if (availableCount === 0) {\n return (\n <EmptyState variant=\"no-results\" title={t('booking.noSlotsForDate')} />\n );\n }\n\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n <div className=\"ds:flex ds:items-baseline ds:justify-between ds:gap-[var(--spacing-sm)]\">\n <div className=\"ds:flex ds:items-center ds:gap-[var(--spacing-xs)]\">\n <CalendarRange\n aria-hidden=\"true\"\n className=\"ds:size-4 ds:text-[color:var(--accent)]\"\n />\n <h3 className=\"type-label ds:font-[var(--font-weight-semibold)] ds:text-[var(--foreground)] ds:m-0\">\n {dateLabel}\n </h3>\n </div>\n <span className=\"type-meta ds:text-[var(--muted-foreground)]\">\n {t('booking.slotsAvailable', { count: availableCount })}\n </span>\n </div>\n {order.map((bucket) => {\n const items = groups[bucket];\n if (items.length === 0) return null;\n const Icon = BUCKET_ICONS[bucket];\n return (\n <div\n key={bucket}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\"\n >\n <div className=\"ds:flex ds:items-center ds:gap-[var(--spacing-xs)] ds:text-[color:var(--muted-foreground)]\">\n <Icon aria-hidden=\"true\" className=\"ds:size-3.5\" />\n <span className=\"type-meta ds:font-[var(--font-weight-semibold)] ds:uppercase\">\n {t(`booking.timeOfDay.${bucket}`)}\n </span>\n </div>\n <div\n role=\"group\"\n aria-label={t(`booking.timeOfDay.${bucket}`)}\n className=\"ds:grid ds:grid-cols-3 ds:gap-[var(--spacing-xs)] ds:sm:grid-cols-4\"\n >\n {items.map((slot) => {\n const isSelected = slot.key === selectedSlotKey;\n const state = !slot.available\n ? 'unavailable'\n : isSelected\n ? 'selected'\n : 'idle';\n return (\n <button\n key={slot.key}\n type=\"button\"\n data-slot-id={slot.key}\n disabled={!slot.available}\n aria-pressed={isSelected}\n aria-label={t('booking.slotAvailableLabel', {\n time: formatClockTime(date, slot.time, locale),\n })}\n onClick={() => slot.available && onSelect(slot)}\n className={slotChipVariants({ state })}\n >\n {formatClockTime(date, slot.time, locale)}\n </button>\n );\n })}\n </div>\n </div>\n );\n })}\n </div>\n );\n}\n\n/* -------------------------------------------------------------------- */\n/* FourDayPicker — adapter for `datePickerStyle='four-day-grid'` */\n/* */\n/* Thin wrapper around the kit's `<SlotGrid>` primitive that translates */\n/* Booking's data shape (`availableDates`, `availableSlots`, `value`) */\n/* into the SlotGrid `days` array, and back from SlotGrid's `onSlotSelect`*/\n/* into Booking's atomic date+slot onChange. Window of 4 days, ±4-day */\n/* arrow navigation, \"Show more\" expander at 6 slots (matches prod). */\n/* */\n/* Slot selection sets `value.date` and `value.slotKey` atomically (one */\n/* onChange call composing resetOnDateChange + resetOnSlotChange). That */\n/* matches the prod UX where a user clicks a tile directly without a */\n/* separate date pick. `onDateSelect` fires alongside so consumers using */\n/* the two-query lazy-load pattern get the same signal as the month- */\n/* calendar picker. The cascade's separate \"slot\" step is suppressed */\n/* (see `renderSlotStep`) because the slots are inline with the strip. */\n/* -------------------------------------------------------------------- */\n\nconst FOUR_DAY_WINDOW_SIZE = 4;\n\ninterface FourDayPickerProps {\n availableDates: string[];\n availableSlots: Record<string, BookingSlot[]>;\n value: BookingValue;\n onChange: (next: BookingValue) => void;\n onDateSelect?: (iso: string) => void;\n onWindowChange?: (startIso: string, endIso: string) => void;\n loadingDates?: boolean;\n loadingSlots?: boolean;\n locale: string;\n agentIdBase?: string;\n}\n\nfunction FourDayPicker({\n availableDates,\n availableSlots,\n value,\n onChange,\n onDateSelect,\n onWindowChange,\n loadingDates,\n loadingSlots,\n locale,\n agentIdBase,\n}: FourDayPickerProps) {\n const today = useMemo(() => startOfDay(new Date()), []);\n\n // Initial window: snap to value.date if set and not in the past;\n // otherwise to the first availableDate when it's in the future;\n // otherwise today. Saves the user from manually advancing 4-day\n // chunks when availability is days or weeks out.\n const [windowStart, setWindowStart] = useState<Date>(() => {\n if (value.date) {\n const d = startOfDay(parseISO(value.date));\n if (!isAfter(today, d)) return d;\n }\n if (availableDates.length > 0) {\n const first = startOfDay(parseISO(availableDates[0]));\n if (isAfter(first, today)) return first;\n }\n return today;\n });\n\n const windowEnd = useMemo(\n () => addDays(windowStart, FOUR_DAY_WINDOW_SIZE - 1),\n [windowStart],\n );\n\n // Build the SlotGrid days array — one entry per visible calendar\n // day in the 4-day window. Columns without availability render as\n // empty columns (SlotGrid handles the \"no slots\" rendering itself).\n const days = useMemo<SlotGridDay[]>(() => {\n return Array.from({ length: FOUR_DAY_WINDOW_SIZE }, (_, i) => {\n const d = addDays(windowStart, i);\n const iso = isoOf(d);\n const bookingSlots = availableSlots[iso] ?? [];\n const slots: SlotGridSlot[] = bookingSlots.map((s) => ({\n id: s.key,\n // SlotGrid formats `start` as a time via Intl.DateTimeFormat —\n // compose a full ISO from the column's date + the slot's HH:mm\n // so the locale-formatter has a real timestamp to work with.\n start: `${iso}T${s.time}:00`,\n available: s.available,\n }));\n return { date: iso, slots };\n });\n }, [windowStart, availableSlots]);\n\n const hasPrevious = isAfter(windowStart, today);\n // 0.33.11: forward navigation is unconditional. With two-query\n // consumers, `availableDates` reflects only what's been fetched —\n // gating on it would lock the user out of exploring further\n // windows the consumer hasn't fetched yet. `onWindowChange` lets\n // the consumer lazy-load as the user advances; the \"no slots in\n // window\" state is handled by the next-available banner (fix 2).\n const hasNext = true;\n\n const handlePreviousDays = useCallback(() => {\n setWindowStart((prev) => {\n const next = subDays(prev, FOUR_DAY_WINDOW_SIZE);\n // Clamp at today so the strip never shows past dates.\n return isAfter(today, next) ? today : next;\n });\n }, [today]);\n\n const handleNextDays = useCallback(() => {\n setWindowStart((prev) => addDays(prev, FOUR_DAY_WINDOW_SIZE));\n }, []);\n\n // Fix 1 (0.33.11): re-sync windowStart when availableDates arrives.\n // Two-query consumers ship [] on first render and the real list\n // arrives a frame later — the useState initialiser has already\n // locked windowStart at today and the picker shows today..today+3\n // empty even when the summary returned dates starting day+7.\n //\n // Only snap when the current window has zero overlap with\n // availability AND the first available date is in the future. The\n // overlap check (any availableDate inside [windowStart..windowEnd])\n // preserves user navigation — once they've advanced past the first\n // available date to look further out, we don't yank them back.\n useEffect(() => {\n if (availableDates.length === 0) return;\n const firstAvailable = startOfDay(parseISO(availableDates[0]));\n if (!isAfter(firstAvailable, today)) return;\n const overlaps = availableDates.some((iso) => {\n const d = startOfDay(parseISO(iso));\n return !isAfter(d, windowEnd) && !isBefore(d, windowStart);\n });\n if (overlaps) return;\n setWindowStart(firstAvailable);\n // Intentionally omits windowStart / windowEnd / today — react\n // only to new availability lists. Re-snapping every time the\n // window moves would trap the user inside the first-available\n // 4-day chunk.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [availableDates]);\n\n // Fix 3 (0.33.11): notify two-query consumers whenever the\n // visible window starts or shifts so they can lazy-fetch\n // dailySlots/{date} for the now-visible dates. Fires on mount\n // with the resolved initial window, then on every prev/next\n // arrow click, the fix-1 auto-sync, and the fix-2 jump CTA.\n useEffect(() => {\n onWindowChange?.(isoOf(windowStart), isoOf(windowEnd));\n }, [windowStart, windowEnd, onWindowChange]);\n\n const handleSlotSelect = useCallback(\n (slot: SlotGridSlot, day: SlotGridDay) => {\n const dateIso = typeof day.date === 'string' ? day.date : isoOf(day.date);\n // Atomic: set date + slot in one onChange so cascade.gates.slot\n // observes both together. Without this the consumer would see\n // two renders (date set, then slotKey set) which can re-fire\n // analytics / loading effects unnecessarily.\n onChange({\n ...resetOnSlotChange(resetOnDateChange(value, dateIso), slot.id),\n });\n onDateSelect?.(dateIso);\n },\n [onChange, onDateSelect, value],\n );\n\n // SlotGrid has a single loading state — either flag triggers the\n // shimmer (granular per-header vs per-tile shimmer would require\n // a SlotGrid API extension; treating both as one loading state\n // already satisfies the 0.33.9 split for two-query consumers since\n // only one of the two flags is set at a time in that pattern).\n const state: 'default' | 'loading' =\n loadingDates || loadingSlots ? 'loading' : 'default';\n\n // Fix 2 (0.33.11): \"Next available\" banner above the SlotGrid\n // when the visible window has no slots but the consumer told us\n // availability exists somewhere. Covers two cases the original\n // picker had no recovery for: (a) the user hasn't yet reached\n // the first available date (window is BEFORE availability), and\n // (b) the user advanced past availability (window is AFTER all\n // known available dates). Both render the same banner pointing\n // back to `availableDates[0]` with a jump button.\n //\n // The SlotGrid itself stays mounted so the column headers remain\n // visible — the banner sits above as the recovery affordance.\n const visibleWindowHasSlots = days.some((d) => d.slots.length > 0);\n const firstAvailableIso = availableDates[0];\n // Not while loading: the visible days' times may still be on their way,\n // and the banner would flash \"no openings\" before they arrive.\n const showJumpCta =\n state !== 'loading' && !visibleWindowHasSlots && !!firstAvailableIso;\n\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n {showJumpCta ? (\n <NextAvailableCta\n nextAvailableDate={firstAvailableIso}\n onJump={() => setWindowStart(startOfDay(parseISO(firstAvailableIso)))}\n locale={locale}\n />\n ) : null}\n <SlotGrid\n id={agentIdBase ? `${agentIdBase}-slots` : undefined}\n days={days}\n state={state}\n selectedSlotId={value.slotKey}\n maxInitialSlotsPerDay={6}\n locale={locale}\n hasPrevious={hasPrevious}\n hasNext={hasNext}\n onSlotSelect={handleSlotSelect}\n onPreviousDays={handlePreviousDays}\n onNextDays={handleNextDays}\n />\n </div>\n );\n}\n\n/* -------------------------------------------------------------------- */\n/* renderDateStep / renderSlotStep — variant-agnostic picker renderers */\n/* */\n/* Both InlineListBody and getStepNode (the cascade-variant body shared */\n/* renderer) call these helpers instead of inlining `<MonthGrid>` / */\n/* `<GroupedTimeSlots>`. Switches on `datePickerStyle`: */\n/* */\n/* - 'month-calendar' (default): MonthGrid for date, GroupedTimeSlots */\n/* for slot. Byte-identical to pre-0.33.10 behaviour. */\n/* - 'four-day-grid': FourDayPicker for date (slots embedded); */\n/* renderSlotStep returns null since slots are inline. */\n/* -------------------------------------------------------------------- */\n\ninterface DateStepRenderProps {\n inputs: VariantBodyProps['inputs'];\n value: BookingValue;\n onChange: (next: BookingValue) => void;\n onDateSelect?: (iso: string) => void;\n onWindowChange?: (startIso: string, endIso: string) => void;\n loadingDates?: boolean;\n loadingSlots?: boolean;\n locale: string;\n datePickerStyle: 'month-calendar' | 'four-day-grid';\n agentIdBase?: string;\n}\n\nfunction renderDateStep(props: DateStepRenderProps): ReactNode {\n const {\n inputs,\n value,\n onChange,\n onDateSelect,\n onWindowChange,\n loadingDates,\n loadingSlots,\n locale,\n datePickerStyle,\n agentIdBase,\n } = props;\n if (datePickerStyle === 'four-day-grid') {\n return (\n <FourDayPicker\n availableDates={inputs.availableDates}\n availableSlots={inputs.availableSlots}\n value={value}\n onChange={onChange}\n onDateSelect={onDateSelect}\n onWindowChange={onWindowChange}\n loadingDates={loadingDates}\n loadingSlots={loadingSlots}\n locale={locale}\n agentIdBase={agentIdBase}\n />\n );\n }\n return (\n <MonthGrid\n availableDates={inputs.availableDates}\n selectedDate={value.date}\n onSelectDate={(iso) => {\n onChange(resetOnDateChange(value, iso));\n onDateSelect?.(iso);\n }}\n locale={locale}\n loading={loadingDates ?? loadingSlots}\n />\n );\n}\n\nfunction renderSlotStep(props: DateStepRenderProps): ReactNode {\n const { inputs, value, onChange, loadingSlots, locale, datePickerStyle } =\n props;\n // four-day-grid embeds the slot tiles inside the picker itself —\n // no separate slot block needed in the variant body.\n if (datePickerStyle === 'four-day-grid') return null;\n if (!value.date) return null;\n return (\n <GroupedTimeSlots\n date={value.date}\n slots={inputs.availableSlots[value.date] ?? []}\n selectedSlotKey={value.slotKey}\n onSelect={(slot) => onChange(resetOnSlotChange(value, slot.key))}\n loading={loadingSlots}\n locale={locale}\n />\n );\n}\n\n/* -------------------------------------------------------------------- */\n/* Step subcomponents */\n/* */\n/* Each step is rendered by every variant that needs it. The variants */\n/* differ in layout (chip rail vs accordion vs vertical list) but the */\n/* step content itself is the same. */\n/* -------------------------------------------------------------------- */\n\ninterface InsuranceStepProps {\n value?: InsuranceType;\n onChange: (next: InsuranceType) => void;\n}\n\nfunction InsuranceStep({ value, onChange }: InsuranceStepProps) {\n const { t } = useTranslation('ui');\n const options: SelectOption[] = [\n { value: 'private', label: t('booking.insurance.private') },\n { value: 'public', label: t('booking.insurance.public') },\n ];\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n <h3 className=\"type-label ds:font-[var(--font-weight-semibold)] ds:text-[var(--foreground)] ds:m-0\">\n {t('booking.insurance.heading')}\n </h3>\n <Select\n options={options}\n value={value ?? ''}\n onValueChange={(next) => {\n if (next === 'private' || next === 'public') onChange(next);\n }}\n placeholder={t('booking.insurance.placeholder')}\n aria-label={t('booking.insurance.heading')}\n />\n </div>\n );\n}\n\ninterface SpecialtyStepProps {\n specialties: BookingSpecialty[];\n value?: string;\n valueIds?: string[];\n onChange: (next: string) => void;\n onChangeIds?: (next: string[]) => void;\n pickerStyle?: 'select' | 'combobox' | 'multi-select';\n}\n\nfunction SpecialtyStep({\n specialties,\n value,\n valueIds,\n onChange,\n onChangeIds,\n pickerStyle = 'select',\n}: SpecialtyStepProps) {\n const { t } = useTranslation('ui');\n // Specialty, service and professional names are the practice's own\n // text: `dir: 'auto'` keeps the direction they were typed in.\n const options: OptionShape[] = specialties.map((s) => ({\n value: s.id,\n label: s.label,\n dir: 'auto',\n }));\n const heading = (\n <h3 className=\"type-label ds:font-[var(--font-weight-semibold)] ds:text-[var(--foreground)] ds:m-0\">\n {t('booking.specialty.heading')}\n </h3>\n );\n if (pickerStyle === 'multi-select' && onChangeIds) {\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n {heading}\n <MultiSelect\n options={options}\n value={valueIds ?? []}\n onChange={onChangeIds}\n placeholder={t('booking.specialty.placeholder')}\n aria-label={t('booking.specialty.heading')}\n allowClear\n />\n </div>\n );\n }\n if (pickerStyle === 'combobox') {\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n {heading}\n <Combobox\n options={options}\n value={value ?? ''}\n onValueChange={(next) => onChange(next === '' ? '' : next)}\n placeholder={t('booking.specialty.placeholder')}\n aria-label={t('booking.specialty.heading')}\n clearable\n />\n </div>\n );\n }\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n {heading}\n <Select\n options={options as SelectOption[]}\n value={value ?? ''}\n onValueChange={(next) => onChange(next)}\n placeholder={t('booking.specialty.placeholder')}\n aria-label={t('booking.specialty.heading')}\n />\n </div>\n );\n}\n\ninterface ServiceStepProps {\n services: BookingService[];\n value?: string;\n valueIds?: string[];\n onChange: (next: string) => void;\n onChangeIds?: (next: string[]) => void;\n /**\n * 0.34.0: explicit picker style. When undefined, falls back to the\n * `compact` boolean (true → 'select', false → 'cards') so existing\n * variant-body code continues to work unchanged.\n */\n pickerStyle?: 'select' | 'combobox' | 'multi-select' | 'cards';\n /** @deprecated 0.34.0 — pass `pickerStyle='cards'` (default) or `'select'` instead. */\n compact?: boolean;\n /** Booking's `showServiceDuration`. */\n showDuration: boolean;\n}\n\nfunction ServiceStep({\n services,\n value,\n valueIds,\n onChange,\n onChangeIds,\n pickerStyle,\n compact,\n showDuration,\n}: ServiceStepProps) {\n const { t } = useTranslation('ui');\n const rowText = useServiceRowText();\n const resolvedStyle = pickerStyle ?? (compact ? 'select' : 'cards');\n // A priced service puts the price in `endContent`, so it renders as a\n // chip pinned to the row's end and the label stays just the service\n // name. `endContent` is not aria-hidden, so the price still reaches\n // the option's accessible name — it must NOT also be repeated in\n // `label` or it is announced twice.\n //\n // The payment a service requires is its `description`: a second line\n // under the name, which wraps, and which every picker reads after the\n // label and the price (Select through `descriptionInName`). The name\n // itself may wrap to two lines (`wrapOptionLabels`) rather than lose\n // its end to an ellipsis on a phone.\n //\n // A service with neither keeps the duration appended to the label as\n // before: it is a fallback, not the comparable figure, so it does not\n // earn a chip. With `showDuration` off it is the service name alone.\n const options: OptionShape[] = services.map((s) => {\n const { price, payment, paymentTone } = rowText(s);\n return {\n value: s.id,\n // The practice's service name leads the label, so it decides the\n // direction, even when the kit's duration is appended after it.\n dir: 'auto',\n label:\n price || payment || !showDuration\n ? s.label\n : `${s.label} · ${t('booking.serviceSummary', {\n minutes: s.durationMin,\n })}`,\n ...(price\n ? {\n endContent: (\n <Badge variant=\"accentSoft\" size=\"lg\">\n {price}\n </Badge>\n ),\n }\n : {}),\n ...(payment\n ? { description: payment, descriptionTone: paymentTone }\n : {}),\n };\n });\n const heading = (\n <h3 className=\"type-label ds:font-[var(--font-weight-semibold)] ds:text-[var(--foreground)] ds:m-0\">\n {t('booking.service.heading')}\n </h3>\n );\n if (resolvedStyle === 'multi-select' && onChangeIds) {\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n {heading}\n <MultiSelect\n options={options}\n value={valueIds ?? []}\n onChange={onChangeIds}\n placeholder={t('booking.service.placeholder')}\n aria-label={t('booking.service.heading')}\n allowClear\n wrapOptionLabels\n />\n </div>\n );\n }\n if (resolvedStyle === 'combobox') {\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n {heading}\n <Combobox\n options={options}\n value={value ?? ''}\n onValueChange={(next) => onChange(next === '' ? '' : next)}\n placeholder={t('booking.service.placeholder')}\n aria-label={t('booking.service.heading')}\n clearable\n wrapOptionLabels\n />\n </div>\n );\n }\n if (resolvedStyle === 'select') {\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n {heading}\n <Select\n options={options as SelectOption[]}\n value={value ?? ''}\n onValueChange={(next) => onChange(next)}\n placeholder={t('booking.service.placeholder')}\n aria-label={t('booking.service.heading')}\n showDescriptions\n descriptionInName\n wrapOptionLabels\n />\n </div>\n );\n }\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n {heading}\n <ServiceCardGroup\n services={services}\n selectedServiceId={value}\n onSelect={onChange}\n showDuration={showDuration}\n />\n </div>\n );\n}\n\ninterface OperatorStepProps {\n operators: BookingOperator[];\n value?: string;\n valueIds?: string[];\n onChange: (next: string) => void;\n onChangeIds?: (next: string[]) => void;\n pickerStyle?: 'select' | 'combobox' | 'multi-select';\n}\n\nfunction OperatorStep({\n operators,\n value,\n valueIds,\n onChange,\n onChangeIds,\n pickerStyle = 'select',\n}: OperatorStepProps) {\n const { t } = useTranslation('ui');\n const heading = (\n <h3 className=\"type-label ds:font-[var(--font-weight-semibold)] ds:text-[var(--foreground)] ds:m-0\">\n {t('booking.operator.heading')}\n </h3>\n );\n // Multi-select drops the \"all\" sentinel — selecting zero operators\n // (an empty array) already means \"no preference.\"\n if (pickerStyle === 'multi-select' && onChangeIds) {\n const options: OptionShape[] = operators.map((op) => ({\n value: op.id,\n label: op.name,\n dir: 'auto',\n }));\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n {heading}\n <MultiSelect\n options={options}\n value={valueIds ?? []}\n onChange={onChangeIds}\n // Nothing picked means any provider, so the empty field says so\n // rather than asking the patient to choose.\n placeholder={t('booking.operator.all')}\n aria-label={t('booking.operator.heading')}\n allowClear\n />\n </div>\n );\n }\n // \"All operators\" is always the first option — matches the legacy\n // `OPERATORS_ALL` sentinel from the booking-website state hook.\n const options: OptionShape[] = [\n { value: OPERATORS_ALL, label: t('booking.operator.all') },\n ...operators.map(\n (op): OptionShape => ({ value: op.id, label: op.name, dir: 'auto' }),\n ),\n ];\n if (pickerStyle === 'combobox') {\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n {heading}\n <Combobox\n options={options}\n value={value ?? OPERATORS_ALL}\n onValueChange={(next) => onChange(next === '' ? OPERATORS_ALL : next)}\n placeholder={t('booking.operator.placeholder')}\n aria-label={t('booking.operator.heading')}\n clearable\n />\n </div>\n );\n }\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n {heading}\n <Select\n options={options as SelectOption[]}\n value={value ?? OPERATORS_ALL}\n onValueChange={(next) => onChange(next)}\n placeholder={t('booking.operator.placeholder')}\n aria-label={t('booking.operator.heading')}\n />\n </div>\n );\n}\n\ninterface OnboardingIncompleteAlertProps {\n customSlot?: ReactNode;\n}\n\nfunction OnboardingIncompleteAlert({\n customSlot,\n}: OnboardingIncompleteAlertProps) {\n const { t } = useTranslation('ui');\n if (customSlot) return <>{customSlot}</>;\n // Use Alert.Title with `as=\"h4\"` so the heading-order stays valid\n // inside the booking section (which has h2 panel + h3 step headers).\n // The default h5 would skip the h4 level and trip\n // `heading-order` in axe.\n return (\n <Alert variant=\"warning\">\n <Alert.Title as=\"h4\">\n {t('booking.onboardingIncomplete.title')}\n </Alert.Title>\n <Alert.Description>\n {t('booking.onboardingIncomplete.description')}\n </Alert.Description>\n </Alert>\n );\n}\n\ninterface NextAvailableCtaProps {\n nextAvailableDate: string;\n onJump: () => void;\n locale: string;\n}\n\nfunction NextAvailableCta({\n nextAvailableDate,\n onJump,\n locale,\n}: NextAvailableCtaProps) {\n const { t } = useTranslation('ui');\n const formatted = useMemo(() => {\n try {\n return new Intl.DateTimeFormat(locale, { dateStyle: 'long' }).format(\n parseISO(nextAvailableDate),\n );\n } catch {\n return nextAvailableDate;\n }\n }, [nextAvailableDate, locale]);\n return (\n <Alert variant=\"info\">\n <Alert.Description>\n {t('booking.nextAvailable.description', { date: formatted })}\n </Alert.Description>\n <Alert.Action>\n <Button intent=\"secondary\" size=\"sm\" onClick={onJump}>\n {t('booking.nextAvailable.cta')}\n </Button>\n </Alert.Action>\n </Alert>\n );\n}\n\ninterface BookingSuccessProps {\n codeVerified?: boolean;\n /** A checked address: shows \"Time reserved\" and opens it. */\n handoverUrl?: string;\n handoverDelayMs?: number;\n onNavigate?: (url: string) => void;\n payment?: BookingResolvedPayment;\n confirmationChannels?: BookingProps['confirmationChannels'];\n snapshot: {\n slot: BookingSlot;\n details: BookingDetails;\n insuranceType?: InsuranceType;\n operatorId?: string;\n /** Every professional the patient picked — the multi-select arm\n * writes here and leaves `operatorId` empty. */\n operatorIds?: string[];\n specialtyId?: string;\n serviceId?: string;\n date?: string;\n };\n operators: BookingOperator[];\n specialties: BookingSpecialty[];\n services: BookingService[];\n locale: string;\n mode: 'live' | 'demo';\n showModify: boolean;\n onReset: () => void;\n onModify: () => void;\n /** True when a removed Booking control dropped focus, not a click away. */\n focusWasLost: () => boolean;\n}\n\nfunction BookingSuccess({\n codeVerified = false,\n handoverUrl,\n handoverDelayMs,\n onNavigate,\n payment,\n confirmationChannels,\n snapshot,\n operators,\n specialties,\n services,\n locale,\n mode,\n showModify,\n onReset,\n onModify,\n focusWasLost,\n}: BookingSuccessProps) {\n const { t } = useTranslation('ui');\n const titleRef = useRef<HTMLHeadingElement>(null);\n useEffect(() => {\n // A paid result unmounts the payment stage and drops focus to <body>.\n // Land it on the confirmation, unless the patient is elsewhere.\n const title = titleRef.current;\n const active = document.activeElement;\n const booking = title?.closest('[data-component=\"booking\"]');\n if ((!payment && !codeVerified) || !title) return;\n if ((active && booking?.contains(active)) || focusWasLost()) title.focus();\n // Mount only: the paid receipt never swaps payments in place.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n const enabledChannels = resolveConfirmationChannels(confirmationChannels);\n const channels = resolveEffectiveConfirmationChannels(\n enabledChannels,\n snapshot.details.confirmationChannels,\n );\n\n const channelLabels = channels.map((c) =>\n t(`booking.confirmation.channel.${c}`),\n );\n // In demo mode, override the channel-aware description with the\n // honest \"this was a demo\" copy — consumers running in mock mode\n // (no real API call) shouldn't tell the patient an email was sent.\n const paidAmount = payment\n ? formatPrice(payment.amountCents, payment.currencyCode, locale)\n : '';\n const description = payment\n ? t(\n mode === 'demo'\n ? 'booking.payment.paidDemo'\n : 'booking.payment.paidBody',\n { amount: paidAmount },\n )\n : codeVerified\n ? mode === 'demo'\n ? t('booking.code.confirmedDemo')\n : t('booking.code.confirmedBody')\n : mode === 'demo'\n ? t('booking.success.descriptionDemo')\n : channelLabels.length > 1\n ? t('booking.success.descriptionMultiple', {\n channels: channelLabels.join(' · '),\n })\n : t('booking.success.descriptionSingle', {\n channel: channelLabels[0],\n });\n\n const formattedDate = useMemo(() => {\n if (!snapshot.date) return undefined;\n try {\n return new Intl.DateTimeFormat(locale, {\n weekday: 'long',\n day: 'numeric',\n month: 'long',\n }).format(parseISO(snapshot.date));\n } catch {\n return snapshot.date;\n }\n }, [snapshot.date, locale]);\n\n // The confirmation read `operatorId` alone, so a professional chosen in\n // the multi-select picker (the only arm the booking site renders) never\n // reached the summary. Read both shapes and name every pick.\n const providerNames = useMemo(() => {\n const ids =\n snapshot.operatorIds && snapshot.operatorIds.length > 0\n ? snapshot.operatorIds\n : snapshot.operatorId\n ? [snapshot.operatorId]\n : [];\n const names = ids\n .filter((id) => id !== OPERATORS_ALL)\n .map((id) => operators.find((op) => op.id === id)?.name)\n .filter((name): name is string => name !== undefined);\n if (names.length === 0) return [];\n // Parts, not one string: each name is the practice's own text and is\n // isolated in its own <bdi> below, while the list's commas and \"and\"\n // follow the page. Bare `en` is CLDR root English, which sets the\n // Oxford comma. House style is British English, so ask for en-GB\n // (\"a, b and c\").\n try {\n return new Intl.ListFormat(locale === 'en' ? 'en-GB' : locale, {\n style: 'long',\n type: 'conjunction',\n }).formatToParts(names);\n } catch {\n return names.flatMap((name, index) => [\n ...(index > 0 ? [{ type: 'literal' as const, value: ', ' }] : []),\n { type: 'element' as const, value: name },\n ]);\n }\n }, [snapshot.operatorIds, snapshot.operatorId, operators, locale]);\n const specialty = snapshot.specialtyId\n ? specialties.find((s) => s.id === snapshot.specialtyId)\n : undefined;\n const service = snapshot.serviceId\n ? services.find((s) => s.id === snapshot.serviceId)\n : undefined;\n\n if (handoverUrl) {\n let shortDate: string | undefined;\n if (snapshot.date) {\n try {\n shortDate = new Intl.DateTimeFormat(locale, {\n weekday: 'short',\n day: 'numeric',\n month: 'short',\n }).format(parseISO(snapshot.date));\n } catch {\n shortDate = snapshot.date;\n }\n }\n const what = service?.label ?? specialty?.label;\n const who = providerNames.map((part, index) =>\n part.type === 'element' ? (\n <bdi key={index}>{part.value}</bdi>\n ) : (\n part.value\n ),\n );\n return (\n <BookingReserved\n url={handoverUrl}\n delayMs={resolveHandoverDelay(handoverDelayMs)}\n onNavigate={onNavigate}\n date={shortDate}\n time={formatClockTime(snapshot.date, snapshot.slot.time, locale)}\n details={\n what || who.length > 0 ? (\n <>\n {what ? <bdi>{what}</bdi> : null}\n {what && who.length > 0 ? ' · ' : null}\n {who}\n </>\n ) : undefined\n }\n shouldTakeFocus={(root) => {\n const active = document.activeElement;\n const booking = root.closest('[data-component=\"booking\"]');\n return Boolean(\n (active && booking?.contains(active)) || focusWasLost(),\n );\n }}\n />\n );\n }\n\n return (\n <div\n data-component=\"booking-success\"\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\"\n >\n <Alert variant=\"success\">\n <Alert.Title\n as=\"h3\"\n ref={titleRef}\n tabIndex={payment || codeVerified ? -1 : undefined}\n // Focused so a screen reader reads the result; not a control, so\n // no ring (a typed code would make the browser draw one).\n className={payment || codeVerified ? 'ds:outline-none' : undefined}\n >\n {t(\n payment\n ? mode === 'demo'\n ? 'booking.payment.paidDemoTitle'\n : 'booking.payment.paidTitle'\n : codeVerified\n ? 'booking.code.confirmedHeading'\n : 'booking.success.heading',\n )}\n </Alert.Title>\n <Alert.Description>{description}</Alert.Description>\n </Alert>\n\n <div className=\"ds:rounded-[var(--radius-md)] ds:bg-[var(--secondary)] ds:p-[var(--spacing-md)]\">\n <dl className=\"ds:grid ds:grid-cols-[auto_minmax(0,1fr)] ds:gap-x-[var(--spacing-md)] ds:gap-y-[var(--spacing-xs)] ds:m-0\">\n {payment && mode !== 'demo' ? (\n <>\n <dt className=\"type-label ds:text-[var(--muted-foreground)]\">\n {t('booking.payment.summaryPaid')}\n </dt>\n <dd className=\"type-body ds:m-0 ds:text-[var(--foreground)]\">\n {paidAmount}\n </dd>\n </>\n ) : null}\n {specialty ? (\n <>\n <dt className=\"type-label ds:text-[var(--muted-foreground)]\">\n {t('booking.success.summarySpecialty')}\n </dt>\n <dd\n dir=\"auto\"\n className=\"type-body ds:m-0 ds:text-[var(--foreground)]\"\n >\n {specialty.label}\n </dd>\n </>\n ) : null}\n {service ? (\n <>\n <dt className=\"type-label ds:text-[var(--muted-foreground)]\">\n {t('booking.success.summaryService')}\n </dt>\n <dd\n dir=\"auto\"\n className=\"type-body ds:m-0 ds:text-[var(--foreground)]\"\n >\n {service.label}\n </dd>\n </>\n ) : null}\n {formattedDate ? (\n <>\n <dt className=\"type-label ds:text-[var(--muted-foreground)]\">\n {t('booking.success.summaryDate')}\n </dt>\n <dd className=\"type-body ds:m-0 ds:text-[var(--foreground)]\">\n {formattedDate}\n </dd>\n </>\n ) : null}\n <dt className=\"type-label ds:text-[var(--muted-foreground)]\">\n {t('booking.success.summaryTime')}\n </dt>\n <dd className=\"type-body ds:m-0 ds:text-[var(--foreground)]\">\n {formatClockTime(snapshot.date, snapshot.slot.time, locale)}\n </dd>\n {providerNames.length > 0 ? (\n <>\n <dt className=\"type-label ds:text-[var(--muted-foreground)]\">\n {t('booking.success.summaryProvider')}\n </dt>\n <dd className=\"type-body ds:m-0 ds:text-[var(--foreground)]\">\n {providerNames.map((part, index) =>\n part.type === 'element' ? (\n <bdi key={index}>{part.value}</bdi>\n ) : (\n part.value\n ),\n )}\n </dd>\n </>\n ) : null}\n </dl>\n </div>\n\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-sm)]\">\n <Button intent=\"secondary\" size=\"md\" onClick={onReset}>\n {t('booking.success.bookAnother')}\n </Button>\n {showModify ? (\n <Button intent=\"ghost\" size=\"md\" onClick={onModify}>\n {t('booking.success.modifyBooking')}\n </Button>\n ) : null}\n </div>\n </div>\n );\n}\n\ninterface EmptyServicesProps {\n customSlot?: ReactNode;\n}\n\nfunction EmptyServicesAlert({ customSlot }: EmptyServicesProps) {\n const { t } = useTranslation('ui');\n if (customSlot) return <>{customSlot}</>;\n return (\n <EmptyState\n variant=\"no-results\"\n title={t('booking.emptyServices.title')}\n description={t('booking.emptyServices.description')}\n />\n );\n}\n\n/* -------------------------------------------------------------------- */\n/* StepRegion — the focus anchor for one cascade step. */\n/* */\n/* Every variant body wraps each step it renders in one of these, and */\n/* flags exactly one as `active`. The root's focus effect looks for that */\n/* single `[data-booking-step-active]` node, so focus management is one */\n/* query rather than five variant-specific DOM walks. */\n/* */\n/* `tabIndex={-1}` makes it a programmatic focus target without adding a */\n/* Tab stop. It carries deliberately NO role and NO aria-label: every */\n/* step already contains a labelled control or heading of its own, and a */\n/* second copy of that name on the wrapper both doubles the announcement */\n/* and puts two nodes with the same accessible name in the tree. What */\n/* the patient hears on landing is the root's polite live region — */\n/* \"Step 3 of 7: Service\" — followed by the step's own content. */\n/* -------------------------------------------------------------------- */\n\n/** Marks the step the cursor is on — the focus effect's only selector. */\nconst ACTIVE_STEP_ATTR = 'data-booking-step-active';\nconst ACTIVE_STEP_SELECTOR = `[${ACTIVE_STEP_ATTR}]`;\n\ninterface StepRegionProps {\n step: CascadeStep;\n active: boolean;\n className?: string;\n /** Set when a disclosure control points at this region via `aria-controls`. */\n id?: string;\n children: ReactNode;\n}\n\nfunction StepRegion({\n step,\n active,\n className,\n id,\n children,\n}: StepRegionProps) {\n return (\n <div\n id={id}\n data-booking-step={String(step)}\n {...(active ? { [ACTIVE_STEP_ATTR]: '' } : null)}\n tabIndex={-1}\n className={\n className\n ? `${className} ${stepRegionFocusClasses}`\n : stepRegionFocusClasses\n }\n >\n {children}\n </div>\n );\n}\n\n/* -------------------------------------------------------------------- */\n/* Ladder folding */\n/* */\n/* four-day-grid sets `value.date` AND `value.slotKey` atomically from */\n/* one tile click, so step 6 (slot) renders nothing of its own. The */\n/* variants that visibly enumerate the cascade — accordion, progress — */\n/* drop it from their ladder, and the root's step announcement has to */\n/* count the same ladder or it reports \"step 6 of 7\" against a 6-rung */\n/* list. */\n/* -------------------------------------------------------------------- */\n\nfunction foldLadder(\n visibleSteps: CascadeStep[],\n datePickerStyle: VariantBodyProps['datePickerStyle'],\n): CascadeStep[] {\n return datePickerStyle === 'four-day-grid'\n ? visibleSteps.filter((s) => s !== 6)\n : visibleSteps;\n}\n\n/* -------------------------------------------------------------------- */\n/* Variant body shared props */\n/* -------------------------------------------------------------------- */\n\ninterface VariantBodyProps {\n cascade: CascadeOutputs;\n inputs: {\n specialties: BookingSpecialty[];\n services: BookingService[];\n operators: BookingOperator[];\n availableDates: string[];\n availableSlots: Record<string, BookingSlot[]>;\n nextAvailableDate?: string;\n };\n value: BookingValue;\n onChange: (next: BookingValue) => void;\n onSubmit: (details: BookingDetails) => void | Promise<void>;\n policy: {\n country?: string;\n lockedOperatorId?: string;\n };\n detailsProps: Omit<\n React.ComponentProps<typeof BookingDetailsForm>,\n 'value' | 'onChange' | 'onSubmit' | 'summarySlot' | 'defaultPhoneCountry'\n >;\n emptyServicesSlot?: ReactNode;\n onboardingIncompleteSlot?: ReactNode;\n loadingDates?: boolean;\n loadingSlots?: boolean;\n onDateSelect?: (iso: string) => void;\n onWindowChange?: (startIso: string, endIso: string) => void;\n datePickerStyle: 'month-calendar' | 'four-day-grid';\n specialtyPickerStyle?: 'select' | 'combobox' | 'multi-select';\n servicePickerStyle?: 'select' | 'combobox' | 'multi-select' | 'cards';\n showServiceDuration: boolean;\n operatorPickerStyle?: 'select' | 'combobox' | 'multi-select';\n submitting?: boolean;\n locale: string;\n activeStep: CascadeStep;\n setActiveStep: (step: CascadeStep) => void;\n /** Booking's own `id`. Nested agent-registering primitives derive theirs from it. */\n agentIdBase?: string;\n}\n\n/* -------------------------------------------------------------------- */\n/* InlineListBody */\n/* -------------------------------------------------------------------- */\n\nfunction InlineListBody(props: VariantBodyProps) {\n const {\n cascade,\n inputs,\n value,\n onChange,\n onSubmit,\n emptyServicesSlot,\n onboardingIncompleteSlot,\n loadingDates,\n loadingSlots,\n onDateSelect,\n onWindowChange,\n datePickerStyle,\n specialtyPickerStyle,\n servicePickerStyle,\n showServiceDuration,\n operatorPickerStyle,\n submitting,\n locale,\n detailsProps,\n agentIdBase,\n activeStep,\n } = props;\n const { t } = useTranslation('ui');\n // inline-list paints every gated step at once, so \"active\" here means\n // \"the step the cursor is on\" — the one the focus effect lands in. Fold\n // the cursor first: four-day-grid renders no separate slot block, so a\n // step-6 cursor belongs on the date region or nothing would be marked.\n const cursorStep = foldCursorStep(activeStep, datePickerStyle);\n const region = (step: CascadeStep, className?: string) => ({\n step,\n active: step === cursorStep,\n className,\n });\n\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n {cascade.gates.insurance ? (\n <StepRegion {...region(1)}>\n <InsuranceStep\n value={value.insuranceType}\n onChange={(next) => onChange(resetOnInsuranceChange(value, next))}\n />\n </StepRegion>\n ) : null}\n\n {cascade.gates.specialty ? (\n <StepRegion {...region(2)}>\n <SpecialtyStep\n specialties={cascade.filtered.specialties}\n value={value.specialtyId}\n valueIds={value.specialtyIds}\n onChange={(next) => onChange(resetOnSpecialtyChange(value, next))}\n onChangeIds={(next) =>\n onChange(resetOnSpecialtyIdsChange(value, next))\n }\n pickerStyle={specialtyPickerStyle}\n />\n </StepRegion>\n ) : null}\n\n {cascade.gates.service ? (\n <StepRegion {...region(3)}>\n {cascade.filtered.services.length === 0 ? (\n <EmptyServicesAlert customSlot={emptyServicesSlot} />\n ) : (\n <ServiceStep\n services={cascade.filtered.services}\n value={value.serviceId}\n valueIds={value.serviceIds}\n onChange={(next) => onChange(resetOnServiceChange(value, next))}\n onChangeIds={(next) =>\n onChange(resetOnServiceIdsChange(value, next))\n }\n pickerStyle={servicePickerStyle}\n showDuration={showServiceDuration}\n />\n )}\n </StepRegion>\n ) : null}\n\n {cascade.gates.onboardingIncomplete ? (\n <OnboardingIncompleteAlert customSlot={onboardingIncompleteSlot} />\n ) : null}\n\n {cascade.gates.operator ? (\n <StepRegion {...region(4)}>\n <OperatorStep\n operators={cascade.filtered.operators}\n value={value.operatorId}\n valueIds={value.operatorIds}\n onChange={(next) => onChange(resetOnOperatorChange(value, next))}\n onChangeIds={(next) =>\n onChange(resetOnOperatorIdsChange(value, next))\n }\n pickerStyle={operatorPickerStyle}\n />\n </StepRegion>\n ) : null}\n\n {cascade.gates.date ? (\n <StepRegion\n {...region(5, 'ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]')}\n >\n <h3 className=\"type-label ds:font-[var(--font-weight-semibold)] ds:text-[var(--foreground)] ds:m-0\">\n {t('booking.date.heading')}\n </h3>\n {inputs.availableDates.length === 0 && inputs.nextAvailableDate ? (\n <NextAvailableCta\n nextAvailableDate={inputs.nextAvailableDate}\n onJump={() =>\n onChange(resetOnDateChange(value, inputs.nextAvailableDate))\n }\n locale={locale}\n />\n ) : (\n renderDateStep({\n inputs,\n value,\n onChange,\n onDateSelect,\n onWindowChange,\n loadingDates,\n loadingSlots,\n locale,\n datePickerStyle,\n agentIdBase,\n })\n )}\n </StepRegion>\n ) : null}\n\n {cascade.gates.slot &&\n value.date &&\n datePickerStyle === 'month-calendar' ? (\n <StepRegion\n {...region(6, 'ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]')}\n >\n <h3 className=\"type-label ds:font-[var(--font-weight-semibold)] ds:text-[var(--foreground)] ds:m-0\">\n {t('booking.slot.heading')}\n </h3>\n {renderSlotStep({\n inputs,\n value,\n onChange,\n onDateSelect,\n onWindowChange,\n loadingDates,\n loadingSlots,\n locale,\n datePickerStyle,\n })}\n </StepRegion>\n ) : null}\n\n {cascade.gates.details && cascade.selectedSlot ? (\n <StepRegion {...region(7)}>\n <BookingDetailsForm\n {...detailsProps}\n value={value.details ?? {}}\n onChange={(next) => onChange({ ...value, details: next })}\n onSubmit={onSubmit}\n submitting={submitting}\n defaultPhoneCountry={props.policy.country}\n />\n </StepRegion>\n ) : null}\n </div>\n );\n}\n\n/* -------------------------------------------------------------------- */\n/* getStepNode — render a single cascade step's content. */\n/* */\n/* Shared by all variants so the cascade renders the same content; */\n/* variants just choose how to chrome / sequence it. */\n/* -------------------------------------------------------------------- */\n\ninterface GetStepNodeOptions {\n /** When true, ServiceStep renders as a compact Select (used by all\n * variants except inline-list, which gets the full ServiceCardGroup). */\n compactService?: boolean;\n}\n\nfunction getStepNode(\n step: CascadeStep,\n props: VariantBodyProps,\n options: GetStepNodeOptions = {},\n): ReactNode {\n const {\n cascade,\n inputs,\n value,\n onChange,\n onSubmit,\n emptyServicesSlot,\n onboardingIncompleteSlot,\n loadingDates,\n loadingSlots,\n onDateSelect,\n onWindowChange,\n datePickerStyle,\n specialtyPickerStyle,\n servicePickerStyle,\n showServiceDuration,\n operatorPickerStyle,\n submitting,\n locale,\n detailsProps,\n policy,\n agentIdBase,\n } = props;\n\n switch (step) {\n case 1:\n return (\n <InsuranceStep\n value={value.insuranceType}\n onChange={(next) => onChange(resetOnInsuranceChange(value, next))}\n />\n );\n case 2:\n return (\n <SpecialtyStep\n specialties={cascade.filtered.specialties}\n value={value.specialtyId}\n valueIds={value.specialtyIds}\n onChange={(next) => onChange(resetOnSpecialtyChange(value, next))}\n onChangeIds={(next) =>\n onChange(resetOnSpecialtyIdsChange(value, next))\n }\n pickerStyle={specialtyPickerStyle}\n />\n );\n case 3:\n if (cascade.filtered.services.length === 0) {\n return <EmptyServicesAlert customSlot={emptyServicesSlot} />;\n }\n if (cascade.gates.onboardingIncomplete) {\n return (\n <OnboardingIncompleteAlert customSlot={onboardingIncompleteSlot} />\n );\n }\n return (\n <ServiceStep\n services={cascade.filtered.services}\n value={value.serviceId}\n valueIds={value.serviceIds}\n onChange={(next) => onChange(resetOnServiceChange(value, next))}\n onChangeIds={(next) => onChange(resetOnServiceIdsChange(value, next))}\n pickerStyle={servicePickerStyle}\n compact={options.compactService}\n showDuration={showServiceDuration}\n />\n );\n case 4:\n return (\n <OperatorStep\n operators={cascade.filtered.operators}\n value={value.operatorId}\n valueIds={value.operatorIds}\n onChange={(next) => onChange(resetOnOperatorChange(value, next))}\n onChangeIds={(next) =>\n onChange(resetOnOperatorIdsChange(value, next))\n }\n pickerStyle={operatorPickerStyle}\n />\n );\n case 5:\n if (inputs.availableDates.length === 0 && inputs.nextAvailableDate) {\n return (\n <NextAvailableCta\n nextAvailableDate={inputs.nextAvailableDate}\n onJump={() =>\n onChange(resetOnDateChange(value, inputs.nextAvailableDate))\n }\n locale={locale}\n />\n );\n }\n return renderDateStep({\n inputs,\n value,\n onChange,\n onDateSelect,\n onWindowChange,\n loadingDates,\n loadingSlots,\n locale,\n datePickerStyle,\n agentIdBase,\n });\n case 6:\n return renderSlotStep({\n inputs,\n value,\n onChange,\n onDateSelect,\n onWindowChange,\n loadingDates,\n loadingSlots,\n locale,\n datePickerStyle,\n });\n case 7:\n if (!cascade.selectedSlot) return null;\n return (\n <BookingDetailsForm\n {...detailsProps}\n value={value.details ?? {}}\n onChange={(next) => onChange({ ...value, details: next })}\n onSubmit={onSubmit}\n submitting={submitting}\n defaultPhoneCountry={policy.country}\n />\n );\n /* c8 ignore next 2 */\n default:\n return null;\n }\n}\n\n/* -------------------------------------------------------------------- */\n/* getStepLabel — i18n label per cascade step. */\n/* -------------------------------------------------------------------- */\n\nfunction useStepLabels(): Record<CascadeStep, string> {\n const { t } = useTranslation('ui');\n return useMemo(\n () => ({\n 1: t('booking.insurance.heading'),\n 2: t('booking.specialty.heading'),\n 3: t('booking.service.heading'),\n 4: t('booking.operator.heading'),\n 5: t('booking.date.heading'),\n 6: t('booking.slot.heading'),\n 7: t('booking.details.heading'),\n }),\n [t],\n );\n}\n\n/* -------------------------------------------------------------------- */\n/* AccordionBody — StepperAccordion-backed flow with per-step summaries. */\n/* -------------------------------------------------------------------- */\n\n/**\n * four-day-grid folds step 6 into step 5 — the slot tiles live inside the\n * date picker — so a step-6 cursor belongs on the date panel. Both ladder\n * variants drop step 6 from their step list and must fold the cursor to\n * match, or `indexOf` misses and the ladder snaps to its first step.\n */\nfunction foldCursorStep(\n step: CascadeStep,\n datePickerStyle: VariantBodyProps['datePickerStyle'],\n): CascadeStep {\n return datePickerStyle === 'four-day-grid' && step === 6 ? 5 : step;\n}\n\nfunction AccordionBody(props: VariantBodyProps) {\n const { cascade, value, activeStep, setActiveStep, datePickerStyle } = props;\n const labels = useStepLabels();\n const { t } = useTranslation('ui');\n const allOperatorsLabel = t('booking.operator.all');\n\n // four-day-grid embeds slot tiles inside the date step's picker —\n // step 6 (slot) renders nothing of its own. Drop it from the\n // accordion ladder so the user doesn't see an empty \"Orario\"\n // panel that would just expand to whitespace.\n const visibleStepsForBody = useMemo(\n () => foldLadder(cascade.visibleSteps, datePickerStyle),\n [cascade.visibleSteps, datePickerStyle],\n );\n\n // Map the 1-indexed cascade step onto the ladder we actually rendered —\n // not `cascade.visibleSteps`, which still holds the step 6 that\n // four-day-grid drops.\n const cursorStep = foldCursorStep(activeStep, datePickerStyle);\n const activeIndex = Math.max(0, visibleStepsForBody.indexOf(cursorStep));\n\n // Compose accordion specs from the visible cascade steps. Pull a\n // localised summary off `value` for completed steps so collapsed\n // panels still convey what was picked.\n const accordionSteps = useMemo(\n () =>\n visibleStepsForBody.map((stepNum) => ({\n label: labels[stepNum],\n summary: getStepSummary(stepNum, value, cascade, allOperatorsLabel),\n status: statusForStep(stepNum, value, cascade),\n content: (\n <StepRegion step={stepNum} active={stepNum === cursorStep}>\n {getStepNode(stepNum, props, { compactService: true })}\n </StepRegion>\n ),\n })),\n [\n visibleStepsForBody,\n value,\n labels,\n cascade,\n props,\n cursorStep,\n allOperatorsLabel,\n ],\n );\n\n return (\n <StepperAccordion\n activeStep={activeIndex}\n steps={accordionSteps}\n onStepChange={(idx) => {\n const next = visibleStepsForBody[idx];\n if (next) setActiveStep(next);\n }}\n />\n );\n}\n\n/**\n * The status the ladder variants hand each step.\n *\n * `completed` is the step that holds a value and sits behind the cascade's\n * own frontier. `unlocked` is every other step the cascade has legitimately\n * *reached* — including step 7, whose fulfilment is owned by the details\n * form and which therefore never reports itself completed. Without the\n * `unlocked` rung, pressing Edit on an earlier row left every step from the\n * frontier onwards HTML-`disabled`, escapable only by changing a selection\n * (which wipes the date and slot). Steps ahead of the frontier still return\n * `undefined` and stay locked, exactly as before.\n */\nfunction statusForStep(\n step: CascadeStep,\n value: BookingValue,\n cascade: CascadeOutputs,\n): StepStatus | undefined {\n if (stepIsFulfilled(step, value) && step < cascade.currentStep) {\n return 'completed';\n }\n return step <= cascade.currentStep ? 'unlocked' : undefined;\n}\n\n/**\n * Has the patient answered this step themselves? Differs from\n * `stepIsFulfilled` only at the professional step, where \"no preference\"\n * (the `'all'` sentinel, or an empty multi-select) satisfies the cascade\n * without the patient having chosen.\n */\nfunction stepIsAnswered(step: CascadeStep, value: BookingValue): boolean {\n if (step !== 4) return stepIsFulfilled(step, value);\n if (value.operatorIds && value.operatorIds.length > 0) return true;\n return resolveOperatorId(value) !== undefined;\n}\n\n/** Labels of the picked entries — multi-select steps can hold several. */\nfunction pickedLabels(\n ids: string[],\n items: { id: string; label: string }[],\n): string | undefined {\n const labels = ids\n .map((id) => items.find((item) => item.id === id)?.label)\n .filter((label): label is string => label !== undefined);\n return labels.length > 0 ? labels.join(', ') : undefined;\n}\n\nfunction getStepSummary(\n step: CascadeStep,\n value: BookingValue,\n cascade: CascadeOutputs,\n /** Translated `booking.operator.all` — summarises the `'all'` sentinel. */\n allOperatorsLabel: string,\n): ReactNode {\n if (!stepIsFulfilled(step, value)) return undefined;\n switch (step) {\n case 1:\n return value.insuranceType;\n case 2:\n return pickedLabels(\n resolveSpecialtyIds(value),\n cascade.filtered.specialties,\n );\n case 3:\n return pickedLabels(resolveServiceIds(value), cascade.filtered.services);\n case 4: {\n const raw = resolveOperatorIds(value);\n const ids = raw.filter((id) => id !== OPERATORS_ALL);\n const named = pickedLabels(\n ids,\n cascade.filtered.operators.map((op) => ({\n id: op.id,\n label: op.name,\n })),\n );\n if (named !== undefined) return named;\n // No pick at all is \"no preference\": the `'all'` sentinel, or an empty\n // multi-select. Resolving it to `undefined` dropped the chip from the\n // calendar rail even though the step was answered.\n return ids.length === 0 ? allOperatorsLabel : undefined;\n }\n case 5:\n return value.date;\n case 6:\n return cascade.selectedSlot?.time;\n case 7:\n return undefined;\n }\n}\n\n/* -------------------------------------------------------------------- */\n/* CalendarBody — chip rail of completed selections + calendar dominant. */\n/* -------------------------------------------------------------------- */\n\nfunction CalendarBody(props: VariantBodyProps) {\n const { cascade, value, activeStep, setActiveStep } = props;\n const { t } = useTranslation('ui');\n const labels = useStepLabels();\n const allOperatorsLabel = t('booking.operator.all');\n const panelId = `${useId()}-filter`;\n const cursorStep = foldCursorStep(activeStep, props.datePickerStyle);\n\n // Filters that come before the calendar (insurance/specialty/service/operator).\n const filterSteps = cascade.visibleSteps.filter(\n (s) => s === 1 || s === 2 || s === 3 || s === 4,\n );\n const hasUnfulfilledFilter = filterSteps.some(\n (s) => !stepIsFulfilled(s, value),\n );\n\n // Which filter is open. The rail's chips write `activeStep` — reading it\n // back here is what makes them controls rather than decoration. When the\n // cursor is past the filters (or on a step the rail doesn't own) fall\n // back to the first filter still missing an answer, which is the\n // behaviour the variant has always had.\n //\n // This is also what makes step 4 reachable at all: the `OPERATORS_ALL`\n // sentinel pre-fulfils the provider step, so it is never the \"first\n // unfulfilled filter\" and the old first-unfulfilled-only rule meant the\n // picker could not be rendered by any sequence of user actions — in\n // contradiction with the documented cascade, which gates step 4 on\n // `allowOperatorSelection` + a service + >1 eligible operator and carves\n // out no variant.\n const expandedFilter: CascadeStep | undefined = filterSteps.some(\n (s) => s === activeStep,\n )\n ? activeStep\n : filterSteps.find((s) => !stepIsFulfilled(s, value));\n\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n {filterSteps.length > 0 ? (\n <div\n role=\"group\"\n aria-label={t('booking.filtersLabel')}\n className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-xs)]\"\n >\n {filterSteps.map((s) => {\n const summary = getStepSummary(\n s,\n value,\n cascade,\n allOperatorsLabel,\n );\n const isExpanded = s === expandedFilter;\n // A filter that already holds an answer is a true disclosure —\n // it can be closed again by handing the cursor back to the\n // cascade's own frontier. The one the cascade is still waiting\n // on is not: closing it would hide the only thing the patient\n // can usefully do next, so it is marked as the current step\n // rather than claiming a toggle it cannot honour.\n const collapsible = stepIsFulfilled(s, value);\n return (\n <Button\n key={`csc-${s}`}\n // `tonal` falls back to the primary palette outside a\n // tint-painting container, so an expanded `primary` chip\n // and a collapsed `tonal` one were pixel-identical at rest\n // — the rail read as N identical CTAs with no cue as to\n // which one had opened the panel. `outline` gives the\n // collapsed chips their own resting treatment, and the\n // chevron carries the state without relying on colour.\n intent={isExpanded ? 'primary' : 'outline'}\n size=\"sm\"\n endIcon={\n <ChevronDown\n aria-hidden=\"true\"\n className={isExpanded ? 'ds:rotate-180' : undefined}\n />\n }\n aria-expanded={collapsible ? isExpanded : undefined}\n aria-controls={collapsible && isExpanded ? panelId : undefined}\n aria-current={!collapsible && isExpanded ? 'step' : undefined}\n onClick={() =>\n setActiveStep(\n collapsible && isExpanded ? cascade.currentStep : s,\n )\n }\n >\n {/* Rendered as children rather than a concatenated string\n so the browser resolves the bidi run itself — a\n JS-built \"label: value\" puts the colon on the wrong\n side under `dir=\"rtl\"`. */}\n {summary ? (\n <>\n {labels[s]}: {summary}\n </>\n ) : (\n labels[s]\n )}\n </Button>\n );\n })}\n </div>\n ) : null}\n\n {expandedFilter !== undefined ? (\n <StepRegion\n step={expandedFilter}\n active={expandedFilter === cursorStep}\n id={panelId}\n >\n {getStepNode(expandedFilter, props, { compactService: true })}\n </StepRegion>\n ) : null}\n\n {!hasUnfulfilledFilter && cascade.gates.date ? (\n // four-day-grid embeds slots inline with the day strip — the\n // historic 2-col date|slot split collapses to a single column\n // so the picker spans the full width instead of orphaning an\n // empty right cell.\n props.datePickerStyle === 'four-day-grid' ? (\n <StepRegion step={5} active={cursorStep === 5}>\n {getStepNode(5, props)}\n </StepRegion>\n ) : (\n <div className=\"ds:grid ds:grid-cols-1 ds:gap-[var(--spacing-md)] ds:md:grid-cols-2\">\n <StepRegion\n step={5}\n active={cursorStep === 5}\n className=\"ds:min-w-0\"\n >\n {getStepNode(5, props)}\n </StepRegion>\n {value.date ? (\n <StepRegion\n step={6}\n active={cursorStep === 6}\n className=\"ds:min-w-0\"\n >\n {getStepNode(6, props)}\n </StepRegion>\n ) : (\n <div className=\"ds:min-w-0\" />\n )}\n </div>\n )\n ) : null}\n\n {cascade.gates.details ? (\n <StepRegion step={7} active={cursorStep === 7}>\n {getStepNode(7, props)}\n </StepRegion>\n ) : null}\n </div>\n );\n}\n\n/* -------------------------------------------------------------------- */\n/* FlexibleBody — 2-col desktop (filters L, calendar+slots R), inline */\n/* below md. */\n/* -------------------------------------------------------------------- */\n\nfunction FlexibleBody(props: VariantBodyProps) {\n const { cascade, datePickerStyle, activeStep } = props;\n const cursorStep = foldCursorStep(activeStep, datePickerStyle);\n\n const filterStepNumbers = cascade.visibleSteps.filter(\n (s) => s === 1 || s === 2 || s === 3 || s === 4,\n );\n\n // 0.33.12: four-day-grid renders 4 day columns + ±arrows. The\n // historic 2-col split (filters left, picker right) crushes\n // that 4-column strip into ~half the widget width — slot tiles\n // truncate, day headers become unreadable. Stack to single\n // column when four-day-grid so the picker gets the full width.\n // (The calendar variant already does this in 0.33.10.)\n const stackedLayout = datePickerStyle === 'four-day-grid';\n\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n <div\n className={\n stackedLayout\n ? 'ds:flex ds:flex-col ds:gap-[var(--spacing-md)]'\n : 'ds:grid ds:grid-cols-1 ds:gap-[var(--spacing-md)] ds:md:grid-cols-2'\n }\n >\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n {filterStepNumbers.map((s) => (\n <StepRegion key={`fbf-${s}`} step={s} active={s === cursorStep}>\n {getStepNode(s, props, { compactService: true })}\n </StepRegion>\n ))}\n </div>\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n {cascade.gates.date ? (\n <StepRegion step={5} active={cursorStep === 5}>\n {getStepNode(5, props)}\n </StepRegion>\n ) : null}\n {cascade.gates.slot &&\n props.value.date &&\n datePickerStyle === 'month-calendar' ? (\n <StepRegion step={6} active={cursorStep === 6}>\n {getStepNode(6, props)}\n </StepRegion>\n ) : null}\n </div>\n </div>\n {cascade.gates.details ? (\n <StepRegion step={7} active={cursorStep === 7}>\n {getStepNode(7, props)}\n </StepRegion>\n ) : null}\n </div>\n );\n}\n\n/* -------------------------------------------------------------------- */\n/* ProgressBody — wizard with stepper + one step on screen + Back/Next. */\n/* -------------------------------------------------------------------- */\n\nfunction ProgressBody(props: VariantBodyProps) {\n const { cascade, value, activeStep, setActiveStep, datePickerStyle } = props;\n const { t } = useTranslation('ui');\n const labels = useStepLabels();\n\n // four-day-grid sets both value.date and value.slotKey atomically\n // when the user picks a tile, so step 6 (slot) has nothing of its\n // own to render. Drop it from the wizard ladder so the user\n // doesn't land on an empty page mid-flow.\n const visibleSteps = useMemo(\n () => foldLadder(cascade.visibleSteps, datePickerStyle),\n [cascade.visibleSteps, datePickerStyle],\n );\n const cursorStep = foldCursorStep(activeStep, datePickerStyle);\n const activeIndex = Math.max(0, visibleSteps.indexOf(cursorStep));\n const totalSteps = visibleSteps.length;\n\n const stepSpecs = useMemo(\n () => visibleSteps.map((s) => ({ label: labels[s] })),\n [visibleSteps, labels],\n );\n\n const canGoBack = activeIndex > 0;\n // Forward navigation is gated by the cascade — can only advance when the\n // active step is fulfilled.\n //\n // Folding the cursor changes what that asks: under four-day-grid a step-6\n // cursor reads as 5, so \"is the date set?\" would stand in for \"is the SLOT\n // set?\". FourDayPicker sets both atomically, so a user-driven flow cannot\n // reach date-without-slot — but a consumer hydrating a saved draft or a\n // deep link can, and Next would then land the wizard on step 7, which\n // renders nothing without a slot and whose only exit is Back.\n const nextNeedsSlot = cursorStep === 5 && datePickerStyle === 'four-day-grid';\n const canGoNext =\n activeIndex < totalSteps - 1 &&\n stepIsFulfilled(cursorStep, value) &&\n (!nextNeedsSlot || stepIsFulfilled(6, value));\n\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n <StepperProgress activeStep={activeIndex} steps={stepSpecs} />\n <StepRegion step={cursorStep} active>\n {getStepNode(cursorStep, props, { compactService: true })}\n </StepRegion>\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:justify-between ds:gap-[var(--spacing-sm)]\">\n <Button\n intent=\"ghost\"\n size=\"md\"\n disabled={!canGoBack}\n onClick={() => {\n const prev = visibleSteps[activeIndex - 1];\n if (prev) setActiveStep(prev);\n }}\n >\n {t('booking.actions.back')}\n </Button>\n {cursorStep < 7 ? (\n <Button\n intent=\"primary\"\n size=\"md\"\n disabled={!canGoNext}\n onClick={() => {\n const next = visibleSteps[activeIndex + 1];\n if (next) setActiveStep(next);\n }}\n >\n {t('booking.actions.next')}\n </Button>\n ) : null}\n </div>\n </div>\n );\n}\n\n/* -------------------------------------------------------------------- */\n/* Root Booking component */\n/* -------------------------------------------------------------------- */\n\nconst EMPTY_SPECIALTIES: BookingSpecialty[] = [];\nconst EMPTY_OPERATORS: BookingOperator[] = [];\n\n/** Read the OS motion preference at call time — it can change mid-session. */\nfunction prefersReducedMotion(): boolean {\n return (\n typeof window !== 'undefined' &&\n typeof window.matchMedia === 'function' &&\n window.matchMedia('(prefers-reduced-motion: reduce)').matches\n );\n}\n\nexport const Booking = forwardRef<HTMLDivElement, BookingProps>(\n (\n {\n variant = 'inline-list',\n country,\n // No default — the cascade engine treats `undefined` as \"auto-on\n // when `specialties` has items\" so consumers who pass specialty\n // data without the explicit flag still get the step.\n useSpecialties,\n allowOperatorSelection = false,\n lockedOperatorId,\n operatorsByService = false,\n autoSelectSingleService = false,\n specialties: specialtiesProp,\n services,\n operators: operatorsProp,\n availableDates,\n availableSlots,\n nextAvailableDate,\n hideEmail = false,\n emailOptional = false,\n requireCodiceFiscale,\n requireDateOfBirth,\n requireInsuranceNumber,\n billingInDetails = false,\n paymentNoticeStyle = 'highlighted',\n showNote,\n showReturningPatientFlag,\n privacyPolicyUrl,\n termsUrl,\n practiceConsent,\n paymentTermsUrl,\n paymentState,\n handoverDelayMs,\n onNavigate,\n renderPayment,\n renderPaymentCompletion,\n validateCodiceFiscale,\n validateInsuranceNumber,\n confirmationChannels,\n defaultConfirmationChannels,\n singleConfirmationChannel,\n value,\n onChange,\n onSubmit,\n codeStep,\n onStepChange,\n onDateSelect,\n onWindowChange,\n datePickerStyle = 'month-calendar',\n specialtyPickerStyle,\n servicePickerStyle,\n showServiceDuration = true,\n operatorPickerStyle,\n loadingDates,\n loadingSlots,\n submitting,\n submitError,\n mode = 'live',\n showModifyOnSuccess = true,\n surface = 'flat',\n emptyServicesSlot,\n onboardingIncompleteSlot,\n 'aria-label': ariaLabel,\n id,\n className,\n onFocus: onFocusProp,\n onBlur: onBlurProp,\n ...rest\n },\n ref,\n ) => {\n const { t, i18n } = useTranslation('ui');\n const resolvedVariant = (variant ?? 'inline-list') as BookingVariant;\n const locale = i18n.language ?? 'en';\n\n const specialties = specialtiesProp ?? EMPTY_SPECIALTIES;\n const operators = operatorsProp ?? EMPTY_OPERATORS;\n\n // Auto-pre-select on mount + whenever the inputs that drive them\n // arrive (e.g. when `specialties` populates from an async fetch).\n useEffect(() => {\n const next = applyAutoSelects(value, {\n country,\n useSpecialties,\n allowOperatorSelection,\n lockedOperatorId,\n autoSelectSingleService,\n specialties,\n services,\n });\n // Shallow compare the keys we might have changed.\n if (\n next.specialtyId !== value.specialtyId ||\n next.operatorId !== value.operatorId ||\n next.serviceId !== value.serviceId\n ) {\n onChange(next);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n lockedOperatorId,\n useSpecialties,\n autoSelectSingleService,\n specialties,\n services,\n ]);\n\n const cascade = useMemo(\n () =>\n deriveCascade({\n country,\n useSpecialties,\n allowOperatorSelection,\n lockedOperatorId,\n operatorsByService,\n autoSelectSingleService,\n specialties,\n services,\n operators,\n availableDates,\n availableSlots,\n value,\n }),\n [\n country,\n useSpecialties,\n allowOperatorSelection,\n lockedOperatorId,\n operatorsByService,\n autoSelectSingleService,\n specialties,\n services,\n operators,\n availableDates,\n availableSlots,\n value,\n ],\n );\n\n // Per-step signature of every cascade-relevant selection. `details` is\n // deliberately excluded so typing in the form never moves the cursor.\n const selectionParts = useMemo(\n () => [\n JSON.stringify(value.insuranceType),\n JSON.stringify(resolveSpecialtyIds(value)),\n JSON.stringify(resolveServiceIds(value)),\n JSON.stringify(resolveOperatorIds(value)),\n JSON.stringify(value.date),\n JSON.stringify(value.slotKey),\n ],\n [value],\n );\n\n // The wizard shows one step at a time, so a step the cursor skips is\n // reachable only by pressing Back. Rest on every unanswered step there —\n // the professional step is pre-fulfilled by the \"all\" sentinel and would\n // otherwise be walked straight past. Other variants show the whole ladder.\n const oneStepAtATime = resolvedVariant === 'progress';\n\n // Where the cursor should rest once the patient has answered `changedStep`.\n // Never past `currentStep`: clearing an answer, or an auto-select filling\n // a later step, would otherwise land the wizard on a dead page.\n const landingStep = useCallback(\n (changedStep: number): CascadeStep => {\n // Clearing every professional is \"no preference\", so nothing after\n // step 4 locks. It is not a choice, though: stay on the step, as\n // clearing any other answer does, so the patient can pick again.\n if (\n changedStep === 4 &&\n cascade.visibleSteps.includes(4) &&\n resolveOperatorIds(value).length === 0\n ) {\n return Math.min(4, cascade.currentStep) as CascadeStep;\n }\n if (!oneStepAtATime) return cascade.currentStep;\n const next = cascade.visibleSteps.find(\n (s) => s > changedStep && !stepIsAnswered(s, value),\n );\n if (next === undefined) return cascade.currentStep;\n return Math.min(next, cascade.currentStep) as CascadeStep;\n },\n [oneStepAtATime, cascade.visibleSteps, cascade.currentStep, value],\n );\n\n // Mount resumes at the cascade's own cursor: a hydrated draft or deep\n // link should open where the flow stopped, not rewind to a step the\n // consumer already answered for the patient.\n const [activeStep, setActiveStep] = useState<CascadeStep>(\n cascade.currentStep,\n );\n // Re-sync the cursor on any selection change — either direction, and\n // even when `currentStep` doesn't move. A forward-only sync stranded\n // the accordion, leaving later steps HTML-disabled.\n const lastPartsRef = useRef(selectionParts);\n const lastLadderRef = useRef(cascade.visibleSteps);\n useEffect(() => {\n const prevParts = lastPartsRef.current;\n const prevLadder = lastLadderRef.current;\n lastPartsRef.current = selectionParts;\n lastLadderRef.current = cascade.visibleSteps;\n const changedIndex = selectionParts.findIndex(\n (part, i) => part !== prevParts[i],\n );\n if (changedIndex !== -1) {\n setActiveStep(landingStep(changedIndex + 1));\n return;\n }\n // A gate can open late — operators arriving after the service pick.\n // In the wizard that step is then only reachable backwards, so land\n // on it rather than walking past it.\n const appeared = oneStepAtATime\n ? cascade.visibleSteps.find(\n (s) =>\n s < activeStep &&\n !prevLadder.includes(s) &&\n !stepIsAnswered(s, value),\n )\n : undefined;\n if (appeared !== undefined) {\n setActiveStep(appeared);\n return;\n }\n // A closing gate can drop the cursor out of the ladder — the variant\n // bodies would otherwise silently clamp it to their first step.\n if (cascade.visibleSteps.includes(activeStep)) return;\n setActiveStep(cascade.currentStep);\n }, [\n selectionParts,\n landingStep,\n oneStepAtATime,\n cascade.currentStep,\n cascade.visibleSteps,\n activeStep,\n value,\n ]);\n\n // Declared here rather than beside the imperative handle below: the\n // focus effect needs it, and a ref must exist before its first reader.\n const rootRef = useRef<HTMLDivElement>(null);\n\n /* ---------- Focus management + step announcement ---------- */\n\n // The ladder the user actually sees — four-day-grid folds the slot step\n // into the date picker, so counting `cascade.visibleSteps` raw would\n // announce \"step 6 of 7\" against a six-rung list.\n const ladder = useMemo(\n () => foldLadder(cascade.visibleSteps, datePickerStyle),\n [cascade.visibleSteps, datePickerStyle],\n );\n const stepLabels = useStepLabels();\n const [stepAnnouncement, setStepAnnouncement] = useState('');\n // The element inside the widget that last held focus — including inside\n // a Radix portal, which React's synthetic `focusin` still routes through\n // this subtree. The effect below repairs focus only when THAT element\n // has since left the document, which is precisely the \"the control I was\n // using was unmounted by the cursor move\" case. A boolean \"focus was in\n // here\" flag is not enough: clicking non-focusable page content blurs\n // with a null `relatedTarget`, so the flag would stay set and a later\n // consumer- or agent-driven cursor move would yank the viewport back.\n const lastFocusedRef = useRef<HTMLElement | null>(null);\n const announcedStepRef = useRef<CascadeStep | null>(null);\n\n useEffect(() => {\n const cursor = foldCursorStep(activeStep, datePickerStyle);\n // First run is mount: nothing has moved, so neither announce nor grab\n // focus — otherwise every page embedding the widget would steal it.\n if (announcedStepRef.current === null) {\n announcedStepRef.current = cursor;\n return;\n }\n if (announcedStepRef.current === cursor) return;\n announcedStepRef.current = cursor;\n\n const position = ladder.indexOf(cursor);\n setStepAnnouncement(\n position === -1\n ? ''\n : t('booking.stepAnnouncement', {\n current: position + 1,\n total: ladder.length,\n label: stepLabels[cursor],\n }),\n );\n\n // WCAG 2.4.3 — moving the cursor unmounts the control the patient just\n // used, dropping focus to <body> and restarting the tab order at the\n // top of the host page. Put focus in the step that just opened.\n //\n // Two guards keep this from hijacking anything. The element the\n // patient was last on must have LEFT THE DOCUMENT — if it is still\n // connected they either still have it or deliberately moved away, and\n // either way nothing is broken. And focus must actually be lost right\n // now, so a Radix Select restoring focus to its own trigger, or a\n // click on an accordion header, keeps the focus its primitive chose.\n const previous = lastFocusedRef.current;\n if (!previous || previous.isConnected) return;\n const root = rootRef.current;\n if (!root) return;\n const active = document.activeElement;\n const focusWasLost =\n active === null || active === document.body || !root.contains(active);\n if (!focusWasLost) return;\n // Fall back to the root so focus lands somewhere inside the widget\n // even if no step is currently flagged active (e.g. a cursor on a\n // step this variant does not paint).\n const target =\n root.querySelector<HTMLElement>(ACTIVE_STEP_SELECTOR) ?? root;\n target.focus({ preventScroll: true });\n // jsdom does not implement `scrollIntoView` at all, so a try/catch\n // round the options form would just throw again from the fallback.\n // Check for the method itself; focus has already been repaired, which\n // is the part that matters.\n if (typeof target.scrollIntoView !== 'function') return;\n try {\n target.scrollIntoView({\n behavior: prefersReducedMotion() ? 'auto' : 'smooth',\n block: 'nearest',\n });\n } catch {\n // Older browsers may implement the method but reject the options\n // form — a plain scroll is still better than nothing.\n target.scrollIntoView();\n }\n }, [activeStep, datePickerStyle, ladder, stepLabels, t]);\n\n const paymentFlow = useBookingPayment({\n services,\n value,\n availableSlots,\n onSubmit,\n onChange,\n paymentState,\n submitting,\n paymentTermsUrl,\n renderPayment,\n codeStep,\n });\n const submitState = paymentFlow.status;\n const handleSubmit = paymentFlow.submit;\n const resetSubmission = useRef(paymentFlow.reset);\n resetSubmission.current = paymentFlow.reset;\n // Set by \"Change\": move focus into the form once it is editable again.\n const focusDetailsRef = useRef(false);\n // Change stays off while a code is being checked: a confirmed result\n // must not land on an unmounted step.\n const [codeBusy, setCodeBusy] = useState(false);\n useEffect(() => {\n if (!focusDetailsRef.current || submitState !== 'idle') return;\n focusDetailsRef.current = false;\n const field = rootRef.current?.querySelector<HTMLElement>(\n 'form input:not([type=\"hidden\"]):not(:disabled), form select:not(:disabled), form textarea:not(:disabled)',\n );\n if (!field) return;\n field.focus({ preventScroll: true });\n field.scrollIntoView?.({ block: 'nearest' });\n }, [submitState]);\n const paymentHeadingId = useId();\n const paymentHeadingRef = useRef<HTMLHeadingElement>(null);\n const paymentErrorRef = useRef<HTMLDivElement>(null);\n const paymentFailed = paymentFlow.state?.status === 'failed';\n const completionPhase =\n paymentFlow.state &&\n 'phase' in paymentFlow.state &&\n paymentFlow.state.phase === 'completion';\n useEffect(() => {\n if (submitState === 'payment') {\n const active = document.activeElement;\n if (\n !completionPhase ||\n !active ||\n active === document.body ||\n !rootRef.current?.contains(active)\n )\n paymentHeadingRef.current?.focus();\n }\n }, [submitState, completionPhase]);\n useEffect(() => {\n // A card form can extend below the viewport. Bring a failed attempt's\n // error into view and announce it rather than leaving focus on Pay.\n if (submitState === 'payment' && paymentFailed)\n paymentErrorRef.current?.focus();\n }, [submitState, paymentFailed]);\n\n /* ---------- Imperative handle ---------- */\n\n useImperativeHandle(ref, () => rootRef.current as HTMLDivElement, []);\n\n /* ---------- onStepChange + auto-scroll on success ---------- */\n\n // The displayed step is `8` when the success view is mounted, and\n // matches the cascade's `currentStep` otherwise. Tracked via a ref\n // so the effect only fires when the displayed step actually changes\n // (vs every time `currentStep` or `submitState` updates).\n const displayedStep: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 =\n submitState === 'success'\n ? 8\n : submitState === 'payment' || submitState === 'code'\n ? 7\n : cascade.currentStep;\n // Initialise to `null` so the first effect-fire (after mount) still\n // emits onStepChange with the initial step. Subsequent fires only\n // emit when the step actually changes.\n const lastDisplayedStepRef = useRef<typeof displayedStep | null>(null);\n // The success views are much shorter than the form they replace. Were the\n // card to shrink at once, the browser would pull the page up under the\n // patient in one frame. Keep the form's height until the glide below has\n // brought the card's top into view; it then shrinks off screen.\n const heldHeightRef = useRef(0);\n useLayoutEffect(() => {\n if (\n submitState === 'submitting' ||\n submitState === 'code' ||\n submitState === 'payment'\n )\n heldHeightRef.current = rootRef.current?.offsetHeight ?? 0;\n });\n useLayoutEffect(() => {\n const root = rootRef.current;\n if (displayedStep !== 8 || !root || heldHeightRef.current === 0) return;\n // Inline style: permitted per 23-constraints §Runtime-computed\n // dimensions (custom property setter; the rule lives in rootVariants).\n root.style.setProperty(\n '--booking-held-height',\n `${heldHeightRef.current}px`,\n );\n heldHeightRef.current = 0;\n }, [displayedStep]);\n useEffect(() => {\n if (displayedStep === lastDisplayedStepRef.current) return;\n lastDisplayedStepRef.current = displayedStep;\n onStepChange?.(displayedStep);\n // Auto-scroll the booking surface into view on the transition to\n // step 8 — the success card is much shorter than the form, so\n // without this the patient often ends up below the booking column\n // and has to scroll up to see \"Booking submitted.\" See the\n // 0.30.0-adoption follow-up notes for the failure mode.\n // One glide, and only when part of the card is off screen: the views of\n // this step (success, \"Orario riservato\") take no scroll of their own.\n const root = rootRef.current;\n if (displayedStep !== 8 || !root) return;\n const release = () => root.style.removeProperty('--booking-held-height');\n // Not cancelled by a re-run: this effect also re-runs when the host\n // passes a new onStepChange, and the height must still be let go.\n if (glideIntoView(root, 'start')) afterScrollSettles(release);\n else release();\n }, [displayedStep, onStepChange]);\n\n // Snapshot of everything the agent handle reads. Kept in a ref so\n // `cascade` stays out of the handle's useMemo deps — otherwise every\n // keystroke in the details form would re-register the component with\n // the host registry. (`onChange` is still a dep, so a consumer passing\n // an inline arrow re-registers on every render regardless; memoise it\n // if that matters to the host.)\n const flowRef = useRef({ activeStep, cascade, submitState });\n useEffect(() => {\n flowRef.current = { activeStep, cascade, submitState };\n }, [activeStep, cascade, submitState]);\n\n const agentHandle = useMemo<BookingHandle>(\n () => ({\n getVariant: () => resolvedVariant,\n getCurrentStep: () => {\n const flow = flowRef.current;\n // 8 is the terminal confirmation view, matching `onStepChange`.\n return flow.submitState === 'success'\n ? 8\n : flow.submitState === 'payment' || flow.submitState === 'code'\n ? 7\n : flow.activeStep;\n },\n reset: () => {\n // The host owns pending payments and bookings awaiting an SMS code.\n // Clearing either locally would discard a request that is still live.\n if (\n flowRef.current.submitState === 'payment' ||\n flowRef.current.submitState === 'code'\n )\n return;\n // Clear the value to an empty state + drop any success view;\n // the consumer's onChange observes the normalised value.\n onChange({});\n resetSubmission.current();\n setActiveStep(1);\n },\n goToStep: (step) => {\n // The adapter has always declared that an unreachable step clamps\n // to the first incomplete one; until 1.11.0 it did no such thing\n // and set the cursor blind. `cascade.currentStep` IS the first\n // incomplete step, and `visibleSteps` is the ladder the variant\n // renders, so honour both: a step outside the ladder, or ahead of\n // the frontier, lands on the frontier instead.\n const flow = flowRef.current;\n const inLadder = flow.cascade.visibleSteps.includes(step);\n const frontier = flow.cascade.currentStep;\n const next =\n flow.submitState === 'payment' || flow.submitState === 'code'\n ? 7\n : !inLadder || step > frontier\n ? frontier\n : step;\n // Write the clamped value into the snapshot HERE, not just via the\n // effect that mirrors it after paint. The adapter tells hosts to\n // read `currentStep` back after `goto_step`, and a bridge doing\n // both in one tick would otherwise get the pre-move step.\n flowRef.current = { ...flow, activeStep: next };\n setActiveStep(next);\n },\n }),\n [resolvedVariant, onChange],\n );\n useAgentRegistration(bookingAgent, agentHandle, id);\n\n const resolvedAriaLabel = ariaLabel ?? t('booking.regionLabel');\n\n // Success follows submission, payment and (when opted in) code verification.\n // The header keeps the booking context above the confirmation card.\n const submitted = paymentFlow.snapshot;\n const successBody =\n submitState === 'success' && submitted ? (\n <BookingSuccess\n codeVerified={paymentFlow.codeVerified}\n handoverUrl={safeHandoverUrl(paymentFlow.redirectUrl)}\n handoverDelayMs={handoverDelayMs}\n onNavigate={onNavigate}\n payment={submitted.payment}\n confirmationChannels={confirmationChannels}\n snapshot={{\n ...submitted.value,\n slot: submitted.slot,\n details: submitted.details,\n serviceId:\n submitted.payment?.serviceId ??\n submitted.slot.serviceId ??\n submitted.value.serviceId,\n }}\n operators={operators}\n specialties={specialties}\n services={services}\n locale={locale}\n mode={mode}\n showModify={\n showModifyOnSuccess &&\n !submitted.payment &&\n !paymentFlow.codeVerified\n }\n onReset={() => agentHandle.reset()}\n focusWasLost={() => {\n const previous = lastFocusedRef.current;\n const active = document.activeElement;\n return (\n Boolean(previous && !previous.isConnected) &&\n (!active || active === document.body)\n );\n }}\n onModify={() => {\n resetSubmission.current();\n setActiveStep(7);\n }}\n />\n ) : null;\n const codeBody =\n submitState === 'code' && paymentFlow.codeStep ? (\n <BookingCodeVerification\n {...paymentFlow.codeStep}\n {...codeStep}\n onVerified={paymentFlow.completeCode}\n onBusyChange={setCodeBusy}\n />\n ) : null;\n const session = paymentFlow.activeSession;\n const state = paymentFlow.state;\n const context =\n session && state\n ? {\n session,\n payment: session.payment,\n state,\n billing: paymentFlow.snapshot?.details.billing,\n }\n : undefined;\n const completing =\n state && 'phase' in state && state.phase === 'completion';\n const paymentBody =\n submitState === 'payment' && context ? (\n <section\n aria-labelledby={paymentHeadingId}\n data-component=\"booking-payment\"\n data-payment-status={context.state.status}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\"\n >\n <h3\n ref={paymentHeadingRef}\n id={paymentHeadingId}\n tabIndex={-1}\n className=\"type-title-card ds:m-0\"\n >\n {t(\n completing\n ? 'booking.payment.confirming'\n : 'booking.payment.heading',\n )}\n </h3>\n {!completing ? (\n <p className=\"type-body ds:m-0\">\n {t('booking.payment.noticeBody', {\n amount: formatPrice(\n context.payment.amountCents,\n context.payment.currencyCode,\n locale,\n ),\n })}\n </p>\n ) : null}\n {/* Always mounted: a live region inserted together with its text\n is often not announced, so only its content changes. */}\n <p\n role=\"status\"\n className={\n context.state.status === 'processing'\n ? 'type-body ds:m-0 ds:flex ds:items-center ds:gap-[var(--spacing-sm)]'\n : 'ds:sr-only'\n }\n >\n {context.state.status === 'processing' ? (\n <>\n <Spinner variant=\"pulse\" size=\"lg\" aria-hidden=\"true\" />\n <span>\n {t(\n completing\n ? 'booking.payment.confirming'\n : 'booking.payment.processing',\n )}\n </span>\n </>\n ) : null}\n </p>\n {context.state.status === 'failed' ? (\n <Alert\n ref={paymentErrorRef}\n variant=\"error\"\n tabIndex={-1}\n className={stepRegionFocusClasses}\n >\n <Alert.Description>\n {context.state.error ??\n t(\n completing\n ? 'booking.payment.completionFailed'\n : 'booking.payment.failed',\n )}\n </Alert.Description>\n </Alert>\n ) : null}\n {completing\n ? renderPaymentCompletion?.(context)\n : renderPayment?.(context)}\n </section>\n ) : null;\n\n // Text the patient must accept before booking, gathered from the\n // selected service(s). Multi-select can pick several services at\n // once: when more than one carries text, each block is prefixed with\n // its service label so the patient can tell which instructions belong\n // to which reason; a single text stays unprefixed. Blank texts are\n // dropped so a reason without one adds no step.\n const criticalInformationToAccept = useMemo(() => {\n const picked = new Set(resolveServiceIds(value));\n const entries = services\n .filter((s) => picked.has(s.id))\n .map((s) => ({\n label: s.label,\n text: s.criticalInformationToAccept?.trim() ?? '',\n }))\n .filter((entry) => entry.text.length > 0);\n if (entries.length === 0) return undefined;\n if (entries.length === 1) return entries[0].text;\n return entries\n .map((entry) => `${entry.label}: ${entry.text}`)\n .join('\\n\\n');\n }, [services, value]);\n\n const variantBody = useMemo(() => {\n // The form stays (locked) while the code box is open.\n if (submitState === 'success' || submitState === 'payment') return null;\n const Body =\n resolvedVariant === 'accordion'\n ? AccordionBody\n : resolvedVariant === 'calendar'\n ? CalendarBody\n : resolvedVariant === 'flexible'\n ? FlexibleBody\n : resolvedVariant === 'progress'\n ? ProgressBody\n : InlineListBody;\n const bodyProps: VariantBodyProps = {\n cascade,\n inputs: {\n specialties,\n services,\n operators,\n availableDates,\n availableSlots,\n nextAvailableDate,\n },\n value,\n onChange,\n onSubmit: handleSubmit,\n policy: { country, lockedOperatorId },\n detailsProps: {\n hideEmail,\n emailOptional,\n requireCodiceFiscale,\n requireDateOfBirth,\n requireInsuranceNumber,\n insuranceType: value.insuranceType,\n showNote,\n showReturningPatientFlag,\n privacyPolicyUrl,\n termsUrl,\n practiceConsent,\n criticalInformationToAccept,\n locked: submitState === 'code',\n payment: paymentFlow.payment,\n paymentTermsUrl,\n paymentBlocked: paymentFlow.blocked,\n billingInDetails,\n paymentNoticeStyle,\n validateCodiceFiscale,\n validateInsuranceNumber,\n confirmationChannels,\n defaultConfirmationChannels,\n singleConfirmationChannel,\n submitError:\n submitError ??\n (submitState === 'error'\n ? t('booking.payment.submitFailed')\n : undefined),\n },\n emptyServicesSlot,\n onboardingIncompleteSlot,\n loadingDates,\n loadingSlots,\n onDateSelect,\n onWindowChange,\n datePickerStyle,\n specialtyPickerStyle,\n servicePickerStyle,\n showServiceDuration,\n operatorPickerStyle,\n submitting: submitting || submitState === 'submitting',\n locale,\n activeStep,\n setActiveStep,\n agentIdBase: id,\n };\n return <Body {...bodyProps} />;\n }, [\n submitState,\n paymentFlow.payment,\n paymentFlow.blocked,\n paymentTermsUrl,\n t,\n resolvedVariant,\n cascade,\n specialties,\n services,\n operators,\n availableDates,\n availableSlots,\n nextAvailableDate,\n value,\n onChange,\n handleSubmit,\n country,\n lockedOperatorId,\n hideEmail,\n emailOptional,\n requireCodiceFiscale,\n requireDateOfBirth,\n requireInsuranceNumber,\n billingInDetails,\n paymentNoticeStyle,\n submitError,\n showNote,\n showReturningPatientFlag,\n privacyPolicyUrl,\n termsUrl,\n practiceConsent,\n criticalInformationToAccept,\n validateCodiceFiscale,\n validateInsuranceNumber,\n confirmationChannels,\n defaultConfirmationChannels,\n singleConfirmationChannel,\n emptyServicesSlot,\n onboardingIncompleteSlot,\n loadingDates,\n loadingSlots,\n onDateSelect,\n onWindowChange,\n datePickerStyle,\n specialtyPickerStyle,\n servicePickerStyle,\n showServiceDuration,\n operatorPickerStyle,\n submitting,\n locale,\n activeStep,\n id,\n ]);\n\n return (\n <div\n ref={rootRef}\n role=\"region\"\n aria-label={resolvedAriaLabel}\n id={id}\n data-component=\"booking\"\n data-component-id={id}\n data-variant={resolvedVariant}\n className={rootVariants({\n variant: resolvedVariant,\n surface,\n className,\n })}\n // Programmatic focus target of last resort for the step effect —\n // never a Tab stop.\n tabIndex={-1}\n onFocus={(event) => {\n // React routes `focusin` through the React tree, so this fires for\n // Radix portal content too — which is what makes the unmount test\n // in the step effect correct for a Select's listbox.\n lastFocusedRef.current = event.target as HTMLElement;\n onFocusProp?.(event);\n }}\n onBlur={(event) => {\n // A click on non-focusable page content blurs a control that stays\n // mounted. Forget it, so a later update cannot pull focus back.\n const left = event.target as HTMLElement;\n window.setTimeout(() => {\n const active = document.activeElement;\n if (\n lastFocusedRef.current === left &&\n left.isConnected &&\n !(active && rootRef.current?.contains(active))\n )\n lastFocusedRef.current = null;\n });\n onBlurProp?.(event);\n }}\n {...rest}\n >\n {/* Step changes are otherwise silent for screen readers: the panel\n swaps under them with no announcement. `role=\"status\"` already\n implies aria-live=\"polite\" + aria-atomic — setting them again\n double-announces in some AT combinations. */}\n <div role=\"status\" className=\"ds:sr-only\">\n {stepAnnouncement}\n </div>\n <div\n // Hero gradient backdrop is shared across every Booking\n // variant — the header is the kit's brand marker for the\n // surface and should not visually fragment by variant.\n // (0.31.x gated this to `inline-list` only; lifted in\n // 0.32.0 so `accordion` / `calendar` / `flexible` /\n // `progress` carry the same chrome.)\n className={[\n 'ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]',\n 'ds:rounded-[var(--radius-md)]',\n 'ds:bg-[color-mix(in_srgb,var(--primary)_35%,var(--background))]',\n 'ds:bg-[image:var(--gradient-hero-brand)]',\n 'ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)]',\n 'ds:pt-[var(--spacing-md)] ds:pb-[var(--spacing-md)]',\n ].join(' ')}\n >\n <h2 className=\"type-title-card ds:text-[var(--foreground)] ds:m-0\">\n {t('booking.regionLabel')}\n </h2>\n {/* --foreground, not --muted-foreground: muted measures 3.91:1 at\n the gradient's accent end in light, below the 4.5:1 AA floor. */}\n <p className=\"type-body-sm ds:text-[var(--foreground)] ds:m-0\">\n {t('booking.headingSubtitle')}\n </p>\n </div>\n {paymentFlow.cancelled ? (\n <Alert variant=\"info\">\n <Alert.Description>\n {t('booking.payment.cancelled')}\n </Alert.Description>\n </Alert>\n ) : null}\n {successBody ?? paymentBody ?? (\n <>\n {/* A native disabled fieldset blocks every control and keeps\n the content readable. Mounted whenever the host passes a\n code step, so locking never remounts the form; hosts\n without one get no extra group. */}\n {codeStep ? (\n <fieldset\n data-slot=\"booking-form\"\n disabled={codeBody ? true : undefined}\n className=\"ds:m-0 ds:min-w-0 ds:border-0 ds:p-0\"\n >\n {variantBody}\n </fieldset>\n ) : (\n variantBody\n )}\n {codeBody ? (\n <>\n <div className=\"ds:flex ds:justify-end\">\n <Button\n type=\"button\"\n intent=\"ghost\"\n size=\"md\"\n disabled={codeBusy}\n onClick={() => {\n focusDetailsRef.current = true;\n resetSubmission.current();\n }}\n >\n {t('booking.actions.change')}\n </Button>\n </div>\n {codeBody}\n </>\n ) : null}\n </>\n )}\n </div>\n );\n },\n);\n\nBooking.displayName = 'Booking';\n"],"names":["__iconNode","Activity","createLucideIcon","Bone","Brain","CalendarRange","Ear","Microscope","Pill","Scissors","Smile","Sunset","Syringe","subMonths","date","amount","options","addMonths","bookingAgent","handle","args","CONFIRMATION_CHANNEL_ORDER","OPERATORS_ALL","COUNTRY_GERMANY","filterSpecialties","inputs","locked","sp","sv","_a","s","a","b","aSeq","bSeq","filterServices","list","specialtyIds","resolveSpecialtyIds","eligibleOperators","useSpecialtiesResolved","serviceIds","resolveServiceIds","op","rid","sid","computeGates","filtered","insuranceVisible","insuranceSatisfied","specialtyVisible","specialtyPicked","serviceVisible","servicePicked","serviceSatisfied","eligibleOps","operatorVisible","dateVisible","slotVisible","detailsVisible","onboardingIncomplete","deriveStep","gates","visible","stepIsFulfilled","step","value","deriveCascade","currentStep","visibleSteps","selectedSlot","day","selectedService","specialtyPickedFinal","isReadyToSubmit","resetOnInsuranceChange","next","resetOnSpecialtyChange","resetOnSpecialtyIdsChange","resetOnServiceChange","resetOnServiceIdsChange","hasAny","resetOnOperatorChange","resetOnOperatorIdsChange","resolveOperatorIds","resetOnDateChange","resetOnSlotChange","applyAutoSelects","resolvedServices","resolveOperatorId","looksLikePhone","trimmed","resolveConfirmationChannels","enabled","set","c","resolveEffectiveConfirmationChannels","selection","defaultConfirmationSelection","mobile","override","resolvedEnabled","enabledSet","out","mobilePlausible","hasWhatsApp","outSet","URL_PATTERN","TRAILING_PUNCTUATION","OPENERS","count","text","char","trimUrl","raw","surplus","closer","opener","end","last","NON_LATIN_LETTER","ASCII_ALNUM","cutAtScriptSwitch","first","isHttpUrl","candidate","protocol","hostname","linkifyText","segments","cursor","pushText","previous","match","start","url","NOTE_MAX_LENGTH","CF_REGEX","EMAIL_REGEX","VALIDATE_DEBOUNCE_MS","CONSENT_LINK_CLASSES","safeHttpUrl","toStructured","billing","fallbackCountry","fromStructured","address","name","line2","paymentNoticeVariants","cva","BILLING_COUNTRIES","BILLING_FIELDS","ITALIAN_POSTCODE","billingComplete","line1","city","postalCode","country","state","normaliseBilling","idleStatus","SUBMIT_REVEALED","NONE_QUIET","BookingDetailsForm","forwardRef","onChange","onSubmit","hideEmail","emailOptional","requireCodiceFiscale","requireDateOfBirth","requireInsuranceNumber","insuranceType","showNote","showReturningPatientFlag","privacyPolicyUrl","termsUrl","practiceConsent","payment","paymentTermsUrl","paymentBlocked","billingInDetails","paymentNoticeStyle","criticalInformationToAccept","validateCodiceFiscale","validateInsuranceNumber","submitting","summarySlot","defaultPhoneCountry","confirmationChannels","defaultConfirmationChannels","singleConfirmationChannel","submitError","ref","t","i18n","useTranslation","formId","useId","formElement","useRef","setFormElement","useCallback","node","revealTick","setRevealTick","useState","useEffect","gaps","gap","inFlight","pending","setPending","submissionFailed","setSubmissionFailed","busy","cfStatus","setCfStatus","insuranceStatus","setInsuranceStatus","touched","setTouched","markTouched","field","quiet","setQuiet","cfTimerRef","insuranceTimerRef","update","patch","paymentKey","acceptedPaymentKey","setAcceptedPaymentKey","previousPaymentKey","paymentAccepted","practiceConsentShown","practiceConsentKey","acceptedPracticeConsentKey","setAcceptedPracticeConsentKey","previousPracticeConsentKey","practiceConsentAccepted","paymentAmount","formatPrice","safePaymentTermsUrl","collectBilling","cfRequired","billingCountry","billingValid","billingAddress","billingInItaly","billingRef","secondLineRef","billingLine1","billingLine2","_c","_b","billingError","key","markBillingTouched","current","resolvedEnabledChannels","useMemo","pickerVisible","seededRef","seed","selectedChannels","noChannelsSelected","effectiveChannels","emailRequired","validateCodiceFiscaleRef","validateInsuranceNumberRef","hasCfValidator","hasInsuranceValidator","cf","active","validate","res","insuranceShown","n","emailValid","email","phoneValid","requiredFieldsValid","criticalInformation","criticalInformationRequired","criticalInformationTicked","practiceConsentTicked","consentsTicked","channelsSatisfied","canSubmit","waitingOnPatient","submitHintId","fieldErrors","_d","_e","stillQuiet","announce","handleSubmit","e","tick","payload","codiceFiscaleField","jsx","FormField","TextInput","renderConsentLabel","i18nKey","safeUrl","Trans","jsxs","event","block","EmailInput","PhoneInput","e164","DatePicker","AddressFields","TextArea","Checkbox","checked","segment","index","Fragment","CreditCard","RadioGroup","Radio","CheckboxGroup","Alert","Button","Spinner","stepRegionFocusClasses","motionIsOff","root","duration","glideIntoView","element","style","page","top","bottom","box","afterScrollSettles","done","maxMs","finished","finish","timer","BookingCodeVerification","length","onVerify","onResend","resendSeconds","phoneHint","onVerified","onBusyChange","headingId","instructionId","headingRef","sectionRef","inputRef","resendRef","mounted","setBusy","resent","setResent","codeError","setCodeError","requestError","setRequestError","inputVersion","setInputVersion","waitSeconds","deadline","setDeadline","secondsLeft","setSecondsLeft","section","verify","code","result","version","resend","codeMessage","Card","OTPInput","resolveServicePayment","service","currencyCode","servicePickerParts","priceLabel","price","resolveBookingPayment","services","slot","selected","actualId","actual","paymentIdentity","useBookingPayment","availableSlots","paymentState","renderPayment","codeStep","heldSlot","item","resolution","blocked","signature","quoteIdentity","acceptedQuote","accepted","currentSignature","submission","setSubmission","generation","terminal","completionSession","sessionScope","held","activeSession","reportedState","reset","submit","details","submittedCodeStep","attempt","scope","session","redirectUrl","MAX_BAR_MS","checkClasses","barClasses","BookingReserved","delayMs","onNavigate","time","shouldTakeFocus","rootRef","messageId","goRef","stayed","setStayed","still","setStill","open","stay","openRef","useLayoutEffect","heading","DEFAULT_HANDOVER_DELAY_MS","safeHandoverUrl","isSafeHref","MAX_TIMEOUT_MS","resolveHandoverDelay","rootVariants","SERVICE_ICON_RULES","HeartPulse","Eye","Baby","ScanLine","Astroid","ClipboardCheck","pickIcon","pattern","Icon","inferServiceIcon","Stethoscope","useServiceRowText","parts","amountOf","isoOf","fnsFormat","monthCellBase","monthCellVariants","MonthGrid","availableDates","selectedDate","onSelectDate","locale","loading","initialMonth","startOfMonth","parseISO","viewMonth","setViewMonth","focusDate","setFocusDate","cells","monthStart","monthEnd","endOfMonth","startWeekday","totalDays","grid","i","d","monthLabel","weekdayLabels","base","_","availableSet","isAvailable","rovingDate","firstAvailable","isSameMonth","handleKeyDown","Skeleton","IconButton","ChevronLeft","m","ChevronRight","label","rowIndex","colIndex","inMonth","available","isSelected","isSameDay","isRoving","dayLabel","serviceCardVariants","ServiceCardGroup","selectedServiceId","onSelect","showDuration","rowText","groupId","focusIndex","setFocusIndex","cardRefs","focusAt","id","total","prev","isFocused","paymentTone","ariaLabel","iconNode","optionDescriptionVariants","Badge","slotChipVariants","bucketForTime","hh","hour","formatClockTime","BUCKET_ICONS","Sun","Moon","GroupedTimeSlots","slots","selectedSlotKey","dateLabel","groups","availableCount","order","row","EmptyState","bucket","items","FOUR_DAY_WINDOW_SIZE","FourDayPicker","onDateSelect","onWindowChange","loadingDates","loadingSlots","agentIdBase","today","startOfDay","windowStart","setWindowStart","isAfter","windowEnd","addDays","days","iso","hasPrevious","hasNext","handlePreviousDays","subDays","handleNextDays","isBefore","handleSlotSelect","dateIso","visibleWindowHasSlots","firstAvailableIso","NextAvailableCta","SlotGrid","renderDateStep","props","datePickerStyle","renderSlotStep","InsuranceStep","Select","SpecialtyStep","specialties","valueIds","onChangeIds","pickerStyle","MultiSelect","Combobox","ServiceStep","compact","resolvedStyle","OperatorStep","operators","OnboardingIncompleteAlert","customSlot","nextAvailableDate","onJump","formatted","BookingSuccess","codeVerified","handoverUrl","handoverDelayMs","snapshot","mode","showModify","onReset","onModify","focusWasLost","titleRef","title","booking","enabledChannels","channelLabels","paidAmount","description","formattedDate","providerNames","names","specialty","shortDate","what","who","part","EmptyServicesAlert","ACTIVE_STEP_ATTR","ACTIVE_STEP_SELECTOR","StepRegion","className","children","foldLadder","InlineListBody","cascade","emptyServicesSlot","onboardingIncompleteSlot","specialtyPickerStyle","servicePickerStyle","showServiceDuration","operatorPickerStyle","detailsProps","activeStep","cursorStep","foldCursorStep","region","getStepNode","policy","useStepLabels","AccordionBody","setActiveStep","labels","allOperatorsLabel","visibleStepsForBody","activeIndex","accordionSteps","stepNum","getStepSummary","statusForStep","StepperAccordion","idx","stepIsAnswered","pickedLabels","ids","named","CalendarBody","panelId","filterSteps","hasUnfulfilledFilter","expandedFilter","summary","isExpanded","collapsible","ChevronDown","FlexibleBody","filterStepNumbers","ProgressBody","totalSteps","stepSpecs","canGoBack","nextNeedsSlot","canGoNext","StepperProgress","EMPTY_SPECIALTIES","EMPTY_OPERATORS","prefersReducedMotion","Booking","variant","useSpecialties","allowOperatorSelection","lockedOperatorId","operatorsByService","autoSelectSingleService","specialtiesProp","operatorsProp","renderPaymentCompletion","onStepChange","showModifyOnSuccess","surface","onFocusProp","onBlurProp","rest","resolvedVariant","selectionParts","oneStepAtATime","landingStep","changedStep","lastPartsRef","lastLadderRef","prevParts","prevLadder","changedIndex","appeared","ladder","stepLabels","stepAnnouncement","setStepAnnouncement","lastFocusedRef","announcedStepRef","position","target","paymentFlow","submitState","resetSubmission","focusDetailsRef","codeBusy","setCodeBusy","paymentHeadingId","paymentHeadingRef","paymentErrorRef","paymentFailed","completionPhase","useImperativeHandle","displayedStep","lastDisplayedStepRef","heldHeightRef","release","flowRef","agentHandle","flow","inLadder","frontier","useAgentRegistration","resolvedAriaLabel","submitted","successBody","codeBody","context","completing","paymentBody","picked","entries","entry","variantBody","Body","bodyProps","left"],"mappings":"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","x_google_ignoreList":[0,1,2,3,4,5,6,7,8,9,10,11]}