@realiizlabs/admin 0.1.0 → 0.7.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.
- package/dist/auth/index.cjs +182 -0
- package/dist/auth/index.cjs.map +1 -0
- package/dist/auth/index.d.cts +178 -0
- package/dist/auth/index.d.ts +178 -0
- package/dist/auth/index.js +167 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth-ui/index.cjs +124 -0
- package/dist/auth-ui/index.cjs.map +1 -0
- package/dist/auth-ui/index.d.cts +40 -0
- package/dist/auth-ui/index.d.ts +40 -0
- package/dist/auth-ui/index.js +81 -0
- package/dist/auth-ui/index.js.map +1 -0
- package/dist/chunk-4OCBMOEP.js +42 -0
- package/dist/chunk-4OCBMOEP.js.map +1 -0
- package/dist/chunk-IS52OXZ2.js +252 -0
- package/dist/chunk-IS52OXZ2.js.map +1 -0
- package/dist/forms/index.cjs +256 -0
- package/dist/forms/index.cjs.map +1 -0
- package/dist/forms/index.d.cts +48 -0
- package/dist/forms/index.d.ts +48 -0
- package/dist/forms/index.js +3 -0
- package/dist/forms/index.js.map +1 -0
- package/dist/forms-ui/index.cjs +584 -0
- package/dist/forms-ui/index.cjs.map +1 -0
- package/dist/forms-ui/index.d.cts +33 -0
- package/dist/forms-ui/index.d.ts +33 -0
- package/dist/forms-ui/index.js +336 -0
- package/dist/forms-ui/index.js.map +1 -0
- package/dist/git/index.cjs +283 -0
- package/dist/git/index.cjs.map +1 -0
- package/dist/git/index.d.cts +258 -0
- package/dist/git/index.d.ts +258 -0
- package/dist/git/index.js +269 -0
- package/dist/git/index.js.map +1 -0
- package/dist/index.cjs +9 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +9 -8
- package/dist/index.js.map +1 -1
- package/dist/types-DsSMscTh.d.cts +74 -0
- package/dist/types-DsSMscTh.d.ts +74 -0
- package/package.json +55 -3
package/dist/index.cjs
CHANGED
|
@@ -255,9 +255,9 @@ function BookingWidget({
|
|
|
255
255
|
step === "slot" && service && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: st.section, className: "realiiz-bw__step realiiz-bw__step--slot", children: [
|
|
256
256
|
/* @__PURE__ */ jsxRuntime.jsx("div", { style: st.header, children: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "realiiz-bw__back", onClick: reset, children: "\u2190 Back" }) }),
|
|
257
257
|
retakenNotice && /* @__PURE__ */ jsxRuntime.jsx("p", { style: st.notice, role: "status", children: retakenNotice }),
|
|
258
|
-
slotsLoading && /* @__PURE__ */ jsxRuntime.jsx("p", {
|
|
258
|
+
slotsLoading && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "realiiz-bw__times-empty", children: "Loading available times\u2026" }),
|
|
259
259
|
loadError && /* @__PURE__ */ jsxRuntime.jsx("p", { style: st.error, role: "alert", children: loadError }),
|
|
260
|
-
!slotsLoading && !loadError && slots.length === 0 && /* @__PURE__ */ jsxRuntime.jsxs("p", {
|
|
260
|
+
!slotsLoading && !loadError && slots.length === 0 && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "realiiz-bw__times-empty", children: [
|
|
261
261
|
"No times available in the next ",
|
|
262
262
|
daysAhead,
|
|
263
263
|
" days."
|
|
@@ -592,7 +592,7 @@ var CALENDAR_CSS = `
|
|
|
592
592
|
/* Service picker option: stacked title + supporting description, duration kept at the right. */
|
|
593
593
|
.realiiz-bw__service-main { display: flex; flex-direction: column; min-width: 0; }
|
|
594
594
|
.realiiz-bw__service-name { font-weight: 600; }
|
|
595
|
-
.realiiz-bw__service-duration { flex: none; white-space: nowrap; }
|
|
595
|
+
.realiiz-bw__service-duration { flex: none; white-space: nowrap; font-family: var(--realiiz-bw-label-font, inherit); }
|
|
596
596
|
.realiiz-bw__cal-header { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-bottom: 0.5rem; }
|
|
597
597
|
.realiiz-bw__cal-title { font-weight: 600; }
|
|
598
598
|
.realiiz-bw__cal-nav { display: flex; gap: 0.25rem; }
|
|
@@ -605,7 +605,7 @@ var CALENDAR_CSS = `
|
|
|
605
605
|
.realiiz-bw__cal-nav button:hover:not(:disabled) { background: var(--realiiz-bw-available-hover-bg, #f4f4f5); }
|
|
606
606
|
.realiiz-bw__cal-nav button:disabled { opacity: 0.4; cursor: not-allowed; }
|
|
607
607
|
.realiiz-bw__weekdays, .realiiz-bw__days { display: grid; grid-template-columns: repeat(7, 1fr); gap: 0.25rem; }
|
|
608
|
-
.realiiz-bw__weekday { text-align: center; font-size: 0.7rem; padding: 0.25rem 0; color: var(--realiiz-bw-muted, #71717a); }
|
|
608
|
+
.realiiz-bw__weekday { text-align: center; font-size: 0.7rem; padding: 0.25rem 0; color: var(--realiiz-bw-muted, #71717a); font-family: var(--realiiz-bw-label-font, inherit); }
|
|
609
609
|
.realiiz-bw__day {
|
|
610
610
|
position: relative;
|
|
611
611
|
aspect-ratio: 1 / 1; min-width: 2.25rem; display: flex; align-items: center; justify-content: center;
|
|
@@ -648,7 +648,7 @@ var CALENDAR_CSS = `
|
|
|
648
648
|
}
|
|
649
649
|
.realiiz-bw__day--today.realiiz-bw__day--selected::after { display: none; }
|
|
650
650
|
.realiiz-bw__times-title { margin: 0 0 0.5rem; font-weight: 600; font-size: 0.875rem; }
|
|
651
|
-
.realiiz-bw__times-empty { margin: 0; color: var(--realiiz-bw-muted, #71717a); font-size: 0.875rem; }
|
|
651
|
+
.realiiz-bw__times-empty { margin: 0; color: var(--realiiz-bw-muted, #71717a); font-size: 0.875rem; font-family: var(--realiiz-bw-label-font, inherit); }
|
|
652
652
|
/* Single vertical list: one time slot per row, full width of the times column,
|
|
653
653
|
broken into Morning/Afternoon/Evening sections for scannability. */
|
|
654
654
|
.realiiz-bw__times-list {
|
|
@@ -669,6 +669,7 @@ var CALENDAR_CSS = `
|
|
|
669
669
|
.realiiz-bw__times-group-label {
|
|
670
670
|
margin: 0; font-size: 0.68rem; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase;
|
|
671
671
|
color: var(--realiiz-bw-muted, #71717a);
|
|
672
|
+
font-family: var(--realiiz-bw-label-font, inherit);
|
|
672
673
|
}
|
|
673
674
|
.realiiz-bw__times-group-slots { display: flex; flex-direction: column; gap: 0.4rem; }
|
|
674
675
|
.realiiz-bw__time {
|
|
@@ -704,7 +705,7 @@ var CALENDAR_CSS = `
|
|
|
704
705
|
refined surface + border, tight label hierarchy, comfortable padding, and an
|
|
705
706
|
elegant accent focus ring (replacing the browser default outline). */
|
|
706
707
|
.realiiz-bw__field { display: flex; flex-direction: column; gap: 0.35rem; }
|
|
707
|
-
.realiiz-bw__field-label { font-size: 0.8rem; font-weight: 500; color: var(--realiiz-bw-fg, inherit); }
|
|
708
|
+
.realiiz-bw__field-label { font-size: 0.8rem; font-weight: 500; color: var(--realiiz-bw-fg, inherit); font-family: var(--realiiz-bw-label-font, inherit); }
|
|
708
709
|
/* SMS consent: small, quiet supporting text that doesn't compete with the fields. */
|
|
709
710
|
.realiiz-bw__consent { display: flex; align-items: flex-start; gap: 0.5rem; cursor: pointer; }
|
|
710
711
|
.realiiz-bw__consent-check {
|
|
@@ -732,7 +733,7 @@ var CALENDAR_CSS = `
|
|
|
732
733
|
Service name is the prominent, readable line; the date/time is muted beneath. */
|
|
733
734
|
.realiiz-bw__summary { display: flex; flex-direction: column; gap: 0.1rem; }
|
|
734
735
|
.realiiz-bw__summary-service { font-weight: 600; font-size: 0.95rem; color: var(--realiiz-bw-fg, inherit); }
|
|
735
|
-
.realiiz-bw__summary-when { font-size: 0.8rem; color: var(--realiiz-bw-muted, #71717a); }
|
|
736
|
+
.realiiz-bw__summary-when { font-size: 0.8rem; color: var(--realiiz-bw-muted, #71717a); font-family: var(--realiiz-bw-label-font, inherit); }
|
|
736
737
|
/* Primary action. Styled as a class (like the inputs) so the two share the
|
|
737
738
|
exact same corner radius \u2014 both use --realiiz-bw-radius, so they agree
|
|
738
739
|
instead of one being a rounded rect and the other a pill. */
|
|
@@ -761,7 +762,7 @@ var st = {
|
|
|
761
762
|
boxSizing: "border-box"
|
|
762
763
|
},
|
|
763
764
|
section: { display: "flex", flexDirection: "column", gap: "0.75rem" },
|
|
764
|
-
legend: { fontWeight: 600, padding: 0 },
|
|
765
|
+
legend: { fontWeight: 600, padding: 0, fontFamily: "var(--realiiz-bw-label-font, inherit)" },
|
|
765
766
|
header: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: "0.5rem" },
|
|
766
767
|
list: { display: "flex", flexDirection: "column", gap: "0.5rem" },
|
|
767
768
|
optionButton: {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/slots.ts","../src/components/BookingWidget.tsx"],"names":["dateKey","useMemo","useState","useCallback","jsxs","jsx","Fragment"],"mappings":"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","file":"index.cjs","sourcesContent":["// Pure slot-computation logic — no React, no Supabase. Kept separate so it can\n// be reasoned about and tested in isolation. The widget feeds it the rows it\n// read from the live schema (availability / blocked_dates / get_busy_slots).\n\n/** A recurring weekly availability rule (table: public.availability). */\nexport interface AvailabilityRule {\n /** 0 = Sunday .. 6 = Saturday (matches Postgres EXTRACT(DOW) and JS Date.getDay()). */\n day_of_week: number;\n /** \"HH:MM\" or \"HH:MM:SS\". */\n start_time: string;\n /** \"HH:MM\" or \"HH:MM:SS\". */\n end_time: string;\n is_active?: boolean;\n}\n\n/** A blocked date range (table: public.blocked_dates). Inclusive on both ends. */\nexport interface BlockedDate {\n /** ISO date \"YYYY-MM-DD\". */\n start_date: string;\n /** ISO date \"YYYY-MM-DD\". */\n end_date: string;\n}\n\n/** A taken slot as returned by the get_busy_slots(range_start, range_end) function. */\nexport interface BusySlot {\n /** ISO timestamptz. */\n requested_at: string;\n service_type: string;\n}\n\n/** A candidate slot offered to the user. `available: false` means render it greyed/disabled. */\nexport interface SlotOption {\n start: Date;\n available: boolean;\n}\n\nconst DEFAULT_DURATION_MINUTES = 30;\n\n/**\n * Derive a slot length (minutes) from a service-type label like\n * \"15-min website review\" or \"30 minute strategy session\". Falls back to 30.\n */\nexport function parseDurationMinutes(serviceType: string, fallback = DEFAULT_DURATION_MINUTES): number {\n const match = serviceType.match(/(\\d+)\\s*-?\\s*min/i);\n if (match) {\n const n = Number.parseInt(match[1], 10);\n if (Number.isFinite(n) && n > 0) return n;\n }\n return fallback;\n}\n\nfunction timeToMinutes(time: string): number {\n const [h, m] = time.split(\":\");\n return Number(h) * 60 + Number(m);\n}\n\n/** Local YYYY-MM-DD for a Date (uses the browser's timezone, like the rest of the widget). */\nfunction localDateKey(d: Date): string {\n const y = d.getFullYear();\n const mo = String(d.getMonth() + 1).padStart(2, \"0\");\n const da = String(d.getDate()).padStart(2, \"0\");\n return `${y}-${mo}-${da}`;\n}\n\nfunction isBlocked(dateKey: string, blocked: BlockedDate[]): boolean {\n // ISO date strings compare correctly with lexical >= / <=.\n return blocked.some((b) => dateKey >= b.start_date && dateKey <= b.end_date);\n}\n\n/**\n * Expand recurring availability rules into concrete bookable slots over the next\n * `days`, dropping blocked dates and past times, and marking slots that overlap\n * an existing booking as unavailable (for graying out).\n *\n * Times are computed in the browser's local timezone; `start` Dates carry an\n * absolute instant, so `.toISOString()` sends an unambiguous timestamptz.\n */\nexport function generateSlots(opts: {\n rules: AvailabilityRule[];\n blocked: BlockedDate[];\n busy: BusySlot[];\n durationMinutes: number;\n now: Date;\n days: number;\n}): SlotOption[] {\n const { rules, blocked, busy, durationMinutes, now, days } = opts;\n\n const activeRules = rules.filter((r) => r.is_active !== false);\n\n // Busy intervals as [startMs, endMs); a busy booking's own length comes from\n // its service_type so a 30-min booking correctly blocks two adjacent 15s.\n const busyIntervals = busy.map((b) => {\n const start = new Date(b.requested_at).getTime();\n return [start, start + parseDurationMinutes(b.service_type) * 60_000] as const;\n });\n\n const slots: SlotOption[] = [];\n const base = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n\n for (let offset = 0; offset < days; offset++) {\n const day = new Date(base);\n day.setDate(base.getDate() + offset);\n if (isBlocked(localDateKey(day), blocked)) continue;\n\n const dow = day.getDay();\n for (const rule of activeRules) {\n if (rule.day_of_week !== dow) continue;\n\n const startMin = timeToMinutes(rule.start_time);\n const endMin = timeToMinutes(rule.end_time);\n\n for (let t = startMin; t + durationMinutes <= endMin; t += durationMinutes) {\n const slotStart = new Date(day);\n slotStart.setHours(Math.floor(t / 60), t % 60, 0, 0);\n if (slotStart.getTime() <= now.getTime()) continue; // skip past slots\n\n const s = slotStart.getTime();\n const e = s + durationMinutes * 60_000;\n const taken = busyIntervals.some(([bs, be]) => s < be && bs < e);\n slots.push({ start: slotStart, available: !taken });\n }\n }\n }\n\n slots.sort((a, b) => a.start.getTime() - b.start.getTime());\n return slots;\n}\n","\"use client\";\n\nimport { useCallback, useMemo, useState } from \"react\";\nimport type { ChangeEvent, CSSProperties, ReactNode } from \"react\";\nimport type { SupabaseClient } from \"@supabase/supabase-js\";\n\nimport {\n generateSlots,\n parseDurationMinutes,\n type AvailabilityRule,\n type BlockedDate,\n type BusySlot,\n type SlotOption,\n} from \"../lib/slots\";\n\n/**\n * A service the visitor can book. A bare string derives its length from the\n * label; the object form adds an explicit duration and an optional description\n * shown beneath the service title on the calendar step.\n */\nexport type ServiceType =\n | string\n | { label: string; durationMinutes: number; description?: string };\n\n/** Payload passed to `onBookingComplete` after a successful insert. */\nexport interface CompletedBooking {\n service_type: string;\n requested_at: string;\n name: string;\n email: string;\n phone: string | null;\n sms_consent: boolean;\n}\n\nexport interface BookingWidgetProps {\n /**\n * A configured Supabase client (anon key). The widget never creates its own\n * client or reads env vars — the host owns all configuration.\n */\n supabase: SupabaseClient;\n /** Services to offer, e.g. [\"15-min website review\", \"30-min strategy session\"]. */\n serviceTypes: ServiceType[];\n /** Fired once a booking row has been created. */\n onBookingComplete?: (booking: CompletedBooking) => void;\n /**\n * What to show on the confirmation step. Either static text, or a render\n * function receiving the booking details so the host can format its own\n * wording. The widget hardcodes nothing site-specific about how a booking is\n * confirmed (e.g. it does not promise email). Defaults to a generic message.\n */\n confirmationMessage?: ReactNode | ((booking: CompletedBooking) => ReactNode);\n /** How many days ahead to offer slots. Default 14. */\n daysAhead?: number;\n /** Extra class on the root element, for host-site styling. */\n className?: string;\n}\n\ninterface NormalizedService {\n label: string;\n durationMinutes: number;\n description?: string;\n}\n\nfunction normalizeService(s: ServiceType): NormalizedService {\n return typeof s === \"string\"\n ? { label: s, durationMinutes: parseDurationMinutes(s) }\n : s;\n}\n\nconst EMAIL_RE = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\n/** Format up to 10 digits as a US phone number, progressively: \"(555) 123-4567\". */\nfunction formatPhone(input: string): string {\n const d = input.replace(/\\D/g, \"\").slice(0, 10);\n if (d.length === 0) return \"\";\n if (d.length < 4) return `(${d}`;\n if (d.length < 7) return `(${d.slice(0, 3)}) ${d.slice(3)}`;\n return `(${d.slice(0, 3)}) ${d.slice(3, 6)}-${d.slice(6)}`;\n}\n\ntype Step = \"service\" | \"slot\" | \"details\" | \"done\";\n\nexport function BookingWidget({\n supabase,\n serviceTypes,\n onBookingComplete,\n confirmationMessage,\n daysAhead = 14,\n className,\n}: BookingWidgetProps) {\n const services = useMemo(() => serviceTypes.map(normalizeService), [serviceTypes]);\n\n const [step, setStep] = useState<Step>(\"service\");\n const [service, setService] = useState<NormalizedService | null>(null);\n\n const [slots, setSlots] = useState<SlotOption[]>([]);\n const [slotsLoading, setSlotsLoading] = useState(false);\n const [loadError, setLoadError] = useState<string | null>(null);\n const [retakenNotice, setRetakenNotice] = useState<string | null>(null);\n const [selectedSlot, setSelectedSlot] = useState<Date | null>(null);\n\n const [name, setName] = useState(\"\");\n const [email, setEmail] = useState(\"\");\n const [phone, setPhone] = useState(\"\");\n const [smsConsent, setSmsConsent] = useState(false);\n const [submitting, setSubmitting] = useState(false);\n const [formError, setFormError] = useState<string | null>(null);\n\n const loadSlots = useCallback(\n async (svc: NormalizedService) => {\n setSlotsLoading(true);\n setLoadError(null);\n const now = new Date();\n const rangeEnd = new Date(now.getFullYear(), now.getMonth(), now.getDate() + daysAhead);\n\n try {\n const [availabilityRes, blockedRes, busyRes] = await Promise.all([\n supabase.from(\"availability\").select(\"day_of_week,start_time,end_time,is_active\").eq(\"is_active\", true),\n supabase.from(\"blocked_dates\").select(\"start_date,end_date\"),\n supabase.rpc(\"get_busy_slots\", {\n range_start: now.toISOString(),\n range_end: rangeEnd.toISOString(),\n }),\n ]);\n\n const firstError = availabilityRes.error || blockedRes.error || busyRes.error;\n if (firstError) throw firstError;\n\n const computed = generateSlots({\n rules: (availabilityRes.data ?? []) as AvailabilityRule[],\n blocked: (blockedRes.data ?? []) as BlockedDate[],\n busy: (busyRes.data ?? []) as BusySlot[],\n durationMinutes: svc.durationMinutes,\n now,\n days: daysAhead,\n });\n setSlots(computed);\n } catch {\n setLoadError(\"Couldn't load available times. Please try again.\");\n setSlots([]);\n } finally {\n setSlotsLoading(false);\n }\n },\n [supabase, daysAhead],\n );\n\n const pickService = useCallback(\n (svc: NormalizedService) => {\n setService(svc);\n setSelectedSlot(null);\n setRetakenNotice(null);\n setStep(\"slot\");\n void loadSlots(svc);\n },\n [loadSlots],\n );\n\n const pickSlot = useCallback((slot: Date) => {\n setSelectedSlot(slot);\n setFormError(null);\n setStep(\"details\");\n }, []);\n\n // Phone auto-formatting. We store the formatted display string in state and\n // strip to digits at submit time. To avoid the cursor jumping to the end on\n // reformat, we count the digits before the caret, reformat, then place the\n // caret after that many digits — applied imperatively so it survives even\n // when the formatted value is unchanged (e.g. deleting a separator).\n const handlePhoneChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {\n const el = e.target;\n const raw = el.value;\n const caret = el.selectionStart ?? raw.length;\n const digitsBeforeCaret = raw.slice(0, caret).replace(/\\D/g, \"\").length;\n const formatted = formatPhone(raw);\n\n let pos = formatted.length;\n if (digitsBeforeCaret === 0) {\n pos = 0;\n } else {\n let seen = 0;\n for (let i = 0; i < formatted.length; i++) {\n if (formatted[i] >= \"0\" && formatted[i] <= \"9\") {\n seen++;\n if (seen === digitsBeforeCaret) {\n pos = i + 1;\n break;\n }\n }\n }\n }\n\n el.value = formatted;\n el.setSelectionRange(pos, pos);\n setPhone(formatted);\n }, []);\n\n const submit = useCallback(async () => {\n if (!service || !selectedSlot) return;\n // Clean, digits-only phone (the field displays it formatted). Required.\n const cleanPhone = phone.replace(/\\D/g, \"\");\n if (!name.trim()) return setFormError(\"Please enter your name.\");\n if (!EMAIL_RE.test(email)) return setFormError(\"Please enter a valid email address.\");\n if (cleanPhone.length !== 10) return setFormError(\"Please enter a valid phone number.\");\n\n setSubmitting(true);\n setFormError(null);\n\n // No .select() chained: the anon role can INSERT but not SELECT bookings\n // (RLS), so we must not request the inserted row back.\n const { error } = await supabase.from(\"bookings\").insert({\n service_type: service.label,\n name: name.trim(),\n email: email.trim(),\n phone: cleanPhone,\n requested_at: selectedSlot.toISOString(),\n status: \"pending\",\n sms_consent: smsConsent,\n });\n\n setSubmitting(false);\n\n if (error) {\n // 23505 = unique_violation: a unique index (separate migration) rejected\n // a slot that was taken between load and submit. Recover gracefully.\n if (error.code === \"23505\") {\n setRetakenNotice(\"That slot was just booked — please pick another.\");\n setSelectedSlot(null);\n setStep(\"slot\");\n if (service) void loadSlots(service);\n return;\n }\n setFormError(\"Something went wrong submitting your booking. Please try again.\");\n return;\n }\n\n const completed: CompletedBooking = {\n service_type: service.label,\n requested_at: selectedSlot.toISOString(),\n name: name.trim(),\n email: email.trim(),\n phone: cleanPhone,\n sms_consent: smsConsent,\n };\n setStep(\"done\");\n onBookingComplete?.(completed);\n }, [service, selectedSlot, name, email, phone, smsConsent, supabase, loadSlots, onBookingComplete]);\n\n const reset = useCallback(() => {\n setStep(\"service\");\n setService(null);\n setSlots([]);\n setSelectedSlot(null);\n setName(\"\");\n setEmail(\"\");\n setPhone(\"\");\n setSmsConsent(false);\n setFormError(null);\n setRetakenNotice(null);\n }, []);\n\n return (\n <div\n data-realiiz-booking-widget=\"\"\n className={[\"realiiz-bw\", className].filter(Boolean).join(\" \")}\n style={st.root}\n >\n <style>{CALENDAR_CSS}</style>\n\n {step === \"service\" && (\n <fieldset style={st.section} className=\"realiiz-bw__step realiiz-bw__step--service\">\n <legend style={st.legend}>Choose a service</legend>\n <div style={st.list}>\n {services.map((svc) => (\n <button\n key={svc.label}\n type=\"button\"\n style={st.optionButton}\n className=\"realiiz-bw__service\"\n onClick={() => pickService(svc)}\n >\n <span className=\"realiiz-bw__service-main\">\n <span className=\"realiiz-bw__service-name\">{svc.label}</span>\n {svc.description && (\n <span className=\"realiiz-bw__service-desc\">{svc.description}</span>\n )}\n </span>\n <span style={st.muted} className=\"realiiz-bw__service-duration\">\n {svc.durationMinutes} min\n </span>\n </button>\n ))}\n </div>\n </fieldset>\n )}\n\n {step === \"slot\" && service && (\n <div style={st.section} className=\"realiiz-bw__step realiiz-bw__step--slot\">\n <div style={st.header}>\n <button type=\"button\" className=\"realiiz-bw__back\" onClick={reset}>\n ← Back\n </button>\n </div>\n\n {retakenNotice && <p style={st.notice} role=\"status\">{retakenNotice}</p>}\n {slotsLoading && <p style={st.muted}>Loading available times…</p>}\n {loadError && <p style={st.error} role=\"alert\">{loadError}</p>}\n\n {!slotsLoading && !loadError && slots.length === 0 && (\n <p style={st.muted}>No times available in the next {daysAhead} days.</p>\n )}\n\n {!slotsLoading && !loadError && slots.length > 0 && (\n <CalendarSlotPicker slots={slots} daysAhead={daysAhead} service={service} onPick={pickSlot} />\n )}\n </div>\n )}\n\n {step === \"details\" && service && selectedSlot && (\n <form\n style={st.section}\n className=\"realiiz-bw__step realiiz-bw__step--details\"\n onSubmit={(e) => {\n e.preventDefault();\n void submit();\n }}\n >\n <div style={st.header}>\n <button type=\"button\" className=\"realiiz-bw__back\" onClick={() => setStep(\"slot\")}>\n ← Back\n </button>\n </div>\n\n <div className=\"realiiz-bw__summary\">\n <span className=\"realiiz-bw__summary-service\">{service.label}</span>\n <span className=\"realiiz-bw__summary-when\">{formatSlot(selectedSlot)}</span>\n </div>\n\n <label className=\"realiiz-bw__field\">\n <span className=\"realiiz-bw__field-label\">Name</span>\n <input\n className=\"realiiz-bw__input\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n required\n />\n </label>\n <label className=\"realiiz-bw__field\">\n <span className=\"realiiz-bw__field-label\">Email</span>\n <input\n className=\"realiiz-bw__input\"\n type=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n required\n />\n </label>\n <label className=\"realiiz-bw__field\">\n <span className=\"realiiz-bw__field-label\">Phone</span>\n <input\n className=\"realiiz-bw__input\"\n type=\"tel\"\n inputMode=\"tel\"\n autoComplete=\"tel\"\n placeholder=\"(555) 123-4567\"\n value={phone}\n onChange={handlePhoneChange}\n required\n />\n </label>\n\n <label className=\"realiiz-bw__consent\">\n <input\n type=\"checkbox\"\n className=\"realiiz-bw__consent-check\"\n checked={smsConsent}\n onChange={(e) => setSmsConsent(e.target.checked)}\n />\n <span className=\"realiiz-bw__consent-text\">\n By providing my phone number, I agree to receive appointment-related and occasional\n follow-up text messages from Realiiz. Message frequency varies. Message and data rates\n may apply. Reply STOP to opt out at any time. Consent is not a condition of booking.\n </span>\n </label>\n\n {formError && <p style={st.error} role=\"alert\">{formError}</p>}\n\n <button type=\"submit\" className=\"realiiz-bw__submit\" disabled={submitting}>\n {submitting ? \"Booking…\" : \"Confirm booking\"}\n </button>\n </form>\n )}\n\n {step === \"done\" && service && selectedSlot && (\n <div style={st.section} className=\"realiiz-bw__step realiiz-bw__step--done\">\n <p style={st.doneTitle}>Request received ✓</p>\n <div style={st.muted} className=\"realiiz-bw__confirmation\">\n {resolveConfirmation(confirmationMessage, {\n service_type: service.label,\n requested_at: selectedSlot.toISOString(),\n name: name.trim(),\n email: email.trim(),\n phone: phone.replace(/\\D/g, \"\") || null,\n sms_consent: smsConsent,\n }, selectedSlot)}\n </div>\n <button type=\"button\" style={st.linkButton} className=\"realiiz-bw__again\" onClick={reset}>\n Book another\n </button>\n </div>\n )}\n </div>\n );\n}\n\n// --- Calendar date helpers (local-time, mirroring slots.ts conventions) -----\nfunction dateKey(d: Date): string {\n const y = d.getFullYear();\n const m = String(d.getMonth() + 1).padStart(2, \"0\");\n const da = String(d.getDate()).padStart(2, \"0\");\n return `${y}-${m}-${da}`;\n}\nfunction startOfMonth(d: Date): Date {\n return new Date(d.getFullYear(), d.getMonth(), 1);\n}\nfunction addMonths(d: Date, n: number): Date {\n return new Date(d.getFullYear(), d.getMonth() + n, 1);\n}\nfunction sameMonth(a: Date, b: Date): boolean {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth();\n}\n\n/**\n * Split an already-sorted day's slots into Morning / Afternoon / Evening\n * sections (only non-empty ones), so the time column reads as a scannable\n * structure rather than one long identical list. Boundaries: <12, 12–17, ≥17.\n */\nfunction groupTimesByPartOfDay(slots: SlotOption[]): { key: string; label: string; slots: SlotOption[] }[] {\n const buckets: { key: string; label: string; slots: SlotOption[] }[] = [\n { key: \"morning\", label: \"Morning\", slots: [] },\n { key: \"afternoon\", label: \"Afternoon\", slots: [] },\n { key: \"evening\", label: \"Evening\", slots: [] },\n ];\n for (const slot of slots) {\n const h = slot.start.getHours();\n const idx = h < 12 ? 0 : h < 17 ? 1 : 2;\n buckets[idx].slots.push(slot);\n }\n return buckets.filter((b) => b.slots.length > 0);\n}\n\n/**\n * Month-view calendar slot picker. Consumes the SlotOption[] already computed\n * by generateSlots() — it does NOT re-derive availability. A day is clickable\n * iff it has at least one available slot; every other in-window day (fully\n * booked, blocked, past, or outside the availability rules) renders disabled.\n * Month navigation is clamped to [current month, month of (today + daysAhead)].\n */\nfunction CalendarSlotPicker({\n slots,\n daysAhead,\n service,\n onPick,\n}: {\n slots: SlotOption[];\n daysAhead: number;\n service: NormalizedService;\n onPick: (d: Date) => void;\n}) {\n const now = useMemo(() => new Date(), []);\n const todayKey = dateKey(now);\n\n // Window bounds: generateSlots emits offsets 0..daysAhead-1, so the last\n // bookable day is today + (daysAhead - 1).\n const minMonth = useMemo(() => startOfMonth(now), [now]);\n const maxMonth = useMemo(\n () => startOfMonth(new Date(now.getFullYear(), now.getMonth(), now.getDate() + (daysAhead - 1))),\n [now, daysAhead],\n );\n\n const slotsByDay = useMemo(() => {\n const map = new Map<string, SlotOption[]>();\n for (const slot of slots) {\n const k = dateKey(slot.start);\n const arr = map.get(k);\n if (arr) arr.push(slot);\n else map.set(k, [slot]);\n }\n return map;\n }, [slots]);\n\n const availableDays = useMemo(() => {\n const set = new Set<string>();\n for (const [k, arr] of slotsByDay) {\n if (arr.some((s) => s.available)) set.add(k);\n }\n return set;\n }, [slotsByDay]);\n\n const weekdays = useMemo(() => {\n const base = new Date(2023, 0, 1); // a Sunday\n return Array.from({ length: 7 }, (_, i) => {\n const d = new Date(base);\n d.setDate(base.getDate() + i);\n return d.toLocaleDateString(undefined, { weekday: \"short\" });\n });\n }, []);\n\n const [viewMonth, setViewMonth] = useState<Date>(minMonth);\n const [selectedDay, setSelectedDay] = useState<string | null>(null);\n\n const canPrev = viewMonth.getTime() > minMonth.getTime();\n const canNext = viewMonth.getTime() < maxMonth.getTime();\n\n const cells = useMemo(() => {\n const first = startOfMonth(viewMonth);\n const gridStart = new Date(first);\n gridStart.setDate(first.getDate() - first.getDay()); // back up to Sunday\n return Array.from({ length: 42 }, (_, i) => {\n const d = new Date(gridStart);\n d.setDate(gridStart.getDate() + i);\n return d;\n });\n }, [viewMonth]);\n\n const goMonth = (delta: number) => {\n setSelectedDay(null);\n setViewMonth((m) => addMonths(m, delta));\n };\n\n const daySlots = selectedDay\n ? (slotsByDay.get(selectedDay)?.filter((s) => s.available) ?? [])\n : [];\n\n return (\n <div className=\"realiiz-bw__scheduler\">\n <div className=\"realiiz-bw__scheduler-inner\">\n <div className=\"realiiz-bw__calendar\" role=\"group\" aria-label=\"Choose a date\">\n <div className=\"realiiz-bw__service-header\">\n <h3 className=\"realiiz-bw__service-title\">{service.label}</h3>\n {service.description && (\n <p className=\"realiiz-bw__service-desc\">{service.description}</p>\n )}\n </div>\n\n <div className=\"realiiz-bw__cal-header\">\n <span className=\"realiiz-bw__cal-title\" aria-live=\"polite\">\n {viewMonth.toLocaleDateString(undefined, { month: \"long\", year: \"numeric\" })}\n </span>\n <div className=\"realiiz-bw__cal-nav\">\n <button type=\"button\" aria-label=\"Previous month\" disabled={!canPrev} onClick={() => goMonth(-1)}>\n ‹\n </button>\n <button type=\"button\" aria-label=\"Next month\" disabled={!canNext} onClick={() => goMonth(1)}>\n ›\n </button>\n </div>\n </div>\n\n <div className=\"realiiz-bw__weekdays\" aria-hidden=\"true\">\n {weekdays.map((w) => (\n <span key={w} className=\"realiiz-bw__weekday\">\n {w}\n </span>\n ))}\n </div>\n\n <div className=\"realiiz-bw__days\">\n {cells.map((cell) => {\n const k = dateKey(cell);\n if (!sameMonth(cell, viewMonth)) {\n return <span key={k} className=\"realiiz-bw__day realiiz-bw__day--outside\" aria-hidden=\"true\" />;\n }\n const isAvailable = availableDays.has(k);\n const isToday = k === todayKey;\n const isSelected = k === selectedDay;\n const className = [\n \"realiiz-bw__day\",\n isToday && \"realiiz-bw__day--today\",\n isAvailable ? \"realiiz-bw__day--available\" : \"realiiz-bw__day--disabled\",\n isSelected && \"realiiz-bw__day--selected\",\n ]\n .filter(Boolean)\n .join(\" \");\n const fullDate = cell.toLocaleDateString(undefined, {\n weekday: \"long\",\n month: \"long\",\n day: \"numeric\",\n year: \"numeric\",\n });\n return (\n <button\n key={k}\n type=\"button\"\n className={className}\n disabled={!isAvailable}\n aria-pressed={isSelected}\n aria-current={isToday ? \"date\" : undefined}\n aria-label={isAvailable ? fullDate : `${fullDate}, unavailable`}\n onClick={() => setSelectedDay(k)}\n >\n {cell.getDate()}\n </button>\n );\n })}\n </div>\n </div>\n\n <div className=\"realiiz-bw__times\" role=\"group\" aria-label=\"Choose a time\">\n <div className=\"realiiz-bw__times-inner\">\n {!selectedDay && (\n <p className=\"realiiz-bw__times-empty\">Select a date to see available times.</p>\n )}\n {selectedDay && (\n <>\n <p className=\"realiiz-bw__times-title\">\n {new Date(`${selectedDay}T00:00:00`).toLocaleDateString(undefined, {\n weekday: \"short\",\n month: \"short\",\n day: \"numeric\",\n })}\n </p>\n {daySlots.length === 0 ? (\n <p className=\"realiiz-bw__times-empty\">No times available.</p>\n ) : (\n <div className=\"realiiz-bw__times-list\">\n {groupTimesByPartOfDay(daySlots).map((group) => (\n <div key={group.key} className=\"realiiz-bw__times-group\">\n <p className=\"realiiz-bw__times-group-label\">{group.label}</p>\n <div className=\"realiiz-bw__times-group-slots\">\n {group.slots.map((slot) => (\n <button\n key={slot.start.toISOString()}\n type=\"button\"\n className=\"realiiz-bw__time\"\n aria-label={slot.start.toLocaleString(undefined, {\n weekday: \"long\",\n month: \"long\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\",\n })}\n onClick={() => onPick(slot.start)}\n >\n {slot.start.toLocaleTimeString(undefined, { hour: \"numeric\", minute: \"2-digit\" })}\n </button>\n ))}\n </div>\n </div>\n ))}\n </div>\n )}\n </>\n )}\n </div>\n </div>\n </div>\n </div>\n );\n}\n\n/**\n * Resolve the confirmation content: call the render function if given one, use\n * static content if provided, otherwise fall back to a generic message that\n * makes no promise about *how* the booking is confirmed.\n */\nfunction resolveConfirmation(\n message: BookingWidgetProps[\"confirmationMessage\"],\n booking: CompletedBooking,\n slot: Date,\n): ReactNode {\n if (typeof message === \"function\") return message(booking);\n if (message != null) return message;\n return (\n <>\n Your <strong>{booking.service_type}</strong> is requested for {formatSlot(slot)}.\n </>\n );\n}\n\nfunction formatSlot(d: Date): string {\n return d.toLocaleString(undefined, {\n weekday: \"short\",\n month: \"short\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\",\n });\n}\n\n// Calendar styling lives in real CSS (not inline styles) because it needs\n// container queries (responsive), :hover and :focus-visible states — none of\n// which inline styles can express. Every color/font is a --realiiz-bw-* custom\n// property with a neutral fallback, so a host site themes it by setting those\n// variables on any ancestor. Layout is container-query based, so the calendar\n// adapts to the width it's dropped into, not the viewport.\nconst CALENDAR_CSS = `\n.realiiz-bw__scheduler { container-type: inline-size; }\n.realiiz-bw__scheduler-inner { display: flex; flex-direction: column; gap: 1rem; box-sizing: border-box; }\n.realiiz-bw__scheduler-inner * { box-sizing: border-box; }\n/* DESKTOP ONLY (mobile/stacked layout above is intentionally untouched).\n Lay the two columns side by side. The widget renders \"naked\" — no outer\n card chrome (no background, border, accent edge, radius, or padding) so the\n host can wrap it in whatever container treatment it wants. */\n@container (min-width: 28rem) {\n .realiiz-bw__scheduler-inner {\n flex-direction: row;\n align-items: stretch;\n gap: 1.25rem;\n }\n .realiiz-bw__calendar { flex: 1 1 auto; min-width: 0; }\n /* Slim times column, separated by an internal divider so the columns feel joined.\n Its content is taken out of flow (see __times-inner) so the column never\n inflates the card height — the left column (title + description + calendar)\n drives it. position: relative makes it the containing block for that inner. */\n .realiiz-bw__times {\n flex: 0 0 9rem;\n border-left: 1px solid var(--realiiz-bw-border, #d4d4d8);\n position: relative;\n }\n /* Absolutely fill the (stretched) times column. Because it's out of flow, the\n times side contributes no height of its own, so the card is sized to the\n calendar side — no stranded void under the calendar — while the list below\n flexes to fill this height and scrolls, reaching the bottom in alignment. */\n .realiiz-bw__times-inner {\n position: absolute;\n inset: 0;\n padding-left: 1.25rem;\n display: flex;\n flex-direction: column;\n min-height: 0;\n }\n .realiiz-bw__times-list {\n flex: 1 1 0;\n min-height: 0;\n overflow-y: auto;\n /* Breathing room so the pills don't crowd the (subtle) scrollbar. */\n padding-right: 0.4rem;\n }\n}\n/* Prominent service header at the top of the left column: clear title, with\n the description and duration beneath so users know what they're booking. */\n.realiiz-bw__service-header { margin-bottom: 0.85rem; }\n.realiiz-bw__service-title { margin: 0; font-size: 1.05rem; font-weight: 700; line-height: 1.25; color: var(--realiiz-bw-fg, inherit); }\n.realiiz-bw__service-desc { margin: 0.3rem 0 0; font-size: 0.78rem; line-height: 1.4; color: var(--realiiz-bw-muted, #71717a); }\n/* Service picker option: stacked title + supporting description, duration kept at the right. */\n.realiiz-bw__service-main { display: flex; flex-direction: column; min-width: 0; }\n.realiiz-bw__service-name { font-weight: 600; }\n.realiiz-bw__service-duration { flex: none; white-space: nowrap; }\n.realiiz-bw__cal-header { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-bottom: 0.5rem; }\n.realiiz-bw__cal-title { font-weight: 600; }\n.realiiz-bw__cal-nav { display: flex; gap: 0.25rem; }\n.realiiz-bw__cal-nav button {\n width: 2rem; height: 2rem; line-height: 1; cursor: pointer; font: inherit; color: inherit;\n border: 1px solid var(--realiiz-bw-border, #d4d4d8);\n border-radius: var(--realiiz-bw-radius, 8px);\n background: var(--realiiz-bw-surface, transparent);\n}\n.realiiz-bw__cal-nav button:hover:not(:disabled) { background: var(--realiiz-bw-available-hover-bg, #f4f4f5); }\n.realiiz-bw__cal-nav button:disabled { opacity: 0.4; cursor: not-allowed; }\n.realiiz-bw__weekdays, .realiiz-bw__days { display: grid; grid-template-columns: repeat(7, 1fr); gap: 0.25rem; }\n.realiiz-bw__weekday { text-align: center; font-size: 0.7rem; padding: 0.25rem 0; color: var(--realiiz-bw-muted, #71717a); }\n.realiiz-bw__day {\n position: relative;\n aspect-ratio: 1 / 1; min-width: 2.25rem; display: flex; align-items: center; justify-content: center;\n padding: 0; font: inherit; font-size: 0.9rem; color: inherit;\n border: 1px solid transparent; border-radius: var(--realiiz-bw-radius, 8px); background: transparent;\n}\n.realiiz-bw__day--outside { visibility: hidden; }\n.realiiz-bw__day--disabled { color: var(--realiiz-bw-disabled-fg, #c4c4c8); cursor: not-allowed; }\n/* Available days get a subtle surface fill + bold dark text so they read as\n confident, tappable targets that clearly stand apart from disabled days —\n without competing with the selected (accent fill) state. */\n.realiiz-bw__day--available {\n cursor: pointer; font-weight: 600;\n color: var(--realiiz-bw-available-fg, inherit);\n background: var(--realiiz-bw-available-bg, #fafafb);\n border-color: var(--realiiz-bw-available-border, var(--realiiz-bw-border, #d4d4d8));\n}\n/* Hover only shifts the background; text stays dark. Scoped to :not(--selected)\n so it can never override the selected fill and leave white text on a light bg. */\n.realiiz-bw__day--available:not(.realiiz-bw__day--selected):hover {\n background: var(--realiiz-bw-available-hover-bg, #f4f4f5);\n color: var(--realiiz-bw-available-fg, inherit);\n}\n/* Today: a small dot centered under the day number (no underline bar). */\n.realiiz-bw__day--today::after {\n content: \"\"; position: absolute; left: 50%; bottom: 0.3rem; transform: translateX(-50%);\n width: 0.32rem; height: 0.32rem; border-radius: 50%;\n background: var(--realiiz-bw-today-marker, var(--realiiz-bw-accent, #18181b));\n}\n.realiiz-bw__day--selected {\n border-color: transparent;\n background: var(--realiiz-bw-selected-bg, var(--realiiz-bw-accent, #18181b));\n color: var(--realiiz-bw-selected-fg, var(--realiiz-bw-accent-fg, #ffffff));\n}\n/* Selected always wins: keep the fill on hover, and hide the today dot when a\n day is both today and selected so the two markers never clash. */\n.realiiz-bw__day--selected:hover {\n background: var(--realiiz-bw-selected-bg, var(--realiiz-bw-accent, #18181b));\n color: var(--realiiz-bw-selected-fg, var(--realiiz-bw-accent-fg, #ffffff));\n}\n.realiiz-bw__day--today.realiiz-bw__day--selected::after { display: none; }\n.realiiz-bw__times-title { margin: 0 0 0.5rem; font-weight: 600; font-size: 0.875rem; }\n.realiiz-bw__times-empty { margin: 0; color: var(--realiiz-bw-muted, #71717a); font-size: 0.875rem; }\n/* Single vertical list: one time slot per row, full width of the times column,\n broken into Morning/Afternoon/Evening sections for scannability. */\n.realiiz-bw__times-list {\n display: flex; flex-direction: column; gap: 0.9rem;\n /* Quiet scrollbar (only shows on desktop, where the list is height-capped):\n no track, just a faint slim thumb in a low-contrast neutral. Firefox. */\n scrollbar-width: thin;\n scrollbar-color: var(--realiiz-bw-scrollbar-thumb, color-mix(in srgb, var(--realiiz-bw-muted, #71717a) 18%, transparent)) transparent;\n}\n/* WebKit (Chrome/Safari/Edge): track removed entirely, thumb only. */\n.realiiz-bw__times-list::-webkit-scrollbar { width: 6px; }\n.realiiz-bw__times-list::-webkit-scrollbar-track { background: transparent; }\n.realiiz-bw__times-list::-webkit-scrollbar-thumb {\n background: var(--realiiz-bw-scrollbar-thumb, color-mix(in srgb, var(--realiiz-bw-muted, #71717a) 18%, transparent));\n border-radius: 999px;\n}\n.realiiz-bw__times-group { display: flex; flex-direction: column; gap: 0.4rem; }\n.realiiz-bw__times-group-label {\n margin: 0; font-size: 0.68rem; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase;\n color: var(--realiiz-bw-muted, #71717a);\n}\n.realiiz-bw__times-group-slots { display: flex; flex-direction: column; gap: 0.4rem; }\n.realiiz-bw__time {\n width: 100%; padding: 0.6rem 0.75rem; cursor: pointer; font: inherit; color: inherit;\n white-space: nowrap; text-align: center;\n border: 1px solid var(--realiiz-bw-border, #d4d4d8);\n border-radius: var(--realiiz-bw-radius, 8px);\n background: var(--realiiz-bw-surface, transparent);\n}\n/* Hover shifts background only — text stays readable. */\n.realiiz-bw__time:hover { background: var(--realiiz-bw-available-hover-bg, #f4f4f5); color: inherit; }\n/* Back: a quiet ghost/bordered secondary button (no underline). Deliberately\n muted — it must not compete with the accent-filled primary booking action. */\n.realiiz-bw__back {\n display: inline-flex; align-items: center; gap: 0.25rem;\n padding: 0.3rem 0.6rem; font: inherit; font-size: 0.8rem; line-height: 1;\n cursor: pointer; text-decoration: none;\n color: var(--realiiz-bw-muted, #71717a);\n background: var(--realiiz-bw-surface, transparent);\n border: 1px solid var(--realiiz-bw-border, #d4d4d8);\n border-radius: var(--realiiz-bw-radius, 8px);\n}\n.realiiz-bw__back:hover { background: var(--realiiz-bw-available-hover-bg, #f4f4f5); color: var(--realiiz-bw-fg, inherit); }\n.realiiz-bw__day--available:focus-visible,\n.realiiz-bw__time:focus-visible,\n.realiiz-bw__back:focus-visible,\n.realiiz-bw__consent-check:focus-visible,\n.realiiz-bw__cal-nav button:focus-visible {\n outline: 2px solid var(--realiiz-bw-focus-ring, var(--realiiz-bw-accent, #18181b));\n outline-offset: 2px;\n}\n/* Details form fields — part of the same designed system as the calendar:\n refined surface + border, tight label hierarchy, comfortable padding, and an\n elegant accent focus ring (replacing the browser default outline). */\n.realiiz-bw__field { display: flex; flex-direction: column; gap: 0.35rem; }\n.realiiz-bw__field-label { font-size: 0.8rem; font-weight: 500; color: var(--realiiz-bw-fg, inherit); }\n/* SMS consent: small, quiet supporting text that doesn't compete with the fields. */\n.realiiz-bw__consent { display: flex; align-items: flex-start; gap: 0.5rem; cursor: pointer; }\n.realiiz-bw__consent-check {\n margin: 0.1rem 0 0; flex: none; cursor: pointer;\n accent-color: var(--realiiz-bw-accent, #18181b);\n}\n.realiiz-bw__consent-text { font-size: 0.7rem; line-height: 1.45; color: var(--realiiz-bw-muted, #71717a); }\n.realiiz-bw__input {\n width: 100%; box-sizing: border-box;\n padding: 0.65rem 0.8rem;\n font: inherit; color: inherit;\n background: var(--realiiz-bw-surface, transparent);\n border: 1px solid var(--realiiz-bw-border, #d4d4d8);\n border-radius: var(--realiiz-bw-radius, 8px);\n outline: none;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n}\n.realiiz-bw__input::placeholder { color: var(--realiiz-bw-muted, #71717a); opacity: 0.7; }\n.realiiz-bw__input:hover { border-color: var(--realiiz-bw-muted, #71717a); }\n.realiiz-bw__input:focus {\n border-color: var(--realiiz-bw-focus-ring, var(--realiiz-bw-accent, #18181b));\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--realiiz-bw-focus-ring, var(--realiiz-bw-accent, #18181b)) 22%, transparent);\n}\n/* Selected service + time, so the user sees WHAT they're booking, not just when.\n Service name is the prominent, readable line; the date/time is muted beneath. */\n.realiiz-bw__summary { display: flex; flex-direction: column; gap: 0.1rem; }\n.realiiz-bw__summary-service { font-weight: 600; font-size: 0.95rem; color: var(--realiiz-bw-fg, inherit); }\n.realiiz-bw__summary-when { font-size: 0.8rem; color: var(--realiiz-bw-muted, #71717a); }\n/* Primary action. Styled as a class (like the inputs) so the two share the\n exact same corner radius — both use --realiiz-bw-radius, so they agree\n instead of one being a rounded rect and the other a pill. */\n.realiiz-bw__submit {\n padding: 0.7rem 1rem;\n border: 1px solid transparent;\n border-radius: var(--realiiz-bw-radius, 8px);\n background: var(--realiiz-bw-accent, #18181b);\n color: var(--realiiz-bw-accent-fg, #ffffff);\n font: inherit; font-weight: 600;\n cursor: pointer;\n transition: filter 0.15s ease;\n}\n.realiiz-bw__submit:hover:not(:disabled) { filter: brightness(0.94); }\n.realiiz-bw__submit:disabled { opacity: 0.6; cursor: not-allowed; }\n.realiiz-bw__submit:focus-visible {\n outline: 2px solid var(--realiiz-bw-focus-ring, var(--realiiz-bw-accent, #18181b));\n outline-offset: 2px;\n}\n`;\n\n// Minimal, neutral styling driven by CSS custom properties so a host site can\n// theme it (set --realiiz-bw-* on any ancestor) without fighting hardcoded\n// brand colors. Structural class names (\"realiiz-bw__*\") allow deeper overrides.\nconst st: Record<string, CSSProperties> = {\n root: {\n fontFamily: \"var(--realiiz-bw-font, inherit)\",\n color: \"var(--realiiz-bw-fg, inherit)\",\n maxWidth: \"var(--realiiz-bw-width, 34rem)\",\n boxSizing: \"border-box\",\n },\n section: { display: \"flex\", flexDirection: \"column\", gap: \"0.75rem\" },\n legend: { fontWeight: 600, padding: 0 },\n header: { display: \"flex\", alignItems: \"center\", justifyContent: \"space-between\", gap: \"0.5rem\" },\n list: { display: \"flex\", flexDirection: \"column\", gap: \"0.5rem\" },\n optionButton: {\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"flex-start\",\n gap: \"0.5rem\",\n padding: \"0.75rem 1rem\",\n border: \"1px solid var(--realiiz-bw-border, #d4d4d8)\",\n borderRadius: \"var(--realiiz-bw-radius, 8px)\",\n background: \"var(--realiiz-bw-surface, transparent)\",\n color: \"inherit\",\n font: \"inherit\",\n cursor: \"pointer\",\n textAlign: \"left\",\n },\n linkButton: {\n background: \"none\",\n border: \"none\",\n padding: 0,\n color: \"var(--realiiz-bw-muted, #71717a)\",\n font: \"inherit\",\n cursor: \"pointer\",\n textDecoration: \"underline\",\n },\n muted: { color: \"var(--realiiz-bw-muted, #71717a)\", fontSize: \"0.875rem\" },\n notice: {\n margin: 0,\n padding: \"0.5rem 0.75rem\",\n borderRadius: \"var(--realiiz-bw-radius, 8px)\",\n background: \"var(--realiiz-bw-notice-surface, #fef9c3)\",\n color: \"var(--realiiz-bw-notice-fg, #713f12)\",\n fontSize: \"0.875rem\",\n },\n error: { margin: 0, color: \"var(--realiiz-bw-danger, #b91c1c)\", fontSize: \"0.875rem\" },\n doneTitle: { margin: 0, fontWeight: 600, fontSize: \"1.125rem\" },\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/slots.ts","../src/components/BookingWidget.tsx"],"names":["dateKey","useMemo","useState","useCallback","jsxs","jsx","Fragment"],"mappings":"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","file":"index.cjs","sourcesContent":["// Pure slot-computation logic — no React, no Supabase. Kept separate so it can\n// be reasoned about and tested in isolation. The widget feeds it the rows it\n// read from the live schema (availability / blocked_dates / get_busy_slots).\n\n/** A recurring weekly availability rule (table: public.availability). */\nexport interface AvailabilityRule {\n /** 0 = Sunday .. 6 = Saturday (matches Postgres EXTRACT(DOW) and JS Date.getDay()). */\n day_of_week: number;\n /** \"HH:MM\" or \"HH:MM:SS\". */\n start_time: string;\n /** \"HH:MM\" or \"HH:MM:SS\". */\n end_time: string;\n is_active?: boolean;\n}\n\n/** A blocked date range (table: public.blocked_dates). Inclusive on both ends. */\nexport interface BlockedDate {\n /** ISO date \"YYYY-MM-DD\". */\n start_date: string;\n /** ISO date \"YYYY-MM-DD\". */\n end_date: string;\n}\n\n/** A taken slot as returned by the get_busy_slots(range_start, range_end) function. */\nexport interface BusySlot {\n /** ISO timestamptz. */\n requested_at: string;\n service_type: string;\n}\n\n/** A candidate slot offered to the user. `available: false` means render it greyed/disabled. */\nexport interface SlotOption {\n start: Date;\n available: boolean;\n}\n\nconst DEFAULT_DURATION_MINUTES = 30;\n\n/**\n * Derive a slot length (minutes) from a service-type label like\n * \"15-min website review\" or \"30 minute strategy session\". Falls back to 30.\n */\nexport function parseDurationMinutes(serviceType: string, fallback = DEFAULT_DURATION_MINUTES): number {\n const match = serviceType.match(/(\\d+)\\s*-?\\s*min/i);\n if (match) {\n const n = Number.parseInt(match[1], 10);\n if (Number.isFinite(n) && n > 0) return n;\n }\n return fallback;\n}\n\nfunction timeToMinutes(time: string): number {\n const [h, m] = time.split(\":\");\n return Number(h) * 60 + Number(m);\n}\n\n/** Local YYYY-MM-DD for a Date (uses the browser's timezone, like the rest of the widget). */\nfunction localDateKey(d: Date): string {\n const y = d.getFullYear();\n const mo = String(d.getMonth() + 1).padStart(2, \"0\");\n const da = String(d.getDate()).padStart(2, \"0\");\n return `${y}-${mo}-${da}`;\n}\n\nfunction isBlocked(dateKey: string, blocked: BlockedDate[]): boolean {\n // ISO date strings compare correctly with lexical >= / <=.\n return blocked.some((b) => dateKey >= b.start_date && dateKey <= b.end_date);\n}\n\n/**\n * Expand recurring availability rules into concrete bookable slots over the next\n * `days`, dropping blocked dates and past times, and marking slots that overlap\n * an existing booking as unavailable (for graying out).\n *\n * Times are computed in the browser's local timezone; `start` Dates carry an\n * absolute instant, so `.toISOString()` sends an unambiguous timestamptz.\n */\nexport function generateSlots(opts: {\n rules: AvailabilityRule[];\n blocked: BlockedDate[];\n busy: BusySlot[];\n durationMinutes: number;\n now: Date;\n days: number;\n}): SlotOption[] {\n const { rules, blocked, busy, durationMinutes, now, days } = opts;\n\n const activeRules = rules.filter((r) => r.is_active !== false);\n\n // Busy intervals as [startMs, endMs); a busy booking's own length comes from\n // its service_type so a 30-min booking correctly blocks two adjacent 15s.\n const busyIntervals = busy.map((b) => {\n const start = new Date(b.requested_at).getTime();\n return [start, start + parseDurationMinutes(b.service_type) * 60_000] as const;\n });\n\n const slots: SlotOption[] = [];\n const base = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n\n for (let offset = 0; offset < days; offset++) {\n const day = new Date(base);\n day.setDate(base.getDate() + offset);\n if (isBlocked(localDateKey(day), blocked)) continue;\n\n const dow = day.getDay();\n for (const rule of activeRules) {\n if (rule.day_of_week !== dow) continue;\n\n const startMin = timeToMinutes(rule.start_time);\n const endMin = timeToMinutes(rule.end_time);\n\n for (let t = startMin; t + durationMinutes <= endMin; t += durationMinutes) {\n const slotStart = new Date(day);\n slotStart.setHours(Math.floor(t / 60), t % 60, 0, 0);\n if (slotStart.getTime() <= now.getTime()) continue; // skip past slots\n\n const s = slotStart.getTime();\n const e = s + durationMinutes * 60_000;\n const taken = busyIntervals.some(([bs, be]) => s < be && bs < e);\n slots.push({ start: slotStart, available: !taken });\n }\n }\n }\n\n slots.sort((a, b) => a.start.getTime() - b.start.getTime());\n return slots;\n}\n","\"use client\";\n\nimport { useCallback, useMemo, useState } from \"react\";\nimport type { ChangeEvent, CSSProperties, ReactNode } from \"react\";\nimport type { SupabaseClient } from \"@supabase/supabase-js\";\n\nimport {\n generateSlots,\n parseDurationMinutes,\n type AvailabilityRule,\n type BlockedDate,\n type BusySlot,\n type SlotOption,\n} from \"../lib/slots\";\n\n/**\n * A service the visitor can book. A bare string derives its length from the\n * label; the object form adds an explicit duration and an optional description\n * shown beneath the service title on the calendar step.\n */\nexport type ServiceType =\n | string\n | { label: string; durationMinutes: number; description?: string };\n\n/** Payload passed to `onBookingComplete` after a successful insert. */\nexport interface CompletedBooking {\n service_type: string;\n requested_at: string;\n name: string;\n email: string;\n phone: string | null;\n sms_consent: boolean;\n}\n\nexport interface BookingWidgetProps {\n /**\n * A configured Supabase client (anon key). The widget never creates its own\n * client or reads env vars — the host owns all configuration.\n */\n supabase: SupabaseClient;\n /** Services to offer, e.g. [\"15-min website review\", \"30-min strategy session\"]. */\n serviceTypes: ServiceType[];\n /** Fired once a booking row has been created. */\n onBookingComplete?: (booking: CompletedBooking) => void;\n /**\n * What to show on the confirmation step. Either static text, or a render\n * function receiving the booking details so the host can format its own\n * wording. The widget hardcodes nothing site-specific about how a booking is\n * confirmed (e.g. it does not promise email). Defaults to a generic message.\n */\n confirmationMessage?: ReactNode | ((booking: CompletedBooking) => ReactNode);\n /** How many days ahead to offer slots. Default 14. */\n daysAhead?: number;\n /** Extra class on the root element, for host-site styling. */\n className?: string;\n}\n\ninterface NormalizedService {\n label: string;\n durationMinutes: number;\n description?: string;\n}\n\nfunction normalizeService(s: ServiceType): NormalizedService {\n return typeof s === \"string\"\n ? { label: s, durationMinutes: parseDurationMinutes(s) }\n : s;\n}\n\nconst EMAIL_RE = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\n/** Format up to 10 digits as a US phone number, progressively: \"(555) 123-4567\". */\nfunction formatPhone(input: string): string {\n const d = input.replace(/\\D/g, \"\").slice(0, 10);\n if (d.length === 0) return \"\";\n if (d.length < 4) return `(${d}`;\n if (d.length < 7) return `(${d.slice(0, 3)}) ${d.slice(3)}`;\n return `(${d.slice(0, 3)}) ${d.slice(3, 6)}-${d.slice(6)}`;\n}\n\ntype Step = \"service\" | \"slot\" | \"details\" | \"done\";\n\nexport function BookingWidget({\n supabase,\n serviceTypes,\n onBookingComplete,\n confirmationMessage,\n daysAhead = 14,\n className,\n}: BookingWidgetProps) {\n const services = useMemo(() => serviceTypes.map(normalizeService), [serviceTypes]);\n\n const [step, setStep] = useState<Step>(\"service\");\n const [service, setService] = useState<NormalizedService | null>(null);\n\n const [slots, setSlots] = useState<SlotOption[]>([]);\n const [slotsLoading, setSlotsLoading] = useState(false);\n const [loadError, setLoadError] = useState<string | null>(null);\n const [retakenNotice, setRetakenNotice] = useState<string | null>(null);\n const [selectedSlot, setSelectedSlot] = useState<Date | null>(null);\n\n const [name, setName] = useState(\"\");\n const [email, setEmail] = useState(\"\");\n const [phone, setPhone] = useState(\"\");\n const [smsConsent, setSmsConsent] = useState(false);\n const [submitting, setSubmitting] = useState(false);\n const [formError, setFormError] = useState<string | null>(null);\n\n const loadSlots = useCallback(\n async (svc: NormalizedService) => {\n setSlotsLoading(true);\n setLoadError(null);\n const now = new Date();\n const rangeEnd = new Date(now.getFullYear(), now.getMonth(), now.getDate() + daysAhead);\n\n try {\n const [availabilityRes, blockedRes, busyRes] = await Promise.all([\n supabase.from(\"availability\").select(\"day_of_week,start_time,end_time,is_active\").eq(\"is_active\", true),\n supabase.from(\"blocked_dates\").select(\"start_date,end_date\"),\n supabase.rpc(\"get_busy_slots\", {\n range_start: now.toISOString(),\n range_end: rangeEnd.toISOString(),\n }),\n ]);\n\n const firstError = availabilityRes.error || blockedRes.error || busyRes.error;\n if (firstError) throw firstError;\n\n const computed = generateSlots({\n rules: (availabilityRes.data ?? []) as AvailabilityRule[],\n blocked: (blockedRes.data ?? []) as BlockedDate[],\n busy: (busyRes.data ?? []) as BusySlot[],\n durationMinutes: svc.durationMinutes,\n now,\n days: daysAhead,\n });\n setSlots(computed);\n } catch {\n setLoadError(\"Couldn't load available times. Please try again.\");\n setSlots([]);\n } finally {\n setSlotsLoading(false);\n }\n },\n [supabase, daysAhead],\n );\n\n const pickService = useCallback(\n (svc: NormalizedService) => {\n setService(svc);\n setSelectedSlot(null);\n setRetakenNotice(null);\n setStep(\"slot\");\n void loadSlots(svc);\n },\n [loadSlots],\n );\n\n const pickSlot = useCallback((slot: Date) => {\n setSelectedSlot(slot);\n setFormError(null);\n setStep(\"details\");\n }, []);\n\n // Phone auto-formatting. We store the formatted display string in state and\n // strip to digits at submit time. To avoid the cursor jumping to the end on\n // reformat, we count the digits before the caret, reformat, then place the\n // caret after that many digits — applied imperatively so it survives even\n // when the formatted value is unchanged (e.g. deleting a separator).\n const handlePhoneChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {\n const el = e.target;\n const raw = el.value;\n const caret = el.selectionStart ?? raw.length;\n const digitsBeforeCaret = raw.slice(0, caret).replace(/\\D/g, \"\").length;\n const formatted = formatPhone(raw);\n\n let pos = formatted.length;\n if (digitsBeforeCaret === 0) {\n pos = 0;\n } else {\n let seen = 0;\n for (let i = 0; i < formatted.length; i++) {\n if (formatted[i] >= \"0\" && formatted[i] <= \"9\") {\n seen++;\n if (seen === digitsBeforeCaret) {\n pos = i + 1;\n break;\n }\n }\n }\n }\n\n el.value = formatted;\n el.setSelectionRange(pos, pos);\n setPhone(formatted);\n }, []);\n\n const submit = useCallback(async () => {\n if (!service || !selectedSlot) return;\n // Clean, digits-only phone (the field displays it formatted). Required.\n const cleanPhone = phone.replace(/\\D/g, \"\");\n if (!name.trim()) return setFormError(\"Please enter your name.\");\n if (!EMAIL_RE.test(email)) return setFormError(\"Please enter a valid email address.\");\n if (cleanPhone.length !== 10) return setFormError(\"Please enter a valid phone number.\");\n\n setSubmitting(true);\n setFormError(null);\n\n // No .select() chained: the anon role can INSERT but not SELECT bookings\n // (RLS), so we must not request the inserted row back.\n const { error } = await supabase.from(\"bookings\").insert({\n service_type: service.label,\n name: name.trim(),\n email: email.trim(),\n phone: cleanPhone,\n requested_at: selectedSlot.toISOString(),\n status: \"pending\",\n sms_consent: smsConsent,\n });\n\n setSubmitting(false);\n\n if (error) {\n // 23505 = unique_violation: a unique index (separate migration) rejected\n // a slot that was taken between load and submit. Recover gracefully.\n if (error.code === \"23505\") {\n setRetakenNotice(\"That slot was just booked — please pick another.\");\n setSelectedSlot(null);\n setStep(\"slot\");\n if (service) void loadSlots(service);\n return;\n }\n setFormError(\"Something went wrong submitting your booking. Please try again.\");\n return;\n }\n\n const completed: CompletedBooking = {\n service_type: service.label,\n requested_at: selectedSlot.toISOString(),\n name: name.trim(),\n email: email.trim(),\n phone: cleanPhone,\n sms_consent: smsConsent,\n };\n setStep(\"done\");\n onBookingComplete?.(completed);\n }, [service, selectedSlot, name, email, phone, smsConsent, supabase, loadSlots, onBookingComplete]);\n\n const reset = useCallback(() => {\n setStep(\"service\");\n setService(null);\n setSlots([]);\n setSelectedSlot(null);\n setName(\"\");\n setEmail(\"\");\n setPhone(\"\");\n setSmsConsent(false);\n setFormError(null);\n setRetakenNotice(null);\n }, []);\n\n return (\n <div\n data-realiiz-booking-widget=\"\"\n className={[\"realiiz-bw\", className].filter(Boolean).join(\" \")}\n style={st.root}\n >\n <style>{CALENDAR_CSS}</style>\n\n {step === \"service\" && (\n <fieldset style={st.section} className=\"realiiz-bw__step realiiz-bw__step--service\">\n <legend style={st.legend}>Choose a service</legend>\n <div style={st.list}>\n {services.map((svc) => (\n <button\n key={svc.label}\n type=\"button\"\n style={st.optionButton}\n className=\"realiiz-bw__service\"\n onClick={() => pickService(svc)}\n >\n <span className=\"realiiz-bw__service-main\">\n <span className=\"realiiz-bw__service-name\">{svc.label}</span>\n {svc.description && (\n <span className=\"realiiz-bw__service-desc\">{svc.description}</span>\n )}\n </span>\n <span style={st.muted} className=\"realiiz-bw__service-duration\">\n {svc.durationMinutes} min\n </span>\n </button>\n ))}\n </div>\n </fieldset>\n )}\n\n {step === \"slot\" && service && (\n <div style={st.section} className=\"realiiz-bw__step realiiz-bw__step--slot\">\n <div style={st.header}>\n <button type=\"button\" className=\"realiiz-bw__back\" onClick={reset}>\n ← Back\n </button>\n </div>\n\n {retakenNotice && <p style={st.notice} role=\"status\">{retakenNotice}</p>}\n {slotsLoading && <p className=\"realiiz-bw__times-empty\">Loading available times…</p>}\n {loadError && <p style={st.error} role=\"alert\">{loadError}</p>}\n\n {!slotsLoading && !loadError && slots.length === 0 && (\n <p className=\"realiiz-bw__times-empty\">No times available in the next {daysAhead} days.</p>\n )}\n\n {!slotsLoading && !loadError && slots.length > 0 && (\n <CalendarSlotPicker slots={slots} daysAhead={daysAhead} service={service} onPick={pickSlot} />\n )}\n </div>\n )}\n\n {step === \"details\" && service && selectedSlot && (\n <form\n style={st.section}\n className=\"realiiz-bw__step realiiz-bw__step--details\"\n onSubmit={(e) => {\n e.preventDefault();\n void submit();\n }}\n >\n <div style={st.header}>\n <button type=\"button\" className=\"realiiz-bw__back\" onClick={() => setStep(\"slot\")}>\n ← Back\n </button>\n </div>\n\n <div className=\"realiiz-bw__summary\">\n <span className=\"realiiz-bw__summary-service\">{service.label}</span>\n <span className=\"realiiz-bw__summary-when\">{formatSlot(selectedSlot)}</span>\n </div>\n\n <label className=\"realiiz-bw__field\">\n <span className=\"realiiz-bw__field-label\">Name</span>\n <input\n className=\"realiiz-bw__input\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n required\n />\n </label>\n <label className=\"realiiz-bw__field\">\n <span className=\"realiiz-bw__field-label\">Email</span>\n <input\n className=\"realiiz-bw__input\"\n type=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n required\n />\n </label>\n <label className=\"realiiz-bw__field\">\n <span className=\"realiiz-bw__field-label\">Phone</span>\n <input\n className=\"realiiz-bw__input\"\n type=\"tel\"\n inputMode=\"tel\"\n autoComplete=\"tel\"\n placeholder=\"(555) 123-4567\"\n value={phone}\n onChange={handlePhoneChange}\n required\n />\n </label>\n\n <label className=\"realiiz-bw__consent\">\n <input\n type=\"checkbox\"\n className=\"realiiz-bw__consent-check\"\n checked={smsConsent}\n onChange={(e) => setSmsConsent(e.target.checked)}\n />\n <span className=\"realiiz-bw__consent-text\">\n By providing my phone number, I agree to receive appointment-related and occasional\n follow-up text messages from Realiiz. Message frequency varies. Message and data rates\n may apply. Reply STOP to opt out at any time. Consent is not a condition of booking.\n </span>\n </label>\n\n {formError && <p style={st.error} role=\"alert\">{formError}</p>}\n\n <button type=\"submit\" className=\"realiiz-bw__submit\" disabled={submitting}>\n {submitting ? \"Booking…\" : \"Confirm booking\"}\n </button>\n </form>\n )}\n\n {step === \"done\" && service && selectedSlot && (\n <div style={st.section} className=\"realiiz-bw__step realiiz-bw__step--done\">\n <p style={st.doneTitle}>Request received ✓</p>\n <div style={st.muted} className=\"realiiz-bw__confirmation\">\n {resolveConfirmation(confirmationMessage, {\n service_type: service.label,\n requested_at: selectedSlot.toISOString(),\n name: name.trim(),\n email: email.trim(),\n phone: phone.replace(/\\D/g, \"\") || null,\n sms_consent: smsConsent,\n }, selectedSlot)}\n </div>\n <button type=\"button\" style={st.linkButton} className=\"realiiz-bw__again\" onClick={reset}>\n Book another\n </button>\n </div>\n )}\n </div>\n );\n}\n\n// --- Calendar date helpers (local-time, mirroring slots.ts conventions) -----\nfunction dateKey(d: Date): string {\n const y = d.getFullYear();\n const m = String(d.getMonth() + 1).padStart(2, \"0\");\n const da = String(d.getDate()).padStart(2, \"0\");\n return `${y}-${m}-${da}`;\n}\nfunction startOfMonth(d: Date): Date {\n return new Date(d.getFullYear(), d.getMonth(), 1);\n}\nfunction addMonths(d: Date, n: number): Date {\n return new Date(d.getFullYear(), d.getMonth() + n, 1);\n}\nfunction sameMonth(a: Date, b: Date): boolean {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth();\n}\n\n/**\n * Split an already-sorted day's slots into Morning / Afternoon / Evening\n * sections (only non-empty ones), so the time column reads as a scannable\n * structure rather than one long identical list. Boundaries: <12, 12–17, ≥17.\n */\nfunction groupTimesByPartOfDay(slots: SlotOption[]): { key: string; label: string; slots: SlotOption[] }[] {\n const buckets: { key: string; label: string; slots: SlotOption[] }[] = [\n { key: \"morning\", label: \"Morning\", slots: [] },\n { key: \"afternoon\", label: \"Afternoon\", slots: [] },\n { key: \"evening\", label: \"Evening\", slots: [] },\n ];\n for (const slot of slots) {\n const h = slot.start.getHours();\n const idx = h < 12 ? 0 : h < 17 ? 1 : 2;\n buckets[idx].slots.push(slot);\n }\n return buckets.filter((b) => b.slots.length > 0);\n}\n\n/**\n * Month-view calendar slot picker. Consumes the SlotOption[] already computed\n * by generateSlots() — it does NOT re-derive availability. A day is clickable\n * iff it has at least one available slot; every other in-window day (fully\n * booked, blocked, past, or outside the availability rules) renders disabled.\n * Month navigation is clamped to [current month, month of (today + daysAhead)].\n */\nfunction CalendarSlotPicker({\n slots,\n daysAhead,\n service,\n onPick,\n}: {\n slots: SlotOption[];\n daysAhead: number;\n service: NormalizedService;\n onPick: (d: Date) => void;\n}) {\n const now = useMemo(() => new Date(), []);\n const todayKey = dateKey(now);\n\n // Window bounds: generateSlots emits offsets 0..daysAhead-1, so the last\n // bookable day is today + (daysAhead - 1).\n const minMonth = useMemo(() => startOfMonth(now), [now]);\n const maxMonth = useMemo(\n () => startOfMonth(new Date(now.getFullYear(), now.getMonth(), now.getDate() + (daysAhead - 1))),\n [now, daysAhead],\n );\n\n const slotsByDay = useMemo(() => {\n const map = new Map<string, SlotOption[]>();\n for (const slot of slots) {\n const k = dateKey(slot.start);\n const arr = map.get(k);\n if (arr) arr.push(slot);\n else map.set(k, [slot]);\n }\n return map;\n }, [slots]);\n\n const availableDays = useMemo(() => {\n const set = new Set<string>();\n for (const [k, arr] of slotsByDay) {\n if (arr.some((s) => s.available)) set.add(k);\n }\n return set;\n }, [slotsByDay]);\n\n const weekdays = useMemo(() => {\n const base = new Date(2023, 0, 1); // a Sunday\n return Array.from({ length: 7 }, (_, i) => {\n const d = new Date(base);\n d.setDate(base.getDate() + i);\n return d.toLocaleDateString(undefined, { weekday: \"short\" });\n });\n }, []);\n\n const [viewMonth, setViewMonth] = useState<Date>(minMonth);\n const [selectedDay, setSelectedDay] = useState<string | null>(null);\n\n const canPrev = viewMonth.getTime() > minMonth.getTime();\n const canNext = viewMonth.getTime() < maxMonth.getTime();\n\n const cells = useMemo(() => {\n const first = startOfMonth(viewMonth);\n const gridStart = new Date(first);\n gridStart.setDate(first.getDate() - first.getDay()); // back up to Sunday\n return Array.from({ length: 42 }, (_, i) => {\n const d = new Date(gridStart);\n d.setDate(gridStart.getDate() + i);\n return d;\n });\n }, [viewMonth]);\n\n const goMonth = (delta: number) => {\n setSelectedDay(null);\n setViewMonth((m) => addMonths(m, delta));\n };\n\n const daySlots = selectedDay\n ? (slotsByDay.get(selectedDay)?.filter((s) => s.available) ?? [])\n : [];\n\n return (\n <div className=\"realiiz-bw__scheduler\">\n <div className=\"realiiz-bw__scheduler-inner\">\n <div className=\"realiiz-bw__calendar\" role=\"group\" aria-label=\"Choose a date\">\n <div className=\"realiiz-bw__service-header\">\n <h3 className=\"realiiz-bw__service-title\">{service.label}</h3>\n {service.description && (\n <p className=\"realiiz-bw__service-desc\">{service.description}</p>\n )}\n </div>\n\n <div className=\"realiiz-bw__cal-header\">\n <span className=\"realiiz-bw__cal-title\" aria-live=\"polite\">\n {viewMonth.toLocaleDateString(undefined, { month: \"long\", year: \"numeric\" })}\n </span>\n <div className=\"realiiz-bw__cal-nav\">\n <button type=\"button\" aria-label=\"Previous month\" disabled={!canPrev} onClick={() => goMonth(-1)}>\n ‹\n </button>\n <button type=\"button\" aria-label=\"Next month\" disabled={!canNext} onClick={() => goMonth(1)}>\n ›\n </button>\n </div>\n </div>\n\n <div className=\"realiiz-bw__weekdays\" aria-hidden=\"true\">\n {weekdays.map((w) => (\n <span key={w} className=\"realiiz-bw__weekday\">\n {w}\n </span>\n ))}\n </div>\n\n <div className=\"realiiz-bw__days\">\n {cells.map((cell) => {\n const k = dateKey(cell);\n if (!sameMonth(cell, viewMonth)) {\n return <span key={k} className=\"realiiz-bw__day realiiz-bw__day--outside\" aria-hidden=\"true\" />;\n }\n const isAvailable = availableDays.has(k);\n const isToday = k === todayKey;\n const isSelected = k === selectedDay;\n const className = [\n \"realiiz-bw__day\",\n isToday && \"realiiz-bw__day--today\",\n isAvailable ? \"realiiz-bw__day--available\" : \"realiiz-bw__day--disabled\",\n isSelected && \"realiiz-bw__day--selected\",\n ]\n .filter(Boolean)\n .join(\" \");\n const fullDate = cell.toLocaleDateString(undefined, {\n weekday: \"long\",\n month: \"long\",\n day: \"numeric\",\n year: \"numeric\",\n });\n return (\n <button\n key={k}\n type=\"button\"\n className={className}\n disabled={!isAvailable}\n aria-pressed={isSelected}\n aria-current={isToday ? \"date\" : undefined}\n aria-label={isAvailable ? fullDate : `${fullDate}, unavailable`}\n onClick={() => setSelectedDay(k)}\n >\n {cell.getDate()}\n </button>\n );\n })}\n </div>\n </div>\n\n <div className=\"realiiz-bw__times\" role=\"group\" aria-label=\"Choose a time\">\n <div className=\"realiiz-bw__times-inner\">\n {!selectedDay && (\n <p className=\"realiiz-bw__times-empty\">Select a date to see available times.</p>\n )}\n {selectedDay && (\n <>\n <p className=\"realiiz-bw__times-title\">\n {new Date(`${selectedDay}T00:00:00`).toLocaleDateString(undefined, {\n weekday: \"short\",\n month: \"short\",\n day: \"numeric\",\n })}\n </p>\n {daySlots.length === 0 ? (\n <p className=\"realiiz-bw__times-empty\">No times available.</p>\n ) : (\n <div className=\"realiiz-bw__times-list\">\n {groupTimesByPartOfDay(daySlots).map((group) => (\n <div key={group.key} className=\"realiiz-bw__times-group\">\n <p className=\"realiiz-bw__times-group-label\">{group.label}</p>\n <div className=\"realiiz-bw__times-group-slots\">\n {group.slots.map((slot) => (\n <button\n key={slot.start.toISOString()}\n type=\"button\"\n className=\"realiiz-bw__time\"\n aria-label={slot.start.toLocaleString(undefined, {\n weekday: \"long\",\n month: \"long\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\",\n })}\n onClick={() => onPick(slot.start)}\n >\n {slot.start.toLocaleTimeString(undefined, { hour: \"numeric\", minute: \"2-digit\" })}\n </button>\n ))}\n </div>\n </div>\n ))}\n </div>\n )}\n </>\n )}\n </div>\n </div>\n </div>\n </div>\n );\n}\n\n/**\n * Resolve the confirmation content: call the render function if given one, use\n * static content if provided, otherwise fall back to a generic message that\n * makes no promise about *how* the booking is confirmed.\n */\nfunction resolveConfirmation(\n message: BookingWidgetProps[\"confirmationMessage\"],\n booking: CompletedBooking,\n slot: Date,\n): ReactNode {\n if (typeof message === \"function\") return message(booking);\n if (message != null) return message;\n return (\n <>\n Your <strong>{booking.service_type}</strong> is requested for {formatSlot(slot)}.\n </>\n );\n}\n\nfunction formatSlot(d: Date): string {\n return d.toLocaleString(undefined, {\n weekday: \"short\",\n month: \"short\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\",\n });\n}\n\n// Calendar styling lives in real CSS (not inline styles) because it needs\n// container queries (responsive), :hover and :focus-visible states — none of\n// which inline styles can express. Every color/font is a --realiiz-bw-* custom\n// property with a neutral fallback, so a host site themes it by setting those\n// variables on any ancestor. Layout is container-query based, so the calendar\n// adapts to the width it's dropped into, not the viewport.\nconst CALENDAR_CSS = `\n.realiiz-bw__scheduler { container-type: inline-size; }\n.realiiz-bw__scheduler-inner { display: flex; flex-direction: column; gap: 1rem; box-sizing: border-box; }\n.realiiz-bw__scheduler-inner * { box-sizing: border-box; }\n/* DESKTOP ONLY (mobile/stacked layout above is intentionally untouched).\n Lay the two columns side by side. The widget renders \"naked\" — no outer\n card chrome (no background, border, accent edge, radius, or padding) so the\n host can wrap it in whatever container treatment it wants. */\n@container (min-width: 28rem) {\n .realiiz-bw__scheduler-inner {\n flex-direction: row;\n align-items: stretch;\n gap: 1.25rem;\n }\n .realiiz-bw__calendar { flex: 1 1 auto; min-width: 0; }\n /* Slim times column, separated by an internal divider so the columns feel joined.\n Its content is taken out of flow (see __times-inner) so the column never\n inflates the card height — the left column (title + description + calendar)\n drives it. position: relative makes it the containing block for that inner. */\n .realiiz-bw__times {\n flex: 0 0 9rem;\n border-left: 1px solid var(--realiiz-bw-border, #d4d4d8);\n position: relative;\n }\n /* Absolutely fill the (stretched) times column. Because it's out of flow, the\n times side contributes no height of its own, so the card is sized to the\n calendar side — no stranded void under the calendar — while the list below\n flexes to fill this height and scrolls, reaching the bottom in alignment. */\n .realiiz-bw__times-inner {\n position: absolute;\n inset: 0;\n padding-left: 1.25rem;\n display: flex;\n flex-direction: column;\n min-height: 0;\n }\n .realiiz-bw__times-list {\n flex: 1 1 0;\n min-height: 0;\n overflow-y: auto;\n /* Breathing room so the pills don't crowd the (subtle) scrollbar. */\n padding-right: 0.4rem;\n }\n}\n/* Prominent service header at the top of the left column: clear title, with\n the description and duration beneath so users know what they're booking. */\n.realiiz-bw__service-header { margin-bottom: 0.85rem; }\n.realiiz-bw__service-title { margin: 0; font-size: 1.05rem; font-weight: 700; line-height: 1.25; color: var(--realiiz-bw-fg, inherit); }\n.realiiz-bw__service-desc { margin: 0.3rem 0 0; font-size: 0.78rem; line-height: 1.4; color: var(--realiiz-bw-muted, #71717a); }\n/* Service picker option: stacked title + supporting description, duration kept at the right. */\n.realiiz-bw__service-main { display: flex; flex-direction: column; min-width: 0; }\n.realiiz-bw__service-name { font-weight: 600; }\n.realiiz-bw__service-duration { flex: none; white-space: nowrap; font-family: var(--realiiz-bw-label-font, inherit); }\n.realiiz-bw__cal-header { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-bottom: 0.5rem; }\n.realiiz-bw__cal-title { font-weight: 600; }\n.realiiz-bw__cal-nav { display: flex; gap: 0.25rem; }\n.realiiz-bw__cal-nav button {\n width: 2rem; height: 2rem; line-height: 1; cursor: pointer; font: inherit; color: inherit;\n border: 1px solid var(--realiiz-bw-border, #d4d4d8);\n border-radius: var(--realiiz-bw-radius, 8px);\n background: var(--realiiz-bw-surface, transparent);\n}\n.realiiz-bw__cal-nav button:hover:not(:disabled) { background: var(--realiiz-bw-available-hover-bg, #f4f4f5); }\n.realiiz-bw__cal-nav button:disabled { opacity: 0.4; cursor: not-allowed; }\n.realiiz-bw__weekdays, .realiiz-bw__days { display: grid; grid-template-columns: repeat(7, 1fr); gap: 0.25rem; }\n.realiiz-bw__weekday { text-align: center; font-size: 0.7rem; padding: 0.25rem 0; color: var(--realiiz-bw-muted, #71717a); font-family: var(--realiiz-bw-label-font, inherit); }\n.realiiz-bw__day {\n position: relative;\n aspect-ratio: 1 / 1; min-width: 2.25rem; display: flex; align-items: center; justify-content: center;\n padding: 0; font: inherit; font-size: 0.9rem; color: inherit;\n border: 1px solid transparent; border-radius: var(--realiiz-bw-radius, 8px); background: transparent;\n}\n.realiiz-bw__day--outside { visibility: hidden; }\n.realiiz-bw__day--disabled { color: var(--realiiz-bw-disabled-fg, #c4c4c8); cursor: not-allowed; }\n/* Available days get a subtle surface fill + bold dark text so they read as\n confident, tappable targets that clearly stand apart from disabled days —\n without competing with the selected (accent fill) state. */\n.realiiz-bw__day--available {\n cursor: pointer; font-weight: 600;\n color: var(--realiiz-bw-available-fg, inherit);\n background: var(--realiiz-bw-available-bg, #fafafb);\n border-color: var(--realiiz-bw-available-border, var(--realiiz-bw-border, #d4d4d8));\n}\n/* Hover only shifts the background; text stays dark. Scoped to :not(--selected)\n so it can never override the selected fill and leave white text on a light bg. */\n.realiiz-bw__day--available:not(.realiiz-bw__day--selected):hover {\n background: var(--realiiz-bw-available-hover-bg, #f4f4f5);\n color: var(--realiiz-bw-available-fg, inherit);\n}\n/* Today: a small dot centered under the day number (no underline bar). */\n.realiiz-bw__day--today::after {\n content: \"\"; position: absolute; left: 50%; bottom: 0.3rem; transform: translateX(-50%);\n width: 0.32rem; height: 0.32rem; border-radius: 50%;\n background: var(--realiiz-bw-today-marker, var(--realiiz-bw-accent, #18181b));\n}\n.realiiz-bw__day--selected {\n border-color: transparent;\n background: var(--realiiz-bw-selected-bg, var(--realiiz-bw-accent, #18181b));\n color: var(--realiiz-bw-selected-fg, var(--realiiz-bw-accent-fg, #ffffff));\n}\n/* Selected always wins: keep the fill on hover, and hide the today dot when a\n day is both today and selected so the two markers never clash. */\n.realiiz-bw__day--selected:hover {\n background: var(--realiiz-bw-selected-bg, var(--realiiz-bw-accent, #18181b));\n color: var(--realiiz-bw-selected-fg, var(--realiiz-bw-accent-fg, #ffffff));\n}\n.realiiz-bw__day--today.realiiz-bw__day--selected::after { display: none; }\n.realiiz-bw__times-title { margin: 0 0 0.5rem; font-weight: 600; font-size: 0.875rem; }\n.realiiz-bw__times-empty { margin: 0; color: var(--realiiz-bw-muted, #71717a); font-size: 0.875rem; font-family: var(--realiiz-bw-label-font, inherit); }\n/* Single vertical list: one time slot per row, full width of the times column,\n broken into Morning/Afternoon/Evening sections for scannability. */\n.realiiz-bw__times-list {\n display: flex; flex-direction: column; gap: 0.9rem;\n /* Quiet scrollbar (only shows on desktop, where the list is height-capped):\n no track, just a faint slim thumb in a low-contrast neutral. Firefox. */\n scrollbar-width: thin;\n scrollbar-color: var(--realiiz-bw-scrollbar-thumb, color-mix(in srgb, var(--realiiz-bw-muted, #71717a) 18%, transparent)) transparent;\n}\n/* WebKit (Chrome/Safari/Edge): track removed entirely, thumb only. */\n.realiiz-bw__times-list::-webkit-scrollbar { width: 6px; }\n.realiiz-bw__times-list::-webkit-scrollbar-track { background: transparent; }\n.realiiz-bw__times-list::-webkit-scrollbar-thumb {\n background: var(--realiiz-bw-scrollbar-thumb, color-mix(in srgb, var(--realiiz-bw-muted, #71717a) 18%, transparent));\n border-radius: 999px;\n}\n.realiiz-bw__times-group { display: flex; flex-direction: column; gap: 0.4rem; }\n.realiiz-bw__times-group-label {\n margin: 0; font-size: 0.68rem; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase;\n color: var(--realiiz-bw-muted, #71717a);\n font-family: var(--realiiz-bw-label-font, inherit);\n}\n.realiiz-bw__times-group-slots { display: flex; flex-direction: column; gap: 0.4rem; }\n.realiiz-bw__time {\n width: 100%; padding: 0.6rem 0.75rem; cursor: pointer; font: inherit; color: inherit;\n white-space: nowrap; text-align: center;\n border: 1px solid var(--realiiz-bw-border, #d4d4d8);\n border-radius: var(--realiiz-bw-radius, 8px);\n background: var(--realiiz-bw-surface, transparent);\n}\n/* Hover shifts background only — text stays readable. */\n.realiiz-bw__time:hover { background: var(--realiiz-bw-available-hover-bg, #f4f4f5); color: inherit; }\n/* Back: a quiet ghost/bordered secondary button (no underline). Deliberately\n muted — it must not compete with the accent-filled primary booking action. */\n.realiiz-bw__back {\n display: inline-flex; align-items: center; gap: 0.25rem;\n padding: 0.3rem 0.6rem; font: inherit; font-size: 0.8rem; line-height: 1;\n cursor: pointer; text-decoration: none;\n color: var(--realiiz-bw-muted, #71717a);\n background: var(--realiiz-bw-surface, transparent);\n border: 1px solid var(--realiiz-bw-border, #d4d4d8);\n border-radius: var(--realiiz-bw-radius, 8px);\n}\n.realiiz-bw__back:hover { background: var(--realiiz-bw-available-hover-bg, #f4f4f5); color: var(--realiiz-bw-fg, inherit); }\n.realiiz-bw__day--available:focus-visible,\n.realiiz-bw__time:focus-visible,\n.realiiz-bw__back:focus-visible,\n.realiiz-bw__consent-check:focus-visible,\n.realiiz-bw__cal-nav button:focus-visible {\n outline: 2px solid var(--realiiz-bw-focus-ring, var(--realiiz-bw-accent, #18181b));\n outline-offset: 2px;\n}\n/* Details form fields — part of the same designed system as the calendar:\n refined surface + border, tight label hierarchy, comfortable padding, and an\n elegant accent focus ring (replacing the browser default outline). */\n.realiiz-bw__field { display: flex; flex-direction: column; gap: 0.35rem; }\n.realiiz-bw__field-label { font-size: 0.8rem; font-weight: 500; color: var(--realiiz-bw-fg, inherit); font-family: var(--realiiz-bw-label-font, inherit); }\n/* SMS consent: small, quiet supporting text that doesn't compete with the fields. */\n.realiiz-bw__consent { display: flex; align-items: flex-start; gap: 0.5rem; cursor: pointer; }\n.realiiz-bw__consent-check {\n margin: 0.1rem 0 0; flex: none; cursor: pointer;\n accent-color: var(--realiiz-bw-accent, #18181b);\n}\n.realiiz-bw__consent-text { font-size: 0.7rem; line-height: 1.45; color: var(--realiiz-bw-muted, #71717a); }\n.realiiz-bw__input {\n width: 100%; box-sizing: border-box;\n padding: 0.65rem 0.8rem;\n font: inherit; color: inherit;\n background: var(--realiiz-bw-surface, transparent);\n border: 1px solid var(--realiiz-bw-border, #d4d4d8);\n border-radius: var(--realiiz-bw-radius, 8px);\n outline: none;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n}\n.realiiz-bw__input::placeholder { color: var(--realiiz-bw-muted, #71717a); opacity: 0.7; }\n.realiiz-bw__input:hover { border-color: var(--realiiz-bw-muted, #71717a); }\n.realiiz-bw__input:focus {\n border-color: var(--realiiz-bw-focus-ring, var(--realiiz-bw-accent, #18181b));\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--realiiz-bw-focus-ring, var(--realiiz-bw-accent, #18181b)) 22%, transparent);\n}\n/* Selected service + time, so the user sees WHAT they're booking, not just when.\n Service name is the prominent, readable line; the date/time is muted beneath. */\n.realiiz-bw__summary { display: flex; flex-direction: column; gap: 0.1rem; }\n.realiiz-bw__summary-service { font-weight: 600; font-size: 0.95rem; color: var(--realiiz-bw-fg, inherit); }\n.realiiz-bw__summary-when { font-size: 0.8rem; color: var(--realiiz-bw-muted, #71717a); font-family: var(--realiiz-bw-label-font, inherit); }\n/* Primary action. Styled as a class (like the inputs) so the two share the\n exact same corner radius — both use --realiiz-bw-radius, so they agree\n instead of one being a rounded rect and the other a pill. */\n.realiiz-bw__submit {\n padding: 0.7rem 1rem;\n border: 1px solid transparent;\n border-radius: var(--realiiz-bw-radius, 8px);\n background: var(--realiiz-bw-accent, #18181b);\n color: var(--realiiz-bw-accent-fg, #ffffff);\n font: inherit; font-weight: 600;\n cursor: pointer;\n transition: filter 0.15s ease;\n}\n.realiiz-bw__submit:hover:not(:disabled) { filter: brightness(0.94); }\n.realiiz-bw__submit:disabled { opacity: 0.6; cursor: not-allowed; }\n.realiiz-bw__submit:focus-visible {\n outline: 2px solid var(--realiiz-bw-focus-ring, var(--realiiz-bw-accent, #18181b));\n outline-offset: 2px;\n}\n`;\n\n// Minimal, neutral styling driven by CSS custom properties so a host site can\n// theme it (set --realiiz-bw-* on any ancestor) without fighting hardcoded\n// brand colors. Structural class names (\"realiiz-bw__*\") allow deeper overrides.\nconst st: Record<string, CSSProperties> = {\n root: {\n fontFamily: \"var(--realiiz-bw-font, inherit)\",\n color: \"var(--realiiz-bw-fg, inherit)\",\n maxWidth: \"var(--realiiz-bw-width, 34rem)\",\n boxSizing: \"border-box\",\n },\n section: { display: \"flex\", flexDirection: \"column\", gap: \"0.75rem\" },\n legend: { fontWeight: 600, padding: 0, fontFamily: \"var(--realiiz-bw-label-font, inherit)\" },\n header: { display: \"flex\", alignItems: \"center\", justifyContent: \"space-between\", gap: \"0.5rem\" },\n list: { display: \"flex\", flexDirection: \"column\", gap: \"0.5rem\" },\n optionButton: {\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"flex-start\",\n gap: \"0.5rem\",\n padding: \"0.75rem 1rem\",\n border: \"1px solid var(--realiiz-bw-border, #d4d4d8)\",\n borderRadius: \"var(--realiiz-bw-radius, 8px)\",\n background: \"var(--realiiz-bw-surface, transparent)\",\n color: \"inherit\",\n font: \"inherit\",\n cursor: \"pointer\",\n textAlign: \"left\",\n },\n linkButton: {\n background: \"none\",\n border: \"none\",\n padding: 0,\n color: \"var(--realiiz-bw-muted, #71717a)\",\n font: \"inherit\",\n cursor: \"pointer\",\n textDecoration: \"underline\",\n },\n muted: { color: \"var(--realiiz-bw-muted, #71717a)\", fontSize: \"0.875rem\" },\n notice: {\n margin: 0,\n padding: \"0.5rem 0.75rem\",\n borderRadius: \"var(--realiiz-bw-radius, 8px)\",\n background: \"var(--realiiz-bw-notice-surface, #fef9c3)\",\n color: \"var(--realiiz-bw-notice-fg, #713f12)\",\n fontSize: \"0.875rem\",\n },\n error: { margin: 0, color: \"var(--realiiz-bw-danger, #b91c1c)\", fontSize: \"0.875rem\" },\n doneTitle: { margin: 0, fontWeight: 600, fontSize: \"1.125rem\" },\n};\n"]}
|
package/dist/index.js
CHANGED
|
@@ -253,9 +253,9 @@ function BookingWidget({
|
|
|
253
253
|
step === "slot" && service && /* @__PURE__ */ jsxs("div", { style: st.section, className: "realiiz-bw__step realiiz-bw__step--slot", children: [
|
|
254
254
|
/* @__PURE__ */ jsx("div", { style: st.header, children: /* @__PURE__ */ jsx("button", { type: "button", className: "realiiz-bw__back", onClick: reset, children: "\u2190 Back" }) }),
|
|
255
255
|
retakenNotice && /* @__PURE__ */ jsx("p", { style: st.notice, role: "status", children: retakenNotice }),
|
|
256
|
-
slotsLoading && /* @__PURE__ */ jsx("p", {
|
|
256
|
+
slotsLoading && /* @__PURE__ */ jsx("p", { className: "realiiz-bw__times-empty", children: "Loading available times\u2026" }),
|
|
257
257
|
loadError && /* @__PURE__ */ jsx("p", { style: st.error, role: "alert", children: loadError }),
|
|
258
|
-
!slotsLoading && !loadError && slots.length === 0 && /* @__PURE__ */ jsxs("p", {
|
|
258
|
+
!slotsLoading && !loadError && slots.length === 0 && /* @__PURE__ */ jsxs("p", { className: "realiiz-bw__times-empty", children: [
|
|
259
259
|
"No times available in the next ",
|
|
260
260
|
daysAhead,
|
|
261
261
|
" days."
|
|
@@ -590,7 +590,7 @@ var CALENDAR_CSS = `
|
|
|
590
590
|
/* Service picker option: stacked title + supporting description, duration kept at the right. */
|
|
591
591
|
.realiiz-bw__service-main { display: flex; flex-direction: column; min-width: 0; }
|
|
592
592
|
.realiiz-bw__service-name { font-weight: 600; }
|
|
593
|
-
.realiiz-bw__service-duration { flex: none; white-space: nowrap; }
|
|
593
|
+
.realiiz-bw__service-duration { flex: none; white-space: nowrap; font-family: var(--realiiz-bw-label-font, inherit); }
|
|
594
594
|
.realiiz-bw__cal-header { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-bottom: 0.5rem; }
|
|
595
595
|
.realiiz-bw__cal-title { font-weight: 600; }
|
|
596
596
|
.realiiz-bw__cal-nav { display: flex; gap: 0.25rem; }
|
|
@@ -603,7 +603,7 @@ var CALENDAR_CSS = `
|
|
|
603
603
|
.realiiz-bw__cal-nav button:hover:not(:disabled) { background: var(--realiiz-bw-available-hover-bg, #f4f4f5); }
|
|
604
604
|
.realiiz-bw__cal-nav button:disabled { opacity: 0.4; cursor: not-allowed; }
|
|
605
605
|
.realiiz-bw__weekdays, .realiiz-bw__days { display: grid; grid-template-columns: repeat(7, 1fr); gap: 0.25rem; }
|
|
606
|
-
.realiiz-bw__weekday { text-align: center; font-size: 0.7rem; padding: 0.25rem 0; color: var(--realiiz-bw-muted, #71717a); }
|
|
606
|
+
.realiiz-bw__weekday { text-align: center; font-size: 0.7rem; padding: 0.25rem 0; color: var(--realiiz-bw-muted, #71717a); font-family: var(--realiiz-bw-label-font, inherit); }
|
|
607
607
|
.realiiz-bw__day {
|
|
608
608
|
position: relative;
|
|
609
609
|
aspect-ratio: 1 / 1; min-width: 2.25rem; display: flex; align-items: center; justify-content: center;
|
|
@@ -646,7 +646,7 @@ var CALENDAR_CSS = `
|
|
|
646
646
|
}
|
|
647
647
|
.realiiz-bw__day--today.realiiz-bw__day--selected::after { display: none; }
|
|
648
648
|
.realiiz-bw__times-title { margin: 0 0 0.5rem; font-weight: 600; font-size: 0.875rem; }
|
|
649
|
-
.realiiz-bw__times-empty { margin: 0; color: var(--realiiz-bw-muted, #71717a); font-size: 0.875rem; }
|
|
649
|
+
.realiiz-bw__times-empty { margin: 0; color: var(--realiiz-bw-muted, #71717a); font-size: 0.875rem; font-family: var(--realiiz-bw-label-font, inherit); }
|
|
650
650
|
/* Single vertical list: one time slot per row, full width of the times column,
|
|
651
651
|
broken into Morning/Afternoon/Evening sections for scannability. */
|
|
652
652
|
.realiiz-bw__times-list {
|
|
@@ -667,6 +667,7 @@ var CALENDAR_CSS = `
|
|
|
667
667
|
.realiiz-bw__times-group-label {
|
|
668
668
|
margin: 0; font-size: 0.68rem; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase;
|
|
669
669
|
color: var(--realiiz-bw-muted, #71717a);
|
|
670
|
+
font-family: var(--realiiz-bw-label-font, inherit);
|
|
670
671
|
}
|
|
671
672
|
.realiiz-bw__times-group-slots { display: flex; flex-direction: column; gap: 0.4rem; }
|
|
672
673
|
.realiiz-bw__time {
|
|
@@ -702,7 +703,7 @@ var CALENDAR_CSS = `
|
|
|
702
703
|
refined surface + border, tight label hierarchy, comfortable padding, and an
|
|
703
704
|
elegant accent focus ring (replacing the browser default outline). */
|
|
704
705
|
.realiiz-bw__field { display: flex; flex-direction: column; gap: 0.35rem; }
|
|
705
|
-
.realiiz-bw__field-label { font-size: 0.8rem; font-weight: 500; color: var(--realiiz-bw-fg, inherit); }
|
|
706
|
+
.realiiz-bw__field-label { font-size: 0.8rem; font-weight: 500; color: var(--realiiz-bw-fg, inherit); font-family: var(--realiiz-bw-label-font, inherit); }
|
|
706
707
|
/* SMS consent: small, quiet supporting text that doesn't compete with the fields. */
|
|
707
708
|
.realiiz-bw__consent { display: flex; align-items: flex-start; gap: 0.5rem; cursor: pointer; }
|
|
708
709
|
.realiiz-bw__consent-check {
|
|
@@ -730,7 +731,7 @@ var CALENDAR_CSS = `
|
|
|
730
731
|
Service name is the prominent, readable line; the date/time is muted beneath. */
|
|
731
732
|
.realiiz-bw__summary { display: flex; flex-direction: column; gap: 0.1rem; }
|
|
732
733
|
.realiiz-bw__summary-service { font-weight: 600; font-size: 0.95rem; color: var(--realiiz-bw-fg, inherit); }
|
|
733
|
-
.realiiz-bw__summary-when { font-size: 0.8rem; color: var(--realiiz-bw-muted, #71717a); }
|
|
734
|
+
.realiiz-bw__summary-when { font-size: 0.8rem; color: var(--realiiz-bw-muted, #71717a); font-family: var(--realiiz-bw-label-font, inherit); }
|
|
734
735
|
/* Primary action. Styled as a class (like the inputs) so the two share the
|
|
735
736
|
exact same corner radius \u2014 both use --realiiz-bw-radius, so they agree
|
|
736
737
|
instead of one being a rounded rect and the other a pill. */
|
|
@@ -759,7 +760,7 @@ var st = {
|
|
|
759
760
|
boxSizing: "border-box"
|
|
760
761
|
},
|
|
761
762
|
section: { display: "flex", flexDirection: "column", gap: "0.75rem" },
|
|
762
|
-
legend: { fontWeight: 600, padding: 0 },
|
|
763
|
+
legend: { fontWeight: 600, padding: 0, fontFamily: "var(--realiiz-bw-label-font, inherit)" },
|
|
763
764
|
header: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: "0.5rem" },
|
|
764
765
|
list: { display: "flex", flexDirection: "column", gap: "0.5rem" },
|
|
765
766
|
optionButton: {
|