2026-05-02 08:26:18 +12:00
|
|
|
|
<script lang="ts">
|
2026-05-02 11:24:11 +12:00
|
|
|
|
import { onMount } from 'svelte';
|
2026-05-02 08:26:18 +12:00
|
|
|
|
import Icon from '$lib/components/Icon.svelte';
|
|
|
|
|
|
import { reveal } from '$lib/actions/reveal';
|
|
|
|
|
|
import type { BookingContent } from '$lib/types';
|
2026-05-18 09:43:29 +12:00
|
|
|
|
type SuccessModalComponentType = typeof import('$lib/components/SuccessModal.svelte').default;
|
|
|
|
|
|
type ErrorModalComponentType = typeof import('$lib/components/ErrorModal.svelte').default;
|
2026-05-02 08:26:18 +12:00
|
|
|
|
|
|
|
|
|
|
export let booking: BookingContent;
|
2026-05-04 20:32:24 +12:00
|
|
|
|
export let allowGeneralEnquiry = false;
|
2026-05-18 09:43:29 +12:00
|
|
|
|
export let variant: 'default' | 'minimal-premium' | 'card-stepper' | 'contact-modern' = 'default';
|
2026-05-04 20:32:24 +12:00
|
|
|
|
type EnquiryType = 'booking' | 'general';
|
2026-05-06 15:50:01 +12:00
|
|
|
|
const visitStartedStorageKey = 'goodwalk_visit_started_at';
|
|
|
|
|
|
const journeyStorageKey = 'goodwalk_journey';
|
2026-05-07 21:47:42 +12:00
|
|
|
|
const requestedServiceStorageKey = 'goodwalk_requested_service';
|
2026-05-06 15:50:01 +12:00
|
|
|
|
const maxJourneyEntries = 8;
|
2026-05-07 21:47:42 +12:00
|
|
|
|
const servicePrompts: Record<
|
|
|
|
|
|
string,
|
|
|
|
|
|
{
|
|
|
|
|
|
intro: string;
|
|
|
|
|
|
messageLabel: string;
|
|
|
|
|
|
messagePlaceholder: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
> = {
|
2026-05-15 01:28:10 +12:00
|
|
|
|
'Tiny Gang Pack Walks': {
|
2026-05-07 21:47:42 +12:00
|
|
|
|
intro:
|
2026-05-18 09:43:29 +12:00
|
|
|
|
'Tell us about your dog, your suburb, and how they are around other dogs so we can see whether Tiny Gang Pack Walks are the right fit.',
|
|
|
|
|
|
messageLabel: 'A bit about your dog',
|
2026-05-07 21:47:42 +12:00
|
|
|
|
messagePlaceholder:
|
2026-05-18 09:43:29 +12:00
|
|
|
|
'For example: age, confidence around other dogs, recall, and anything else that would help us place them well.'
|
2026-05-07 21:47:42 +12:00
|
|
|
|
},
|
|
|
|
|
|
'1:1 Walks': {
|
|
|
|
|
|
intro:
|
2026-05-18 09:43:29 +12:00
|
|
|
|
'Tell us about your dog, your suburb, and what you want from one-to-one walks so we can plan the right routine.',
|
|
|
|
|
|
messageLabel: 'What your dog needs',
|
2026-05-07 21:47:42 +12:00
|
|
|
|
messagePlaceholder:
|
2026-05-18 09:43:29 +12:00
|
|
|
|
'For example: size, pace, lead manners, confidence, and anything else that would help us tailor a one-to-one walk.'
|
2026-05-07 21:47:42 +12:00
|
|
|
|
},
|
|
|
|
|
|
'Puppy Visits': {
|
|
|
|
|
|
intro:
|
2026-05-18 09:43:29 +12:00
|
|
|
|
'Tell us about your puppy, your suburb, and the support you need at home so we can plan the right visit.',
|
|
|
|
|
|
messageLabel: 'A bit about your puppy',
|
2026-05-07 21:47:42 +12:00
|
|
|
|
messagePlaceholder:
|
2026-05-18 09:43:29 +12:00
|
|
|
|
'For example: age, routine, toilet needs, feeding schedule, and anything important we should know before visiting.'
|
2026-05-07 21:47:42 +12:00
|
|
|
|
}
|
|
|
|
|
|
};
|
2026-05-15 16:27:39 +12:00
|
|
|
|
const bookingAvatarDogs = [
|
2026-05-18 09:43:29 +12:00
|
|
|
|
{ image: '/images/archie-goodwalk-dog-walking-review-auckland.webp', alt: 'Archie' },
|
|
|
|
|
|
{ image: '/images/monty-goodwalk-dog-walking-review-auckland.webp', alt: 'Monty' },
|
|
|
|
|
|
{ image: '/images/otis-goodwalk-dog-walking-review-auckland.webp', alt: 'Otis' }
|
2026-05-15 16:27:39 +12:00
|
|
|
|
];
|
2026-05-02 08:26:18 +12:00
|
|
|
|
|
|
|
|
|
|
let step = 1;
|
|
|
|
|
|
$: headingParts = splitBookingTitle(booking.title);
|
|
|
|
|
|
|
2026-05-04 20:32:24 +12:00
|
|
|
|
let enquiryType: EnquiryType = 'booking';
|
2026-05-02 08:26:18 +12:00
|
|
|
|
let fullName = '';
|
|
|
|
|
|
let email = '';
|
|
|
|
|
|
let phone = '';
|
|
|
|
|
|
let petName = '';
|
|
|
|
|
|
let location = '';
|
|
|
|
|
|
let message = '';
|
|
|
|
|
|
let selectedServices: string[] = [];
|
2026-05-02 11:24:11 +12:00
|
|
|
|
let website = '';
|
|
|
|
|
|
let formStartedAt = 0;
|
2026-05-06 15:50:01 +12:00
|
|
|
|
let visitStartedAt = 0;
|
|
|
|
|
|
let pageEnteredAt = 0;
|
|
|
|
|
|
let firstInteractionAt = 0;
|
|
|
|
|
|
let sendClickedAt = 0;
|
|
|
|
|
|
let stepChanges = 0;
|
|
|
|
|
|
let journey: string[] = [];
|
2026-05-02 08:26:18 +12:00
|
|
|
|
|
|
|
|
|
|
let fullNameInput: HTMLInputElement;
|
|
|
|
|
|
let emailInput: HTMLInputElement;
|
|
|
|
|
|
let phoneInput: HTMLInputElement;
|
|
|
|
|
|
let petNameInput: HTMLInputElement;
|
|
|
|
|
|
let locationInput: HTMLInputElement;
|
|
|
|
|
|
|
|
|
|
|
|
let errors: Record<string, string> = {};
|
|
|
|
|
|
let submitting = false;
|
|
|
|
|
|
let submitted = false;
|
2026-05-02 09:43:32 +12:00
|
|
|
|
let showErrorModal = false;
|
|
|
|
|
|
let submitErrorDetail = '';
|
2026-05-15 01:28:10 +12:00
|
|
|
|
let showServicePicker = false;
|
2026-05-18 09:43:29 +12:00
|
|
|
|
let SuccessModalComponent: SuccessModalComponentType | null = null;
|
|
|
|
|
|
let ErrorModalComponent: ErrorModalComponentType | null = null;
|
|
|
|
|
|
|
|
|
|
|
|
async function ensureSuccessModal() {
|
|
|
|
|
|
if (SuccessModalComponent) return;
|
|
|
|
|
|
SuccessModalComponent = (await import('$lib/components/SuccessModal.svelte')).default;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function ensureErrorModal() {
|
|
|
|
|
|
if (ErrorModalComponent) return;
|
|
|
|
|
|
ErrorModalComponent = (await import('$lib/components/ErrorModal.svelte')).default;
|
|
|
|
|
|
}
|
2026-05-02 09:43:32 +12:00
|
|
|
|
|
|
|
|
|
|
function validateEmail(raw: string): string {
|
|
|
|
|
|
const value = raw.trim();
|
|
|
|
|
|
if (!value) return 'Please enter your email address';
|
|
|
|
|
|
if (!value.includes('@')) return 'Email is missing the @ sign';
|
|
|
|
|
|
|
|
|
|
|
|
const [local, ...domainParts] = value.split('@');
|
|
|
|
|
|
const domain = domainParts.join('@');
|
|
|
|
|
|
|
|
|
|
|
|
if (domainParts.length > 1) return 'Email can only contain one @ sign';
|
|
|
|
|
|
if (!local) return 'Please add the part before the @';
|
|
|
|
|
|
if (!domain) return 'Please add a domain after the @, like @gmail.com';
|
|
|
|
|
|
if (!domain.includes('.')) return 'Please include a domain ending, like @gmail.com';
|
|
|
|
|
|
|
|
|
|
|
|
const tld = domain.split('.').pop() ?? '';
|
|
|
|
|
|
if (tld.length < 2) return 'That domain ending looks too short';
|
|
|
|
|
|
|
|
|
|
|
|
if (/\s/.test(value)) return 'Email cannot contain spaces';
|
|
|
|
|
|
|
|
|
|
|
|
const re = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,}$/;
|
|
|
|
|
|
if (!re.test(value)) return 'That email doesn’t look quite right';
|
|
|
|
|
|
|
|
|
|
|
|
return '';
|
|
|
|
|
|
}
|
2026-05-02 08:26:18 +12:00
|
|
|
|
|
|
|
|
|
|
const defaultDogIntro =
|
2026-05-18 09:43:29 +12:00
|
|
|
|
'Tell us about your dog and your suburb so we can plan the right Meet & Greet.';
|
2026-05-04 20:32:24 +12:00
|
|
|
|
const defaultGeneralIntro =
|
2026-05-18 09:43:29 +12:00
|
|
|
|
'Need help with something else? Choose general enquiry and tell us what you need.';
|
2026-05-04 20:32:24 +12:00
|
|
|
|
const defaultGeneralSubtitle =
|
2026-05-18 09:43:29 +12:00
|
|
|
|
'Almost there, just your contact details so we can reply properly.';
|
2026-05-02 08:26:18 +12:00
|
|
|
|
|
2026-05-07 21:47:42 +12:00
|
|
|
|
$: primarySelectedService = selectedServices[0] ?? '';
|
|
|
|
|
|
$: activeServicePrompt = servicePrompts[primarySelectedService];
|
|
|
|
|
|
$: dogIntro = activeServicePrompt?.intro || booking.dogIntro?.trim() || defaultDogIntro;
|
2026-05-04 20:32:24 +12:00
|
|
|
|
$: generalIntro = booking.generalIntro?.trim() || defaultGeneralIntro;
|
2026-05-02 08:26:18 +12:00
|
|
|
|
$: hasServices = booking.serviceOptions.length > 0;
|
2026-05-04 20:32:24 +12:00
|
|
|
|
$: if (!allowGeneralEnquiry && enquiryType === 'general') {
|
|
|
|
|
|
enquiryType = 'booking';
|
|
|
|
|
|
}
|
|
|
|
|
|
$: isGeneralEnquiry = allowGeneralEnquiry && enquiryType === 'general';
|
2026-05-06 11:36:19 +12:00
|
|
|
|
$: ownerIntro = isGeneralEnquiry
|
2026-05-04 20:32:24 +12:00
|
|
|
|
? booking.generalSubtitle?.trim() || defaultGeneralSubtitle
|
|
|
|
|
|
: booking.subtitle;
|
2026-05-18 09:43:29 +12:00
|
|
|
|
$: enquiryModeLegend = 'What do you need help with?';
|
2026-05-02 08:26:18 +12:00
|
|
|
|
$: ownerStepLabel = booking.ownerStepLabel?.trim() || 'Owner Details';
|
|
|
|
|
|
$: dogStepLabel = booking.dogStepLabel?.trim() || 'Your dog';
|
2026-05-06 11:36:19 +12:00
|
|
|
|
$: detailsStepLabel = isGeneralEnquiry ? 'Your enquiry' : dogStepLabel;
|
|
|
|
|
|
$: detailsStepIntro = isGeneralEnquiry ? generalIntro : dogIntro;
|
2026-05-07 21:47:42 +12:00
|
|
|
|
$: bookingEyebrow = isGeneralEnquiry ? 'Friendly contact' : primarySelectedService || 'Free Meet & Greet';
|
|
|
|
|
|
$: bookingIntro = isGeneralEnquiry
|
2026-05-18 09:43:29 +12:00
|
|
|
|
? 'Send us the details and we will point you in the right direction.'
|
|
|
|
|
|
: 'Start with a few details about your dog. We will come back within 24 hours with the right next step.';
|
2026-05-07 21:47:42 +12:00
|
|
|
|
$: detailsMessageLabel = isGeneralEnquiry
|
2026-05-18 09:43:29 +12:00
|
|
|
|
? 'How can we help?'
|
|
|
|
|
|
: activeServicePrompt?.messageLabel || 'Anything we should know?';
|
2026-05-07 21:47:42 +12:00
|
|
|
|
$: detailsMessagePlaceholder = isGeneralEnquiry
|
2026-05-18 09:43:29 +12:00
|
|
|
|
? 'Tell us what you need help with and any details that would help us reply properly.'
|
|
|
|
|
|
: activeServicePrompt?.messagePlaceholder || 'Tell us about your dog, any support they need, and anything else that would help us prepare.';
|
|
|
|
|
|
function capitalizeFirst(value: string) {
|
|
|
|
|
|
if (!value) return value;
|
|
|
|
|
|
return value.charAt(0).toLocaleUpperCase() + value.slice(1);
|
|
|
|
|
|
}
|
|
|
|
|
|
$: trimmedPetName = petName.trim();
|
|
|
|
|
|
$: displayPetName = capitalizeFirst(trimmedPetName);
|
|
|
|
|
|
$: successPetName = displayPetName || 'your dog';
|
2026-05-15 01:28:10 +12:00
|
|
|
|
$: serviceChoiceLocked = !isGeneralEnquiry && selectedServices.length === 1 && !showServicePicker;
|
2026-05-15 16:27:39 +12:00
|
|
|
|
$: isCardStepper = variant === 'card-stepper';
|
2026-05-18 09:43:29 +12:00
|
|
|
|
$: isContactModern = variant === 'contact-modern';
|
|
|
|
|
|
$: usesStepperShell = isCardStepper || isContactModern;
|
|
|
|
|
|
$: isSingleStep = usesStepperShell;
|
|
|
|
|
|
$: detailsStepComplete = isGeneralEnquiry
|
|
|
|
|
|
? Boolean(message.trim())
|
|
|
|
|
|
: Boolean(petName.trim() && location.trim() && (!hasServices || selectedServices.length > 0));
|
|
|
|
|
|
$: bookingSocialProofTitle = isGeneralEnquiry
|
|
|
|
|
|
? 'A real reply from a real person.'
|
|
|
|
|
|
: trimmedPetName
|
|
|
|
|
|
? `${displayPetName} could be a great fit for Goodwalk.`
|
|
|
|
|
|
: 'Trusted by Goodwalk dog owners across Auckland.';
|
|
|
|
|
|
$: bookingSocialProofNote = isGeneralEnquiry
|
|
|
|
|
|
? 'Tell us what you need and we will reply with the right next step.'
|
|
|
|
|
|
: primarySelectedService
|
|
|
|
|
|
? `${primarySelectedService}, planned around your dog rather than a generic routine.`
|
|
|
|
|
|
: 'Tell us a little about your dog and we will help you find the right fit.';
|
|
|
|
|
|
$: bookingStepContext = step === 1
|
|
|
|
|
|
? isGeneralEnquiry
|
|
|
|
|
|
? 'Start with the basics and we will send this to the right place.'
|
|
|
|
|
|
: 'Start with your dog, then we will ask where to reply.'
|
|
|
|
|
|
: fullName.trim()
|
|
|
|
|
|
? `Almost there, ${fullName.trim().split(' ')[0]}.`
|
|
|
|
|
|
: 'Almost there, where should we reply?';
|
|
|
|
|
|
$: bookingStepAside = isGeneralEnquiry
|
|
|
|
|
|
? 'A friendly reply, usually within 24 hours.'
|
|
|
|
|
|
: primarySelectedService
|
|
|
|
|
|
? `${primarySelectedService}, with a calm and personal start.`
|
|
|
|
|
|
: '';
|
|
|
|
|
|
$: detailsStepStatus = step === 1 ? 'Current step' : 'Completed';
|
|
|
|
|
|
$: ownerStepStatus = step === 2 ? 'Current step' : detailsStepComplete ? 'Ready next' : 'Complete step 1 first';
|
|
|
|
|
|
$: if (submitted) {
|
|
|
|
|
|
ensureSuccessModal();
|
|
|
|
|
|
}
|
|
|
|
|
|
$: if (showErrorModal) {
|
|
|
|
|
|
ensureErrorModal();
|
|
|
|
|
|
}
|
2026-05-02 08:26:18 +12:00
|
|
|
|
|
2026-05-02 11:24:11 +12:00
|
|
|
|
onMount(() => {
|
2026-05-06 15:50:01 +12:00
|
|
|
|
const now = Date.now();
|
|
|
|
|
|
formStartedAt = now;
|
|
|
|
|
|
pageEnteredAt = now;
|
|
|
|
|
|
visitStartedAt = readOrCreateVisitStartedAt(now);
|
|
|
|
|
|
journey = updateJourneySnapshot(window.location.pathname, window.location.search);
|
2026-05-07 21:47:42 +12:00
|
|
|
|
|
|
|
|
|
|
applyRequestedService();
|
|
|
|
|
|
|
|
|
|
|
|
const handleRequestedService = (event: Event) => {
|
|
|
|
|
|
const customEvent = event as CustomEvent<{ service?: string }>;
|
|
|
|
|
|
applyRequestedService(customEvent.detail?.service?.trim());
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
window.addEventListener('goodwalk:service-selected', handleRequestedService as EventListener);
|
|
|
|
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
|
|
window.removeEventListener('goodwalk:service-selected', handleRequestedService as EventListener);
|
|
|
|
|
|
};
|
2026-05-02 11:24:11 +12:00
|
|
|
|
});
|
|
|
|
|
|
|
2026-05-02 08:26:18 +12:00
|
|
|
|
function splitBookingTitle(title: string) {
|
|
|
|
|
|
const trimmed = title.trim();
|
|
|
|
|
|
const lastSpace = trimmed.lastIndexOf(' ');
|
|
|
|
|
|
|
|
|
|
|
|
if (lastSpace === -1) {
|
|
|
|
|
|
return { plain: trimmed, highlight: '' };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
plain: trimmed.slice(0, lastSpace),
|
|
|
|
|
|
highlight: trimmed.slice(lastSpace + 1)
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function clearError(field: string) {
|
|
|
|
|
|
if (errors[field]) {
|
|
|
|
|
|
errors = { ...errors, [field]: '' };
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-06 15:50:01 +12:00
|
|
|
|
function readOrCreateVisitStartedAt(fallback: number) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const raw = window.sessionStorage.getItem(visitStartedStorageKey);
|
|
|
|
|
|
const parsed = raw ? Number(raw) : NaN;
|
|
|
|
|
|
|
|
|
|
|
|
if (Number.isFinite(parsed) && parsed > 0) {
|
|
|
|
|
|
return parsed;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
window.sessionStorage.setItem(visitStartedStorageKey, String(fallback));
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
return fallback;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return fallback;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function updateJourneySnapshot(pathname: string, search: string) {
|
|
|
|
|
|
const nextEntry = `${pathname}${search}`;
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
const raw = window.sessionStorage.getItem(journeyStorageKey);
|
|
|
|
|
|
const previous = raw ? (JSON.parse(raw) as string[]) : [];
|
|
|
|
|
|
const cleaned = previous.filter((value) => typeof value === 'string' && value.trim());
|
|
|
|
|
|
const deduped = cleaned[cleaned.length - 1] === nextEntry ? cleaned : [...cleaned, nextEntry];
|
|
|
|
|
|
const nextJourney = deduped.slice(-maxJourneyEntries);
|
|
|
|
|
|
|
|
|
|
|
|
window.sessionStorage.setItem(journeyStorageKey, JSON.stringify(nextJourney));
|
|
|
|
|
|
return nextJourney;
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
return [nextEntry];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function noteInteraction() {
|
|
|
|
|
|
if (!firstInteractionAt) {
|
|
|
|
|
|
firstInteractionAt = Date.now();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function setStep(nextStep: number, trackTransition = false) {
|
|
|
|
|
|
if (step !== nextStep && trackTransition) {
|
|
|
|
|
|
stepChanges += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
step = nextStep;
|
|
|
|
|
|
errors = {};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-07 21:47:42 +12:00
|
|
|
|
function applyRequestedService(service?: string) {
|
|
|
|
|
|
const requestedService =
|
|
|
|
|
|
service ||
|
|
|
|
|
|
(() => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
return window.sessionStorage.getItem(requestedServiceStorageKey)?.trim() || '';
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
return '';
|
|
|
|
|
|
}
|
|
|
|
|
|
})();
|
|
|
|
|
|
|
|
|
|
|
|
if (!requestedService || !booking.serviceOptions.includes(requestedService)) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
selectedServices = [requestedService];
|
2026-05-15 01:28:10 +12:00
|
|
|
|
showServicePicker = false;
|
2026-05-07 21:47:42 +12:00
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
window.sessionStorage.removeItem(requestedServiceStorageKey);
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
// Ignore storage cleanup failures.
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-11 21:02:24 +12:00
|
|
|
|
function sortSelectedServices(services: string[]) {
|
|
|
|
|
|
return [...services].sort((a, b) => {
|
|
|
|
|
|
const indexA = booking.serviceOptions.indexOf(a);
|
|
|
|
|
|
const indexB = booking.serviceOptions.indexOf(b);
|
|
|
|
|
|
|
|
|
|
|
|
if (indexA === -1 && indexB === -1) return a.localeCompare(b);
|
|
|
|
|
|
if (indexA === -1) return 1;
|
|
|
|
|
|
if (indexB === -1) return -1;
|
|
|
|
|
|
|
|
|
|
|
|
return indexA - indexB;
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-02 08:26:18 +12:00
|
|
|
|
function toggleService(service: string, checked: boolean) {
|
2026-05-06 15:50:01 +12:00
|
|
|
|
noteInteraction();
|
2026-05-18 09:43:29 +12:00
|
|
|
|
clearError('services');
|
2026-05-06 15:50:01 +12:00
|
|
|
|
|
2026-05-02 08:26:18 +12:00
|
|
|
|
if (checked) {
|
2026-05-18 09:43:29 +12:00
|
|
|
|
selectedServices = [service];
|
|
|
|
|
|
showServicePicker = false;
|
2026-05-02 08:26:18 +12:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
selectedServices = selectedServices.filter((item) => item !== service);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-04 20:32:24 +12:00
|
|
|
|
function setEnquiryType(nextType: EnquiryType) {
|
2026-05-06 15:50:01 +12:00
|
|
|
|
noteInteraction();
|
2026-05-04 20:32:24 +12:00
|
|
|
|
enquiryType = nextType;
|
|
|
|
|
|
if (nextType === 'general') {
|
|
|
|
|
|
petName = '';
|
|
|
|
|
|
location = '';
|
|
|
|
|
|
selectedServices = [];
|
2026-05-15 01:28:10 +12:00
|
|
|
|
showServicePicker = false;
|
2026-05-04 20:32:24 +12:00
|
|
|
|
}
|
|
|
|
|
|
errors = {};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-18 09:43:29 +12:00
|
|
|
|
function serviceInputId(service: string) {
|
|
|
|
|
|
return `booking-service-${service
|
|
|
|
|
|
.toLowerCase()
|
|
|
|
|
|
.replace(/[^a-z0-9]+/g, '-')
|
|
|
|
|
|
.replace(/(^-|-$)/g, '')}`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-06 11:36:19 +12:00
|
|
|
|
function validateOwnerStep(): boolean {
|
|
|
|
|
|
const next: Record<string, string> = {};
|
|
|
|
|
|
|
|
|
|
|
|
if (!fullName.trim()) next.fullName = 'Please enter your full name';
|
|
|
|
|
|
|
|
|
|
|
|
const emailError = validateEmail(email);
|
|
|
|
|
|
if (emailError) next.email = emailError;
|
|
|
|
|
|
|
|
|
|
|
|
if (!phone.trim()) next.phone = 'Please enter your contact number';
|
|
|
|
|
|
|
|
|
|
|
|
errors = next;
|
|
|
|
|
|
|
|
|
|
|
|
if (next.fullName) {
|
|
|
|
|
|
fullNameInput?.focus();
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (next.email) {
|
|
|
|
|
|
emailInput?.focus();
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (next.phone) {
|
|
|
|
|
|
phoneInput?.focus();
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function validateDetailsStep(): boolean {
|
2026-05-02 08:26:18 +12:00
|
|
|
|
const next: Record<string, string> = {};
|
|
|
|
|
|
|
2026-05-04 20:32:24 +12:00
|
|
|
|
if (isGeneralEnquiry) {
|
|
|
|
|
|
if (!message.trim()) next.message = 'Please tell us how we can help';
|
|
|
|
|
|
} else {
|
|
|
|
|
|
if (!petName.trim()) next.petName = "Please enter your dog's name";
|
|
|
|
|
|
if (!location.trim()) next.location = 'Please enter your location';
|
2026-05-18 09:43:29 +12:00
|
|
|
|
if (hasServices && selectedServices.length === 0) {
|
|
|
|
|
|
next.services = 'Please choose a service so we can guide you properly';
|
|
|
|
|
|
}
|
2026-05-04 20:32:24 +12:00
|
|
|
|
}
|
2026-05-02 08:26:18 +12:00
|
|
|
|
|
|
|
|
|
|
errors = next;
|
|
|
|
|
|
|
2026-05-04 20:32:24 +12:00
|
|
|
|
if (next.petName) {
|
|
|
|
|
|
petNameInput?.focus();
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (next.location) {
|
|
|
|
|
|
locationInput?.focus();
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (next.message) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2026-05-02 08:26:18 +12:00
|
|
|
|
|
2026-05-18 09:43:29 +12:00
|
|
|
|
if (next.services) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-02 08:26:18 +12:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-03 11:49:59 +12:00
|
|
|
|
function goToOwnerStep() {
|
2026-05-06 15:50:01 +12:00
|
|
|
|
noteInteraction();
|
2026-05-06 11:36:19 +12:00
|
|
|
|
if (!validateDetailsStep()) return;
|
2026-05-06 15:50:01 +12:00
|
|
|
|
setStep(2, true);
|
2026-05-02 08:26:18 +12:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function handleSubmit(event: SubmitEvent) {
|
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
|
2026-05-18 09:43:29 +12:00
|
|
|
|
if (isSingleStep) {
|
|
|
|
|
|
if (!validateDetailsStep()) return;
|
|
|
|
|
|
if (!validateOwnerStep()) return;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
if (step === 1) {
|
|
|
|
|
|
goToOwnerStep();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2026-05-02 08:26:18 +12:00
|
|
|
|
|
2026-05-18 09:43:29 +12:00
|
|
|
|
if (!validateOwnerStep()) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2026-05-02 08:26:18 +12:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-06 11:36:19 +12:00
|
|
|
|
errors = {};
|
2026-05-06 15:50:01 +12:00
|
|
|
|
noteInteraction();
|
|
|
|
|
|
sendClickedAt = Date.now();
|
2026-05-02 08:26:18 +12:00
|
|
|
|
submitting = true;
|
2026-05-02 09:43:32 +12:00
|
|
|
|
submitErrorDetail = '';
|
|
|
|
|
|
showErrorModal = false;
|
2026-05-02 08:26:18 +12:00
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
const res = await fetch('/api/submit', {
|
|
|
|
|
|
method: 'POST',
|
|
|
|
|
|
headers: { 'Content-Type': 'application/json' },
|
|
|
|
|
|
body: JSON.stringify({
|
2026-05-06 11:36:19 +12:00
|
|
|
|
enquiryType,
|
|
|
|
|
|
fullName,
|
|
|
|
|
|
email,
|
|
|
|
|
|
phone,
|
|
|
|
|
|
petName: isGeneralEnquiry ? '' : petName,
|
|
|
|
|
|
location: isGeneralEnquiry ? '' : location,
|
|
|
|
|
|
message,
|
|
|
|
|
|
services: isGeneralEnquiry ? [] : selectedServices,
|
|
|
|
|
|
website,
|
|
|
|
|
|
formStartedAt,
|
2026-05-06 15:50:01 +12:00
|
|
|
|
visitStartedAt,
|
|
|
|
|
|
pageEnteredAt,
|
|
|
|
|
|
firstInteractionAt,
|
|
|
|
|
|
sendClickedAt,
|
|
|
|
|
|
stepChanges,
|
|
|
|
|
|
journey,
|
2026-05-06 11:36:19 +12:00
|
|
|
|
referrer: document.referrer,
|
|
|
|
|
|
page: window.location.href
|
|
|
|
|
|
})
|
2026-05-02 08:26:18 +12:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (!res.ok) {
|
|
|
|
|
|
const body = await res.json().catch(() => ({}));
|
2026-05-06 11:36:19 +12:00
|
|
|
|
const detail =
|
|
|
|
|
|
typeof body?.detail === 'string'
|
|
|
|
|
|
? body.detail
|
|
|
|
|
|
: body?.detail?.message ?? body?.message ?? `Server responded with ${res.status}`;
|
2026-05-02 09:43:32 +12:00
|
|
|
|
throw new Error(detail);
|
2026-05-02 08:26:18 +12:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
submitted = true;
|
|
|
|
|
|
} catch (err: unknown) {
|
2026-05-02 09:43:32 +12:00
|
|
|
|
submitErrorDetail = err instanceof Error ? err.message : String(err);
|
|
|
|
|
|
showErrorModal = true;
|
2026-05-02 08:26:18 +12:00
|
|
|
|
} finally {
|
|
|
|
|
|
submitting = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
2026-05-15 16:27:39 +12:00
|
|
|
|
<section
|
|
|
|
|
|
id="newlead"
|
|
|
|
|
|
use:reveal={{ delay: 70 }}
|
|
|
|
|
|
class="booking-shell reveal-block"
|
|
|
|
|
|
class:booking-shell--minimal-premium={variant === 'minimal-premium'}
|
|
|
|
|
|
class:booking-shell--card-stepper={variant === 'card-stepper'}
|
2026-05-18 09:43:29 +12:00
|
|
|
|
class:booking-shell--contact-modern={variant === 'contact-modern'}
|
2026-05-15 16:27:39 +12:00
|
|
|
|
>
|
2026-05-02 08:26:18 +12:00
|
|
|
|
<div class="form-inner">
|
2026-05-18 09:43:29 +12:00
|
|
|
|
{#if submitted && SuccessModalComponent}
|
|
|
|
|
|
<svelte:component
|
|
|
|
|
|
this={SuccessModalComponent}
|
2026-05-02 08:26:18 +12:00
|
|
|
|
firstName={fullName.split(' ')[0]}
|
2026-05-04 20:32:24 +12:00
|
|
|
|
petName={successPetName}
|
2026-05-02 08:26:18 +12:00
|
|
|
|
{email}
|
2026-05-04 20:32:24 +12:00
|
|
|
|
{enquiryType}
|
2026-05-02 08:26:18 +12:00
|
|
|
|
onClose={() => (submitted = false)}
|
|
|
|
|
|
/>
|
|
|
|
|
|
{/if}
|
|
|
|
|
|
|
2026-05-18 09:43:29 +12:00
|
|
|
|
{#if showErrorModal && ErrorModalComponent}
|
|
|
|
|
|
<svelte:component
|
|
|
|
|
|
this={ErrorModalComponent}
|
2026-05-02 09:43:32 +12:00
|
|
|
|
detail={submitErrorDetail}
|
2026-05-04 20:32:24 +12:00
|
|
|
|
{enquiryType}
|
2026-05-02 09:43:32 +12:00
|
|
|
|
onClose={() => (showErrorModal = false)}
|
|
|
|
|
|
onRetry={() => (showErrorModal = false)}
|
|
|
|
|
|
/>
|
|
|
|
|
|
{/if}
|
|
|
|
|
|
|
2026-05-02 08:26:18 +12:00
|
|
|
|
<div class="booking-header">
|
2026-05-15 01:28:10 +12:00
|
|
|
|
<span class="eyebrow booking-eyebrow">{bookingEyebrow}</span>
|
2026-05-02 08:26:18 +12:00
|
|
|
|
<h2 class="booking-title">
|
2026-05-06 11:36:19 +12:00
|
|
|
|
<span class="booking-title-plain">{headingParts.plain}</span>{' '}
|
|
|
|
|
|
<span class="booking-title-highlight">{headingParts.highlight}</span>
|
2026-05-02 08:26:18 +12:00
|
|
|
|
</h2>
|
2026-05-07 21:47:42 +12:00
|
|
|
|
<p class="booking-intro">{bookingIntro}</p>
|
2026-05-18 09:43:29 +12:00
|
|
|
|
{#if !usesStepperShell}
|
2026-05-15 16:27:39 +12:00
|
|
|
|
<div class="booking-trust-row" aria-label="Booking highlights">
|
|
|
|
|
|
<span class="booking-trust-chip">
|
|
|
|
|
|
<Icon name="fas fa-comment-dots" />
|
|
|
|
|
|
Reply within 24 hours
|
|
|
|
|
|
</span>
|
|
|
|
|
|
<span class="booking-trust-chip">
|
|
|
|
|
|
<Icon name="fas fa-paw" />
|
|
|
|
|
|
Free, no-obligation Meet & Greet
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</div>
|
2026-05-02 08:26:18 +12:00
|
|
|
|
|
2026-05-15 16:27:39 +12:00
|
|
|
|
<div class="booking-stepper" aria-label="Booking form steps">
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
class:active={step === 1}
|
|
|
|
|
|
class="booking-step"
|
|
|
|
|
|
on:click={() => setStep(1, step !== 1)}
|
|
|
|
|
|
>
|
|
|
|
|
|
<span class="booking-step-number">1</span>
|
|
|
|
|
|
<span class="booking-step-label">{detailsStepLabel}</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<span class="booking-step-divider" aria-hidden="true"></span>
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
class:active={step === 2}
|
|
|
|
|
|
class="booking-step"
|
2026-05-18 09:43:29 +12:00
|
|
|
|
disabled={!detailsStepComplete}
|
|
|
|
|
|
aria-disabled={!detailsStepComplete}
|
2026-05-15 16:27:39 +12:00
|
|
|
|
on:click={goToOwnerStep}
|
|
|
|
|
|
>
|
|
|
|
|
|
<span class="booking-step-number">2</span>
|
|
|
|
|
|
<span class="booking-step-label">{ownerStepLabel}</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
{/if}
|
2026-05-02 08:26:18 +12:00
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-05-06 15:50:01 +12:00
|
|
|
|
<form
|
|
|
|
|
|
class="booking-form"
|
|
|
|
|
|
id="bookingForm"
|
|
|
|
|
|
novalidate
|
|
|
|
|
|
on:submit={handleSubmit}
|
|
|
|
|
|
on:focusin={noteInteraction}
|
|
|
|
|
|
on:input={noteInteraction}
|
|
|
|
|
|
on:change={noteInteraction}
|
|
|
|
|
|
>
|
2026-05-02 11:24:11 +12:00
|
|
|
|
<div class="booking-honeypot" aria-hidden="true">
|
|
|
|
|
|
<label for="website">Website</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
bind:value={website}
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
id="website"
|
|
|
|
|
|
name="website"
|
|
|
|
|
|
tabindex="-1"
|
|
|
|
|
|
autocomplete="new-password"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-05-18 09:43:29 +12:00
|
|
|
|
<div class:booking-form-shell={usesStepperShell}>
|
|
|
|
|
|
{#if usesStepperShell}
|
2026-05-15 16:27:39 +12:00
|
|
|
|
<div class="booking-social-proof" aria-label="Goodwalk dog families">
|
|
|
|
|
|
<div class="booking-avatar-group" aria-hidden="true">
|
|
|
|
|
|
{#each bookingAvatarDogs as dog}
|
|
|
|
|
|
<span class="booking-avatar-bubble">
|
|
|
|
|
|
<img src={dog.image} alt="" loading="lazy" />
|
|
|
|
|
|
</span>
|
|
|
|
|
|
{/each}
|
|
|
|
|
|
</div>
|
2026-05-18 09:43:29 +12:00
|
|
|
|
<div class="booking-social-proof-copy">
|
|
|
|
|
|
<p>{bookingSocialProofTitle}</p>
|
|
|
|
|
|
<span class="booking-social-proof-note">{bookingSocialProofNote}</span>
|
2026-05-15 16:27:39 +12:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2026-05-18 09:43:29 +12:00
|
|
|
|
|
2026-05-15 16:27:39 +12:00
|
|
|
|
{/if}
|
|
|
|
|
|
|
2026-05-18 09:43:29 +12:00
|
|
|
|
{#if step === 1 || isSingleStep}
|
2026-05-06 11:36:19 +12:00
|
|
|
|
<input type="hidden" name="enquiryType" value={enquiryType} />
|
2026-05-03 11:49:59 +12:00
|
|
|
|
<div class="booking-panel">
|
2026-05-18 09:43:29 +12:00
|
|
|
|
{#if detailsStepIntro && !usesStepperShell}
|
2026-05-06 11:36:19 +12:00
|
|
|
|
<div class="booking-panel-banner">{detailsStepIntro}</div>
|
2026-05-03 11:49:59 +12:00
|
|
|
|
{/if}
|
|
|
|
|
|
|
2026-05-06 11:36:19 +12:00
|
|
|
|
<div
|
2026-05-18 09:43:29 +12:00
|
|
|
|
class:booking-card-grid-with-banner={Boolean(detailsStepIntro) && !usesStepperShell}
|
2026-05-06 11:36:19 +12:00
|
|
|
|
class="booking-card-grid booking-card-grid-dog"
|
|
|
|
|
|
>
|
2026-05-18 09:43:29 +12:00
|
|
|
|
{#if allowGeneralEnquiry}
|
|
|
|
|
|
<div class="booking-field-card booking-mode-card booking-field-card-full">
|
|
|
|
|
|
<fieldset class="booking-mode-group">
|
|
|
|
|
|
<legend class="booking-service-label">
|
|
|
|
|
|
<Icon name="fas fa-compass" /> {enquiryModeLegend}
|
|
|
|
|
|
</legend>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="booking-mode-options">
|
|
|
|
|
|
<label class="booking-mode-option" class:booking-mode-option-active={!isGeneralEnquiry}>
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="radio"
|
|
|
|
|
|
name="enquiryMode"
|
|
|
|
|
|
value="booking"
|
|
|
|
|
|
checked={!isGeneralEnquiry}
|
|
|
|
|
|
on:change={() => setEnquiryType('booking')}
|
|
|
|
|
|
/>
|
|
|
|
|
|
<span class="booking-mode-option-title">Book a Meet & Greet</span>
|
|
|
|
|
|
<span class="booking-mode-option-copy">
|
|
|
|
|
|
Tell us about your dog, your suburb, and the service you are interested in.
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
|
|
|
|
|
|
<label class="booking-mode-option" class:booking-mode-option-active={isGeneralEnquiry}>
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="radio"
|
|
|
|
|
|
name="enquiryMode"
|
|
|
|
|
|
value="general"
|
|
|
|
|
|
checked={isGeneralEnquiry}
|
|
|
|
|
|
on:change={() => setEnquiryType('general')}
|
|
|
|
|
|
/>
|
|
|
|
|
|
<span class="booking-mode-option-title">General enquiry</span>
|
|
|
|
|
|
<span class="booking-mode-option-copy">
|
|
|
|
|
|
Use this for feedback, complaints, or business questions.
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</fieldset>
|
2026-05-04 20:32:24 +12:00
|
|
|
|
</div>
|
|
|
|
|
|
{/if}
|
|
|
|
|
|
|
|
|
|
|
|
{#if !isGeneralEnquiry}
|
2026-05-07 21:47:42 +12:00
|
|
|
|
<div class="booking-field-card booking-field-card-group booking-field-card-full">
|
|
|
|
|
|
<div class="booking-field-group booking-field-group-dog">
|
|
|
|
|
|
<div class="booking-field-stack" class:booking-field-stack-invalid={errors.petName}>
|
|
|
|
|
|
<label for="petName">
|
2026-05-18 09:43:29 +12:00
|
|
|
|
<Icon name="fas fa-dog" /> Your dog's name <span class="booking-required">*</span>
|
2026-05-07 21:47:42 +12:00
|
|
|
|
</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
bind:this={petNameInput}
|
|
|
|
|
|
bind:value={petName}
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
id="petName"
|
|
|
|
|
|
name="petName"
|
|
|
|
|
|
required
|
2026-05-18 09:43:29 +12:00
|
|
|
|
placeholder="For example, Teddy"
|
2026-05-07 21:47:42 +12:00
|
|
|
|
class:input-invalid={errors.petName}
|
|
|
|
|
|
on:input={() => clearError('petName')}
|
|
|
|
|
|
/>
|
|
|
|
|
|
{#if errors.petName}
|
|
|
|
|
|
<p class="field-error">
|
|
|
|
|
|
<Icon name="fas fa-circle-exclamation" />
|
|
|
|
|
|
{errors.petName}
|
|
|
|
|
|
</p>
|
|
|
|
|
|
{/if}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="booking-field-stack" class:booking-field-stack-invalid={errors.location}>
|
|
|
|
|
|
<label for="location">
|
2026-05-18 09:43:29 +12:00
|
|
|
|
<Icon name="fas fa-location-dot" /> Your suburb <span class="booking-required">*</span>
|
2026-05-07 21:47:42 +12:00
|
|
|
|
</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
bind:this={locationInput}
|
|
|
|
|
|
bind:value={location}
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
id="location"
|
|
|
|
|
|
name="location"
|
|
|
|
|
|
required
|
2026-05-18 09:43:29 +12:00
|
|
|
|
placeholder="For example, Grey Lynn"
|
2026-05-07 21:47:42 +12:00
|
|
|
|
class:input-invalid={errors.location}
|
|
|
|
|
|
on:input={() => clearError('location')}
|
|
|
|
|
|
/>
|
|
|
|
|
|
{#if errors.location}
|
|
|
|
|
|
<p class="field-error">
|
|
|
|
|
|
<Icon name="fas fa-circle-exclamation" />
|
|
|
|
|
|
{errors.location}
|
|
|
|
|
|
</p>
|
|
|
|
|
|
{/if}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-05-15 01:28:10 +12:00
|
|
|
|
{#if hasServices}
|
2026-05-18 09:43:29 +12:00
|
|
|
|
<div
|
|
|
|
|
|
class="booking-field-stack booking-field-stack-full"
|
|
|
|
|
|
class:booking-field-stack-invalid={errors.services}
|
|
|
|
|
|
>
|
2026-05-15 01:28:10 +12:00
|
|
|
|
<div class="booking-selected-service-row">
|
2026-05-18 09:43:29 +12:00
|
|
|
|
<span class="booking-service-label"><Icon name="fas fa-paw" /> Which service are you interested in?</span>
|
2026-05-15 01:28:10 +12:00
|
|
|
|
{#if serviceChoiceLocked}
|
|
|
|
|
|
<button type="button" class="booking-inline-link" on:click={() => (showServicePicker = true)}>
|
2026-05-18 09:43:29 +12:00
|
|
|
|
Change service
|
2026-05-15 01:28:10 +12:00
|
|
|
|
</button>
|
|
|
|
|
|
{/if}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{#if serviceChoiceLocked}
|
|
|
|
|
|
<div class="booking-selected-service-chip">{selectedServices[0]}</div>
|
|
|
|
|
|
{:else}
|
|
|
|
|
|
<div class="booking-service-options">
|
|
|
|
|
|
{#each booking.serviceOptions as service}
|
2026-05-18 09:43:29 +12:00
|
|
|
|
<label class="booking-check-option" for={serviceInputId(service)}>
|
2026-05-15 01:28:10 +12:00
|
|
|
|
<input
|
2026-05-18 09:43:29 +12:00
|
|
|
|
id={serviceInputId(service)}
|
|
|
|
|
|
type="radio"
|
|
|
|
|
|
name="service"
|
2026-05-15 01:28:10 +12:00
|
|
|
|
value={service}
|
|
|
|
|
|
checked={selectedServices.includes(service)}
|
|
|
|
|
|
on:change={(event) =>
|
|
|
|
|
|
toggleService(service, (event.currentTarget as HTMLInputElement).checked)}
|
|
|
|
|
|
/>
|
|
|
|
|
|
<span class="booking-check-box" aria-hidden="true"></span>
|
|
|
|
|
|
<span>{service}</span>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
{/each}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
{/if}
|
2026-05-18 09:43:29 +12:00
|
|
|
|
|
|
|
|
|
|
{#if errors.services}
|
|
|
|
|
|
<p class="field-error">
|
|
|
|
|
|
<Icon name="fas fa-circle-exclamation" />
|
|
|
|
|
|
{errors.services}
|
|
|
|
|
|
</p>
|
|
|
|
|
|
{/if}
|
2026-05-15 01:28:10 +12:00
|
|
|
|
</div>
|
|
|
|
|
|
{/if}
|
|
|
|
|
|
|
2026-05-07 21:47:42 +12:00
|
|
|
|
<div
|
|
|
|
|
|
class="booking-field-stack booking-field-stack-full"
|
|
|
|
|
|
class:booking-field-stack-invalid={errors.message}
|
|
|
|
|
|
>
|
|
|
|
|
|
<label for="message">
|
|
|
|
|
|
<Icon name="fas fa-comment" /> {detailsMessageLabel}
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<textarea
|
|
|
|
|
|
bind:value={message}
|
|
|
|
|
|
id="message"
|
|
|
|
|
|
name="message"
|
|
|
|
|
|
rows="4"
|
|
|
|
|
|
placeholder={detailsMessagePlaceholder}
|
|
|
|
|
|
class:input-invalid={errors.message}
|
|
|
|
|
|
on:input={() => clearError('message')}
|
|
|
|
|
|
></textarea>
|
|
|
|
|
|
{#if errors.message}
|
|
|
|
|
|
<p class="field-error">
|
|
|
|
|
|
<Icon name="fas fa-circle-exclamation" />
|
|
|
|
|
|
{errors.message}
|
|
|
|
|
|
</p>
|
|
|
|
|
|
{/if}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2026-05-04 20:32:24 +12:00
|
|
|
|
</div>
|
2026-05-07 21:47:42 +12:00
|
|
|
|
{/if}
|
2026-05-03 11:49:59 +12:00
|
|
|
|
|
2026-05-07 21:47:42 +12:00
|
|
|
|
{#if isGeneralEnquiry}
|
2026-05-06 11:36:19 +12:00
|
|
|
|
<div
|
2026-05-07 21:47:42 +12:00
|
|
|
|
class="booking-field-card booking-field-card-full"
|
|
|
|
|
|
class:booking-field-card-invalid={errors.message}
|
2026-05-06 11:36:19 +12:00
|
|
|
|
>
|
2026-05-07 21:47:42 +12:00
|
|
|
|
<label for="message">
|
|
|
|
|
|
<Icon name="fas fa-comment" /> {detailsMessageLabel}
|
|
|
|
|
|
<span class="booking-required">*</span>
|
2026-05-04 20:32:24 +12:00
|
|
|
|
</label>
|
2026-05-07 21:47:42 +12:00
|
|
|
|
<textarea
|
|
|
|
|
|
bind:value={message}
|
|
|
|
|
|
id="message"
|
|
|
|
|
|
name="message"
|
|
|
|
|
|
rows="4"
|
|
|
|
|
|
placeholder={detailsMessagePlaceholder}
|
|
|
|
|
|
class:input-invalid={errors.message}
|
|
|
|
|
|
on:input={() => clearError('message')}
|
|
|
|
|
|
></textarea>
|
|
|
|
|
|
{#if errors.message}
|
2026-05-04 20:32:24 +12:00
|
|
|
|
<p class="field-error">
|
|
|
|
|
|
<Icon name="fas fa-circle-exclamation" />
|
2026-05-07 21:47:42 +12:00
|
|
|
|
{errors.message}
|
2026-05-04 20:32:24 +12:00
|
|
|
|
</p>
|
|
|
|
|
|
{/if}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
{/if}
|
2026-05-03 11:49:59 +12:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-05-18 09:43:29 +12:00
|
|
|
|
{#if !isSingleStep}
|
|
|
|
|
|
<div class="booking-actions booking-actions-next">
|
|
|
|
|
|
<button type="button" class="btn btn-yellow btn-with-arrow booking-next-button" on:click={goToOwnerStep}>
|
|
|
|
|
|
Continue to {ownerStepLabel.toLowerCase()}
|
|
|
|
|
|
<Icon name="fas fa-arrow-right" />
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<p class="booking-next-note">No payment, no pressure, just the right starting point for your dog.</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
{/if}
|
|
|
|
|
|
{/if}
|
|
|
|
|
|
{#if step === 2 || isSingleStep}
|
|
|
|
|
|
{#if !isSingleStep}
|
|
|
|
|
|
<input type="hidden" name="fullName" value={fullName} />
|
|
|
|
|
|
<input type="hidden" name="email" value={email} />
|
|
|
|
|
|
<input type="hidden" name="phone" value={phone} />
|
|
|
|
|
|
<input type="hidden" name="petName" value={petName} />
|
|
|
|
|
|
<input type="hidden" name="location" value={location} />
|
|
|
|
|
|
<input type="hidden" name="message" value={message} />
|
|
|
|
|
|
{/if}
|
2026-05-03 11:49:59 +12:00
|
|
|
|
|
2026-05-02 08:26:18 +12:00
|
|
|
|
<div class="booking-panel">
|
2026-05-18 09:43:29 +12:00
|
|
|
|
{#if ownerIntro && !usesStepperShell}
|
2026-05-06 11:36:19 +12:00
|
|
|
|
<div class="booking-panel-banner">{ownerIntro}</div>
|
2026-05-02 08:26:18 +12:00
|
|
|
|
{/if}
|
|
|
|
|
|
|
2026-05-06 11:36:19 +12:00
|
|
|
|
<div
|
2026-05-18 09:43:29 +12:00
|
|
|
|
class:booking-card-grid-with-banner={Boolean(ownerIntro) && !usesStepperShell}
|
2026-05-06 11:36:19 +12:00
|
|
|
|
class="booking-card-grid booking-card-grid-owner"
|
|
|
|
|
|
>
|
2026-05-02 08:26:18 +12:00
|
|
|
|
<div class="booking-field-card booking-field-card-group booking-field-card-full">
|
|
|
|
|
|
<div class="booking-field-group booking-field-group-owner">
|
|
|
|
|
|
<div class="booking-field-stack" class:booking-field-stack-invalid={errors.fullName}>
|
|
|
|
|
|
<label for="fullName">
|
|
|
|
|
|
<Icon name="fas fa-user" /> Full Name <span class="booking-required">*</span>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
bind:this={fullNameInput}
|
|
|
|
|
|
bind:value={fullName}
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
id="fullName"
|
|
|
|
|
|
name="fullName"
|
|
|
|
|
|
required
|
2026-05-18 09:43:29 +12:00
|
|
|
|
placeholder="Your full name"
|
2026-05-02 08:26:18 +12:00
|
|
|
|
class:input-invalid={errors.fullName}
|
|
|
|
|
|
on:input={() => clearError('fullName')}
|
|
|
|
|
|
/>
|
|
|
|
|
|
{#if errors.fullName}
|
|
|
|
|
|
<p class="field-error">
|
|
|
|
|
|
<Icon name="fas fa-circle-exclamation" />
|
|
|
|
|
|
{errors.fullName}
|
|
|
|
|
|
</p>
|
|
|
|
|
|
{/if}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="booking-field-stack" class:booking-field-stack-invalid={errors.email}>
|
|
|
|
|
|
<label for="email">
|
2026-05-18 09:43:29 +12:00
|
|
|
|
<Icon name="fas fa-envelope" /> Email address <span class="booking-required">*</span>
|
2026-05-02 08:26:18 +12:00
|
|
|
|
</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
bind:this={emailInput}
|
|
|
|
|
|
bind:value={email}
|
|
|
|
|
|
type="email"
|
|
|
|
|
|
id="email"
|
|
|
|
|
|
name="email"
|
|
|
|
|
|
required
|
2026-05-18 09:43:29 +12:00
|
|
|
|
placeholder="you@example.com"
|
2026-05-02 08:26:18 +12:00
|
|
|
|
class:input-invalid={errors.email}
|
|
|
|
|
|
on:input={() => clearError('email')}
|
2026-05-02 09:43:32 +12:00
|
|
|
|
on:blur={() => {
|
|
|
|
|
|
if (!email.trim()) return;
|
|
|
|
|
|
const msg = validateEmail(email);
|
|
|
|
|
|
errors = { ...errors, email: msg };
|
|
|
|
|
|
}}
|
2026-05-02 08:26:18 +12:00
|
|
|
|
/>
|
|
|
|
|
|
{#if errors.email}
|
|
|
|
|
|
<p class="field-error">
|
|
|
|
|
|
<Icon name="fas fa-circle-exclamation" />
|
|
|
|
|
|
{errors.email}
|
|
|
|
|
|
</p>
|
|
|
|
|
|
{/if}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="booking-field-stack" class:booking-field-stack-invalid={errors.phone}>
|
|
|
|
|
|
<label for="phone">
|
2026-05-18 09:43:29 +12:00
|
|
|
|
<Icon name="fas fa-phone" /> Phone number <span class="booking-required">*</span>
|
2026-05-02 08:26:18 +12:00
|
|
|
|
</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
bind:this={phoneInput}
|
|
|
|
|
|
bind:value={phone}
|
|
|
|
|
|
type="tel"
|
|
|
|
|
|
id="phone"
|
|
|
|
|
|
name="phone"
|
|
|
|
|
|
required
|
2026-05-18 09:43:29 +12:00
|
|
|
|
placeholder="For example, 021 123 4567"
|
2026-05-02 08:26:18 +12:00
|
|
|
|
class:input-invalid={errors.phone}
|
|
|
|
|
|
on:input={() => clearError('phone')}
|
|
|
|
|
|
/>
|
|
|
|
|
|
{#if errors.phone}
|
|
|
|
|
|
<p class="field-error">
|
|
|
|
|
|
<Icon name="fas fa-circle-exclamation" />
|
|
|
|
|
|
{errors.phone}
|
|
|
|
|
|
</p>
|
|
|
|
|
|
{/if}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-05-18 09:43:29 +12:00
|
|
|
|
<div class="booking-actions booking-actions-final" class:booking-actions-final-single={isSingleStep}>
|
|
|
|
|
|
{#if !isSingleStep}
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
class="btn btn-outline btn-outline-green"
|
|
|
|
|
|
on:click={() => setStep(1, true)}
|
|
|
|
|
|
>
|
|
|
|
|
|
Back
|
|
|
|
|
|
</button>
|
|
|
|
|
|
{/if}
|
2026-05-15 01:28:10 +12:00
|
|
|
|
<button type="submit" class="btn btn-yellow btn-with-arrow booking-submit-button" disabled={submitting}>
|
2026-05-07 21:47:42 +12:00
|
|
|
|
{#if submitting}
|
|
|
|
|
|
Sending…
|
|
|
|
|
|
{:else if isGeneralEnquiry}
|
|
|
|
|
|
Send enquiry <Icon name="fas fa-arrow-right" />
|
|
|
|
|
|
{:else}
|
2026-05-18 09:43:29 +12:00
|
|
|
|
Send Meet & Greet request <Icon name="fas fa-arrow-right" />
|
2026-05-07 21:47:42 +12:00
|
|
|
|
{/if}
|
2026-05-02 08:26:18 +12:00
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
{/if}
|
2026-05-15 16:27:39 +12:00
|
|
|
|
|
|
|
|
|
|
</div>
|
2026-05-02 08:26:18 +12:00
|
|
|
|
</form>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
|
|
<style>
|
|
|
|
|
|
:global(.reveal-ready.reveal-block) {
|
|
|
|
|
|
opacity: 0;
|
2026-05-18 09:43:29 +12:00
|
|
|
|
transform: translate3d(0, var(--reveal-distance, 16px), 0);
|
2026-05-02 08:26:18 +12:00
|
|
|
|
transition:
|
2026-05-18 09:43:29 +12:00
|
|
|
|
opacity 0.3s ease,
|
|
|
|
|
|
transform 0.45s cubic-bezier(0.2, 0.8, 0.2, 1);
|
2026-05-02 08:26:18 +12:00
|
|
|
|
transition-delay: var(--reveal-delay, 0ms);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
:global(.reveal-visible.reveal-block) {
|
|
|
|
|
|
opacity: 1;
|
|
|
|
|
|
transform: translate3d(0, 0, 0);
|
|
|
|
|
|
}
|
2026-05-02 11:24:11 +12:00
|
|
|
|
|
|
|
|
|
|
.booking-honeypot {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
left: -10000px;
|
|
|
|
|
|
top: auto;
|
|
|
|
|
|
width: 1px;
|
|
|
|
|
|
height: 1px;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
opacity: 0;
|
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
|
}
|
2026-05-15 16:27:39 +12:00
|
|
|
|
|
2026-05-18 09:43:29 +12:00
|
|
|
|
.booking-mode-card {
|
|
|
|
|
|
padding: 22px 24px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-mode-group {
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
border: 0;
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-mode-options {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
|
|
|
|
gap: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-mode-option {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
gap: 6px;
|
|
|
|
|
|
min-height: 44px;
|
|
|
|
|
|
padding: 16px 18px;
|
|
|
|
|
|
border-radius: 20px;
|
|
|
|
|
|
border: 2px solid var(--border-brand-strong);
|
|
|
|
|
|
background: var(--surface-page);
|
|
|
|
|
|
color: var(--text-heading-soft);
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
transition:
|
|
|
|
|
|
border-color 0.2s,
|
|
|
|
|
|
background 0.2s,
|
|
|
|
|
|
box-shadow 0.2s ease,
|
|
|
|
|
|
transform 0.16s cubic-bezier(0.22, 1, 0.36, 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-mode-option input {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
opacity: 0;
|
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-mode-option-title {
|
|
|
|
|
|
font-family: var(--font-head);
|
|
|
|
|
|
font-size: 15px;
|
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
line-height: 1.2;
|
|
|
|
|
|
color: var(--text-brand);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-mode-option-copy {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
line-height: 1.5;
|
|
|
|
|
|
color: var(--text-muted);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-mode-option-active {
|
|
|
|
|
|
border-color: var(--text-brand);
|
|
|
|
|
|
background: var(--surface-brand-selected);
|
|
|
|
|
|
box-shadow: var(--shadow-inset-soft);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@media (hover: hover) {
|
|
|
|
|
|
.booking-mode-option:hover {
|
|
|
|
|
|
border-color: var(--border-brand-hover);
|
|
|
|
|
|
transform: translateY(-1px);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-mode-option:focus-within {
|
|
|
|
|
|
border-color: var(--text-brand);
|
|
|
|
|
|
box-shadow: 0 0 0 4px rgba(var(--accent-rgb), 0.14);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-15 16:27:39 +12:00
|
|
|
|
.booking-shell--card-stepper {
|
|
|
|
|
|
background:
|
|
|
|
|
|
linear-gradient(180deg, rgba(255, 255, 255, 0.7), rgba(248, 247, 242, 0.9));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper :global(.form-inner) {
|
|
|
|
|
|
max-width: 1040px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-header {
|
|
|
|
|
|
max-width: 840px;
|
|
|
|
|
|
margin: 0 auto 34px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-eyebrow {
|
|
|
|
|
|
padding: 7px 14px;
|
|
|
|
|
|
background: rgba(33, 48, 33, 0.05);
|
|
|
|
|
|
box-shadow: inset 0 0 0 1px rgba(17, 20, 24, 0.05);
|
|
|
|
|
|
text-transform: none;
|
|
|
|
|
|
letter-spacing: 0.04em;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-title {
|
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
font-size: clamp(38px, 5vw, 58px);
|
|
|
|
|
|
line-height: 1.02;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-intro {
|
|
|
|
|
|
max-width: 42rem;
|
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-form-shell {
|
2026-05-18 09:43:29 +12:00
|
|
|
|
position: relative;
|
2026-05-15 16:27:39 +12:00
|
|
|
|
max-width: 900px;
|
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
|
padding: 0 24px 28px;
|
|
|
|
|
|
border-radius: 30px;
|
|
|
|
|
|
background: rgba(255, 255, 255, 0.94);
|
|
|
|
|
|
box-shadow:
|
|
|
|
|
|
inset 0 0 0 1px rgba(17, 20, 24, 0.06),
|
|
|
|
|
|
0 22px 52px rgba(17, 20, 24, 0.08);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-social-proof {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
gap: 16px;
|
|
|
|
|
|
margin: 0 -24px;
|
|
|
|
|
|
padding: 16px 24px;
|
|
|
|
|
|
border-radius: 30px 30px 0 0;
|
|
|
|
|
|
background:
|
|
|
|
|
|
linear-gradient(180deg, rgba(33, 48, 33, 0.06), rgba(33, 48, 33, 0.035));
|
|
|
|
|
|
box-shadow: inset 0 -1px 0 rgba(17, 20, 24, 0.08);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-18 09:43:29 +12:00
|
|
|
|
.booking-shell--card-stepper .booking-social-proof-copy {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
gap: 6px;
|
|
|
|
|
|
justify-items: center;
|
2026-05-15 16:27:39 +12:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-social-proof p {
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
color: var(--gw-green);
|
|
|
|
|
|
font-family: var(--font-head);
|
|
|
|
|
|
font-size: 17px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
line-height: 1.3;
|
|
|
|
|
|
text-wrap: balance;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-18 09:43:29 +12:00
|
|
|
|
.booking-shell--card-stepper .booking-social-proof-note {
|
|
|
|
|
|
color: var(--text-subtle);
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
line-height: 1.45;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
text-wrap: balance;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-15 16:27:39 +12:00
|
|
|
|
.booking-shell--card-stepper .booking-avatar-group {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
flex: none;
|
|
|
|
|
|
padding-left: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-avatar-bubble {
|
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
|
width: 50px;
|
|
|
|
|
|
height: 50px;
|
|
|
|
|
|
margin-left: -14px;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
border: 3px solid rgba(255, 255, 255, 0.96);
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
background: rgba(255, 255, 255, 0.16);
|
|
|
|
|
|
box-shadow: 0 8px 18px rgba(17, 20, 24, 0.08);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-avatar-bubble img {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
object-fit: cover;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-stepper {
|
2026-05-18 09:43:29 +12:00
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
2026-05-15 16:27:39 +12:00
|
|
|
|
gap: 20px;
|
2026-05-18 09:43:29 +12:00
|
|
|
|
margin-top: 0;
|
2026-05-15 16:27:39 +12:00
|
|
|
|
padding: 0;
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
box-shadow: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-step {
|
2026-05-18 09:43:29 +12:00
|
|
|
|
min-width: 0;
|
|
|
|
|
|
min-height: 0;
|
|
|
|
|
|
align-items: start;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
padding: 0 0 14px;
|
|
|
|
|
|
border-radius: 0;
|
|
|
|
|
|
border-bottom: 1px solid rgba(17, 20, 24, 0.12);
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-step:disabled {
|
|
|
|
|
|
cursor: not-allowed;
|
|
|
|
|
|
opacity: 0.64;
|
2026-05-15 16:27:39 +12:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-step.active {
|
2026-05-18 09:43:29 +12:00
|
|
|
|
border-bottom-color: color-mix(in srgb, var(--gw-green) 56%, white);
|
|
|
|
|
|
background: transparent;
|
2026-05-15 16:27:39 +12:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-step-number {
|
2026-05-18 09:43:29 +12:00
|
|
|
|
display: inline-flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
width: auto;
|
|
|
|
|
|
height: auto;
|
|
|
|
|
|
padding: 7px 10px;
|
|
|
|
|
|
border: 1px solid color-mix(in srgb, var(--gw-green) 82%, black);
|
|
|
|
|
|
border-radius: 999px;
|
2026-05-15 16:27:39 +12:00
|
|
|
|
background: var(--gw-green);
|
|
|
|
|
|
color: var(--yellow);
|
2026-05-18 09:43:29 +12:00
|
|
|
|
font-size: 11px;
|
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
letter-spacing: 0.16em;
|
|
|
|
|
|
line-height: 1;
|
|
|
|
|
|
text-transform: uppercase;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-step-number :global(.icon) {
|
|
|
|
|
|
color: var(--yellow);
|
|
|
|
|
|
font-size: 12px;
|
2026-05-15 16:27:39 +12:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-step.active .booking-step-number {
|
2026-05-18 09:43:29 +12:00
|
|
|
|
border-color: color-mix(in srgb, var(--gw-green) 74%, black);
|
|
|
|
|
|
background: var(--gw-green);
|
|
|
|
|
|
color: var(--yellow);
|
2026-05-15 16:27:39 +12:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-step-divider {
|
2026-05-18 09:43:29 +12:00
|
|
|
|
display: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-step-label {
|
|
|
|
|
|
color: var(--text-muted);
|
|
|
|
|
|
font-family: var(--font-head);
|
|
|
|
|
|
font-size: 19px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
letter-spacing: -0.025em;
|
|
|
|
|
|
line-height: 1.2;
|
|
|
|
|
|
text-align: left;
|
|
|
|
|
|
text-wrap: balance;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-step.active .booking-step-label {
|
|
|
|
|
|
color: var(--text-brand);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-step:disabled .booking-step-number {
|
|
|
|
|
|
background: rgba(17, 20, 24, 0.04);
|
|
|
|
|
|
color: var(--text-subtle);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-step:disabled .booking-step-number :global(.icon) {
|
|
|
|
|
|
color: var(--text-subtle);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-step:disabled .booking-step-label {
|
|
|
|
|
|
color: var(--text-subtle);
|
2026-05-15 16:27:39 +12:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-panel {
|
|
|
|
|
|
max-width: none;
|
|
|
|
|
|
margin: 24px 0 0;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
box-shadow: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-panel-banner {
|
|
|
|
|
|
margin-bottom: 18px;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
border-radius: 0;
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
box-shadow: none;
|
|
|
|
|
|
color: #4f555c;
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
line-height: 1.65;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-card-grid {
|
|
|
|
|
|
gap: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-card-grid-with-banner .booking-field-card {
|
|
|
|
|
|
border-radius: 26px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-field-card {
|
|
|
|
|
|
border-radius: 0;
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
box-shadow: none;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-field-card-group {
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-18 09:43:29 +12:00
|
|
|
|
.booking-shell--card-stepper .booking-mode-card {
|
|
|
|
|
|
padding: 0;
|
2026-05-15 16:27:39 +12:00
|
|
|
|
background: transparent;
|
|
|
|
|
|
box-shadow: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-18 09:43:29 +12:00
|
|
|
|
.booking-shell--card-stepper .booking-mode-option {
|
|
|
|
|
|
background: rgba(255, 255, 255, 0.86);
|
|
|
|
|
|
box-shadow:
|
|
|
|
|
|
inset 0 0 0 1px rgba(17, 20, 24, 0.06),
|
|
|
|
|
|
0 8px 18px rgba(17, 20, 24, 0.05);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-mode-option-active {
|
|
|
|
|
|
background: rgba(33, 48, 33, 0.08);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-field-stack {
|
|
|
|
|
|
padding: 18px;
|
|
|
|
|
|
border-radius: 24px;
|
|
|
|
|
|
background: linear-gradient(180deg, rgba(255, 255, 255, 0.96), rgba(247, 248, 246, 0.94));
|
|
|
|
|
|
box-shadow:
|
|
|
|
|
|
inset 0 0 0 1px rgba(17, 20, 24, 0.05),
|
|
|
|
|
|
0 12px 24px rgba(17, 20, 24, 0.04);
|
|
|
|
|
|
transition:
|
|
|
|
|
|
transform 0.2s cubic-bezier(0.22, 1, 0.36, 1),
|
|
|
|
|
|
box-shadow 0.2s ease,
|
|
|
|
|
|
background 0.2s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-field-stack:focus-within {
|
|
|
|
|
|
transform: translateY(-1px);
|
|
|
|
|
|
background: linear-gradient(180deg, rgba(255, 255, 255, 1), rgba(248, 247, 242, 0.98));
|
|
|
|
|
|
box-shadow:
|
|
|
|
|
|
inset 0 0 0 1px rgba(255, 209, 0, 0.42),
|
|
|
|
|
|
0 16px 28px rgba(17, 20, 24, 0.06);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-15 16:27:39 +12:00
|
|
|
|
.booking-shell--card-stepper .booking-field-card label,
|
|
|
|
|
|
.booking-shell--card-stepper .booking-service-label {
|
|
|
|
|
|
color: #171b20;
|
|
|
|
|
|
font-size: 15px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
letter-spacing: 0;
|
|
|
|
|
|
text-transform: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-field-card input,
|
|
|
|
|
|
.booking-shell--card-stepper .booking-field-card textarea {
|
|
|
|
|
|
border: 1px solid rgba(17, 20, 24, 0.1);
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
box-shadow: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-field-card input:hover,
|
|
|
|
|
|
.booking-shell--card-stepper .booking-field-card textarea:hover {
|
|
|
|
|
|
border-color: rgba(17, 20, 24, 0.18);
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
box-shadow: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-field-card input:focus,
|
|
|
|
|
|
.booking-shell--card-stepper .booking-field-card textarea:focus {
|
|
|
|
|
|
border-color: rgba(33, 48, 33, 0.45);
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
box-shadow: 0 0 0 4px rgba(255, 209, 0, 0.12);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-selected-service-chip,
|
|
|
|
|
|
.booking-shell--card-stepper .booking-check-option {
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-18 09:43:29 +12:00
|
|
|
|
.booking-shell--card-stepper .booking-selected-service-chip {
|
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
min-height: 42px;
|
|
|
|
|
|
padding: 0 16px;
|
|
|
|
|
|
border-radius: 999px;
|
|
|
|
|
|
background: rgba(33, 48, 33, 0.06);
|
|
|
|
|
|
box-shadow:
|
|
|
|
|
|
inset 0 0 0 1px rgba(33, 48, 33, 0.1),
|
|
|
|
|
|
0 10px 18px rgba(17, 20, 24, 0.04);
|
|
|
|
|
|
color: var(--gw-green);
|
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-15 16:27:39 +12:00
|
|
|
|
.booking-shell--card-stepper .booking-actions {
|
|
|
|
|
|
max-width: none;
|
|
|
|
|
|
margin-left: 0;
|
|
|
|
|
|
margin-right: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-actions-next,
|
|
|
|
|
|
.booking-shell--card-stepper .booking-actions-final {
|
|
|
|
|
|
margin-top: 18px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-next-note {
|
|
|
|
|
|
color: #687076;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-submit-button,
|
|
|
|
|
|
.booking-shell--card-stepper .booking-next-button {
|
|
|
|
|
|
box-shadow:
|
|
|
|
|
|
inset 0 -2px 0 rgba(0, 0, 0, 0.08),
|
|
|
|
|
|
0 12px 24px rgba(17, 20, 24, 0.1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium {
|
|
|
|
|
|
background:
|
|
|
|
|
|
linear-gradient(180deg, rgba(255, 255, 255, 0.78), rgba(248, 247, 242, 0.72));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium :global(.form-inner) {
|
|
|
|
|
|
max-width: 980px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-header {
|
|
|
|
|
|
max-width: 760px;
|
|
|
|
|
|
margin: 0 auto 34px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-eyebrow {
|
|
|
|
|
|
background: rgba(33, 48, 33, 0.06);
|
|
|
|
|
|
box-shadow: inset 0 0 0 1px rgba(17, 20, 24, 0.05);
|
|
|
|
|
|
color: var(--gw-green);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-title {
|
|
|
|
|
|
margin-bottom: 18px;
|
|
|
|
|
|
color: #11171b;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-intro {
|
|
|
|
|
|
max-width: 38rem;
|
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
|
color: #59606d;
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
line-height: 1.65;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-trust-row {
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-trust-chip {
|
|
|
|
|
|
background: rgba(33, 48, 33, 0.05);
|
|
|
|
|
|
box-shadow: inset 0 0 0 1px rgba(17, 20, 24, 0.05);
|
|
|
|
|
|
color: var(--gw-green);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-stepper {
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
margin-top: 24px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-step {
|
|
|
|
|
|
background: rgba(255, 255, 255, 0.86);
|
|
|
|
|
|
box-shadow:
|
|
|
|
|
|
inset 0 0 0 1px rgba(17, 20, 24, 0.06),
|
|
|
|
|
|
0 8px 18px rgba(17, 20, 24, 0.05);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-step.active {
|
|
|
|
|
|
background: rgba(33, 48, 33, 0.08);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-panel {
|
|
|
|
|
|
max-width: 860px;
|
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
|
padding: 30px;
|
|
|
|
|
|
border-radius: 32px;
|
|
|
|
|
|
background: rgba(251, 251, 251, 0.92);
|
|
|
|
|
|
box-shadow:
|
|
|
|
|
|
inset 0 0 0 1px rgba(17, 20, 24, 0.05),
|
|
|
|
|
|
0 22px 52px rgba(17, 20, 24, 0.08);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-panel-banner {
|
|
|
|
|
|
margin-bottom: 22px;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
border-radius: 0;
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
box-shadow: none;
|
|
|
|
|
|
color: #59606d;
|
|
|
|
|
|
font-size: 15px;
|
|
|
|
|
|
line-height: 1.65;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-card-grid {
|
|
|
|
|
|
gap: 18px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-field-card,
|
2026-05-18 09:43:29 +12:00
|
|
|
|
.booking-shell--minimal-premium .booking-mode-card {
|
2026-05-15 16:27:39 +12:00
|
|
|
|
border-radius: 24px;
|
|
|
|
|
|
background: linear-gradient(180deg, rgba(251, 251, 251, 0.98), rgba(247, 248, 246, 1));
|
|
|
|
|
|
box-shadow:
|
|
|
|
|
|
inset 0 0 0 1px rgba(17, 20, 24, 0.05),
|
|
|
|
|
|
0 12px 26px rgba(17, 20, 24, 0.05);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-field-card {
|
|
|
|
|
|
padding: 24px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-field-card-group {
|
|
|
|
|
|
padding: 24px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-18 09:43:29 +12:00
|
|
|
|
.booking-shell--minimal-premium .booking-mode-card {
|
2026-05-15 16:27:39 +12:00
|
|
|
|
padding: 16px 18px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-field-card label,
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-service-label {
|
|
|
|
|
|
color: #171b20;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-field-card input,
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-field-card textarea {
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
background: rgba(255, 255, 255, 0.96);
|
|
|
|
|
|
box-shadow:
|
|
|
|
|
|
inset 0 0 0 1px rgba(17, 20, 24, 0.08),
|
|
|
|
|
|
0 1px 0 rgba(255, 255, 255, 0.3);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-field-card input:hover,
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-field-card textarea:hover {
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
box-shadow:
|
|
|
|
|
|
inset 0 0 0 1px rgba(17, 20, 24, 0.12),
|
|
|
|
|
|
0 4px 12px rgba(17, 20, 24, 0.04);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-field-card input:focus,
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-field-card textarea:focus {
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
box-shadow:
|
|
|
|
|
|
inset 0 0 0 2px rgba(255, 209, 0, 0.6),
|
|
|
|
|
|
0 0 0 4px rgba(255, 209, 0, 0.14);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-selected-service-chip,
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-check-option {
|
|
|
|
|
|
background: rgba(255, 255, 255, 0.9);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-actions {
|
|
|
|
|
|
max-width: 860px;
|
|
|
|
|
|
margin-left: auto;
|
|
|
|
|
|
margin-right: auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-actions-next {
|
|
|
|
|
|
margin-top: 18px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-actions-final {
|
|
|
|
|
|
margin-top: 18px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-next-note {
|
|
|
|
|
|
color: #687076;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-submit-button,
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-next-button {
|
|
|
|
|
|
box-shadow:
|
|
|
|
|
|
inset 0 -2px 0 rgba(0, 0, 0, 0.08),
|
|
|
|
|
|
0 12px 24px rgba(17, 20, 24, 0.1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-18 09:43:29 +12:00
|
|
|
|
.booking-shell--contact-modern {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
overflow: clip;
|
|
|
|
|
|
background:
|
|
|
|
|
|
radial-gradient(circle at top left, rgba(229, 214, 194, 0.24), transparent 34%),
|
|
|
|
|
|
radial-gradient(circle at top right, rgba(33, 48, 33, 0.06), transparent 30%),
|
|
|
|
|
|
linear-gradient(180deg, rgba(251, 251, 251, 0.96), rgba(244, 246, 242, 0.99));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern::before {
|
|
|
|
|
|
content: '';
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
inset: 22px auto auto 50%;
|
|
|
|
|
|
width: min(720px, calc(100% - 48px));
|
|
|
|
|
|
height: 1px;
|
|
|
|
|
|
transform: translateX(-50%);
|
|
|
|
|
|
background: linear-gradient(90deg, transparent, rgba(33, 48, 33, 0.16), transparent);
|
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern::after {
|
|
|
|
|
|
content: '';
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
inset: 0;
|
|
|
|
|
|
background:
|
|
|
|
|
|
linear-gradient(180deg, rgba(255, 255, 255, 0.12), transparent 18%),
|
|
|
|
|
|
radial-gradient(circle at 50% 0, rgba(255, 209, 0, 0.05), transparent 22%);
|
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern :global(.form-inner) {
|
|
|
|
|
|
max-width: 1080px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-header {
|
|
|
|
|
|
max-width: 760px;
|
|
|
|
|
|
margin: 0 auto 32px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-eyebrow {
|
|
|
|
|
|
padding: 7px 14px;
|
|
|
|
|
|
background: rgba(33, 48, 33, 0.05);
|
|
|
|
|
|
box-shadow: inset 0 0 0 1px rgba(17, 20, 24, 0.05);
|
|
|
|
|
|
letter-spacing: 0.04em;
|
|
|
|
|
|
text-transform: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-title {
|
|
|
|
|
|
margin-bottom: 18px;
|
|
|
|
|
|
color: #11171b;
|
|
|
|
|
|
font-size: clamp(36px, 4.6vw, 56px);
|
|
|
|
|
|
line-height: 1.04;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-title-highlight {
|
|
|
|
|
|
color: color-mix(in srgb, var(--gw-green) 88%, black);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-intro {
|
|
|
|
|
|
max-width: 42rem;
|
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
|
color: var(--text-muted);
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
line-height: 1.68;
|
|
|
|
|
|
text-wrap: balance;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-form-shell {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
max-width: 960px;
|
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
|
padding: 18px 22px 30px;
|
|
|
|
|
|
border-radius: 36px;
|
|
|
|
|
|
background:
|
|
|
|
|
|
linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(249, 249, 248, 0.98));
|
|
|
|
|
|
box-shadow:
|
|
|
|
|
|
inset 0 0 0 1px rgba(17, 20, 24, 0.05),
|
|
|
|
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.42),
|
|
|
|
|
|
0 26px 60px rgba(17, 20, 24, 0.07);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-social-proof {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: auto minmax(0, 1fr);
|
|
|
|
|
|
gap: 18px;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
margin: 0 0 16px;
|
|
|
|
|
|
padding: 18px 20px 20px;
|
|
|
|
|
|
border-radius: 26px;
|
|
|
|
|
|
background:
|
|
|
|
|
|
linear-gradient(135deg, rgba(33, 48, 33, 0.07), rgba(229, 214, 194, 0.18));
|
|
|
|
|
|
box-shadow:
|
|
|
|
|
|
inset 0 0 0 1px rgba(17, 20, 24, 0.05),
|
|
|
|
|
|
0 14px 34px rgba(17, 20, 24, 0.06);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-social-proof-copy {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
gap: 4px;
|
|
|
|
|
|
justify-items: start;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-social-proof p {
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
color: var(--gw-green);
|
|
|
|
|
|
font-family: var(--font-head);
|
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
line-height: 1.3;
|
|
|
|
|
|
text-wrap: balance;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-social-proof-note {
|
|
|
|
|
|
color: var(--text-subtle);
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
line-height: 1.5;
|
|
|
|
|
|
text-wrap: balance;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-avatar-group {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
flex: none;
|
|
|
|
|
|
padding-left: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-avatar-bubble {
|
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
|
width: 54px;
|
|
|
|
|
|
height: 54px;
|
|
|
|
|
|
margin-left: -16px;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
border: 3px solid rgba(255, 255, 255, 0.98);
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
box-shadow: 0 10px 24px rgba(17, 20, 24, 0.08);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-avatar-bubble img {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
object-fit: cover;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-stepper {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
|
|
|
|
gap: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-step {
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
min-height: 0;
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
padding: 18px 20px;
|
|
|
|
|
|
border-radius: 22px;
|
|
|
|
|
|
background: linear-gradient(180deg, rgba(33, 48, 33, 0.94), rgba(45, 66, 48, 0.98));
|
|
|
|
|
|
box-shadow:
|
|
|
|
|
|
inset 0 0 0 1px rgba(255, 255, 255, 0.06),
|
|
|
|
|
|
0 12px 26px rgba(17, 20, 24, 0.12);
|
|
|
|
|
|
transition:
|
|
|
|
|
|
transform 0.24s cubic-bezier(0.22, 1, 0.36, 1),
|
|
|
|
|
|
background 0.24s ease,
|
|
|
|
|
|
box-shadow 0.24s ease,
|
|
|
|
|
|
opacity 0.24s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-step.active {
|
|
|
|
|
|
transform: translateY(-2px);
|
|
|
|
|
|
background: linear-gradient(180deg, rgba(33, 48, 33, 1), rgba(52, 75, 56, 1));
|
|
|
|
|
|
box-shadow:
|
|
|
|
|
|
inset 0 0 0 1px rgba(255, 209, 0, 0.22),
|
|
|
|
|
|
0 16px 30px rgba(17, 20, 24, 0.18);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-step:disabled {
|
|
|
|
|
|
opacity: 0.72;
|
|
|
|
|
|
cursor: not-allowed;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@media (hover: hover) {
|
|
|
|
|
|
.booking-shell--contact-modern .booking-step:not(:disabled):hover {
|
|
|
|
|
|
transform: translateY(-1px);
|
|
|
|
|
|
background: linear-gradient(180deg, rgba(38, 56, 38, 0.98), rgba(52, 75, 56, 0.98));
|
|
|
|
|
|
box-shadow:
|
|
|
|
|
|
inset 0 0 0 1px rgba(255, 255, 255, 0.08),
|
|
|
|
|
|
0 14px 28px rgba(17, 20, 24, 0.16);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-step-number {
|
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
width: auto;
|
|
|
|
|
|
height: auto;
|
|
|
|
|
|
padding: 7px 12px;
|
|
|
|
|
|
border: 1px solid rgba(255, 209, 0, 0.2);
|
|
|
|
|
|
border-radius: 999px;
|
|
|
|
|
|
background: rgba(255, 209, 0, 0.12);
|
|
|
|
|
|
color: var(--yellow);
|
|
|
|
|
|
font-size: 11px;
|
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
letter-spacing: 0.14em;
|
|
|
|
|
|
line-height: 1;
|
|
|
|
|
|
text-transform: uppercase;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-step-number :global(.icon) {
|
|
|
|
|
|
color: var(--yellow);
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-step.active .booking-step-number {
|
|
|
|
|
|
border-color: rgba(255, 209, 0, 0.28);
|
|
|
|
|
|
background: rgba(255, 209, 0, 0.18);
|
|
|
|
|
|
color: var(--yellow);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-step.active .booking-step-number :global(.icon) {
|
|
|
|
|
|
color: var(--yellow);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-step-divider {
|
|
|
|
|
|
display: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-step-label {
|
|
|
|
|
|
color: rgba(255, 255, 255, 0.98);
|
|
|
|
|
|
font-family: var(--font-head);
|
|
|
|
|
|
font-size: 19px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
letter-spacing: -0.025em;
|
|
|
|
|
|
line-height: 1.2;
|
|
|
|
|
|
text-align: left;
|
|
|
|
|
|
text-wrap: balance;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-step:disabled .booking-step-label {
|
|
|
|
|
|
color: rgba(255, 255, 255, 0.66);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-panel {
|
|
|
|
|
|
max-width: none;
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
box-shadow: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-panel-banner {
|
|
|
|
|
|
margin-bottom: 18px;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
border-radius: 0;
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
box-shadow: none;
|
|
|
|
|
|
color: var(--text-muted);
|
|
|
|
|
|
font-size: 15px;
|
|
|
|
|
|
line-height: 1.65;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-card-grid {
|
|
|
|
|
|
gap: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-field-card,
|
|
|
|
|
|
.booking-shell--contact-modern .booking-field-card-group,
|
|
|
|
|
|
.booking-shell--contact-modern .booking-mode-card {
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
border-radius: 0;
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
box-shadow: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-mode-options {
|
|
|
|
|
|
gap: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-mode-option {
|
|
|
|
|
|
background: linear-gradient(180deg, rgba(255, 255, 255, 0.86), rgba(247, 248, 246, 0.9));
|
|
|
|
|
|
box-shadow:
|
|
|
|
|
|
inset 0 0 0 1px rgba(17, 20, 24, 0.06),
|
|
|
|
|
|
0 10px 24px rgba(17, 20, 24, 0.04);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-mode-option-active {
|
|
|
|
|
|
background: linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(241, 245, 239, 0.98));
|
|
|
|
|
|
box-shadow:
|
|
|
|
|
|
inset 0 0 0 1px rgba(33, 48, 33, 0.18),
|
|
|
|
|
|
0 14px 28px rgba(17, 20, 24, 0.05);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-field-stack {
|
|
|
|
|
|
padding: 20px;
|
|
|
|
|
|
border-radius: 24px;
|
|
|
|
|
|
background: linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(248, 248, 247, 0.98));
|
|
|
|
|
|
box-shadow:
|
|
|
|
|
|
inset 0 0 0 1px rgba(17, 20, 24, 0.06),
|
|
|
|
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.3),
|
|
|
|
|
|
0 10px 22px rgba(17, 20, 24, 0.04);
|
|
|
|
|
|
transition:
|
|
|
|
|
|
transform 0.22s cubic-bezier(0.22, 1, 0.36, 1),
|
|
|
|
|
|
box-shadow 0.22s ease,
|
|
|
|
|
|
background 0.22s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-field-stack:focus-within {
|
|
|
|
|
|
transform: translateY(-2px);
|
|
|
|
|
|
background: linear-gradient(180deg, rgba(255, 255, 255, 1), rgba(249, 248, 245, 0.98));
|
|
|
|
|
|
box-shadow:
|
|
|
|
|
|
inset 0 0 0 1px rgba(255, 209, 0, 0.42),
|
|
|
|
|
|
0 18px 34px rgba(17, 20, 24, 0.07);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-field-card label,
|
|
|
|
|
|
.booking-shell--contact-modern .booking-service-label {
|
|
|
|
|
|
color: #171b20;
|
|
|
|
|
|
font-size: 15px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
letter-spacing: 0;
|
|
|
|
|
|
text-transform: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-field-card input,
|
|
|
|
|
|
.booking-shell--contact-modern .booking-field-card textarea {
|
|
|
|
|
|
border: 1px solid rgba(17, 20, 24, 0.1);
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
box-shadow: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-field-card input:hover,
|
|
|
|
|
|
.booking-shell--contact-modern .booking-field-card textarea:hover {
|
|
|
|
|
|
border-color: rgba(17, 20, 24, 0.18);
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
box-shadow: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-field-card input:focus,
|
|
|
|
|
|
.booking-shell--contact-modern .booking-field-card textarea:focus {
|
|
|
|
|
|
border-color: rgba(33, 48, 33, 0.45);
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
box-shadow: 0 0 0 4px rgba(255, 209, 0, 0.12);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-selected-service-chip,
|
|
|
|
|
|
.booking-shell--contact-modern .booking-check-option {
|
|
|
|
|
|
background: rgba(255, 255, 255, 0.92);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-check-option {
|
|
|
|
|
|
box-shadow:
|
|
|
|
|
|
inset 0 0 0 1px rgba(17, 20, 24, 0.06),
|
|
|
|
|
|
0 8px 18px rgba(17, 20, 24, 0.03);
|
|
|
|
|
|
transition:
|
|
|
|
|
|
transform 0.2s cubic-bezier(0.22, 1, 0.36, 1),
|
|
|
|
|
|
box-shadow 0.2s ease,
|
|
|
|
|
|
background 0.2s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@media (hover: hover) {
|
|
|
|
|
|
.booking-shell--contact-modern .booking-check-option:hover {
|
|
|
|
|
|
transform: translateY(-1px);
|
|
|
|
|
|
box-shadow:
|
|
|
|
|
|
inset 0 0 0 1px rgba(33, 48, 33, 0.12),
|
|
|
|
|
|
0 12px 24px rgba(17, 20, 24, 0.05);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-selected-service-chip {
|
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
min-height: 42px;
|
|
|
|
|
|
padding: 0 16px;
|
|
|
|
|
|
border-radius: 999px;
|
|
|
|
|
|
background: rgba(33, 48, 33, 0.06);
|
|
|
|
|
|
box-shadow: inset 0 0 0 1px rgba(33, 48, 33, 0.1);
|
|
|
|
|
|
color: var(--gw-green);
|
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-actions {
|
|
|
|
|
|
max-width: none;
|
|
|
|
|
|
margin-left: 0;
|
|
|
|
|
|
margin-right: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-actions-next,
|
|
|
|
|
|
.booking-shell--contact-modern .booking-actions-final {
|
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-next-note {
|
|
|
|
|
|
color: #687076;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-submit-button,
|
|
|
|
|
|
.booking-shell--contact-modern .booking-next-button {
|
|
|
|
|
|
box-shadow:
|
|
|
|
|
|
inset 0 -2px 0 rgba(0, 0, 0, 0.08),
|
|
|
|
|
|
0 16px 30px rgba(17, 20, 24, 0.12);
|
|
|
|
|
|
transition:
|
|
|
|
|
|
transform 0.22s cubic-bezier(0.22, 1, 0.36, 1),
|
|
|
|
|
|
box-shadow 0.22s ease,
|
|
|
|
|
|
filter 0.22s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@media (hover: hover) {
|
|
|
|
|
|
.booking-shell--contact-modern .booking-submit-button:hover,
|
|
|
|
|
|
.booking-shell--contact-modern .booking-next-button:hover {
|
|
|
|
|
|
transform: translateY(-2px);
|
|
|
|
|
|
filter: brightness(1.02);
|
|
|
|
|
|
box-shadow:
|
|
|
|
|
|
inset 0 -2px 0 rgba(0, 0, 0, 0.08),
|
|
|
|
|
|
0 20px 34px rgba(17, 20, 24, 0.14);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-15 16:27:39 +12:00
|
|
|
|
@media (max-width: 768px) {
|
2026-05-18 09:43:29 +12:00
|
|
|
|
.booking-mode-card {
|
|
|
|
|
|
padding: 20px 18px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-mode-options {
|
|
|
|
|
|
grid-template-columns: 1fr;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-mode-option {
|
|
|
|
|
|
padding: 14px 16px;
|
|
|
|
|
|
border-radius: 18px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-header {
|
|
|
|
|
|
margin-bottom: 26px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-title {
|
|
|
|
|
|
font-size: 34px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-form-shell {
|
|
|
|
|
|
padding: 16px 16px 22px;
|
|
|
|
|
|
border-radius: 26px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-social-proof {
|
|
|
|
|
|
grid-template-columns: 1fr;
|
|
|
|
|
|
justify-items: center;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
padding: 16px;
|
|
|
|
|
|
border-radius: 22px;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-social-proof-copy {
|
|
|
|
|
|
justify-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-stepper {
|
|
|
|
|
|
grid-template-columns: 1fr;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-step {
|
|
|
|
|
|
padding: 16px;
|
|
|
|
|
|
border-radius: 18px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-step-label {
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-selected-service-row {
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-selected-service-row .booking-service-label {
|
|
|
|
|
|
margin-bottom: 0;
|
|
|
|
|
|
line-height: 1.35;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-selected-service-chip {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
padding: 10px 14px;
|
|
|
|
|
|
line-height: 1.35;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
white-space: normal;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-service-options {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: 1fr;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-check-option {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
padding: 12px 14px;
|
|
|
|
|
|
border-radius: 16px;
|
|
|
|
|
|
line-height: 1.35;
|
|
|
|
|
|
box-shadow: inset 0 0 0 1px rgba(17, 20, 24, 0.06);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-check-box {
|
|
|
|
|
|
margin-top: 1px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-field-card,
|
|
|
|
|
|
.booking-shell--contact-modern .booking-field-card-group {
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
border-radius: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-field-stack {
|
|
|
|
|
|
padding: 16px;
|
|
|
|
|
|
border-radius: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-field-card label,
|
|
|
|
|
|
.booking-shell--contact-modern .booking-service-label {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
line-height: 1.35;
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-actions-next,
|
|
|
|
|
|
.booking-shell--contact-modern .booking-actions-final {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-actions-next .btn,
|
|
|
|
|
|
.booking-shell--contact-modern .booking-actions-final .btn {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--contact-modern .booking-next-note {
|
|
|
|
|
|
max-width: 24rem;
|
|
|
|
|
|
margin-left: auto;
|
|
|
|
|
|
margin-right: auto;
|
|
|
|
|
|
text-wrap: balance;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-15 16:27:39 +12:00
|
|
|
|
.booking-shell--card-stepper .booking-header {
|
|
|
|
|
|
margin-bottom: 26px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-title {
|
|
|
|
|
|
margin-bottom: 18px;
|
|
|
|
|
|
font-size: 34px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-form-shell {
|
|
|
|
|
|
padding: 0 18px 22px;
|
|
|
|
|
|
border-radius: 24px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-social-proof {
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
margin: 0 -18px;
|
|
|
|
|
|
padding: 14px 18px;
|
|
|
|
|
|
border-radius: 24px 24px 0 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-18 09:43:29 +12:00
|
|
|
|
.booking-shell--card-stepper .booking-social-proof-copy {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
max-width: 24rem;
|
2026-05-15 16:27:39 +12:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-social-proof p {
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-18 09:43:29 +12:00
|
|
|
|
.booking-shell--card-stepper .booking-social-proof-note {
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-15 16:27:39 +12:00
|
|
|
|
.booking-shell--card-stepper .booking-stepper {
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
padding: 0;
|
2026-05-18 09:43:29 +12:00
|
|
|
|
align-items: stretch;
|
2026-05-15 16:27:39 +12:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-step {
|
2026-05-18 09:43:29 +12:00
|
|
|
|
width: 100%;
|
|
|
|
|
|
gap: 6px;
|
|
|
|
|
|
padding: 0 0 12px;
|
2026-05-15 16:27:39 +12:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-step-number {
|
2026-05-18 09:43:29 +12:00
|
|
|
|
font-size: 10px;
|
2026-05-15 16:27:39 +12:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-step-label {
|
2026-05-18 09:43:29 +12:00
|
|
|
|
font-size: 15px;
|
|
|
|
|
|
line-height: 1.22;
|
|
|
|
|
|
text-wrap: balance;
|
2026-05-15 16:27:39 +12:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-panel {
|
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-panel-banner {
|
|
|
|
|
|
font-size: 15px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-18 09:43:29 +12:00
|
|
|
|
.booking-shell--card-stepper .booking-selected-service-row {
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-selected-service-row .booking-service-label {
|
|
|
|
|
|
margin-bottom: 0;
|
|
|
|
|
|
line-height: 1.35;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-inline-link {
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-selected-service-chip {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
padding: 10px 14px;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
line-height: 1.35;
|
|
|
|
|
|
white-space: normal;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-service-options {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: 1fr;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-check-option {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
padding: 12px 14px;
|
|
|
|
|
|
border-radius: 16px;
|
|
|
|
|
|
background: rgba(255, 255, 255, 0.92);
|
|
|
|
|
|
box-shadow: inset 0 0 0 1px rgba(17, 20, 24, 0.06);
|
|
|
|
|
|
line-height: 1.35;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-check-box {
|
|
|
|
|
|
margin-top: 1px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-15 16:27:39 +12:00
|
|
|
|
.booking-shell--card-stepper .booking-field-card,
|
|
|
|
|
|
.booking-shell--card-stepper .booking-field-card-group {
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
border-radius: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-18 09:43:29 +12:00
|
|
|
|
.booking-shell--card-stepper .booking-field-stack {
|
|
|
|
|
|
padding: 16px;
|
2026-05-15 16:27:39 +12:00
|
|
|
|
border-radius: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-18 09:43:29 +12:00
|
|
|
|
.booking-shell--card-stepper .booking-field-card label,
|
|
|
|
|
|
.booking-shell--card-stepper .booking-service-label {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
line-height: 1.35;
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-actions-next,
|
|
|
|
|
|
.booking-shell--card-stepper .booking-actions-final {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-actions-next .btn,
|
|
|
|
|
|
.booking-shell--card-stepper .booking-actions-final .btn {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-next-note {
|
|
|
|
|
|
max-width: 24rem;
|
|
|
|
|
|
margin-left: auto;
|
|
|
|
|
|
margin-right: auto;
|
|
|
|
|
|
text-wrap: balance;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-15 16:27:39 +12:00
|
|
|
|
.booking-shell--minimal-premium .booking-header {
|
|
|
|
|
|
margin-bottom: 26px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-intro {
|
|
|
|
|
|
font-size: 15px;
|
|
|
|
|
|
line-height: 1.58;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-stepper {
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-panel {
|
|
|
|
|
|
padding: 18px;
|
|
|
|
|
|
border-radius: 24px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-field-card,
|
|
|
|
|
|
.booking-shell--minimal-premium .booking-field-card-group {
|
|
|
|
|
|
padding: 20px;
|
|
|
|
|
|
border-radius: 22px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-18 09:43:29 +12:00
|
|
|
|
.booking-shell--minimal-premium .booking-mode-card {
|
2026-05-15 16:27:39 +12:00
|
|
|
|
border-radius: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-05-18 09:43:29 +12:00
|
|
|
|
|
|
|
|
|
|
.booking-actions-final-single {
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@media (max-width: 600px) {
|
|
|
|
|
|
.booking-submit-button,
|
|
|
|
|
|
.booking-next-button {
|
|
|
|
|
|
white-space: normal;
|
|
|
|
|
|
line-height: 1.25;
|
|
|
|
|
|
padding: 14px 18px;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-submit-button :global(.icon),
|
|
|
|
|
|
.booking-next-button :global(.icon) {
|
|
|
|
|
|
flex: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-form-shell,
|
|
|
|
|
|
.booking-shell--contact-modern .booking-form-shell {
|
|
|
|
|
|
overflow-x: clip;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Booking section uses the shared --space-container-x-mobile gutter
|
|
|
|
|
|
(responsive.css). The bordered .booking-form-shell card therefore
|
|
|
|
|
|
aligns with every other bordered container at 24px inset on mobile. */
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-field-card input,
|
|
|
|
|
|
.booking-shell--card-stepper .booking-field-card textarea,
|
|
|
|
|
|
.booking-shell--contact-modern .booking-field-card input,
|
|
|
|
|
|
.booking-shell--contact-modern .booking-field-card textarea {
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
max-width: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-field-stack,
|
|
|
|
|
|
.booking-shell--contact-modern .booking-field-stack {
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-card-grid-owner,
|
|
|
|
|
|
.booking-shell--contact-modern .booking-card-grid-owner {
|
|
|
|
|
|
margin-top: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@media (max-width: 600px) {
|
|
|
|
|
|
.booking-shell--card-stepper .booking-social-proof,
|
|
|
|
|
|
.booking-shell--contact-modern .booking-social-proof {
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
padding: 10px 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-avatar-bubble,
|
|
|
|
|
|
.booking-shell--contact-modern .booking-avatar-bubble {
|
|
|
|
|
|
width: 36px;
|
|
|
|
|
|
height: 36px;
|
|
|
|
|
|
margin-left: -10px;
|
|
|
|
|
|
border-width: 2px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-social-proof p,
|
|
|
|
|
|
.booking-shell--contact-modern .booking-social-proof p {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
line-height: 1.3;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-social-proof-note,
|
|
|
|
|
|
.booking-shell--contact-modern .booking-social-proof-note {
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
line-height: 1.35;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-panel,
|
|
|
|
|
|
.booking-shell--contact-modern .booking-panel {
|
|
|
|
|
|
margin-top: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-field-stack,
|
|
|
|
|
|
.booking-shell--contact-modern .booking-field-stack {
|
|
|
|
|
|
padding: 12px;
|
|
|
|
|
|
border-radius: 18px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.booking-shell--card-stepper .booking-card-grid,
|
|
|
|
|
|
.booking-shell--contact-modern .booking-card-grid {
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-05-02 08:26:18 +12:00
|
|
|
|
</style>
|