simpo-component-library 3.6.951 → 3.6.952
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/lib/ecommerce/sections/book-appointment/book-appointment.component.mjs +19 -3
- package/esm2022/lib/sections/appointment-form/appointment-booking/appointment-booking/appointment-booking.component.mjs +22 -4
- package/fesm2022/simpo-component-library.mjs +32 -5
- package/fesm2022/simpo-component-library.mjs.map +1 -1
- package/lib/ecommerce/sections/book-appointment/book-appointment.component.d.ts +10 -0
- package/lib/sections/appointment-form/appointment-booking/appointment-booking/appointment-booking.component.d.ts +11 -1
- package/package.json +1 -1
- package/simpo-component-library-3.6.952.tgz +0 -0
- package/simpo-component-library-3.6.951.tgz +0 -0
|
@@ -25345,8 +25345,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
25345
25345
|
args: ['input', ['$event']]
|
|
25346
25346
|
}] } });
|
|
25347
25347
|
|
|
25348
|
-
class AppointmentBookingComponent {
|
|
25348
|
+
class AppointmentBookingComponent extends BaseSection {
|
|
25349
25349
|
constructor(restService, _eventService, router, messageService, bookingProductCartService, storageService, matDialog, dialogRef) {
|
|
25350
|
+
super();
|
|
25350
25351
|
this.restService = restService;
|
|
25351
25352
|
this._eventService = _eventService;
|
|
25352
25353
|
this.router = router;
|
|
@@ -25418,6 +25419,19 @@ class AppointmentBookingComponent {
|
|
|
25418
25419
|
};
|
|
25419
25420
|
this.apiStatus = false;
|
|
25420
25421
|
}
|
|
25422
|
+
/** Editor-configurable background - falls back to undefined (letting the component's own CSS
|
|
25423
|
+
* defaults show through unchanged) for existing pages saved before this section supported
|
|
25424
|
+
* custom colors. */
|
|
25425
|
+
get backgroundInfo() {
|
|
25426
|
+
return this.data?.styles?.background;
|
|
25427
|
+
}
|
|
25428
|
+
/** Overrides this component's own --color-accent-gradient CSS variable (scoped to its :host,
|
|
25429
|
+
* see appointment-booking.component.css) when a business has picked a custom accent color -
|
|
25430
|
+
* null when unset, so the [style.--color-accent-gradient] binding removes the inline override
|
|
25431
|
+
* entirely and the CSS default shows through, rather than forcing an empty value. */
|
|
25432
|
+
get accentColor() {
|
|
25433
|
+
return this.data?.styles?.background?.accentColor || null;
|
|
25434
|
+
}
|
|
25421
25435
|
ngOnInit() {
|
|
25422
25436
|
// Login is required before entering the wizard at all (not mid-flow, like cart's
|
|
25423
25437
|
// checkout-commit gate) - the wizard's selections live only in component memory, so a
|
|
@@ -25961,11 +25975,11 @@ class AppointmentBookingComponent {
|
|
|
25961
25975
|
this.resetWizard();
|
|
25962
25976
|
}
|
|
25963
25977
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AppointmentBookingComponent, deps: [{ token: RestService }, { token: EventsService }, { token: i2$2.Router }, { token: i6$1.MessageService }, { token: BookingProductCartService }, { token: StorageServiceService }, { token: i3$2.MatDialog }, { token: i3$2.MatDialogRef, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
25964
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: AppointmentBookingComponent, isStandalone: true, selector: "simpo-appointment-booking", inputs: { data: "data", index: "index", edit: "edit", isAdminBooking: "isAdminBooking", delete: "delete", customClass: "customClass", nextComponentColor: "nextComponentColor", prefillContact: "prefillContact" }, host: { listeners: { "window: resize": "getScreenSize($event)", "document:click": "closeOnOutsideClick()" } }, providers: [MessageService], ngImport: i0, template: "<p-toast position=\"bottom-right\" [baseZIndex]=\"10000000000\" [autoZIndex]=\"true\"\n [showTransformOptions]=\"screenWidth < 475 ? 'translateY(-100%)' : ''\"></p-toast>\n<section class=\"main_section\">\n <div class=\"main_header\">\n <div class=\"header d-flex justify-content-between align-items-center\">\n <div class=\"back-btn d-flex justify-content-center align-items-center cursor-pointer gap-2 mb-3\"\n (click)=\"goBack()\">\n <mat-icon>keyboard_backspace</mat-icon><span *ngIf=\"screenWidth > 475\">Back to Home</span>\n </div>\n <div class=\"header-title\">\n <h1>Book New Appointment</h1>\n <p>{{businessName ?? \"N/A\" }}</p>\n </div>\n </div>\n\n <div class=\"progress-bar\">\n <div class=\"progress-fill\" [style.width]=\"barWidth + '%'\"></div>\n </div>\n </div>\n <div class=\"main_body w-100 d-flex justify-content-center\">\n <ng-container *ngIf=\"selectedTab === 'modeSelection'\">\n <ng-container *ngTemplateOutlet=\"modeSelection\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'serviceListing'\">\n <ng-container *ngIf=\"!skeletonLoader\">\n <ng-container *ngTemplateOutlet=\"serviceListing\"></ng-container>\n </ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'locationListing'\">\n <ng-container *ngTemplateOutlet=\"locationListing\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'staffListing'\">\n <ng-container *ngTemplateOutlet=\"staffListing\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'dateSelection'\">\n <ng-container *ngTemplateOutlet=\"dateSelection\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab==='contactDetails'\">\n <ng-container *ngTemplateOutlet=\"contactDetails\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab==='paymentTab'\">\n <ng-container *ngTemplateOutlet=\"paymentTab\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab==='statusTemplate'\">\n <ng-container *ngTemplateOutlet=\"statusTemplate\"></ng-container>\n </ng-container>\n </div>\n <div class=\"main_footer d-flex justify-content-center align-items-center\"\n *ngIf=\"selectedTab!=='statusTemplate' && selectedTab!=='modeSelection'\">\n <div class=\"footer-buttons\"\n [ngStyle]=\"{'justify-content': selectedTab != 'serviceListing' ? 'space-between' : 'end'}\">\n <span class=\"back-footer-btn cursor-pointer\" (click)=\"previousStep()\"\n *ngIf=\"selectedTab != 'serviceListing'\">Back</span>\n <button class=\"continue-btn\" [disabled]=\"!activeButton\" (click)=\"nextStep()\"\n *ngIf=\"selectedTab!='paymentTab'\">{{!loader ? 'Continue' : 'Loading...'}}</button>\n <button class=\"cursor-pointer d-flex justify-content-evenly align-items-center\"\n *ngIf=\"selectedTab==='paymentTab'\" (click)=\"confirmBooking()\" [disabled]=\"isProcessing\"\n [ngClass]=\"{'pay-now-btn' : bookingGroup?.totalCollectedAtBooking > 0 || !bookingGroup,'complete_booking' : bookingGroup && !bookingGroup?.totalCollectedAtBooking}\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/304012c1753440087996Background.png\">\n {{isProcessing ? 'Please wait...' : 'Confirm Booking'}}\n </button>\n </div>\n </div>\n</section>\n\n<ng-template #modeSelection>\n <div class=\"w-60 service_section\">\n <div class=\"service-selection\">\n <h2>How would you like this?</h2>\n <p>Choose how you'd like to be served</p>\n <div class=\"services-grid\">\n <div class=\"service-card\" (click)=\"selectMode('STORE_VISIT')\">\n <div class=\"service-header\">\n <div class=\"service-icon\"><mat-icon>storefront</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">Visit our Store</div>\n </div>\n </div>\n <div class=\"service-description\">Come to us at one of our locations</div>\n </div>\n <div class=\"service-card\" (click)=\"selectMode('HOME_VISIT')\">\n <div class=\"service-header\">\n <div class=\"service-icon\"><mat-icon>home</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">We come to you</div>\n </div>\n </div>\n <div class=\"service-description\">A professional visits your address</div>\n </div>\n <div class=\"service-card\" (click)=\"selectMode('VIDEO_CALL')\">\n <div class=\"service-header\">\n <div class=\"service-icon\"><mat-icon>videocam</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">Video consultation</div>\n </div>\n </div>\n <div class=\"service-description\">Connect over a video call</div>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #serviceListing>\n <div class=\"w-60 service_section\">\n <div class=\"service-selection\">\n <h2>Select a Service</h2>\n <p>Choose the service(s) you'd like to book<span *ngIf=\"cartServices.length > 0\"> \u2014 {{cartServices.length}} selected</span></p>\n <p *ngIf=\"productCartItems.length > 0\" class=\"cart-hint\">{{productCartItems.length}} product(s) already in your cart \u2014 you can continue without picking a service.</p>\n\n <div class=\"services-grid\">\n <ng-container *ngFor=\"let service of serviceData\">\n <div class=\"\" (click)=\"selectService(service)\"\n [ngClass]=\"{ 'service-card-selected' : service?.selected, 'service-card': !service?.selected }\">\n <div class=\" service-header\">\n <div class=\"service-icon\"><mat-icon>person_outline</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">{{service?.name ? service?.name : 'N/A'}}</div>\n </div>\n <div>\n <div class=\"service-price\">\u20B9{{service?.priceDetails?.price ?\n service?.priceDetails?.price : 'N/A' }}</div>\n <div class=\"service-duration\">{{service?.duration ? service?.duration : 'N/A'}} min\n </div>\n </div>\n </div>\n <div class=\"service-description\" *ngIf=\"service?.description\">\n {{service?.description ? service?.description : 'N/A'}}\n </div>\n <div class=\"home-visit\" *ngIf=\"selectedMode === 'STORE_VISIT' && service?.homeAppointmentAvailable\"><img\n src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/982126c1758628863129furniture_16406103.png\">Home\n Visit Available</div>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #locationListing>\n <div class=\"location_section\">\n <div class=\"header flex-column align-items-start\">\n <h1>Choose Location</h1>\n <p>Select where you'd like to receive the service</p>\n </div>\n\n <div class=\"location-list\">\n <ng-container *ngFor=\"let location of locationData\">\n <div (click)=\"selectLocation(location)\"\n [ngClass]=\"{ 'location-card-selected' : location?.selected, 'location-card': !location?.selected }\">\n <div class=\"location-content\">\n <div class=\"location-info\">\n <div class=\"location-icon\"><img\n src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/427226c1758629157758store_3171510.png\">\n </div>\n <div class=\"location-details\">\n <div class=\"d-flex justify-content-between align-items-center\">\n <h3>{{location?.storeName ? location?.storeName : 'N/A'}}</h3>\n </div>\n <p>{{location?.addressDetails?.addressLine}}, {{location?.addressDetails?.city}},\n {{location?.addressDetails?.state}} {{location?.pincode}}</p>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n</ng-template>\n\n<ng-template #staffListing>\n <div class=\"w-60 overflow-hidden staff-listing\">\n <div class=\"d-flex w-100 h-100\">\n <div class=\"w-100\">\n <div class=\"staff-header mb-3\">\n <h1>Select Staff Member</h1>\n <p class=\"staff-subtitle mb-0\">Choose your preferred professional</p>\n </div>\n\n <div class=\"search-container mb-4\">\n <div class=\"search-input-wrapper d-flex align-items-center\">\n <mat-icon class=\"search-icon me-2\">search</mat-icon>\n <input type=\"text\" class=\"search-input border-0 flex-grow-1\" placeholder=\"Search staff member by name...\" [(ngModel)]=\"staffSearchQuery\">\n <mat-icon class=\"clear-icon cursor-pointer ms-2\" *ngIf=\"staffSearchQuery\" (click)=\"staffSearchQuery = ''\">close</mat-icon>\n </div>\n </div>\n\n <!-- Pure product-only line: one flat staff list, same as the old single-service flow -->\n <div class=\"staff-list\" *ngIf=\"cartServices.length === 0\">\n <ng-container *ngFor=\"let staff of filteredStaff\">\n <div class=\"card rounded-3 p-3\" (click)=\"selectStaffForProductOnlyLine(staff)\"\n [ngClass]=\"{ 'staff-card-selected' : staff?.selected, 'staff-card': !staff?.selected }\">\n <div class=\"d-flex align-items-center justify-content-between w-100\">\n <div class=\"d-flex align-items-center flex-grow-1\">\n <div class=\"staff-avatar rounded-circle d-flex align-items-center justify-content-center me-4\">\n {{staff?.staffName.slice(0,2).toUpperCase()}}\n </div>\n <div class=\"staff-details flex-grow-1\">\n <h3 class=\"staff-name\">{{(staff?.staffName ? staff?.staffName : 'N/A') | titlecase}}</h3>\n <p class=\"staff-specialty\">{{(businessName && businessName !== 'N/A') ? businessName : 'Booking Specialist'}}</p>\n </div>\n </div>\n <div class=\"selection-indicator\">\n <div class=\"checkmark-circle-mini d-flex align-items-center justify-content-center\" [class.selected]=\"staff?.selected\">\n <mat-icon *ngIf=\"staff?.selected\">check</mat-icon>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n\n <!-- Bundled cart: one pool per line that resolution couldn't collapse to a single provider -->\n <ng-container *ngIf=\"cartServices.length > 0\">\n <div class=\"staff-line-group mb-4\" *ngFor=\"let line of resolvedLines\">\n <ng-container *ngIf=\"line.candidateStaffPool?.length\">\n <h4 class=\"mb-2\">For {{line.services.length}} service(s): {{ (line.services | slice:0:3).length ? '' : '' }}<span *ngFor=\"let s of line.services; let last = last\">{{s.name}}{{last ? '' : ', '}}</span></h4>\n <div class=\"staff-list mb-3\">\n <ng-container *ngFor=\"let staff of line.candidateStaffPool\">\n <div class=\"card rounded-3 p-3\" (click)=\"selectStaffForLine(line, staff)\"\n [ngClass]=\"{ 'staff-card-selected' : line.selectedStaffId === staff.id, 'staff-card': line.selectedStaffId !== staff.id }\">\n <div class=\"d-flex align-items-center justify-content-between w-100\">\n <div class=\"d-flex align-items-center flex-grow-1\">\n <div class=\"staff-avatar rounded-circle d-flex align-items-center justify-content-center me-4\">\n {{staff?.name?.slice(0,2)?.toUpperCase()}}\n </div>\n <div class=\"staff-details flex-grow-1\">\n <h3 class=\"staff-name\">{{(staff?.name ? staff?.name : 'N/A') | titlecase}}</h3>\n </div>\n </div>\n <div class=\"selection-indicator\">\n <div class=\"checkmark-circle-mini d-flex align-items-center justify-content-center\" [class.selected]=\"line.selectedStaffId === staff.id\">\n <mat-icon *ngIf=\"line.selectedStaffId === staff.id\">check</mat-icon>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n </ng-container>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #dateSelection>\n <div class=\"w-60 date_section\">\n <div class=\"row justify-content-center h-100\">\n <div class=\"col-12 h-100\">\n <div class=\"datetime-header mb-2\">\n <h1>Select Date & Time</h1>\n <p class=\"datetime-subtitle mb-0\">Choose when you'd like your appointment</p>\n </div>\n\n <div class=\"d-flex gap-4 main_container\">\n <div [ngClass]=\"{'w-50' : screenWidth > 475 , 'w-100':screenWidth < 475}\">\n <div class=\"section-card card rounded-3 p-4 h-100\">\n <h3 class=\"section-title\">Select Date</h3>\n\n <div class=\"date-picker-container d-flex align-items-center justify-content-between\"\n (click)=\"$event.stopPropagation()\">\n <input type=\"text\" class=\"date-input border-0 rounded-2\" placeholder=\"dd-mm-yyyy\"\n [value]=\"selectedDateStr\" readonly (click)=\"toggleCalendar($event)\">\n\n <mat-icon class=\"ms-2\" (click)=\"toggleCalendar($event)\">calendar_today</mat-icon>\n </div>\n <div class=\"position-relative\" (click)=\"$event.stopPropagation()\">\n <div class=\"datepicker-popover\" *ngIf=\"showCalendar\">\n <mat-calendar [(selected)]=\"selectedDate\" [dateFilter]=\"dateFilter\"\n (selectedChange)=\"onDateSelected($event)\" class=\"datepicker-calendar\">\n </mat-calendar>\n </div>\n </div>\n </div>\n </div>\n\n <!-- One slot-picker per resolved line, side by side when there's more than one (design doc \u00A73b) -->\n <div class=\"time_selection\" [ngClass]=\"{'w-50' : screenWidth > 475 , 'w-100':screenWidth < 475}\" *ngIf=\"resolvedLines.length <= 1\">\n <div class=\"section-card card h-100 rounded-3 p-4\">\n <h3 class=\"section-title\">Available Times</h3>\n <div class=\"row g-2 mb-4 overflow-scroll\">\n <ng-container *ngIf=\"!skeletonLoader && resolvedLines[0]\">\n <div class=\"col-4\" *ngFor=\"let time of resolvedLines[0].slots\">\n <div class=\"time-slot rounded-2\" [class.selected]=\"time.selected\"\n (click)=\"selectSlotForLine(resolvedLines[0], time)\">{{time ? time?.value : 'N/A'}}</div>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Multi-line case: each line gets its own full-width card with a staff header -->\n <div class=\"d-flex gap-4 main_container flex-wrap\" *ngIf=\"resolvedLines.length > 1\">\n <div class=\"w-100\" *ngFor=\"let line of resolvedLines\">\n <div class=\"section-card card rounded-3 p-4\">\n <h3 class=\"section-title\">Professional: {{line.staffName || line.selectedStaffName}}</h3>\n <p class=\"mb-2\" *ngIf=\"line.services.length\"><span *ngFor=\"let s of line.services; let last = last\">{{s.name}}{{last ? '' : ', '}}</span></p>\n <div class=\"row g-2 mb-2 overflow-scroll\">\n <ng-container *ngIf=\"!line.slotsLoading\">\n <div class=\"col-4\" *ngFor=\"let time of line.slots\">\n <div class=\"time-slot rounded-2\" [class.selected]=\"time.selected\"\n (click)=\"selectSlotForLine(line, time)\">{{time ? time?.value : 'N/A'}}</div>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #contactDetails>\n <div class=\"w-60 contact_section\">\n <div class=\"contact-header mb-2\">\n <h1>Contact Details</h1>\n <p class=\"contact-subtitle mb-0\">Provide your contact information</p>\n </div>\n\n <div class=\"d-flex gap-3 details_container flex-column w-100\">\n <div class=\"d-flex gap-4\">\n <div [ngClass]=\"{'w-50' : selectedMode === 'HOME_VISIT', 'w-100' : selectedMode !== 'HOME_VISIT'}\">\n <div class=\"form-section card rounded-3 p-4 h-100\">\n <h3 class=\"section-title\">Personal Information</h3>\n\n <div class=\"mb-4\">\n <label class=\"form-label d-flex align-items-center\">\n Full Name\n <span class=\"required-asterisk\">*</span>\n </label>\n <input type=\"text\" class=\"form-control form-input rounded-2\"\n [(ngModel)]=\"appointmentPayload.customerDetail.name\"\n (ngModelChange)=\"checkRequiredValues()\" simpoLettersOnly>\n </div>\n\n <div class=\"mb-4\">\n <label class=\"form-label d-flex align-items-center\">\n Email Address\n <span class=\"required-asterisk\">*</span>\n </label>\n <input type=\"email\" class=\"form-control form-input rounded-2\"\n [(ngModel)]=\"appointmentPayload.customerDetail.email\"\n (ngModelChange)=\"checkRequiredValues()\"\n pattern=\"^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,4}$\" #emailField=\"ngModel\"\n name=\"email\" required>\n </div>\n\n <div class=\"mb-0\">\n <label class=\"form-label d-flex align-items-center\">\n Phone Number\n <span class=\"required-asterisk\">*</span>\n </label>\n <input type=\"tel\" class=\"form-control rounded-2\"\n [(ngModel)]=\"appointmentPayload.customerDetail.phoneNumber\"\n (ngModelChange)=\"checkRequiredValues()\" simpoNumbersOnly\n [ngClass]=\"{'mobile_number' : appointmentPayload.customerDetail.phoneNumber.length != 10}\">\n </div>\n </div>\n </div>\n <!-- Home Visit address. Customer context: same saved-address flow as\n checkout/BookAppointmentComponent. Admin context (isAdminBooking): no\n logged-in customer account to read a saved address book from, so staff type\n the address manually instead. -->\n <div class=\"w-50\" *ngIf=\"selectedMode === 'HOME_VISIT'\">\n <div class=\"form-section card rounded-3 p-4 h-100\">\n <h3 class=\"section-title\">Home Visit Details</h3>\n\n <ng-container *ngIf=\"!isAdminBooking; else manualHomeVisitAddress\">\n <div class=\"shipping-info\" *ngIf=\"defaultAddress\">\n <div class=\"address-info\">\n <div class=\"address-name\">{{defaultAddress?.receiverName}} ({{defaultAddress?.addressType}})</div>\n <div class=\"address-details\">{{defaultAddress?.addressLine1}}, {{defaultAddress?.cityName}},\n {{defaultAddress?.stateName}}</div>\n <div class=\"mobile-number\">Mobile: {{defaultAddress?.receiverPhone}}</div>\n </div>\n </div>\n <button type=\"button\" class=\"change-address-btn w-100\" (click)=\"changeAddress()\" *ngIf=\"defaultAddress\">\n CHANGE OR ADD ADDRESS\n </button>\n\n <div class=\"addLinks\" *ngIf=\"!defaultAddress\" (click)=\"addAddress()\">\n <mat-icon>add</mat-icon>\n <span class=\"ms-2\">Add an address</span>\n </div>\n </ng-container>\n\n <ng-template #manualHomeVisitAddress>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Receiver Name</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.receiverName\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Receiver Phone</label>\n <input type=\"tel\" class=\"form-control form-input rounded-2\" simpoNumbersOnly [(ngModel)]=\"homeVisitAddress.receiverPhone\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Address Line 1</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.addressLine1\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Address Line 2 (optional)</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.addressLine2\">\n </div>\n <div class=\"d-flex gap-2 mb-3\">\n <div class=\"w-50\">\n <label class=\"form-label d-flex align-items-center\">City</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.city\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"w-50\">\n <label class=\"form-label d-flex align-items-center\">State</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.state\">\n </div>\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Pincode</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" simpoNumbersOnly [(ngModel)]=\"homeVisitAddress.zipCode\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n </ng-template>\n\n <div class=\"mb-0 mt-3\">\n <label class=\"form-label d-flex align-items-center\">Special Instructions</label>\n <textarea class=\"form-control form-textarea rounded-2\"\n placeholder=\"Any special instructions for the professional (optional)\"\n [(ngModel)]=\"instructions\"></textarea>\n </div>\n </div>\n </div>\n </div>\n <div class=\"policies-container\"\n *ngIf=\"cartServices[0]?.cancellationPolicy?.length > 0 || cartServices[0]?.reschedulePolicy?.length\">\n <h2 class=\"policies-title\">Policies & Terms</h2>\n\n <div class=\"policy-items-container d-flex flex-column gap-3\">\n <div class=\"policy-item d-flex justify-content-between align-items-center\"\n (click)=\"showCancellationPolicy = !showCancellationPolicy\">\n <h3 class=\"policy-title\">Cancellation Policy</h3>\n <div class=\"policy-arrow d-flex align-items-center justify-content-center\"><mat-icon\n *ngIf=\"!showCancellationPolicy\">keyboard_arrow_right</mat-icon>\n <mat-icon *ngIf=\"showCancellationPolicy\">keyboard_arrow_down</mat-icon>\n </div>\n </div>\n <div class=\"cancellation_policies d-flex flex-column gap-2 fw-500\"\n *ngIf=\"showCancellationPolicy\">\n <span *ngFor=\"let policy of cartServices[0]?.cancellationPolicy\">•\n {{policy}}</span>\n </div>\n\n <div class=\"policy-item d-flex justify-content-between align-items-center\"\n (click)=\"showReducingPolicy = !showReducingPolicy\">\n <h3 class=\"policy-title\">Rescheduling Policy</h3>\n <div class=\"policy-arrow d-flex align-items-center justify-content-center\"><mat-icon\n *ngIf=\"!showReducingPolicy\">keyboard_arrow_right</mat-icon>\n <mat-icon *ngIf=\"showReducingPolicy\">keyboard_arrow_down</mat-icon>\n </div>\n </div>\n <div class=\"cancellation_policies d-flex flex-column gap-2 fw-500\"\n *ngIf=\"showReducingPolicy\">\n <span *ngFor=\"let policy of cartServices[0]?.reschedulePolicy\">• {{policy}}</span>\n </div>\n </div>\n\n <div class=\"acceptance-section\">\n <input type=\"checkbox\" class=\"custom-checkbox\" [(ngModel)]=\"termsAndConditions\"\n (ngModelChange)=\"checkRequiredValues()\">\n <p class=\"acceptance-text\" style=\"margin-bottom:0px !important\">\n I understand and accept the cancellation & rescheduling policies.\n </p>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #paymentTab>\n <div class=\"w-60 payment_section\">\n <div class=\"w-100 h-100\">\n <div class=\"w-100 d-flex justify-content-center align-items-center flex-column\">\n <div class=\"payment-header mb-3 w-100\">\n <h1 style=\"font-size:24px;font-weight: 600;\">Booking Summary</h1>\n <p class=\"payment-subtitle mb-0\">Review your booking before confirming</p>\n </div>\n\n <div class=\"booking-summary-card\" [ngClass]=\"{'w-100' : screenWidth < 475,'w-50':screenWidth > 475}\">\n <div *ngFor=\"let line of resolvedLines; let i = index\">\n <h2 class=\"summary-title\" *ngIf=\"resolvedLines.length > 1\">Line {{i + 1}}</h2>\n <div class=\"summary-row\" *ngIf=\"line.services.length\">\n <div class=\"summary-label\">Service(s)</div>\n <div class=\"summary-value\"><span *ngFor=\"let s of line.services; let last = last\">{{s.name}}{{last ? '' : ', '}}</span></div>\n </div>\n <div class=\"summary-row\" *ngIf=\"line.staffName || line.selectedStaffName\">\n <div class=\"summary-label\">Professional</div>\n <div class=\"summary-value\">{{line.staffName || line.selectedStaffName}}</div>\n </div>\n <div class=\"summary-row\" *ngIf=\"selectedMode === 'STORE_VISIT'\">\n <div class=\"summary-label\">Location</div>\n <div class=\"summary-value\">{{selectedLocation?.storeName ?? 'N/A'}}</div>\n </div>\n <div class=\"summary-row\">\n <div class=\"summary-label\">Date & Time</div>\n <div class=\"summary-value\">{{selectedDateStr}} at {{line.selectedSlot?.value ?? 'N/A'}}</div>\n </div>\n </div>\n\n <div *ngIf=\"productCartItems.length > 0\">\n <h2 class=\"summary-title\">Products</h2>\n <div class=\"summary-row\" *ngFor=\"let p of productCartItems\">\n <div class=\"summary-label\">{{p.itemName}} x{{p.quantity}}</div>\n <div class=\"summary-value\"><span class=\"currency-symbol\">\u20B9</span>{{(p.sellingPrice ?? p.price ?? 0) * (p.quantity ?? 1)}}</div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #statusTemplate>\n <div class=\"booking-confirmation\">\n <div class=\"success-icon\">\n <div class=\"checkmark-circle\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/881293c1758695578518success.gif\"\n class=\"w-100 h-100\" *ngIf=\"apiStatus\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/325000c1758695564518fail.gif\"\n class=\"w-100 h-100\" *ngIf=\"!apiStatus\">\n </div>\n </div>\n\n <div class=\"confirmation-content\">\n <h1 class=\"confirmation-title\">{{apiStatus ? 'Booking Confirmed!' : 'Booking Failed'}}</h1>\n <p class=\"confirmation-message\">\n {{apiStatus ? 'Your appointment has been successfully booked.':'Failed to book you appointment. Please\n try again later'}}\n </p>\n\n <!-- Video Call link, when already present on the confirmed group (a paid Video Call's\n link only appears once payment verification completes, handled elsewhere - see\n verify-payment.component.ts, not this screen). -->\n <div class=\"video-call-link-card d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus && selectedMode === 'VIDEO_CALL' && bookingGroup?.videoCallLink\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Your Video Call Link</h3>\n <a [href]=\"bookingGroup.videoCallLink\" target=\"_blank\">{{bookingGroup.videoCallLink}}</a>\n </div>\n </div>\n\n <div class=\"d-flex w-100 align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Appointment Details</h3>\n <div class=\"details-row\" *ngFor=\"let line of resolvedLines\">\n <span class=\"detail-label\">{{line.services.length ? (line.services[0].name) : 'Products'}}</span>\n <span class=\"detail-value\">{{selectedDateStr}} at {{line.selectedSlot?.value ?? 'N/A'}}</span>\n </div>\n </div>\n </div>\n\n <div class=\"done-actions d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <ng-container *ngIf=\"!isAdminContext; else adminDoneActions\">\n <button type=\"button\" class=\"done-btn done-btn-primary\" (click)=\"goToMyBookings()\">View my bookings</button>\n <button type=\"button\" class=\"done-btn done-btn-secondary\" (click)=\"goToListing()\">Keep shopping</button>\n </ng-container>\n <ng-template #adminDoneActions>\n <button type=\"button\" class=\"done-btn done-btn-primary\" (click)=\"goToAppointmentsList()\">Back to Appointments List</button>\n <button type=\"button\" class=\"done-btn done-btn-secondary\" (click)=\"bookAnother()\">Book Another</button>\n </ng-template>\n </div>\n </div>\n </div>\n</ng-template>\n", styles: ["@import\"https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&display=swap\";mat-icon{font-family:Material Icons!important}:host{--font-sans: \"Outfit\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;--slate-50: #f8fafc;--slate-100: #f1f5f9;--slate-200: #e2e8f0;--slate-300: #cbd5e1;--slate-400: #94a3b8;--slate-500: #64748b;--slate-600: #475569;--slate-700: #334155;--slate-800: #1e293b;--slate-900: #0f172a;--color-primary: #230860;--color-secondary: #00b6ff;--color-accent-gradient: linear-gradient(135deg, #230860 0%, #00b6ff 100%);--color-success: #10b981;--color-success-bg: #ecfdf5;--color-error: #ef4444;--color-error-bg: #fef2f2;--border-radius-sm: 8px;--border-radius-md: 12px;--border-radius-lg: 16px;--border-radius-xl: 24px;--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, .05);--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, .05), 0 2px 4px -2px rgba(0, 0, 0, .05);--shadow-lg: 0 10px 15px -3px rgba(35, 8, 96, .05), 0 4px 6px -4px rgba(35, 8, 96, .05);--shadow-xl: 0 20px 25px -5px rgba(35, 8, 96, .08), 0 8px 10px -6px rgba(35, 8, 96, .08);--transition-smooth: all .3s cubic-bezier(.4, 0, .2, 1);--transition-bounce: all .4s cubic-bezier(.175, .885, .32, 1.275)}*{box-sizing:border-box;font-family:var(--font-sans)}.main_section{position:relative;height:100vh;background-color:var(--slate-50);display:flex;flex-direction:column;overflow:hidden}.main_header{padding:15px;background:#fff;border-bottom:1px solid var(--slate-100);flex-shrink:0;box-shadow:0 2px 8px #00000003}.header{display:flex;align-items:center;justify-content:space-between}.back-btn{display:flex;align-items:center;justify-content:center;gap:.5rem;padding:.6rem 1.2rem;border-radius:var(--border-radius-md);background:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-700)!important;transition:var(--transition-smooth);font-weight:500;font-size:.9rem;cursor:pointer}.back-btn mat-icon{font-size:18px!important;width:18px!important;height:18px!important;color:var(--slate-700)!important;display:flex;align-items:center;justify-content:center}.back-btn:hover{background:var(--slate-100);transform:translate(-3px);color:var(--slate-900)!important}.header-title{flex-grow:1;text-align:right}.header-title h1{font-size:1.5rem;font-weight:700;margin-bottom:.2rem;color:var(--slate-900)!important;letter-spacing:-.025em}.header-title p{color:var(--slate-500)!important;font-size:.9rem;font-weight:500;margin-bottom:0}.progress-bar{width:100%;height:6px;background-color:var(--slate-100);margin-top:3px;border-radius:10px;overflow:hidden;position:relative}.progress-fill{height:100%;background:var(--color-accent-gradient);border-radius:10px;transition:width .5s cubic-bezier(.4,0,.2,1);position:relative}.progress-fill:after{content:\"\";position:absolute;inset:0;background:linear-gradient(90deg,#fff0,#ffffff4d,#fff0);animation:shimmer 2s infinite linear}@keyframes shimmer{0%{transform:translate(-100%)}to{transform:translate(100%)}}.main_body{flex-grow:1;overflow-y:auto;padding:10px;display:flex;justify-content:center;background:var(--slate-50)}.w-60{width:100%;max-width:800px}.service_section,.location_section,.staff-listing,.date_section,.contact_section,.payment_section,.booking-confirmation{animation:slideUp .5s cubic-bezier(.16,1,.3,1) forwards}@keyframes slideUp{0%{opacity:0;transform:translateY(15px)}to{opacity:1;transform:translateY(0)}}h2{font-size:1.5rem;font-weight:700;color:var(--slate-900)!important;letter-spacing:-.02em;margin-bottom:.3rem}p.subtitle,.service-selection p,.location_section p,.staff-subtitle,.datetime-subtitle,.contact-subtitle,.payment-subtitle{color:var(--slate-500)!important;font-size:13px;margin-bottom:2rem}.services-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding-bottom:2rem}.service-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px}.service-card:hover{border-color:var(--slate-400);transform:translateY(-4px);box-shadow:var(--shadow-lg)}.service-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px;transform:translateY(-2px)}.service-card-selected:before,.location-card-selected:before{content:\"\\2713\";position:absolute;top:-10px;right:-10px;background:var(--color-accent-gradient);color:#fff!important;width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.8rem;font-weight:700;box-shadow:0 4px 8px #2308604d;animation:popIn .3s cubic-bezier(.175,.885,.32,1.275);z-index:10}@keyframes popIn{0%{transform:scale(0)}to{transform:scale(1)}}.service-header{display:flex;align-items:flex-start;gap:1rem;margin-bottom:1rem}.service-icon{width:48px;height:48px;border-radius:var(--border-radius-md);background-color:var(--slate-100);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.service-icon mat-icon{font-size:24px!important;width:24px!important;height:24px!important;color:var(--color-primary)!important}.service-card-selected .service-icon{background:var(--slate-900)}.service-card-selected .service-icon mat-icon{color:#fff!important}.service-info{flex-grow:1}.service-title{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;line-height:1.3;margin-bottom:.2rem}.service-price{font-size:1.25rem;font-weight:800;color:var(--slate-900)!important;text-align:right}.service-duration{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;text-align:right;margin-top:.1rem}.service-description{color:var(--slate-600)!important;font-size:.9rem;line-height:1.5;margin-bottom:1.25rem;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.home-visit{align-self:flex-start;display:inline-flex;align-items:center;gap:.5rem;font-size:.75rem;font-weight:600;color:var(--slate-700)!important;border:1px solid var(--slate-200);padding:.35rem .75rem;border-radius:20px;background-color:var(--slate-50);transition:var(--transition-smooth)}.home-visit img{width:14px;height:14px}.home-visit:before{content:\"\";display:inline-block;width:6px;height:6px;border-radius:50%;background-color:var(--color-success);box-shadow:0 0 #10b98166;animation:pulseGlow 1.8s infinite}@keyframes pulseGlow{0%{box-shadow:0 0 #10b981b3}70%{box-shadow:0 0 0 6px #10b98100}to{box-shadow:0 0 #10b98100}}.location-list{display:flex;flex-direction:column;gap:1.25rem;padding-bottom:2rem}.location-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm)}.location-card:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md)}.location-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px)}.location-content{display:flex;align-items:center}.location-info{display:flex;align-items:center;gap:1.25rem;width:100%}.location-icon{width:52px;height:52px;background-color:var(--slate-100);border-radius:var(--border-radius-md);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.location-icon img{width:28px;height:28px}.location-card-selected .location-icon{background:var(--slate-900)}.location-details{flex-grow:1}.location-details h3{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.3rem}.location-details p{font-size:.9rem;color:var(--slate-500)!important;font-weight:450;line-height:1.4;margin-bottom:0}.search-container{width:100%;margin-bottom:1.25rem}.search-input-wrapper{width:100%;background-color:var(--slate-100);border:1.5px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem 1rem;transition:var(--transition-smooth)}.search-input-wrapper:focus-within{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #23086014}.search-input{font-size:.95rem;font-weight:500;color:var(--slate-900)!important;background:transparent;outline:none;width:100%}.search-input::placeholder{color:var(--slate-400)}.search-icon{color:var(--slate-400)!important;font-size:20px!important;width:20px!important;height:20px!important}.clear-icon{color:var(--slate-400)!important;font-size:18px!important;width:18px!important;height:18px!important;transition:var(--transition-smooth)}.clear-icon:hover{color:var(--slate-600)!important}.staff-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:1rem;max-height:48vh;overflow-y:auto;padding-right:.5rem;padding-bottom:1rem}.staff-list::-webkit-scrollbar{width:6px}.staff-list::-webkit-scrollbar-track{background:var(--slate-50);border-radius:4px}.staff-list::-webkit-scrollbar-thumb{background:var(--slate-200);border-radius:4px}.staff-list::-webkit-scrollbar-thumb:hover{background:var(--slate-300)}.staff-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);margin-bottom:0!important}.staff-card:hover{border-color:var(--slate-300);transform:translateY(-2px);box-shadow:var(--shadow-md)}.staff-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px);margin-bottom:0!important}.staff-avatar{width:48px;height:48px;background:var(--color-accent-gradient);font-size:.95rem;font-weight:700;color:#fff!important;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;box-shadow:0 4px 10px #2308601a;letter-spacing:.5px;transition:var(--transition-smooth)}.staff-card-selected .staff-avatar{transform:scale(1.05)}.staff-name{font-size:1.05rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.2rem;letter-spacing:-.015em}.staff-specialty{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;margin-bottom:0;text-transform:uppercase;letter-spacing:.05em}.selection-indicator{display:flex;align-items:center;justify-content:center;margin-left:auto;padding-left:1rem}.checkmark-circle-mini{width:24px;height:24px;border:2px solid var(--slate-300);border-radius:50%;background-color:#fff;transition:var(--transition-bounce);color:#fff!important}.checkmark-circle-mini.selected{background:var(--color-accent-gradient);border-color:transparent;box-shadow:0 3px 8px #23086040}.checkmark-circle-mini mat-icon{font-size:14px!important;width:14px!important;height:14px!important;color:#fff!important;font-weight:800!important;display:flex;align-items:center;justify-content:center}.main_container{display:flex;gap:2rem;margin-bottom:2rem}.section-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm);height:100%}.section-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:10px!important;letter-spacing:-.01em}.date-picker-container{border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem 1rem;display:flex;align-items:center;justify-content:space-between;transition:var(--transition-smooth);background-color:var(--slate-50);cursor:pointer}.date-picker-container:hover{border-color:var(--slate-400);background-color:#fff}.date-input{font-size:.95rem;font-weight:600;color:var(--slate-800)!important;background:transparent;border:none;outline:none;cursor:pointer;width:100%}.date-picker-container mat-icon{color:var(--color-primary)!important;font-size:20px!important;width:20px!important;height:20px!important}.datepicker-popover{position:absolute;z-index:1000;margin-top:4px;border-radius:var(--border-radius-lg);overflow:hidden;box-shadow:var(--shadow-xl);background:#fff;border:1px solid var(--slate-200);width:320px}::ng-deep .datepicker-calendar{border-radius:var(--border-radius-lg)!important;width:100%!important}::ng-deep .mat-calendar-header{background:var(--color-accent-gradient)!important;color:#fff!important;padding:.5rem!important}::ng-deep .mat-calendar-content{padding:8px!important}::ng-deep .mat-calendar-controls{margin:0!important}::ng-deep .mat-calendar-period-button{color:#fff!important;font-weight:700!important;font-size:1rem!important}::ng-deep .mat-calendar-arrow{fill:#fff!important}::ng-deep .mat-calendar-previous-button,::ng-deep .mat-calendar-next-button{color:#fff!important}::ng-deep .mat-calendar-body-cell{font-size:13px!important}::ng-deep .mat-calendar-body-cell-content{font-weight:600!important;color:var(--slate-800)!important;border-radius:8px!important}::ng-deep .mat-calendar-body-selected{background:var(--color-accent-gradient)!important;color:#fff!important;box-shadow:0 4px 10px #23086033!important}::ng-deep .mat-calendar-body-today:not(.mat-calendar-body-selected){border:2px solid var(--color-primary)!important;color:var(--color-primary)!important}.time_selection{max-height:420px;display:flex;flex-direction:column}.time_selection .row{flex-grow:1;overflow-y:auto;padding-right:.25rem;margin-top:10px}.time-slot{background:#fff;border:1px solid var(--slate-200);font-size:.9rem;font-weight:600;color:var(--slate-800)!important;padding:.75rem .5rem;border-radius:var(--border-radius-md);cursor:pointer;transition:var(--transition-smooth);text-align:center;box-shadow:var(--shadow-sm)}.time-slot:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md);background-color:var(--slate-50)}.time-slot.selected{background:var(--color-accent-gradient);border-color:transparent;color:#fff!important;box-shadow:0 4px 12px #23086033}.form-section{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm)}.form-label{font-size:.85rem;font-weight:600;color:var(--slate-700)!important;margin-bottom:.5rem;text-transform:uppercase;letter-spacing:.05em}.required-asterisk{color:var(--color-error);margin-left:2px}.form-control,.form-input,.form-textarea{width:100%;background-color:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-900)!important;font-size:.95rem;font-weight:500;padding:.75rem 1rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);outline:none}.form-control:focus,.form-input:focus,.form-textarea:focus{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #2308601a}.form-textarea{min-height:100px;resize:vertical}.policies-container{background-color:#fff;border:1px solid var(--slate-200);padding:1.75rem;border-radius:var(--border-radius-lg);margin-top:1.5rem;box-shadow:var(--shadow-sm)}.policies-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1.25rem}.policy-item{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1rem 1.25rem;cursor:pointer;transition:var(--transition-smooth);display:flex;justify-content:space-between;align-items:center}.policy-item:hover{background-color:var(--slate-100);border-color:var(--slate-300)}.policy-title{font-size:.95rem;font-weight:600;color:var(--slate-800)!important}.policy-arrow mat-icon{color:var(--slate-500)!important;transition:var(--transition-smooth)}.cancellation_policies{background-color:var(--slate-50);padding:1rem 1.5rem;border-left:3px solid var(--color-primary);border-radius:0 0 var(--border-radius-md) var(--border-radius-md);margin-top:-4px;margin-bottom:1rem;font-size:.9rem;color:var(--slate-600)!important;line-height:1.5}.acceptance-section{display:flex;align-items:center;gap:.75rem;margin-top:1.5rem}.custom-checkbox{width:20px;height:20px;border:2px solid var(--slate-300);border-radius:6px;cursor:pointer;transition:var(--transition-smooth);position:relative;appearance:none;background-color:#fff;outline:none}.custom-checkbox:checked{background:var(--color-accent-gradient);border-color:transparent}.custom-checkbox:checked:after{content:\"\\2713\";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#fff!important;font-size:.75rem;font-weight:800}.acceptance-text{font-size:.95rem;color:var(--slate-700)!important;font-weight:500;-webkit-user-select:none;user-select:none;line-height:1.4}.booking-summary-card{background-color:#fff;border:1px solid var(--slate-200);padding:2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);position:relative}.booking-summary-card:after{content:\"\";position:absolute;bottom:-1px;left:0;right:0;height:10px;background-image:radial-gradient(circle,white 4px,transparent 5px);background-size:12px 12px;background-position:0 0;z-index:2}.summary-title{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important;border-bottom:2px dashed var(--slate-200);padding-bottom:1rem;margin-bottom:1.5rem;text-align:center}.summary-row{display:flex;justify-content:space-between;align-items:center;padding:.85rem 0;border-bottom:1px solid var(--slate-100)}.summary-label{font-size:.95rem;color:var(--slate-500)!important;font-weight:500}.summary-value{font-size:.95rem;color:var(--slate-900)!important;font-weight:600;text-align:right}.total-row{margin-top:1rem;padding-top:1.25rem;border-top:2px dashed var(--slate-200);border-bottom:none}.total-row .summary-label{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important}.total-row .summary-value{font-size:1.5rem;font-weight:800;color:var(--color-primary)!important}.booking-confirmation{background:#fff;border:1px solid var(--slate-200);padding:3rem 2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);display:flex;flex-direction:column;align-items:center;text-align:center;max-width:500px;margin:0 auto}.success-icon{margin-bottom:1.5rem}.checkmark-circle{width:96px;height:96px;display:flex;align-items:center;justify-content:center}.confirmation-title{font-size:1.5rem;font-weight:800;color:var(--slate-900)!important;margin-bottom:.5rem}.confirmation-message{font-size:1rem;color:var(--slate-500)!important;line-height:1.6;margin-bottom:2rem;font-weight:450}.details-card{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1.5rem;width:100%;margin-bottom:2rem;text-align:left}.details-title{font-size:1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1rem;text-transform:uppercase;letter-spacing:.05em}.details-row{display:flex;justify-content:space-between;padding:.5rem 0;border-bottom:1px dashed var(--slate-200)}.details-row:last-child{border-bottom:none}.detail-label{font-size:.85rem;color:var(--slate-500)!important;font-weight:500}.detail-value{font-size:.9rem;color:var(--slate-900)!important;font-weight:600}.main_footer{border-top:1px solid var(--slate-200);background-color:#fff;padding:15px;flex-shrink:0;display:flex;justify-content:center;box-shadow:0 -4px 12px #00000005}.footer-buttons{width:100%;max-width:800px;display:flex;align-items:center}.back-footer-btn{font-size:.95rem;font-weight:600;color:var(--slate-600)!important;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);cursor:pointer}.back-footer-btn:hover{color:var(--slate-900)!important;background-color:var(--slate-100)}.continue-btn{background:var(--color-accent-gradient);color:#fff!important;border:none;padding:.75rem 2rem;border-radius:var(--border-radius-md);font-size:.95rem!important;font-weight:600;cursor:pointer;transition:var(--transition-smooth);box-shadow:0 4px 10px #23086033;width:max-content!important}.continue-btn:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.continue-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed!important;box-shadow:none!important}.complete_booking,.pay-now-btn{background:var(--color-accent-gradient)!important;color:#fff!important;border:none;padding:.75rem 2.25rem!important;font-size:.95rem!important;font-weight:600;border-radius:var(--border-radius-md)!important;box-shadow:0 4px 12px #23086040;transition:var(--transition-smooth);cursor:pointer;display:flex;align-items:center;gap:.5rem;width:max-content!important}.complete_booking img,.pay-now-btn img{width:20px;height:20px;filter:brightness(0) invert(1)}.complete_booking:hover:not([disabled]),.pay-now-btn:hover:not([disabled]){transform:translateY(-2px);box-shadow:0 6px 18px #23086059}.complete_booking:disabled,.pay-now-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed;box-shadow:none}.service-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding:0;width:100%}.skeleton-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;height:180px;display:flex;flex-direction:column;justify-content:space-between}.skeleton{background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border-radius:4px}@keyframes loading-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}.skeleton-icon{width:48px;height:48px;border-radius:var(--border-radius-md)}.skeleton-title{height:20px;width:60%;margin-bottom:.5rem}.skeleton-price{height:20px;width:30%}.skeleton-duration{height:12px;width:25%;margin-top:.25rem}.skeleton-description{height:14px;width:85%}.skeleton-badge{height:28px;width:120px;border-radius:20px}.time-slot-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:.75rem;width:100%}.skeleton-time-slot{height:42px;border-radius:var(--border-radius-md);background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border:1px solid var(--slate-100)}@media screen and (max-width: 475px){.main_header{padding:1rem}.header-title h1{font-size:1.25rem}.back-btn{padding:.5rem .8rem}.back-btn span{display:none}.main_body{padding:15px}.services-grid{grid-template-columns:1fr;gap:1rem}.staff-list{grid-template-columns:1fr!important;gap:.85rem!important}.service-card,.service-card-selected{min-height:auto}.main_container{flex-direction:column;gap:1.5rem}.datepicker-popover{width:100%;left:0}.details_container{gap:1.5rem}.details_container>.d-flex{flex-direction:column;gap:1.5rem}.details_container>.d-flex>div{width:100%!important}.booking-summary-card{padding:1.25rem}.summary-title{font-size:1.15rem}.total-row .summary-label{font-size:1.1rem}.total-row .summary-value{font-size:1.3rem}.main_footer{padding:1rem}.continue-btn{padding:.75rem 1.5rem}}.shipping-info{border-radius:10px;padding:20px;margin-bottom:12px;border:1px solid var(--slate-200);box-shadow:var(--shadow-sm)}.address-info{margin-bottom:0}.address-name{font-weight:700;margin-bottom:8px;color:var(--slate-900)!important}.address-details{color:var(--slate-500)!important;margin-bottom:8px}.mobile-number{font-weight:700;color:var(--slate-900)!important;font-size:15px}.change-address-btn{font-size:.85rem!important;font-weight:700!important;padding:10px;background:#fff;border:1px solid var(--slate-200);border-radius:8px;color:var(--slate-900)!important;cursor:pointer;transition:var(--transition-smooth)}.change-address-btn:hover{border-color:var(--color-primary);color:var(--color-primary)!important}.addLinks{padding:14px;border:1px dashed var(--slate-300);display:flex;align-items:center;justify-content:center;cursor:pointer;border-radius:8px;color:var(--slate-500)!important;margin-bottom:12px}.addLinks:hover{border-color:var(--color-primary);color:var(--color-primary)!important}h1{font-size:24px!important;font-weight:600!important}.done-actions{display:flex;gap:12px;width:100%}.done-btn{flex:1;max-width:220px;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);font-size:.95rem;font-weight:600;cursor:pointer;transition:var(--transition-smooth);border:none}.done-btn-primary{background:var(--color-accent-gradient);color:#fff!important;box-shadow:0 4px 10px #23086033}.done-btn-primary:hover{transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.done-btn-secondary{background:#fff;color:var(--slate-600)!important;border:1px solid var(--slate-200)}.done-btn-secondary:hover{background-color:var(--slate-100);color:var(--slate-900)!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "pipe", type: i3.SlicePipe, name: "slice" }, { kind: "pipe", type: i3.TitleCasePipe, name: "titlecase" }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatDatepickerModule }, { kind: "component", type: i9$2.MatCalendar, selector: "mat-calendar", inputs: ["headerComponent", "startAt", "startView", "selected", "minDate", "maxDate", "dateFilter", "dateClass", "comparisonStart", "comparisonEnd", "startDateAccessibleName", "endDateAccessibleName"], outputs: ["selectedChange", "yearSelected", "monthSelected", "viewChanged", "_userSelection", "_userDragDrop"], exportAs: ["matCalendar"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i9.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i9.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i9.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i9.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i9.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i9.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatNativeDateModule }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: LettersOnlyDirective, selector: "[simpoLettersOnly]" }, { kind: "directive", type: NumbersOnlyDirective, selector: "[simpoNumbersOnly]" }, { kind: "ngmodule", type: ToastModule }, { kind: "component", type: i11.Toast, selector: "p-toast", inputs: ["key", "autoZIndex", "baseZIndex", "life", "style", "styleClass", "position", "preventOpenDuplicates", "preventDuplicates", "showTransformOptions", "hideTransformOptions", "showTransitionOptions", "hideTransitionOptions", "breakpoints"], outputs: ["onClose"] }] }); }
|
|
25978
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: AppointmentBookingComponent, isStandalone: true, selector: "simpo-appointment-booking", inputs: { data: "data", index: "index", edit: "edit", isAdminBooking: "isAdminBooking", delete: "delete", customClass: "customClass", nextComponentColor: "nextComponentColor", prefillContact: "prefillContact" }, host: { listeners: { "window: resize": "getScreenSize($event)", "document:click": "closeOnOutsideClick()" } }, providers: [MessageService], usesInheritance: true, ngImport: i0, template: "<p-toast position=\"bottom-right\" [baseZIndex]=\"10000000000\" [autoZIndex]=\"true\"\n [showTransformOptions]=\"screenWidth < 475 ? 'translateY(-100%)' : ''\"></p-toast>\n<section class=\"main_section\" simpoHover (hovering)=\"showEditTabs($event)\"\n [simpoBackground]=\"backgroundInfo\" [style.--color-accent-gradient]=\"accentColor\">\n <div [ngClass]=\"{'hover_effect': edit}\" *ngIf=\"showEditors\">\n <simpo-hover-elements [data]=\"data\" [index]=\"index\" [editOptions]=\"edit\"></simpo-hover-elements>\n </div>\n <div class=\"main_header\">\n <div class=\"header d-flex justify-content-between align-items-center\">\n <div class=\"back-btn d-flex justify-content-center align-items-center cursor-pointer gap-2 mb-3\"\n (click)=\"goBack()\">\n <mat-icon>keyboard_backspace</mat-icon><span *ngIf=\"screenWidth > 475\">Back to Home</span>\n </div>\n <div class=\"header-title\">\n <h1>Book New Appointment</h1>\n <p>{{businessName ?? \"N/A\" }}</p>\n </div>\n </div>\n\n <div class=\"progress-bar\">\n <div class=\"progress-fill\" [style.width]=\"barWidth + '%'\"></div>\n </div>\n </div>\n <div class=\"main_body w-100 d-flex justify-content-center\">\n <ng-container *ngIf=\"selectedTab === 'modeSelection'\">\n <ng-container *ngTemplateOutlet=\"modeSelection\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'serviceListing'\">\n <ng-container *ngIf=\"!skeletonLoader\">\n <ng-container *ngTemplateOutlet=\"serviceListing\"></ng-container>\n </ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'locationListing'\">\n <ng-container *ngTemplateOutlet=\"locationListing\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'staffListing'\">\n <ng-container *ngTemplateOutlet=\"staffListing\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'dateSelection'\">\n <ng-container *ngTemplateOutlet=\"dateSelection\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab==='contactDetails'\">\n <ng-container *ngTemplateOutlet=\"contactDetails\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab==='paymentTab'\">\n <ng-container *ngTemplateOutlet=\"paymentTab\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab==='statusTemplate'\">\n <ng-container *ngTemplateOutlet=\"statusTemplate\"></ng-container>\n </ng-container>\n </div>\n <div class=\"main_footer d-flex justify-content-center align-items-center\"\n *ngIf=\"selectedTab!=='statusTemplate' && selectedTab!=='modeSelection'\">\n <div class=\"footer-buttons\"\n [ngStyle]=\"{'justify-content': selectedTab != 'serviceListing' ? 'space-between' : 'end'}\">\n <span class=\"back-footer-btn cursor-pointer\" (click)=\"previousStep()\"\n *ngIf=\"selectedTab != 'serviceListing'\">Back</span>\n <button class=\"continue-btn\" [disabled]=\"!activeButton\" (click)=\"nextStep()\"\n *ngIf=\"selectedTab!='paymentTab'\">{{!loader ? 'Continue' : 'Loading...'}}</button>\n <button class=\"cursor-pointer d-flex justify-content-evenly align-items-center\"\n *ngIf=\"selectedTab==='paymentTab'\" (click)=\"confirmBooking()\" [disabled]=\"isProcessing\"\n [ngClass]=\"{'pay-now-btn' : bookingGroup?.totalCollectedAtBooking > 0 || !bookingGroup,'complete_booking' : bookingGroup && !bookingGroup?.totalCollectedAtBooking}\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/304012c1753440087996Background.png\">\n {{isProcessing ? 'Please wait...' : 'Confirm Booking'}}\n </button>\n </div>\n </div>\n</section>\n\n<ng-template #modeSelection>\n <div class=\"w-60 service_section\">\n <div class=\"service-selection\">\n <h2>How would you like this?</h2>\n <p>Choose how you'd like to be served</p>\n <div class=\"services-grid\">\n <div class=\"service-card\" (click)=\"selectMode('STORE_VISIT')\">\n <div class=\"service-header\">\n <div class=\"service-icon\"><mat-icon>storefront</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">Visit our Store</div>\n </div>\n </div>\n <div class=\"service-description\">Come to us at one of our locations</div>\n </div>\n <div class=\"service-card\" (click)=\"selectMode('HOME_VISIT')\">\n <div class=\"service-header\">\n <div class=\"service-icon\"><mat-icon>home</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">We come to you</div>\n </div>\n </div>\n <div class=\"service-description\">A professional visits your address</div>\n </div>\n <div class=\"service-card\" (click)=\"selectMode('VIDEO_CALL')\">\n <div class=\"service-header\">\n <div class=\"service-icon\"><mat-icon>videocam</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">Video consultation</div>\n </div>\n </div>\n <div class=\"service-description\">Connect over a video call</div>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #serviceListing>\n <div class=\"w-60 service_section\">\n <div class=\"service-selection\">\n <h2>Select a Service</h2>\n <p>Choose the service(s) you'd like to book<span *ngIf=\"cartServices.length > 0\"> \u2014 {{cartServices.length}} selected</span></p>\n <p *ngIf=\"productCartItems.length > 0\" class=\"cart-hint\">{{productCartItems.length}} product(s) already in your cart \u2014 you can continue without picking a service.</p>\n\n <div class=\"services-grid\">\n <ng-container *ngFor=\"let service of serviceData\">\n <div class=\"\" (click)=\"selectService(service)\"\n [ngClass]=\"{ 'service-card-selected' : service?.selected, 'service-card': !service?.selected }\">\n <div class=\" service-header\">\n <div class=\"service-icon\"><mat-icon>person_outline</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">{{service?.name ? service?.name : 'N/A'}}</div>\n </div>\n <div>\n <div class=\"service-price\">\u20B9{{service?.priceDetails?.price ?\n service?.priceDetails?.price : 'N/A' }}</div>\n <div class=\"service-duration\">{{service?.duration ? service?.duration : 'N/A'}} min\n </div>\n </div>\n </div>\n <div class=\"service-description\" *ngIf=\"service?.description\">\n {{service?.description ? service?.description : 'N/A'}}\n </div>\n <div class=\"home-visit\" *ngIf=\"selectedMode === 'STORE_VISIT' && service?.homeAppointmentAvailable\"><img\n src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/982126c1758628863129furniture_16406103.png\">Home\n Visit Available</div>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #locationListing>\n <div class=\"location_section\">\n <div class=\"header flex-column align-items-start\">\n <h1>Choose Location</h1>\n <p>Select where you'd like to receive the service</p>\n </div>\n\n <div class=\"location-list\">\n <ng-container *ngFor=\"let location of locationData\">\n <div (click)=\"selectLocation(location)\"\n [ngClass]=\"{ 'location-card-selected' : location?.selected, 'location-card': !location?.selected }\">\n <div class=\"location-content\">\n <div class=\"location-info\">\n <div class=\"location-icon\"><img\n src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/427226c1758629157758store_3171510.png\">\n </div>\n <div class=\"location-details\">\n <div class=\"d-flex justify-content-between align-items-center\">\n <h3>{{location?.storeName ? location?.storeName : 'N/A'}}</h3>\n </div>\n <p>{{location?.addressDetails?.addressLine}}, {{location?.addressDetails?.city}},\n {{location?.addressDetails?.state}} {{location?.pincode}}</p>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n</ng-template>\n\n<ng-template #staffListing>\n <div class=\"w-60 overflow-hidden staff-listing\">\n <div class=\"d-flex w-100 h-100\">\n <div class=\"w-100\">\n <div class=\"staff-header mb-3\">\n <h1>Select Staff Member</h1>\n <p class=\"staff-subtitle mb-0\">Choose your preferred professional</p>\n </div>\n\n <div class=\"search-container mb-4\">\n <div class=\"search-input-wrapper d-flex align-items-center\">\n <mat-icon class=\"search-icon me-2\">search</mat-icon>\n <input type=\"text\" class=\"search-input border-0 flex-grow-1\" placeholder=\"Search staff member by name...\" [(ngModel)]=\"staffSearchQuery\">\n <mat-icon class=\"clear-icon cursor-pointer ms-2\" *ngIf=\"staffSearchQuery\" (click)=\"staffSearchQuery = ''\">close</mat-icon>\n </div>\n </div>\n\n <!-- Pure product-only line: one flat staff list, same as the old single-service flow -->\n <div class=\"staff-list\" *ngIf=\"cartServices.length === 0\">\n <ng-container *ngFor=\"let staff of filteredStaff\">\n <div class=\"card rounded-3 p-3\" (click)=\"selectStaffForProductOnlyLine(staff)\"\n [ngClass]=\"{ 'staff-card-selected' : staff?.selected, 'staff-card': !staff?.selected }\">\n <div class=\"d-flex align-items-center justify-content-between w-100\">\n <div class=\"d-flex align-items-center flex-grow-1\">\n <div class=\"staff-avatar rounded-circle d-flex align-items-center justify-content-center me-4\">\n {{staff?.staffName.slice(0,2).toUpperCase()}}\n </div>\n <div class=\"staff-details flex-grow-1\">\n <h3 class=\"staff-name\">{{(staff?.staffName ? staff?.staffName : 'N/A') | titlecase}}</h3>\n <p class=\"staff-specialty\">{{(businessName && businessName !== 'N/A') ? businessName : 'Booking Specialist'}}</p>\n </div>\n </div>\n <div class=\"selection-indicator\">\n <div class=\"checkmark-circle-mini d-flex align-items-center justify-content-center\" [class.selected]=\"staff?.selected\">\n <mat-icon *ngIf=\"staff?.selected\">check</mat-icon>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n\n <!-- Bundled cart: one pool per line that resolution couldn't collapse to a single provider -->\n <ng-container *ngIf=\"cartServices.length > 0\">\n <div class=\"staff-line-group mb-4\" *ngFor=\"let line of resolvedLines\">\n <ng-container *ngIf=\"line.candidateStaffPool?.length\">\n <h4 class=\"mb-2\">For {{line.services.length}} service(s): {{ (line.services | slice:0:3).length ? '' : '' }}<span *ngFor=\"let s of line.services; let last = last\">{{s.name}}{{last ? '' : ', '}}</span></h4>\n <div class=\"staff-list mb-3\">\n <ng-container *ngFor=\"let staff of line.candidateStaffPool\">\n <div class=\"card rounded-3 p-3\" (click)=\"selectStaffForLine(line, staff)\"\n [ngClass]=\"{ 'staff-card-selected' : line.selectedStaffId === staff.id, 'staff-card': line.selectedStaffId !== staff.id }\">\n <div class=\"d-flex align-items-center justify-content-between w-100\">\n <div class=\"d-flex align-items-center flex-grow-1\">\n <div class=\"staff-avatar rounded-circle d-flex align-items-center justify-content-center me-4\">\n {{staff?.name?.slice(0,2)?.toUpperCase()}}\n </div>\n <div class=\"staff-details flex-grow-1\">\n <h3 class=\"staff-name\">{{(staff?.name ? staff?.name : 'N/A') | titlecase}}</h3>\n </div>\n </div>\n <div class=\"selection-indicator\">\n <div class=\"checkmark-circle-mini d-flex align-items-center justify-content-center\" [class.selected]=\"line.selectedStaffId === staff.id\">\n <mat-icon *ngIf=\"line.selectedStaffId === staff.id\">check</mat-icon>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n </ng-container>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #dateSelection>\n <div class=\"w-60 date_section\">\n <div class=\"row justify-content-center h-100\">\n <div class=\"col-12 h-100\">\n <div class=\"datetime-header mb-2\">\n <h1>Select Date & Time</h1>\n <p class=\"datetime-subtitle mb-0\">Choose when you'd like your appointment</p>\n </div>\n\n <div class=\"d-flex gap-4 main_container\">\n <div [ngClass]=\"{'w-50' : screenWidth > 475 , 'w-100':screenWidth < 475}\">\n <div class=\"section-card card rounded-3 p-4 h-100\">\n <h3 class=\"section-title\">Select Date</h3>\n\n <div class=\"date-picker-container d-flex align-items-center justify-content-between\"\n (click)=\"$event.stopPropagation()\">\n <input type=\"text\" class=\"date-input border-0 rounded-2\" placeholder=\"dd-mm-yyyy\"\n [value]=\"selectedDateStr\" readonly (click)=\"toggleCalendar($event)\">\n\n <mat-icon class=\"ms-2\" (click)=\"toggleCalendar($event)\">calendar_today</mat-icon>\n </div>\n <div class=\"position-relative\" (click)=\"$event.stopPropagation()\">\n <div class=\"datepicker-popover\" *ngIf=\"showCalendar\">\n <mat-calendar [(selected)]=\"selectedDate\" [dateFilter]=\"dateFilter\"\n (selectedChange)=\"onDateSelected($event)\" class=\"datepicker-calendar\">\n </mat-calendar>\n </div>\n </div>\n </div>\n </div>\n\n <!-- One slot-picker per resolved line, side by side when there's more than one (design doc \u00A73b) -->\n <div class=\"time_selection\" [ngClass]=\"{'w-50' : screenWidth > 475 , 'w-100':screenWidth < 475}\" *ngIf=\"resolvedLines.length <= 1\">\n <div class=\"section-card card h-100 rounded-3 p-4\">\n <h3 class=\"section-title\">Available Times</h3>\n <div class=\"row g-2 mb-4 overflow-scroll\">\n <ng-container *ngIf=\"!skeletonLoader && resolvedLines[0]\">\n <div class=\"col-4\" *ngFor=\"let time of resolvedLines[0].slots\">\n <div class=\"time-slot rounded-2\" [class.selected]=\"time.selected\"\n (click)=\"selectSlotForLine(resolvedLines[0], time)\">{{time ? time?.value : 'N/A'}}</div>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Multi-line case: each line gets its own full-width card with a staff header -->\n <div class=\"d-flex gap-4 main_container flex-wrap\" *ngIf=\"resolvedLines.length > 1\">\n <div class=\"w-100\" *ngFor=\"let line of resolvedLines\">\n <div class=\"section-card card rounded-3 p-4\">\n <h3 class=\"section-title\">Professional: {{line.staffName || line.selectedStaffName}}</h3>\n <p class=\"mb-2\" *ngIf=\"line.services.length\"><span *ngFor=\"let s of line.services; let last = last\">{{s.name}}{{last ? '' : ', '}}</span></p>\n <div class=\"row g-2 mb-2 overflow-scroll\">\n <ng-container *ngIf=\"!line.slotsLoading\">\n <div class=\"col-4\" *ngFor=\"let time of line.slots\">\n <div class=\"time-slot rounded-2\" [class.selected]=\"time.selected\"\n (click)=\"selectSlotForLine(line, time)\">{{time ? time?.value : 'N/A'}}</div>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #contactDetails>\n <div class=\"w-60 contact_section\">\n <div class=\"contact-header mb-2\">\n <h1>Contact Details</h1>\n <p class=\"contact-subtitle mb-0\">Provide your contact information</p>\n </div>\n\n <div class=\"d-flex gap-3 details_container flex-column w-100\">\n <div class=\"d-flex gap-4\">\n <div [ngClass]=\"{'w-50' : selectedMode === 'HOME_VISIT', 'w-100' : selectedMode !== 'HOME_VISIT'}\">\n <div class=\"form-section card rounded-3 p-4 h-100\">\n <h3 class=\"section-title\">Personal Information</h3>\n\n <div class=\"mb-4\">\n <label class=\"form-label d-flex align-items-center\">\n Full Name\n <span class=\"required-asterisk\">*</span>\n </label>\n <input type=\"text\" class=\"form-control form-input rounded-2\"\n [(ngModel)]=\"appointmentPayload.customerDetail.name\"\n (ngModelChange)=\"checkRequiredValues()\" simpoLettersOnly>\n </div>\n\n <div class=\"mb-4\">\n <label class=\"form-label d-flex align-items-center\">\n Email Address\n <span class=\"required-asterisk\">*</span>\n </label>\n <input type=\"email\" class=\"form-control form-input rounded-2\"\n [(ngModel)]=\"appointmentPayload.customerDetail.email\"\n (ngModelChange)=\"checkRequiredValues()\"\n pattern=\"^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,4}$\" #emailField=\"ngModel\"\n name=\"email\" required>\n </div>\n\n <div class=\"mb-0\">\n <label class=\"form-label d-flex align-items-center\">\n Phone Number\n <span class=\"required-asterisk\">*</span>\n </label>\n <input type=\"tel\" class=\"form-control rounded-2\"\n [(ngModel)]=\"appointmentPayload.customerDetail.phoneNumber\"\n (ngModelChange)=\"checkRequiredValues()\" simpoNumbersOnly\n [ngClass]=\"{'mobile_number' : appointmentPayload.customerDetail.phoneNumber.length != 10}\">\n </div>\n </div>\n </div>\n <!-- Home Visit address. Customer context: same saved-address flow as\n checkout/BookAppointmentComponent. Admin context (isAdminBooking): no\n logged-in customer account to read a saved address book from, so staff type\n the address manually instead. -->\n <div class=\"w-50\" *ngIf=\"selectedMode === 'HOME_VISIT'\">\n <div class=\"form-section card rounded-3 p-4 h-100\">\n <h3 class=\"section-title\">Home Visit Details</h3>\n\n <ng-container *ngIf=\"!isAdminBooking; else manualHomeVisitAddress\">\n <div class=\"shipping-info\" *ngIf=\"defaultAddress\">\n <div class=\"address-info\">\n <div class=\"address-name\">{{defaultAddress?.receiverName}} ({{defaultAddress?.addressType}})</div>\n <div class=\"address-details\">{{defaultAddress?.addressLine1}}, {{defaultAddress?.cityName}},\n {{defaultAddress?.stateName}}</div>\n <div class=\"mobile-number\">Mobile: {{defaultAddress?.receiverPhone}}</div>\n </div>\n </div>\n <button type=\"button\" class=\"change-address-btn w-100\" (click)=\"changeAddress()\" *ngIf=\"defaultAddress\">\n CHANGE OR ADD ADDRESS\n </button>\n\n <div class=\"addLinks\" *ngIf=\"!defaultAddress\" (click)=\"addAddress()\">\n <mat-icon>add</mat-icon>\n <span class=\"ms-2\">Add an address</span>\n </div>\n </ng-container>\n\n <ng-template #manualHomeVisitAddress>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Receiver Name</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.receiverName\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Receiver Phone</label>\n <input type=\"tel\" class=\"form-control form-input rounded-2\" simpoNumbersOnly [(ngModel)]=\"homeVisitAddress.receiverPhone\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Address Line 1</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.addressLine1\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Address Line 2 (optional)</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.addressLine2\">\n </div>\n <div class=\"d-flex gap-2 mb-3\">\n <div class=\"w-50\">\n <label class=\"form-label d-flex align-items-center\">City</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.city\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"w-50\">\n <label class=\"form-label d-flex align-items-center\">State</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.state\">\n </div>\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Pincode</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" simpoNumbersOnly [(ngModel)]=\"homeVisitAddress.zipCode\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n </ng-template>\n\n <div class=\"mb-0 mt-3\">\n <label class=\"form-label d-flex align-items-center\">Special Instructions</label>\n <textarea class=\"form-control form-textarea rounded-2\"\n placeholder=\"Any special instructions for the professional (optional)\"\n [(ngModel)]=\"instructions\"></textarea>\n </div>\n </div>\n </div>\n </div>\n <div class=\"policies-container\"\n *ngIf=\"cartServices[0]?.cancellationPolicy?.length > 0 || cartServices[0]?.reschedulePolicy?.length\">\n <h2 class=\"policies-title\">Policies & Terms</h2>\n\n <div class=\"policy-items-container d-flex flex-column gap-3\">\n <div class=\"policy-item d-flex justify-content-between align-items-center\"\n (click)=\"showCancellationPolicy = !showCancellationPolicy\">\n <h3 class=\"policy-title\">Cancellation Policy</h3>\n <div class=\"policy-arrow d-flex align-items-center justify-content-center\"><mat-icon\n *ngIf=\"!showCancellationPolicy\">keyboard_arrow_right</mat-icon>\n <mat-icon *ngIf=\"showCancellationPolicy\">keyboard_arrow_down</mat-icon>\n </div>\n </div>\n <div class=\"cancellation_policies d-flex flex-column gap-2 fw-500\"\n *ngIf=\"showCancellationPolicy\">\n <span *ngFor=\"let policy of cartServices[0]?.cancellationPolicy\">•\n {{policy}}</span>\n </div>\n\n <div class=\"policy-item d-flex justify-content-between align-items-center\"\n (click)=\"showReducingPolicy = !showReducingPolicy\">\n <h3 class=\"policy-title\">Rescheduling Policy</h3>\n <div class=\"policy-arrow d-flex align-items-center justify-content-center\"><mat-icon\n *ngIf=\"!showReducingPolicy\">keyboard_arrow_right</mat-icon>\n <mat-icon *ngIf=\"showReducingPolicy\">keyboard_arrow_down</mat-icon>\n </div>\n </div>\n <div class=\"cancellation_policies d-flex flex-column gap-2 fw-500\"\n *ngIf=\"showReducingPolicy\">\n <span *ngFor=\"let policy of cartServices[0]?.reschedulePolicy\">• {{policy}}</span>\n </div>\n </div>\n\n <div class=\"acceptance-section\">\n <input type=\"checkbox\" class=\"custom-checkbox\" [(ngModel)]=\"termsAndConditions\"\n (ngModelChange)=\"checkRequiredValues()\">\n <p class=\"acceptance-text\" style=\"margin-bottom:0px !important\">\n I understand and accept the cancellation & rescheduling policies.\n </p>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #paymentTab>\n <div class=\"w-60 payment_section\">\n <div class=\"w-100 h-100\">\n <div class=\"w-100 d-flex justify-content-center align-items-center flex-column\">\n <div class=\"payment-header mb-3 w-100\">\n <h1 style=\"font-size:24px;font-weight: 600;\">Booking Summary</h1>\n <p class=\"payment-subtitle mb-0\">Review your booking before confirming</p>\n </div>\n\n <div class=\"booking-summary-card\" [ngClass]=\"{'w-100' : screenWidth < 475,'w-50':screenWidth > 475}\">\n <div *ngFor=\"let line of resolvedLines; let i = index\">\n <h2 class=\"summary-title\" *ngIf=\"resolvedLines.length > 1\">Line {{i + 1}}</h2>\n <div class=\"summary-row\" *ngIf=\"line.services.length\">\n <div class=\"summary-label\">Service(s)</div>\n <div class=\"summary-value\"><span *ngFor=\"let s of line.services; let last = last\">{{s.name}}{{last ? '' : ', '}}</span></div>\n </div>\n <div class=\"summary-row\" *ngIf=\"line.staffName || line.selectedStaffName\">\n <div class=\"summary-label\">Professional</div>\n <div class=\"summary-value\">{{line.staffName || line.selectedStaffName}}</div>\n </div>\n <div class=\"summary-row\" *ngIf=\"selectedMode === 'STORE_VISIT'\">\n <div class=\"summary-label\">Location</div>\n <div class=\"summary-value\">{{selectedLocation?.storeName ?? 'N/A'}}</div>\n </div>\n <div class=\"summary-row\">\n <div class=\"summary-label\">Date & Time</div>\n <div class=\"summary-value\">{{selectedDateStr}} at {{line.selectedSlot?.value ?? 'N/A'}}</div>\n </div>\n </div>\n\n <div *ngIf=\"productCartItems.length > 0\">\n <h2 class=\"summary-title\">Products</h2>\n <div class=\"summary-row\" *ngFor=\"let p of productCartItems\">\n <div class=\"summary-label\">{{p.itemName}} x{{p.quantity}}</div>\n <div class=\"summary-value\"><span class=\"currency-symbol\">\u20B9</span>{{(p.sellingPrice ?? p.price ?? 0) * (p.quantity ?? 1)}}</div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #statusTemplate>\n <div class=\"booking-confirmation\">\n <div class=\"success-icon\">\n <div class=\"checkmark-circle\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/881293c1758695578518success.gif\"\n class=\"w-100 h-100\" *ngIf=\"apiStatus\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/325000c1758695564518fail.gif\"\n class=\"w-100 h-100\" *ngIf=\"!apiStatus\">\n </div>\n </div>\n\n <div class=\"confirmation-content\">\n <h1 class=\"confirmation-title\">{{apiStatus ? 'Booking Confirmed!' : 'Booking Failed'}}</h1>\n <p class=\"confirmation-message\">\n {{apiStatus ? 'Your appointment has been successfully booked.':'Failed to book you appointment. Please\n try again later'}}\n </p>\n\n <!-- Video Call link, when already present on the confirmed group (a paid Video Call's\n link only appears once payment verification completes, handled elsewhere - see\n verify-payment.component.ts, not this screen). -->\n <div class=\"video-call-link-card d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus && selectedMode === 'VIDEO_CALL' && bookingGroup?.videoCallLink\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Your Video Call Link</h3>\n <a [href]=\"bookingGroup.videoCallLink\" target=\"_blank\">{{bookingGroup.videoCallLink}}</a>\n </div>\n </div>\n\n <div class=\"d-flex w-100 align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Appointment Details</h3>\n <div class=\"details-row\" *ngFor=\"let line of resolvedLines\">\n <span class=\"detail-label\">{{line.services.length ? (line.services[0].name) : 'Products'}}</span>\n <span class=\"detail-value\">{{selectedDateStr}} at {{line.selectedSlot?.value ?? 'N/A'}}</span>\n </div>\n </div>\n </div>\n\n <div class=\"done-actions d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <ng-container *ngIf=\"!isAdminContext; else adminDoneActions\">\n <button type=\"button\" class=\"done-btn done-btn-primary\" (click)=\"goToMyBookings()\">View my bookings</button>\n <button type=\"button\" class=\"done-btn done-btn-secondary\" (click)=\"goToListing()\">Keep shopping</button>\n </ng-container>\n <ng-template #adminDoneActions>\n <button type=\"button\" class=\"done-btn done-btn-primary\" (click)=\"goToAppointmentsList()\">Back to Appointments List</button>\n <button type=\"button\" class=\"done-btn done-btn-secondary\" (click)=\"bookAnother()\">Book Another</button>\n </ng-template>\n </div>\n </div>\n </div>\n</ng-template>\n", styles: ["@import\"https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&display=swap\";mat-icon{font-family:Material Icons!important}:host{--font-sans: \"Outfit\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;--slate-50: #f8fafc;--slate-100: #f1f5f9;--slate-200: #e2e8f0;--slate-300: #cbd5e1;--slate-400: #94a3b8;--slate-500: #64748b;--slate-600: #475569;--slate-700: #334155;--slate-800: #1e293b;--slate-900: #0f172a;--color-primary: #230860;--color-secondary: #00b6ff;--color-accent-gradient: linear-gradient(135deg, #230860 0%, #00b6ff 100%);--color-success: #10b981;--color-success-bg: #ecfdf5;--color-error: #ef4444;--color-error-bg: #fef2f2;--border-radius-sm: 8px;--border-radius-md: 12px;--border-radius-lg: 16px;--border-radius-xl: 24px;--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, .05);--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, .05), 0 2px 4px -2px rgba(0, 0, 0, .05);--shadow-lg: 0 10px 15px -3px rgba(35, 8, 96, .05), 0 4px 6px -4px rgba(35, 8, 96, .05);--shadow-xl: 0 20px 25px -5px rgba(35, 8, 96, .08), 0 8px 10px -6px rgba(35, 8, 96, .08);--transition-smooth: all .3s cubic-bezier(.4, 0, .2, 1);--transition-bounce: all .4s cubic-bezier(.175, .885, .32, 1.275)}*{box-sizing:border-box;font-family:var(--font-sans)}.main_section{position:relative;height:100vh;background-color:var(--slate-50);display:flex;flex-direction:column;overflow:hidden}.hover_effect{position:absolute;width:100%;top:0;left:0;height:100%}.main_header{padding:15px;background:#fff;border-bottom:1px solid var(--slate-100);flex-shrink:0;box-shadow:0 2px 8px #00000003}.header{display:flex;align-items:center;justify-content:space-between}.back-btn{display:flex;align-items:center;justify-content:center;gap:.5rem;padding:.6rem 1.2rem;border-radius:var(--border-radius-md);background:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-700)!important;transition:var(--transition-smooth);font-weight:500;font-size:.9rem;cursor:pointer}.back-btn mat-icon{font-size:18px!important;width:18px!important;height:18px!important;color:var(--slate-700)!important;display:flex;align-items:center;justify-content:center}.back-btn:hover{background:var(--slate-100);transform:translate(-3px);color:var(--slate-900)!important}.header-title{flex-grow:1;text-align:right}.header-title h1{font-size:1.5rem;font-weight:700;margin-bottom:.2rem;color:var(--slate-900)!important;letter-spacing:-.025em}.header-title p{color:var(--slate-500)!important;font-size:.9rem;font-weight:500;margin-bottom:0}.progress-bar{width:100%;height:6px;background-color:var(--slate-100);margin-top:3px;border-radius:10px;overflow:hidden;position:relative}.progress-fill{height:100%;background:var(--color-accent-gradient);border-radius:10px;transition:width .5s cubic-bezier(.4,0,.2,1);position:relative}.progress-fill:after{content:\"\";position:absolute;inset:0;background:linear-gradient(90deg,#fff0,#ffffff4d,#fff0);animation:shimmer 2s infinite linear}@keyframes shimmer{0%{transform:translate(-100%)}to{transform:translate(100%)}}.main_body{flex-grow:1;overflow-y:auto;padding:10px;display:flex;justify-content:center;background:var(--slate-50)}.w-60{width:100%;max-width:800px}.service_section,.location_section,.staff-listing,.date_section,.contact_section,.payment_section,.booking-confirmation{animation:slideUp .5s cubic-bezier(.16,1,.3,1) forwards}@keyframes slideUp{0%{opacity:0;transform:translateY(15px)}to{opacity:1;transform:translateY(0)}}h2{font-size:1.5rem;font-weight:700;color:var(--slate-900)!important;letter-spacing:-.02em;margin-bottom:.3rem}p.subtitle,.service-selection p,.location_section p,.staff-subtitle,.datetime-subtitle,.contact-subtitle,.payment-subtitle{color:var(--slate-500)!important;font-size:13px;margin-bottom:2rem}.services-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding-bottom:2rem}.service-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px}.service-card:hover{border-color:var(--slate-400);transform:translateY(-4px);box-shadow:var(--shadow-lg)}.service-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px;transform:translateY(-2px)}.service-card-selected:before,.location-card-selected:before{content:\"\\2713\";position:absolute;top:-10px;right:-10px;background:var(--color-accent-gradient);color:#fff!important;width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.8rem;font-weight:700;box-shadow:0 4px 8px #2308604d;animation:popIn .3s cubic-bezier(.175,.885,.32,1.275);z-index:10}@keyframes popIn{0%{transform:scale(0)}to{transform:scale(1)}}.service-header{display:flex;align-items:flex-start;gap:1rem;margin-bottom:1rem}.service-icon{width:48px;height:48px;border-radius:var(--border-radius-md);background-color:var(--slate-100);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.service-icon mat-icon{font-size:24px!important;width:24px!important;height:24px!important;color:var(--color-primary)!important}.service-card-selected .service-icon{background:var(--slate-900)}.service-card-selected .service-icon mat-icon{color:#fff!important}.service-info{flex-grow:1}.service-title{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;line-height:1.3;margin-bottom:.2rem}.service-price{font-size:1.25rem;font-weight:800;color:var(--slate-900)!important;text-align:right}.service-duration{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;text-align:right;margin-top:.1rem}.service-description{color:var(--slate-600)!important;font-size:.9rem;line-height:1.5;margin-bottom:1.25rem;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.home-visit{align-self:flex-start;display:inline-flex;align-items:center;gap:.5rem;font-size:.75rem;font-weight:600;color:var(--slate-700)!important;border:1px solid var(--slate-200);padding:.35rem .75rem;border-radius:20px;background-color:var(--slate-50);transition:var(--transition-smooth)}.home-visit img{width:14px;height:14px}.home-visit:before{content:\"\";display:inline-block;width:6px;height:6px;border-radius:50%;background-color:var(--color-success);box-shadow:0 0 #10b98166;animation:pulseGlow 1.8s infinite}@keyframes pulseGlow{0%{box-shadow:0 0 #10b981b3}70%{box-shadow:0 0 0 6px #10b98100}to{box-shadow:0 0 #10b98100}}.location-list{display:flex;flex-direction:column;gap:1.25rem;padding-bottom:2rem}.location-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm)}.location-card:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md)}.location-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px)}.location-content{display:flex;align-items:center}.location-info{display:flex;align-items:center;gap:1.25rem;width:100%}.location-icon{width:52px;height:52px;background-color:var(--slate-100);border-radius:var(--border-radius-md);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.location-icon img{width:28px;height:28px}.location-card-selected .location-icon{background:var(--slate-900)}.location-details{flex-grow:1}.location-details h3{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.3rem}.location-details p{font-size:.9rem;color:var(--slate-500)!important;font-weight:450;line-height:1.4;margin-bottom:0}.search-container{width:100%;margin-bottom:1.25rem}.search-input-wrapper{width:100%;background-color:var(--slate-100);border:1.5px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem 1rem;transition:var(--transition-smooth)}.search-input-wrapper:focus-within{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #23086014}.search-input{font-size:.95rem;font-weight:500;color:var(--slate-900)!important;background:transparent;outline:none;width:100%}.search-input::placeholder{color:var(--slate-400)}.search-icon{color:var(--slate-400)!important;font-size:20px!important;width:20px!important;height:20px!important}.clear-icon{color:var(--slate-400)!important;font-size:18px!important;width:18px!important;height:18px!important;transition:var(--transition-smooth)}.clear-icon:hover{color:var(--slate-600)!important}.staff-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:1rem;max-height:48vh;overflow-y:auto;padding-right:.5rem;padding-bottom:1rem}.staff-list::-webkit-scrollbar{width:6px}.staff-list::-webkit-scrollbar-track{background:var(--slate-50);border-radius:4px}.staff-list::-webkit-scrollbar-thumb{background:var(--slate-200);border-radius:4px}.staff-list::-webkit-scrollbar-thumb:hover{background:var(--slate-300)}.staff-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);margin-bottom:0!important}.staff-card:hover{border-color:var(--slate-300);transform:translateY(-2px);box-shadow:var(--shadow-md)}.staff-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px);margin-bottom:0!important}.staff-avatar{width:48px;height:48px;background:var(--color-accent-gradient);font-size:.95rem;font-weight:700;color:#fff!important;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;box-shadow:0 4px 10px #2308601a;letter-spacing:.5px;transition:var(--transition-smooth)}.staff-card-selected .staff-avatar{transform:scale(1.05)}.staff-name{font-size:1.05rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.2rem;letter-spacing:-.015em}.staff-specialty{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;margin-bottom:0;text-transform:uppercase;letter-spacing:.05em}.selection-indicator{display:flex;align-items:center;justify-content:center;margin-left:auto;padding-left:1rem}.checkmark-circle-mini{width:24px;height:24px;border:2px solid var(--slate-300);border-radius:50%;background-color:#fff;transition:var(--transition-bounce);color:#fff!important}.checkmark-circle-mini.selected{background:var(--color-accent-gradient);border-color:transparent;box-shadow:0 3px 8px #23086040}.checkmark-circle-mini mat-icon{font-size:14px!important;width:14px!important;height:14px!important;color:#fff!important;font-weight:800!important;display:flex;align-items:center;justify-content:center}.main_container{display:flex;gap:2rem;margin-bottom:2rem}.section-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm);height:100%}.section-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:10px!important;letter-spacing:-.01em}.date-picker-container{border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem 1rem;display:flex;align-items:center;justify-content:space-between;transition:var(--transition-smooth);background-color:var(--slate-50);cursor:pointer}.date-picker-container:hover{border-color:var(--slate-400);background-color:#fff}.date-input{font-size:.95rem;font-weight:600;color:var(--slate-800)!important;background:transparent;border:none;outline:none;cursor:pointer;width:100%}.date-picker-container mat-icon{color:var(--color-primary)!important;font-size:20px!important;width:20px!important;height:20px!important}.datepicker-popover{position:absolute;z-index:1000;margin-top:4px;border-radius:var(--border-radius-lg);overflow:hidden;box-shadow:var(--shadow-xl);background:#fff;border:1px solid var(--slate-200);width:320px}::ng-deep .datepicker-calendar{border-radius:var(--border-radius-lg)!important;width:100%!important}::ng-deep .mat-calendar-header{background:var(--color-accent-gradient)!important;color:#fff!important;padding:.5rem!important}::ng-deep .mat-calendar-content{padding:8px!important}::ng-deep .mat-calendar-controls{margin:0!important}::ng-deep .mat-calendar-period-button{color:#fff!important;font-weight:700!important;font-size:1rem!important}::ng-deep .mat-calendar-arrow{fill:#fff!important}::ng-deep .mat-calendar-previous-button,::ng-deep .mat-calendar-next-button{color:#fff!important}::ng-deep .mat-calendar-body-cell{font-size:13px!important}::ng-deep .mat-calendar-body-cell-content{font-weight:600!important;color:var(--slate-800)!important;border-radius:8px!important}::ng-deep .mat-calendar-body-selected{background:var(--color-accent-gradient)!important;color:#fff!important;box-shadow:0 4px 10px #23086033!important}::ng-deep .mat-calendar-body-today:not(.mat-calendar-body-selected){border:2px solid var(--color-primary)!important;color:var(--color-primary)!important}.time_selection{max-height:420px;display:flex;flex-direction:column}.time_selection .row{flex-grow:1;overflow-y:auto;padding-right:.25rem;margin-top:10px}.time-slot{background:#fff;border:1px solid var(--slate-200);font-size:.9rem;font-weight:600;color:var(--slate-800)!important;padding:.75rem .5rem;border-radius:var(--border-radius-md);cursor:pointer;transition:var(--transition-smooth);text-align:center;box-shadow:var(--shadow-sm)}.time-slot:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md);background-color:var(--slate-50)}.time-slot.selected{background:var(--color-accent-gradient);border-color:transparent;color:#fff!important;box-shadow:0 4px 12px #23086033}.form-section{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm)}.form-label{font-size:.85rem;font-weight:600;color:var(--slate-700)!important;margin-bottom:.5rem;text-transform:uppercase;letter-spacing:.05em}.required-asterisk{color:var(--color-error);margin-left:2px}.form-control,.form-input,.form-textarea{width:100%;background-color:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-900)!important;font-size:.95rem;font-weight:500;padding:.75rem 1rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);outline:none}.form-control:focus,.form-input:focus,.form-textarea:focus{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #2308601a}.form-textarea{min-height:100px;resize:vertical}.policies-container{background-color:#fff;border:1px solid var(--slate-200);padding:1.75rem;border-radius:var(--border-radius-lg);margin-top:1.5rem;box-shadow:var(--shadow-sm)}.policies-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1.25rem}.policy-item{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1rem 1.25rem;cursor:pointer;transition:var(--transition-smooth);display:flex;justify-content:space-between;align-items:center}.policy-item:hover{background-color:var(--slate-100);border-color:var(--slate-300)}.policy-title{font-size:.95rem;font-weight:600;color:var(--slate-800)!important}.policy-arrow mat-icon{color:var(--slate-500)!important;transition:var(--transition-smooth)}.cancellation_policies{background-color:var(--slate-50);padding:1rem 1.5rem;border-left:3px solid var(--color-primary);border-radius:0 0 var(--border-radius-md) var(--border-radius-md);margin-top:-4px;margin-bottom:1rem;font-size:.9rem;color:var(--slate-600)!important;line-height:1.5}.acceptance-section{display:flex;align-items:center;gap:.75rem;margin-top:1.5rem}.custom-checkbox{width:20px;height:20px;border:2px solid var(--slate-300);border-radius:6px;cursor:pointer;transition:var(--transition-smooth);position:relative;appearance:none;background-color:#fff;outline:none}.custom-checkbox:checked{background:var(--color-accent-gradient);border-color:transparent}.custom-checkbox:checked:after{content:\"\\2713\";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#fff!important;font-size:.75rem;font-weight:800}.acceptance-text{font-size:.95rem;color:var(--slate-700)!important;font-weight:500;-webkit-user-select:none;user-select:none;line-height:1.4}.booking-summary-card{background-color:#fff;border:1px solid var(--slate-200);padding:2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);position:relative}.booking-summary-card:after{content:\"\";position:absolute;bottom:-1px;left:0;right:0;height:10px;background-image:radial-gradient(circle,white 4px,transparent 5px);background-size:12px 12px;background-position:0 0;z-index:2}.summary-title{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important;border-bottom:2px dashed var(--slate-200);padding-bottom:1rem;margin-bottom:1.5rem;text-align:center}.summary-row{display:flex;justify-content:space-between;align-items:center;padding:.85rem 0;border-bottom:1px solid var(--slate-100)}.summary-label{font-size:.95rem;color:var(--slate-500)!important;font-weight:500}.summary-value{font-size:.95rem;color:var(--slate-900)!important;font-weight:600;text-align:right}.total-row{margin-top:1rem;padding-top:1.25rem;border-top:2px dashed var(--slate-200);border-bottom:none}.total-row .summary-label{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important}.total-row .summary-value{font-size:1.5rem;font-weight:800;color:var(--color-primary)!important}.booking-confirmation{background:#fff;border:1px solid var(--slate-200);padding:3rem 2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);display:flex;flex-direction:column;align-items:center;text-align:center;max-width:500px;margin:0 auto}.success-icon{margin-bottom:1.5rem}.checkmark-circle{width:96px;height:96px;display:flex;align-items:center;justify-content:center}.confirmation-title{font-size:1.5rem;font-weight:800;color:var(--slate-900)!important;margin-bottom:.5rem}.confirmation-message{font-size:1rem;color:var(--slate-500)!important;line-height:1.6;margin-bottom:2rem;font-weight:450}.details-card{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1.5rem;width:100%;margin-bottom:2rem;text-align:left}.details-title{font-size:1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1rem;text-transform:uppercase;letter-spacing:.05em}.details-row{display:flex;justify-content:space-between;padding:.5rem 0;border-bottom:1px dashed var(--slate-200)}.details-row:last-child{border-bottom:none}.detail-label{font-size:.85rem;color:var(--slate-500)!important;font-weight:500}.detail-value{font-size:.9rem;color:var(--slate-900)!important;font-weight:600}.main_footer{border-top:1px solid var(--slate-200);background-color:#fff;padding:15px;flex-shrink:0;display:flex;justify-content:center;box-shadow:0 -4px 12px #00000005}.footer-buttons{width:100%;max-width:800px;display:flex;align-items:center}.back-footer-btn{font-size:.95rem;font-weight:600;color:var(--slate-600)!important;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);cursor:pointer}.back-footer-btn:hover{color:var(--slate-900)!important;background-color:var(--slate-100)}.continue-btn{background:var(--color-accent-gradient);color:#fff!important;border:none;padding:.75rem 2rem;border-radius:var(--border-radius-md);font-size:.95rem!important;font-weight:600;cursor:pointer;transition:var(--transition-smooth);box-shadow:0 4px 10px #23086033;width:max-content!important}.continue-btn:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.continue-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed!important;box-shadow:none!important}.complete_booking,.pay-now-btn{background:var(--color-accent-gradient)!important;color:#fff!important;border:none;padding:.75rem 2.25rem!important;font-size:.95rem!important;font-weight:600;border-radius:var(--border-radius-md)!important;box-shadow:0 4px 12px #23086040;transition:var(--transition-smooth);cursor:pointer;display:flex;align-items:center;gap:.5rem;width:max-content!important}.complete_booking img,.pay-now-btn img{width:20px;height:20px;filter:brightness(0) invert(1)}.complete_booking:hover:not([disabled]),.pay-now-btn:hover:not([disabled]){transform:translateY(-2px);box-shadow:0 6px 18px #23086059}.complete_booking:disabled,.pay-now-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed;box-shadow:none}.service-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding:0;width:100%}.skeleton-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;height:180px;display:flex;flex-direction:column;justify-content:space-between}.skeleton{background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border-radius:4px}@keyframes loading-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}.skeleton-icon{width:48px;height:48px;border-radius:var(--border-radius-md)}.skeleton-title{height:20px;width:60%;margin-bottom:.5rem}.skeleton-price{height:20px;width:30%}.skeleton-duration{height:12px;width:25%;margin-top:.25rem}.skeleton-description{height:14px;width:85%}.skeleton-badge{height:28px;width:120px;border-radius:20px}.time-slot-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:.75rem;width:100%}.skeleton-time-slot{height:42px;border-radius:var(--border-radius-md);background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border:1px solid var(--slate-100)}@media screen and (max-width: 475px){.main_header{padding:1rem}.header-title h1{font-size:1.25rem}.back-btn{padding:.5rem .8rem}.back-btn span{display:none}.main_body{padding:15px}.services-grid{grid-template-columns:1fr;gap:1rem}.staff-list{grid-template-columns:1fr!important;gap:.85rem!important}.service-card,.service-card-selected{min-height:auto}.main_container{flex-direction:column;gap:1.5rem}.datepicker-popover{width:100%;left:0}.details_container{gap:1.5rem}.details_container>.d-flex{flex-direction:column;gap:1.5rem}.details_container>.d-flex>div{width:100%!important}.booking-summary-card{padding:1.25rem}.summary-title{font-size:1.15rem}.total-row .summary-label{font-size:1.1rem}.total-row .summary-value{font-size:1.3rem}.main_footer{padding:1rem}.continue-btn{padding:.75rem 1.5rem}}.shipping-info{border-radius:10px;padding:20px;margin-bottom:12px;border:1px solid var(--slate-200);box-shadow:var(--shadow-sm)}.address-info{margin-bottom:0}.address-name{font-weight:700;margin-bottom:8px;color:var(--slate-900)!important}.address-details{color:var(--slate-500)!important;margin-bottom:8px}.mobile-number{font-weight:700;color:var(--slate-900)!important;font-size:15px}.change-address-btn{font-size:.85rem!important;font-weight:700!important;padding:10px;background:#fff;border:1px solid var(--slate-200);border-radius:8px;color:var(--slate-900)!important;cursor:pointer;transition:var(--transition-smooth)}.change-address-btn:hover{border-color:var(--color-primary);color:var(--color-primary)!important}.addLinks{padding:14px;border:1px dashed var(--slate-300);display:flex;align-items:center;justify-content:center;cursor:pointer;border-radius:8px;color:var(--slate-500)!important;margin-bottom:12px}.addLinks:hover{border-color:var(--color-primary);color:var(--color-primary)!important}h1{font-size:24px!important;font-weight:600!important}.done-actions{display:flex;gap:12px;width:100%}.done-btn{flex:1;max-width:220px;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);font-size:.95rem;font-weight:600;cursor:pointer;transition:var(--transition-smooth);border:none}.done-btn-primary{background:var(--color-accent-gradient);color:#fff!important;box-shadow:0 4px 10px #23086033}.done-btn-primary:hover{transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.done-btn-secondary{background:#fff;color:var(--slate-600)!important;border:1px solid var(--slate-200)}.done-btn-secondary:hover{background-color:var(--slate-100);color:var(--slate-900)!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "pipe", type: i3.SlicePipe, name: "slice" }, { kind: "pipe", type: i3.TitleCasePipe, name: "titlecase" }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatDatepickerModule }, { kind: "component", type: i9$2.MatCalendar, selector: "mat-calendar", inputs: ["headerComponent", "startAt", "startView", "selected", "minDate", "maxDate", "dateFilter", "dateClass", "comparisonStart", "comparisonEnd", "startDateAccessibleName", "endDateAccessibleName"], outputs: ["selectedChange", "yearSelected", "monthSelected", "viewChanged", "_userSelection", "_userDragDrop"], exportAs: ["matCalendar"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i9.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i9.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i9.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i9.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i9.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i9.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatNativeDateModule }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: LettersOnlyDirective, selector: "[simpoLettersOnly]" }, { kind: "directive", type: NumbersOnlyDirective, selector: "[simpoNumbersOnly]" }, { kind: "ngmodule", type: ToastModule }, { kind: "component", type: i11.Toast, selector: "p-toast", inputs: ["key", "autoZIndex", "baseZIndex", "life", "style", "styleClass", "position", "preventOpenDuplicates", "preventDuplicates", "showTransformOptions", "hideTransformOptions", "showTransitionOptions", "hideTransitionOptions", "breakpoints"], outputs: ["onClose"] }, { kind: "directive", type: HoverDirective, selector: "[simpoHover]", outputs: ["hovering"] }, { kind: "component", type: HoverElementsComponent, selector: "simpo-hover-elements", inputs: ["data", "index", "editOptions", "isMerged", "isEcommerce"], outputs: ["edit"] }, { kind: "directive", type: BackgroundDirective, selector: "[simpoBackground]", inputs: ["simpoBackground", "scrollValue"] }] }); }
|
|
25965
25979
|
}
|
|
25966
25980
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AppointmentBookingComponent, decorators: [{
|
|
25967
25981
|
type: Component,
|
|
25968
|
-
args: [{ selector: 'simpo-appointment-booking', standalone: true, imports: [CdkDragPlaceholder, CommonModule, MatIcon, MatFormFieldModule, MatDatepickerModule, FormsModule, MatNativeDateModule, MatInputModule, MatDialogModule, LettersOnlyDirective, NumbersOnlyDirective, ToastModule], providers: [MessageService], template: "<p-toast position=\"bottom-right\" [baseZIndex]=\"10000000000\" [autoZIndex]=\"true\"\n [showTransformOptions]=\"screenWidth < 475 ? 'translateY(-100%)' : ''\"></p-toast>\n<section class=\"main_section\">\n <div class=\"main_header\">\n <div class=\"header d-flex justify-content-between align-items-center\">\n <div class=\"back-btn d-flex justify-content-center align-items-center cursor-pointer gap-2 mb-3\"\n (click)=\"goBack()\">\n <mat-icon>keyboard_backspace</mat-icon><span *ngIf=\"screenWidth > 475\">Back to Home</span>\n </div>\n <div class=\"header-title\">\n <h1>Book New Appointment</h1>\n <p>{{businessName ?? \"N/A\" }}</p>\n </div>\n </div>\n\n <div class=\"progress-bar\">\n <div class=\"progress-fill\" [style.width]=\"barWidth + '%'\"></div>\n </div>\n </div>\n <div class=\"main_body w-100 d-flex justify-content-center\">\n <ng-container *ngIf=\"selectedTab === 'modeSelection'\">\n <ng-container *ngTemplateOutlet=\"modeSelection\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'serviceListing'\">\n <ng-container *ngIf=\"!skeletonLoader\">\n <ng-container *ngTemplateOutlet=\"serviceListing\"></ng-container>\n </ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'locationListing'\">\n <ng-container *ngTemplateOutlet=\"locationListing\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'staffListing'\">\n <ng-container *ngTemplateOutlet=\"staffListing\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'dateSelection'\">\n <ng-container *ngTemplateOutlet=\"dateSelection\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab==='contactDetails'\">\n <ng-container *ngTemplateOutlet=\"contactDetails\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab==='paymentTab'\">\n <ng-container *ngTemplateOutlet=\"paymentTab\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab==='statusTemplate'\">\n <ng-container *ngTemplateOutlet=\"statusTemplate\"></ng-container>\n </ng-container>\n </div>\n <div class=\"main_footer d-flex justify-content-center align-items-center\"\n *ngIf=\"selectedTab!=='statusTemplate' && selectedTab!=='modeSelection'\">\n <div class=\"footer-buttons\"\n [ngStyle]=\"{'justify-content': selectedTab != 'serviceListing' ? 'space-between' : 'end'}\">\n <span class=\"back-footer-btn cursor-pointer\" (click)=\"previousStep()\"\n *ngIf=\"selectedTab != 'serviceListing'\">Back</span>\n <button class=\"continue-btn\" [disabled]=\"!activeButton\" (click)=\"nextStep()\"\n *ngIf=\"selectedTab!='paymentTab'\">{{!loader ? 'Continue' : 'Loading...'}}</button>\n <button class=\"cursor-pointer d-flex justify-content-evenly align-items-center\"\n *ngIf=\"selectedTab==='paymentTab'\" (click)=\"confirmBooking()\" [disabled]=\"isProcessing\"\n [ngClass]=\"{'pay-now-btn' : bookingGroup?.totalCollectedAtBooking > 0 || !bookingGroup,'complete_booking' : bookingGroup && !bookingGroup?.totalCollectedAtBooking}\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/304012c1753440087996Background.png\">\n {{isProcessing ? 'Please wait...' : 'Confirm Booking'}}\n </button>\n </div>\n </div>\n</section>\n\n<ng-template #modeSelection>\n <div class=\"w-60 service_section\">\n <div class=\"service-selection\">\n <h2>How would you like this?</h2>\n <p>Choose how you'd like to be served</p>\n <div class=\"services-grid\">\n <div class=\"service-card\" (click)=\"selectMode('STORE_VISIT')\">\n <div class=\"service-header\">\n <div class=\"service-icon\"><mat-icon>storefront</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">Visit our Store</div>\n </div>\n </div>\n <div class=\"service-description\">Come to us at one of our locations</div>\n </div>\n <div class=\"service-card\" (click)=\"selectMode('HOME_VISIT')\">\n <div class=\"service-header\">\n <div class=\"service-icon\"><mat-icon>home</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">We come to you</div>\n </div>\n </div>\n <div class=\"service-description\">A professional visits your address</div>\n </div>\n <div class=\"service-card\" (click)=\"selectMode('VIDEO_CALL')\">\n <div class=\"service-header\">\n <div class=\"service-icon\"><mat-icon>videocam</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">Video consultation</div>\n </div>\n </div>\n <div class=\"service-description\">Connect over a video call</div>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #serviceListing>\n <div class=\"w-60 service_section\">\n <div class=\"service-selection\">\n <h2>Select a Service</h2>\n <p>Choose the service(s) you'd like to book<span *ngIf=\"cartServices.length > 0\"> \u2014 {{cartServices.length}} selected</span></p>\n <p *ngIf=\"productCartItems.length > 0\" class=\"cart-hint\">{{productCartItems.length}} product(s) already in your cart \u2014 you can continue without picking a service.</p>\n\n <div class=\"services-grid\">\n <ng-container *ngFor=\"let service of serviceData\">\n <div class=\"\" (click)=\"selectService(service)\"\n [ngClass]=\"{ 'service-card-selected' : service?.selected, 'service-card': !service?.selected }\">\n <div class=\" service-header\">\n <div class=\"service-icon\"><mat-icon>person_outline</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">{{service?.name ? service?.name : 'N/A'}}</div>\n </div>\n <div>\n <div class=\"service-price\">\u20B9{{service?.priceDetails?.price ?\n service?.priceDetails?.price : 'N/A' }}</div>\n <div class=\"service-duration\">{{service?.duration ? service?.duration : 'N/A'}} min\n </div>\n </div>\n </div>\n <div class=\"service-description\" *ngIf=\"service?.description\">\n {{service?.description ? service?.description : 'N/A'}}\n </div>\n <div class=\"home-visit\" *ngIf=\"selectedMode === 'STORE_VISIT' && service?.homeAppointmentAvailable\"><img\n src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/982126c1758628863129furniture_16406103.png\">Home\n Visit Available</div>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #locationListing>\n <div class=\"location_section\">\n <div class=\"header flex-column align-items-start\">\n <h1>Choose Location</h1>\n <p>Select where you'd like to receive the service</p>\n </div>\n\n <div class=\"location-list\">\n <ng-container *ngFor=\"let location of locationData\">\n <div (click)=\"selectLocation(location)\"\n [ngClass]=\"{ 'location-card-selected' : location?.selected, 'location-card': !location?.selected }\">\n <div class=\"location-content\">\n <div class=\"location-info\">\n <div class=\"location-icon\"><img\n src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/427226c1758629157758store_3171510.png\">\n </div>\n <div class=\"location-details\">\n <div class=\"d-flex justify-content-between align-items-center\">\n <h3>{{location?.storeName ? location?.storeName : 'N/A'}}</h3>\n </div>\n <p>{{location?.addressDetails?.addressLine}}, {{location?.addressDetails?.city}},\n {{location?.addressDetails?.state}} {{location?.pincode}}</p>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n</ng-template>\n\n<ng-template #staffListing>\n <div class=\"w-60 overflow-hidden staff-listing\">\n <div class=\"d-flex w-100 h-100\">\n <div class=\"w-100\">\n <div class=\"staff-header mb-3\">\n <h1>Select Staff Member</h1>\n <p class=\"staff-subtitle mb-0\">Choose your preferred professional</p>\n </div>\n\n <div class=\"search-container mb-4\">\n <div class=\"search-input-wrapper d-flex align-items-center\">\n <mat-icon class=\"search-icon me-2\">search</mat-icon>\n <input type=\"text\" class=\"search-input border-0 flex-grow-1\" placeholder=\"Search staff member by name...\" [(ngModel)]=\"staffSearchQuery\">\n <mat-icon class=\"clear-icon cursor-pointer ms-2\" *ngIf=\"staffSearchQuery\" (click)=\"staffSearchQuery = ''\">close</mat-icon>\n </div>\n </div>\n\n <!-- Pure product-only line: one flat staff list, same as the old single-service flow -->\n <div class=\"staff-list\" *ngIf=\"cartServices.length === 0\">\n <ng-container *ngFor=\"let staff of filteredStaff\">\n <div class=\"card rounded-3 p-3\" (click)=\"selectStaffForProductOnlyLine(staff)\"\n [ngClass]=\"{ 'staff-card-selected' : staff?.selected, 'staff-card': !staff?.selected }\">\n <div class=\"d-flex align-items-center justify-content-between w-100\">\n <div class=\"d-flex align-items-center flex-grow-1\">\n <div class=\"staff-avatar rounded-circle d-flex align-items-center justify-content-center me-4\">\n {{staff?.staffName.slice(0,2).toUpperCase()}}\n </div>\n <div class=\"staff-details flex-grow-1\">\n <h3 class=\"staff-name\">{{(staff?.staffName ? staff?.staffName : 'N/A') | titlecase}}</h3>\n <p class=\"staff-specialty\">{{(businessName && businessName !== 'N/A') ? businessName : 'Booking Specialist'}}</p>\n </div>\n </div>\n <div class=\"selection-indicator\">\n <div class=\"checkmark-circle-mini d-flex align-items-center justify-content-center\" [class.selected]=\"staff?.selected\">\n <mat-icon *ngIf=\"staff?.selected\">check</mat-icon>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n\n <!-- Bundled cart: one pool per line that resolution couldn't collapse to a single provider -->\n <ng-container *ngIf=\"cartServices.length > 0\">\n <div class=\"staff-line-group mb-4\" *ngFor=\"let line of resolvedLines\">\n <ng-container *ngIf=\"line.candidateStaffPool?.length\">\n <h4 class=\"mb-2\">For {{line.services.length}} service(s): {{ (line.services | slice:0:3).length ? '' : '' }}<span *ngFor=\"let s of line.services; let last = last\">{{s.name}}{{last ? '' : ', '}}</span></h4>\n <div class=\"staff-list mb-3\">\n <ng-container *ngFor=\"let staff of line.candidateStaffPool\">\n <div class=\"card rounded-3 p-3\" (click)=\"selectStaffForLine(line, staff)\"\n [ngClass]=\"{ 'staff-card-selected' : line.selectedStaffId === staff.id, 'staff-card': line.selectedStaffId !== staff.id }\">\n <div class=\"d-flex align-items-center justify-content-between w-100\">\n <div class=\"d-flex align-items-center flex-grow-1\">\n <div class=\"staff-avatar rounded-circle d-flex align-items-center justify-content-center me-4\">\n {{staff?.name?.slice(0,2)?.toUpperCase()}}\n </div>\n <div class=\"staff-details flex-grow-1\">\n <h3 class=\"staff-name\">{{(staff?.name ? staff?.name : 'N/A') | titlecase}}</h3>\n </div>\n </div>\n <div class=\"selection-indicator\">\n <div class=\"checkmark-circle-mini d-flex align-items-center justify-content-center\" [class.selected]=\"line.selectedStaffId === staff.id\">\n <mat-icon *ngIf=\"line.selectedStaffId === staff.id\">check</mat-icon>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n </ng-container>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #dateSelection>\n <div class=\"w-60 date_section\">\n <div class=\"row justify-content-center h-100\">\n <div class=\"col-12 h-100\">\n <div class=\"datetime-header mb-2\">\n <h1>Select Date & Time</h1>\n <p class=\"datetime-subtitle mb-0\">Choose when you'd like your appointment</p>\n </div>\n\n <div class=\"d-flex gap-4 main_container\">\n <div [ngClass]=\"{'w-50' : screenWidth > 475 , 'w-100':screenWidth < 475}\">\n <div class=\"section-card card rounded-3 p-4 h-100\">\n <h3 class=\"section-title\">Select Date</h3>\n\n <div class=\"date-picker-container d-flex align-items-center justify-content-between\"\n (click)=\"$event.stopPropagation()\">\n <input type=\"text\" class=\"date-input border-0 rounded-2\" placeholder=\"dd-mm-yyyy\"\n [value]=\"selectedDateStr\" readonly (click)=\"toggleCalendar($event)\">\n\n <mat-icon class=\"ms-2\" (click)=\"toggleCalendar($event)\">calendar_today</mat-icon>\n </div>\n <div class=\"position-relative\" (click)=\"$event.stopPropagation()\">\n <div class=\"datepicker-popover\" *ngIf=\"showCalendar\">\n <mat-calendar [(selected)]=\"selectedDate\" [dateFilter]=\"dateFilter\"\n (selectedChange)=\"onDateSelected($event)\" class=\"datepicker-calendar\">\n </mat-calendar>\n </div>\n </div>\n </div>\n </div>\n\n <!-- One slot-picker per resolved line, side by side when there's more than one (design doc \u00A73b) -->\n <div class=\"time_selection\" [ngClass]=\"{'w-50' : screenWidth > 475 , 'w-100':screenWidth < 475}\" *ngIf=\"resolvedLines.length <= 1\">\n <div class=\"section-card card h-100 rounded-3 p-4\">\n <h3 class=\"section-title\">Available Times</h3>\n <div class=\"row g-2 mb-4 overflow-scroll\">\n <ng-container *ngIf=\"!skeletonLoader && resolvedLines[0]\">\n <div class=\"col-4\" *ngFor=\"let time of resolvedLines[0].slots\">\n <div class=\"time-slot rounded-2\" [class.selected]=\"time.selected\"\n (click)=\"selectSlotForLine(resolvedLines[0], time)\">{{time ? time?.value : 'N/A'}}</div>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Multi-line case: each line gets its own full-width card with a staff header -->\n <div class=\"d-flex gap-4 main_container flex-wrap\" *ngIf=\"resolvedLines.length > 1\">\n <div class=\"w-100\" *ngFor=\"let line of resolvedLines\">\n <div class=\"section-card card rounded-3 p-4\">\n <h3 class=\"section-title\">Professional: {{line.staffName || line.selectedStaffName}}</h3>\n <p class=\"mb-2\" *ngIf=\"line.services.length\"><span *ngFor=\"let s of line.services; let last = last\">{{s.name}}{{last ? '' : ', '}}</span></p>\n <div class=\"row g-2 mb-2 overflow-scroll\">\n <ng-container *ngIf=\"!line.slotsLoading\">\n <div class=\"col-4\" *ngFor=\"let time of line.slots\">\n <div class=\"time-slot rounded-2\" [class.selected]=\"time.selected\"\n (click)=\"selectSlotForLine(line, time)\">{{time ? time?.value : 'N/A'}}</div>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #contactDetails>\n <div class=\"w-60 contact_section\">\n <div class=\"contact-header mb-2\">\n <h1>Contact Details</h1>\n <p class=\"contact-subtitle mb-0\">Provide your contact information</p>\n </div>\n\n <div class=\"d-flex gap-3 details_container flex-column w-100\">\n <div class=\"d-flex gap-4\">\n <div [ngClass]=\"{'w-50' : selectedMode === 'HOME_VISIT', 'w-100' : selectedMode !== 'HOME_VISIT'}\">\n <div class=\"form-section card rounded-3 p-4 h-100\">\n <h3 class=\"section-title\">Personal Information</h3>\n\n <div class=\"mb-4\">\n <label class=\"form-label d-flex align-items-center\">\n Full Name\n <span class=\"required-asterisk\">*</span>\n </label>\n <input type=\"text\" class=\"form-control form-input rounded-2\"\n [(ngModel)]=\"appointmentPayload.customerDetail.name\"\n (ngModelChange)=\"checkRequiredValues()\" simpoLettersOnly>\n </div>\n\n <div class=\"mb-4\">\n <label class=\"form-label d-flex align-items-center\">\n Email Address\n <span class=\"required-asterisk\">*</span>\n </label>\n <input type=\"email\" class=\"form-control form-input rounded-2\"\n [(ngModel)]=\"appointmentPayload.customerDetail.email\"\n (ngModelChange)=\"checkRequiredValues()\"\n pattern=\"^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,4}$\" #emailField=\"ngModel\"\n name=\"email\" required>\n </div>\n\n <div class=\"mb-0\">\n <label class=\"form-label d-flex align-items-center\">\n Phone Number\n <span class=\"required-asterisk\">*</span>\n </label>\n <input type=\"tel\" class=\"form-control rounded-2\"\n [(ngModel)]=\"appointmentPayload.customerDetail.phoneNumber\"\n (ngModelChange)=\"checkRequiredValues()\" simpoNumbersOnly\n [ngClass]=\"{'mobile_number' : appointmentPayload.customerDetail.phoneNumber.length != 10}\">\n </div>\n </div>\n </div>\n <!-- Home Visit address. Customer context: same saved-address flow as\n checkout/BookAppointmentComponent. Admin context (isAdminBooking): no\n logged-in customer account to read a saved address book from, so staff type\n the address manually instead. -->\n <div class=\"w-50\" *ngIf=\"selectedMode === 'HOME_VISIT'\">\n <div class=\"form-section card rounded-3 p-4 h-100\">\n <h3 class=\"section-title\">Home Visit Details</h3>\n\n <ng-container *ngIf=\"!isAdminBooking; else manualHomeVisitAddress\">\n <div class=\"shipping-info\" *ngIf=\"defaultAddress\">\n <div class=\"address-info\">\n <div class=\"address-name\">{{defaultAddress?.receiverName}} ({{defaultAddress?.addressType}})</div>\n <div class=\"address-details\">{{defaultAddress?.addressLine1}}, {{defaultAddress?.cityName}},\n {{defaultAddress?.stateName}}</div>\n <div class=\"mobile-number\">Mobile: {{defaultAddress?.receiverPhone}}</div>\n </div>\n </div>\n <button type=\"button\" class=\"change-address-btn w-100\" (click)=\"changeAddress()\" *ngIf=\"defaultAddress\">\n CHANGE OR ADD ADDRESS\n </button>\n\n <div class=\"addLinks\" *ngIf=\"!defaultAddress\" (click)=\"addAddress()\">\n <mat-icon>add</mat-icon>\n <span class=\"ms-2\">Add an address</span>\n </div>\n </ng-container>\n\n <ng-template #manualHomeVisitAddress>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Receiver Name</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.receiverName\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Receiver Phone</label>\n <input type=\"tel\" class=\"form-control form-input rounded-2\" simpoNumbersOnly [(ngModel)]=\"homeVisitAddress.receiverPhone\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Address Line 1</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.addressLine1\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Address Line 2 (optional)</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.addressLine2\">\n </div>\n <div class=\"d-flex gap-2 mb-3\">\n <div class=\"w-50\">\n <label class=\"form-label d-flex align-items-center\">City</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.city\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"w-50\">\n <label class=\"form-label d-flex align-items-center\">State</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.state\">\n </div>\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Pincode</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" simpoNumbersOnly [(ngModel)]=\"homeVisitAddress.zipCode\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n </ng-template>\n\n <div class=\"mb-0 mt-3\">\n <label class=\"form-label d-flex align-items-center\">Special Instructions</label>\n <textarea class=\"form-control form-textarea rounded-2\"\n placeholder=\"Any special instructions for the professional (optional)\"\n [(ngModel)]=\"instructions\"></textarea>\n </div>\n </div>\n </div>\n </div>\n <div class=\"policies-container\"\n *ngIf=\"cartServices[0]?.cancellationPolicy?.length > 0 || cartServices[0]?.reschedulePolicy?.length\">\n <h2 class=\"policies-title\">Policies & Terms</h2>\n\n <div class=\"policy-items-container d-flex flex-column gap-3\">\n <div class=\"policy-item d-flex justify-content-between align-items-center\"\n (click)=\"showCancellationPolicy = !showCancellationPolicy\">\n <h3 class=\"policy-title\">Cancellation Policy</h3>\n <div class=\"policy-arrow d-flex align-items-center justify-content-center\"><mat-icon\n *ngIf=\"!showCancellationPolicy\">keyboard_arrow_right</mat-icon>\n <mat-icon *ngIf=\"showCancellationPolicy\">keyboard_arrow_down</mat-icon>\n </div>\n </div>\n <div class=\"cancellation_policies d-flex flex-column gap-2 fw-500\"\n *ngIf=\"showCancellationPolicy\">\n <span *ngFor=\"let policy of cartServices[0]?.cancellationPolicy\">•\n {{policy}}</span>\n </div>\n\n <div class=\"policy-item d-flex justify-content-between align-items-center\"\n (click)=\"showReducingPolicy = !showReducingPolicy\">\n <h3 class=\"policy-title\">Rescheduling Policy</h3>\n <div class=\"policy-arrow d-flex align-items-center justify-content-center\"><mat-icon\n *ngIf=\"!showReducingPolicy\">keyboard_arrow_right</mat-icon>\n <mat-icon *ngIf=\"showReducingPolicy\">keyboard_arrow_down</mat-icon>\n </div>\n </div>\n <div class=\"cancellation_policies d-flex flex-column gap-2 fw-500\"\n *ngIf=\"showReducingPolicy\">\n <span *ngFor=\"let policy of cartServices[0]?.reschedulePolicy\">• {{policy}}</span>\n </div>\n </div>\n\n <div class=\"acceptance-section\">\n <input type=\"checkbox\" class=\"custom-checkbox\" [(ngModel)]=\"termsAndConditions\"\n (ngModelChange)=\"checkRequiredValues()\">\n <p class=\"acceptance-text\" style=\"margin-bottom:0px !important\">\n I understand and accept the cancellation & rescheduling policies.\n </p>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #paymentTab>\n <div class=\"w-60 payment_section\">\n <div class=\"w-100 h-100\">\n <div class=\"w-100 d-flex justify-content-center align-items-center flex-column\">\n <div class=\"payment-header mb-3 w-100\">\n <h1 style=\"font-size:24px;font-weight: 600;\">Booking Summary</h1>\n <p class=\"payment-subtitle mb-0\">Review your booking before confirming</p>\n </div>\n\n <div class=\"booking-summary-card\" [ngClass]=\"{'w-100' : screenWidth < 475,'w-50':screenWidth > 475}\">\n <div *ngFor=\"let line of resolvedLines; let i = index\">\n <h2 class=\"summary-title\" *ngIf=\"resolvedLines.length > 1\">Line {{i + 1}}</h2>\n <div class=\"summary-row\" *ngIf=\"line.services.length\">\n <div class=\"summary-label\">Service(s)</div>\n <div class=\"summary-value\"><span *ngFor=\"let s of line.services; let last = last\">{{s.name}}{{last ? '' : ', '}}</span></div>\n </div>\n <div class=\"summary-row\" *ngIf=\"line.staffName || line.selectedStaffName\">\n <div class=\"summary-label\">Professional</div>\n <div class=\"summary-value\">{{line.staffName || line.selectedStaffName}}</div>\n </div>\n <div class=\"summary-row\" *ngIf=\"selectedMode === 'STORE_VISIT'\">\n <div class=\"summary-label\">Location</div>\n <div class=\"summary-value\">{{selectedLocation?.storeName ?? 'N/A'}}</div>\n </div>\n <div class=\"summary-row\">\n <div class=\"summary-label\">Date & Time</div>\n <div class=\"summary-value\">{{selectedDateStr}} at {{line.selectedSlot?.value ?? 'N/A'}}</div>\n </div>\n </div>\n\n <div *ngIf=\"productCartItems.length > 0\">\n <h2 class=\"summary-title\">Products</h2>\n <div class=\"summary-row\" *ngFor=\"let p of productCartItems\">\n <div class=\"summary-label\">{{p.itemName}} x{{p.quantity}}</div>\n <div class=\"summary-value\"><span class=\"currency-symbol\">\u20B9</span>{{(p.sellingPrice ?? p.price ?? 0) * (p.quantity ?? 1)}}</div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #statusTemplate>\n <div class=\"booking-confirmation\">\n <div class=\"success-icon\">\n <div class=\"checkmark-circle\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/881293c1758695578518success.gif\"\n class=\"w-100 h-100\" *ngIf=\"apiStatus\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/325000c1758695564518fail.gif\"\n class=\"w-100 h-100\" *ngIf=\"!apiStatus\">\n </div>\n </div>\n\n <div class=\"confirmation-content\">\n <h1 class=\"confirmation-title\">{{apiStatus ? 'Booking Confirmed!' : 'Booking Failed'}}</h1>\n <p class=\"confirmation-message\">\n {{apiStatus ? 'Your appointment has been successfully booked.':'Failed to book you appointment. Please\n try again later'}}\n </p>\n\n <!-- Video Call link, when already present on the confirmed group (a paid Video Call's\n link only appears once payment verification completes, handled elsewhere - see\n verify-payment.component.ts, not this screen). -->\n <div class=\"video-call-link-card d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus && selectedMode === 'VIDEO_CALL' && bookingGroup?.videoCallLink\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Your Video Call Link</h3>\n <a [href]=\"bookingGroup.videoCallLink\" target=\"_blank\">{{bookingGroup.videoCallLink}}</a>\n </div>\n </div>\n\n <div class=\"d-flex w-100 align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Appointment Details</h3>\n <div class=\"details-row\" *ngFor=\"let line of resolvedLines\">\n <span class=\"detail-label\">{{line.services.length ? (line.services[0].name) : 'Products'}}</span>\n <span class=\"detail-value\">{{selectedDateStr}} at {{line.selectedSlot?.value ?? 'N/A'}}</span>\n </div>\n </div>\n </div>\n\n <div class=\"done-actions d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <ng-container *ngIf=\"!isAdminContext; else adminDoneActions\">\n <button type=\"button\" class=\"done-btn done-btn-primary\" (click)=\"goToMyBookings()\">View my bookings</button>\n <button type=\"button\" class=\"done-btn done-btn-secondary\" (click)=\"goToListing()\">Keep shopping</button>\n </ng-container>\n <ng-template #adminDoneActions>\n <button type=\"button\" class=\"done-btn done-btn-primary\" (click)=\"goToAppointmentsList()\">Back to Appointments List</button>\n <button type=\"button\" class=\"done-btn done-btn-secondary\" (click)=\"bookAnother()\">Book Another</button>\n </ng-template>\n </div>\n </div>\n </div>\n</ng-template>\n", styles: ["@import\"https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&display=swap\";mat-icon{font-family:Material Icons!important}:host{--font-sans: \"Outfit\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;--slate-50: #f8fafc;--slate-100: #f1f5f9;--slate-200: #e2e8f0;--slate-300: #cbd5e1;--slate-400: #94a3b8;--slate-500: #64748b;--slate-600: #475569;--slate-700: #334155;--slate-800: #1e293b;--slate-900: #0f172a;--color-primary: #230860;--color-secondary: #00b6ff;--color-accent-gradient: linear-gradient(135deg, #230860 0%, #00b6ff 100%);--color-success: #10b981;--color-success-bg: #ecfdf5;--color-error: #ef4444;--color-error-bg: #fef2f2;--border-radius-sm: 8px;--border-radius-md: 12px;--border-radius-lg: 16px;--border-radius-xl: 24px;--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, .05);--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, .05), 0 2px 4px -2px rgba(0, 0, 0, .05);--shadow-lg: 0 10px 15px -3px rgba(35, 8, 96, .05), 0 4px 6px -4px rgba(35, 8, 96, .05);--shadow-xl: 0 20px 25px -5px rgba(35, 8, 96, .08), 0 8px 10px -6px rgba(35, 8, 96, .08);--transition-smooth: all .3s cubic-bezier(.4, 0, .2, 1);--transition-bounce: all .4s cubic-bezier(.175, .885, .32, 1.275)}*{box-sizing:border-box;font-family:var(--font-sans)}.main_section{position:relative;height:100vh;background-color:var(--slate-50);display:flex;flex-direction:column;overflow:hidden}.main_header{padding:15px;background:#fff;border-bottom:1px solid var(--slate-100);flex-shrink:0;box-shadow:0 2px 8px #00000003}.header{display:flex;align-items:center;justify-content:space-between}.back-btn{display:flex;align-items:center;justify-content:center;gap:.5rem;padding:.6rem 1.2rem;border-radius:var(--border-radius-md);background:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-700)!important;transition:var(--transition-smooth);font-weight:500;font-size:.9rem;cursor:pointer}.back-btn mat-icon{font-size:18px!important;width:18px!important;height:18px!important;color:var(--slate-700)!important;display:flex;align-items:center;justify-content:center}.back-btn:hover{background:var(--slate-100);transform:translate(-3px);color:var(--slate-900)!important}.header-title{flex-grow:1;text-align:right}.header-title h1{font-size:1.5rem;font-weight:700;margin-bottom:.2rem;color:var(--slate-900)!important;letter-spacing:-.025em}.header-title p{color:var(--slate-500)!important;font-size:.9rem;font-weight:500;margin-bottom:0}.progress-bar{width:100%;height:6px;background-color:var(--slate-100);margin-top:3px;border-radius:10px;overflow:hidden;position:relative}.progress-fill{height:100%;background:var(--color-accent-gradient);border-radius:10px;transition:width .5s cubic-bezier(.4,0,.2,1);position:relative}.progress-fill:after{content:\"\";position:absolute;inset:0;background:linear-gradient(90deg,#fff0,#ffffff4d,#fff0);animation:shimmer 2s infinite linear}@keyframes shimmer{0%{transform:translate(-100%)}to{transform:translate(100%)}}.main_body{flex-grow:1;overflow-y:auto;padding:10px;display:flex;justify-content:center;background:var(--slate-50)}.w-60{width:100%;max-width:800px}.service_section,.location_section,.staff-listing,.date_section,.contact_section,.payment_section,.booking-confirmation{animation:slideUp .5s cubic-bezier(.16,1,.3,1) forwards}@keyframes slideUp{0%{opacity:0;transform:translateY(15px)}to{opacity:1;transform:translateY(0)}}h2{font-size:1.5rem;font-weight:700;color:var(--slate-900)!important;letter-spacing:-.02em;margin-bottom:.3rem}p.subtitle,.service-selection p,.location_section p,.staff-subtitle,.datetime-subtitle,.contact-subtitle,.payment-subtitle{color:var(--slate-500)!important;font-size:13px;margin-bottom:2rem}.services-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding-bottom:2rem}.service-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px}.service-card:hover{border-color:var(--slate-400);transform:translateY(-4px);box-shadow:var(--shadow-lg)}.service-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px;transform:translateY(-2px)}.service-card-selected:before,.location-card-selected:before{content:\"\\2713\";position:absolute;top:-10px;right:-10px;background:var(--color-accent-gradient);color:#fff!important;width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.8rem;font-weight:700;box-shadow:0 4px 8px #2308604d;animation:popIn .3s cubic-bezier(.175,.885,.32,1.275);z-index:10}@keyframes popIn{0%{transform:scale(0)}to{transform:scale(1)}}.service-header{display:flex;align-items:flex-start;gap:1rem;margin-bottom:1rem}.service-icon{width:48px;height:48px;border-radius:var(--border-radius-md);background-color:var(--slate-100);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.service-icon mat-icon{font-size:24px!important;width:24px!important;height:24px!important;color:var(--color-primary)!important}.service-card-selected .service-icon{background:var(--slate-900)}.service-card-selected .service-icon mat-icon{color:#fff!important}.service-info{flex-grow:1}.service-title{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;line-height:1.3;margin-bottom:.2rem}.service-price{font-size:1.25rem;font-weight:800;color:var(--slate-900)!important;text-align:right}.service-duration{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;text-align:right;margin-top:.1rem}.service-description{color:var(--slate-600)!important;font-size:.9rem;line-height:1.5;margin-bottom:1.25rem;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.home-visit{align-self:flex-start;display:inline-flex;align-items:center;gap:.5rem;font-size:.75rem;font-weight:600;color:var(--slate-700)!important;border:1px solid var(--slate-200);padding:.35rem .75rem;border-radius:20px;background-color:var(--slate-50);transition:var(--transition-smooth)}.home-visit img{width:14px;height:14px}.home-visit:before{content:\"\";display:inline-block;width:6px;height:6px;border-radius:50%;background-color:var(--color-success);box-shadow:0 0 #10b98166;animation:pulseGlow 1.8s infinite}@keyframes pulseGlow{0%{box-shadow:0 0 #10b981b3}70%{box-shadow:0 0 0 6px #10b98100}to{box-shadow:0 0 #10b98100}}.location-list{display:flex;flex-direction:column;gap:1.25rem;padding-bottom:2rem}.location-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm)}.location-card:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md)}.location-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px)}.location-content{display:flex;align-items:center}.location-info{display:flex;align-items:center;gap:1.25rem;width:100%}.location-icon{width:52px;height:52px;background-color:var(--slate-100);border-radius:var(--border-radius-md);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.location-icon img{width:28px;height:28px}.location-card-selected .location-icon{background:var(--slate-900)}.location-details{flex-grow:1}.location-details h3{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.3rem}.location-details p{font-size:.9rem;color:var(--slate-500)!important;font-weight:450;line-height:1.4;margin-bottom:0}.search-container{width:100%;margin-bottom:1.25rem}.search-input-wrapper{width:100%;background-color:var(--slate-100);border:1.5px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem 1rem;transition:var(--transition-smooth)}.search-input-wrapper:focus-within{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #23086014}.search-input{font-size:.95rem;font-weight:500;color:var(--slate-900)!important;background:transparent;outline:none;width:100%}.search-input::placeholder{color:var(--slate-400)}.search-icon{color:var(--slate-400)!important;font-size:20px!important;width:20px!important;height:20px!important}.clear-icon{color:var(--slate-400)!important;font-size:18px!important;width:18px!important;height:18px!important;transition:var(--transition-smooth)}.clear-icon:hover{color:var(--slate-600)!important}.staff-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:1rem;max-height:48vh;overflow-y:auto;padding-right:.5rem;padding-bottom:1rem}.staff-list::-webkit-scrollbar{width:6px}.staff-list::-webkit-scrollbar-track{background:var(--slate-50);border-radius:4px}.staff-list::-webkit-scrollbar-thumb{background:var(--slate-200);border-radius:4px}.staff-list::-webkit-scrollbar-thumb:hover{background:var(--slate-300)}.staff-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);margin-bottom:0!important}.staff-card:hover{border-color:var(--slate-300);transform:translateY(-2px);box-shadow:var(--shadow-md)}.staff-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px);margin-bottom:0!important}.staff-avatar{width:48px;height:48px;background:var(--color-accent-gradient);font-size:.95rem;font-weight:700;color:#fff!important;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;box-shadow:0 4px 10px #2308601a;letter-spacing:.5px;transition:var(--transition-smooth)}.staff-card-selected .staff-avatar{transform:scale(1.05)}.staff-name{font-size:1.05rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.2rem;letter-spacing:-.015em}.staff-specialty{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;margin-bottom:0;text-transform:uppercase;letter-spacing:.05em}.selection-indicator{display:flex;align-items:center;justify-content:center;margin-left:auto;padding-left:1rem}.checkmark-circle-mini{width:24px;height:24px;border:2px solid var(--slate-300);border-radius:50%;background-color:#fff;transition:var(--transition-bounce);color:#fff!important}.checkmark-circle-mini.selected{background:var(--color-accent-gradient);border-color:transparent;box-shadow:0 3px 8px #23086040}.checkmark-circle-mini mat-icon{font-size:14px!important;width:14px!important;height:14px!important;color:#fff!important;font-weight:800!important;display:flex;align-items:center;justify-content:center}.main_container{display:flex;gap:2rem;margin-bottom:2rem}.section-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm);height:100%}.section-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:10px!important;letter-spacing:-.01em}.date-picker-container{border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem 1rem;display:flex;align-items:center;justify-content:space-between;transition:var(--transition-smooth);background-color:var(--slate-50);cursor:pointer}.date-picker-container:hover{border-color:var(--slate-400);background-color:#fff}.date-input{font-size:.95rem;font-weight:600;color:var(--slate-800)!important;background:transparent;border:none;outline:none;cursor:pointer;width:100%}.date-picker-container mat-icon{color:var(--color-primary)!important;font-size:20px!important;width:20px!important;height:20px!important}.datepicker-popover{position:absolute;z-index:1000;margin-top:4px;border-radius:var(--border-radius-lg);overflow:hidden;box-shadow:var(--shadow-xl);background:#fff;border:1px solid var(--slate-200);width:320px}::ng-deep .datepicker-calendar{border-radius:var(--border-radius-lg)!important;width:100%!important}::ng-deep .mat-calendar-header{background:var(--color-accent-gradient)!important;color:#fff!important;padding:.5rem!important}::ng-deep .mat-calendar-content{padding:8px!important}::ng-deep .mat-calendar-controls{margin:0!important}::ng-deep .mat-calendar-period-button{color:#fff!important;font-weight:700!important;font-size:1rem!important}::ng-deep .mat-calendar-arrow{fill:#fff!important}::ng-deep .mat-calendar-previous-button,::ng-deep .mat-calendar-next-button{color:#fff!important}::ng-deep .mat-calendar-body-cell{font-size:13px!important}::ng-deep .mat-calendar-body-cell-content{font-weight:600!important;color:var(--slate-800)!important;border-radius:8px!important}::ng-deep .mat-calendar-body-selected{background:var(--color-accent-gradient)!important;color:#fff!important;box-shadow:0 4px 10px #23086033!important}::ng-deep .mat-calendar-body-today:not(.mat-calendar-body-selected){border:2px solid var(--color-primary)!important;color:var(--color-primary)!important}.time_selection{max-height:420px;display:flex;flex-direction:column}.time_selection .row{flex-grow:1;overflow-y:auto;padding-right:.25rem;margin-top:10px}.time-slot{background:#fff;border:1px solid var(--slate-200);font-size:.9rem;font-weight:600;color:var(--slate-800)!important;padding:.75rem .5rem;border-radius:var(--border-radius-md);cursor:pointer;transition:var(--transition-smooth);text-align:center;box-shadow:var(--shadow-sm)}.time-slot:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md);background-color:var(--slate-50)}.time-slot.selected{background:var(--color-accent-gradient);border-color:transparent;color:#fff!important;box-shadow:0 4px 12px #23086033}.form-section{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm)}.form-label{font-size:.85rem;font-weight:600;color:var(--slate-700)!important;margin-bottom:.5rem;text-transform:uppercase;letter-spacing:.05em}.required-asterisk{color:var(--color-error);margin-left:2px}.form-control,.form-input,.form-textarea{width:100%;background-color:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-900)!important;font-size:.95rem;font-weight:500;padding:.75rem 1rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);outline:none}.form-control:focus,.form-input:focus,.form-textarea:focus{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #2308601a}.form-textarea{min-height:100px;resize:vertical}.policies-container{background-color:#fff;border:1px solid var(--slate-200);padding:1.75rem;border-radius:var(--border-radius-lg);margin-top:1.5rem;box-shadow:var(--shadow-sm)}.policies-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1.25rem}.policy-item{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1rem 1.25rem;cursor:pointer;transition:var(--transition-smooth);display:flex;justify-content:space-between;align-items:center}.policy-item:hover{background-color:var(--slate-100);border-color:var(--slate-300)}.policy-title{font-size:.95rem;font-weight:600;color:var(--slate-800)!important}.policy-arrow mat-icon{color:var(--slate-500)!important;transition:var(--transition-smooth)}.cancellation_policies{background-color:var(--slate-50);padding:1rem 1.5rem;border-left:3px solid var(--color-primary);border-radius:0 0 var(--border-radius-md) var(--border-radius-md);margin-top:-4px;margin-bottom:1rem;font-size:.9rem;color:var(--slate-600)!important;line-height:1.5}.acceptance-section{display:flex;align-items:center;gap:.75rem;margin-top:1.5rem}.custom-checkbox{width:20px;height:20px;border:2px solid var(--slate-300);border-radius:6px;cursor:pointer;transition:var(--transition-smooth);position:relative;appearance:none;background-color:#fff;outline:none}.custom-checkbox:checked{background:var(--color-accent-gradient);border-color:transparent}.custom-checkbox:checked:after{content:\"\\2713\";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#fff!important;font-size:.75rem;font-weight:800}.acceptance-text{font-size:.95rem;color:var(--slate-700)!important;font-weight:500;-webkit-user-select:none;user-select:none;line-height:1.4}.booking-summary-card{background-color:#fff;border:1px solid var(--slate-200);padding:2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);position:relative}.booking-summary-card:after{content:\"\";position:absolute;bottom:-1px;left:0;right:0;height:10px;background-image:radial-gradient(circle,white 4px,transparent 5px);background-size:12px 12px;background-position:0 0;z-index:2}.summary-title{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important;border-bottom:2px dashed var(--slate-200);padding-bottom:1rem;margin-bottom:1.5rem;text-align:center}.summary-row{display:flex;justify-content:space-between;align-items:center;padding:.85rem 0;border-bottom:1px solid var(--slate-100)}.summary-label{font-size:.95rem;color:var(--slate-500)!important;font-weight:500}.summary-value{font-size:.95rem;color:var(--slate-900)!important;font-weight:600;text-align:right}.total-row{margin-top:1rem;padding-top:1.25rem;border-top:2px dashed var(--slate-200);border-bottom:none}.total-row .summary-label{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important}.total-row .summary-value{font-size:1.5rem;font-weight:800;color:var(--color-primary)!important}.booking-confirmation{background:#fff;border:1px solid var(--slate-200);padding:3rem 2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);display:flex;flex-direction:column;align-items:center;text-align:center;max-width:500px;margin:0 auto}.success-icon{margin-bottom:1.5rem}.checkmark-circle{width:96px;height:96px;display:flex;align-items:center;justify-content:center}.confirmation-title{font-size:1.5rem;font-weight:800;color:var(--slate-900)!important;margin-bottom:.5rem}.confirmation-message{font-size:1rem;color:var(--slate-500)!important;line-height:1.6;margin-bottom:2rem;font-weight:450}.details-card{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1.5rem;width:100%;margin-bottom:2rem;text-align:left}.details-title{font-size:1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1rem;text-transform:uppercase;letter-spacing:.05em}.details-row{display:flex;justify-content:space-between;padding:.5rem 0;border-bottom:1px dashed var(--slate-200)}.details-row:last-child{border-bottom:none}.detail-label{font-size:.85rem;color:var(--slate-500)!important;font-weight:500}.detail-value{font-size:.9rem;color:var(--slate-900)!important;font-weight:600}.main_footer{border-top:1px solid var(--slate-200);background-color:#fff;padding:15px;flex-shrink:0;display:flex;justify-content:center;box-shadow:0 -4px 12px #00000005}.footer-buttons{width:100%;max-width:800px;display:flex;align-items:center}.back-footer-btn{font-size:.95rem;font-weight:600;color:var(--slate-600)!important;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);cursor:pointer}.back-footer-btn:hover{color:var(--slate-900)!important;background-color:var(--slate-100)}.continue-btn{background:var(--color-accent-gradient);color:#fff!important;border:none;padding:.75rem 2rem;border-radius:var(--border-radius-md);font-size:.95rem!important;font-weight:600;cursor:pointer;transition:var(--transition-smooth);box-shadow:0 4px 10px #23086033;width:max-content!important}.continue-btn:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.continue-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed!important;box-shadow:none!important}.complete_booking,.pay-now-btn{background:var(--color-accent-gradient)!important;color:#fff!important;border:none;padding:.75rem 2.25rem!important;font-size:.95rem!important;font-weight:600;border-radius:var(--border-radius-md)!important;box-shadow:0 4px 12px #23086040;transition:var(--transition-smooth);cursor:pointer;display:flex;align-items:center;gap:.5rem;width:max-content!important}.complete_booking img,.pay-now-btn img{width:20px;height:20px;filter:brightness(0) invert(1)}.complete_booking:hover:not([disabled]),.pay-now-btn:hover:not([disabled]){transform:translateY(-2px);box-shadow:0 6px 18px #23086059}.complete_booking:disabled,.pay-now-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed;box-shadow:none}.service-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding:0;width:100%}.skeleton-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;height:180px;display:flex;flex-direction:column;justify-content:space-between}.skeleton{background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border-radius:4px}@keyframes loading-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}.skeleton-icon{width:48px;height:48px;border-radius:var(--border-radius-md)}.skeleton-title{height:20px;width:60%;margin-bottom:.5rem}.skeleton-price{height:20px;width:30%}.skeleton-duration{height:12px;width:25%;margin-top:.25rem}.skeleton-description{height:14px;width:85%}.skeleton-badge{height:28px;width:120px;border-radius:20px}.time-slot-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:.75rem;width:100%}.skeleton-time-slot{height:42px;border-radius:var(--border-radius-md);background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border:1px solid var(--slate-100)}@media screen and (max-width: 475px){.main_header{padding:1rem}.header-title h1{font-size:1.25rem}.back-btn{padding:.5rem .8rem}.back-btn span{display:none}.main_body{padding:15px}.services-grid{grid-template-columns:1fr;gap:1rem}.staff-list{grid-template-columns:1fr!important;gap:.85rem!important}.service-card,.service-card-selected{min-height:auto}.main_container{flex-direction:column;gap:1.5rem}.datepicker-popover{width:100%;left:0}.details_container{gap:1.5rem}.details_container>.d-flex{flex-direction:column;gap:1.5rem}.details_container>.d-flex>div{width:100%!important}.booking-summary-card{padding:1.25rem}.summary-title{font-size:1.15rem}.total-row .summary-label{font-size:1.1rem}.total-row .summary-value{font-size:1.3rem}.main_footer{padding:1rem}.continue-btn{padding:.75rem 1.5rem}}.shipping-info{border-radius:10px;padding:20px;margin-bottom:12px;border:1px solid var(--slate-200);box-shadow:var(--shadow-sm)}.address-info{margin-bottom:0}.address-name{font-weight:700;margin-bottom:8px;color:var(--slate-900)!important}.address-details{color:var(--slate-500)!important;margin-bottom:8px}.mobile-number{font-weight:700;color:var(--slate-900)!important;font-size:15px}.change-address-btn{font-size:.85rem!important;font-weight:700!important;padding:10px;background:#fff;border:1px solid var(--slate-200);border-radius:8px;color:var(--slate-900)!important;cursor:pointer;transition:var(--transition-smooth)}.change-address-btn:hover{border-color:var(--color-primary);color:var(--color-primary)!important}.addLinks{padding:14px;border:1px dashed var(--slate-300);display:flex;align-items:center;justify-content:center;cursor:pointer;border-radius:8px;color:var(--slate-500)!important;margin-bottom:12px}.addLinks:hover{border-color:var(--color-primary);color:var(--color-primary)!important}h1{font-size:24px!important;font-weight:600!important}.done-actions{display:flex;gap:12px;width:100%}.done-btn{flex:1;max-width:220px;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);font-size:.95rem;font-weight:600;cursor:pointer;transition:var(--transition-smooth);border:none}.done-btn-primary{background:var(--color-accent-gradient);color:#fff!important;box-shadow:0 4px 10px #23086033}.done-btn-primary:hover{transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.done-btn-secondary{background:#fff;color:var(--slate-600)!important;border:1px solid var(--slate-200)}.done-btn-secondary:hover{background-color:var(--slate-100);color:var(--slate-900)!important}\n"] }]
|
|
25982
|
+
args: [{ selector: 'simpo-appointment-booking', standalone: true, imports: [CdkDragPlaceholder, CommonModule, MatIcon, MatFormFieldModule, MatDatepickerModule, FormsModule, MatNativeDateModule, MatInputModule, MatDialogModule, LettersOnlyDirective, NumbersOnlyDirective, ToastModule, HoverDirective, HoverElementsComponent, BackgroundDirective], providers: [MessageService], template: "<p-toast position=\"bottom-right\" [baseZIndex]=\"10000000000\" [autoZIndex]=\"true\"\n [showTransformOptions]=\"screenWidth < 475 ? 'translateY(-100%)' : ''\"></p-toast>\n<section class=\"main_section\" simpoHover (hovering)=\"showEditTabs($event)\"\n [simpoBackground]=\"backgroundInfo\" [style.--color-accent-gradient]=\"accentColor\">\n <div [ngClass]=\"{'hover_effect': edit}\" *ngIf=\"showEditors\">\n <simpo-hover-elements [data]=\"data\" [index]=\"index\" [editOptions]=\"edit\"></simpo-hover-elements>\n </div>\n <div class=\"main_header\">\n <div class=\"header d-flex justify-content-between align-items-center\">\n <div class=\"back-btn d-flex justify-content-center align-items-center cursor-pointer gap-2 mb-3\"\n (click)=\"goBack()\">\n <mat-icon>keyboard_backspace</mat-icon><span *ngIf=\"screenWidth > 475\">Back to Home</span>\n </div>\n <div class=\"header-title\">\n <h1>Book New Appointment</h1>\n <p>{{businessName ?? \"N/A\" }}</p>\n </div>\n </div>\n\n <div class=\"progress-bar\">\n <div class=\"progress-fill\" [style.width]=\"barWidth + '%'\"></div>\n </div>\n </div>\n <div class=\"main_body w-100 d-flex justify-content-center\">\n <ng-container *ngIf=\"selectedTab === 'modeSelection'\">\n <ng-container *ngTemplateOutlet=\"modeSelection\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'serviceListing'\">\n <ng-container *ngIf=\"!skeletonLoader\">\n <ng-container *ngTemplateOutlet=\"serviceListing\"></ng-container>\n </ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'locationListing'\">\n <ng-container *ngTemplateOutlet=\"locationListing\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'staffListing'\">\n <ng-container *ngTemplateOutlet=\"staffListing\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab === 'dateSelection'\">\n <ng-container *ngTemplateOutlet=\"dateSelection\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab==='contactDetails'\">\n <ng-container *ngTemplateOutlet=\"contactDetails\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab==='paymentTab'\">\n <ng-container *ngTemplateOutlet=\"paymentTab\"></ng-container>\n </ng-container>\n <ng-container *ngIf=\"selectedTab==='statusTemplate'\">\n <ng-container *ngTemplateOutlet=\"statusTemplate\"></ng-container>\n </ng-container>\n </div>\n <div class=\"main_footer d-flex justify-content-center align-items-center\"\n *ngIf=\"selectedTab!=='statusTemplate' && selectedTab!=='modeSelection'\">\n <div class=\"footer-buttons\"\n [ngStyle]=\"{'justify-content': selectedTab != 'serviceListing' ? 'space-between' : 'end'}\">\n <span class=\"back-footer-btn cursor-pointer\" (click)=\"previousStep()\"\n *ngIf=\"selectedTab != 'serviceListing'\">Back</span>\n <button class=\"continue-btn\" [disabled]=\"!activeButton\" (click)=\"nextStep()\"\n *ngIf=\"selectedTab!='paymentTab'\">{{!loader ? 'Continue' : 'Loading...'}}</button>\n <button class=\"cursor-pointer d-flex justify-content-evenly align-items-center\"\n *ngIf=\"selectedTab==='paymentTab'\" (click)=\"confirmBooking()\" [disabled]=\"isProcessing\"\n [ngClass]=\"{'pay-now-btn' : bookingGroup?.totalCollectedAtBooking > 0 || !bookingGroup,'complete_booking' : bookingGroup && !bookingGroup?.totalCollectedAtBooking}\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/304012c1753440087996Background.png\">\n {{isProcessing ? 'Please wait...' : 'Confirm Booking'}}\n </button>\n </div>\n </div>\n</section>\n\n<ng-template #modeSelection>\n <div class=\"w-60 service_section\">\n <div class=\"service-selection\">\n <h2>How would you like this?</h2>\n <p>Choose how you'd like to be served</p>\n <div class=\"services-grid\">\n <div class=\"service-card\" (click)=\"selectMode('STORE_VISIT')\">\n <div class=\"service-header\">\n <div class=\"service-icon\"><mat-icon>storefront</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">Visit our Store</div>\n </div>\n </div>\n <div class=\"service-description\">Come to us at one of our locations</div>\n </div>\n <div class=\"service-card\" (click)=\"selectMode('HOME_VISIT')\">\n <div class=\"service-header\">\n <div class=\"service-icon\"><mat-icon>home</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">We come to you</div>\n </div>\n </div>\n <div class=\"service-description\">A professional visits your address</div>\n </div>\n <div class=\"service-card\" (click)=\"selectMode('VIDEO_CALL')\">\n <div class=\"service-header\">\n <div class=\"service-icon\"><mat-icon>videocam</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">Video consultation</div>\n </div>\n </div>\n <div class=\"service-description\">Connect over a video call</div>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #serviceListing>\n <div class=\"w-60 service_section\">\n <div class=\"service-selection\">\n <h2>Select a Service</h2>\n <p>Choose the service(s) you'd like to book<span *ngIf=\"cartServices.length > 0\"> \u2014 {{cartServices.length}} selected</span></p>\n <p *ngIf=\"productCartItems.length > 0\" class=\"cart-hint\">{{productCartItems.length}} product(s) already in your cart \u2014 you can continue without picking a service.</p>\n\n <div class=\"services-grid\">\n <ng-container *ngFor=\"let service of serviceData\">\n <div class=\"\" (click)=\"selectService(service)\"\n [ngClass]=\"{ 'service-card-selected' : service?.selected, 'service-card': !service?.selected }\">\n <div class=\" service-header\">\n <div class=\"service-icon\"><mat-icon>person_outline</mat-icon></div>\n <div class=\"service-info\">\n <div class=\"service-title\">{{service?.name ? service?.name : 'N/A'}}</div>\n </div>\n <div>\n <div class=\"service-price\">\u20B9{{service?.priceDetails?.price ?\n service?.priceDetails?.price : 'N/A' }}</div>\n <div class=\"service-duration\">{{service?.duration ? service?.duration : 'N/A'}} min\n </div>\n </div>\n </div>\n <div class=\"service-description\" *ngIf=\"service?.description\">\n {{service?.description ? service?.description : 'N/A'}}\n </div>\n <div class=\"home-visit\" *ngIf=\"selectedMode === 'STORE_VISIT' && service?.homeAppointmentAvailable\"><img\n src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/982126c1758628863129furniture_16406103.png\">Home\n Visit Available</div>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #locationListing>\n <div class=\"location_section\">\n <div class=\"header flex-column align-items-start\">\n <h1>Choose Location</h1>\n <p>Select where you'd like to receive the service</p>\n </div>\n\n <div class=\"location-list\">\n <ng-container *ngFor=\"let location of locationData\">\n <div (click)=\"selectLocation(location)\"\n [ngClass]=\"{ 'location-card-selected' : location?.selected, 'location-card': !location?.selected }\">\n <div class=\"location-content\">\n <div class=\"location-info\">\n <div class=\"location-icon\"><img\n src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/427226c1758629157758store_3171510.png\">\n </div>\n <div class=\"location-details\">\n <div class=\"d-flex justify-content-between align-items-center\">\n <h3>{{location?.storeName ? location?.storeName : 'N/A'}}</h3>\n </div>\n <p>{{location?.addressDetails?.addressLine}}, {{location?.addressDetails?.city}},\n {{location?.addressDetails?.state}} {{location?.pincode}}</p>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n</ng-template>\n\n<ng-template #staffListing>\n <div class=\"w-60 overflow-hidden staff-listing\">\n <div class=\"d-flex w-100 h-100\">\n <div class=\"w-100\">\n <div class=\"staff-header mb-3\">\n <h1>Select Staff Member</h1>\n <p class=\"staff-subtitle mb-0\">Choose your preferred professional</p>\n </div>\n\n <div class=\"search-container mb-4\">\n <div class=\"search-input-wrapper d-flex align-items-center\">\n <mat-icon class=\"search-icon me-2\">search</mat-icon>\n <input type=\"text\" class=\"search-input border-0 flex-grow-1\" placeholder=\"Search staff member by name...\" [(ngModel)]=\"staffSearchQuery\">\n <mat-icon class=\"clear-icon cursor-pointer ms-2\" *ngIf=\"staffSearchQuery\" (click)=\"staffSearchQuery = ''\">close</mat-icon>\n </div>\n </div>\n\n <!-- Pure product-only line: one flat staff list, same as the old single-service flow -->\n <div class=\"staff-list\" *ngIf=\"cartServices.length === 0\">\n <ng-container *ngFor=\"let staff of filteredStaff\">\n <div class=\"card rounded-3 p-3\" (click)=\"selectStaffForProductOnlyLine(staff)\"\n [ngClass]=\"{ 'staff-card-selected' : staff?.selected, 'staff-card': !staff?.selected }\">\n <div class=\"d-flex align-items-center justify-content-between w-100\">\n <div class=\"d-flex align-items-center flex-grow-1\">\n <div class=\"staff-avatar rounded-circle d-flex align-items-center justify-content-center me-4\">\n {{staff?.staffName.slice(0,2).toUpperCase()}}\n </div>\n <div class=\"staff-details flex-grow-1\">\n <h3 class=\"staff-name\">{{(staff?.staffName ? staff?.staffName : 'N/A') | titlecase}}</h3>\n <p class=\"staff-specialty\">{{(businessName && businessName !== 'N/A') ? businessName : 'Booking Specialist'}}</p>\n </div>\n </div>\n <div class=\"selection-indicator\">\n <div class=\"checkmark-circle-mini d-flex align-items-center justify-content-center\" [class.selected]=\"staff?.selected\">\n <mat-icon *ngIf=\"staff?.selected\">check</mat-icon>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n\n <!-- Bundled cart: one pool per line that resolution couldn't collapse to a single provider -->\n <ng-container *ngIf=\"cartServices.length > 0\">\n <div class=\"staff-line-group mb-4\" *ngFor=\"let line of resolvedLines\">\n <ng-container *ngIf=\"line.candidateStaffPool?.length\">\n <h4 class=\"mb-2\">For {{line.services.length}} service(s): {{ (line.services | slice:0:3).length ? '' : '' }}<span *ngFor=\"let s of line.services; let last = last\">{{s.name}}{{last ? '' : ', '}}</span></h4>\n <div class=\"staff-list mb-3\">\n <ng-container *ngFor=\"let staff of line.candidateStaffPool\">\n <div class=\"card rounded-3 p-3\" (click)=\"selectStaffForLine(line, staff)\"\n [ngClass]=\"{ 'staff-card-selected' : line.selectedStaffId === staff.id, 'staff-card': line.selectedStaffId !== staff.id }\">\n <div class=\"d-flex align-items-center justify-content-between w-100\">\n <div class=\"d-flex align-items-center flex-grow-1\">\n <div class=\"staff-avatar rounded-circle d-flex align-items-center justify-content-center me-4\">\n {{staff?.name?.slice(0,2)?.toUpperCase()}}\n </div>\n <div class=\"staff-details flex-grow-1\">\n <h3 class=\"staff-name\">{{(staff?.name ? staff?.name : 'N/A') | titlecase}}</h3>\n </div>\n </div>\n <div class=\"selection-indicator\">\n <div class=\"checkmark-circle-mini d-flex align-items-center justify-content-center\" [class.selected]=\"line.selectedStaffId === staff.id\">\n <mat-icon *ngIf=\"line.selectedStaffId === staff.id\">check</mat-icon>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n </ng-container>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #dateSelection>\n <div class=\"w-60 date_section\">\n <div class=\"row justify-content-center h-100\">\n <div class=\"col-12 h-100\">\n <div class=\"datetime-header mb-2\">\n <h1>Select Date & Time</h1>\n <p class=\"datetime-subtitle mb-0\">Choose when you'd like your appointment</p>\n </div>\n\n <div class=\"d-flex gap-4 main_container\">\n <div [ngClass]=\"{'w-50' : screenWidth > 475 , 'w-100':screenWidth < 475}\">\n <div class=\"section-card card rounded-3 p-4 h-100\">\n <h3 class=\"section-title\">Select Date</h3>\n\n <div class=\"date-picker-container d-flex align-items-center justify-content-between\"\n (click)=\"$event.stopPropagation()\">\n <input type=\"text\" class=\"date-input border-0 rounded-2\" placeholder=\"dd-mm-yyyy\"\n [value]=\"selectedDateStr\" readonly (click)=\"toggleCalendar($event)\">\n\n <mat-icon class=\"ms-2\" (click)=\"toggleCalendar($event)\">calendar_today</mat-icon>\n </div>\n <div class=\"position-relative\" (click)=\"$event.stopPropagation()\">\n <div class=\"datepicker-popover\" *ngIf=\"showCalendar\">\n <mat-calendar [(selected)]=\"selectedDate\" [dateFilter]=\"dateFilter\"\n (selectedChange)=\"onDateSelected($event)\" class=\"datepicker-calendar\">\n </mat-calendar>\n </div>\n </div>\n </div>\n </div>\n\n <!-- One slot-picker per resolved line, side by side when there's more than one (design doc \u00A73b) -->\n <div class=\"time_selection\" [ngClass]=\"{'w-50' : screenWidth > 475 , 'w-100':screenWidth < 475}\" *ngIf=\"resolvedLines.length <= 1\">\n <div class=\"section-card card h-100 rounded-3 p-4\">\n <h3 class=\"section-title\">Available Times</h3>\n <div class=\"row g-2 mb-4 overflow-scroll\">\n <ng-container *ngIf=\"!skeletonLoader && resolvedLines[0]\">\n <div class=\"col-4\" *ngFor=\"let time of resolvedLines[0].slots\">\n <div class=\"time-slot rounded-2\" [class.selected]=\"time.selected\"\n (click)=\"selectSlotForLine(resolvedLines[0], time)\">{{time ? time?.value : 'N/A'}}</div>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Multi-line case: each line gets its own full-width card with a staff header -->\n <div class=\"d-flex gap-4 main_container flex-wrap\" *ngIf=\"resolvedLines.length > 1\">\n <div class=\"w-100\" *ngFor=\"let line of resolvedLines\">\n <div class=\"section-card card rounded-3 p-4\">\n <h3 class=\"section-title\">Professional: {{line.staffName || line.selectedStaffName}}</h3>\n <p class=\"mb-2\" *ngIf=\"line.services.length\"><span *ngFor=\"let s of line.services; let last = last\">{{s.name}}{{last ? '' : ', '}}</span></p>\n <div class=\"row g-2 mb-2 overflow-scroll\">\n <ng-container *ngIf=\"!line.slotsLoading\">\n <div class=\"col-4\" *ngFor=\"let time of line.slots\">\n <div class=\"time-slot rounded-2\" [class.selected]=\"time.selected\"\n (click)=\"selectSlotForLine(line, time)\">{{time ? time?.value : 'N/A'}}</div>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #contactDetails>\n <div class=\"w-60 contact_section\">\n <div class=\"contact-header mb-2\">\n <h1>Contact Details</h1>\n <p class=\"contact-subtitle mb-0\">Provide your contact information</p>\n </div>\n\n <div class=\"d-flex gap-3 details_container flex-column w-100\">\n <div class=\"d-flex gap-4\">\n <div [ngClass]=\"{'w-50' : selectedMode === 'HOME_VISIT', 'w-100' : selectedMode !== 'HOME_VISIT'}\">\n <div class=\"form-section card rounded-3 p-4 h-100\">\n <h3 class=\"section-title\">Personal Information</h3>\n\n <div class=\"mb-4\">\n <label class=\"form-label d-flex align-items-center\">\n Full Name\n <span class=\"required-asterisk\">*</span>\n </label>\n <input type=\"text\" class=\"form-control form-input rounded-2\"\n [(ngModel)]=\"appointmentPayload.customerDetail.name\"\n (ngModelChange)=\"checkRequiredValues()\" simpoLettersOnly>\n </div>\n\n <div class=\"mb-4\">\n <label class=\"form-label d-flex align-items-center\">\n Email Address\n <span class=\"required-asterisk\">*</span>\n </label>\n <input type=\"email\" class=\"form-control form-input rounded-2\"\n [(ngModel)]=\"appointmentPayload.customerDetail.email\"\n (ngModelChange)=\"checkRequiredValues()\"\n pattern=\"^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,4}$\" #emailField=\"ngModel\"\n name=\"email\" required>\n </div>\n\n <div class=\"mb-0\">\n <label class=\"form-label d-flex align-items-center\">\n Phone Number\n <span class=\"required-asterisk\">*</span>\n </label>\n <input type=\"tel\" class=\"form-control rounded-2\"\n [(ngModel)]=\"appointmentPayload.customerDetail.phoneNumber\"\n (ngModelChange)=\"checkRequiredValues()\" simpoNumbersOnly\n [ngClass]=\"{'mobile_number' : appointmentPayload.customerDetail.phoneNumber.length != 10}\">\n </div>\n </div>\n </div>\n <!-- Home Visit address. Customer context: same saved-address flow as\n checkout/BookAppointmentComponent. Admin context (isAdminBooking): no\n logged-in customer account to read a saved address book from, so staff type\n the address manually instead. -->\n <div class=\"w-50\" *ngIf=\"selectedMode === 'HOME_VISIT'\">\n <div class=\"form-section card rounded-3 p-4 h-100\">\n <h3 class=\"section-title\">Home Visit Details</h3>\n\n <ng-container *ngIf=\"!isAdminBooking; else manualHomeVisitAddress\">\n <div class=\"shipping-info\" *ngIf=\"defaultAddress\">\n <div class=\"address-info\">\n <div class=\"address-name\">{{defaultAddress?.receiverName}} ({{defaultAddress?.addressType}})</div>\n <div class=\"address-details\">{{defaultAddress?.addressLine1}}, {{defaultAddress?.cityName}},\n {{defaultAddress?.stateName}}</div>\n <div class=\"mobile-number\">Mobile: {{defaultAddress?.receiverPhone}}</div>\n </div>\n </div>\n <button type=\"button\" class=\"change-address-btn w-100\" (click)=\"changeAddress()\" *ngIf=\"defaultAddress\">\n CHANGE OR ADD ADDRESS\n </button>\n\n <div class=\"addLinks\" *ngIf=\"!defaultAddress\" (click)=\"addAddress()\">\n <mat-icon>add</mat-icon>\n <span class=\"ms-2\">Add an address</span>\n </div>\n </ng-container>\n\n <ng-template #manualHomeVisitAddress>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Receiver Name</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.receiverName\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Receiver Phone</label>\n <input type=\"tel\" class=\"form-control form-input rounded-2\" simpoNumbersOnly [(ngModel)]=\"homeVisitAddress.receiverPhone\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Address Line 1</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.addressLine1\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Address Line 2 (optional)</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.addressLine2\">\n </div>\n <div class=\"d-flex gap-2 mb-3\">\n <div class=\"w-50\">\n <label class=\"form-label d-flex align-items-center\">City</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.city\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n <div class=\"w-50\">\n <label class=\"form-label d-flex align-items-center\">State</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" [(ngModel)]=\"homeVisitAddress.state\">\n </div>\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center\">Pincode</label>\n <input type=\"text\" class=\"form-control form-input rounded-2\" simpoNumbersOnly [(ngModel)]=\"homeVisitAddress.zipCode\" (ngModelChange)=\"checkRequiredValues()\">\n </div>\n </ng-template>\n\n <div class=\"mb-0 mt-3\">\n <label class=\"form-label d-flex align-items-center\">Special Instructions</label>\n <textarea class=\"form-control form-textarea rounded-2\"\n placeholder=\"Any special instructions for the professional (optional)\"\n [(ngModel)]=\"instructions\"></textarea>\n </div>\n </div>\n </div>\n </div>\n <div class=\"policies-container\"\n *ngIf=\"cartServices[0]?.cancellationPolicy?.length > 0 || cartServices[0]?.reschedulePolicy?.length\">\n <h2 class=\"policies-title\">Policies & Terms</h2>\n\n <div class=\"policy-items-container d-flex flex-column gap-3\">\n <div class=\"policy-item d-flex justify-content-between align-items-center\"\n (click)=\"showCancellationPolicy = !showCancellationPolicy\">\n <h3 class=\"policy-title\">Cancellation Policy</h3>\n <div class=\"policy-arrow d-flex align-items-center justify-content-center\"><mat-icon\n *ngIf=\"!showCancellationPolicy\">keyboard_arrow_right</mat-icon>\n <mat-icon *ngIf=\"showCancellationPolicy\">keyboard_arrow_down</mat-icon>\n </div>\n </div>\n <div class=\"cancellation_policies d-flex flex-column gap-2 fw-500\"\n *ngIf=\"showCancellationPolicy\">\n <span *ngFor=\"let policy of cartServices[0]?.cancellationPolicy\">•\n {{policy}}</span>\n </div>\n\n <div class=\"policy-item d-flex justify-content-between align-items-center\"\n (click)=\"showReducingPolicy = !showReducingPolicy\">\n <h3 class=\"policy-title\">Rescheduling Policy</h3>\n <div class=\"policy-arrow d-flex align-items-center justify-content-center\"><mat-icon\n *ngIf=\"!showReducingPolicy\">keyboard_arrow_right</mat-icon>\n <mat-icon *ngIf=\"showReducingPolicy\">keyboard_arrow_down</mat-icon>\n </div>\n </div>\n <div class=\"cancellation_policies d-flex flex-column gap-2 fw-500\"\n *ngIf=\"showReducingPolicy\">\n <span *ngFor=\"let policy of cartServices[0]?.reschedulePolicy\">• {{policy}}</span>\n </div>\n </div>\n\n <div class=\"acceptance-section\">\n <input type=\"checkbox\" class=\"custom-checkbox\" [(ngModel)]=\"termsAndConditions\"\n (ngModelChange)=\"checkRequiredValues()\">\n <p class=\"acceptance-text\" style=\"margin-bottom:0px !important\">\n I understand and accept the cancellation & rescheduling policies.\n </p>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #paymentTab>\n <div class=\"w-60 payment_section\">\n <div class=\"w-100 h-100\">\n <div class=\"w-100 d-flex justify-content-center align-items-center flex-column\">\n <div class=\"payment-header mb-3 w-100\">\n <h1 style=\"font-size:24px;font-weight: 600;\">Booking Summary</h1>\n <p class=\"payment-subtitle mb-0\">Review your booking before confirming</p>\n </div>\n\n <div class=\"booking-summary-card\" [ngClass]=\"{'w-100' : screenWidth < 475,'w-50':screenWidth > 475}\">\n <div *ngFor=\"let line of resolvedLines; let i = index\">\n <h2 class=\"summary-title\" *ngIf=\"resolvedLines.length > 1\">Line {{i + 1}}</h2>\n <div class=\"summary-row\" *ngIf=\"line.services.length\">\n <div class=\"summary-label\">Service(s)</div>\n <div class=\"summary-value\"><span *ngFor=\"let s of line.services; let last = last\">{{s.name}}{{last ? '' : ', '}}</span></div>\n </div>\n <div class=\"summary-row\" *ngIf=\"line.staffName || line.selectedStaffName\">\n <div class=\"summary-label\">Professional</div>\n <div class=\"summary-value\">{{line.staffName || line.selectedStaffName}}</div>\n </div>\n <div class=\"summary-row\" *ngIf=\"selectedMode === 'STORE_VISIT'\">\n <div class=\"summary-label\">Location</div>\n <div class=\"summary-value\">{{selectedLocation?.storeName ?? 'N/A'}}</div>\n </div>\n <div class=\"summary-row\">\n <div class=\"summary-label\">Date & Time</div>\n <div class=\"summary-value\">{{selectedDateStr}} at {{line.selectedSlot?.value ?? 'N/A'}}</div>\n </div>\n </div>\n\n <div *ngIf=\"productCartItems.length > 0\">\n <h2 class=\"summary-title\">Products</h2>\n <div class=\"summary-row\" *ngFor=\"let p of productCartItems\">\n <div class=\"summary-label\">{{p.itemName}} x{{p.quantity}}</div>\n <div class=\"summary-value\"><span class=\"currency-symbol\">\u20B9</span>{{(p.sellingPrice ?? p.price ?? 0) * (p.quantity ?? 1)}}</div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #statusTemplate>\n <div class=\"booking-confirmation\">\n <div class=\"success-icon\">\n <div class=\"checkmark-circle\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/881293c1758695578518success.gif\"\n class=\"w-100 h-100\" *ngIf=\"apiStatus\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/325000c1758695564518fail.gif\"\n class=\"w-100 h-100\" *ngIf=\"!apiStatus\">\n </div>\n </div>\n\n <div class=\"confirmation-content\">\n <h1 class=\"confirmation-title\">{{apiStatus ? 'Booking Confirmed!' : 'Booking Failed'}}</h1>\n <p class=\"confirmation-message\">\n {{apiStatus ? 'Your appointment has been successfully booked.':'Failed to book you appointment. Please\n try again later'}}\n </p>\n\n <!-- Video Call link, when already present on the confirmed group (a paid Video Call's\n link only appears once payment verification completes, handled elsewhere - see\n verify-payment.component.ts, not this screen). -->\n <div class=\"video-call-link-card d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus && selectedMode === 'VIDEO_CALL' && bookingGroup?.videoCallLink\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Your Video Call Link</h3>\n <a [href]=\"bookingGroup.videoCallLink\" target=\"_blank\">{{bookingGroup.videoCallLink}}</a>\n </div>\n </div>\n\n <div class=\"d-flex w-100 align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Appointment Details</h3>\n <div class=\"details-row\" *ngFor=\"let line of resolvedLines\">\n <span class=\"detail-label\">{{line.services.length ? (line.services[0].name) : 'Products'}}</span>\n <span class=\"detail-value\">{{selectedDateStr}} at {{line.selectedSlot?.value ?? 'N/A'}}</span>\n </div>\n </div>\n </div>\n\n <div class=\"done-actions d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <ng-container *ngIf=\"!isAdminContext; else adminDoneActions\">\n <button type=\"button\" class=\"done-btn done-btn-primary\" (click)=\"goToMyBookings()\">View my bookings</button>\n <button type=\"button\" class=\"done-btn done-btn-secondary\" (click)=\"goToListing()\">Keep shopping</button>\n </ng-container>\n <ng-template #adminDoneActions>\n <button type=\"button\" class=\"done-btn done-btn-primary\" (click)=\"goToAppointmentsList()\">Back to Appointments List</button>\n <button type=\"button\" class=\"done-btn done-btn-secondary\" (click)=\"bookAnother()\">Book Another</button>\n </ng-template>\n </div>\n </div>\n </div>\n</ng-template>\n", styles: ["@import\"https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&display=swap\";mat-icon{font-family:Material Icons!important}:host{--font-sans: \"Outfit\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;--slate-50: #f8fafc;--slate-100: #f1f5f9;--slate-200: #e2e8f0;--slate-300: #cbd5e1;--slate-400: #94a3b8;--slate-500: #64748b;--slate-600: #475569;--slate-700: #334155;--slate-800: #1e293b;--slate-900: #0f172a;--color-primary: #230860;--color-secondary: #00b6ff;--color-accent-gradient: linear-gradient(135deg, #230860 0%, #00b6ff 100%);--color-success: #10b981;--color-success-bg: #ecfdf5;--color-error: #ef4444;--color-error-bg: #fef2f2;--border-radius-sm: 8px;--border-radius-md: 12px;--border-radius-lg: 16px;--border-radius-xl: 24px;--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, .05);--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, .05), 0 2px 4px -2px rgba(0, 0, 0, .05);--shadow-lg: 0 10px 15px -3px rgba(35, 8, 96, .05), 0 4px 6px -4px rgba(35, 8, 96, .05);--shadow-xl: 0 20px 25px -5px rgba(35, 8, 96, .08), 0 8px 10px -6px rgba(35, 8, 96, .08);--transition-smooth: all .3s cubic-bezier(.4, 0, .2, 1);--transition-bounce: all .4s cubic-bezier(.175, .885, .32, 1.275)}*{box-sizing:border-box;font-family:var(--font-sans)}.main_section{position:relative;height:100vh;background-color:var(--slate-50);display:flex;flex-direction:column;overflow:hidden}.hover_effect{position:absolute;width:100%;top:0;left:0;height:100%}.main_header{padding:15px;background:#fff;border-bottom:1px solid var(--slate-100);flex-shrink:0;box-shadow:0 2px 8px #00000003}.header{display:flex;align-items:center;justify-content:space-between}.back-btn{display:flex;align-items:center;justify-content:center;gap:.5rem;padding:.6rem 1.2rem;border-radius:var(--border-radius-md);background:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-700)!important;transition:var(--transition-smooth);font-weight:500;font-size:.9rem;cursor:pointer}.back-btn mat-icon{font-size:18px!important;width:18px!important;height:18px!important;color:var(--slate-700)!important;display:flex;align-items:center;justify-content:center}.back-btn:hover{background:var(--slate-100);transform:translate(-3px);color:var(--slate-900)!important}.header-title{flex-grow:1;text-align:right}.header-title h1{font-size:1.5rem;font-weight:700;margin-bottom:.2rem;color:var(--slate-900)!important;letter-spacing:-.025em}.header-title p{color:var(--slate-500)!important;font-size:.9rem;font-weight:500;margin-bottom:0}.progress-bar{width:100%;height:6px;background-color:var(--slate-100);margin-top:3px;border-radius:10px;overflow:hidden;position:relative}.progress-fill{height:100%;background:var(--color-accent-gradient);border-radius:10px;transition:width .5s cubic-bezier(.4,0,.2,1);position:relative}.progress-fill:after{content:\"\";position:absolute;inset:0;background:linear-gradient(90deg,#fff0,#ffffff4d,#fff0);animation:shimmer 2s infinite linear}@keyframes shimmer{0%{transform:translate(-100%)}to{transform:translate(100%)}}.main_body{flex-grow:1;overflow-y:auto;padding:10px;display:flex;justify-content:center;background:var(--slate-50)}.w-60{width:100%;max-width:800px}.service_section,.location_section,.staff-listing,.date_section,.contact_section,.payment_section,.booking-confirmation{animation:slideUp .5s cubic-bezier(.16,1,.3,1) forwards}@keyframes slideUp{0%{opacity:0;transform:translateY(15px)}to{opacity:1;transform:translateY(0)}}h2{font-size:1.5rem;font-weight:700;color:var(--slate-900)!important;letter-spacing:-.02em;margin-bottom:.3rem}p.subtitle,.service-selection p,.location_section p,.staff-subtitle,.datetime-subtitle,.contact-subtitle,.payment-subtitle{color:var(--slate-500)!important;font-size:13px;margin-bottom:2rem}.services-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding-bottom:2rem}.service-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px}.service-card:hover{border-color:var(--slate-400);transform:translateY(-4px);box-shadow:var(--shadow-lg)}.service-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px;transform:translateY(-2px)}.service-card-selected:before,.location-card-selected:before{content:\"\\2713\";position:absolute;top:-10px;right:-10px;background:var(--color-accent-gradient);color:#fff!important;width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.8rem;font-weight:700;box-shadow:0 4px 8px #2308604d;animation:popIn .3s cubic-bezier(.175,.885,.32,1.275);z-index:10}@keyframes popIn{0%{transform:scale(0)}to{transform:scale(1)}}.service-header{display:flex;align-items:flex-start;gap:1rem;margin-bottom:1rem}.service-icon{width:48px;height:48px;border-radius:var(--border-radius-md);background-color:var(--slate-100);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.service-icon mat-icon{font-size:24px!important;width:24px!important;height:24px!important;color:var(--color-primary)!important}.service-card-selected .service-icon{background:var(--slate-900)}.service-card-selected .service-icon mat-icon{color:#fff!important}.service-info{flex-grow:1}.service-title{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;line-height:1.3;margin-bottom:.2rem}.service-price{font-size:1.25rem;font-weight:800;color:var(--slate-900)!important;text-align:right}.service-duration{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;text-align:right;margin-top:.1rem}.service-description{color:var(--slate-600)!important;font-size:.9rem;line-height:1.5;margin-bottom:1.25rem;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.home-visit{align-self:flex-start;display:inline-flex;align-items:center;gap:.5rem;font-size:.75rem;font-weight:600;color:var(--slate-700)!important;border:1px solid var(--slate-200);padding:.35rem .75rem;border-radius:20px;background-color:var(--slate-50);transition:var(--transition-smooth)}.home-visit img{width:14px;height:14px}.home-visit:before{content:\"\";display:inline-block;width:6px;height:6px;border-radius:50%;background-color:var(--color-success);box-shadow:0 0 #10b98166;animation:pulseGlow 1.8s infinite}@keyframes pulseGlow{0%{box-shadow:0 0 #10b981b3}70%{box-shadow:0 0 0 6px #10b98100}to{box-shadow:0 0 #10b98100}}.location-list{display:flex;flex-direction:column;gap:1.25rem;padding-bottom:2rem}.location-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm)}.location-card:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md)}.location-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px)}.location-content{display:flex;align-items:center}.location-info{display:flex;align-items:center;gap:1.25rem;width:100%}.location-icon{width:52px;height:52px;background-color:var(--slate-100);border-radius:var(--border-radius-md);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.location-icon img{width:28px;height:28px}.location-card-selected .location-icon{background:var(--slate-900)}.location-details{flex-grow:1}.location-details h3{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.3rem}.location-details p{font-size:.9rem;color:var(--slate-500)!important;font-weight:450;line-height:1.4;margin-bottom:0}.search-container{width:100%;margin-bottom:1.25rem}.search-input-wrapper{width:100%;background-color:var(--slate-100);border:1.5px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem 1rem;transition:var(--transition-smooth)}.search-input-wrapper:focus-within{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #23086014}.search-input{font-size:.95rem;font-weight:500;color:var(--slate-900)!important;background:transparent;outline:none;width:100%}.search-input::placeholder{color:var(--slate-400)}.search-icon{color:var(--slate-400)!important;font-size:20px!important;width:20px!important;height:20px!important}.clear-icon{color:var(--slate-400)!important;font-size:18px!important;width:18px!important;height:18px!important;transition:var(--transition-smooth)}.clear-icon:hover{color:var(--slate-600)!important}.staff-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:1rem;max-height:48vh;overflow-y:auto;padding-right:.5rem;padding-bottom:1rem}.staff-list::-webkit-scrollbar{width:6px}.staff-list::-webkit-scrollbar-track{background:var(--slate-50);border-radius:4px}.staff-list::-webkit-scrollbar-thumb{background:var(--slate-200);border-radius:4px}.staff-list::-webkit-scrollbar-thumb:hover{background:var(--slate-300)}.staff-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);margin-bottom:0!important}.staff-card:hover{border-color:var(--slate-300);transform:translateY(-2px);box-shadow:var(--shadow-md)}.staff-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px);margin-bottom:0!important}.staff-avatar{width:48px;height:48px;background:var(--color-accent-gradient);font-size:.95rem;font-weight:700;color:#fff!important;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;box-shadow:0 4px 10px #2308601a;letter-spacing:.5px;transition:var(--transition-smooth)}.staff-card-selected .staff-avatar{transform:scale(1.05)}.staff-name{font-size:1.05rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.2rem;letter-spacing:-.015em}.staff-specialty{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;margin-bottom:0;text-transform:uppercase;letter-spacing:.05em}.selection-indicator{display:flex;align-items:center;justify-content:center;margin-left:auto;padding-left:1rem}.checkmark-circle-mini{width:24px;height:24px;border:2px solid var(--slate-300);border-radius:50%;background-color:#fff;transition:var(--transition-bounce);color:#fff!important}.checkmark-circle-mini.selected{background:var(--color-accent-gradient);border-color:transparent;box-shadow:0 3px 8px #23086040}.checkmark-circle-mini mat-icon{font-size:14px!important;width:14px!important;height:14px!important;color:#fff!important;font-weight:800!important;display:flex;align-items:center;justify-content:center}.main_container{display:flex;gap:2rem;margin-bottom:2rem}.section-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm);height:100%}.section-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:10px!important;letter-spacing:-.01em}.date-picker-container{border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem 1rem;display:flex;align-items:center;justify-content:space-between;transition:var(--transition-smooth);background-color:var(--slate-50);cursor:pointer}.date-picker-container:hover{border-color:var(--slate-400);background-color:#fff}.date-input{font-size:.95rem;font-weight:600;color:var(--slate-800)!important;background:transparent;border:none;outline:none;cursor:pointer;width:100%}.date-picker-container mat-icon{color:var(--color-primary)!important;font-size:20px!important;width:20px!important;height:20px!important}.datepicker-popover{position:absolute;z-index:1000;margin-top:4px;border-radius:var(--border-radius-lg);overflow:hidden;box-shadow:var(--shadow-xl);background:#fff;border:1px solid var(--slate-200);width:320px}::ng-deep .datepicker-calendar{border-radius:var(--border-radius-lg)!important;width:100%!important}::ng-deep .mat-calendar-header{background:var(--color-accent-gradient)!important;color:#fff!important;padding:.5rem!important}::ng-deep .mat-calendar-content{padding:8px!important}::ng-deep .mat-calendar-controls{margin:0!important}::ng-deep .mat-calendar-period-button{color:#fff!important;font-weight:700!important;font-size:1rem!important}::ng-deep .mat-calendar-arrow{fill:#fff!important}::ng-deep .mat-calendar-previous-button,::ng-deep .mat-calendar-next-button{color:#fff!important}::ng-deep .mat-calendar-body-cell{font-size:13px!important}::ng-deep .mat-calendar-body-cell-content{font-weight:600!important;color:var(--slate-800)!important;border-radius:8px!important}::ng-deep .mat-calendar-body-selected{background:var(--color-accent-gradient)!important;color:#fff!important;box-shadow:0 4px 10px #23086033!important}::ng-deep .mat-calendar-body-today:not(.mat-calendar-body-selected){border:2px solid var(--color-primary)!important;color:var(--color-primary)!important}.time_selection{max-height:420px;display:flex;flex-direction:column}.time_selection .row{flex-grow:1;overflow-y:auto;padding-right:.25rem;margin-top:10px}.time-slot{background:#fff;border:1px solid var(--slate-200);font-size:.9rem;font-weight:600;color:var(--slate-800)!important;padding:.75rem .5rem;border-radius:var(--border-radius-md);cursor:pointer;transition:var(--transition-smooth);text-align:center;box-shadow:var(--shadow-sm)}.time-slot:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md);background-color:var(--slate-50)}.time-slot.selected{background:var(--color-accent-gradient);border-color:transparent;color:#fff!important;box-shadow:0 4px 12px #23086033}.form-section{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm)}.form-label{font-size:.85rem;font-weight:600;color:var(--slate-700)!important;margin-bottom:.5rem;text-transform:uppercase;letter-spacing:.05em}.required-asterisk{color:var(--color-error);margin-left:2px}.form-control,.form-input,.form-textarea{width:100%;background-color:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-900)!important;font-size:.95rem;font-weight:500;padding:.75rem 1rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);outline:none}.form-control:focus,.form-input:focus,.form-textarea:focus{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #2308601a}.form-textarea{min-height:100px;resize:vertical}.policies-container{background-color:#fff;border:1px solid var(--slate-200);padding:1.75rem;border-radius:var(--border-radius-lg);margin-top:1.5rem;box-shadow:var(--shadow-sm)}.policies-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1.25rem}.policy-item{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1rem 1.25rem;cursor:pointer;transition:var(--transition-smooth);display:flex;justify-content:space-between;align-items:center}.policy-item:hover{background-color:var(--slate-100);border-color:var(--slate-300)}.policy-title{font-size:.95rem;font-weight:600;color:var(--slate-800)!important}.policy-arrow mat-icon{color:var(--slate-500)!important;transition:var(--transition-smooth)}.cancellation_policies{background-color:var(--slate-50);padding:1rem 1.5rem;border-left:3px solid var(--color-primary);border-radius:0 0 var(--border-radius-md) var(--border-radius-md);margin-top:-4px;margin-bottom:1rem;font-size:.9rem;color:var(--slate-600)!important;line-height:1.5}.acceptance-section{display:flex;align-items:center;gap:.75rem;margin-top:1.5rem}.custom-checkbox{width:20px;height:20px;border:2px solid var(--slate-300);border-radius:6px;cursor:pointer;transition:var(--transition-smooth);position:relative;appearance:none;background-color:#fff;outline:none}.custom-checkbox:checked{background:var(--color-accent-gradient);border-color:transparent}.custom-checkbox:checked:after{content:\"\\2713\";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#fff!important;font-size:.75rem;font-weight:800}.acceptance-text{font-size:.95rem;color:var(--slate-700)!important;font-weight:500;-webkit-user-select:none;user-select:none;line-height:1.4}.booking-summary-card{background-color:#fff;border:1px solid var(--slate-200);padding:2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);position:relative}.booking-summary-card:after{content:\"\";position:absolute;bottom:-1px;left:0;right:0;height:10px;background-image:radial-gradient(circle,white 4px,transparent 5px);background-size:12px 12px;background-position:0 0;z-index:2}.summary-title{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important;border-bottom:2px dashed var(--slate-200);padding-bottom:1rem;margin-bottom:1.5rem;text-align:center}.summary-row{display:flex;justify-content:space-between;align-items:center;padding:.85rem 0;border-bottom:1px solid var(--slate-100)}.summary-label{font-size:.95rem;color:var(--slate-500)!important;font-weight:500}.summary-value{font-size:.95rem;color:var(--slate-900)!important;font-weight:600;text-align:right}.total-row{margin-top:1rem;padding-top:1.25rem;border-top:2px dashed var(--slate-200);border-bottom:none}.total-row .summary-label{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important}.total-row .summary-value{font-size:1.5rem;font-weight:800;color:var(--color-primary)!important}.booking-confirmation{background:#fff;border:1px solid var(--slate-200);padding:3rem 2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);display:flex;flex-direction:column;align-items:center;text-align:center;max-width:500px;margin:0 auto}.success-icon{margin-bottom:1.5rem}.checkmark-circle{width:96px;height:96px;display:flex;align-items:center;justify-content:center}.confirmation-title{font-size:1.5rem;font-weight:800;color:var(--slate-900)!important;margin-bottom:.5rem}.confirmation-message{font-size:1rem;color:var(--slate-500)!important;line-height:1.6;margin-bottom:2rem;font-weight:450}.details-card{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1.5rem;width:100%;margin-bottom:2rem;text-align:left}.details-title{font-size:1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1rem;text-transform:uppercase;letter-spacing:.05em}.details-row{display:flex;justify-content:space-between;padding:.5rem 0;border-bottom:1px dashed var(--slate-200)}.details-row:last-child{border-bottom:none}.detail-label{font-size:.85rem;color:var(--slate-500)!important;font-weight:500}.detail-value{font-size:.9rem;color:var(--slate-900)!important;font-weight:600}.main_footer{border-top:1px solid var(--slate-200);background-color:#fff;padding:15px;flex-shrink:0;display:flex;justify-content:center;box-shadow:0 -4px 12px #00000005}.footer-buttons{width:100%;max-width:800px;display:flex;align-items:center}.back-footer-btn{font-size:.95rem;font-weight:600;color:var(--slate-600)!important;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);cursor:pointer}.back-footer-btn:hover{color:var(--slate-900)!important;background-color:var(--slate-100)}.continue-btn{background:var(--color-accent-gradient);color:#fff!important;border:none;padding:.75rem 2rem;border-radius:var(--border-radius-md);font-size:.95rem!important;font-weight:600;cursor:pointer;transition:var(--transition-smooth);box-shadow:0 4px 10px #23086033;width:max-content!important}.continue-btn:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.continue-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed!important;box-shadow:none!important}.complete_booking,.pay-now-btn{background:var(--color-accent-gradient)!important;color:#fff!important;border:none;padding:.75rem 2.25rem!important;font-size:.95rem!important;font-weight:600;border-radius:var(--border-radius-md)!important;box-shadow:0 4px 12px #23086040;transition:var(--transition-smooth);cursor:pointer;display:flex;align-items:center;gap:.5rem;width:max-content!important}.complete_booking img,.pay-now-btn img{width:20px;height:20px;filter:brightness(0) invert(1)}.complete_booking:hover:not([disabled]),.pay-now-btn:hover:not([disabled]){transform:translateY(-2px);box-shadow:0 6px 18px #23086059}.complete_booking:disabled,.pay-now-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed;box-shadow:none}.service-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding:0;width:100%}.skeleton-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;height:180px;display:flex;flex-direction:column;justify-content:space-between}.skeleton{background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border-radius:4px}@keyframes loading-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}.skeleton-icon{width:48px;height:48px;border-radius:var(--border-radius-md)}.skeleton-title{height:20px;width:60%;margin-bottom:.5rem}.skeleton-price{height:20px;width:30%}.skeleton-duration{height:12px;width:25%;margin-top:.25rem}.skeleton-description{height:14px;width:85%}.skeleton-badge{height:28px;width:120px;border-radius:20px}.time-slot-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:.75rem;width:100%}.skeleton-time-slot{height:42px;border-radius:var(--border-radius-md);background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border:1px solid var(--slate-100)}@media screen and (max-width: 475px){.main_header{padding:1rem}.header-title h1{font-size:1.25rem}.back-btn{padding:.5rem .8rem}.back-btn span{display:none}.main_body{padding:15px}.services-grid{grid-template-columns:1fr;gap:1rem}.staff-list{grid-template-columns:1fr!important;gap:.85rem!important}.service-card,.service-card-selected{min-height:auto}.main_container{flex-direction:column;gap:1.5rem}.datepicker-popover{width:100%;left:0}.details_container{gap:1.5rem}.details_container>.d-flex{flex-direction:column;gap:1.5rem}.details_container>.d-flex>div{width:100%!important}.booking-summary-card{padding:1.25rem}.summary-title{font-size:1.15rem}.total-row .summary-label{font-size:1.1rem}.total-row .summary-value{font-size:1.3rem}.main_footer{padding:1rem}.continue-btn{padding:.75rem 1.5rem}}.shipping-info{border-radius:10px;padding:20px;margin-bottom:12px;border:1px solid var(--slate-200);box-shadow:var(--shadow-sm)}.address-info{margin-bottom:0}.address-name{font-weight:700;margin-bottom:8px;color:var(--slate-900)!important}.address-details{color:var(--slate-500)!important;margin-bottom:8px}.mobile-number{font-weight:700;color:var(--slate-900)!important;font-size:15px}.change-address-btn{font-size:.85rem!important;font-weight:700!important;padding:10px;background:#fff;border:1px solid var(--slate-200);border-radius:8px;color:var(--slate-900)!important;cursor:pointer;transition:var(--transition-smooth)}.change-address-btn:hover{border-color:var(--color-primary);color:var(--color-primary)!important}.addLinks{padding:14px;border:1px dashed var(--slate-300);display:flex;align-items:center;justify-content:center;cursor:pointer;border-radius:8px;color:var(--slate-500)!important;margin-bottom:12px}.addLinks:hover{border-color:var(--color-primary);color:var(--color-primary)!important}h1{font-size:24px!important;font-weight:600!important}.done-actions{display:flex;gap:12px;width:100%}.done-btn{flex:1;max-width:220px;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);font-size:.95rem;font-weight:600;cursor:pointer;transition:var(--transition-smooth);border:none}.done-btn-primary{background:var(--color-accent-gradient);color:#fff!important;box-shadow:0 4px 10px #23086033}.done-btn-primary:hover{transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.done-btn-secondary{background:#fff;color:var(--slate-600)!important;border:1px solid var(--slate-200)}.done-btn-secondary:hover{background-color:var(--slate-100);color:var(--slate-900)!important}\n"] }]
|
|
25969
25983
|
}], ctorParameters: () => [{ type: RestService }, { type: EventsService }, { type: i2$2.Router }, { type: i6$1.MessageService }, { type: BookingProductCartService }, { type: StorageServiceService }, { type: i3$2.MatDialog }, { type: i3$2.MatDialogRef, decorators: [{
|
|
25970
25984
|
type: Optional
|
|
25971
25985
|
}] }], propDecorators: { data: [{
|
|
@@ -26004,6 +26018,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
26004
26018
|
* wizard (service bookings) is unaffected and still opens as a dialog.
|
|
26005
26019
|
*/
|
|
26006
26020
|
class BookAppointmentComponent extends BaseSection {
|
|
26021
|
+
/** Editor-configurable background - falls back to undefined (letting the component's own CSS
|
|
26022
|
+
* defaults show through unchanged) for existing pages saved before this section supported
|
|
26023
|
+
* custom colors. */
|
|
26024
|
+
get backgroundInfo() {
|
|
26025
|
+
return this.data?.styles?.background;
|
|
26026
|
+
}
|
|
26027
|
+
/** Overrides this component's own --color-accent-gradient CSS variable (scoped to its :host,
|
|
26028
|
+
* see book-appointment.component.css) when a business has picked a custom accent color - null
|
|
26029
|
+
* when unset, so the [style.--color-accent-gradient] binding removes the inline override
|
|
26030
|
+
* entirely and the CSS default shows through, rather than forcing an empty value. */
|
|
26031
|
+
get accentColor() {
|
|
26032
|
+
return this.data?.styles?.background?.accentColor || null;
|
|
26033
|
+
}
|
|
26007
26034
|
constructor(route, router, restService, _eventService, messageService, storageService, bookingProductCartService, matDialog) {
|
|
26008
26035
|
super();
|
|
26009
26036
|
this.route = route;
|
|
@@ -26317,11 +26344,11 @@ class BookAppointmentComponent extends BaseSection {
|
|
|
26317
26344
|
});
|
|
26318
26345
|
}
|
|
26319
26346
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BookAppointmentComponent, deps: [{ token: i2$2.ActivatedRoute }, { token: i2$2.Router }, { token: RestService }, { token: EventsService }, { token: i6$1.MessageService }, { token: StorageServiceService }, { token: BookingProductCartService }, { token: i3$2.MatDialog }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
26320
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: BookAppointmentComponent, isStandalone: true, selector: "simpo-book-appointment", inputs: { data: "data", index: "index", edit: "edit", delete: "delete", customClass: "customClass" }, providers: [MessageService], usesInheritance: true, ngImport: i0, template: "<p-toast position=\"bottom-right\" [baseZIndex]=\"10000000000\" [autoZIndex]=\"true\"\n [showTransformOptions]=\"screenWidth < 475 ? 'translateY(-100%)' : ''\"></p-toast>\n<section class=\"main_section\">\n <div class=\"main_header\">\n <div class=\"header d-flex justify-content-between align-items-center\">\n <div class=\"header-title\">\n <h1>{{bannerTitle}}</h1>\n <p>{{bannerDesc}}</p>\n </div>\n </div>\n </div>\n\n <div class=\"main_body w-100 d-flex justify-content-center\">\n <div class=\"wiz-container\">\n\n <div class=\"step-indicator\" *ngIf=\"step !== 'done'\">\n <div class=\"step-dot\" [class.active]=\"true\">1</div>\n <div class=\"step-label\" [class.active]=\"step==='form'\">Date, time & details</div>\n <div class=\"step-divider\"></div>\n <div class=\"step-dot\" [class.active]=\"step==='review'\">2</div>\n <div class=\"step-label\" [class.active]=\"step==='review'\">Review & confirm</div>\n </div>\n\n <ng-container *ngIf=\"step === 'form'\">\n <div class=\"single-grid\">\n <div class=\"single-left\">\n\n <div class=\"section-card card\">\n <div class=\"week-header\">\n <div>\n <h3 class=\"section-title mb-0\">Select a Date</h3>\n <p class=\"subtitle mb-0\">{{weekRangeLabel}}</p>\n </div>\n <div class=\"week-arrows\">\n <button type=\"button\" class=\"week-arrow-btn\" (click)=\"prevWeek()\" [disabled]=\"weekOffset <= 0\">\n <mat-icon>chevron_left</mat-icon>\n </button>\n <button type=\"button\" class=\"week-arrow-btn\" (click)=\"nextWeek()\" [disabled]=\"weekOffset >= maxWeekOffset\">\n <mat-icon>chevron_right</mat-icon>\n </button>\n </div>\n </div>\n <div class=\"week-strip\">\n <button type=\"button\" class=\"week-day\" *ngFor=\"let d of weekDays\" [class.selected]=\"d.selected\"\n (click)=\"pickDay(d)\">\n <div class=\"week-day-dow\">{{d.dow}}</div>\n <div class=\"week-day-num\">{{d.num}}</div>\n </button>\n </div>\n </div>\n\n <div class=\"section-card card\">\n <h3 class=\"section-title mb-0\">Select a Time</h3>\n <p class=\"subtitle\" *ngIf=\"selectedDateStr\">Available slots for {{selectedDateStr}}</p>\n <p class=\"subtitle mb-0\" *ngIf=\"!selectedDateStr\">Pick a date to see available times.</p>\n <div class=\"row g-2 overflow-scroll\" *ngIf=\"selectedDateStr\">\n <ng-container *ngIf=\"!slotsLoading; else slotsLoadingTpl\">\n <div class=\"col-4\" *ngFor=\"let time of slots\">\n <div class=\"time-slot rounded-2\" [class.selected]=\"time.selected\"\n (click)=\"selectSlot(time)\">{{time?.value}}</div>\n </div>\n <p class=\"mb-0\" *ngIf=\"slots.length === 0\">No slots available for this date.</p>\n </ng-container>\n <ng-template #slotsLoadingTpl>\n <p class=\"mb-0\">Loading available times...</p>\n </ng-template>\n </div>\n </div>\n\n <div class=\"section-card card\">\n <h3 class=\"section-title\">Booking Details</h3>\n <div class=\"booking-for-line\">\n Booking for <strong>{{userDetails?.contact?.name}}</strong>\n <ng-container *ngIf=\"userDetails?.contact?.mobile\"> \u00B7 {{userDetails?.contact?.mobile}}</ng-container>\n <ng-container *ngIf=\"userDetails?.contact?.email\"> \u00B7 {{userDetails?.contact?.email}}</ng-container>\n </div>\n\n <ng-container *ngIf=\"mode === 'HOME_VISIT'\">\n <p class=\"policies-title mt-3 mb-2\" style=\"font-size:1rem;\">Shipping Address</p>\n\n <div class=\"shipping-info\" *ngIf=\"defaultAddress\">\n <div class=\"address-info\">\n <div class=\"address-name\">{{defaultAddress?.receiverName}} ({{defaultAddress?.addressType}})</div>\n <div class=\"address-details\">{{defaultAddress?.addressLine1}}, {{defaultAddress?.cityName}},\n {{defaultAddress?.stateName}}</div>\n <div class=\"mobile-number\">Mobile: {{defaultAddress?.receiverPhone}}</div>\n </div>\n </div>\n <button type=\"button\" class=\"change-address-btn w-100\" (click)=\"changeAddress()\" *ngIf=\"defaultAddress\">\n CHANGE OR ADD ADDRESS\n </button>\n\n <div class=\"addLinks\" *ngIf=\"!defaultAddress\" (click)=\"addAddress()\">\n <mat-icon>add</mat-icon>\n <span class=\"ms-2\">Add an address</span>\n </div>\n\n <div class=\"mb-0 mt-3\">\n <label class=\"form-label d-flex align-items-center\">Instructions (optional)</label>\n <textarea class=\"form-control form-textarea rounded-2\" [(ngModel)]=\"instructions\"></textarea>\n </div>\n </ng-container>\n </div>\n </div>\n\n <div class=\"single-right section-card card\">\n <h3 class=\"section-title\">Your Shortlisted Designs</h3>\n <div class=\"design-row\" *ngFor=\"let it of productCartItems\">\n <div class=\"design-thumb\"></div>\n <div class=\"design-info\">\n <div class=\"design-name\">{{it.itemName}}</div>\n <div class=\"design-price\">\u20B9{{(it.sellingPrice ?? it.price ?? 0) * (it.quantity ?? 1)}}</div>\n </div>\n </div>\n <button type=\"button\" class=\"add-more-btn\" (click)=\"goToListing()\">+ Add More Designs</button>\n\n <div class=\"summary-divider\"></div>\n\n <div class=\"summary-line\" *ngIf=\"mode !== 'HOME_VISIT' || homeVisitCharge <= 0\">\n <div class=\"summary-label\">Service:</div>\n <div class=\"free-label\">FREE</div>\n </div>\n <div class=\"summary-line\" *ngIf=\"mode === 'HOME_VISIT' && homeVisitCharge > 0\">\n <div class=\"summary-label\">Home visit charge</div>\n <div class=\"summary-value\">\u20B9{{homeVisitCharge}}</div>\n </div>\n\n <button class=\"continue-btn w-100 mt-2\" [disabled]=\"invalid()\" (click)=\"goToReview()\">Review Booking</button>\n <p class=\"footnote\">You will review everything on the next screen before it is confirmed.</p>\n </div>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"step === 'review'\">\n <div class=\"review-card card\">\n <div class=\"review-header\">Review your booking</div>\n <div class=\"review-row\" *ngFor=\"let rc of reviewRows\">\n <div class=\"review-k\">{{rc.k}}</div>\n <div class=\"review-v\">{{rc.v}}</div>\n </div>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"step === 'done'\">\n <div class=\"booking-confirmation\">\n <div class=\"success-icon\">\n <div class=\"checkmark-circle\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/881293c1758695578518success.gif\"\n class=\"w-100 h-100\" *ngIf=\"apiStatus\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/325000c1758695564518fail.gif\"\n class=\"w-100 h-100\" *ngIf=\"!apiStatus\">\n </div>\n </div>\n\n <div class=\"confirmation-content\">\n <h1 class=\"confirmation-title\">{{apiStatus ? 'Booking Confirmed!' : 'Booking Failed'}}</h1>\n <p class=\"confirmation-message\">\n {{apiStatus ? 'Your appointment has been successfully booked.':'Failed to book your appointment. Please\n try again later'}}\n </p>\n\n <div class=\"video-call-link-card d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus && mode === 'VIDEO_CALL' && bookingGroup?.videoCallLink\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Your Video Call Link</h3>\n <a [href]=\"bookingGroup.videoCallLink\" target=\"_blank\">{{bookingGroup.videoCallLink}}</a>\n </div>\n </div>\n\n <div class=\"d-flex w-100 align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Appointment Details</h3>\n <div class=\"details-row\">\n <span class=\"detail-label\">{{productCartItems.length ? 'Products' : (mode === 'HOME_VISIT' ? 'Home Visit' : 'Video Call')}}</span>\n <span class=\"detail-value\">{{selectedDateStr}} at {{selectedSlot?.value ?? 'N/A'}}</span>\n </div>\n </div>\n </div>\n\n <div class=\"done-actions d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <button type=\"button\" class=\"done-btn done-btn-primary\" (click)=\"goToMyBookings()\">View my bookings</button>\n <button type=\"button\" class=\"done-btn done-btn-secondary\" (click)=\"goToListing()\">Keep shopping</button>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n\n <div class=\"main_footer d-flex justify-content-center align-items-center\" *ngIf=\"step === 'review'\">\n <div class=\"footer-buttons\" style=\"justify-content:space-between\">\n <span class=\"back-footer-btn cursor-pointer\" (click)=\"backToForm()\">Back</span>\n <button class=\"cursor-pointer d-flex justify-content-evenly align-items-center complete_booking\"\n (click)=\"confirmBooking()\" [disabled]=\"isProcessing\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/304012c1753440087996Background.png\">\n {{isProcessing ? 'Please wait...' : 'Confirm Booking'}}\n </button>\n </div>\n </div>\n</section>\n", styles: ["@import\"https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&display=swap\";mat-icon{font-family:Material Icons!important}:host{--font-sans: \"Outfit\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;--slate-50: #f8fafc;--slate-100: #f1f5f9;--slate-200: #e2e8f0;--slate-300: #cbd5e1;--slate-400: #94a3b8;--slate-500: #64748b;--slate-600: #475569;--slate-700: #334155;--slate-800: #1e293b;--slate-900: #0f172a;--color-primary: #230860;--color-secondary: #00b6ff;--color-accent-gradient: linear-gradient(135deg, #230860 0%, #00b6ff 100%);--color-success: #10b981;--color-success-bg: #ecfdf5;--color-error: #ef4444;--color-error-bg: #fef2f2;--border-radius-sm: 8px;--border-radius-md: 12px;--border-radius-lg: 16px;--border-radius-xl: 24px;--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, .05);--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, .05), 0 2px 4px -2px rgba(0, 0, 0, .05);--shadow-lg: 0 10px 15px -3px rgba(35, 8, 96, .05), 0 4px 6px -4px rgba(35, 8, 96, .05);--shadow-xl: 0 20px 25px -5px rgba(35, 8, 96, .08), 0 8px 10px -6px rgba(35, 8, 96, .08);--transition-smooth: all .3s cubic-bezier(.4, 0, .2, 1);--transition-bounce: all .4s cubic-bezier(.175, .885, .32, 1.275)}*{box-sizing:border-box;font-family:var(--font-sans)}.main_section{position:relative;height:100vh;background-color:var(--slate-50);display:flex;flex-direction:column;overflow:hidden}.main_header{padding:15px;background:#fff;border-bottom:1px solid var(--slate-100);flex-shrink:0;box-shadow:0 2px 8px #00000003}.header{display:flex;align-items:center;justify-content:space-between}.back-btn{display:flex;align-items:center;justify-content:center;gap:.5rem;padding:.6rem 1.2rem;border-radius:var(--border-radius-md);background:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-700)!important;transition:var(--transition-smooth);font-weight:500;font-size:.9rem;cursor:pointer}.back-btn mat-icon{font-size:18px!important;width:18px!important;height:18px!important;color:var(--slate-700)!important;display:flex;align-items:center;justify-content:center}.back-btn:hover{background:var(--slate-100);transform:translate(-3px);color:var(--slate-900)!important}.header-title{flex-grow:1;text-align:right}.header-title h1{font-size:1.5rem;font-weight:700;margin-bottom:.2rem;color:var(--slate-900)!important;letter-spacing:-.025em}.header-title p{color:var(--slate-500)!important;font-size:.9rem;font-weight:500;margin-bottom:0}.progress-bar{width:100%;height:6px;background-color:var(--slate-100);margin-top:3px;border-radius:10px;overflow:hidden;position:relative}.progress-fill{height:100%;background:var(--color-accent-gradient);border-radius:10px;transition:width .5s cubic-bezier(.4,0,.2,1);position:relative}.progress-fill:after{content:\"\";position:absolute;inset:0;background:linear-gradient(90deg,#fff0,#ffffff4d,#fff0);animation:shimmer 2s infinite linear}@keyframes shimmer{0%{transform:translate(-100%)}to{transform:translate(100%)}}.main_body{flex-grow:1;overflow-y:auto;padding:10px;display:flex;justify-content:center;background:var(--slate-50)}.w-60{width:100%;max-width:800px}.service_section,.location_section,.staff-listing,.date_section,.contact_section,.payment_section,.booking-confirmation{animation:slideUp .5s cubic-bezier(.16,1,.3,1) forwards}@keyframes slideUp{0%{opacity:0;transform:translateY(15px)}to{opacity:1;transform:translateY(0)}}h2{font-size:1.5rem;font-weight:700;color:var(--slate-900)!important;letter-spacing:-.02em;margin-bottom:.3rem}p.subtitle,.service-selection p,.location_section p,.staff-subtitle,.datetime-subtitle,.contact-subtitle,.payment-subtitle{color:var(--slate-500)!important;font-size:13px;margin-bottom:2rem}.services-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding-bottom:2rem}.service-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px}.service-card:hover{border-color:var(--slate-400);transform:translateY(-4px);box-shadow:var(--shadow-lg)}.service-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px;transform:translateY(-2px)}.service-card-selected:before,.location-card-selected:before{content:\"\\2713\";position:absolute;top:-10px;right:-10px;background:var(--color-accent-gradient);color:#fff!important;width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.8rem;font-weight:700;box-shadow:0 4px 8px #2308604d;animation:popIn .3s cubic-bezier(.175,.885,.32,1.275);z-index:10}@keyframes popIn{0%{transform:scale(0)}to{transform:scale(1)}}.service-header{display:flex;align-items:flex-start;gap:1rem;margin-bottom:1rem}.service-icon{width:48px;height:48px;border-radius:var(--border-radius-md);background-color:var(--slate-100);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.service-icon mat-icon{font-size:24px!important;width:24px!important;height:24px!important;color:var(--color-primary)!important}.service-card-selected .service-icon{background:var(--slate-900)}.service-card-selected .service-icon mat-icon{color:#fff!important}.service-info{flex-grow:1}.service-title{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;line-height:1.3;margin-bottom:.2rem}.service-price{font-size:1.25rem;font-weight:800;color:var(--slate-900)!important;text-align:right}.service-duration{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;text-align:right;margin-top:.1rem}.service-description{color:var(--slate-600)!important;font-size:.9rem;line-height:1.5;margin-bottom:1.25rem;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.home-visit{align-self:flex-start;display:inline-flex;align-items:center;gap:.5rem;font-size:.75rem;font-weight:600;color:var(--slate-700)!important;border:1px solid var(--slate-200);padding:.35rem .75rem;border-radius:20px;background-color:var(--slate-50);transition:var(--transition-smooth)}.home-visit img{width:14px;height:14px}.home-visit:before{content:\"\";display:inline-block;width:6px;height:6px;border-radius:50%;background-color:var(--color-success);box-shadow:0 0 #10b98166;animation:pulseGlow 1.8s infinite}@keyframes pulseGlow{0%{box-shadow:0 0 #10b981b3}70%{box-shadow:0 0 0 6px #10b98100}to{box-shadow:0 0 #10b98100}}.location-list{display:flex;flex-direction:column;gap:1.25rem;padding-bottom:2rem}.location-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm)}.location-card:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md)}.location-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px)}.location-content{display:flex;align-items:center}.location-info{display:flex;align-items:center;gap:1.25rem;width:100%}.location-icon{width:52px;height:52px;background-color:var(--slate-100);border-radius:var(--border-radius-md);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.location-icon img{width:28px;height:28px}.location-card-selected .location-icon{background:var(--slate-900)}.location-details{flex-grow:1}.location-details h3{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.3rem}.location-details p{font-size:.9rem;color:var(--slate-500)!important;font-weight:450;line-height:1.4;margin-bottom:0}.search-container{width:100%;margin-bottom:1.25rem}.search-input-wrapper{width:100%;background-color:var(--slate-100);border:1.5px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem 1rem;transition:var(--transition-smooth)}.search-input-wrapper:focus-within{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #23086014}.search-input{font-size:.95rem;font-weight:500;color:var(--slate-900)!important;background:transparent;outline:none;width:100%}.search-input::placeholder{color:var(--slate-400)}.search-icon{color:var(--slate-400)!important;font-size:20px!important;width:20px!important;height:20px!important}.clear-icon{color:var(--slate-400)!important;font-size:18px!important;width:18px!important;height:18px!important;transition:var(--transition-smooth)}.clear-icon:hover{color:var(--slate-600)!important}.staff-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:1rem;max-height:48vh;overflow-y:auto;padding-right:.5rem;padding-bottom:1rem}.staff-list::-webkit-scrollbar{width:6px}.staff-list::-webkit-scrollbar-track{background:var(--slate-50);border-radius:4px}.staff-list::-webkit-scrollbar-thumb{background:var(--slate-200);border-radius:4px}.staff-list::-webkit-scrollbar-thumb:hover{background:var(--slate-300)}.staff-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);margin-bottom:0!important}.staff-card:hover{border-color:var(--slate-300);transform:translateY(-2px);box-shadow:var(--shadow-md)}.staff-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px);margin-bottom:0!important}.staff-avatar{width:48px;height:48px;background:var(--color-accent-gradient);font-size:.95rem;font-weight:700;color:#fff!important;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;box-shadow:0 4px 10px #2308601a;letter-spacing:.5px;transition:var(--transition-smooth)}.staff-card-selected .staff-avatar{transform:scale(1.05)}.staff-name{font-size:1.05rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.2rem;letter-spacing:-.015em}.staff-specialty{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;margin-bottom:0;text-transform:uppercase;letter-spacing:.05em}.selection-indicator{display:flex;align-items:center;justify-content:center;margin-left:auto;padding-left:1rem}.checkmark-circle-mini{width:24px;height:24px;border:2px solid var(--slate-300);border-radius:50%;background-color:#fff;transition:var(--transition-bounce);color:#fff!important}.checkmark-circle-mini.selected{background:var(--color-accent-gradient);border-color:transparent;box-shadow:0 3px 8px #23086040}.checkmark-circle-mini mat-icon{font-size:14px!important;width:14px!important;height:14px!important;color:#fff!important;font-weight:800!important;display:flex;align-items:center;justify-content:center}.main_container{display:flex;gap:2rem;margin-bottom:2rem}.section-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm);height:100%}.section-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:10px!important;letter-spacing:-.01em}.time_selection{max-height:420px;display:flex;flex-direction:column}.time_selection .row{flex-grow:1;overflow-y:auto;padding-right:.25rem;margin-top:10px}.time-slot{background:#fff;border:1px solid var(--slate-200);font-size:.9rem;font-weight:600;color:var(--slate-800)!important;padding:.75rem .5rem;border-radius:var(--border-radius-md);cursor:pointer;transition:var(--transition-smooth);text-align:center;box-shadow:var(--shadow-sm)}.time-slot:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md);background-color:var(--slate-50)}.time-slot.selected{background:var(--color-accent-gradient);border-color:transparent;color:#fff!important;box-shadow:0 4px 12px #23086033}.form-section{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm)}.form-label{font-size:.85rem;font-weight:600;color:var(--slate-700)!important;margin-bottom:.5rem;text-transform:uppercase;letter-spacing:.05em}.required-asterisk{color:var(--color-error);margin-left:2px}.form-control,.form-input,.form-textarea{width:100%;background-color:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-900)!important;font-size:.95rem;font-weight:500;padding:.75rem 1rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);outline:none}.form-control:focus,.form-input:focus,.form-textarea:focus{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #2308601a}.form-textarea{min-height:100px;resize:vertical}.policies-container{background-color:#fff;border:1px solid var(--slate-200);padding:1.75rem;border-radius:var(--border-radius-lg);margin-top:1.5rem;box-shadow:var(--shadow-sm)}.policies-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1.25rem}.policy-item{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1rem 1.25rem;cursor:pointer;transition:var(--transition-smooth);display:flex;justify-content:space-between;align-items:center}.policy-item:hover{background-color:var(--slate-100);border-color:var(--slate-300)}.policy-title{font-size:.95rem;font-weight:600;color:var(--slate-800)!important}.policy-arrow mat-icon{color:var(--slate-500)!important;transition:var(--transition-smooth)}.cancellation_policies{background-color:var(--slate-50);padding:1rem 1.5rem;border-left:3px solid var(--color-primary);border-radius:0 0 var(--border-radius-md) var(--border-radius-md);margin-top:-4px;margin-bottom:1rem;font-size:.9rem;color:var(--slate-600)!important;line-height:1.5}.acceptance-section{display:flex;align-items:center;gap:.75rem;margin-top:1.5rem}.custom-checkbox{width:20px;height:20px;border:2px solid var(--slate-300);border-radius:6px;cursor:pointer;transition:var(--transition-smooth);position:relative;appearance:none;background-color:#fff;outline:none}.custom-checkbox:checked{background:var(--color-accent-gradient);border-color:transparent}.custom-checkbox:checked:after{content:\"\\2713\";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#fff!important;font-size:.75rem;font-weight:800}.acceptance-text{font-size:.95rem;color:var(--slate-700)!important;font-weight:500;-webkit-user-select:none;user-select:none;line-height:1.4}.booking-summary-card{background-color:#fff;border:1px solid var(--slate-200);padding:2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);position:relative}.booking-summary-card:after{content:\"\";position:absolute;bottom:-1px;left:0;right:0;height:10px;background-image:radial-gradient(circle,white 4px,transparent 5px);background-size:12px 12px;background-position:0 0;z-index:2}.summary-title{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important;border-bottom:2px dashed var(--slate-200);padding-bottom:1rem;margin-bottom:1.5rem;text-align:center}.summary-row{display:flex;justify-content:space-between;align-items:center;padding:.85rem 0;border-bottom:1px solid var(--slate-100)}.summary-label{font-size:.95rem;color:var(--slate-500)!important;font-weight:500}.summary-value{font-size:.95rem;color:var(--slate-900)!important;font-weight:600;text-align:right}.total-row{margin-top:1rem;padding-top:1.25rem;border-top:2px dashed var(--slate-200);border-bottom:none}.total-row .summary-label{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important}.total-row .summary-value{font-size:1.5rem;font-weight:800;color:var(--color-primary)!important}.booking-confirmation{background:#fff;border:1px solid var(--slate-200);padding:3rem 2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);display:flex;flex-direction:column;align-items:center;text-align:center;max-width:500px;margin:0 auto}.success-icon{margin-bottom:1.5rem}.checkmark-circle{width:96px;height:96px;display:flex;align-items:center;justify-content:center}.confirmation-title{font-size:1.5rem;font-weight:800;color:var(--slate-900)!important;margin-bottom:.5rem}.confirmation-message{font-size:1rem;color:var(--slate-500)!important;line-height:1.6;margin-bottom:2rem;font-weight:450}.details-card{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1.5rem;width:100%;margin-bottom:2rem;text-align:left}.details-title{font-size:1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1rem;text-transform:uppercase;letter-spacing:.05em}.details-row{display:flex;justify-content:space-between;padding:.5rem 0;border-bottom:1px dashed var(--slate-200)}.details-row:last-child{border-bottom:none}.detail-label{font-size:.85rem;color:var(--slate-500)!important;font-weight:500}.detail-value{font-size:.9rem;color:var(--slate-900)!important;font-weight:600}.done-actions{display:flex;gap:12px;width:100%}.done-btn{flex:1;max-width:220px;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);font-size:.95rem;font-weight:600;cursor:pointer;transition:var(--transition-smooth);border:none}.done-btn-primary{background:var(--color-accent-gradient);color:#fff!important;box-shadow:0 4px 10px #23086033}.done-btn-primary:hover{transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.done-btn-secondary{background:#fff;color:var(--slate-600)!important;border:1px solid var(--slate-200)}.done-btn-secondary:hover{background-color:var(--slate-100);color:var(--slate-900)!important}.main_footer{border-top:1px solid var(--slate-200);background-color:#fff;padding:15px;flex-shrink:0;display:flex;justify-content:center;box-shadow:0 -4px 12px #00000005}.footer-buttons{width:100%;max-width:800px;display:flex;align-items:center}.back-footer-btn{font-size:.95rem;font-weight:600;color:var(--slate-600)!important;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);cursor:pointer}.back-footer-btn:hover{color:var(--slate-900)!important;background-color:var(--slate-100)}.continue-btn{background:var(--color-accent-gradient);color:#fff!important;border:none;padding:.75rem 2rem;border-radius:var(--border-radius-md);font-size:.95rem!important;font-weight:600;cursor:pointer;transition:var(--transition-smooth);box-shadow:0 4px 10px #23086033;width:max-content!important}.continue-btn:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.continue-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed!important;box-shadow:none!important}.complete_booking,.pay-now-btn{background:var(--color-accent-gradient)!important;color:#fff!important;border:none;padding:.75rem 2.25rem!important;font-size:.95rem!important;font-weight:600;border-radius:var(--border-radius-md)!important;box-shadow:0 4px 12px #23086040;transition:var(--transition-smooth);cursor:pointer;display:flex;align-items:center;gap:.5rem;width:max-content!important}.complete_booking img,.pay-now-btn img{width:20px;height:20px;filter:brightness(0) invert(1)}.complete_booking:hover:not([disabled]),.pay-now-btn:hover:not([disabled]){transform:translateY(-2px);box-shadow:0 6px 18px #23086059}.complete_booking:disabled,.pay-now-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed;box-shadow:none}.service-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding:0;width:100%}.skeleton-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;height:180px;display:flex;flex-direction:column;justify-content:space-between}.skeleton{background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border-radius:4px}@keyframes loading-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}.skeleton-icon{width:48px;height:48px;border-radius:var(--border-radius-md)}.skeleton-title{height:20px;width:60%;margin-bottom:.5rem}.skeleton-price{height:20px;width:30%}.skeleton-duration{height:12px;width:25%;margin-top:.25rem}.skeleton-description{height:14px;width:85%}.skeleton-badge{height:28px;width:120px;border-radius:20px}.time-slot-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:.75rem;width:100%}.skeleton-time-slot{height:42px;border-radius:var(--border-radius-md);background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border:1px solid var(--slate-100)}@media screen and (max-width: 475px){.main_header{padding:1rem}.header-title h1{font-size:1.25rem}.back-btn{padding:.5rem .8rem}.back-btn span{display:none}.main_body{padding:15px}.services-grid{grid-template-columns:1fr;gap:1rem}.staff-list{grid-template-columns:1fr!important;gap:.85rem!important}.service-card,.service-card-selected{min-height:auto}.main_container{flex-direction:column;gap:1.5rem}.details_container{gap:1.5rem}.details_container>.d-flex{flex-direction:column;gap:1.5rem}.details_container>.d-flex>div{width:100%!important}.booking-summary-card{padding:1.25rem}.summary-title{font-size:1.15rem}.total-row .summary-label{font-size:1.1rem}.total-row .summary-value{font-size:1.3rem}.main_footer{padding:1rem}.continue-btn{padding:.75rem 1.5rem}}h1{font-size:24px!important;font-weight:600!important}.wiz-container{width:100%;max-width:1120px}.step-indicator{display:flex;align-items:center;gap:10px;padding-bottom:18px}.step-dot{width:26px;height:26px;border-radius:50%;background:var(--slate-200);color:var(--slate-500)!important;font-size:.8rem;font-weight:700;display:flex;align-items:center;justify-content:center;flex-shrink:0}.step-dot.active{background:var(--color-accent-gradient);color:#fff!important}.step-label{font-size:12.5px;color:var(--slate-400)!important;font-weight:600}.step-label.active{color:var(--slate-900)!important}.step-divider{width:40px;height:1px;background:var(--slate-200)}.single-grid{display:grid;grid-template-columns:1fr 360px;gap:1.5rem;align-items:start}.single-left{display:flex;flex-direction:column;gap:1.5rem}.single-right{align-self:flex-start;position:sticky;top:10px}.week-header{display:flex;align-items:center;justify-content:space-between;padding-bottom:14px}.week-arrows{display:flex;gap:8px}.week-arrow-btn{width:34px;height:34px;border-radius:8px;border:1px solid var(--slate-200);background:#fff;color:var(--slate-700)!important;cursor:pointer;display:flex;align-items:center;justify-content:center}.week-arrow-btn:disabled{color:var(--slate-300)!important;cursor:not-allowed}.week-strip{display:grid;grid-template-columns:repeat(7,1fr);gap:10px}.week-day{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem .25rem;cursor:pointer;transition:var(--transition-smooth);text-align:center}.week-day:hover{border-color:var(--slate-400)}.week-day.selected{background:var(--color-accent-gradient);border-color:transparent}.week-day.selected .week-day-dow,.week-day.selected .week-day-num{color:#fff!important}.week-day-dow{font-size:.75rem;font-weight:600;color:var(--slate-500)!important;text-transform:uppercase}.week-day-num{font-size:1rem;font-weight:700;color:var(--slate-900)!important;margin-top:2px}.booking-for-line{font-size:.9rem;color:var(--slate-600)!important;padding:.85rem 1rem;background:var(--slate-50);border-radius:var(--border-radius-md);margin-bottom:.5rem}.booking-for-line strong{color:var(--slate-900)!important}.shipping-info{border-radius:10px;padding:20px;margin-bottom:12px;border:1px solid var(--slate-200);box-shadow:var(--shadow-sm)}.address-info{margin-bottom:0}.address-name{font-weight:700;margin-bottom:8px;color:var(--slate-900)!important}.address-details{color:var(--slate-500)!important;margin-bottom:8px}.mobile-number{font-weight:700;color:var(--slate-900)!important;font-size:15px}.change-address-btn{font-size:.85rem!important;font-weight:700!important;padding:10px;background:#fff;border:1px solid var(--slate-200);border-radius:8px;color:var(--slate-900)!important;cursor:pointer;transition:var(--transition-smooth)}.change-address-btn:hover{border-color:var(--color-primary);color:var(--color-primary)!important}.addLinks{padding:14px;border:1px dashed var(--slate-300);display:flex;align-items:center;justify-content:center;cursor:pointer;border-radius:8px;color:var(--slate-500)!important;margin-bottom:12px}.addLinks:hover{border-color:var(--color-primary);color:var(--color-primary)!important}.design-row{display:flex;gap:13px;align-items:center;padding-bottom:1rem}.design-thumb{width:56px;height:56px;border-radius:8px;background:var(--slate-100);flex:none}.design-info{flex:1}.design-name{font-size:13.5px;color:var(--slate-900)!important;line-height:1.35}.design-price{font-size:13.5px;font-weight:600;color:var(--slate-900)!important;margin-top:3px}.add-more-btn{width:100%;height:44px;border:1.5px dashed var(--slate-300);border-radius:8px;background:none;color:var(--color-primary)!important;font-size:13px;font-weight:600;cursor:pointer;margin-bottom:1rem}.summary-divider{height:1px;background:var(--slate-100);margin-bottom:1rem}.summary-line{display:flex;justify-content:space-between;align-items:center;margin-bottom:.75rem}.free-label{font-size:13.5px;font-weight:600;color:var(--color-success)!important}.footnote{font-size:11.5px;line-height:1.5;color:var(--slate-500)!important;text-align:center;margin:.75rem 0 0}.review-card{max-width:560px;margin:0 auto;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);overflow:hidden}.review-header{padding:14px 18px;background:var(--slate-50);border-bottom:1px solid var(--slate-100);font-size:14.5px;font-weight:700;color:var(--slate-900)!important}.review-row{display:flex;justify-content:space-between;gap:16px;padding:12px 18px;border-bottom:1px solid var(--slate-100);font-size:13.5px}.review-row:last-child{border-bottom:none}.review-k{color:var(--slate-500)!important;flex-shrink:0}.review-v{color:var(--slate-900)!important;font-weight:500;text-align:right}@media screen and (max-width: 475px){.single-grid{grid-template-columns:1fr}.single-right{position:static}.week-strip{gap:6px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i9.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i9.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i9.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: ToastModule }, { kind: "component", type: i11.Toast, selector: "p-toast", inputs: ["key", "autoZIndex", "baseZIndex", "life", "style", "styleClass", "position", "preventOpenDuplicates", "preventDuplicates", "showTransformOptions", "hideTransformOptions", "showTransitionOptions", "hideTransitionOptions", "breakpoints"], outputs: ["onClose"] }] }); }
|
|
26347
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: BookAppointmentComponent, isStandalone: true, selector: "simpo-book-appointment", inputs: { data: "data", index: "index", edit: "edit", delete: "delete", customClass: "customClass" }, providers: [MessageService], usesInheritance: true, ngImport: i0, template: "<p-toast position=\"bottom-right\" [baseZIndex]=\"10000000000\" [autoZIndex]=\"true\"\n [showTransformOptions]=\"screenWidth < 475 ? 'translateY(-100%)' : ''\"></p-toast>\n<section class=\"main_section\" simpoHover (hovering)=\"showEditTabs($event)\"\n [simpoBackground]=\"backgroundInfo\" [style.--color-accent-gradient]=\"accentColor\">\n <div [ngClass]=\"{'hover_effect': edit}\" *ngIf=\"showEditors\">\n <simpo-hover-elements [data]=\"data\" [index]=\"index\" [editOptions]=\"edit\"></simpo-hover-elements>\n </div>\n <div class=\"main_header\">\n <div class=\"header d-flex justify-content-between align-items-center\">\n <div class=\"header-title\">\n <h1>{{bannerTitle}}</h1>\n <p>{{bannerDesc}}</p>\n </div>\n </div>\n </div>\n\n <div class=\"main_body w-100 d-flex justify-content-center\">\n <div class=\"wiz-container\">\n\n <div class=\"step-indicator\" *ngIf=\"step !== 'done'\">\n <div class=\"step-dot\" [class.active]=\"true\">1</div>\n <div class=\"step-label\" [class.active]=\"step==='form'\">Date, time & details</div>\n <div class=\"step-divider\"></div>\n <div class=\"step-dot\" [class.active]=\"step==='review'\">2</div>\n <div class=\"step-label\" [class.active]=\"step==='review'\">Review & confirm</div>\n </div>\n\n <ng-container *ngIf=\"step === 'form'\">\n <div class=\"single-grid\">\n <div class=\"single-left\">\n\n <div class=\"section-card card\">\n <div class=\"week-header\">\n <div>\n <h3 class=\"section-title mb-0\">Select a Date</h3>\n <p class=\"subtitle mb-0\">{{weekRangeLabel}}</p>\n </div>\n <div class=\"week-arrows\">\n <button type=\"button\" class=\"week-arrow-btn\" (click)=\"prevWeek()\" [disabled]=\"weekOffset <= 0\">\n <mat-icon>chevron_left</mat-icon>\n </button>\n <button type=\"button\" class=\"week-arrow-btn\" (click)=\"nextWeek()\" [disabled]=\"weekOffset >= maxWeekOffset\">\n <mat-icon>chevron_right</mat-icon>\n </button>\n </div>\n </div>\n <div class=\"week-strip\">\n <button type=\"button\" class=\"week-day\" *ngFor=\"let d of weekDays\" [class.selected]=\"d.selected\"\n (click)=\"pickDay(d)\">\n <div class=\"week-day-dow\">{{d.dow}}</div>\n <div class=\"week-day-num\">{{d.num}}</div>\n </button>\n </div>\n </div>\n\n <div class=\"section-card card\">\n <h3 class=\"section-title mb-0\">Select a Time</h3>\n <p class=\"subtitle\" *ngIf=\"selectedDateStr\">Available slots for {{selectedDateStr}}</p>\n <p class=\"subtitle mb-0\" *ngIf=\"!selectedDateStr\">Pick a date to see available times.</p>\n <div class=\"row g-2 overflow-scroll\" *ngIf=\"selectedDateStr\">\n <ng-container *ngIf=\"!slotsLoading; else slotsLoadingTpl\">\n <div class=\"col-4\" *ngFor=\"let time of slots\">\n <div class=\"time-slot rounded-2\" [class.selected]=\"time.selected\"\n (click)=\"selectSlot(time)\">{{time?.value}}</div>\n </div>\n <p class=\"mb-0\" *ngIf=\"slots.length === 0\">No slots available for this date.</p>\n </ng-container>\n <ng-template #slotsLoadingTpl>\n <p class=\"mb-0\">Loading available times...</p>\n </ng-template>\n </div>\n </div>\n\n <div class=\"section-card card\">\n <h3 class=\"section-title\">Booking Details</h3>\n <div class=\"booking-for-line\">\n Booking for <strong>{{userDetails?.contact?.name}}</strong>\n <ng-container *ngIf=\"userDetails?.contact?.mobile\"> \u00B7 {{userDetails?.contact?.mobile}}</ng-container>\n <ng-container *ngIf=\"userDetails?.contact?.email\"> \u00B7 {{userDetails?.contact?.email}}</ng-container>\n </div>\n\n <ng-container *ngIf=\"mode === 'HOME_VISIT'\">\n <p class=\"policies-title mt-3 mb-2\" style=\"font-size:1rem;\">Shipping Address</p>\n\n <div class=\"shipping-info\" *ngIf=\"defaultAddress\">\n <div class=\"address-info\">\n <div class=\"address-name\">{{defaultAddress?.receiverName}} ({{defaultAddress?.addressType}})</div>\n <div class=\"address-details\">{{defaultAddress?.addressLine1}}, {{defaultAddress?.cityName}},\n {{defaultAddress?.stateName}}</div>\n <div class=\"mobile-number\">Mobile: {{defaultAddress?.receiverPhone}}</div>\n </div>\n </div>\n <button type=\"button\" class=\"change-address-btn w-100\" (click)=\"changeAddress()\" *ngIf=\"defaultAddress\">\n CHANGE OR ADD ADDRESS\n </button>\n\n <div class=\"addLinks\" *ngIf=\"!defaultAddress\" (click)=\"addAddress()\">\n <mat-icon>add</mat-icon>\n <span class=\"ms-2\">Add an address</span>\n </div>\n\n <div class=\"mb-0 mt-3\">\n <label class=\"form-label d-flex align-items-center\">Instructions (optional)</label>\n <textarea class=\"form-control form-textarea rounded-2\" [(ngModel)]=\"instructions\"></textarea>\n </div>\n </ng-container>\n </div>\n </div>\n\n <div class=\"single-right section-card card\">\n <h3 class=\"section-title\">Your Shortlisted Designs</h3>\n <div class=\"design-row\" *ngFor=\"let it of productCartItems\">\n <div class=\"design-thumb\"></div>\n <div class=\"design-info\">\n <div class=\"design-name\">{{it.itemName}}</div>\n <div class=\"design-price\">\u20B9{{(it.sellingPrice ?? it.price ?? 0) * (it.quantity ?? 1)}}</div>\n </div>\n </div>\n <button type=\"button\" class=\"add-more-btn\" (click)=\"goToListing()\">+ Add More Designs</button>\n\n <div class=\"summary-divider\"></div>\n\n <div class=\"summary-line\" *ngIf=\"mode !== 'HOME_VISIT' || homeVisitCharge <= 0\">\n <div class=\"summary-label\">Service:</div>\n <div class=\"free-label\">FREE</div>\n </div>\n <div class=\"summary-line\" *ngIf=\"mode === 'HOME_VISIT' && homeVisitCharge > 0\">\n <div class=\"summary-label\">Home visit charge</div>\n <div class=\"summary-value\">\u20B9{{homeVisitCharge}}</div>\n </div>\n\n <button class=\"continue-btn w-100 mt-2\" [disabled]=\"invalid()\" (click)=\"goToReview()\">Review Booking</button>\n <p class=\"footnote\">You will review everything on the next screen before it is confirmed.</p>\n </div>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"step === 'review'\">\n <div class=\"review-card card\">\n <div class=\"review-header\">Review your booking</div>\n <div class=\"review-row\" *ngFor=\"let rc of reviewRows\">\n <div class=\"review-k\">{{rc.k}}</div>\n <div class=\"review-v\">{{rc.v}}</div>\n </div>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"step === 'done'\">\n <div class=\"booking-confirmation\">\n <div class=\"success-icon\">\n <div class=\"checkmark-circle\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/881293c1758695578518success.gif\"\n class=\"w-100 h-100\" *ngIf=\"apiStatus\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/325000c1758695564518fail.gif\"\n class=\"w-100 h-100\" *ngIf=\"!apiStatus\">\n </div>\n </div>\n\n <div class=\"confirmation-content\">\n <h1 class=\"confirmation-title\">{{apiStatus ? 'Booking Confirmed!' : 'Booking Failed'}}</h1>\n <p class=\"confirmation-message\">\n {{apiStatus ? 'Your appointment has been successfully booked.':'Failed to book your appointment. Please\n try again later'}}\n </p>\n\n <div class=\"video-call-link-card d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus && mode === 'VIDEO_CALL' && bookingGroup?.videoCallLink\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Your Video Call Link</h3>\n <a [href]=\"bookingGroup.videoCallLink\" target=\"_blank\">{{bookingGroup.videoCallLink}}</a>\n </div>\n </div>\n\n <div class=\"d-flex w-100 align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Appointment Details</h3>\n <div class=\"details-row\">\n <span class=\"detail-label\">{{productCartItems.length ? 'Products' : (mode === 'HOME_VISIT' ? 'Home Visit' : 'Video Call')}}</span>\n <span class=\"detail-value\">{{selectedDateStr}} at {{selectedSlot?.value ?? 'N/A'}}</span>\n </div>\n </div>\n </div>\n\n <div class=\"done-actions d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <button type=\"button\" class=\"done-btn done-btn-primary\" (click)=\"goToMyBookings()\">View my bookings</button>\n <button type=\"button\" class=\"done-btn done-btn-secondary\" (click)=\"goToListing()\">Keep shopping</button>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n\n <div class=\"main_footer d-flex justify-content-center align-items-center\" *ngIf=\"step === 'review'\">\n <div class=\"footer-buttons\" style=\"justify-content:space-between\">\n <span class=\"back-footer-btn cursor-pointer\" (click)=\"backToForm()\">Back</span>\n <button class=\"cursor-pointer d-flex justify-content-evenly align-items-center complete_booking\"\n (click)=\"confirmBooking()\" [disabled]=\"isProcessing\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/304012c1753440087996Background.png\">\n {{isProcessing ? 'Please wait...' : 'Confirm Booking'}}\n </button>\n </div>\n </div>\n</section>\n", styles: ["@import\"https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&display=swap\";mat-icon{font-family:Material Icons!important}:host{--font-sans: \"Outfit\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;--slate-50: #f8fafc;--slate-100: #f1f5f9;--slate-200: #e2e8f0;--slate-300: #cbd5e1;--slate-400: #94a3b8;--slate-500: #64748b;--slate-600: #475569;--slate-700: #334155;--slate-800: #1e293b;--slate-900: #0f172a;--color-primary: #230860;--color-secondary: #00b6ff;--color-accent-gradient: linear-gradient(135deg, #230860 0%, #00b6ff 100%);--color-success: #10b981;--color-success-bg: #ecfdf5;--color-error: #ef4444;--color-error-bg: #fef2f2;--border-radius-sm: 8px;--border-radius-md: 12px;--border-radius-lg: 16px;--border-radius-xl: 24px;--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, .05);--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, .05), 0 2px 4px -2px rgba(0, 0, 0, .05);--shadow-lg: 0 10px 15px -3px rgba(35, 8, 96, .05), 0 4px 6px -4px rgba(35, 8, 96, .05);--shadow-xl: 0 20px 25px -5px rgba(35, 8, 96, .08), 0 8px 10px -6px rgba(35, 8, 96, .08);--transition-smooth: all .3s cubic-bezier(.4, 0, .2, 1);--transition-bounce: all .4s cubic-bezier(.175, .885, .32, 1.275)}*{box-sizing:border-box;font-family:var(--font-sans)}.main_section{position:relative;height:100vh;background-color:var(--slate-50);display:flex;flex-direction:column;overflow:hidden}.hover_effect{position:absolute;width:100%;top:0;left:0;height:100%}.main_header{padding:15px;background:#fff;border-bottom:1px solid var(--slate-100);flex-shrink:0;box-shadow:0 2px 8px #00000003}.header{display:flex;align-items:center;justify-content:space-between}.back-btn{display:flex;align-items:center;justify-content:center;gap:.5rem;padding:.6rem 1.2rem;border-radius:var(--border-radius-md);background:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-700)!important;transition:var(--transition-smooth);font-weight:500;font-size:.9rem;cursor:pointer}.back-btn mat-icon{font-size:18px!important;width:18px!important;height:18px!important;color:var(--slate-700)!important;display:flex;align-items:center;justify-content:center}.back-btn:hover{background:var(--slate-100);transform:translate(-3px);color:var(--slate-900)!important}.header-title{flex-grow:1;text-align:right}.header-title h1{font-size:1.5rem;font-weight:700;margin-bottom:.2rem;color:var(--slate-900)!important;letter-spacing:-.025em}.header-title p{color:var(--slate-500)!important;font-size:.9rem;font-weight:500;margin-bottom:0}.progress-bar{width:100%;height:6px;background-color:var(--slate-100);margin-top:3px;border-radius:10px;overflow:hidden;position:relative}.progress-fill{height:100%;background:var(--color-accent-gradient);border-radius:10px;transition:width .5s cubic-bezier(.4,0,.2,1);position:relative}.progress-fill:after{content:\"\";position:absolute;inset:0;background:linear-gradient(90deg,#fff0,#ffffff4d,#fff0);animation:shimmer 2s infinite linear}@keyframes shimmer{0%{transform:translate(-100%)}to{transform:translate(100%)}}.main_body{flex-grow:1;overflow-y:auto;padding:10px;display:flex;justify-content:center;background:var(--slate-50)}.w-60{width:100%;max-width:800px}.service_section,.location_section,.staff-listing,.date_section,.contact_section,.payment_section,.booking-confirmation{animation:slideUp .5s cubic-bezier(.16,1,.3,1) forwards}@keyframes slideUp{0%{opacity:0;transform:translateY(15px)}to{opacity:1;transform:translateY(0)}}h2{font-size:1.5rem;font-weight:700;color:var(--slate-900)!important;letter-spacing:-.02em;margin-bottom:.3rem}p.subtitle,.service-selection p,.location_section p,.staff-subtitle,.datetime-subtitle,.contact-subtitle,.payment-subtitle{color:var(--slate-500)!important;font-size:13px;margin-bottom:2rem}.services-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding-bottom:2rem}.service-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px}.service-card:hover{border-color:var(--slate-400);transform:translateY(-4px);box-shadow:var(--shadow-lg)}.service-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px;transform:translateY(-2px)}.service-card-selected:before,.location-card-selected:before{content:\"\\2713\";position:absolute;top:-10px;right:-10px;background:var(--color-accent-gradient);color:#fff!important;width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.8rem;font-weight:700;box-shadow:0 4px 8px #2308604d;animation:popIn .3s cubic-bezier(.175,.885,.32,1.275);z-index:10}@keyframes popIn{0%{transform:scale(0)}to{transform:scale(1)}}.service-header{display:flex;align-items:flex-start;gap:1rem;margin-bottom:1rem}.service-icon{width:48px;height:48px;border-radius:var(--border-radius-md);background-color:var(--slate-100);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.service-icon mat-icon{font-size:24px!important;width:24px!important;height:24px!important;color:var(--color-primary)!important}.service-card-selected .service-icon{background:var(--slate-900)}.service-card-selected .service-icon mat-icon{color:#fff!important}.service-info{flex-grow:1}.service-title{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;line-height:1.3;margin-bottom:.2rem}.service-price{font-size:1.25rem;font-weight:800;color:var(--slate-900)!important;text-align:right}.service-duration{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;text-align:right;margin-top:.1rem}.service-description{color:var(--slate-600)!important;font-size:.9rem;line-height:1.5;margin-bottom:1.25rem;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.home-visit{align-self:flex-start;display:inline-flex;align-items:center;gap:.5rem;font-size:.75rem;font-weight:600;color:var(--slate-700)!important;border:1px solid var(--slate-200);padding:.35rem .75rem;border-radius:20px;background-color:var(--slate-50);transition:var(--transition-smooth)}.home-visit img{width:14px;height:14px}.home-visit:before{content:\"\";display:inline-block;width:6px;height:6px;border-radius:50%;background-color:var(--color-success);box-shadow:0 0 #10b98166;animation:pulseGlow 1.8s infinite}@keyframes pulseGlow{0%{box-shadow:0 0 #10b981b3}70%{box-shadow:0 0 0 6px #10b98100}to{box-shadow:0 0 #10b98100}}.location-list{display:flex;flex-direction:column;gap:1.25rem;padding-bottom:2rem}.location-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm)}.location-card:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md)}.location-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px)}.location-content{display:flex;align-items:center}.location-info{display:flex;align-items:center;gap:1.25rem;width:100%}.location-icon{width:52px;height:52px;background-color:var(--slate-100);border-radius:var(--border-radius-md);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.location-icon img{width:28px;height:28px}.location-card-selected .location-icon{background:var(--slate-900)}.location-details{flex-grow:1}.location-details h3{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.3rem}.location-details p{font-size:.9rem;color:var(--slate-500)!important;font-weight:450;line-height:1.4;margin-bottom:0}.search-container{width:100%;margin-bottom:1.25rem}.search-input-wrapper{width:100%;background-color:var(--slate-100);border:1.5px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem 1rem;transition:var(--transition-smooth)}.search-input-wrapper:focus-within{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #23086014}.search-input{font-size:.95rem;font-weight:500;color:var(--slate-900)!important;background:transparent;outline:none;width:100%}.search-input::placeholder{color:var(--slate-400)}.search-icon{color:var(--slate-400)!important;font-size:20px!important;width:20px!important;height:20px!important}.clear-icon{color:var(--slate-400)!important;font-size:18px!important;width:18px!important;height:18px!important;transition:var(--transition-smooth)}.clear-icon:hover{color:var(--slate-600)!important}.staff-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:1rem;max-height:48vh;overflow-y:auto;padding-right:.5rem;padding-bottom:1rem}.staff-list::-webkit-scrollbar{width:6px}.staff-list::-webkit-scrollbar-track{background:var(--slate-50);border-radius:4px}.staff-list::-webkit-scrollbar-thumb{background:var(--slate-200);border-radius:4px}.staff-list::-webkit-scrollbar-thumb:hover{background:var(--slate-300)}.staff-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);margin-bottom:0!important}.staff-card:hover{border-color:var(--slate-300);transform:translateY(-2px);box-shadow:var(--shadow-md)}.staff-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px);margin-bottom:0!important}.staff-avatar{width:48px;height:48px;background:var(--color-accent-gradient);font-size:.95rem;font-weight:700;color:#fff!important;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;box-shadow:0 4px 10px #2308601a;letter-spacing:.5px;transition:var(--transition-smooth)}.staff-card-selected .staff-avatar{transform:scale(1.05)}.staff-name{font-size:1.05rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.2rem;letter-spacing:-.015em}.staff-specialty{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;margin-bottom:0;text-transform:uppercase;letter-spacing:.05em}.selection-indicator{display:flex;align-items:center;justify-content:center;margin-left:auto;padding-left:1rem}.checkmark-circle-mini{width:24px;height:24px;border:2px solid var(--slate-300);border-radius:50%;background-color:#fff;transition:var(--transition-bounce);color:#fff!important}.checkmark-circle-mini.selected{background:var(--color-accent-gradient);border-color:transparent;box-shadow:0 3px 8px #23086040}.checkmark-circle-mini mat-icon{font-size:14px!important;width:14px!important;height:14px!important;color:#fff!important;font-weight:800!important;display:flex;align-items:center;justify-content:center}.main_container{display:flex;gap:2rem;margin-bottom:2rem}.section-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm);height:100%}.section-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:10px!important;letter-spacing:-.01em}.time_selection{max-height:420px;display:flex;flex-direction:column}.time_selection .row{flex-grow:1;overflow-y:auto;padding-right:.25rem;margin-top:10px}.time-slot{background:#fff;border:1px solid var(--slate-200);font-size:.9rem;font-weight:600;color:var(--slate-800)!important;padding:.75rem .5rem;border-radius:var(--border-radius-md);cursor:pointer;transition:var(--transition-smooth);text-align:center;box-shadow:var(--shadow-sm)}.time-slot:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md);background-color:var(--slate-50)}.time-slot.selected{background:var(--color-accent-gradient);border-color:transparent;color:#fff!important;box-shadow:0 4px 12px #23086033}.form-section{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm)}.form-label{font-size:.85rem;font-weight:600;color:var(--slate-700)!important;margin-bottom:.5rem;text-transform:uppercase;letter-spacing:.05em}.required-asterisk{color:var(--color-error);margin-left:2px}.form-control,.form-input,.form-textarea{width:100%;background-color:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-900)!important;font-size:.95rem;font-weight:500;padding:.75rem 1rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);outline:none}.form-control:focus,.form-input:focus,.form-textarea:focus{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #2308601a}.form-textarea{min-height:100px;resize:vertical}.policies-container{background-color:#fff;border:1px solid var(--slate-200);padding:1.75rem;border-radius:var(--border-radius-lg);margin-top:1.5rem;box-shadow:var(--shadow-sm)}.policies-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1.25rem}.policy-item{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1rem 1.25rem;cursor:pointer;transition:var(--transition-smooth);display:flex;justify-content:space-between;align-items:center}.policy-item:hover{background-color:var(--slate-100);border-color:var(--slate-300)}.policy-title{font-size:.95rem;font-weight:600;color:var(--slate-800)!important}.policy-arrow mat-icon{color:var(--slate-500)!important;transition:var(--transition-smooth)}.cancellation_policies{background-color:var(--slate-50);padding:1rem 1.5rem;border-left:3px solid var(--color-primary);border-radius:0 0 var(--border-radius-md) var(--border-radius-md);margin-top:-4px;margin-bottom:1rem;font-size:.9rem;color:var(--slate-600)!important;line-height:1.5}.acceptance-section{display:flex;align-items:center;gap:.75rem;margin-top:1.5rem}.custom-checkbox{width:20px;height:20px;border:2px solid var(--slate-300);border-radius:6px;cursor:pointer;transition:var(--transition-smooth);position:relative;appearance:none;background-color:#fff;outline:none}.custom-checkbox:checked{background:var(--color-accent-gradient);border-color:transparent}.custom-checkbox:checked:after{content:\"\\2713\";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#fff!important;font-size:.75rem;font-weight:800}.acceptance-text{font-size:.95rem;color:var(--slate-700)!important;font-weight:500;-webkit-user-select:none;user-select:none;line-height:1.4}.booking-summary-card{background-color:#fff;border:1px solid var(--slate-200);padding:2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);position:relative}.booking-summary-card:after{content:\"\";position:absolute;bottom:-1px;left:0;right:0;height:10px;background-image:radial-gradient(circle,white 4px,transparent 5px);background-size:12px 12px;background-position:0 0;z-index:2}.summary-title{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important;border-bottom:2px dashed var(--slate-200);padding-bottom:1rem;margin-bottom:1.5rem;text-align:center}.summary-row{display:flex;justify-content:space-between;align-items:center;padding:.85rem 0;border-bottom:1px solid var(--slate-100)}.summary-label{font-size:.95rem;color:var(--slate-500)!important;font-weight:500}.summary-value{font-size:.95rem;color:var(--slate-900)!important;font-weight:600;text-align:right}.total-row{margin-top:1rem;padding-top:1.25rem;border-top:2px dashed var(--slate-200);border-bottom:none}.total-row .summary-label{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important}.total-row .summary-value{font-size:1.5rem;font-weight:800;color:var(--color-primary)!important}.booking-confirmation{background:#fff;border:1px solid var(--slate-200);padding:3rem 2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);display:flex;flex-direction:column;align-items:center;text-align:center;max-width:500px;margin:0 auto}.success-icon{margin-bottom:1.5rem}.checkmark-circle{width:96px;height:96px;display:flex;align-items:center;justify-content:center}.confirmation-title{font-size:1.5rem;font-weight:800;color:var(--slate-900)!important;margin-bottom:.5rem}.confirmation-message{font-size:1rem;color:var(--slate-500)!important;line-height:1.6;margin-bottom:2rem;font-weight:450}.details-card{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1.5rem;width:100%;margin-bottom:2rem;text-align:left}.details-title{font-size:1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1rem;text-transform:uppercase;letter-spacing:.05em}.details-row{display:flex;justify-content:space-between;padding:.5rem 0;border-bottom:1px dashed var(--slate-200)}.details-row:last-child{border-bottom:none}.detail-label{font-size:.85rem;color:var(--slate-500)!important;font-weight:500}.detail-value{font-size:.9rem;color:var(--slate-900)!important;font-weight:600}.done-actions{display:flex;gap:12px;width:100%}.done-btn{flex:1;max-width:220px;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);font-size:.95rem;font-weight:600;cursor:pointer;transition:var(--transition-smooth);border:none}.done-btn-primary{background:var(--color-accent-gradient);color:#fff!important;box-shadow:0 4px 10px #23086033}.done-btn-primary:hover{transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.done-btn-secondary{background:#fff;color:var(--slate-600)!important;border:1px solid var(--slate-200)}.done-btn-secondary:hover{background-color:var(--slate-100);color:var(--slate-900)!important}.main_footer{border-top:1px solid var(--slate-200);background-color:#fff;padding:15px;flex-shrink:0;display:flex;justify-content:center;box-shadow:0 -4px 12px #00000005}.footer-buttons{width:100%;max-width:800px;display:flex;align-items:center}.back-footer-btn{font-size:.95rem;font-weight:600;color:var(--slate-600)!important;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);cursor:pointer}.back-footer-btn:hover{color:var(--slate-900)!important;background-color:var(--slate-100)}.continue-btn{background:var(--color-accent-gradient);color:#fff!important;border:none;padding:.75rem 2rem;border-radius:var(--border-radius-md);font-size:.95rem!important;font-weight:600;cursor:pointer;transition:var(--transition-smooth);box-shadow:0 4px 10px #23086033;width:max-content!important}.continue-btn:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.continue-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed!important;box-shadow:none!important}.complete_booking,.pay-now-btn{background:var(--color-accent-gradient)!important;color:#fff!important;border:none;padding:.75rem 2.25rem!important;font-size:.95rem!important;font-weight:600;border-radius:var(--border-radius-md)!important;box-shadow:0 4px 12px #23086040;transition:var(--transition-smooth);cursor:pointer;display:flex;align-items:center;gap:.5rem;width:max-content!important}.complete_booking img,.pay-now-btn img{width:20px;height:20px;filter:brightness(0) invert(1)}.complete_booking:hover:not([disabled]),.pay-now-btn:hover:not([disabled]){transform:translateY(-2px);box-shadow:0 6px 18px #23086059}.complete_booking:disabled,.pay-now-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed;box-shadow:none}.service-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding:0;width:100%}.skeleton-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;height:180px;display:flex;flex-direction:column;justify-content:space-between}.skeleton{background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border-radius:4px}@keyframes loading-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}.skeleton-icon{width:48px;height:48px;border-radius:var(--border-radius-md)}.skeleton-title{height:20px;width:60%;margin-bottom:.5rem}.skeleton-price{height:20px;width:30%}.skeleton-duration{height:12px;width:25%;margin-top:.25rem}.skeleton-description{height:14px;width:85%}.skeleton-badge{height:28px;width:120px;border-radius:20px}.time-slot-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:.75rem;width:100%}.skeleton-time-slot{height:42px;border-radius:var(--border-radius-md);background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border:1px solid var(--slate-100)}@media screen and (max-width: 475px){.main_header{padding:1rem}.header-title h1{font-size:1.25rem}.back-btn{padding:.5rem .8rem}.back-btn span{display:none}.main_body{padding:15px}.services-grid{grid-template-columns:1fr;gap:1rem}.staff-list{grid-template-columns:1fr!important;gap:.85rem!important}.service-card,.service-card-selected{min-height:auto}.main_container{flex-direction:column;gap:1.5rem}.details_container{gap:1.5rem}.details_container>.d-flex{flex-direction:column;gap:1.5rem}.details_container>.d-flex>div{width:100%!important}.booking-summary-card{padding:1.25rem}.summary-title{font-size:1.15rem}.total-row .summary-label{font-size:1.1rem}.total-row .summary-value{font-size:1.3rem}.main_footer{padding:1rem}.continue-btn{padding:.75rem 1.5rem}}h1{font-size:24px!important;font-weight:600!important}.wiz-container{width:100%;max-width:1120px}.step-indicator{display:flex;align-items:center;gap:10px;padding-bottom:18px}.step-dot{width:26px;height:26px;border-radius:50%;background:var(--slate-200);color:var(--slate-500)!important;font-size:.8rem;font-weight:700;display:flex;align-items:center;justify-content:center;flex-shrink:0}.step-dot.active{background:var(--color-accent-gradient);color:#fff!important}.step-label{font-size:12.5px;color:var(--slate-400)!important;font-weight:600}.step-label.active{color:var(--slate-900)!important}.step-divider{width:40px;height:1px;background:var(--slate-200)}.single-grid{display:grid;grid-template-columns:1fr 360px;gap:1.5rem;align-items:start}.single-left{display:flex;flex-direction:column;gap:1.5rem}.single-right{align-self:flex-start;position:sticky;top:10px}.week-header{display:flex;align-items:center;justify-content:space-between;padding-bottom:14px}.week-arrows{display:flex;gap:8px}.week-arrow-btn{width:34px;height:34px;border-radius:8px;border:1px solid var(--slate-200);background:#fff;color:var(--slate-700)!important;cursor:pointer;display:flex;align-items:center;justify-content:center}.week-arrow-btn:disabled{color:var(--slate-300)!important;cursor:not-allowed}.week-strip{display:grid;grid-template-columns:repeat(7,1fr);gap:10px}.week-day{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem .25rem;cursor:pointer;transition:var(--transition-smooth);text-align:center}.week-day:hover{border-color:var(--slate-400)}.week-day.selected{background:var(--color-accent-gradient);border-color:transparent}.week-day.selected .week-day-dow,.week-day.selected .week-day-num{color:#fff!important}.week-day-dow{font-size:.75rem;font-weight:600;color:var(--slate-500)!important;text-transform:uppercase}.week-day-num{font-size:1rem;font-weight:700;color:var(--slate-900)!important;margin-top:2px}.booking-for-line{font-size:.9rem;color:var(--slate-600)!important;padding:.85rem 1rem;background:var(--slate-50);border-radius:var(--border-radius-md);margin-bottom:.5rem}.booking-for-line strong{color:var(--slate-900)!important}.shipping-info{border-radius:10px;padding:20px;margin-bottom:12px;border:1px solid var(--slate-200);box-shadow:var(--shadow-sm)}.address-info{margin-bottom:0}.address-name{font-weight:700;margin-bottom:8px;color:var(--slate-900)!important}.address-details{color:var(--slate-500)!important;margin-bottom:8px}.mobile-number{font-weight:700;color:var(--slate-900)!important;font-size:15px}.change-address-btn{font-size:.85rem!important;font-weight:700!important;padding:10px;background:#fff;border:1px solid var(--slate-200);border-radius:8px;color:var(--slate-900)!important;cursor:pointer;transition:var(--transition-smooth)}.change-address-btn:hover{border-color:var(--color-primary);color:var(--color-primary)!important}.addLinks{padding:14px;border:1px dashed var(--slate-300);display:flex;align-items:center;justify-content:center;cursor:pointer;border-radius:8px;color:var(--slate-500)!important;margin-bottom:12px}.addLinks:hover{border-color:var(--color-primary);color:var(--color-primary)!important}.design-row{display:flex;gap:13px;align-items:center;padding-bottom:1rem}.design-thumb{width:56px;height:56px;border-radius:8px;background:var(--slate-100);flex:none}.design-info{flex:1}.design-name{font-size:13.5px;color:var(--slate-900)!important;line-height:1.35}.design-price{font-size:13.5px;font-weight:600;color:var(--slate-900)!important;margin-top:3px}.add-more-btn{width:100%;height:44px;border:1.5px dashed var(--slate-300);border-radius:8px;background:none;color:var(--color-primary)!important;font-size:13px;font-weight:600;cursor:pointer;margin-bottom:1rem}.summary-divider{height:1px;background:var(--slate-100);margin-bottom:1rem}.summary-line{display:flex;justify-content:space-between;align-items:center;margin-bottom:.75rem}.free-label{font-size:13.5px;font-weight:600;color:var(--color-success)!important}.footnote{font-size:11.5px;line-height:1.5;color:var(--slate-500)!important;text-align:center;margin:.75rem 0 0}.review-card{max-width:560px;margin:0 auto;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);overflow:hidden}.review-header{padding:14px 18px;background:var(--slate-50);border-bottom:1px solid var(--slate-100);font-size:14.5px;font-weight:700;color:var(--slate-900)!important}.review-row{display:flex;justify-content:space-between;gap:16px;padding:12px 18px;border-bottom:1px solid var(--slate-100);font-size:13.5px}.review-row:last-child{border-bottom:none}.review-k{color:var(--slate-500)!important;flex-shrink:0}.review-v{color:var(--slate-900)!important;font-weight:500;text-align:right}@media screen and (max-width: 475px){.single-grid{grid-template-columns:1fr}.single-right{position:static}.week-strip{gap:6px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i9.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i9.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i9.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: ToastModule }, { kind: "component", type: i11.Toast, selector: "p-toast", inputs: ["key", "autoZIndex", "baseZIndex", "life", "style", "styleClass", "position", "preventOpenDuplicates", "preventDuplicates", "showTransformOptions", "hideTransformOptions", "showTransitionOptions", "hideTransitionOptions", "breakpoints"], outputs: ["onClose"] }, { kind: "directive", type: HoverDirective, selector: "[simpoHover]", outputs: ["hovering"] }, { kind: "component", type: HoverElementsComponent, selector: "simpo-hover-elements", inputs: ["data", "index", "editOptions", "isMerged", "isEcommerce"], outputs: ["edit"] }, { kind: "directive", type: BackgroundDirective, selector: "[simpoBackground]", inputs: ["simpoBackground", "scrollValue"] }] }); }
|
|
26321
26348
|
}
|
|
26322
26349
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BookAppointmentComponent, decorators: [{
|
|
26323
26350
|
type: Component,
|
|
26324
|
-
args: [{ selector: 'simpo-book-appointment', standalone: true, imports: [CommonModule, MatIcon, MatIconModule, FormsModule, MatDialogModule, ToastModule], providers: [MessageService], template: "<p-toast position=\"bottom-right\" [baseZIndex]=\"10000000000\" [autoZIndex]=\"true\"\n [showTransformOptions]=\"screenWidth < 475 ? 'translateY(-100%)' : ''\"></p-toast>\n<section class=\"main_section\">\n <div class=\"main_header\">\n <div class=\"header d-flex justify-content-between align-items-center\">\n <div class=\"header-title\">\n <h1>{{bannerTitle}}</h1>\n <p>{{bannerDesc}}</p>\n </div>\n </div>\n </div>\n\n <div class=\"main_body w-100 d-flex justify-content-center\">\n <div class=\"wiz-container\">\n\n <div class=\"step-indicator\" *ngIf=\"step !== 'done'\">\n <div class=\"step-dot\" [class.active]=\"true\">1</div>\n <div class=\"step-label\" [class.active]=\"step==='form'\">Date, time & details</div>\n <div class=\"step-divider\"></div>\n <div class=\"step-dot\" [class.active]=\"step==='review'\">2</div>\n <div class=\"step-label\" [class.active]=\"step==='review'\">Review & confirm</div>\n </div>\n\n <ng-container *ngIf=\"step === 'form'\">\n <div class=\"single-grid\">\n <div class=\"single-left\">\n\n <div class=\"section-card card\">\n <div class=\"week-header\">\n <div>\n <h3 class=\"section-title mb-0\">Select a Date</h3>\n <p class=\"subtitle mb-0\">{{weekRangeLabel}}</p>\n </div>\n <div class=\"week-arrows\">\n <button type=\"button\" class=\"week-arrow-btn\" (click)=\"prevWeek()\" [disabled]=\"weekOffset <= 0\">\n <mat-icon>chevron_left</mat-icon>\n </button>\n <button type=\"button\" class=\"week-arrow-btn\" (click)=\"nextWeek()\" [disabled]=\"weekOffset >= maxWeekOffset\">\n <mat-icon>chevron_right</mat-icon>\n </button>\n </div>\n </div>\n <div class=\"week-strip\">\n <button type=\"button\" class=\"week-day\" *ngFor=\"let d of weekDays\" [class.selected]=\"d.selected\"\n (click)=\"pickDay(d)\">\n <div class=\"week-day-dow\">{{d.dow}}</div>\n <div class=\"week-day-num\">{{d.num}}</div>\n </button>\n </div>\n </div>\n\n <div class=\"section-card card\">\n <h3 class=\"section-title mb-0\">Select a Time</h3>\n <p class=\"subtitle\" *ngIf=\"selectedDateStr\">Available slots for {{selectedDateStr}}</p>\n <p class=\"subtitle mb-0\" *ngIf=\"!selectedDateStr\">Pick a date to see available times.</p>\n <div class=\"row g-2 overflow-scroll\" *ngIf=\"selectedDateStr\">\n <ng-container *ngIf=\"!slotsLoading; else slotsLoadingTpl\">\n <div class=\"col-4\" *ngFor=\"let time of slots\">\n <div class=\"time-slot rounded-2\" [class.selected]=\"time.selected\"\n (click)=\"selectSlot(time)\">{{time?.value}}</div>\n </div>\n <p class=\"mb-0\" *ngIf=\"slots.length === 0\">No slots available for this date.</p>\n </ng-container>\n <ng-template #slotsLoadingTpl>\n <p class=\"mb-0\">Loading available times...</p>\n </ng-template>\n </div>\n </div>\n\n <div class=\"section-card card\">\n <h3 class=\"section-title\">Booking Details</h3>\n <div class=\"booking-for-line\">\n Booking for <strong>{{userDetails?.contact?.name}}</strong>\n <ng-container *ngIf=\"userDetails?.contact?.mobile\"> \u00B7 {{userDetails?.contact?.mobile}}</ng-container>\n <ng-container *ngIf=\"userDetails?.contact?.email\"> \u00B7 {{userDetails?.contact?.email}}</ng-container>\n </div>\n\n <ng-container *ngIf=\"mode === 'HOME_VISIT'\">\n <p class=\"policies-title mt-3 mb-2\" style=\"font-size:1rem;\">Shipping Address</p>\n\n <div class=\"shipping-info\" *ngIf=\"defaultAddress\">\n <div class=\"address-info\">\n <div class=\"address-name\">{{defaultAddress?.receiverName}} ({{defaultAddress?.addressType}})</div>\n <div class=\"address-details\">{{defaultAddress?.addressLine1}}, {{defaultAddress?.cityName}},\n {{defaultAddress?.stateName}}</div>\n <div class=\"mobile-number\">Mobile: {{defaultAddress?.receiverPhone}}</div>\n </div>\n </div>\n <button type=\"button\" class=\"change-address-btn w-100\" (click)=\"changeAddress()\" *ngIf=\"defaultAddress\">\n CHANGE OR ADD ADDRESS\n </button>\n\n <div class=\"addLinks\" *ngIf=\"!defaultAddress\" (click)=\"addAddress()\">\n <mat-icon>add</mat-icon>\n <span class=\"ms-2\">Add an address</span>\n </div>\n\n <div class=\"mb-0 mt-3\">\n <label class=\"form-label d-flex align-items-center\">Instructions (optional)</label>\n <textarea class=\"form-control form-textarea rounded-2\" [(ngModel)]=\"instructions\"></textarea>\n </div>\n </ng-container>\n </div>\n </div>\n\n <div class=\"single-right section-card card\">\n <h3 class=\"section-title\">Your Shortlisted Designs</h3>\n <div class=\"design-row\" *ngFor=\"let it of productCartItems\">\n <div class=\"design-thumb\"></div>\n <div class=\"design-info\">\n <div class=\"design-name\">{{it.itemName}}</div>\n <div class=\"design-price\">\u20B9{{(it.sellingPrice ?? it.price ?? 0) * (it.quantity ?? 1)}}</div>\n </div>\n </div>\n <button type=\"button\" class=\"add-more-btn\" (click)=\"goToListing()\">+ Add More Designs</button>\n\n <div class=\"summary-divider\"></div>\n\n <div class=\"summary-line\" *ngIf=\"mode !== 'HOME_VISIT' || homeVisitCharge <= 0\">\n <div class=\"summary-label\">Service:</div>\n <div class=\"free-label\">FREE</div>\n </div>\n <div class=\"summary-line\" *ngIf=\"mode === 'HOME_VISIT' && homeVisitCharge > 0\">\n <div class=\"summary-label\">Home visit charge</div>\n <div class=\"summary-value\">\u20B9{{homeVisitCharge}}</div>\n </div>\n\n <button class=\"continue-btn w-100 mt-2\" [disabled]=\"invalid()\" (click)=\"goToReview()\">Review Booking</button>\n <p class=\"footnote\">You will review everything on the next screen before it is confirmed.</p>\n </div>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"step === 'review'\">\n <div class=\"review-card card\">\n <div class=\"review-header\">Review your booking</div>\n <div class=\"review-row\" *ngFor=\"let rc of reviewRows\">\n <div class=\"review-k\">{{rc.k}}</div>\n <div class=\"review-v\">{{rc.v}}</div>\n </div>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"step === 'done'\">\n <div class=\"booking-confirmation\">\n <div class=\"success-icon\">\n <div class=\"checkmark-circle\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/881293c1758695578518success.gif\"\n class=\"w-100 h-100\" *ngIf=\"apiStatus\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/325000c1758695564518fail.gif\"\n class=\"w-100 h-100\" *ngIf=\"!apiStatus\">\n </div>\n </div>\n\n <div class=\"confirmation-content\">\n <h1 class=\"confirmation-title\">{{apiStatus ? 'Booking Confirmed!' : 'Booking Failed'}}</h1>\n <p class=\"confirmation-message\">\n {{apiStatus ? 'Your appointment has been successfully booked.':'Failed to book your appointment. Please\n try again later'}}\n </p>\n\n <div class=\"video-call-link-card d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus && mode === 'VIDEO_CALL' && bookingGroup?.videoCallLink\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Your Video Call Link</h3>\n <a [href]=\"bookingGroup.videoCallLink\" target=\"_blank\">{{bookingGroup.videoCallLink}}</a>\n </div>\n </div>\n\n <div class=\"d-flex w-100 align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Appointment Details</h3>\n <div class=\"details-row\">\n <span class=\"detail-label\">{{productCartItems.length ? 'Products' : (mode === 'HOME_VISIT' ? 'Home Visit' : 'Video Call')}}</span>\n <span class=\"detail-value\">{{selectedDateStr}} at {{selectedSlot?.value ?? 'N/A'}}</span>\n </div>\n </div>\n </div>\n\n <div class=\"done-actions d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <button type=\"button\" class=\"done-btn done-btn-primary\" (click)=\"goToMyBookings()\">View my bookings</button>\n <button type=\"button\" class=\"done-btn done-btn-secondary\" (click)=\"goToListing()\">Keep shopping</button>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n\n <div class=\"main_footer d-flex justify-content-center align-items-center\" *ngIf=\"step === 'review'\">\n <div class=\"footer-buttons\" style=\"justify-content:space-between\">\n <span class=\"back-footer-btn cursor-pointer\" (click)=\"backToForm()\">Back</span>\n <button class=\"cursor-pointer d-flex justify-content-evenly align-items-center complete_booking\"\n (click)=\"confirmBooking()\" [disabled]=\"isProcessing\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/304012c1753440087996Background.png\">\n {{isProcessing ? 'Please wait...' : 'Confirm Booking'}}\n </button>\n </div>\n </div>\n</section>\n", styles: ["@import\"https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&display=swap\";mat-icon{font-family:Material Icons!important}:host{--font-sans: \"Outfit\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;--slate-50: #f8fafc;--slate-100: #f1f5f9;--slate-200: #e2e8f0;--slate-300: #cbd5e1;--slate-400: #94a3b8;--slate-500: #64748b;--slate-600: #475569;--slate-700: #334155;--slate-800: #1e293b;--slate-900: #0f172a;--color-primary: #230860;--color-secondary: #00b6ff;--color-accent-gradient: linear-gradient(135deg, #230860 0%, #00b6ff 100%);--color-success: #10b981;--color-success-bg: #ecfdf5;--color-error: #ef4444;--color-error-bg: #fef2f2;--border-radius-sm: 8px;--border-radius-md: 12px;--border-radius-lg: 16px;--border-radius-xl: 24px;--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, .05);--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, .05), 0 2px 4px -2px rgba(0, 0, 0, .05);--shadow-lg: 0 10px 15px -3px rgba(35, 8, 96, .05), 0 4px 6px -4px rgba(35, 8, 96, .05);--shadow-xl: 0 20px 25px -5px rgba(35, 8, 96, .08), 0 8px 10px -6px rgba(35, 8, 96, .08);--transition-smooth: all .3s cubic-bezier(.4, 0, .2, 1);--transition-bounce: all .4s cubic-bezier(.175, .885, .32, 1.275)}*{box-sizing:border-box;font-family:var(--font-sans)}.main_section{position:relative;height:100vh;background-color:var(--slate-50);display:flex;flex-direction:column;overflow:hidden}.main_header{padding:15px;background:#fff;border-bottom:1px solid var(--slate-100);flex-shrink:0;box-shadow:0 2px 8px #00000003}.header{display:flex;align-items:center;justify-content:space-between}.back-btn{display:flex;align-items:center;justify-content:center;gap:.5rem;padding:.6rem 1.2rem;border-radius:var(--border-radius-md);background:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-700)!important;transition:var(--transition-smooth);font-weight:500;font-size:.9rem;cursor:pointer}.back-btn mat-icon{font-size:18px!important;width:18px!important;height:18px!important;color:var(--slate-700)!important;display:flex;align-items:center;justify-content:center}.back-btn:hover{background:var(--slate-100);transform:translate(-3px);color:var(--slate-900)!important}.header-title{flex-grow:1;text-align:right}.header-title h1{font-size:1.5rem;font-weight:700;margin-bottom:.2rem;color:var(--slate-900)!important;letter-spacing:-.025em}.header-title p{color:var(--slate-500)!important;font-size:.9rem;font-weight:500;margin-bottom:0}.progress-bar{width:100%;height:6px;background-color:var(--slate-100);margin-top:3px;border-radius:10px;overflow:hidden;position:relative}.progress-fill{height:100%;background:var(--color-accent-gradient);border-radius:10px;transition:width .5s cubic-bezier(.4,0,.2,1);position:relative}.progress-fill:after{content:\"\";position:absolute;inset:0;background:linear-gradient(90deg,#fff0,#ffffff4d,#fff0);animation:shimmer 2s infinite linear}@keyframes shimmer{0%{transform:translate(-100%)}to{transform:translate(100%)}}.main_body{flex-grow:1;overflow-y:auto;padding:10px;display:flex;justify-content:center;background:var(--slate-50)}.w-60{width:100%;max-width:800px}.service_section,.location_section,.staff-listing,.date_section,.contact_section,.payment_section,.booking-confirmation{animation:slideUp .5s cubic-bezier(.16,1,.3,1) forwards}@keyframes slideUp{0%{opacity:0;transform:translateY(15px)}to{opacity:1;transform:translateY(0)}}h2{font-size:1.5rem;font-weight:700;color:var(--slate-900)!important;letter-spacing:-.02em;margin-bottom:.3rem}p.subtitle,.service-selection p,.location_section p,.staff-subtitle,.datetime-subtitle,.contact-subtitle,.payment-subtitle{color:var(--slate-500)!important;font-size:13px;margin-bottom:2rem}.services-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding-bottom:2rem}.service-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px}.service-card:hover{border-color:var(--slate-400);transform:translateY(-4px);box-shadow:var(--shadow-lg)}.service-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px;transform:translateY(-2px)}.service-card-selected:before,.location-card-selected:before{content:\"\\2713\";position:absolute;top:-10px;right:-10px;background:var(--color-accent-gradient);color:#fff!important;width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.8rem;font-weight:700;box-shadow:0 4px 8px #2308604d;animation:popIn .3s cubic-bezier(.175,.885,.32,1.275);z-index:10}@keyframes popIn{0%{transform:scale(0)}to{transform:scale(1)}}.service-header{display:flex;align-items:flex-start;gap:1rem;margin-bottom:1rem}.service-icon{width:48px;height:48px;border-radius:var(--border-radius-md);background-color:var(--slate-100);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.service-icon mat-icon{font-size:24px!important;width:24px!important;height:24px!important;color:var(--color-primary)!important}.service-card-selected .service-icon{background:var(--slate-900)}.service-card-selected .service-icon mat-icon{color:#fff!important}.service-info{flex-grow:1}.service-title{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;line-height:1.3;margin-bottom:.2rem}.service-price{font-size:1.25rem;font-weight:800;color:var(--slate-900)!important;text-align:right}.service-duration{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;text-align:right;margin-top:.1rem}.service-description{color:var(--slate-600)!important;font-size:.9rem;line-height:1.5;margin-bottom:1.25rem;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.home-visit{align-self:flex-start;display:inline-flex;align-items:center;gap:.5rem;font-size:.75rem;font-weight:600;color:var(--slate-700)!important;border:1px solid var(--slate-200);padding:.35rem .75rem;border-radius:20px;background-color:var(--slate-50);transition:var(--transition-smooth)}.home-visit img{width:14px;height:14px}.home-visit:before{content:\"\";display:inline-block;width:6px;height:6px;border-radius:50%;background-color:var(--color-success);box-shadow:0 0 #10b98166;animation:pulseGlow 1.8s infinite}@keyframes pulseGlow{0%{box-shadow:0 0 #10b981b3}70%{box-shadow:0 0 0 6px #10b98100}to{box-shadow:0 0 #10b98100}}.location-list{display:flex;flex-direction:column;gap:1.25rem;padding-bottom:2rem}.location-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm)}.location-card:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md)}.location-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px)}.location-content{display:flex;align-items:center}.location-info{display:flex;align-items:center;gap:1.25rem;width:100%}.location-icon{width:52px;height:52px;background-color:var(--slate-100);border-radius:var(--border-radius-md);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.location-icon img{width:28px;height:28px}.location-card-selected .location-icon{background:var(--slate-900)}.location-details{flex-grow:1}.location-details h3{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.3rem}.location-details p{font-size:.9rem;color:var(--slate-500)!important;font-weight:450;line-height:1.4;margin-bottom:0}.search-container{width:100%;margin-bottom:1.25rem}.search-input-wrapper{width:100%;background-color:var(--slate-100);border:1.5px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem 1rem;transition:var(--transition-smooth)}.search-input-wrapper:focus-within{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #23086014}.search-input{font-size:.95rem;font-weight:500;color:var(--slate-900)!important;background:transparent;outline:none;width:100%}.search-input::placeholder{color:var(--slate-400)}.search-icon{color:var(--slate-400)!important;font-size:20px!important;width:20px!important;height:20px!important}.clear-icon{color:var(--slate-400)!important;font-size:18px!important;width:18px!important;height:18px!important;transition:var(--transition-smooth)}.clear-icon:hover{color:var(--slate-600)!important}.staff-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:1rem;max-height:48vh;overflow-y:auto;padding-right:.5rem;padding-bottom:1rem}.staff-list::-webkit-scrollbar{width:6px}.staff-list::-webkit-scrollbar-track{background:var(--slate-50);border-radius:4px}.staff-list::-webkit-scrollbar-thumb{background:var(--slate-200);border-radius:4px}.staff-list::-webkit-scrollbar-thumb:hover{background:var(--slate-300)}.staff-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);margin-bottom:0!important}.staff-card:hover{border-color:var(--slate-300);transform:translateY(-2px);box-shadow:var(--shadow-md)}.staff-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px);margin-bottom:0!important}.staff-avatar{width:48px;height:48px;background:var(--color-accent-gradient);font-size:.95rem;font-weight:700;color:#fff!important;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;box-shadow:0 4px 10px #2308601a;letter-spacing:.5px;transition:var(--transition-smooth)}.staff-card-selected .staff-avatar{transform:scale(1.05)}.staff-name{font-size:1.05rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.2rem;letter-spacing:-.015em}.staff-specialty{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;margin-bottom:0;text-transform:uppercase;letter-spacing:.05em}.selection-indicator{display:flex;align-items:center;justify-content:center;margin-left:auto;padding-left:1rem}.checkmark-circle-mini{width:24px;height:24px;border:2px solid var(--slate-300);border-radius:50%;background-color:#fff;transition:var(--transition-bounce);color:#fff!important}.checkmark-circle-mini.selected{background:var(--color-accent-gradient);border-color:transparent;box-shadow:0 3px 8px #23086040}.checkmark-circle-mini mat-icon{font-size:14px!important;width:14px!important;height:14px!important;color:#fff!important;font-weight:800!important;display:flex;align-items:center;justify-content:center}.main_container{display:flex;gap:2rem;margin-bottom:2rem}.section-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm);height:100%}.section-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:10px!important;letter-spacing:-.01em}.time_selection{max-height:420px;display:flex;flex-direction:column}.time_selection .row{flex-grow:1;overflow-y:auto;padding-right:.25rem;margin-top:10px}.time-slot{background:#fff;border:1px solid var(--slate-200);font-size:.9rem;font-weight:600;color:var(--slate-800)!important;padding:.75rem .5rem;border-radius:var(--border-radius-md);cursor:pointer;transition:var(--transition-smooth);text-align:center;box-shadow:var(--shadow-sm)}.time-slot:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md);background-color:var(--slate-50)}.time-slot.selected{background:var(--color-accent-gradient);border-color:transparent;color:#fff!important;box-shadow:0 4px 12px #23086033}.form-section{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm)}.form-label{font-size:.85rem;font-weight:600;color:var(--slate-700)!important;margin-bottom:.5rem;text-transform:uppercase;letter-spacing:.05em}.required-asterisk{color:var(--color-error);margin-left:2px}.form-control,.form-input,.form-textarea{width:100%;background-color:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-900)!important;font-size:.95rem;font-weight:500;padding:.75rem 1rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);outline:none}.form-control:focus,.form-input:focus,.form-textarea:focus{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #2308601a}.form-textarea{min-height:100px;resize:vertical}.policies-container{background-color:#fff;border:1px solid var(--slate-200);padding:1.75rem;border-radius:var(--border-radius-lg);margin-top:1.5rem;box-shadow:var(--shadow-sm)}.policies-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1.25rem}.policy-item{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1rem 1.25rem;cursor:pointer;transition:var(--transition-smooth);display:flex;justify-content:space-between;align-items:center}.policy-item:hover{background-color:var(--slate-100);border-color:var(--slate-300)}.policy-title{font-size:.95rem;font-weight:600;color:var(--slate-800)!important}.policy-arrow mat-icon{color:var(--slate-500)!important;transition:var(--transition-smooth)}.cancellation_policies{background-color:var(--slate-50);padding:1rem 1.5rem;border-left:3px solid var(--color-primary);border-radius:0 0 var(--border-radius-md) var(--border-radius-md);margin-top:-4px;margin-bottom:1rem;font-size:.9rem;color:var(--slate-600)!important;line-height:1.5}.acceptance-section{display:flex;align-items:center;gap:.75rem;margin-top:1.5rem}.custom-checkbox{width:20px;height:20px;border:2px solid var(--slate-300);border-radius:6px;cursor:pointer;transition:var(--transition-smooth);position:relative;appearance:none;background-color:#fff;outline:none}.custom-checkbox:checked{background:var(--color-accent-gradient);border-color:transparent}.custom-checkbox:checked:after{content:\"\\2713\";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#fff!important;font-size:.75rem;font-weight:800}.acceptance-text{font-size:.95rem;color:var(--slate-700)!important;font-weight:500;-webkit-user-select:none;user-select:none;line-height:1.4}.booking-summary-card{background-color:#fff;border:1px solid var(--slate-200);padding:2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);position:relative}.booking-summary-card:after{content:\"\";position:absolute;bottom:-1px;left:0;right:0;height:10px;background-image:radial-gradient(circle,white 4px,transparent 5px);background-size:12px 12px;background-position:0 0;z-index:2}.summary-title{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important;border-bottom:2px dashed var(--slate-200);padding-bottom:1rem;margin-bottom:1.5rem;text-align:center}.summary-row{display:flex;justify-content:space-between;align-items:center;padding:.85rem 0;border-bottom:1px solid var(--slate-100)}.summary-label{font-size:.95rem;color:var(--slate-500)!important;font-weight:500}.summary-value{font-size:.95rem;color:var(--slate-900)!important;font-weight:600;text-align:right}.total-row{margin-top:1rem;padding-top:1.25rem;border-top:2px dashed var(--slate-200);border-bottom:none}.total-row .summary-label{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important}.total-row .summary-value{font-size:1.5rem;font-weight:800;color:var(--color-primary)!important}.booking-confirmation{background:#fff;border:1px solid var(--slate-200);padding:3rem 2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);display:flex;flex-direction:column;align-items:center;text-align:center;max-width:500px;margin:0 auto}.success-icon{margin-bottom:1.5rem}.checkmark-circle{width:96px;height:96px;display:flex;align-items:center;justify-content:center}.confirmation-title{font-size:1.5rem;font-weight:800;color:var(--slate-900)!important;margin-bottom:.5rem}.confirmation-message{font-size:1rem;color:var(--slate-500)!important;line-height:1.6;margin-bottom:2rem;font-weight:450}.details-card{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1.5rem;width:100%;margin-bottom:2rem;text-align:left}.details-title{font-size:1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1rem;text-transform:uppercase;letter-spacing:.05em}.details-row{display:flex;justify-content:space-between;padding:.5rem 0;border-bottom:1px dashed var(--slate-200)}.details-row:last-child{border-bottom:none}.detail-label{font-size:.85rem;color:var(--slate-500)!important;font-weight:500}.detail-value{font-size:.9rem;color:var(--slate-900)!important;font-weight:600}.done-actions{display:flex;gap:12px;width:100%}.done-btn{flex:1;max-width:220px;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);font-size:.95rem;font-weight:600;cursor:pointer;transition:var(--transition-smooth);border:none}.done-btn-primary{background:var(--color-accent-gradient);color:#fff!important;box-shadow:0 4px 10px #23086033}.done-btn-primary:hover{transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.done-btn-secondary{background:#fff;color:var(--slate-600)!important;border:1px solid var(--slate-200)}.done-btn-secondary:hover{background-color:var(--slate-100);color:var(--slate-900)!important}.main_footer{border-top:1px solid var(--slate-200);background-color:#fff;padding:15px;flex-shrink:0;display:flex;justify-content:center;box-shadow:0 -4px 12px #00000005}.footer-buttons{width:100%;max-width:800px;display:flex;align-items:center}.back-footer-btn{font-size:.95rem;font-weight:600;color:var(--slate-600)!important;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);cursor:pointer}.back-footer-btn:hover{color:var(--slate-900)!important;background-color:var(--slate-100)}.continue-btn{background:var(--color-accent-gradient);color:#fff!important;border:none;padding:.75rem 2rem;border-radius:var(--border-radius-md);font-size:.95rem!important;font-weight:600;cursor:pointer;transition:var(--transition-smooth);box-shadow:0 4px 10px #23086033;width:max-content!important}.continue-btn:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.continue-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed!important;box-shadow:none!important}.complete_booking,.pay-now-btn{background:var(--color-accent-gradient)!important;color:#fff!important;border:none;padding:.75rem 2.25rem!important;font-size:.95rem!important;font-weight:600;border-radius:var(--border-radius-md)!important;box-shadow:0 4px 12px #23086040;transition:var(--transition-smooth);cursor:pointer;display:flex;align-items:center;gap:.5rem;width:max-content!important}.complete_booking img,.pay-now-btn img{width:20px;height:20px;filter:brightness(0) invert(1)}.complete_booking:hover:not([disabled]),.pay-now-btn:hover:not([disabled]){transform:translateY(-2px);box-shadow:0 6px 18px #23086059}.complete_booking:disabled,.pay-now-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed;box-shadow:none}.service-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding:0;width:100%}.skeleton-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;height:180px;display:flex;flex-direction:column;justify-content:space-between}.skeleton{background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border-radius:4px}@keyframes loading-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}.skeleton-icon{width:48px;height:48px;border-radius:var(--border-radius-md)}.skeleton-title{height:20px;width:60%;margin-bottom:.5rem}.skeleton-price{height:20px;width:30%}.skeleton-duration{height:12px;width:25%;margin-top:.25rem}.skeleton-description{height:14px;width:85%}.skeleton-badge{height:28px;width:120px;border-radius:20px}.time-slot-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:.75rem;width:100%}.skeleton-time-slot{height:42px;border-radius:var(--border-radius-md);background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border:1px solid var(--slate-100)}@media screen and (max-width: 475px){.main_header{padding:1rem}.header-title h1{font-size:1.25rem}.back-btn{padding:.5rem .8rem}.back-btn span{display:none}.main_body{padding:15px}.services-grid{grid-template-columns:1fr;gap:1rem}.staff-list{grid-template-columns:1fr!important;gap:.85rem!important}.service-card,.service-card-selected{min-height:auto}.main_container{flex-direction:column;gap:1.5rem}.details_container{gap:1.5rem}.details_container>.d-flex{flex-direction:column;gap:1.5rem}.details_container>.d-flex>div{width:100%!important}.booking-summary-card{padding:1.25rem}.summary-title{font-size:1.15rem}.total-row .summary-label{font-size:1.1rem}.total-row .summary-value{font-size:1.3rem}.main_footer{padding:1rem}.continue-btn{padding:.75rem 1.5rem}}h1{font-size:24px!important;font-weight:600!important}.wiz-container{width:100%;max-width:1120px}.step-indicator{display:flex;align-items:center;gap:10px;padding-bottom:18px}.step-dot{width:26px;height:26px;border-radius:50%;background:var(--slate-200);color:var(--slate-500)!important;font-size:.8rem;font-weight:700;display:flex;align-items:center;justify-content:center;flex-shrink:0}.step-dot.active{background:var(--color-accent-gradient);color:#fff!important}.step-label{font-size:12.5px;color:var(--slate-400)!important;font-weight:600}.step-label.active{color:var(--slate-900)!important}.step-divider{width:40px;height:1px;background:var(--slate-200)}.single-grid{display:grid;grid-template-columns:1fr 360px;gap:1.5rem;align-items:start}.single-left{display:flex;flex-direction:column;gap:1.5rem}.single-right{align-self:flex-start;position:sticky;top:10px}.week-header{display:flex;align-items:center;justify-content:space-between;padding-bottom:14px}.week-arrows{display:flex;gap:8px}.week-arrow-btn{width:34px;height:34px;border-radius:8px;border:1px solid var(--slate-200);background:#fff;color:var(--slate-700)!important;cursor:pointer;display:flex;align-items:center;justify-content:center}.week-arrow-btn:disabled{color:var(--slate-300)!important;cursor:not-allowed}.week-strip{display:grid;grid-template-columns:repeat(7,1fr);gap:10px}.week-day{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem .25rem;cursor:pointer;transition:var(--transition-smooth);text-align:center}.week-day:hover{border-color:var(--slate-400)}.week-day.selected{background:var(--color-accent-gradient);border-color:transparent}.week-day.selected .week-day-dow,.week-day.selected .week-day-num{color:#fff!important}.week-day-dow{font-size:.75rem;font-weight:600;color:var(--slate-500)!important;text-transform:uppercase}.week-day-num{font-size:1rem;font-weight:700;color:var(--slate-900)!important;margin-top:2px}.booking-for-line{font-size:.9rem;color:var(--slate-600)!important;padding:.85rem 1rem;background:var(--slate-50);border-radius:var(--border-radius-md);margin-bottom:.5rem}.booking-for-line strong{color:var(--slate-900)!important}.shipping-info{border-radius:10px;padding:20px;margin-bottom:12px;border:1px solid var(--slate-200);box-shadow:var(--shadow-sm)}.address-info{margin-bottom:0}.address-name{font-weight:700;margin-bottom:8px;color:var(--slate-900)!important}.address-details{color:var(--slate-500)!important;margin-bottom:8px}.mobile-number{font-weight:700;color:var(--slate-900)!important;font-size:15px}.change-address-btn{font-size:.85rem!important;font-weight:700!important;padding:10px;background:#fff;border:1px solid var(--slate-200);border-radius:8px;color:var(--slate-900)!important;cursor:pointer;transition:var(--transition-smooth)}.change-address-btn:hover{border-color:var(--color-primary);color:var(--color-primary)!important}.addLinks{padding:14px;border:1px dashed var(--slate-300);display:flex;align-items:center;justify-content:center;cursor:pointer;border-radius:8px;color:var(--slate-500)!important;margin-bottom:12px}.addLinks:hover{border-color:var(--color-primary);color:var(--color-primary)!important}.design-row{display:flex;gap:13px;align-items:center;padding-bottom:1rem}.design-thumb{width:56px;height:56px;border-radius:8px;background:var(--slate-100);flex:none}.design-info{flex:1}.design-name{font-size:13.5px;color:var(--slate-900)!important;line-height:1.35}.design-price{font-size:13.5px;font-weight:600;color:var(--slate-900)!important;margin-top:3px}.add-more-btn{width:100%;height:44px;border:1.5px dashed var(--slate-300);border-radius:8px;background:none;color:var(--color-primary)!important;font-size:13px;font-weight:600;cursor:pointer;margin-bottom:1rem}.summary-divider{height:1px;background:var(--slate-100);margin-bottom:1rem}.summary-line{display:flex;justify-content:space-between;align-items:center;margin-bottom:.75rem}.free-label{font-size:13.5px;font-weight:600;color:var(--color-success)!important}.footnote{font-size:11.5px;line-height:1.5;color:var(--slate-500)!important;text-align:center;margin:.75rem 0 0}.review-card{max-width:560px;margin:0 auto;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);overflow:hidden}.review-header{padding:14px 18px;background:var(--slate-50);border-bottom:1px solid var(--slate-100);font-size:14.5px;font-weight:700;color:var(--slate-900)!important}.review-row{display:flex;justify-content:space-between;gap:16px;padding:12px 18px;border-bottom:1px solid var(--slate-100);font-size:13.5px}.review-row:last-child{border-bottom:none}.review-k{color:var(--slate-500)!important;flex-shrink:0}.review-v{color:var(--slate-900)!important;font-weight:500;text-align:right}@media screen and (max-width: 475px){.single-grid{grid-template-columns:1fr}.single-right{position:static}.week-strip{gap:6px}}\n"] }]
|
|
26351
|
+
args: [{ selector: 'simpo-book-appointment', standalone: true, imports: [CommonModule, MatIcon, MatIconModule, FormsModule, MatDialogModule, ToastModule, HoverDirective, HoverElementsComponent, BackgroundDirective], providers: [MessageService], template: "<p-toast position=\"bottom-right\" [baseZIndex]=\"10000000000\" [autoZIndex]=\"true\"\n [showTransformOptions]=\"screenWidth < 475 ? 'translateY(-100%)' : ''\"></p-toast>\n<section class=\"main_section\" simpoHover (hovering)=\"showEditTabs($event)\"\n [simpoBackground]=\"backgroundInfo\" [style.--color-accent-gradient]=\"accentColor\">\n <div [ngClass]=\"{'hover_effect': edit}\" *ngIf=\"showEditors\">\n <simpo-hover-elements [data]=\"data\" [index]=\"index\" [editOptions]=\"edit\"></simpo-hover-elements>\n </div>\n <div class=\"main_header\">\n <div class=\"header d-flex justify-content-between align-items-center\">\n <div class=\"header-title\">\n <h1>{{bannerTitle}}</h1>\n <p>{{bannerDesc}}</p>\n </div>\n </div>\n </div>\n\n <div class=\"main_body w-100 d-flex justify-content-center\">\n <div class=\"wiz-container\">\n\n <div class=\"step-indicator\" *ngIf=\"step !== 'done'\">\n <div class=\"step-dot\" [class.active]=\"true\">1</div>\n <div class=\"step-label\" [class.active]=\"step==='form'\">Date, time & details</div>\n <div class=\"step-divider\"></div>\n <div class=\"step-dot\" [class.active]=\"step==='review'\">2</div>\n <div class=\"step-label\" [class.active]=\"step==='review'\">Review & confirm</div>\n </div>\n\n <ng-container *ngIf=\"step === 'form'\">\n <div class=\"single-grid\">\n <div class=\"single-left\">\n\n <div class=\"section-card card\">\n <div class=\"week-header\">\n <div>\n <h3 class=\"section-title mb-0\">Select a Date</h3>\n <p class=\"subtitle mb-0\">{{weekRangeLabel}}</p>\n </div>\n <div class=\"week-arrows\">\n <button type=\"button\" class=\"week-arrow-btn\" (click)=\"prevWeek()\" [disabled]=\"weekOffset <= 0\">\n <mat-icon>chevron_left</mat-icon>\n </button>\n <button type=\"button\" class=\"week-arrow-btn\" (click)=\"nextWeek()\" [disabled]=\"weekOffset >= maxWeekOffset\">\n <mat-icon>chevron_right</mat-icon>\n </button>\n </div>\n </div>\n <div class=\"week-strip\">\n <button type=\"button\" class=\"week-day\" *ngFor=\"let d of weekDays\" [class.selected]=\"d.selected\"\n (click)=\"pickDay(d)\">\n <div class=\"week-day-dow\">{{d.dow}}</div>\n <div class=\"week-day-num\">{{d.num}}</div>\n </button>\n </div>\n </div>\n\n <div class=\"section-card card\">\n <h3 class=\"section-title mb-0\">Select a Time</h3>\n <p class=\"subtitle\" *ngIf=\"selectedDateStr\">Available slots for {{selectedDateStr}}</p>\n <p class=\"subtitle mb-0\" *ngIf=\"!selectedDateStr\">Pick a date to see available times.</p>\n <div class=\"row g-2 overflow-scroll\" *ngIf=\"selectedDateStr\">\n <ng-container *ngIf=\"!slotsLoading; else slotsLoadingTpl\">\n <div class=\"col-4\" *ngFor=\"let time of slots\">\n <div class=\"time-slot rounded-2\" [class.selected]=\"time.selected\"\n (click)=\"selectSlot(time)\">{{time?.value}}</div>\n </div>\n <p class=\"mb-0\" *ngIf=\"slots.length === 0\">No slots available for this date.</p>\n </ng-container>\n <ng-template #slotsLoadingTpl>\n <p class=\"mb-0\">Loading available times...</p>\n </ng-template>\n </div>\n </div>\n\n <div class=\"section-card card\">\n <h3 class=\"section-title\">Booking Details</h3>\n <div class=\"booking-for-line\">\n Booking for <strong>{{userDetails?.contact?.name}}</strong>\n <ng-container *ngIf=\"userDetails?.contact?.mobile\"> \u00B7 {{userDetails?.contact?.mobile}}</ng-container>\n <ng-container *ngIf=\"userDetails?.contact?.email\"> \u00B7 {{userDetails?.contact?.email}}</ng-container>\n </div>\n\n <ng-container *ngIf=\"mode === 'HOME_VISIT'\">\n <p class=\"policies-title mt-3 mb-2\" style=\"font-size:1rem;\">Shipping Address</p>\n\n <div class=\"shipping-info\" *ngIf=\"defaultAddress\">\n <div class=\"address-info\">\n <div class=\"address-name\">{{defaultAddress?.receiverName}} ({{defaultAddress?.addressType}})</div>\n <div class=\"address-details\">{{defaultAddress?.addressLine1}}, {{defaultAddress?.cityName}},\n {{defaultAddress?.stateName}}</div>\n <div class=\"mobile-number\">Mobile: {{defaultAddress?.receiverPhone}}</div>\n </div>\n </div>\n <button type=\"button\" class=\"change-address-btn w-100\" (click)=\"changeAddress()\" *ngIf=\"defaultAddress\">\n CHANGE OR ADD ADDRESS\n </button>\n\n <div class=\"addLinks\" *ngIf=\"!defaultAddress\" (click)=\"addAddress()\">\n <mat-icon>add</mat-icon>\n <span class=\"ms-2\">Add an address</span>\n </div>\n\n <div class=\"mb-0 mt-3\">\n <label class=\"form-label d-flex align-items-center\">Instructions (optional)</label>\n <textarea class=\"form-control form-textarea rounded-2\" [(ngModel)]=\"instructions\"></textarea>\n </div>\n </ng-container>\n </div>\n </div>\n\n <div class=\"single-right section-card card\">\n <h3 class=\"section-title\">Your Shortlisted Designs</h3>\n <div class=\"design-row\" *ngFor=\"let it of productCartItems\">\n <div class=\"design-thumb\"></div>\n <div class=\"design-info\">\n <div class=\"design-name\">{{it.itemName}}</div>\n <div class=\"design-price\">\u20B9{{(it.sellingPrice ?? it.price ?? 0) * (it.quantity ?? 1)}}</div>\n </div>\n </div>\n <button type=\"button\" class=\"add-more-btn\" (click)=\"goToListing()\">+ Add More Designs</button>\n\n <div class=\"summary-divider\"></div>\n\n <div class=\"summary-line\" *ngIf=\"mode !== 'HOME_VISIT' || homeVisitCharge <= 0\">\n <div class=\"summary-label\">Service:</div>\n <div class=\"free-label\">FREE</div>\n </div>\n <div class=\"summary-line\" *ngIf=\"mode === 'HOME_VISIT' && homeVisitCharge > 0\">\n <div class=\"summary-label\">Home visit charge</div>\n <div class=\"summary-value\">\u20B9{{homeVisitCharge}}</div>\n </div>\n\n <button class=\"continue-btn w-100 mt-2\" [disabled]=\"invalid()\" (click)=\"goToReview()\">Review Booking</button>\n <p class=\"footnote\">You will review everything on the next screen before it is confirmed.</p>\n </div>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"step === 'review'\">\n <div class=\"review-card card\">\n <div class=\"review-header\">Review your booking</div>\n <div class=\"review-row\" *ngFor=\"let rc of reviewRows\">\n <div class=\"review-k\">{{rc.k}}</div>\n <div class=\"review-v\">{{rc.v}}</div>\n </div>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"step === 'done'\">\n <div class=\"booking-confirmation\">\n <div class=\"success-icon\">\n <div class=\"checkmark-circle\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/881293c1758695578518success.gif\"\n class=\"w-100 h-100\" *ngIf=\"apiStatus\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/325000c1758695564518fail.gif\"\n class=\"w-100 h-100\" *ngIf=\"!apiStatus\">\n </div>\n </div>\n\n <div class=\"confirmation-content\">\n <h1 class=\"confirmation-title\">{{apiStatus ? 'Booking Confirmed!' : 'Booking Failed'}}</h1>\n <p class=\"confirmation-message\">\n {{apiStatus ? 'Your appointment has been successfully booked.':'Failed to book your appointment. Please\n try again later'}}\n </p>\n\n <div class=\"video-call-link-card d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus && mode === 'VIDEO_CALL' && bookingGroup?.videoCallLink\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Your Video Call Link</h3>\n <a [href]=\"bookingGroup.videoCallLink\" target=\"_blank\">{{bookingGroup.videoCallLink}}</a>\n </div>\n </div>\n\n <div class=\"d-flex w-100 align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <div class=\"details-card\">\n <h3 class=\"details-title\">Appointment Details</h3>\n <div class=\"details-row\">\n <span class=\"detail-label\">{{productCartItems.length ? 'Products' : (mode === 'HOME_VISIT' ? 'Home Visit' : 'Video Call')}}</span>\n <span class=\"detail-value\">{{selectedDateStr}} at {{selectedSlot?.value ?? 'N/A'}}</span>\n </div>\n </div>\n </div>\n\n <div class=\"done-actions d-flex align-items-center justify-content-center\" *ngIf=\"apiStatus\">\n <button type=\"button\" class=\"done-btn done-btn-primary\" (click)=\"goToMyBookings()\">View my bookings</button>\n <button type=\"button\" class=\"done-btn done-btn-secondary\" (click)=\"goToListing()\">Keep shopping</button>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n\n <div class=\"main_footer d-flex justify-content-center align-items-center\" *ngIf=\"step === 'review'\">\n <div class=\"footer-buttons\" style=\"justify-content:space-between\">\n <span class=\"back-footer-btn cursor-pointer\" (click)=\"backToForm()\">Back</span>\n <button class=\"cursor-pointer d-flex justify-content-evenly align-items-center complete_booking\"\n (click)=\"confirmBooking()\" [disabled]=\"isProcessing\">\n <img src=\"https://d2z9497xp8xb12.cloudfront.net/prod-images/304012c1753440087996Background.png\">\n {{isProcessing ? 'Please wait...' : 'Confirm Booking'}}\n </button>\n </div>\n </div>\n</section>\n", styles: ["@import\"https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&display=swap\";mat-icon{font-family:Material Icons!important}:host{--font-sans: \"Outfit\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;--slate-50: #f8fafc;--slate-100: #f1f5f9;--slate-200: #e2e8f0;--slate-300: #cbd5e1;--slate-400: #94a3b8;--slate-500: #64748b;--slate-600: #475569;--slate-700: #334155;--slate-800: #1e293b;--slate-900: #0f172a;--color-primary: #230860;--color-secondary: #00b6ff;--color-accent-gradient: linear-gradient(135deg, #230860 0%, #00b6ff 100%);--color-success: #10b981;--color-success-bg: #ecfdf5;--color-error: #ef4444;--color-error-bg: #fef2f2;--border-radius-sm: 8px;--border-radius-md: 12px;--border-radius-lg: 16px;--border-radius-xl: 24px;--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, .05);--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, .05), 0 2px 4px -2px rgba(0, 0, 0, .05);--shadow-lg: 0 10px 15px -3px rgba(35, 8, 96, .05), 0 4px 6px -4px rgba(35, 8, 96, .05);--shadow-xl: 0 20px 25px -5px rgba(35, 8, 96, .08), 0 8px 10px -6px rgba(35, 8, 96, .08);--transition-smooth: all .3s cubic-bezier(.4, 0, .2, 1);--transition-bounce: all .4s cubic-bezier(.175, .885, .32, 1.275)}*{box-sizing:border-box;font-family:var(--font-sans)}.main_section{position:relative;height:100vh;background-color:var(--slate-50);display:flex;flex-direction:column;overflow:hidden}.hover_effect{position:absolute;width:100%;top:0;left:0;height:100%}.main_header{padding:15px;background:#fff;border-bottom:1px solid var(--slate-100);flex-shrink:0;box-shadow:0 2px 8px #00000003}.header{display:flex;align-items:center;justify-content:space-between}.back-btn{display:flex;align-items:center;justify-content:center;gap:.5rem;padding:.6rem 1.2rem;border-radius:var(--border-radius-md);background:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-700)!important;transition:var(--transition-smooth);font-weight:500;font-size:.9rem;cursor:pointer}.back-btn mat-icon{font-size:18px!important;width:18px!important;height:18px!important;color:var(--slate-700)!important;display:flex;align-items:center;justify-content:center}.back-btn:hover{background:var(--slate-100);transform:translate(-3px);color:var(--slate-900)!important}.header-title{flex-grow:1;text-align:right}.header-title h1{font-size:1.5rem;font-weight:700;margin-bottom:.2rem;color:var(--slate-900)!important;letter-spacing:-.025em}.header-title p{color:var(--slate-500)!important;font-size:.9rem;font-weight:500;margin-bottom:0}.progress-bar{width:100%;height:6px;background-color:var(--slate-100);margin-top:3px;border-radius:10px;overflow:hidden;position:relative}.progress-fill{height:100%;background:var(--color-accent-gradient);border-radius:10px;transition:width .5s cubic-bezier(.4,0,.2,1);position:relative}.progress-fill:after{content:\"\";position:absolute;inset:0;background:linear-gradient(90deg,#fff0,#ffffff4d,#fff0);animation:shimmer 2s infinite linear}@keyframes shimmer{0%{transform:translate(-100%)}to{transform:translate(100%)}}.main_body{flex-grow:1;overflow-y:auto;padding:10px;display:flex;justify-content:center;background:var(--slate-50)}.w-60{width:100%;max-width:800px}.service_section,.location_section,.staff-listing,.date_section,.contact_section,.payment_section,.booking-confirmation{animation:slideUp .5s cubic-bezier(.16,1,.3,1) forwards}@keyframes slideUp{0%{opacity:0;transform:translateY(15px)}to{opacity:1;transform:translateY(0)}}h2{font-size:1.5rem;font-weight:700;color:var(--slate-900)!important;letter-spacing:-.02em;margin-bottom:.3rem}p.subtitle,.service-selection p,.location_section p,.staff-subtitle,.datetime-subtitle,.contact-subtitle,.payment-subtitle{color:var(--slate-500)!important;font-size:13px;margin-bottom:2rem}.services-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding-bottom:2rem}.service-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px}.service-card:hover{border-color:var(--slate-400);transform:translateY(-4px);box-shadow:var(--shadow-lg)}.service-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);display:flex;flex-direction:column;justify-content:space-between;height:100%;min-height:180px;transform:translateY(-2px)}.service-card-selected:before,.location-card-selected:before{content:\"\\2713\";position:absolute;top:-10px;right:-10px;background:var(--color-accent-gradient);color:#fff!important;width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.8rem;font-weight:700;box-shadow:0 4px 8px #2308604d;animation:popIn .3s cubic-bezier(.175,.885,.32,1.275);z-index:10}@keyframes popIn{0%{transform:scale(0)}to{transform:scale(1)}}.service-header{display:flex;align-items:flex-start;gap:1rem;margin-bottom:1rem}.service-icon{width:48px;height:48px;border-radius:var(--border-radius-md);background-color:var(--slate-100);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.service-icon mat-icon{font-size:24px!important;width:24px!important;height:24px!important;color:var(--color-primary)!important}.service-card-selected .service-icon{background:var(--slate-900)}.service-card-selected .service-icon mat-icon{color:#fff!important}.service-info{flex-grow:1}.service-title{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;line-height:1.3;margin-bottom:.2rem}.service-price{font-size:1.25rem;font-weight:800;color:var(--slate-900)!important;text-align:right}.service-duration{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;text-align:right;margin-top:.1rem}.service-description{color:var(--slate-600)!important;font-size:.9rem;line-height:1.5;margin-bottom:1.25rem;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.home-visit{align-self:flex-start;display:inline-flex;align-items:center;gap:.5rem;font-size:.75rem;font-weight:600;color:var(--slate-700)!important;border:1px solid var(--slate-200);padding:.35rem .75rem;border-radius:20px;background-color:var(--slate-50);transition:var(--transition-smooth)}.home-visit img{width:14px;height:14px}.home-visit:before{content:\"\";display:inline-block;width:6px;height:6px;border-radius:50%;background-color:var(--color-success);box-shadow:0 0 #10b98166;animation:pulseGlow 1.8s infinite}@keyframes pulseGlow{0%{box-shadow:0 0 #10b981b3}70%{box-shadow:0 0 0 6px #10b98100}to{box-shadow:0 0 #10b98100}}.location-list{display:flex;flex-direction:column;gap:1.25rem;padding-bottom:2rem}.location-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm)}.location-card:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md)}.location-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:1.5rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px)}.location-content{display:flex;align-items:center}.location-info{display:flex;align-items:center;gap:1.25rem;width:100%}.location-icon{width:52px;height:52px;background-color:var(--slate-100);border-radius:var(--border-radius-md);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:var(--transition-smooth)}.location-icon img{width:28px;height:28px}.location-card-selected .location-icon{background:var(--slate-900)}.location-details{flex-grow:1}.location-details h3{font-size:1.15rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.3rem}.location-details p{font-size:.9rem;color:var(--slate-500)!important;font-weight:450;line-height:1.4;margin-bottom:0}.search-container{width:100%;margin-bottom:1.25rem}.search-input-wrapper{width:100%;background-color:var(--slate-100);border:1.5px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem 1rem;transition:var(--transition-smooth)}.search-input-wrapper:focus-within{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #23086014}.search-input{font-size:.95rem;font-weight:500;color:var(--slate-900)!important;background:transparent;outline:none;width:100%}.search-input::placeholder{color:var(--slate-400)}.search-icon{color:var(--slate-400)!important;font-size:20px!important;width:20px!important;height:20px!important}.clear-icon{color:var(--slate-400)!important;font-size:18px!important;width:18px!important;height:18px!important;transition:var(--transition-smooth)}.clear-icon:hover{color:var(--slate-600)!important}.staff-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:1rem;max-height:48vh;overflow-y:auto;padding-right:.5rem;padding-bottom:1rem}.staff-list::-webkit-scrollbar{width:6px}.staff-list::-webkit-scrollbar-track{background:var(--slate-50);border-radius:4px}.staff-list::-webkit-scrollbar-thumb{background:var(--slate-200);border-radius:4px}.staff-list::-webkit-scrollbar-thumb:hover{background:var(--slate-300)}.staff-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-sm);margin-bottom:0!important}.staff-card:hover{border-color:var(--slate-300);transform:translateY(-2px);box-shadow:var(--shadow-md)}.staff-card-selected{background:#fff;border:2px solid var(--color-primary);border-radius:var(--border-radius-lg);padding:.9rem 1.25rem;cursor:pointer;transition:var(--transition-bounce);position:relative;box-shadow:var(--shadow-xl);transform:translateY(-1px);margin-bottom:0!important}.staff-avatar{width:48px;height:48px;background:var(--color-accent-gradient);font-size:.95rem;font-weight:700;color:#fff!important;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;box-shadow:0 4px 10px #2308601a;letter-spacing:.5px;transition:var(--transition-smooth)}.staff-card-selected .staff-avatar{transform:scale(1.05)}.staff-name{font-size:1.05rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:.2rem;letter-spacing:-.015em}.staff-specialty{font-size:.8rem;color:var(--slate-500)!important;font-weight:600;margin-bottom:0;text-transform:uppercase;letter-spacing:.05em}.selection-indicator{display:flex;align-items:center;justify-content:center;margin-left:auto;padding-left:1rem}.checkmark-circle-mini{width:24px;height:24px;border:2px solid var(--slate-300);border-radius:50%;background-color:#fff;transition:var(--transition-bounce);color:#fff!important}.checkmark-circle-mini.selected{background:var(--color-accent-gradient);border-color:transparent;box-shadow:0 3px 8px #23086040}.checkmark-circle-mini mat-icon{font-size:14px!important;width:14px!important;height:14px!important;color:#fff!important;font-weight:800!important;display:flex;align-items:center;justify-content:center}.main_container{display:flex;gap:2rem;margin-bottom:2rem}.section-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm);height:100%}.section-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:10px!important;letter-spacing:-.01em}.time_selection{max-height:420px;display:flex;flex-direction:column}.time_selection .row{flex-grow:1;overflow-y:auto;padding-right:.25rem;margin-top:10px}.time-slot{background:#fff;border:1px solid var(--slate-200);font-size:.9rem;font-weight:600;color:var(--slate-800)!important;padding:.75rem .5rem;border-radius:var(--border-radius-md);cursor:pointer;transition:var(--transition-smooth);text-align:center;box-shadow:var(--shadow-sm)}.time-slot:hover{border-color:var(--slate-400);transform:translateY(-2px);box-shadow:var(--shadow-md);background-color:var(--slate-50)}.time-slot.selected{background:var(--color-accent-gradient);border-color:transparent;color:#fff!important;box-shadow:0 4px 12px #23086033}.form-section{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.75rem;box-shadow:var(--shadow-sm)}.form-label{font-size:.85rem;font-weight:600;color:var(--slate-700)!important;margin-bottom:.5rem;text-transform:uppercase;letter-spacing:.05em}.required-asterisk{color:var(--color-error);margin-left:2px}.form-control,.form-input,.form-textarea{width:100%;background-color:var(--slate-50);border:1px solid var(--slate-200);color:var(--slate-900)!important;font-size:.95rem;font-weight:500;padding:.75rem 1rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);outline:none}.form-control:focus,.form-input:focus,.form-textarea:focus{background-color:#fff;border-color:var(--color-primary);box-shadow:0 0 0 3px #2308601a}.form-textarea{min-height:100px;resize:vertical}.policies-container{background-color:#fff;border:1px solid var(--slate-200);padding:1.75rem;border-radius:var(--border-radius-lg);margin-top:1.5rem;box-shadow:var(--shadow-sm)}.policies-title{font-size:1.1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1.25rem}.policy-item{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1rem 1.25rem;cursor:pointer;transition:var(--transition-smooth);display:flex;justify-content:space-between;align-items:center}.policy-item:hover{background-color:var(--slate-100);border-color:var(--slate-300)}.policy-title{font-size:.95rem;font-weight:600;color:var(--slate-800)!important}.policy-arrow mat-icon{color:var(--slate-500)!important;transition:var(--transition-smooth)}.cancellation_policies{background-color:var(--slate-50);padding:1rem 1.5rem;border-left:3px solid var(--color-primary);border-radius:0 0 var(--border-radius-md) var(--border-radius-md);margin-top:-4px;margin-bottom:1rem;font-size:.9rem;color:var(--slate-600)!important;line-height:1.5}.acceptance-section{display:flex;align-items:center;gap:.75rem;margin-top:1.5rem}.custom-checkbox{width:20px;height:20px;border:2px solid var(--slate-300);border-radius:6px;cursor:pointer;transition:var(--transition-smooth);position:relative;appearance:none;background-color:#fff;outline:none}.custom-checkbox:checked{background:var(--color-accent-gradient);border-color:transparent}.custom-checkbox:checked:after{content:\"\\2713\";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#fff!important;font-size:.75rem;font-weight:800}.acceptance-text{font-size:.95rem;color:var(--slate-700)!important;font-weight:500;-webkit-user-select:none;user-select:none;line-height:1.4}.booking-summary-card{background-color:#fff;border:1px solid var(--slate-200);padding:2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);position:relative}.booking-summary-card:after{content:\"\";position:absolute;bottom:-1px;left:0;right:0;height:10px;background-image:radial-gradient(circle,white 4px,transparent 5px);background-size:12px 12px;background-position:0 0;z-index:2}.summary-title{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important;border-bottom:2px dashed var(--slate-200);padding-bottom:1rem;margin-bottom:1.5rem;text-align:center}.summary-row{display:flex;justify-content:space-between;align-items:center;padding:.85rem 0;border-bottom:1px solid var(--slate-100)}.summary-label{font-size:.95rem;color:var(--slate-500)!important;font-weight:500}.summary-value{font-size:.95rem;color:var(--slate-900)!important;font-weight:600;text-align:right}.total-row{margin-top:1rem;padding-top:1.25rem;border-top:2px dashed var(--slate-200);border-bottom:none}.total-row .summary-label{font-size:1.25rem;font-weight:700;color:var(--slate-900)!important}.total-row .summary-value{font-size:1.5rem;font-weight:800;color:var(--color-primary)!important}.booking-confirmation{background:#fff;border:1px solid var(--slate-200);padding:3rem 2rem;border-radius:var(--border-radius-lg);box-shadow:var(--shadow-lg);display:flex;flex-direction:column;align-items:center;text-align:center;max-width:500px;margin:0 auto}.success-icon{margin-bottom:1.5rem}.checkmark-circle{width:96px;height:96px;display:flex;align-items:center;justify-content:center}.confirmation-title{font-size:1.5rem;font-weight:800;color:var(--slate-900)!important;margin-bottom:.5rem}.confirmation-message{font-size:1rem;color:var(--slate-500)!important;line-height:1.6;margin-bottom:2rem;font-weight:450}.details-card{background-color:var(--slate-50);border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:1.5rem;width:100%;margin-bottom:2rem;text-align:left}.details-title{font-size:1rem;font-weight:700;color:var(--slate-900)!important;margin-bottom:1rem;text-transform:uppercase;letter-spacing:.05em}.details-row{display:flex;justify-content:space-between;padding:.5rem 0;border-bottom:1px dashed var(--slate-200)}.details-row:last-child{border-bottom:none}.detail-label{font-size:.85rem;color:var(--slate-500)!important;font-weight:500}.detail-value{font-size:.9rem;color:var(--slate-900)!important;font-weight:600}.done-actions{display:flex;gap:12px;width:100%}.done-btn{flex:1;max-width:220px;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);font-size:.95rem;font-weight:600;cursor:pointer;transition:var(--transition-smooth);border:none}.done-btn-primary{background:var(--color-accent-gradient);color:#fff!important;box-shadow:0 4px 10px #23086033}.done-btn-primary:hover{transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.done-btn-secondary{background:#fff;color:var(--slate-600)!important;border:1px solid var(--slate-200)}.done-btn-secondary:hover{background-color:var(--slate-100);color:var(--slate-900)!important}.main_footer{border-top:1px solid var(--slate-200);background-color:#fff;padding:15px;flex-shrink:0;display:flex;justify-content:center;box-shadow:0 -4px 12px #00000005}.footer-buttons{width:100%;max-width:800px;display:flex;align-items:center}.back-footer-btn{font-size:.95rem;font-weight:600;color:var(--slate-600)!important;padding:.75rem 1.5rem;border-radius:var(--border-radius-md);transition:var(--transition-smooth);cursor:pointer}.back-footer-btn:hover{color:var(--slate-900)!important;background-color:var(--slate-100)}.continue-btn{background:var(--color-accent-gradient);color:#fff!important;border:none;padding:.75rem 2rem;border-radius:var(--border-radius-md);font-size:.95rem!important;font-weight:600;cursor:pointer;transition:var(--transition-smooth);box-shadow:0 4px 10px #23086033;width:max-content!important}.continue-btn:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 6px 15px #2308604d}.continue-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed!important;box-shadow:none!important}.complete_booking,.pay-now-btn{background:var(--color-accent-gradient)!important;color:#fff!important;border:none;padding:.75rem 2.25rem!important;font-size:.95rem!important;font-weight:600;border-radius:var(--border-radius-md)!important;box-shadow:0 4px 12px #23086040;transition:var(--transition-smooth);cursor:pointer;display:flex;align-items:center;gap:.5rem;width:max-content!important}.complete_booking img,.pay-now-btn img{width:20px;height:20px;filter:brightness(0) invert(1)}.complete_booking:hover:not([disabled]),.pay-now-btn:hover:not([disabled]){transform:translateY(-2px);box-shadow:0 6px 18px #23086059}.complete_booking:disabled,.pay-now-btn:disabled{background:var(--slate-200)!important;color:var(--slate-400)!important;cursor:not-allowed;box-shadow:none}.service-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:1.5rem;padding:0;width:100%}.skeleton-card{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);padding:1.5rem;height:180px;display:flex;flex-direction:column;justify-content:space-between}.skeleton{background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border-radius:4px}@keyframes loading-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}.skeleton-icon{width:48px;height:48px;border-radius:var(--border-radius-md)}.skeleton-title{height:20px;width:60%;margin-bottom:.5rem}.skeleton-price{height:20px;width:30%}.skeleton-duration{height:12px;width:25%;margin-top:.25rem}.skeleton-description{height:14px;width:85%}.skeleton-badge{height:28px;width:120px;border-radius:20px}.time-slot-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:.75rem;width:100%}.skeleton-time-slot{height:42px;border-radius:var(--border-radius-md);background:linear-gradient(90deg,#f1f5f9 25%,#e2e8f0,#f1f5f9 75%);background-size:200% 100%;animation:loading-shimmer 1.5s infinite linear;border:1px solid var(--slate-100)}@media screen and (max-width: 475px){.main_header{padding:1rem}.header-title h1{font-size:1.25rem}.back-btn{padding:.5rem .8rem}.back-btn span{display:none}.main_body{padding:15px}.services-grid{grid-template-columns:1fr;gap:1rem}.staff-list{grid-template-columns:1fr!important;gap:.85rem!important}.service-card,.service-card-selected{min-height:auto}.main_container{flex-direction:column;gap:1.5rem}.details_container{gap:1.5rem}.details_container>.d-flex{flex-direction:column;gap:1.5rem}.details_container>.d-flex>div{width:100%!important}.booking-summary-card{padding:1.25rem}.summary-title{font-size:1.15rem}.total-row .summary-label{font-size:1.1rem}.total-row .summary-value{font-size:1.3rem}.main_footer{padding:1rem}.continue-btn{padding:.75rem 1.5rem}}h1{font-size:24px!important;font-weight:600!important}.wiz-container{width:100%;max-width:1120px}.step-indicator{display:flex;align-items:center;gap:10px;padding-bottom:18px}.step-dot{width:26px;height:26px;border-radius:50%;background:var(--slate-200);color:var(--slate-500)!important;font-size:.8rem;font-weight:700;display:flex;align-items:center;justify-content:center;flex-shrink:0}.step-dot.active{background:var(--color-accent-gradient);color:#fff!important}.step-label{font-size:12.5px;color:var(--slate-400)!important;font-weight:600}.step-label.active{color:var(--slate-900)!important}.step-divider{width:40px;height:1px;background:var(--slate-200)}.single-grid{display:grid;grid-template-columns:1fr 360px;gap:1.5rem;align-items:start}.single-left{display:flex;flex-direction:column;gap:1.5rem}.single-right{align-self:flex-start;position:sticky;top:10px}.week-header{display:flex;align-items:center;justify-content:space-between;padding-bottom:14px}.week-arrows{display:flex;gap:8px}.week-arrow-btn{width:34px;height:34px;border-radius:8px;border:1px solid var(--slate-200);background:#fff;color:var(--slate-700)!important;cursor:pointer;display:flex;align-items:center;justify-content:center}.week-arrow-btn:disabled{color:var(--slate-300)!important;cursor:not-allowed}.week-strip{display:grid;grid-template-columns:repeat(7,1fr);gap:10px}.week-day{background:#fff;border:1px solid var(--slate-200);border-radius:var(--border-radius-md);padding:.6rem .25rem;cursor:pointer;transition:var(--transition-smooth);text-align:center}.week-day:hover{border-color:var(--slate-400)}.week-day.selected{background:var(--color-accent-gradient);border-color:transparent}.week-day.selected .week-day-dow,.week-day.selected .week-day-num{color:#fff!important}.week-day-dow{font-size:.75rem;font-weight:600;color:var(--slate-500)!important;text-transform:uppercase}.week-day-num{font-size:1rem;font-weight:700;color:var(--slate-900)!important;margin-top:2px}.booking-for-line{font-size:.9rem;color:var(--slate-600)!important;padding:.85rem 1rem;background:var(--slate-50);border-radius:var(--border-radius-md);margin-bottom:.5rem}.booking-for-line strong{color:var(--slate-900)!important}.shipping-info{border-radius:10px;padding:20px;margin-bottom:12px;border:1px solid var(--slate-200);box-shadow:var(--shadow-sm)}.address-info{margin-bottom:0}.address-name{font-weight:700;margin-bottom:8px;color:var(--slate-900)!important}.address-details{color:var(--slate-500)!important;margin-bottom:8px}.mobile-number{font-weight:700;color:var(--slate-900)!important;font-size:15px}.change-address-btn{font-size:.85rem!important;font-weight:700!important;padding:10px;background:#fff;border:1px solid var(--slate-200);border-radius:8px;color:var(--slate-900)!important;cursor:pointer;transition:var(--transition-smooth)}.change-address-btn:hover{border-color:var(--color-primary);color:var(--color-primary)!important}.addLinks{padding:14px;border:1px dashed var(--slate-300);display:flex;align-items:center;justify-content:center;cursor:pointer;border-radius:8px;color:var(--slate-500)!important;margin-bottom:12px}.addLinks:hover{border-color:var(--color-primary);color:var(--color-primary)!important}.design-row{display:flex;gap:13px;align-items:center;padding-bottom:1rem}.design-thumb{width:56px;height:56px;border-radius:8px;background:var(--slate-100);flex:none}.design-info{flex:1}.design-name{font-size:13.5px;color:var(--slate-900)!important;line-height:1.35}.design-price{font-size:13.5px;font-weight:600;color:var(--slate-900)!important;margin-top:3px}.add-more-btn{width:100%;height:44px;border:1.5px dashed var(--slate-300);border-radius:8px;background:none;color:var(--color-primary)!important;font-size:13px;font-weight:600;cursor:pointer;margin-bottom:1rem}.summary-divider{height:1px;background:var(--slate-100);margin-bottom:1rem}.summary-line{display:flex;justify-content:space-between;align-items:center;margin-bottom:.75rem}.free-label{font-size:13.5px;font-weight:600;color:var(--color-success)!important}.footnote{font-size:11.5px;line-height:1.5;color:var(--slate-500)!important;text-align:center;margin:.75rem 0 0}.review-card{max-width:560px;margin:0 auto;border:1px solid var(--slate-200);border-radius:var(--border-radius-lg);overflow:hidden}.review-header{padding:14px 18px;background:var(--slate-50);border-bottom:1px solid var(--slate-100);font-size:14.5px;font-weight:700;color:var(--slate-900)!important}.review-row{display:flex;justify-content:space-between;gap:16px;padding:12px 18px;border-bottom:1px solid var(--slate-100);font-size:13.5px}.review-row:last-child{border-bottom:none}.review-k{color:var(--slate-500)!important;flex-shrink:0}.review-v{color:var(--slate-900)!important;font-weight:500;text-align:right}@media screen and (max-width: 475px){.single-grid{grid-template-columns:1fr}.single-right{position:static}.week-strip{gap:6px}}\n"] }]
|
|
26325
26352
|
}], ctorParameters: () => [{ type: i2$2.ActivatedRoute }, { type: i2$2.Router }, { type: RestService }, { type: EventsService }, { type: i6$1.MessageService }, { type: StorageServiceService }, { type: BookingProductCartService }, { type: i3$2.MatDialog }], propDecorators: { data: [{
|
|
26326
26353
|
type: Input
|
|
26327
26354
|
}], index: [{
|