"; }, [computedLines, weekdayNights, weekendNights, holidayNightsList, kids6to12, childrenCost, under5, guestName, checkIn, checkOutDate, nightsNum, requestedGuests, allocatedGuests, slab5Subtotal, slab18Subtotal, discountAmount, gst5, gst18, grandTotal]); const openPrintable = () => { try { const html = buildPrintableHTML(); const blob = new Blob([html], { type: "text/html" }); const url = URL.createObjectURL(blob); setPrintUrl(url); window.open(url, "_blank"); } catch (e) {} }; return /*#__PURE__*/h("div", { style: { fontFamily: SANS, background: C.creamSoft, color: C.ink, minHeight: "100%" }, className: "w-full" }, /*#__PURE__*/h("style", null, ` input[type="date"]::-webkit-calendar-picker-indicator { opacity: 0.6; } .qb-select, .qb-input { font-family: ${SANS}; background: #fff; border: 1px solid #DCD4C0; border-radius: 8px; padding: 7px 10px; font-size: 14px; color: ${C.ink}; outline: none; } .qb-select:focus, .qb-input:focus { border-color: ${C.forest}; box-shadow: 0 0 0 3px ${C.goldLight}55; } .qb-btn-ghost:hover { background: ${C.cream}; } `), /*#__PURE__*/h("div", { style: { background: C.forestDark, color: C.creamSoft }, className: "px-5 py-5 sm:px-8" }, /*#__PURE__*/h("div", { className: "max-w-3xl mx-auto flex items-center justify-between" }, /*#__PURE__*/h("div", { className: "flex items-center gap-3" }, /*#__PURE__*/h("img", { src: LOGO_SRC, alt: "Mihra Mist Resort", className: "w-11 h-11 rounded-full object-cover", style: { border: `1px solid ${C.gold}` } }), /*#__PURE__*/h("div", null, /*#__PURE__*/h("div", { style: { fontFamily: SERIF, letterSpacing: 0.5 }, className: "text-2xl sm:text-3xl font-semibold" }, "Mihra Mist Resort"), /*#__PURE__*/h("div", { style: { color: C.goldLight }, className: "text-xs sm:text-sm tracking-wide uppercase mt-0.5" }, "Guest Quote Builder"))), /*#__PURE__*/h("div", { style: { background: C.forest, borderColor: C.gold }, className: "hidden sm:block text-right border rounded-lg px-3 py-2 text-xs" }, /*#__PURE__*/h("div", { style: { color: C.goldLight } }, "Rooms accommodate"), /*#__PURE__*/h("div", { className: "text-lg font-semibold" }, allocatedGuests)))), /*#__PURE__*/h("div", { className: "max-w-3xl mx-auto px-4 sm:px-8 pt-4" }, /*#__PURE__*/h("div", { className: "flex gap-2" }, /*#__PURE__*/h("button", { onClick: () => setActiveTab("quote"), className: "text-sm font-medium px-4 py-2 rounded-lg transition", style: activeTab === "quote" ? { background: C.forest, color: "#fff" } : { background: "#fff", color: C.forestDark, border: `1px solid ${C.cream}` } }, "Quote Builder"), /*#__PURE__*/h("button", { onClick: () => setActiveTab("availability"), className: "text-sm font-medium px-4 py-2 rounded-lg transition", style: activeTab === "availability" ? { background: C.forest, color: "#fff" } : { background: "#fff", color: C.forestDark, border: `1px solid ${C.cream}` } }, "Availability & Bookings"))), activeTab === "quote" && /*#__PURE__*/h("div", { className: "max-w-3xl mx-auto px-4 sm:px-8 py-6 space-y-5" }, /*#__PURE__*/h("section", { style: { background: "#fff", border: `1px solid ${C.cream}` }, className: "rounded-xl p-4 sm:p-5 shadow-sm" }, /*#__PURE__*/h("h2", { style: { fontFamily: SERIF, color: C.forestDark }, className: "text-lg font-semibold mb-3" }, "Stay details"), /*#__PURE__*/h("div", { className: "grid grid-cols-1 sm:grid-cols-4 gap-3" }, /*#__PURE__*/h("label", { className: "flex flex-col gap-1 text-xs text-stone-600" }, "Guest name (optional)", /*#__PURE__*/h("input", { className: "qb-input", value: guestName, onChange: e => setGuestName(e.target.value), placeholder: "e.g. Anitha Rao" })), /*#__PURE__*/h("label", { className: "flex flex-col gap-1 text-xs text-stone-600" }, "Number of guests", /*#__PURE__*/h("input", { type: "number", min: 0, className: "qb-input", value: guestCount, onChange: e => setGuestCount(e.target.value), placeholder: "As requested" })), /*#__PURE__*/h("label", { className: "flex flex-col gap-1 text-xs text-stone-600" }, "Check-in date", /*#__PURE__*/h("input", { type: "date", className: "qb-input", value: checkIn, onChange: e => setCheckIn(e.target.value) })), /*#__PURE__*/h("label", { className: "flex flex-col gap-1 text-xs text-stone-600" }, "Number of nights", /*#__PURE__*/h("input", { type: "number", min: 1, className: "qb-input", value: nights, onChange: e => setNights(e.target.value) }))), /*#__PURE__*/h("div", { className: "mt-3 text-sm text-stone-600 flex flex-wrap gap-x-4 gap-y-1" }, /*#__PURE__*/h("span", null, "Check-out: ", /*#__PURE__*/h("strong", { style: { color: C.forestDark } }, fmtDate(checkOutDate))), /*#__PURE__*/h("span", null, weekdayNights, " weekday night", weekdayNights !== 1 ? "s" : "", " (Mon\u2013Thu)"), /*#__PURE__*/h("span", null, weekendNights, " weekend night", weekendNights !== 1 ? "s" : "", " (Fri\u2013Sun)"), holidayNightsList.length > 0 && /*#__PURE__*/h("span", { style: { color: C.forest }, className: "font-medium" }, "incl. ", holidayNightsList.length, " holiday night", holidayNightsList.length !== 1 ? "s" : "", " @ weekend rate")), /*#__PURE__*/h("div", { className: "mt-3 border-t pt-3", style: { borderColor: C.cream } }, /*#__PURE__*/h("div", { className: "text-xs font-medium text-stone-600 mb-1.5" }, "Nights in this stay \u2014 tick any national holiday / festival (Onam, Deepavali, Gandhi Jayanti, etc.) to bill it at weekend rate"), /*#__PURE__*/h("div", { className: "flex flex-wrap gap-1.5" }, nightDates.map(n => /*#__PURE__*/h("label", { key: n.iso, className: "flex items-center gap-1.5 text-xs px-2 py-1 rounded-md cursor-pointer", style: { background: n.isWeekend ? C.goldLight : C.creamSoft, border: `1px solid ${n.isWeekend ? C.gold : C.cream}`, opacity: n.dayIsWeekend ? 0.85 : 1 }, title: n.dayIsWeekend ? "Already a weekend night" : "Tick if this date is a national holiday / festival" }, !n.dayIsWeekend && /*#__PURE__*/h("input", { type: "checkbox", checked: !!n.isHoliday, onChange: () => toggleHoliday(n.iso), className: "cursor-pointer" }), /*#__PURE__*/h("span", null, fmtDayName(n.date), " ", fmtDateShort(n.date)), n.isHoliday && /*#__PURE__*/h("span", { style: { color: C.forestDark }, className: "font-semibold" }, "Holiday"))))), guestMismatch && /*#__PURE__*/h("div", { className: "mt-2 flex items-start gap-1.5 text-xs rounded-lg px-2.5 py-2", style: { background: "#FBEFDD", color: "#7A5A1E" } }, /*#__PURE__*/h(AlertTriangle, { size: 14, className: "mt-0.5 shrink-0" }), /*#__PURE__*/h("span", null, requestedGuests, " guest", requestedGuests !== 1 ? "s" : "", " requested, but the rooms selected below accommodate ", allocatedGuests, ". Adjust room count or extra adults to match."))), /*#__PURE__*/h("section", { style: { background: "#fff", border: `1px solid ${C.cream}` }, className: "rounded-xl p-4 sm:p-5 shadow-sm" }, /*#__PURE__*/h("div", { className: "flex items-center justify-between mb-3" }, /*#__PURE__*/h("h2", { style: { fontFamily: SERIF, color: C.forestDark }, className: "text-lg font-semibold" }, "Rooms"), /*#__PURE__*/h("button", { onClick: addLine, style: { background: C.forest, color: "#fff" }, className: "flex items-center gap-1.5 text-sm px-3 py-1.5 rounded-lg hover:opacity-90 transition" }, /*#__PURE__*/h(Plus, { size: 15 }), " Add room")), /*#__PURE__*/h("div", { className: "space-y-3" }, computedLines.map(line => /*#__PURE__*/h("div", { key: line.id, style: { borderColor: C.cream, background: C.creamSoft }, className: "border rounded-lg p-3" }, /*#__PURE__*/h("div", { className: "flex flex-col sm:flex-row sm:items-end gap-2.5" }, /*#__PURE__*/h("label", { className: "flex flex-col gap-1 text-xs text-stone-600 flex-1 min-w-0" }, "Room category", /*#__PURE__*/h("select", { className: "qb-select", value: line.categoryId, onChange: e => updateLine(line.id, { categoryId: e.target.value }) }, ROOM_CATEGORIES.map(c => /*#__PURE__*/h("option", { key: c.id, value: c.id }, c.name)))), /*#__PURE__*/h("label", { className: "flex flex-col gap-1 text-xs text-stone-600 w-full sm:w-24" }, "Rooms", /*#__PURE__*/h("input", { type: "number", min: 1, className: "qb-input", value: line.qty, onChange: e => updateLine(line.id, { qty: e.target.value }) })), /*#__PURE__*/h("label", { className: "flex flex-col gap-1 text-xs text-stone-600 w-full sm:w-36" }, "Extra adults (max ", line.qty, ")", line.cat ? ` \u2014 base ${line.cat.base}/room` : "", /*#__PURE__*/h("input", { type: "number", min: 0, max: line.qty, className: "qb-input", value: line.extra, onChange: e => updateLine(line.id, { extra: e.target.value }) })), /*#__PURE__*/h("button", { onClick: () => removeLine(line.id), disabled: lines.length === 1, className: "qb-btn-ghost flex items-center justify-center rounded-lg p-2 text-stone-400 hover:text-red-500 disabled:opacity-30 disabled:hover:text-stone-400 transition", title: "Remove room line" }, /*#__PURE__*/h(Trash2, { size: 16 }))), line.cat && /*#__PURE__*/h("div", { className: "mt-2 text-xs text-stone-500 space-y-0.5" }, /*#__PURE__*/h("div", { className: "flex flex-wrap gap-x-3" }, weekdayNights > 0 && /*#__PURE__*/h("span", null, weekdayNights, " weekday night(s) @ ", inr(line.cat.weekday), " ", /*#__PURE__*/h("em", { className: "not-italic", style: { color: C.forest } }, "(GST ", (line.weekdaySlab * 100).toFixed(0), "%)")), weekendNights > 0 && /*#__PURE__*/h("span", null, weekendNights, " weekend night(s) @ ", inr(line.cat.weekend), " ", /*#__PURE__*/h("em", { className: "not-italic", style: { color: C.forest } }, "(GST ", (line.weekendSlab * 100).toFixed(0), "%)")), line.extra > 0 && /*#__PURE__*/h("span", null, "+", inr(line.cat.extra), "/night \u00d7 ", line.extra, " extra adult(s)")), /*#__PURE__*/h("div", { className: "flex" }, /*#__PURE__*/h("span", { className: "ml-auto font-medium", style: { color: C.forestDark } }, "Line total: ", inr(line.lineRevenue))), lineAvailability[line.id] && line.qty > lineAvailability[line.id].minAvailable && /*#__PURE__*/h("div", { className: "flex items-start gap-1.5 mt-1.5 rounded-md px-2 py-1.5", style: { background: "#FBD9D3", color: "#8a3b2f" } }, /*#__PURE__*/h(AlertTriangle, { size: 13, className: "mt-0.5 shrink-0" }), /*#__PURE__*/h("span", null, "Only ", Math.max(0, lineAvailability[line.id].minAvailable), " of ", line.qty, " ", line.cat.name, " available for these dates (of ", lineAvailability[line.id].total, " total) \u2014 already booked on ", lineAvailability[line.id].conflicts.slice(0, 3).map(c => fmtDateShort(addDays(c.iso, 0))).join(", "), lineAvailability[line.id].conflicts.length > 3 ? " and more" : "", ". Check Availability & Bookings before confirming."))))))), /*#__PURE__*/h("section", { style: { background: "#fff", border: `1px solid ${C.cream}` }, className: "rounded-xl p-4 sm:p-5 shadow-sm" }, /*#__PURE__*/h("h2", { style: { fontFamily: SERIF, color: C.forestDark }, className: "text-lg font-semibold mb-3" }, "Children & adjustments"), /*#__PURE__*/h("div", { className: "grid grid-cols-2 sm:grid-cols-4 gap-3" }, /*#__PURE__*/h("label", { className: "flex flex-col gap-1 text-xs text-stone-600" }, "Children 0\u20135 (free)", /*#__PURE__*/h("input", { type: "number", min: 0, className: "qb-input", value: under5, onChange: e => setUnder5(e.target.value) })), /*#__PURE__*/h("label", { className: "flex flex-col gap-1 text-xs text-stone-600" }, "Children 6\u201312 (\u20b9500/night)", /*#__PURE__*/h("input", { type: "number", min: 0, className: "qb-input", value: kids6to12, onChange: e => setKids6to12(e.target.value) })), /*#__PURE__*/h("label", { className: "flex flex-col gap-1 text-xs text-stone-600" }, "Discount type", /*#__PURE__*/h("select", { className: "qb-select", value: discountType, onChange: e => setDiscountType(e.target.value) }, /*#__PURE__*/h("option", { value: "percent" }, "Percent (%)"), /*#__PURE__*/h("option", { value: "flat" }, "Flat (\u20b9)"))), /*#__PURE__*/h("label", { className: "flex flex-col gap-1 text-xs text-stone-600" }, "Discount value", /*#__PURE__*/h("input", { type: "number", min: 0, className: "qb-input", value: discountValue, onChange: e => setDiscountValue(e.target.value) }))), /*#__PURE__*/h("p", { className: "text-xs text-stone-500 mt-2" }, "Above 12 years considered adult \u2014 add as an extra adult on the relevant room instead."), /*#__PURE__*/h("p", { className: "text-xs text-stone-500 mt-1" }, "GST is applied automatically per government slab: 5% where a night's room tariff is \u20b97,500 or below, 18% where it exceeds \u20b97,500.")), /*#__PURE__*/h("section", { style: { background: C.forestDark, color: C.creamSoft }, className: "rounded-xl p-4 sm:p-5 shadow-sm" }, /*#__PURE__*/h("h2", { style: { fontFamily: SERIF }, className: "text-lg font-semibold mb-3" }, "Quote summary"), /*#__PURE__*/h("div", { className: "space-y-1.5 text-sm" }, /*#__PURE__*/h(Row, { label: "Rent \u2014 5% GST slab (tariff \u2264 \u20b97,500)", value: inr(slab5Subtotal) }), /*#__PURE__*/h(Row, { label: "Rent \u2014 18% GST slab (tariff > \u20b97,500)", value: inr(slab18Subtotal) }), childrenCost > 0 && /*#__PURE__*/h(Row, { label: `Children (6\u201312) \u00d7 ${kids6to12} (included above)`, value: inr(childrenCost), muted: true }), /*#__PURE__*/h(Row, { label: "Subtotal", value: inr(subtotalBeforeDiscount) }), discountAmount > 0 && /*#__PURE__*/h(Row, { label: "Discount", value: `\u2212 ${inr(discountAmount)}`, muted: true }), /*#__PURE__*/h(Row, { label: "GST @ 5%", value: inr(gst5) }), /*#__PURE__*/h(Row, { label: "GST @ 18%", value: inr(gst18) }), /*#__PURE__*/h("div", { style: { borderColor: C.forest }, className: "border-t my-2" }), /*#__PURE__*/h("div", { className: "flex items-baseline justify-between" }, /*#__PURE__*/h("span", { style: { fontFamily: SERIF }, className: "text-lg" }, "Total"), /*#__PURE__*/h("span", { style: { fontFamily: SERIF, color: C.goldLight }, className: "text-2xl font-semibold" }, inr(grandTotal)))), /*#__PURE__*/h("div", { className: "flex flex-wrap gap-2 mt-4" }, /*#__PURE__*/h("button", { onClick: copyQuote, style: { background: C.gold, color: C.ink }, className: "flex items-center gap-1.5 text-sm font-medium px-3 py-2 rounded-lg hover:opacity-90 transition" }, copyState === "copied" ? /*#__PURE__*/h(Check, { size: 15 }) : /*#__PURE__*/h(Copy, { size: 15 }), copyState === "copied" ? "Copied" : "Copy quote text"), /*#__PURE__*/h("a", { href: whatsappHref, target: "_blank", rel: "noreferrer", style: { background: "#25D366", color: "#fff" }, className: "flex items-center gap-1.5 text-sm font-medium px-3 py-2 rounded-lg hover:opacity-90 transition" }, /*#__PURE__*/h(MessageCircle, { size: 15 }), " Share on WhatsApp"), /*#__PURE__*/h("button", { onClick: openPrintable, style: { background: C.goldLight, color: C.ink }, className: "flex items-center gap-1.5 text-sm font-medium px-3 py-2 rounded-lg hover:opacity-90 transition" }, /*#__PURE__*/h(Printer, { size: 15 }), " Print / Save PDF"), /*#__PURE__*/h("button", { onClick: saveQuote, disabled: saving, style: { background: C.forest, color: "#fff" }, className: "flex items-center gap-1.5 text-sm font-medium px-3 py-2 rounded-lg hover:opacity-90 transition disabled:opacity-60" }, saving ? /*#__PURE__*/h(Loader2, { size: 15, className: "animate-spin" }) : /*#__PURE__*/h(Save, { size: 15 }), "Save quote"), /*#__PURE__*/h("button", { onClick: confirmQuoteAsBooking, disabled: confirming, style: { background: "#8a3b2f", color: "#fff" }, className: "flex items-center gap-1.5 text-sm font-medium px-3 py-2 rounded-lg hover:opacity-90 transition disabled:opacity-60" }, confirming ? /*#__PURE__*/h(Loader2, { size: 15, className: "animate-spin" }) : /*#__PURE__*/h(Check, { size: 15 }), "Confirm booking & block dates"), saveMsg && /*#__PURE__*/h("span", { className: "text-xs self-center", style: { color: C.goldLight } }, saveMsg)), confirmMsg && /*#__PURE__*/h("p", { className: "text-xs mt-2", style: { color: C.goldLight } }, confirmMsg), printUrl && /*#__PURE__*/h("p", { className: "text-xs mt-2", style: { color: C.goldLight } }, "If a new tab didn't open (pop-up blocked), ", /*#__PURE__*/h("a", { href: printUrl, target: "_blank", rel: "noreferrer", className: "underline" }, "tap here to open the printable quote"), "."), copyState === "manual" && /*#__PURE__*/h("p", { className: "text-xs mt-2", style: { color: C.goldLight } }, "Clipboard access is blocked here \u2014 the text below is selected, so press Ctrl/Cmd+C to copy it."), /*#__PURE__*/h("textarea", { ref: textAreaRef, readOnly: true, value: shareText, style: { display: copyState === "manual" ? "block" : "none", background: "#fff", color: C.ink }, className: "w-full mt-2 text-xs rounded-lg p-2 h-40 font-mono" })), /*#__PURE__*/h("section", { style: { background: "#fff", border: `1px solid ${C.cream}` }, className: "rounded-xl shadow-sm overflow-hidden" }, /*#__PURE__*/h("button", { onClick: () => setSavedOpen(v => !v), className: "w-full flex items-center justify-between px-4 sm:px-5 py-3.5" }, /*#__PURE__*/h("span", { style: { fontFamily: SERIF, color: C.forestDark }, className: "text-lg font-semibold" }, "Saved quotes"), savedOpen ? /*#__PURE__*/h(ChevronUp, { size: 18, color: C.forest }) : /*#__PURE__*/h(ChevronDown, { size: 18, color: C.forest })), savedOpen && /*#__PURE__*/h("div", { className: "px-4 sm:px-5 pb-4" }, loadingSaved && /*#__PURE__*/h("div", { className: "text-sm text-stone-500 flex items-center gap-2" }, /*#__PURE__*/h(Loader2, { size: 14, className: "animate-spin" }), " Loading\u2026"), !loadingSaved && savedQuotes.length === 0 && /*#__PURE__*/h("div", { className: "text-sm text-stone-500" }, "No saved quotes yet. Build a quote above and tap \"Save quote\"."), /*#__PURE__*/h("div", { className: "space-y-2" }, savedQuotes.map(q => /*#__PURE__*/h("div", { key: q.id, style: { borderColor: C.cream }, className: "border rounded-lg p-3 flex items-center justify-between gap-3" }, /*#__PURE__*/h("div", { className: "min-w-0" }, /*#__PURE__*/h("div", { className: "text-sm font-medium truncate", style: { color: C.forestDark } }, q.guestName && q.guestName.trim() ? q.guestName.trim() : "Unnamed guest"), /*#__PURE__*/h("div", { className: "text-xs text-stone-500" }, q.checkIn, " \u00b7 ", q.nights, " night", q.nights > 1 ? "s" : "", " \u00b7 ", inr(q.grandTotal || 0))), /*#__PURE__*/h("div", { className: "flex items-center gap-2 shrink-0" }, /*#__PURE__*/h("button", { onClick: () => loadQuote(q), className: "text-xs px-2.5 py-1.5 rounded-md", style: { background: C.cream, color: C.forestDark } }, "Load"), /*#__PURE__*/h("button", { onClick: () => deleteQuote(q.id), className: "text-stone-400 hover:text-red-500 p-1.5", title: "Delete" }, /*#__PURE__*/h(X, { size: 15 })))))))), /*#__PURE__*/h("p", { className: "text-xs text-center text-stone-400 pb-2" }, "Rates on CP basis \u00b7 MAP/AP on request \u00b7 Check-in 2:00 PM \u00b7 Check-out 11:00 AM \u00b7 Rates subject to revision")), activeTab === "availability" && /*#__PURE__*/h("div", { className: "max-w-3xl mx-auto px-4 sm:px-8 py-6 space-y-5" }, /*#__PURE__*/h("section", { style: { background: "#fff", border: `1px solid ${C.cream}` }, className: "rounded-xl p-4 sm:p-5 shadow-sm" }, /*#__PURE__*/h("h2", { style: { fontFamily: SERIF, color: C.forestDark }, className: "text-lg font-semibold mb-1" }, "Room inventory"), /*#__PURE__*/h("p", { className: "text-xs text-stone-500 mb-3" }, "Total physical rooms per category \u2014 update any time. This is what availability checks and the calendar below are based on."), /*#__PURE__*/h("div", { className: "grid grid-cols-2 sm:grid-cols-3 gap-3" }, ROOM_CATEGORIES.map(c => /*#__PURE__*/h("label", { key: c.id, className: "flex flex-col gap-1 text-xs text-stone-600" }, c.name, /*#__PURE__*/h("input", { type: "number", min: 0, className: "qb-input", value: inventory[c.id] ?? 0, onChange: e => setInventoryValue(c.id, e.target.value) }))))), /*#__PURE__*/h("section", { style: { background: "#fff", border: `1px solid ${C.cream}` }, className: "rounded-xl p-4 sm:p-5 shadow-sm" }, /*#__PURE__*/h("h2", { style: { fontFamily: SERIF, color: C.forestDark }, className: "text-lg font-semibold mb-3" }, "Add a confirmed booking"), /*#__PURE__*/h("div", { className: "grid grid-cols-1 sm:grid-cols-5 gap-3" }, /*#__PURE__*/h("label", { className: "flex flex-col gap-1 text-xs text-stone-600 sm:col-span-2" }, "Guest name", /*#__PURE__*/h("input", { className: "qb-input", value: newBooking.guestName, onChange: e => setNewBooking({ ...newBooking, guestName: e.target.value }), placeholder: "e.g. Anitha Rao" })), /*#__PURE__*/h("label", { className: "flex flex-col gap-1 text-xs text-stone-600 sm:col-span-2" }, "Room category", /*#__PURE__*/h("select", { className: "qb-select", value: newBooking.categoryId, onChange: e => setNewBooking({ ...newBooking, categoryId: e.target.value }) }, ROOM_CATEGORIES.map(c => /*#__PURE__*/h("option", { key: c.id, value: c.id }, c.name)))), /*#__PURE__*/h("label", { className: "flex flex-col gap-1 text-xs text-stone-600" }, "Rooms", /*#__PURE__*/h("input", { type: "number", min: 1, className: "qb-input", value: newBooking.qty, onChange: e => setNewBooking({ ...newBooking, qty: e.target.value }) })), /*#__PURE__*/h("label", { className: "flex flex-col gap-1 text-xs text-stone-600" }, "Check-in", /*#__PURE__*/h("input", { type: "date", className: "qb-input", value: newBooking.checkIn, onChange: e => setNewBooking({ ...newBooking, checkIn: e.target.value }) })), /*#__PURE__*/h("label", { className: "flex flex-col gap-1 text-xs text-stone-600" }, "Nights", /*#__PURE__*/h("input", { type: "number", min: 1, className: "qb-input", value: newBooking.nights, onChange: e => setNewBooking({ ...newBooking, nights: e.target.value }) }))), /*#__PURE__*/h("button", { onClick: addBookingFromForm, style: { background: C.forest, color: "#fff" }, className: "flex items-center gap-1.5 text-sm font-medium px-3 py-2 rounded-lg hover:opacity-90 transition mt-3" }, /*#__PURE__*/h(Plus, { size: 15 }), " Add booking (blocks these dates)")), /*#__PURE__*/h("section", { style: { background: "#fff", border: `1px solid ${C.cream}` }, className: "rounded-xl p-4 sm:p-5 shadow-sm" }, /*#__PURE__*/h("h2", { style: { fontFamily: SERIF, color: C.forestDark }, className: "text-lg font-semibold mb-3" }, "Current bookings (", bookings.length, ")"), !bookingsLoaded && /*#__PURE__*/h("div", { className: "text-sm text-stone-500 flex items-center gap-2" }, /*#__PURE__*/h(Loader2, { size: 14, className: "animate-spin" }), " Loading\u2026"), bookingsLoaded && bookings.length === 0 && /*#__PURE__*/h("div", { className: "text-sm text-stone-500" }, "No bookings yet. Add one above, or confirm a quote from the Quote Builder tab."), /*#__PURE__*/h("div", { className: "space-y-2" }, bookings.map(b => { const cat = catById(b.categoryId); const bCheckIn = new Date(b.checkIn + "T00:00:00"); const bCheckOut = addDays(b.checkIn, b.nights); return /*#__PURE__*/h("div", { key: b.id, style: { borderColor: C.cream }, className: "border rounded-lg p-3 flex items-center justify-between gap-3" }, /*#__PURE__*/h("div", { className: "min-w-0" }, /*#__PURE__*/h("div", { className: "text-sm font-medium truncate", style: { color: C.forestDark } }, b.guestName && b.guestName.trim() ? b.guestName.trim() : "Unnamed guest", " \u2014 ", cat ? cat.name : b.categoryId), /*#__PURE__*/h("div", { className: "text-xs text-stone-500" }, fmtDate(bCheckIn), " \u2192 ", fmtDate(bCheckOut), " \u00b7 ", b.qty, " room", b.qty > 1 ? "s" : "")), /*#__PURE__*/h("button", { onClick: () => deleteBooking(b.id), className: "text-stone-400 hover:text-red-500 p-1.5 shrink-0", title: "Delete / release booking" }, /*#__PURE__*/h(Trash2, { size: 16 }))); }))), /*#__PURE__*/h("section", { style: { background: "#fff", border: `1px solid ${C.cream}` }, className: "rounded-xl p-4 sm:p-5 shadow-sm" }, /*#__PURE__*/h("h2", { style: { fontFamily: SERIF, color: C.forestDark }, className: "text-lg font-semibold mb-1" }, CAL_DAYS, "-day availability calendar"), /*#__PURE__*/h("label", { className: "flex items-center gap-2 text-xs text-stone-600 mb-3 mt-2" }, "Start date", /*#__PURE__*/h("input", { type: "date", className: "qb-input", value: calStart, onChange: e => setCalStart(e.target.value) })), /*#__PURE__*/h("div", { style: { overflowX: "auto" } }, /*#__PURE__*/h("table", { style: { borderCollapse: "collapse", fontSize: "11px", width: "100%" } }, /*#__PURE__*/h("thead", null, /*#__PURE__*/h("tr", null, /*#__PURE__*/h("th", { style: { padding: "4px 8px", textAlign: "left", color: C.forestDark, position: "sticky", left: 0, background: "#fff" } }, "Category"), Array.from({ length: CAL_DAYS }).map((_, i) => { const d = addDays(calStart, i); return /*#__PURE__*/h("th", { key: i, style: { padding: "4px 5px", textAlign: "center", color: C.forestDark, whiteSpace: "nowrap", fontWeight: 500 } }, fmtDayName(d), /*#__PURE__*/h("br", null), fmtDateShort(d)); }))), /*#__PURE__*/h("tbody", null, ROOM_CATEGORIES.map(cat => /*#__PURE__*/h("tr", { key: cat.id }, /*#__PURE__*/h("td", { style: { padding: "4px 8px", fontWeight: 500, whiteSpace: "nowrap", color: C.ink, position: "sticky", left: 0, background: "#fff" } }, cat.name), Array.from({ length: CAL_DAYS }).map((_, i) => { const d = addDays(calStart, i); const iso = isoOf(d); const total = inventory[cat.id] || 0; const booked = bookedQtyOnDate(cat.id, iso, bookings); const avail = total - booked; const bg = avail <= 0 ? "#FBD9D3" : avail < total ? "#FBEFDD" : "#E7F0E3"; const fg = avail <= 0 ? "#8a3b2f" : avail < total ? "#7A5A1E" : "#3D4F35"; return /*#__PURE__*/h("td", { key: i, style: { padding: "4px 5px", textAlign: "center", background: bg, color: fg, fontWeight: 600 } }, avail, "/", total); })))))), /*#__PURE__*/h("div", { className: "flex flex-wrap gap-4 mt-3 text-xs text-stone-500" }, /*#__PURE__*/h("span", null, /*#__PURE__*/h("span", { style: { display: "inline-block", width: 10, height: 10, background: "#E7F0E3", marginRight: 4, borderRadius: 2 } }), "Fully available"), /*#__PURE__*/h("span", null, /*#__PURE__*/h("span", { style: { display: "inline-block", width: 10, height: 10, background: "#FBEFDD", marginRight: 4, borderRadius: 2 } }), "Partially booked"), /*#__PURE__*/h("span", null, /*#__PURE__*/h("span", { style: { display: "inline-block", width: 10, height: 10, background: "#FBD9D3", marginRight: 4, borderRadius: 2 } }), "Fully booked"))), /*#__PURE__*/h("section", { style: { background: "#fff", border: `1px solid ${C.cream}` }, className: "rounded-xl p-4 sm:p-5 shadow-sm" }, /*#__PURE__*/h("h2", { style: { fontFamily: SERIF, color: C.forestDark }, className: "text-lg font-semibold mb-1" }, "Backup & restore"), /*#__PURE__*/h("p", { className: "text-xs text-stone-500 mb-3" }, "Inventory and bookings live only in this browser, on this computer. Export a backup regularly and keep the file safe \u2014 you can restore it here, or on another computer, at any time."), /*#__PURE__*/h("div", { className: "flex flex-wrap items-center gap-2" }, /*#__PURE__*/h("button", { onClick: exportBackup, disabled: exporting, style: { background: C.forest, color: "#fff" }, className: "flex items-center gap-1.5 text-sm font-medium px-3 py-2 rounded-lg hover:opacity-90 transition disabled:opacity-60" }, exporting ? /*#__PURE__*/h(Loader2, { size: 15, className: "animate-spin" }) : /*#__PURE__*/h(Save, { size: 15 }), "Export backup (.json)"), /*#__PURE__*/h("button", { onClick: () => fileInputRef.current && fileInputRef.current.click(), style: { background: C.goldLight, color: C.ink }, className: "flex items-center gap-1.5 text-sm font-medium px-3 py-2 rounded-lg hover:opacity-90 transition" }, "Restore from backup"), /*#__PURE__*/h("input", { ref: fileInputRef, type: "file", accept: "application/json", onChange: importBackup, style: { display: "none" } })), importMsg && /*#__PURE__*/h("p", { className: "text-xs mt-2", style: { color: C.forest } }, importMsg)))); } function Row({ label, value, muted }) { return /*#__PURE__*/h("div", { className: "flex items-baseline justify-between" }, /*#__PURE__*/h("span", { style: { opacity: muted ? 0.7 : 0.9, fontSize: muted ? "0.8em" : "1em" } }, label), /*#__PURE__*/h("span", { style: { opacity: muted ? 0.7 : 1, fontSize: muted ? "0.8em" : "1em" } }, value)); } mountApp(QuoteBuilder);