@sankhyatronics/sankhya-cms 0.2.0 → 0.3.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 (209) hide show
  1. package/custom-elements.json +10968 -3080
  2. package/dist/attention-panel/index.js +2 -2
  3. package/dist/bar-chart/index.js +2 -2
  4. package/dist/bento-grid/index.d.ts +25 -0
  5. package/dist/bento-grid/index.js +4 -4
  6. package/dist/booking/index.d.ts +309 -0
  7. package/dist/booking/index.js +20 -0
  8. package/dist/booking/index.js.map +1 -0
  9. package/dist/card/index.js +2 -2
  10. package/dist/carousel/index.d.ts +20 -6
  11. package/dist/carousel/index.js +3 -3
  12. package/dist/chip/index.js +2 -2
  13. package/dist/{chunk-OLA35A2O.js → chunk-2GTR37PU.js} +2 -2
  14. package/dist/{chunk-7NIWQWTA.js → chunk-2HMOX253.js} +128 -25
  15. package/dist/chunk-2HMOX253.js.map +1 -0
  16. package/dist/{chunk-DH53HZPB.js → chunk-37KFBKPD.js} +32 -4
  17. package/dist/chunk-37KFBKPD.js.map +1 -0
  18. package/dist/{chunk-EE6PAN3B.js → chunk-4XPKKYVZ.js} +23 -15
  19. package/dist/chunk-4XPKKYVZ.js.map +1 -0
  20. package/dist/chunk-535QAZ6A.js +236 -0
  21. package/dist/chunk-535QAZ6A.js.map +1 -0
  22. package/dist/{chunk-AKJQ345O.js → chunk-5AWGZQWU.js} +2 -2
  23. package/dist/chunk-6OZKZG5J.js +300 -0
  24. package/dist/chunk-6OZKZG5J.js.map +1 -0
  25. package/dist/chunk-AYNT7G3J.js +805 -0
  26. package/dist/chunk-AYNT7G3J.js.map +1 -0
  27. package/dist/chunk-BEWX3E6P.js +32 -0
  28. package/dist/chunk-BEWX3E6P.js.map +1 -0
  29. package/dist/chunk-CZUGPKXV.js +275 -0
  30. package/dist/chunk-CZUGPKXV.js.map +1 -0
  31. package/dist/{chunk-2DXHPEB5.js → chunk-DJFWZOZM.js} +107 -11
  32. package/dist/chunk-DJFWZOZM.js.map +1 -0
  33. package/dist/chunk-DPANTC3O.js +1714 -0
  34. package/dist/chunk-DPANTC3O.js.map +1 -0
  35. package/dist/chunk-EKZFFY45.js +426 -0
  36. package/dist/chunk-EKZFFY45.js.map +1 -0
  37. package/dist/chunk-ER7MCPDV.js +7 -0
  38. package/dist/chunk-ER7MCPDV.js.map +1 -0
  39. package/dist/chunk-EW2RK5Y6.js +383 -0
  40. package/dist/chunk-EW2RK5Y6.js.map +1 -0
  41. package/dist/{chunk-BLQV2YMO.js → chunk-EZOKT7NJ.js} +2 -2
  42. package/dist/chunk-FF2LWEF3.js +386 -0
  43. package/dist/chunk-FF2LWEF3.js.map +1 -0
  44. package/dist/chunk-FOUK3NHR.js +7 -0
  45. package/dist/chunk-FOUK3NHR.js.map +1 -0
  46. package/dist/{chunk-O4FCRKDX.js → chunk-GB4NGCZI.js} +6 -3
  47. package/dist/chunk-GB4NGCZI.js.map +1 -0
  48. package/dist/{chunk-5F5PTVWR.js → chunk-GOFSMD6W.js} +9 -10
  49. package/dist/chunk-GOFSMD6W.js.map +1 -0
  50. package/dist/{chunk-6D6ROU7X.js → chunk-IGMVF3KK.js} +2 -2
  51. package/dist/{chunk-INMSEYT6.js → chunk-IVPVYVWG.js} +2 -2
  52. package/dist/{chunk-ZRC5BVDX.js → chunk-JURCF4OD.js} +174 -12
  53. package/dist/chunk-JURCF4OD.js.map +1 -0
  54. package/dist/{chunk-FZ36KL73.js → chunk-KZ7PMFWS.js} +11 -1
  55. package/dist/chunk-KZ7PMFWS.js.map +1 -0
  56. package/dist/{chunk-EMCQBT3S.js → chunk-LO6TZBGD.js} +129 -35
  57. package/dist/chunk-LO6TZBGD.js.map +1 -0
  58. package/dist/chunk-MFRGAT6D.js +860 -0
  59. package/dist/chunk-MFRGAT6D.js.map +1 -0
  60. package/dist/chunk-MIBVQXRU.js +1098 -0
  61. package/dist/chunk-MIBVQXRU.js.map +1 -0
  62. package/dist/{chunk-35TX3AOA.js → chunk-NABSRUXG.js} +2 -2
  63. package/dist/{chunk-2FJDNJ7R.js → chunk-NXKDZWS7.js} +44 -6
  64. package/dist/chunk-NXKDZWS7.js.map +1 -0
  65. package/dist/{chunk-KMU6ABQF.js → chunk-NXUS2CH7.js} +14 -1
  66. package/dist/chunk-NXUS2CH7.js.map +1 -0
  67. package/dist/{chunk-GJO3RGOB.js → chunk-OCPGOLVF.js} +56 -11
  68. package/dist/chunk-OCPGOLVF.js.map +1 -0
  69. package/dist/chunk-OEOE6IFY.js +628 -0
  70. package/dist/chunk-OEOE6IFY.js.map +1 -0
  71. package/dist/{chunk-OELI3IWC.js → chunk-PV6OCXXN.js} +2 -2
  72. package/dist/{chunk-5C6C6K5U.js → chunk-Q66CJO3P.js} +200 -12
  73. package/dist/chunk-Q66CJO3P.js.map +1 -0
  74. package/dist/{chunk-MG2VTZA4.js → chunk-QS3ANOWN.js} +2 -2
  75. package/dist/{chunk-3OEEOBHB.js → chunk-QSJ543V2.js} +2 -2
  76. package/dist/{chunk-FML6AG2V.js → chunk-RANC3OI6.js} +2 -2
  77. package/dist/chunk-T4BIN37Q.js +32 -0
  78. package/dist/chunk-T4BIN37Q.js.map +1 -0
  79. package/dist/{chunk-YVTFQHVY.js → chunk-TEAZZPDQ.js} +2 -2
  80. package/dist/chunk-TJK55CJ2.js +49 -0
  81. package/dist/chunk-TJK55CJ2.js.map +1 -0
  82. package/dist/chunk-UKIVLF7S.js +32 -0
  83. package/dist/chunk-UKIVLF7S.js.map +1 -0
  84. package/dist/chunk-V4R7PYP5.js +905 -0
  85. package/dist/chunk-V4R7PYP5.js.map +1 -0
  86. package/dist/{chunk-AG2COC64.js → chunk-VVYQ2DDS.js} +2 -2
  87. package/dist/chunk-WAMOAAMN.js +16 -0
  88. package/dist/chunk-WAMOAAMN.js.map +1 -0
  89. package/dist/chunk-WAYHHL4J.js +1234 -0
  90. package/dist/chunk-WAYHHL4J.js.map +1 -0
  91. package/dist/{chunk-PHEGSCOM.js → chunk-WH6HE6SY.js} +10 -4
  92. package/dist/chunk-WH6HE6SY.js.map +1 -0
  93. package/dist/{chunk-5MY6OWMK.js → chunk-XP6DI3VY.js} +59 -4
  94. package/dist/chunk-XP6DI3VY.js.map +1 -0
  95. package/dist/{chunk-QLA4BH2B.js → chunk-XS6LNTSH.js} +73 -11
  96. package/dist/chunk-XS6LNTSH.js.map +1 -0
  97. package/dist/{chunk-WT4OATGP.js → chunk-ZKFCDVB4.js} +16 -7
  98. package/dist/chunk-ZKFCDVB4.js.map +1 -0
  99. package/dist/cms-theme.css +22 -0
  100. package/dist/contact-form/index.d.ts +220 -0
  101. package/dist/contact-form/index.js +16 -0
  102. package/dist/contact-form/index.js.map +1 -0
  103. package/dist/content-block/index.d.ts +39 -3
  104. package/dist/content-block/index.js +8 -5
  105. package/dist/cookie-consent/index.d.ts +60 -12
  106. package/dist/cookie-consent/index.js +3 -2
  107. package/dist/date-tile/index.js +2 -2
  108. package/dist/dropdown/index.d.ts +22 -1
  109. package/dist/dropdown/index.js +4 -2
  110. package/dist/feature-split/index.d.ts +6 -1
  111. package/dist/feature-split/index.js +5 -5
  112. package/dist/features-section/index.d.ts +49 -5
  113. package/dist/features-section/index.js +6 -6
  114. package/dist/flow/index.js +2 -2
  115. package/dist/footer/index.d.ts +13 -0
  116. package/dist/footer/index.js +2 -2
  117. package/dist/header/index.d.ts +127 -1
  118. package/dist/header/index.js +3 -2
  119. package/dist/hero/index.d.ts +75 -6
  120. package/dist/hero/index.js +6 -3
  121. package/dist/icon-button/index.d.ts +5 -3
  122. package/dist/icon-button/index.js +2 -2
  123. package/dist/index.d.ts +9 -3
  124. package/dist/index.js +118 -57
  125. package/dist/items-accordion/index.d.ts +5 -1
  126. package/dist/items-accordion/index.js +4 -4
  127. package/dist/kpi-card/index.js +2 -2
  128. package/dist/markdown/index.d.ts +18 -0
  129. package/dist/markdown/index.js +3 -3
  130. package/dist/mega-menu/index.d.ts +95 -7
  131. package/dist/mega-menu/index.js +7 -2
  132. package/dist/menu-grid/index.js +2 -2
  133. package/dist/menu-grid-item/index.js +2 -2
  134. package/dist/menu-item/index.d.ts +6 -0
  135. package/dist/menu-item/index.js +3 -2
  136. package/dist/plan-cards/index.d.ts +69 -0
  137. package/dist/plan-cards/index.js +13 -0
  138. package/dist/plan-cards/index.js.map +1 -0
  139. package/dist/product-nav/index.d.ts +127 -0
  140. package/dist/product-nav/index.js +11 -0
  141. package/dist/product-nav/index.js.map +1 -0
  142. package/dist/promo-banner/index.d.ts +34 -7
  143. package/dist/promo-banner/index.js +6 -3
  144. package/dist/quote-dialog/index.d.ts +174 -0
  145. package/dist/quote-dialog/index.js +22 -0
  146. package/dist/quote-dialog/index.js.map +1 -0
  147. package/dist/schema/index.d.ts +8 -0
  148. package/dist/schema/index.js +6 -0
  149. package/dist/schema/index.js.map +1 -1
  150. package/dist/screenshot-tour/index.d.ts +54 -0
  151. package/dist/screenshot-tour/index.js +9 -0
  152. package/dist/screenshot-tour/index.js.map +1 -0
  153. package/dist/section/index.js +3 -3
  154. package/dist/segmented-control/index.js +2 -2
  155. package/dist/select/index.js +2 -2
  156. package/dist/shared/styles.d.ts +7 -1
  157. package/dist/shared/styles.js +3 -1
  158. package/dist/stats/index.js +2 -2
  159. package/dist/steps/index.d.ts +12 -0
  160. package/dist/steps/index.js +4 -3
  161. package/dist/tag-strip/index.d.ts +7 -0
  162. package/dist/tag-strip/index.js +2 -2
  163. package/dist/testimonials/index.d.ts +9 -1
  164. package/dist/testimonials/index.js +3 -3
  165. package/dist/tooltip/index.js +2 -2
  166. package/package.json +26 -2
  167. package/dist/chunk-2DXHPEB5.js.map +0 -1
  168. package/dist/chunk-2FJDNJ7R.js.map +0 -1
  169. package/dist/chunk-4AFOKKSU.js +0 -158
  170. package/dist/chunk-4AFOKKSU.js.map +0 -1
  171. package/dist/chunk-5C6C6K5U.js.map +0 -1
  172. package/dist/chunk-5F5PTVWR.js.map +0 -1
  173. package/dist/chunk-5MY6OWMK.js.map +0 -1
  174. package/dist/chunk-7NIWQWTA.js.map +0 -1
  175. package/dist/chunk-DH53HZPB.js.map +0 -1
  176. package/dist/chunk-EE6PAN3B.js.map +0 -1
  177. package/dist/chunk-EMCQBT3S.js.map +0 -1
  178. package/dist/chunk-FZ36KL73.js.map +0 -1
  179. package/dist/chunk-GJO3RGOB.js.map +0 -1
  180. package/dist/chunk-HMUZON6I.js +0 -202
  181. package/dist/chunk-HMUZON6I.js.map +0 -1
  182. package/dist/chunk-J6EO4R73.js +0 -633
  183. package/dist/chunk-J6EO4R73.js.map +0 -1
  184. package/dist/chunk-KMU6ABQF.js.map +0 -1
  185. package/dist/chunk-MSSH3HFK.js +0 -205
  186. package/dist/chunk-MSSH3HFK.js.map +0 -1
  187. package/dist/chunk-O4FCRKDX.js.map +0 -1
  188. package/dist/chunk-PHEGSCOM.js.map +0 -1
  189. package/dist/chunk-QLA4BH2B.js.map +0 -1
  190. package/dist/chunk-SQ3OZO32.js +0 -486
  191. package/dist/chunk-SQ3OZO32.js.map +0 -1
  192. package/dist/chunk-UAIUBPDN.js +0 -11
  193. package/dist/chunk-UAIUBPDN.js.map +0 -1
  194. package/dist/chunk-WT4OATGP.js.map +0 -1
  195. package/dist/chunk-XUGEXERO.js +0 -708
  196. package/dist/chunk-XUGEXERO.js.map +0 -1
  197. package/dist/chunk-ZRC5BVDX.js.map +0 -1
  198. /package/dist/{chunk-OLA35A2O.js.map → chunk-2GTR37PU.js.map} +0 -0
  199. /package/dist/{chunk-AKJQ345O.js.map → chunk-5AWGZQWU.js.map} +0 -0
  200. /package/dist/{chunk-BLQV2YMO.js.map → chunk-EZOKT7NJ.js.map} +0 -0
  201. /package/dist/{chunk-6D6ROU7X.js.map → chunk-IGMVF3KK.js.map} +0 -0
  202. /package/dist/{chunk-INMSEYT6.js.map → chunk-IVPVYVWG.js.map} +0 -0
  203. /package/dist/{chunk-35TX3AOA.js.map → chunk-NABSRUXG.js.map} +0 -0
  204. /package/dist/{chunk-OELI3IWC.js.map → chunk-PV6OCXXN.js.map} +0 -0
  205. /package/dist/{chunk-MG2VTZA4.js.map → chunk-QS3ANOWN.js.map} +0 -0
  206. /package/dist/{chunk-3OEEOBHB.js.map → chunk-QSJ543V2.js.map} +0 -0
  207. /package/dist/{chunk-FML6AG2V.js.map → chunk-RANC3OI6.js.map} +0 -0
  208. /package/dist/{chunk-YVTFQHVY.js.map → chunk-TEAZZPDQ.js.map} +0 -0
  209. /package/dist/{chunk-AG2COC64.js.map → chunk-VVYQ2DDS.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/booking/Booking.ts","../src/booking/BookingEvents.ts","../src/booking/booking-client.ts","../src/booking/booking-labels.ts"],"sourcesContent":["import { LitElement, css, html, nothing, svg } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\n\nimport { controlBaseStyles, fontFamilyStyles } from '../shared/styles';\nimport {\n BOOKING_CANCELLED_EVENT,\n BOOKING_CREATED_EVENT,\n BOOKING_ERROR_EVENT,\n BOOKING_RESCHEDULED_EVENT,\n type BookingCancelledEventDetail,\n type BookingCreatedEventDetail,\n type BookingErrorEventDetail,\n type BookingErrorKind,\n type BookingRescheduledEventDetail\n} from './BookingEvents';\nimport {\n BOOKING_FIELD_NAMES,\n BOOKING_LIMITS,\n DEFAULT_BOOKING_ERROR_MESSAGES,\n MAX_MONTH_LOOKAHEAD,\n type BookingErrorMessages,\n type BookingErrors,\n type BookingFailureKind,\n type BookingFieldLabels,\n type BookingFieldName,\n type BookingInfo,\n type BookingOutcome,\n type BookingService,\n type BookingSlot,\n type BookingValues,\n addDays,\n addMonths,\n appointmentPath,\n buildBookingPayload,\n buildManageUrl,\n callBookings,\n codePointLengthOf,\n dayKey,\n fillTemplate,\n firstInvalidBookingField,\n groupSlotsByDay,\n monthCells,\n monthWindow,\n parseDayKey,\n readBooking,\n readNothing,\n readReferenceParam,\n readServices,\n readSlots,\n staffIdToSend,\n startOfMonth,\n validateBooking\n} from './booking-client';\nimport { DEFAULT_BOOKING_LABELS, type BookingLabels } from './booking-labels';\n\nconst CHECK_ICON = svg`<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M5 12l5 5L20 7\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path></svg>`;\n\ntype View = 'loading' | 'services' | 'time' | 'details' | 'booking' | 'cancelled' | 'notfound' | 'fatal';\ntype Mode = 'new' | 'reschedule';\ntype Banner = '' | 'booked' | 'rescheduled';\n\n/** How far ahead (in months) the visitor may page the calendar. */\nconst MAX_MONTHS_AHEAD = 12;\n\n/**\n * A booking experience for a website, in place of Microsoft's own Bookings page: pick a service, optionally\n * a staff member (\"Any available\" is the default), pick a day on a calendar and a time, enter name, email,\n * an optional phone and notes, accept the consent box, and get a confirmation with a private link to manage\n * the appointment. It talks to Suite Core's public bookings API under `endpoint`\n * (`{endpoint}/public/v1/bookings/...`, no cookies, no credentials).\n *\n * Times are shown in the visitor's own time zone (through `Intl`, never a fixed zone); the API's instants\n * are UTC. The calendar is a keyboard grid: arrow keys move by day and week, Home/End to the week's start\n * and end, Page Up/Page Down by month. Each step moves focus to its heading, results are announced politely\n * and problems with `role=\"alert\"`.\n *\n * Opening an existing booking: set `reference`, or open the page with `#ref=...` (preferred: a hash is never\n * sent to a server or in a Referer header) or `?ref=...`. The booking shows with Reschedule and Cancel.\n * Reschedule picks a new slot among the availability of the same service. The reference is a signed token and\n * the only key to the booking: it is never put in an event, never logged, and the manage link puts it in the\n * hash. After booking, the link is shown (with a copy button) and a note asks the visitor to keep it private.\n *\n * A hidden honeypot field (`website`) must stay empty. A 409 `slot_taken` reloads the times and says so; a 429\n * shows the wait from `Retry-After`; the text the server sends is shown only for the fields it rejected.\n *\n * Every visible string is in `labels` (English defaults, only the keys given are replaced).\n *\n * @fires st-booking-created - Bubbles and is composed. Detail `{ serviceId: string, start: string }`. No personal data and no reference.\n * @fires st-booking-rescheduled - Bubbles and is composed. Detail `{ serviceId: string, start: string }` (the new start).\n * @fires st-booking-cancelled - Bubbles and is composed. Detail `{ serviceId: string }`.\n * @fires st-booking-error - Bubbles and is composed. Detail `{ kind: 'validation' | 'slot_taken' | 'too_late' | 'not_found' | 'rate_limited' | 'unavailable' }`.\n * @csspart steps - The step indicator.\n * @csspart heading - The heading of the current step.\n * @csspart service - Each service choice.\n * @csspart calendar - The month grid.\n * @csspart day - Each day button.\n * @csspart slot - Each time button.\n * @csspart field - Each field's wrapper (label, control and error).\n * @csspart label - Each field's label.\n * @csspart input - Each text input and the notes textarea.\n * @csspart error - Each field's error message.\n * @csspart button - Every button except the primary one.\n * @csspart primary - The primary button of a step.\n * @csspart success - The success note.\n * @csspart alert - The alert (rate limit, taken slot, unavailable, or a server message that is not on one field).\n * @csspart summary - The service, date and time of a booking.\n */\n@customElement('st-booking')\nexport class Booking extends LitElement {\n static styles = css`\n ${controlBaseStyles}\n\n :host {\n display: block;\n box-sizing: border-box;\n ${fontFamilyStyles}\n }\n\n *,\n *::before,\n *::after {\n box-sizing: border-box;\n }\n\n .root {\n display: flex;\n flex-direction: column;\n gap: 16px;\n min-width: 0;\n color: var(--st-color-text);\n }\n\n /* Text uses the theme's own colour tokens (they swap in dark themes), as st-contact-form does. */\n h2 {\n margin: 0;\n font-size: 22px;\n line-height: 1.3;\n color: var(--st-color-text-strong);\n }\n\n h2:focus-visible {\n outline: 2px solid var(--st-cms-brand-azure);\n outline-offset: 4px;\n }\n\n h3 {\n margin: 0;\n font-size: 16px;\n color: var(--st-color-text-strong);\n }\n\n p {\n margin: 0;\n }\n\n .steps {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n margin: 0;\n padding: 0;\n list-style: none;\n font-size: 13px;\n }\n\n .steps li {\n padding: 4px 12px;\n border-radius: 9999px;\n background: var(--st-color-subtle, var(--st-cms-surface-soft));\n color: var(--st-color-text);\n }\n\n .steps li[aria-current='step'] {\n background: var(--st-cms-brand-navy);\n color: var(--st-cms-on-dark);\n font-weight: var(--st-font-weight-semibold);\n }\n\n .options {\n display: grid;\n gap: 12px;\n margin: 0;\n padding: 0;\n list-style: none;\n }\n\n .service {\n display: flex;\n flex-direction: column;\n gap: 6px;\n width: 100%;\n min-height: 44px;\n padding: 16px 18px;\n border: 1px solid var(--st-color-border, var(--st-cms-primary-200));\n border-radius: 16px;\n background: var(--st-color-surface);\n color: var(--st-color-text);\n font: inherit;\n text-align: left;\n cursor: pointer;\n }\n\n .service:hover {\n border-color: var(--st-cms-brand-navy);\n }\n\n .service-name {\n font-size: 17px;\n font-weight: var(--st-font-weight-semibold);\n color: var(--st-color-text-strong);\n }\n\n .meta {\n font-size: 14px;\n color: var(--st-color-text-muted);\n }\n\n fieldset {\n min-width: 0;\n margin: 0;\n padding: 0;\n border: 0;\n }\n\n legend {\n padding: 0;\n margin-bottom: 8px;\n font-size: 14px;\n font-weight: var(--st-font-weight-semibold);\n color: var(--st-color-text-strong);\n }\n\n .choice {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n min-height: 44px;\n margin-right: 16px;\n font-size: 15px;\n cursor: pointer;\n }\n\n .choice input {\n width: 20px;\n height: 20px;\n margin: 0;\n accent-color: var(--st-cms-brand-navy);\n }\n\n .time-layout {\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n gap: 20px;\n }\n\n @media (min-width: 720px) {\n .time-layout {\n grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);\n }\n }\n\n .month-bar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n margin-bottom: 8px;\n }\n\n .month-name {\n font-size: 16px;\n font-weight: var(--st-font-weight-semibold);\n color: var(--st-color-text-strong);\n }\n\n table {\n width: 100%;\n border-collapse: separate;\n border-spacing: 4px;\n table-layout: fixed;\n }\n\n th {\n padding: 4px 0;\n font-size: 12px;\n font-weight: var(--st-font-weight-semibold);\n color: var(--st-color-text-muted);\n }\n\n td {\n padding: 0;\n text-align: center;\n }\n\n .day {\n width: 100%;\n min-height: 44px;\n padding: 0;\n border: 1px solid transparent;\n border-radius: 12px;\n background: transparent;\n color: var(--st-color-text-muted);\n font: inherit;\n font-size: 15px;\n cursor: default;\n }\n\n .day.has-slots {\n border-color: var(--st-color-border, var(--st-cms-primary-200));\n background: var(--st-color-surface);\n color: var(--st-color-text-strong);\n font-weight: var(--st-font-weight-semibold);\n cursor: pointer;\n }\n\n .day.has-slots:hover {\n border-color: var(--st-cms-brand-navy);\n }\n\n .day[aria-pressed='true'] {\n background: var(--st-cms-brand-navy);\n border-color: var(--st-cms-brand-navy);\n color: var(--st-cms-on-dark);\n }\n\n .slots {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));\n gap: 8px;\n margin: 0;\n padding: 0;\n list-style: none;\n }\n\n .slot {\n width: 100%;\n min-height: 44px;\n padding: 0 8px;\n border: 1px solid var(--st-color-border, var(--st-cms-primary-200));\n border-radius: 12px;\n background: var(--st-color-surface);\n color: var(--st-color-text-strong);\n font: inherit;\n font-size: 15px;\n cursor: pointer;\n }\n\n .slot:hover {\n border-color: var(--st-cms-brand-navy);\n }\n\n .slot[aria-pressed='true'] {\n background: var(--st-cms-brand-navy);\n border-color: var(--st-cms-brand-navy);\n color: var(--st-cms-on-dark);\n }\n\n .day:focus-visible,\n .slot:focus-visible,\n .service:focus-visible,\n .btn:focus-visible,\n .input:focus-visible,\n .choice input:focus-visible,\n .consent input:focus-visible {\n outline: 2px solid var(--st-cms-brand-azure);\n outline-offset: 2px;\n }\n\n .note {\n font-size: 14px;\n color: var(--st-color-text-muted);\n }\n\n .field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n min-width: 0;\n }\n\n .label {\n font-size: 14px;\n font-weight: var(--st-font-weight-semibold);\n color: var(--st-color-text-strong);\n }\n\n .input {\n width: 100%;\n min-height: 44px;\n padding: 10px 14px;\n border: 1px solid var(--st-color-border, var(--st-cms-primary-200));\n border-radius: 12px;\n background: var(--st-color-surface);\n color: var(--st-color-text-strong);\n /* 16px stops iOS zooming into the field. */\n font: inherit;\n font-size: 16px;\n }\n\n .input::placeholder {\n color: var(--st-color-text-muted);\n opacity: 1;\n }\n\n textarea.input {\n min-height: 104px;\n resize: vertical;\n }\n\n .input[aria-invalid='true'] {\n border-color: var(--st-color-danger);\n box-shadow: inset 0 0 0 1px var(--st-color-danger);\n }\n\n .error {\n font-size: 13px;\n line-height: 1.4;\n color: var(--st-color-danger-text);\n }\n\n .counter {\n align-self: flex-end;\n font-size: 12px;\n color: var(--st-color-text-muted);\n }\n\n .counter.over {\n color: var(--st-color-danger-text);\n font-weight: var(--st-font-weight-semibold);\n }\n\n .consent {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n min-height: 44px;\n font-size: 14px;\n line-height: 1.5;\n cursor: pointer;\n }\n\n .consent input {\n flex: none;\n width: 20px;\n height: 20px;\n margin: 2px 0 0;\n accent-color: var(--st-cms-brand-navy);\n }\n\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0 0 0 0);\n white-space: nowrap;\n border: 0;\n }\n\n /* Off-screen, not display:none: the browser still fills it in, a person and a screen reader do not see it. */\n .hp {\n position: absolute;\n left: -10000px;\n top: auto;\n width: 1px;\n height: 1px;\n overflow: hidden;\n }\n\n .actions {\n display: flex;\n flex-wrap: wrap;\n gap: 12px;\n }\n\n .btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-height: 48px;\n padding: 0 24px;\n border: 1px solid var(--st-cms-brand-navy);\n border-radius: 9999px;\n background: transparent;\n color: var(--st-color-text-strong);\n font: inherit;\n font-size: 16px;\n font-weight: var(--st-font-weight-semibold);\n cursor: pointer;\n transition: opacity 150ms ease;\n }\n\n .btn.primary {\n background: var(--st-cms-brand-navy);\n color: var(--st-cms-on-dark);\n }\n\n .btn.danger {\n border-color: var(--st-color-danger);\n color: var(--st-color-danger-text);\n }\n\n .btn:hover:not(:disabled) {\n opacity: 0.92;\n }\n\n .btn:disabled {\n opacity: 0.6;\n cursor: progress;\n }\n\n .icon-btn {\n min-width: 44px;\n padding: 0;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .btn {\n transition: none;\n }\n }\n\n .alert {\n margin: 0;\n }\n\n .alert.has-text {\n padding: 12px 14px;\n border-radius: 12px;\n background: var(--st-color-danger-subtle);\n color: var(--st-color-danger-text);\n font-size: 14px;\n line-height: 1.5;\n }\n\n .success {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 16px 18px;\n border-radius: 16px;\n background: var(--st-color-subtle, var(--st-cms-surface-soft));\n color: var(--st-color-text-strong);\n font-size: 15px;\n line-height: 1.6;\n }\n\n .success-icon {\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border-radius: 9999px;\n background: var(--st-cms-highlight);\n color: var(--st-cms-navy);\n }\n\n .success-icon svg {\n width: 18px;\n height: 18px;\n }\n\n dl.summary {\n display: grid;\n grid-template-columns: max-content minmax(0, 1fr);\n gap: 8px 16px;\n margin: 0;\n padding: 16px 18px;\n border: 1px solid var(--st-color-border, var(--st-cms-primary-200));\n border-radius: 16px;\n background: var(--st-color-surface);\n }\n\n dl.summary dt {\n font-weight: var(--st-font-weight-semibold);\n color: var(--st-color-text-strong);\n }\n\n dl.summary dd {\n margin: 0;\n overflow-wrap: anywhere;\n }\n\n .link-row {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n }\n\n .link-row .input {\n flex: 1 1 220px;\n width: auto;\n }\n\n .loading {\n padding: 24px 0;\n color: var(--st-color-text-muted);\n }\n `;\n\n /** Base URL of the Suite Core API, without a path (`https://api.apps.example.com`). The component calls `{endpoint}/public/v1/bookings/...`. Empty: the component shows the unavailable note without sending anything. */\n @property({ type: String })\n endpoint = '';\n\n /** A booking reference to open (the signed token from a manage link). Empty: the page's `#ref=` or `?ref=` is used, else a new booking starts. Treat it as a secret. */\n @property({ type: String })\n reference = '';\n\n /** Preselects a service by id and skips the service step, when the API lists it. */\n @property({ type: String, attribute: 'service-id' })\n serviceId = '';\n\n /** The first day of the calendar's week: `1` (Monday, the default) or `0` (Sunday). */\n @property({ type: Number, attribute: 'week-start' })\n weekStart: 0 | 1 = 1;\n\n /** Language for dates and times (a BCP 47 tag). Empty uses the page's `lang`, or the browser's. */\n @property({ type: String })\n locale = '';\n\n /** The address the manage link points at. Empty uses the current page. The reference goes in its hash. */\n @property({ type: String, attribute: 'manage-url' })\n manageUrl = '';\n\n /** Replaces the English texts. Only the keys given are replaced. See `BookingLabels`. */\n @property({ attribute: false })\n labels: Partial<BookingLabels> = {};\n\n /** Replaces the English validation messages (`required`, `tooLong`, ...). Only the keys given are replaced. */\n @property({ attribute: false })\n errorMessages: Partial<BookingErrorMessages> = {};\n\n @state() private view: View = 'loading';\n @state() private mode: Mode = 'new';\n @state() private services: BookingService[] = [];\n @state() private service?: BookingService;\n @state() private staffId = '';\n @state() private month: Date = startOfMonth(new Date());\n @state() private slots: BookingSlot[] = [];\n @state() private slotsLoading = false;\n @state() private selectedDay = '';\n @state() private focusDay = '';\n @state() private selectedSlot?: BookingSlot;\n @state() private booking?: BookingInfo;\n @state() private banner: Banner = '';\n @state() private confirmingCancel = false;\n @state() private busy = false;\n @state() private errors: BookingErrors = {};\n @state() private alertText = '';\n @state() private notice = '';\n @state() private notesLength = 0;\n\n /** The reference in use: the property, the page URL, or the one the API just gave. Never rendered or sent anywhere but the API. */\n private activeReference = '';\n private inflight: AbortController | null = null;\n private slotsRun = 0;\n /** What the details form held when the visitor went back to change the time, so nothing typed is lost. */\n private draft: Partial<Record<'name' | 'email' | 'phone' | 'notes', string>> & { consent?: boolean } = {};\n\n disconnectedCallback(): void {\n this.inflight?.abort();\n this.inflight = null;\n this.slotsRun += 1;\n super.disconnectedCallback();\n }\n\n protected updated(changed: Map<PropertyKey, unknown>): void {\n if (changed.has('endpoint') || changed.has('reference') || changed.has('serviceId')) void this.start();\n }\n\n /* ------------------------------------------------------------ text and formatting */\n\n private text(key: keyof BookingLabels, values: Record<string, string | number> = {}): string {\n const label = this.labels[key];\n return fillTemplate(typeof label === 'string' ? label : DEFAULT_BOOKING_LABELS[key], values);\n }\n\n private messages(): BookingErrorMessages {\n const merged = { ...DEFAULT_BOOKING_ERROR_MESSAGES };\n for (const key of Object.keys(merged) as (keyof BookingErrorMessages)[]) {\n const override = this.errorMessages[key];\n if (typeof override === 'string') merged[key] = override;\n }\n return merged;\n }\n\n private fieldLabels(): BookingFieldLabels {\n return { name: this.text('nameLabel'), email: this.text('emailLabel'), phone: this.text('phoneLabel'), notes: this.text('notesLabel') };\n }\n\n private format(options: Intl.DateTimeFormatOptions): Intl.DateTimeFormat {\n const tag = this.locale || document.documentElement.lang || undefined;\n try {\n return new Intl.DateTimeFormat(tag, options);\n } catch {\n return new Intl.DateTimeFormat(undefined, options);\n }\n }\n\n private fullDate(date: Date): string {\n return this.format({ weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }).format(date);\n }\n\n private timeOfDay(iso: string): string {\n return this.format({ hour: 'numeric', minute: '2-digit' }).format(new Date(iso));\n }\n\n private whenText(iso: string): string {\n return this.format({ weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: '2-digit', timeZoneName: 'short' }).format(new Date(iso));\n }\n\n private monthName(month: Date): string {\n return this.format({ month: 'long', year: 'numeric' }).format(month);\n }\n\n private zoneName(): string {\n return new Intl.DateTimeFormat().resolvedOptions().timeZone;\n }\n\n /* ------------------------------------------------------------ flow */\n\n private resetState(): void {\n this.service = undefined;\n this.staffId = '';\n this.slots = [];\n this.selectedDay = '';\n this.focusDay = '';\n this.selectedSlot = undefined;\n this.booking = undefined;\n this.banner = '';\n this.confirmingCancel = false;\n this.busy = false;\n this.errors = {};\n this.alertText = '';\n this.notice = '';\n this.notesLength = 0;\n this.draft = {};\n this.mode = 'new';\n }\n\n /** Opens an existing booking when there is a reference, else starts at the services. */\n private async start(): Promise<void> {\n this.inflight?.abort();\n this.slotsRun += 1;\n const controller = new AbortController();\n this.inflight = controller;\n this.resetState();\n this.view = 'loading';\n this.activeReference = this.reference.trim() || readReferenceParam(window.location.search, window.location.hash) || '';\n if (this.activeReference !== '') await this.loadBooking(controller);\n else await this.loadServices(controller);\n }\n\n private async loadServices(controller: AbortController): Promise<void> {\n const outcome = await callBookings({ base: this.endpoint, method: 'GET', path: '/services', readOk: readServices, signal: controller.signal });\n if (this.inflight !== controller) return;\n if (outcome.kind !== 'ok') {\n this.fail(outcome.kind, outcome, 'fatal');\n return;\n }\n this.services = outcome.data;\n const preset = outcome.data.find(item => item.id === this.serviceId.trim());\n if (preset) {\n await this.chooseService(preset);\n return;\n }\n this.go('services');\n }\n\n private async loadBooking(controller: AbortController): Promise<void> {\n const outcome = await callBookings({\n base: this.endpoint,\n method: 'GET',\n path: appointmentPath(this.activeReference),\n readOk: readBooking,\n signal: controller.signal\n });\n if (this.inflight !== controller) return;\n if (outcome.kind !== 'ok') {\n this.fail(outcome.kind, outcome, outcome.kind === 'not_found' ? 'notfound' : 'fatal');\n return;\n }\n this.booking = outcome.data;\n this.go('booking');\n }\n\n /** Switches the step, clears the last problem and moves focus to the new step's heading. */\n private go(view: View): void {\n this.view = view;\n this.alertText = '';\n void this.updateComplete.then(() => this.renderRoot.querySelector<HTMLElement>('#bk-heading')?.focus());\n }\n\n /** Shows the note for a failed call and reports it. `next` is the step to show (when it should change). */\n private fail(kind: BookingFailureKind, outcome: BookingOutcome<unknown>, next?: View): void {\n this.busy = false;\n if (next) {\n this.view = next;\n void this.updateComplete.then(() => this.renderRoot.querySelector<HTMLElement>('#bk-heading')?.focus());\n }\n switch (kind) {\n case 'slot_taken':\n this.alertText = this.text('slotTakenNote');\n break;\n case 'too_late':\n this.alertText = this.text('tooLateNote');\n break;\n case 'not_found':\n this.alertText = this.text('notFoundNote');\n break;\n case 'rate_limited': {\n const seconds = outcome.kind === 'rate_limited' ? outcome.retryAfterSeconds : undefined;\n this.alertText = seconds === undefined ? this.text('rateLimitedGenericNote') : this.text('rateLimitedNote', { seconds });\n break;\n }\n case 'validation':\n this.alertText = this.text('validationNote');\n break;\n case 'unavailable':\n this.alertText = this.text('errorNote');\n break;\n }\n this.dispatchEvent(\n new CustomEvent<BookingErrorEventDetail>(BOOKING_ERROR_EVENT, { detail: { kind: kind satisfies BookingErrorKind }, bubbles: true, composed: true })\n );\n }\n\n private async chooseService(service: BookingService): Promise<void> {\n this.service = service;\n this.staffId = '';\n this.mode = 'new';\n this.selectedSlot = undefined;\n this.selectedDay = '';\n this.month = startOfMonth(new Date());\n this.go('time');\n await this.loadSlots(true);\n }\n\n /** Loads the current month's times. With `advance`, an empty month moves on to the next, up to a few months. */\n private async loadSlots(advance: boolean): Promise<void> {\n const service = this.service;\n if (!service) return;\n const run = (this.slotsRun += 1);\n this.slotsLoading = true;\n this.slots = [];\n let lookahead = 0;\n for (;;) {\n const { from, to } = monthWindow(this.month, new Date());\n const query = new URLSearchParams({ serviceId: service.id, from: from.toISOString(), to: to.toISOString() });\n const staff = staffIdToSend(this.staffId);\n if (staff) query.set('staffId', staff);\n const outcome = await callBookings({\n base: this.endpoint,\n method: 'GET',\n path: `/availability?${query.toString()}`,\n readOk: readSlots,\n signal: this.inflight?.signal\n });\n if (run !== this.slotsRun || !this.isConnected) return;\n if (outcome.kind !== 'ok') {\n this.slotsLoading = false;\n this.fail(outcome.kind, outcome);\n return;\n }\n if (outcome.data.length === 0 && advance && lookahead < MAX_MONTH_LOOKAHEAD) {\n lookahead += 1;\n this.month = addMonths(this.month, 1);\n continue;\n }\n this.slots = outcome.data;\n break;\n }\n this.slotsLoading = false;\n const days = groupSlotsByDay(this.slots);\n const first = [...days.keys()][0];\n this.focusDay = first ?? dayKey(this.month);\n this.notice = this.slots.length === 0 ? this.text('noSlots', { month: this.monthName(this.month) }) : '';\n }\n\n private async shiftMonth(count: number): Promise<void> {\n const next = addMonths(this.month, count);\n const nowMonth = startOfMonth(new Date());\n if (next.getTime() < nowMonth.getTime() || next.getTime() > addMonths(nowMonth, MAX_MONTHS_AHEAD).getTime()) return;\n this.month = next;\n this.selectedDay = '';\n this.selectedSlot = undefined;\n await this.loadSlots(false);\n }\n\n private onStaffChange(event: Event): void {\n this.staffId = (event.target as HTMLInputElement).value;\n this.selectedDay = '';\n this.selectedSlot = undefined;\n this.alertText = '';\n void this.loadSlots(false);\n }\n\n private pickDay(key: string): void {\n const days = groupSlotsByDay(this.slots);\n this.focusDay = key;\n if (!days.has(key)) return;\n this.selectedDay = key;\n this.selectedSlot = undefined;\n this.alertText = '';\n const count = days.get(key)?.length ?? 0;\n this.notice = this.text('slotsAvailable', { count, date: this.fullDate(parseDayKey(key)) });\n }\n\n private pickSlot(slot: BookingSlot): void {\n this.selectedSlot = slot;\n this.alertText = '';\n }\n\n private onGridKeydown(event: KeyboardEvent): void {\n const key = (event.target as HTMLElement).dataset.day;\n if (!key) return;\n const current = parseDayKey(key);\n const moves: Record<string, Date> = {\n ArrowLeft: addDays(current, -1),\n ArrowRight: addDays(current, 1),\n ArrowUp: addDays(current, -7),\n ArrowDown: addDays(current, 7),\n Home: addDays(current, -((current.getDay() - this.weekStart + 7) % 7)),\n End: addDays(current, 6 - ((current.getDay() - this.weekStart + 7) % 7)),\n PageUp: new Date(current.getFullYear(), current.getMonth() - 1, current.getDate()),\n PageDown: new Date(current.getFullYear(), current.getMonth() + 1, current.getDate())\n };\n const target = moves[event.key];\n if (!target) return;\n event.preventDefault();\n const targetKey = dayKey(target);\n const sameMonth = target.getMonth() === this.month.getMonth() && target.getFullYear() === this.month.getFullYear();\n this.focusDay = targetKey;\n if (!sameMonth) void this.shiftMonth(this.monthDelta(target)).then(() => this.focusDayButton(targetKey));\n else this.focusDayButton(targetKey);\n }\n\n private monthDelta(target: Date): number {\n return (target.getFullYear() - this.month.getFullYear()) * 12 + target.getMonth() - this.month.getMonth();\n }\n\n private focusDayButton(key: string): void {\n this.focusDay = key;\n void this.updateComplete.then(() => this.renderRoot.querySelector<HTMLElement>(`[data-day=\"${key}\"]`)?.focus());\n }\n\n private continueFromTime(): void {\n if (!this.selectedSlot) return;\n if (this.mode === 'reschedule') void this.reschedule(this.selectedSlot);\n else this.go('details');\n }\n\n private backFromTime(): void {\n if (this.mode === 'reschedule') this.go('booking');\n else if (this.services.length > 0) this.go('services');\n }\n\n /* ------------------------------------------------------------ calls */\n\n private async book(event: SubmitEvent): Promise<void> {\n event.preventDefault();\n const slot = this.selectedSlot;\n const service = this.service;\n if (this.busy || !slot || !service) return;\n const form = event.currentTarget as HTMLFormElement;\n const values = this.readValues(form);\n this.draft = { name: values.name, email: values.email, phone: values.phone, notes: values.notes, consent: values.consent };\n this.alertText = '';\n const errors = validateBooking(values, this.fieldLabels(), this.messages());\n this.errors = errors;\n const invalid = firstInvalidBookingField(errors);\n if (invalid) {\n this.focusField(invalid);\n return;\n }\n const payload = buildBookingPayload(values, { serviceId: service.id, staffId: staffIdToSend(this.staffId), start: slot.start });\n this.busy = true;\n const controller = this.freshController();\n const outcome = await callBookings({ base: this.endpoint, method: 'POST', path: '/appointments', body: payload, readOk: readBooking, signal: controller.signal });\n if (this.inflight !== controller) return;\n this.busy = false;\n if (outcome.kind === 'ok') {\n this.booking = outcome.data;\n this.activeReference = outcome.data.reference;\n this.banner = 'booked';\n this.draft = {};\n this.errors = {};\n this.go('booking');\n this.dispatchEvent(\n new CustomEvent<BookingCreatedEventDetail>(BOOKING_CREATED_EVENT, { detail: { serviceId: outcome.data.serviceId || service.id, start: outcome.data.start }, bubbles: true, composed: true })\n );\n return;\n }\n if (outcome.kind === 'validation') {\n this.applyServerErrors(outcome.errors);\n this.fail('validation', outcome);\n return;\n }\n if (outcome.kind === 'slot_taken') {\n this.selectedSlot = undefined;\n this.fail('slot_taken', outcome, 'time');\n void this.loadSlots(false).then(() => {\n this.alertText = this.text('slotTakenNote');\n });\n return;\n }\n this.fail(outcome.kind, outcome);\n }\n\n /** Server messages go on the fields that exist; a rejected start or staff means the time must be picked again. */\n private applyServerErrors(errors: Record<string, string>): void {\n const shown: BookingErrors = {};\n const rest: string[] = [];\n const names: readonly string[] = BOOKING_FIELD_NAMES;\n for (const [key, message] of Object.entries(errors)) {\n if (names.includes(key)) shown[key as BookingFieldName] = message;\n else rest.push(message);\n }\n this.errors = shown;\n const invalid = firstInvalidBookingField(shown);\n if (invalid) this.focusField(invalid);\n if (rest.length > 0) {\n this.selectedSlot = undefined;\n void this.loadSlots(false);\n this.go('time');\n this.alertText = rest.join(' ');\n }\n }\n\n private async reschedule(slot: BookingSlot): Promise<void> {\n const booking = this.booking;\n if (this.busy || !booking) return;\n this.busy = true;\n const controller = this.freshController();\n const outcome = await callBookings({\n base: this.endpoint,\n method: 'POST',\n path: appointmentPath(this.activeReference, '/reschedule'),\n body: { start: slot.start },\n readOk: readBooking,\n signal: controller.signal\n });\n if (this.inflight !== controller) return;\n this.busy = false;\n if (outcome.kind === 'ok') {\n this.booking = outcome.data;\n this.activeReference = outcome.data.reference;\n this.banner = 'rescheduled';\n this.mode = 'new';\n this.go('booking');\n this.dispatchEvent(\n new CustomEvent<BookingRescheduledEventDetail>(BOOKING_RESCHEDULED_EVENT, { detail: { serviceId: outcome.data.serviceId || booking.serviceId, start: outcome.data.start }, bubbles: true, composed: true })\n );\n return;\n }\n if (outcome.kind === 'slot_taken') {\n this.selectedSlot = undefined;\n this.fail('slot_taken', outcome);\n void this.loadSlots(false).then(() => {\n this.alertText = this.text('slotTakenNote');\n });\n return;\n }\n if (outcome.kind === 'too_late') {\n this.mode = 'new';\n this.fail('too_late', outcome, 'booking');\n return;\n }\n this.fail(outcome.kind, outcome, outcome.kind === 'not_found' ? 'notfound' : undefined);\n }\n\n private startReschedule(): void {\n const booking = this.booking;\n if (!booking) return;\n this.service = { id: booking.serviceId, name: booking.serviceName, description: '', durationMinutes: 0, online: false, staff: [] };\n this.staffId = '';\n this.mode = 'reschedule';\n this.selectedSlot = undefined;\n this.selectedDay = '';\n this.banner = '';\n this.confirmingCancel = false;\n this.month = startOfMonth(new Date());\n this.go('time');\n void this.loadSlots(true);\n }\n\n private async cancelBooking(): Promise<void> {\n const booking = this.booking;\n if (this.busy || !booking) return;\n this.busy = true;\n const controller = this.freshController();\n const outcome = await callBookings({ base: this.endpoint, method: 'DELETE', path: appointmentPath(this.activeReference), readOk: readNothing, signal: controller.signal });\n if (this.inflight !== controller) return;\n this.busy = false;\n this.confirmingCancel = false;\n if (outcome.kind === 'ok') {\n this.activeReference = '';\n this.banner = '';\n this.go('cancelled');\n this.dispatchEvent(\n new CustomEvent<BookingCancelledEventDetail>(BOOKING_CANCELLED_EVENT, { detail: { serviceId: booking.serviceId }, bubbles: true, composed: true })\n );\n return;\n }\n this.fail(outcome.kind, outcome, outcome.kind === 'not_found' ? 'notfound' : undefined);\n }\n\n private freshController(): AbortController {\n this.inflight?.abort();\n const controller = new AbortController();\n this.inflight = controller;\n return controller;\n }\n\n private bookAnother(): void {\n this.reference = '';\n this.activeReference = '';\n this.inflight?.abort();\n const controller = new AbortController();\n this.inflight = controller;\n this.resetState();\n this.view = 'loading';\n void this.loadServices(controller);\n }\n\n private async copyLink(): Promise<void> {\n const link = this.manageLink();\n try {\n await navigator.clipboard.writeText(link);\n this.notice = this.text('linkCopied');\n } catch {\n const input = this.renderRoot.querySelector<HTMLInputElement>('#bk-link');\n input?.focus();\n input?.select();\n }\n }\n\n private manageLink(): string {\n return buildManageUrl(this.manageUrl.trim() || window.location.href, this.activeReference);\n }\n\n /* ------------------------------------------------------------ details form */\n\n private readText(form: HTMLFormElement, name: string): string {\n const field = form.elements.namedItem(name);\n return field instanceof HTMLInputElement || field instanceof HTMLTextAreaElement ? field.value : '';\n }\n\n private readValues(form: HTMLFormElement): BookingValues {\n const consent = form.elements.namedItem('consent');\n return {\n name: this.readText(form, 'name'),\n email: this.readText(form, 'email'),\n phone: this.readText(form, 'phone'),\n notes: this.readText(form, 'notes'),\n consent: consent instanceof HTMLInputElement && consent.checked,\n website: this.readText(form, 'website')\n };\n }\n\n private focusField(name: BookingFieldName): void {\n void this.updateComplete.then(() => this.renderRoot.querySelector<HTMLElement>(`#bk-${name}`)?.focus());\n }\n\n /* ------------------------------------------------------------ rendering */\n\n private heading(text: string) {\n return html`<h2 id=\"bk-heading\" part=\"heading\" tabindex=\"-1\">${text}</h2>`;\n }\n\n private renderSteps() {\n if (this.mode === 'reschedule' || !['services', 'time', 'details'].includes(this.view)) return nothing;\n const steps: { view: View; label: string }[] = [\n { view: 'services', label: this.text('stepService') },\n { view: 'time', label: this.text('stepTime') },\n { view: 'details', label: this.text('stepDetails') }\n ];\n return html`<ol class=\"steps\" part=\"steps\" aria-label=${this.text('stepsLabel')}>\n ${steps.map(step => html`<li aria-current=${step.view === this.view ? 'step' : nothing}>${step.label}</li>`)}\n </ol>`;\n }\n\n private renderServices() {\n return html`\n ${this.heading(this.text('serviceHeading'))}\n ${this.services.length === 0\n ? html`<p class=\"note\">${this.text('noServices')}</p>`\n : html`<ul class=\"options\">\n ${this.services.map(\n service => html`<li>\n <button class=\"service\" part=\"service\" type=\"button\" @click=${() => void this.chooseService(service)}>\n <span class=\"service-name\">${service.name}</span>\n ${service.description ? html`<span>${service.description}</span>` : nothing}\n <span class=\"meta\">\n ${service.durationMinutes > 0 ? this.text('duration', { minutes: service.durationMinutes }) : nothing}${service.online\n ? html`${service.durationMinutes > 0 ? ' · ' : ''}${this.text('online')}`\n : nothing}\n </span>\n </button>\n </li>`\n )}\n </ul>`}\n `;\n }\n\n private renderStaff() {\n const staff = this.service?.staff ?? [];\n if (this.mode === 'reschedule' || staff.length < 2) return nothing;\n return html`<fieldset>\n <legend>${this.text('staffLegend')}</legend>\n <label class=\"choice\">\n <input type=\"radio\" name=\"staff\" value=\"\" .checked=${this.staffId === ''} @change=${this.onStaffChange} />\n ${this.text('anyStaff')}\n </label>\n ${staff.map(\n member => html`<label class=\"choice\">\n <input type=\"radio\" name=\"staff\" value=${member.id} .checked=${this.staffId === member.id} @change=${this.onStaffChange} />\n ${member.name}\n </label>`\n )}\n </fieldset>`;\n }\n\n private renderCalendar(days: Map<string, BookingSlot[]>) {\n const first = startOfMonth(new Date());\n const canGoBack = this.month.getTime() > first.getTime();\n const canGoForward = this.month.getTime() < addMonths(first, MAX_MONTHS_AHEAD).getTime();\n const cells = monthCells(this.month, this.weekStart === 0 ? 0 : 1);\n const weekdays = Array.from({ length: 7 }, (_, index) => {\n const date = new Date(2021, 0, 3 + ((index + this.weekStart) % 7)); // 3 Jan 2021 was a Sunday\n return { long: this.format({ weekday: 'long' }).format(date), short: this.format({ weekday: 'short' }).format(date) };\n });\n const todayKey = dayKey(new Date());\n const monthKeys = cells.filter((cell): cell is Date => cell !== null).map(dayKey);\n const rovingKey = monthKeys.includes(this.focusDay) ? this.focusDay : (monthKeys.find(key => days.has(key)) ?? monthKeys[0]);\n const rows: (Date | null)[][] = [];\n for (let index = 0; index < cells.length; index += 7) rows.push(cells.slice(index, index + 7));\n return html`<div>\n <div class=\"month-bar\">\n <button class=\"btn icon-btn\" part=\"button\" type=\"button\" ?disabled=${!canGoBack || this.slotsLoading} aria-label=${this.text('previousMonth')} @click=${() => void this.shiftMonth(-1)}>‹</button>\n <span class=\"month-name\" id=\"bk-month\" aria-live=\"polite\">${this.monthName(this.month)}</span>\n <button class=\"btn icon-btn\" part=\"button\" type=\"button\" ?disabled=${!canGoForward || this.slotsLoading} aria-label=${this.text('nextMonth')} @click=${() => void this.shiftMonth(1)}>›</button>\n </div>\n <table part=\"calendar\" role=\"grid\" aria-labelledby=\"bk-month\" aria-busy=${this.slotsLoading ? 'true' : 'false'} @keydown=${this.onGridKeydown}>\n <thead>\n <tr>${weekdays.map(day => html`<th scope=\"col\" abbr=${day.long}>${day.short}</th>`)}</tr>\n </thead>\n <tbody>\n ${rows.map(\n row => html`<tr>\n ${row.map(cell => {\n if (!cell) return html`<td></td>`;\n const key = dayKey(cell);\n const available = days.has(key) && key >= todayKey;\n return html`<td role=\"gridcell\">\n <button\n class=\"day ${available ? 'has-slots' : ''}\"\n part=\"day\"\n type=\"button\"\n data-day=${key}\n tabindex=${key === rovingKey ? '0' : '-1'}\n aria-disabled=${available ? 'false' : 'true'}\n aria-pressed=${available ? (key === this.selectedDay ? 'true' : 'false') : nothing}\n aria-label=${this.fullDate(cell)}\n @click=${() => this.pickDay(key)}\n >\n ${cell.getDate()}\n </button>\n </td>`;\n })}\n </tr>`\n )}\n </tbody>\n </table>\n </div>`;\n }\n\n private renderTime() {\n const days = groupSlotsByDay(this.slots);\n const daySlots = days.get(this.selectedDay) ?? [];\n const heading = this.mode === 'reschedule' ? this.text('rescheduleHeading') : this.text('timeHeading');\n const dayDate = this.selectedDay ? parseDayKey(this.selectedDay) : undefined;\n return html`\n ${this.heading(heading)}\n ${this.service ? html`<p class=\"meta\">${this.service.name}</p>` : nothing}\n ${this.renderStaff()}\n <div class=\"time-layout\">\n ${this.renderCalendar(days)}\n <div>\n ${this.slotsLoading\n ? html`<p class=\"loading\" role=\"status\">${this.text('loading')}</p>`\n : this.slots.length === 0\n ? html`<p class=\"note\">${this.text('noSlots', { month: this.monthName(this.month) })}</p>`\n : dayDate\n ? html`<h3>${this.text('timesHeading', { date: this.fullDate(dayDate) })}</h3>\n <ul class=\"slots\" aria-label=${this.text('timesHeading', { date: this.fullDate(dayDate) })}>\n ${daySlots.map(\n slot => html`<li>\n <button class=\"slot\" part=\"slot\" type=\"button\" aria-pressed=${slot === this.selectedSlot ? 'true' : 'false'} @click=${() => this.pickSlot(slot)}>\n ${this.timeOfDay(slot.start)}\n </button>\n </li>`\n )}\n </ul>`\n : html`<p class=\"note\">${this.text('chooseDay')}</p>`}\n <p class=\"note\">${this.text('timeZoneNote', { zone: this.zoneName() })}</p>\n </div>\n </div>\n <div class=\"actions\">\n ${this.mode === 'reschedule' || this.services.length > 0\n ? html`<button class=\"btn\" part=\"button\" type=\"button\" @click=${this.backFromTime}>${this.text('back')}</button>`\n : nothing}\n <button class=\"btn primary\" part=\"primary\" type=\"button\" ?disabled=${!this.selectedSlot || this.busy} @click=${this.continueFromTime}>\n ${this.mode === 'reschedule' ? this.text('confirmReschedule') : this.text('continue')}\n </button>\n </div>\n `;\n }\n\n private requiredMark() {\n return html`<span aria-hidden=\"true\"> *</span><span class=\"sr-only\"> (${this.text('requiredLabel')})</span>`;\n }\n\n private renderInput(name: 'name' | 'email' | 'phone', label: string, options: { type: string; autocomplete: string; placeholder?: string; required: boolean }) {\n const error = this.errors[name];\n return html`<div class=\"field\" part=\"field\">\n <label class=\"label\" part=\"label\" for=\"bk-${name}\">${label}${options.required ? this.requiredMark() : nothing}</label>\n <input\n class=\"input\"\n part=\"input\"\n id=\"bk-${name}\"\n name=${name}\n type=${options.type}\n autocomplete=${options.autocomplete}\n inputmode=${name === 'phone' ? 'tel' : nothing}\n placeholder=${options.placeholder || nothing}\n .value=${this.draft[name] ?? ''}\n ?required=${options.required}\n aria-invalid=${error ? 'true' : 'false'}\n aria-describedby=${error ? `bk-${name}-error` : nothing}\n />\n ${error ? html`<p class=\"error\" part=\"error\" id=\"bk-${name}-error\">${error}</p>` : nothing}\n </div>`;\n }\n\n private renderDetails() {\n const slot = this.selectedSlot;\n const notesError = this.errors.notes;\n const consentError = this.errors.consent;\n const over = this.notesLength > BOOKING_LIMITS.notesMax;\n return html`\n ${this.heading(this.text('detailsHeading'))}\n ${this.service && slot ? html`<p class=\"meta\" part=\"summary\">${this.service.name} · ${this.whenText(slot.start)}</p>` : nothing}\n <form novalidate aria-busy=${this.busy ? 'true' : 'false'} @submit=${this.book} class=\"root\">\n <p class=\"note\">${this.text('requiredNote')}</p>\n ${this.renderInput('name', this.text('nameLabel'), { type: 'text', autocomplete: 'name', placeholder: this.text('namePlaceholder'), required: true })}\n ${this.renderInput('email', this.text('emailLabel'), { type: 'email', autocomplete: 'email', placeholder: this.text('emailPlaceholder'), required: true })}\n ${this.renderInput('phone', this.text('phoneLabel'), { type: 'tel', autocomplete: 'tel', required: false })}\n <div class=\"field\" part=\"field\">\n <label class=\"label\" part=\"label\" for=\"bk-notes\">${this.text('notesLabel')}</label>\n <textarea\n class=\"input\"\n part=\"input\"\n id=\"bk-notes\"\n name=\"notes\"\n rows=\"4\"\n placeholder=${this.text('notesPlaceholder') || nothing}\n .value=${this.draft.notes ?? ''}\n aria-invalid=${notesError ? 'true' : 'false'}\n aria-describedby=${notesError ? 'bk-notes-error' : nothing}\n @input=${(event: Event) => (this.notesLength = codePointLengthOf((event.target as HTMLTextAreaElement).value.trim()))}\n ></textarea>\n ${this.notesLength >= BOOKING_LIMITS.notesMax * 0.8\n ? html`<p class=\"counter ${over ? 'over' : ''}\">${this.text('notesCounter', { count: this.notesLength, max: BOOKING_LIMITS.notesMax })}</p>`\n : nothing}\n ${notesError ? html`<p class=\"error\" part=\"error\" id=\"bk-notes-error\">${notesError}</p>` : nothing}\n </div>\n <div class=\"field\" part=\"field\">\n <label class=\"consent\">\n <input\n type=\"checkbox\"\n id=\"bk-consent\"\n name=\"consent\"\n required\n .checked=${this.draft.consent === true}\n aria-invalid=${consentError ? 'true' : 'false'}\n aria-describedby=${consentError ? 'bk-consent-error' : nothing}\n />\n <span>${this.text('consentLabel')}${this.requiredMark()}</span>\n </label>\n ${consentError ? html`<p class=\"error\" part=\"error\" id=\"bk-consent-error\">${consentError}</p>` : nothing}\n </div>\n <div class=\"hp\" aria-hidden=\"true\" inert>\n <input type=\"text\" name=\"website\" tabindex=\"-1\" autocomplete=\"off\" aria-hidden=\"true\" />\n </div>\n <div class=\"actions\">\n <button class=\"btn\" part=\"button\" type=\"button\" ?disabled=${this.busy} @click=${() => this.go('time')}>${this.text('back')}</button>\n <button class=\"btn primary\" part=\"primary\" type=\"submit\" ?disabled=${this.busy}>${this.busy ? this.text('sending') : this.text('submit')}</button>\n </div>\n </form>\n `;\n }\n\n private renderBooking() {\n const booking = this.booking;\n if (!booking) return nothing;\n const heading = this.banner === 'booked' ? this.text('bookedHeading') : this.text('bookingHeading');\n return html`\n ${this.heading(heading)}\n ${this.banner\n ? html`<div class=\"success\" part=\"success\">\n <span class=\"success-icon\" aria-hidden=\"true\">${CHECK_ICON}</span>\n <p>${this.banner === 'booked' ? this.text('bookedNote') : this.text('rescheduledNote')}</p>\n </div>`\n : nothing}\n <dl class=\"summary\" part=\"summary\">\n <dt>${this.text('serviceLabel')}</dt>\n <dd>${booking.serviceName}</dd>\n <dt>${this.text('whenLabel')}</dt>\n <dd>${this.whenText(booking.start)}</dd>\n </dl>\n ${this.banner === 'booked'\n ? html`<div class=\"field\">\n <label class=\"label\" for=\"bk-link\">${this.text('manageLinkLabel')}</label>\n <div class=\"link-row\">\n <input class=\"input\" id=\"bk-link\" type=\"text\" readonly aria-describedby=\"bk-link-hint\" .value=${this.manageLink()} @focus=${(event: Event) => (event.target as HTMLInputElement).select()} />\n <button class=\"btn\" part=\"button\" type=\"button\" @click=${() => void this.copyLink()}>${this.text('copyLink')}</button>\n </div>\n <p class=\"note\" id=\"bk-link-hint\">${this.text('manageLinkHint')}</p>\n </div>`\n : nothing}\n ${this.confirmingCancel\n ? html`<div role=\"group\" aria-labelledby=\"bk-cancel-q\" class=\"field\">\n <p id=\"bk-cancel-q\" class=\"label\">${this.text('cancelConfirm')}</p>\n <div class=\"actions\">\n <button class=\"btn danger\" part=\"button\" type=\"button\" ?disabled=${this.busy} @click=${() => void this.cancelBooking()}>${this.text('cancelYes')}</button>\n <button class=\"btn\" part=\"button\" type=\"button\" ?disabled=${this.busy} @click=${() => (this.confirmingCancel = false)}>${this.text('cancelNo')}</button>\n </div>\n </div>`\n : html`<div class=\"actions\">\n <button class=\"btn primary\" part=\"primary\" type=\"button\" @click=${this.startReschedule}>${this.text('reschedule')}</button>\n <button class=\"btn danger\" part=\"button\" type=\"button\" @click=${() => (this.confirmingCancel = true)}>${this.text('cancel')}</button>\n </div>`}\n `;\n }\n\n private renderCancelled() {\n return html`\n ${this.heading(this.text('cancelledHeading'))}\n <p>${this.text('cancelledNote')}</p>\n <div class=\"actions\"><button class=\"btn primary\" part=\"primary\" type=\"button\" @click=${this.bookAnother}>${this.text('bookAnother')}</button></div>\n `;\n }\n\n private renderRetry(label: string) {\n return html`<div class=\"actions\"><button class=\"btn primary\" part=\"primary\" type=\"button\" @click=${() => void this.start()}>${label}</button></div>`;\n }\n\n private renderView() {\n switch (this.view) {\n case 'loading':\n return html`<p class=\"loading\" role=\"status\">${this.text('loading')}</p>`;\n case 'services':\n return this.renderServices();\n case 'time':\n return this.renderTime();\n case 'details':\n return this.renderDetails();\n case 'booking':\n return this.renderBooking();\n case 'cancelled':\n return this.renderCancelled();\n case 'notfound':\n return html`${this.heading(this.text('bookingHeading'))}\n <div class=\"actions\"><button class=\"btn primary\" part=\"primary\" type=\"button\" @click=${this.bookAnother}>${this.text('bookAnother')}</button></div>`;\n case 'fatal':\n return html`${this.heading(this.text('bookingHeading'))}${this.renderRetry(this.text('retry'))}`;\n }\n }\n\n render() {\n return html`\n <div class=\"root\" aria-busy=${this.view === 'loading' || this.slotsLoading ? 'true' : 'false'}>\n ${this.renderSteps()}\n <div class=\"alert ${this.alertText ? 'has-text' : ''}\" part=\"alert\" role=\"alert\">${this.alertText}</div>\n <p class=\"sr-only\" role=\"status\" aria-live=\"polite\">${this.notice}</p>\n ${this.renderView()}\n </div>\n `;\n }\n}\n","/*\n * Events of `st-booking`. They bubble and are composed, and none of them carries personal data (no name,\n * e-mail address, phone number or notes) or the booking reference, which is the only key to the booking.\n */\n\n/** Fired on `st-booking` once a new appointment is booked. Detail `{ serviceId, start }`. Bubbles and is composed. */\nexport const BOOKING_CREATED_EVENT = 'st-booking-created';\n\n/** Fired on `st-booking` once an appointment is moved. Detail `{ serviceId, start }` (the new start). Bubbles and is composed. */\nexport const BOOKING_RESCHEDULED_EVENT = 'st-booking-rescheduled';\n\n/** Fired on `st-booking` once an appointment is cancelled. Detail `{ serviceId }`. Bubbles and is composed. */\nexport const BOOKING_CANCELLED_EVENT = 'st-booking-cancelled';\n\n/** Fired on `st-booking` when a call was not accepted. Detail `{ kind }`. Bubbles and is composed. */\nexport const BOOKING_ERROR_EVENT = 'st-booking-error';\n\n/**\n * Why a call was not accepted: `validation` (the server rejected a field), `slot_taken` (someone else took\n * the time), `too_late` (the appointment has started or is too close to change), `not_found` (no such\n * booking or service), `rate_limited` (too many requests) or `unavailable` (the API could not be reached,\n * is switched off, or failed).\n */\nexport type BookingErrorKind = 'validation' | 'slot_taken' | 'too_late' | 'not_found' | 'rate_limited' | 'unavailable';\n\nexport interface BookingCreatedEventDetail {\n serviceId: string;\n /** RFC 3339 UTC instant. */\n start: string;\n}\n\nexport interface BookingRescheduledEventDetail {\n serviceId: string;\n /** RFC 3339 UTC instant of the new time. */\n start: string;\n}\n\nexport interface BookingCancelledEventDetail {\n serviceId: string;\n}\n\nexport interface BookingErrorEventDetail {\n kind: BookingErrorKind;\n}\n","/**\n * The DOM-free logic behind `st-booking`: the typed reading of Suite Core's public bookings API, the\n * client-side checks of the visitor's details, the request calls, and the calendar arithmetic. The server's\n * rules stay authoritative; the checks here only give the visitor an answer before a request is made. Kept\n * apart from `Booking.ts` so every rule and every response case can be unit-tested without a browser.\n */\n\nimport { codePointLength, fillTemplate, parseRetryAfter } from '../contact-form/contact-form-client';\n\nexport { fillTemplate, codePointLength as codePointLengthOf };\n\n/** The fields of the details form, in the order it shows them. Focus moves through them in this order. */\nexport const BOOKING_FIELD_NAMES = ['name', 'email', 'phone', 'notes', 'consent'] as const;\n\nexport type BookingFieldName = (typeof BOOKING_FIELD_NAMES)[number];\n\n/** Length limits, counted in Unicode code points. They match the server's; change both together. */\nexport const BOOKING_LIMITS = { nameMax: 100, emailMax: 254, phoneMax: 30, notesMax: 1000 } as const;\n\n/** How long a request may take before the component reports that it could not reach the API. */\nexport const BOOKING_TIMEOUT_MS = 15_000;\n\n/** The longest window one availability request may cover (the server's limit is 31 days). */\nexport const MAX_AVAILABILITY_MS = 31 * 24 * 3600_000 - 3600_000;\n\n/** How many months ahead the component looks for a first free day before it shows the empty state. */\nexport const MAX_MONTH_LOOKAHEAD = 3;\n\nconst EMAIL_PATTERN = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\nconst PHONE_PATTERN = /^[0-9 +\\-().]+$/;\nconst REFERENCE_MAX_LENGTH = 2048;\n\nexport interface BookingStaff {\n id: string;\n name: string;\n}\n\nexport interface BookingService {\n id: string;\n name: string;\n description: string;\n durationMinutes: number;\n online: boolean;\n staff: BookingStaff[];\n}\n\nexport interface BookingSlot {\n /** RFC 3339 UTC instant. */\n start: string;\n end: string;\n staffIds: string[];\n}\n\nexport interface BookingInfo {\n /** A signed token. It is the only key to the booking: never logged, never put in an event. */\n reference: string;\n serviceId: string;\n serviceName: string;\n start: string;\n end: string;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction str(value: unknown): string {\n return typeof value === 'string' ? value : '';\n}\n\nfunction validInstant(value: unknown): value is string {\n return typeof value === 'string' && !Number.isNaN(Date.parse(value));\n}\n\n/** Keeps the usable services: an object with a non-empty `id` and `name`. */\nexport function parseServices(input: unknown): BookingService[] {\n if (!Array.isArray(input)) return [];\n const services: BookingService[] = [];\n for (const item of input) {\n if (!isPlainObject(item)) continue;\n const id = str(item.id).trim();\n const name = str(item.name).trim();\n if (id === '' || name === '') continue;\n const staff: BookingStaff[] = [];\n if (Array.isArray(item.staff)) {\n for (const member of item.staff) {\n if (isPlainObject(member) && str(member.id).trim() !== '' && str(member.name).trim() !== '') {\n staff.push({ id: str(member.id).trim(), name: str(member.name).trim() });\n }\n }\n }\n const minutes = typeof item.durationMinutes === 'number' && item.durationMinutes > 0 ? Math.round(item.durationMinutes) : 0;\n services.push({ id, name, description: str(item.description).trim(), durationMinutes: minutes, online: item.online === true, staff });\n }\n return services;\n}\n\n/** Keeps the usable slots (valid instants), sorted by start. */\nexport function parseSlots(input: unknown): BookingSlot[] {\n if (!Array.isArray(input)) return [];\n const slots: BookingSlot[] = [];\n for (const item of input) {\n if (!isPlainObject(item) || !validInstant(item.start) || !validInstant(item.end)) continue;\n const staffIds = Array.isArray(item.staffIds) ? item.staffIds.filter((id): id is string => typeof id === 'string') : [];\n slots.push({ start: item.start, end: item.end, staffIds });\n }\n return slots.sort((a, b) => Date.parse(a.start) - Date.parse(b.start));\n}\n\n/** A booking, or `undefined` when the answer is not one. */\nexport function parseBooking(input: unknown): BookingInfo | undefined {\n if (!isPlainObject(input)) return undefined;\n const reference = str(input.reference).trim();\n if (reference === '' || reference.length > REFERENCE_MAX_LENGTH || !validInstant(input.start) || !validInstant(input.end)) return undefined;\n return { reference, serviceId: str(input.serviceId), serviceName: str(input.serviceName), start: input.start, end: input.end };\n}\n\n/* ---------------------------------------------------------------- the visitor's details */\n\nexport interface BookingValues {\n name: string;\n email: string;\n phone: string;\n notes: string;\n consent: boolean;\n /** The honeypot input. Real visitors leave it empty. */\n website?: string;\n}\n\nexport type BookingFieldLabels = Record<'name' | 'email' | 'phone' | 'notes', string>;\n\n/** The client-side messages. `{field}` and `{max}` are filled in. The server's own messages are shown as sent. */\nexport interface BookingErrorMessages {\n required: string;\n tooLong: string;\n invalidEmail: string;\n invalidPhone: string;\n consentRequired: string;\n}\n\nexport const DEFAULT_BOOKING_ERROR_MESSAGES: BookingErrorMessages = {\n required: '{field} is required.',\n tooLong: '{field} must be {max} characters or fewer.',\n invalidEmail: 'Enter a valid email address.',\n invalidPhone: 'Use only digits, spaces and + - ( ) . in the phone number.',\n consentRequired: 'Please accept to continue.'\n};\n\nexport type BookingErrors = Partial<Record<BookingFieldName, string>>;\n\n/** Checks the details the way the server does. Only failing fields appear in the result. */\nexport function validateBooking(values: BookingValues, labels: BookingFieldLabels, messages: BookingErrorMessages): BookingErrors {\n const errors: BookingErrors = {};\n const name = values.name.trim();\n const email = values.email.trim();\n const phone = values.phone.trim();\n const notes = values.notes.trim();\n const required = (field: keyof BookingFieldLabels) => fillTemplate(messages.required, { field: labels[field] });\n const tooLong = (field: keyof BookingFieldLabels, max: number) => fillTemplate(messages.tooLong, { field: labels[field], max });\n\n if (name === '') errors.name = required('name');\n else if (codePointLength(name) > BOOKING_LIMITS.nameMax) errors.name = tooLong('name', BOOKING_LIMITS.nameMax);\n\n if (email === '') errors.email = required('email');\n else if (codePointLength(email) > BOOKING_LIMITS.emailMax) errors.email = tooLong('email', BOOKING_LIMITS.emailMax);\n else if (!EMAIL_PATTERN.test(email)) errors.email = messages.invalidEmail;\n\n if (phone !== '') {\n if (codePointLength(phone) > BOOKING_LIMITS.phoneMax) errors.phone = tooLong('phone', BOOKING_LIMITS.phoneMax);\n else if (!PHONE_PATTERN.test(phone)) errors.phone = messages.invalidPhone;\n }\n\n if (codePointLength(notes) > BOOKING_LIMITS.notesMax) errors.notes = tooLong('notes', BOOKING_LIMITS.notesMax);\n if (!values.consent) errors.consent = messages.consentRequired;\n return errors;\n}\n\n/** The first failing field, in form order. */\nexport function firstInvalidBookingField(errors: BookingErrors): BookingFieldName | undefined {\n return BOOKING_FIELD_NAMES.find(name => errors[name] !== undefined);\n}\n\n/** The request body of a new appointment. Exactly these keys, always (the server rejects unknown ones). */\nexport interface BookingPayload {\n serviceId: string;\n staffId?: string;\n start: string;\n name: string;\n email: string;\n phone: string;\n notes: string;\n consent: true;\n website: string;\n}\n\n/** Builds the body from checked values: trimmed text, `consent` as the literal `true`, the honeypot as typed. */\nexport function buildBookingPayload(values: BookingValues, choice: { serviceId: string; staffId?: string; start: string }): BookingPayload {\n if (!values.consent) throw new Error('A booking needs consent.');\n const payload: BookingPayload = {\n serviceId: choice.serviceId,\n start: choice.start,\n name: values.name.trim(),\n email: values.email.trim(),\n phone: values.phone.trim(),\n notes: values.notes.trim(),\n consent: true,\n website: values.website ?? ''\n };\n if (choice.staffId) payload.staffId = choice.staffId;\n return payload;\n}\n\n/* ---------------------------------------------------------------- the API */\n\n/** What a call came back with, already interpreted. */\nexport type BookingOutcome<T> =\n | { kind: 'ok'; data: T }\n | { kind: 'validation'; errors: Record<string, string> }\n | { kind: 'slot_taken' }\n | { kind: 'too_late' }\n | { kind: 'not_found' }\n | { kind: 'rate_limited'; retryAfterSeconds?: number }\n | { kind: 'unavailable' };\n\nexport type BookingFailureKind = Exclude<BookingOutcome<unknown>['kind'], 'ok'>;\n\nfunction parseJsonObject(text: string): Record<string, unknown> | undefined {\n try {\n const value: unknown = JSON.parse(text);\n return isPlainObject(value) ? value : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Turns a response into an outcome. 429 is read from the status alone. Anything unexpected (a body that is\n * not the documented JSON, an unknown status) is `unavailable`; the response text is never shown.\n */\nexport function interpretBookingResponse<T>(\n status: number,\n retryAfter: string | null,\n bodyText: string,\n readOk: (body: Record<string, unknown>) => T | undefined\n): BookingOutcome<T> {\n if (status === 429) {\n const retryAfterSeconds = parseRetryAfter(retryAfter);\n return retryAfterSeconds === undefined ? { kind: 'rate_limited' } : { kind: 'rate_limited', retryAfterSeconds };\n }\n const body = parseJsonObject(bodyText);\n if (!body) return { kind: 'unavailable' };\n if (status >= 200 && status < 300) {\n if (body.ok !== true) return { kind: 'unavailable' };\n const data = readOk(body);\n return data === undefined ? { kind: 'unavailable' } : { kind: 'ok', data };\n }\n if (status === 400 && body.error === 'validation' && isPlainObject(body.errors)) {\n const errors: Record<string, string> = {};\n for (const [key, message] of Object.entries(body.errors)) {\n if (typeof message === 'string' && message.trim() !== '') errors[key] = message;\n }\n return Object.keys(errors).length > 0 ? { kind: 'validation', errors } : { kind: 'unavailable' };\n }\n if (status === 409 && body.error === 'slot_taken') return { kind: 'slot_taken' };\n if (status === 409 && body.error === 'too_late') return { kind: 'too_late' };\n if (status === 404 && body.error === 'not_found') return { kind: 'not_found' };\n return { kind: 'unavailable' };\n}\n\n/** Only `http:` and `https:` bases are called. An empty or relative value is not callable. */\nexport function isCallableBase(base: string): boolean {\n if (base.trim() === '') return false;\n try {\n const url = new URL(base);\n return url.protocol === 'https:' || url.protocol === 'http:';\n } catch {\n return false;\n }\n}\n\n/** `{base}/public/v1/bookings{path}`, with the base's trailing slashes dropped. */\nexport function bookingUrl(base: string, path: string): string {\n return `${base.trim().replace(/\\/+$/, '')}/public/v1/bookings${path}`;\n}\n\n/** The path of one appointment. The reference is encoded; it is a secret and never appears in a message. */\nexport function appointmentPath(reference: string, suffix = ''): string {\n return `/appointments/${encodeURIComponent(reference)}${suffix}`;\n}\n\nexport type BookingFetch = (input: string, init?: RequestInit) => Promise<Response>;\n\nexport interface BookingCall<T> {\n base: string;\n method: 'GET' | 'POST' | 'DELETE';\n path: string;\n body?: unknown;\n readOk: (body: Record<string, unknown>) => T | undefined;\n signal?: AbortSignal;\n timeoutMs?: number;\n fetchImpl?: BookingFetch;\n}\n\n/**\n * Calls the API with no cookies and no referrer, and interprets the answer. Never throws: a network error,\n * a timeout, an abort or an uncallable base all give `unavailable` (without a request in the last case).\n * Only requests with a body send a `Content-Type`, so GET and DELETE need no CORS preflight for it.\n */\nexport async function callBookings<T>(call: BookingCall<T>): Promise<BookingOutcome<T>> {\n const { base, method, path, body, readOk, signal, timeoutMs = BOOKING_TIMEOUT_MS, fetchImpl = globalThis.fetch } = call;\n if (!isCallableBase(base) || signal?.aborted) return { kind: 'unavailable' };\n const controller = new AbortController();\n const abort = () => controller.abort();\n const timer = setTimeout(abort, timeoutMs);\n signal?.addEventListener('abort', abort, { once: true });\n try {\n const headers: Record<string, string> = { Accept: 'application/json' };\n if (body !== undefined) headers['Content-Type'] = 'application/json';\n const response = await fetchImpl(bookingUrl(base, path), {\n method,\n mode: 'cors',\n credentials: 'omit',\n cache: 'no-store',\n referrerPolicy: 'no-referrer',\n headers,\n body: body === undefined ? undefined : JSON.stringify(body),\n signal: controller.signal\n });\n const text = await response.text();\n return interpretBookingResponse(response.status, response.headers.get('Retry-After'), text, readOk);\n } catch {\n return { kind: 'unavailable' };\n } finally {\n clearTimeout(timer);\n signal?.removeEventListener('abort', abort);\n }\n}\n\n/** Read helpers for `callBookings`. */\nexport const readServices = (body: Record<string, unknown>) => parseServices(body.services);\nexport const readSlots = (body: Record<string, unknown>) => parseSlots(body.slots);\nexport const readBooking = (body: Record<string, unknown>) => parseBooking(body.booking);\nexport const readNothing = () => true as const;\n\n/* ---------------------------------------------------------------- the reference in the page URL */\n\n/** The `ref` of a query string or a hash (`?ref=...`, `#ref=...`, `#/x?ref=...`). `null` when absent or blank. */\nexport function readReferenceParam(search: string, hash: string): string | null {\n const fromQuery = new URLSearchParams(search).get('ref');\n if (fromQuery?.trim()) return fromQuery.trim();\n const fragment = hash.replace(/^#/, '');\n const queryStart = fragment.indexOf('?');\n const params = new URLSearchParams(queryStart >= 0 ? fragment.slice(queryStart + 1) : fragment);\n const fromHash = params.get('ref');\n return fromHash?.trim() ? fromHash.trim() : null;\n}\n\n/**\n * The link that opens a booking: the page's address with the reference in the hash. A hash is not sent to\n * any server and not in a Referer header; any `ref` already in the query or hash is replaced.\n */\nexport function buildManageUrl(pageUrl: string, reference: string): string {\n const url = new URL(pageUrl);\n url.searchParams.delete('ref');\n url.hash = `ref=${encodeURIComponent(reference)}`;\n return url.toString();\n}\n\n/* ---------------------------------------------------------------- calendar arithmetic (visitor's local time) */\n\n/** `YYYY-MM-DD` of a date in the visitor's time zone. */\nexport function dayKey(date: Date): string {\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const day = String(date.getDate()).padStart(2, '0');\n return `${date.getFullYear()}-${month}-${day}`;\n}\n\nexport function parseDayKey(key: string): Date {\n const [year, month, day] = key.split('-').map(Number);\n return new Date(year ?? 1970, (month ?? 1) - 1, day ?? 1);\n}\n\nexport function startOfMonth(date: Date): Date {\n return new Date(date.getFullYear(), date.getMonth(), 1);\n}\n\nexport function addMonths(month: Date, count: number): Date {\n return new Date(month.getFullYear(), month.getMonth() + count, 1);\n}\n\nexport function addDays(date: Date, count: number): Date {\n return new Date(date.getFullYear(), date.getMonth(), date.getDate() + count);\n}\n\n/**\n * The availability window for a month: from now (or the month's first instant, if later) to the month's end,\n * never longer than the server allows.\n */\nexport function monthWindow(month: Date, now: Date): { from: Date; to: Date } {\n const first = startOfMonth(month);\n const from = first.getTime() > now.getTime() ? first : now;\n const end = addMonths(first, 1);\n const to = new Date(Math.min(end.getTime(), from.getTime() + MAX_AVAILABILITY_MS));\n return { from, to };\n}\n\n/** Slots grouped by local day, in time order. */\nexport function groupSlotsByDay(slots: readonly BookingSlot[]): Map<string, BookingSlot[]> {\n const days = new Map<string, BookingSlot[]>();\n for (const slot of slots) {\n const key = dayKey(new Date(slot.start));\n const list = days.get(key);\n if (list) list.push(slot);\n else days.set(key, [slot]);\n }\n return days;\n}\n\n/** The cells of a month: `null` pads before the first and after the last day, so rows have seven cells. */\nexport function monthCells(month: Date, weekStart: 0 | 1): (Date | null)[] {\n const first = startOfMonth(month);\n const lead = (first.getDay() - weekStart + 7) % 7;\n const count = new Date(first.getFullYear(), first.getMonth() + 1, 0).getDate();\n const cells: (Date | null)[] = Array.from({ length: lead }, () => null);\n for (let day = 1; day <= count; day += 1) cells.push(new Date(first.getFullYear(), first.getMonth(), day));\n while (cells.length % 7 !== 0) cells.push(null);\n return cells;\n}\n\n/** The staff id to send: the chosen member, or none (the server picks) for \"any available\". */\nexport function staffIdToSend(chosen: string): string | undefined {\n return chosen === '' ? undefined : chosen;\n}\n","/**\n * Every visible string of `st-booking`, in English. A page replaces the ones it wants through the element's\n * `labels` property (only the keys given are replaced). `{name}` placeholders are filled in by the component.\n * The text the server sends for a field is shown as it is sent; everything else comes from here.\n */\nexport interface BookingLabels {\n /* steps */\n stepService: string;\n stepTime: string;\n stepDetails: string;\n stepDone: string;\n stepsLabel: string;\n /* service */\n serviceHeading: string;\n staffLegend: string;\n anyStaff: string;\n /** `{minutes}` */\n duration: string;\n online: string;\n noServices: string;\n /* date and time */\n timeHeading: string;\n rescheduleHeading: string;\n previousMonth: string;\n nextMonth: string;\n /** `{date}` */\n timesHeading: string;\n /** `{zone}` */\n timeZoneNote: string;\n chooseDay: string;\n /** `{count}` and `{date}` */\n slotsAvailable: string;\n /** `{month}` */\n noSlots: string;\n loading: string;\n back: string;\n continue: string;\n confirmReschedule: string;\n /* details */\n detailsHeading: string;\n nameLabel: string;\n namePlaceholder: string;\n emailLabel: string;\n emailPlaceholder: string;\n phoneLabel: string;\n notesLabel: string;\n notesPlaceholder: string;\n /** `{count}` and `{max}` */\n notesCounter: string;\n consentLabel: string;\n requiredLabel: string;\n requiredNote: string;\n submit: string;\n sending: string;\n /* the booking */\n bookedHeading: string;\n bookingHeading: string;\n bookedNote: string;\n rescheduledNote: string;\n serviceLabel: string;\n whenLabel: string;\n manageLinkLabel: string;\n manageLinkHint: string;\n copyLink: string;\n linkCopied: string;\n reschedule: string;\n cancel: string;\n cancelConfirm: string;\n cancelYes: string;\n cancelNo: string;\n cancelledHeading: string;\n cancelledNote: string;\n bookAnother: string;\n /* problems */\n errorNote: string;\n retry: string;\n slotTakenNote: string;\n tooLateNote: string;\n notFoundNote: string;\n /** `{seconds}` */\n rateLimitedNote: string;\n rateLimitedGenericNote: string;\n validationNote: string;\n}\n\nexport const DEFAULT_BOOKING_LABELS: BookingLabels = {\n stepService: 'Service',\n stepTime: 'Date and time',\n stepDetails: 'Your details',\n stepDone: 'Confirmation',\n stepsLabel: 'Booking steps',\n serviceHeading: 'Choose a service',\n staffLegend: 'Who would you like to see?',\n anyStaff: 'Any available',\n duration: '{minutes} min',\n online: 'Online meeting',\n noServices: 'No services can be booked online right now. Please try again later.',\n timeHeading: 'Pick a date and time',\n rescheduleHeading: 'Pick a new date and time',\n previousMonth: 'Previous month',\n nextMonth: 'Next month',\n timesHeading: 'Times on {date}',\n timeZoneNote: 'Times are shown in your time zone: {zone}.',\n chooseDay: 'Choose a date to see the available times.',\n slotsAvailable: '{count} times available on {date}.',\n noSlots: 'No times are available in {month}.',\n loading: 'Loading…',\n back: 'Back',\n continue: 'Continue',\n confirmReschedule: 'Confirm new time',\n detailsHeading: 'Your details',\n nameLabel: 'Full name',\n namePlaceholder: 'Your name',\n emailLabel: 'Email',\n emailPlaceholder: 'you@example.com',\n phoneLabel: 'Phone (optional)',\n notesLabel: 'Notes (optional)',\n notesPlaceholder: 'Anything we should know beforehand',\n notesCounter: '{count} / {max}',\n consentLabel: 'I agree that these details may be used to arrange and confirm my appointment.',\n requiredLabel: 'required',\n requiredNote: '* Required',\n submit: 'Book appointment',\n sending: 'Booking…',\n bookedHeading: 'Your appointment is booked',\n bookingHeading: 'Your appointment',\n bookedNote: 'Your appointment is booked.',\n rescheduledNote: 'Your appointment has been moved to the new time.',\n serviceLabel: 'Service',\n whenLabel: 'When',\n manageLinkLabel: 'Link to manage this appointment',\n manageLinkHint: 'Keep this link private. Anyone who has it can change or cancel your appointment.',\n copyLink: 'Copy link',\n linkCopied: 'Link copied.',\n reschedule: 'Reschedule',\n cancel: 'Cancel appointment',\n cancelConfirm: 'Cancel this appointment?',\n cancelYes: 'Yes, cancel it',\n cancelNo: 'Keep it',\n cancelledHeading: 'Your appointment is cancelled',\n cancelledNote: 'The appointment has been cancelled.',\n bookAnother: 'Book another appointment',\n errorNote: 'Sorry, the booking service could not be reached. Please try again later.',\n retry: 'Try again',\n slotTakenNote: 'That time has just been taken. Please choose another.',\n tooLateNote: 'This appointment can no longer be changed online. Please contact us.',\n notFoundNote: 'We could not find this appointment. It may have been cancelled, or the link is incomplete.',\n rateLimitedNote: 'Too many requests in a short time. Please wait {seconds} seconds and try again.',\n rateLimitedGenericNote: 'Too many requests in a short time. Please wait a little and try again.',\n validationNote: 'Please check the highlighted fields.'\n};\n"],"mappings":"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AAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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","names":[]}