{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "hotel-booking-reservation",
  "title": "Hotel Booking Reservation",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/hotel-booking-reservation/HotelBookingReservation.vue",
      "content": "<script setup lang=\"ts\">\nimport { computed, ref, type HTMLAttributes } from 'vue'\nimport {\n  Baby,\n  Bath,\n  BedDouble,\n  Building2,\n  Calendar,\n  CalendarDays,\n  Check,\n  CheckCircle2,\n  Coffee,\n  CreditCard,\n  Heart,\n  Info,\n  Lock,\n  MapPin,\n  Maximize2,\n  Minus,\n  Plus,\n  RotateCcw,\n  Share2,\n  ShieldCheck,\n  Star,\n  Users,\n  Waves,\n  Wifi,\n} from 'lucide-vue-next'\nimport { cn } from '@/lib/utils'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Checkbox } from '@/components/ui/checkbox'\nimport { Input } from '@/components/ui/input'\nimport { Separator } from '@/components/ui/separator'\n\ninterface Props {\n  class?: HTMLAttributes['class']\n  roomTitle?: string\n  hotelName?: string\n  location?: string\n  rating?: number\n  reviewsCount?: number\n  basePrice?: number\n  initialCheckIn?: string\n  initialCheckOut?: string\n  initialAdults?: number\n  initialChildren?: number\n  initialRooms?: number\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n  roomTitle: 'Deluxe Ocean View King Suite',\n  hotelName: 'The Ritz-Carlton Bal Harbour, Miami',\n  location: 'Bal Harbour, Miami Beach, FL',\n  rating: 5.0,\n  reviewsCount: 120,\n  basePrice: 485,\n  initialCheckIn: '2026-08-24',\n  initialCheckOut: '2026-08-29',\n  initialAdults: 2,\n  initialChildren: 1,\n  initialRooms: 1,\n})\n\nconst checkInDate = ref(props.initialCheckIn)\nconst checkOutDate = ref(props.initialCheckOut)\nconst adults = ref(props.initialAdults)\nconst children = ref(props.initialChildren)\nconst rooms = ref(props.initialRooms)\nconst specialRequests = ref('')\nconst isBooked = ref(false)\nconst isSaved = ref(false)\nconst activePhotoIndex = ref(0)\n\nconst roomPhotos = [\n  {\n    url: 'https://images.unsplash.com/photo-1582719478250-c89cae4dc85b?w=1200&auto=format&fit=crop&q=80',\n    title: 'King Master Suite & Ocean Balcony',\n  },\n  {\n    url: 'https://images.unsplash.com/photo-1571896349842-33c89424de2d?w=800&auto=format&fit=crop&q=80',\n    title: 'Atlantic Ocean Sunrise Balcony',\n  },\n  {\n    url: 'https://images.unsplash.com/photo-1584622650111-993a426fbf0a?w=800&auto=format&fit=crop&q=80',\n    title: 'Italian Marble Spa Bathroom',\n  },\n  {\n    url: 'https://images.unsplash.com/photo-1540541338287-41700207dee6?w=800&auto=format&fit=crop&q=80',\n    title: 'Private Beach Club & Ocean Cabanas',\n  },\n]\n\n// Upgrades state: Oceanfront balcony and Daily Breakfast are checked by default\nconst selectedUpgrades = ref<string[]>(['balcony', 'breakfast'])\nconst breakfastGuests = ref(1)\n\nfunction toggleUpgrade(id: string) {\n  if (selectedUpgrades.value.includes(id)) {\n    selectedUpgrades.value = selectedUpgrades.value.filter((item) => item !== id)\n  } else {\n    selectedUpgrades.value = [...selectedUpgrades.value, id]\n  }\n}\n\n// Date calculations\nconst nights = computed(() => {\n  if (!checkInDate.value || !checkOutDate.value) return 5\n  const start = new Date(checkInDate.value).getTime()\n  const end = new Date(checkOutDate.value).getTime()\n  const diffDays = Math.round((end - start) / (1000 * 60 * 60 * 24))\n  return diffDays > 0 ? diffDays : 1\n})\n\nfunction setDuration(presetNights: number) {\n  if (!checkInDate.value) return\n  const start = new Date(checkInDate.value + 'T00:00:00')\n  start.setDate(start.getDate() + presetNights)\n  const y = start.getFullYear()\n  const m = String(start.getMonth() + 1).padStart(2, '0')\n  const d = String(start.getDate()).padStart(2, '0')\n  checkOutDate.value = `${y}-${m}-${d}`\n}\n\nfunction formatDateDisplay(dateStr: string) {\n  if (!dateStr) return ''\n  const [year, month, day] = dateStr.split('-').map(Number)\n  if (!year || !month || !day) return dateStr\n  const date = new Date(year, month - 1, day)\n  return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })\n}\n\nconst formattedRange = computed(() => {\n  return `${formatDateDisplay(checkInDate.value)} → ${formatDateDisplay(checkOutDate.value)} · ${nights.value} ${nights.value === 1 ? 'Night' : 'Nights'}`\n})\n\nconst cancellationDeadline = computed(() => {\n  if (!checkInDate.value) return '48 hours prior to arrival'\n  const start = new Date(checkInDate.value + 'T00:00:00')\n  start.setDate(start.getDate() - 2)\n  const y = start.getFullYear()\n  const m = String(start.getMonth() + 1).padStart(2, '0')\n  const d = String(start.getDate()).padStart(2, '0')\n  return formatDateDisplay(`${y}-${m}-${d}`)\n})\n\n// Financial calculations\nconst roomSubtotal = computed(() => {\n  return props.basePrice * nights.value * rooms.value\n})\n\nconst balconyCost = computed(() => {\n  return selectedUpgrades.value.includes('balcony') ? 50 * nights.value * rooms.value : 0\n})\n\nconst breakfastCost = computed(() => {\n  return selectedUpgrades.value.includes('breakfast') ? 35 * breakfastGuests.value * nights.value : 0\n})\n\nconst chauffeurCost = computed(() => {\n  return selectedUpgrades.value.includes('chauffeur') ? 120 : 0\n})\n\nconst spaCost = computed(() => {\n  return selectedUpgrades.value.includes('spa') ? 65 * adults.value : 0\n})\n\nconst selectedAddonsTotal = computed(() => {\n  return balconyCost.value + breakfastCost.value + chauffeurCost.value + spaCost.value\n})\n\nconst resortFee = computed(() => {\n  // $30 resort & hospitality fee per night per room\n  return 30 * nights.value * rooms.value\n})\n\nconst taxableSubtotal = computed(() => {\n  return roomSubtotal.value + selectedAddonsTotal.value + resortFee.value\n})\n\nconst estimatedTaxes = computed(() => {\n  // 14% state & hospitality tourism tax\n  return Math.round(taxableSubtotal.value * 0.14 * 100) / 100\n})\n\nconst totalStayPrice = computed(() => {\n  return taxableSubtotal.value + estimatedTaxes.value\n})\n\nfunction formatCurrency(val: number) {\n  return new Intl.NumberFormat('en-US', {\n    style: 'currency',\n    currency: 'USD',\n    minimumFractionDigits: 2,\n    maximumFractionDigits: 2,\n  }).format(val)\n}\n\n// Stepper modifiers\nfunction updateAdults(delta: number) {\n  const next = adults.value + delta\n  if (next >= 1 && next <= 8) {\n    adults.value = next\n    if (breakfastGuests.value > next) {\n      breakfastGuests.value = next\n    }\n  }\n}\n\nfunction updateChildren(delta: number) {\n  const next = children.value + delta\n  if (next >= 0 && next <= 6) {\n    children.value = next\n  }\n}\n\nfunction updateRooms(delta: number) {\n  const next = rooms.value + delta\n  if (next >= 1 && next <= 4) {\n    rooms.value = next\n  }\n}\n\nfunction handleReserve() {\n  isBooked.value = true\n}\n\nfunction resetBooking() {\n  isBooked.value = false\n}\n</script>\n\n<template>\n  <div\n    data-slot=\"hotel-booking-reservation\"\n    :class=\"cn('mx-auto w-full max-w-6xl space-y-8 p-4 sm:p-6 lg:p-8', props.class)\"\n  >\n    <!-- Confirmation Banner (Visible when booked) -->\n    <div\n      v-if=\"isBooked\"\n      class=\"border-success/30 bg-success/10 bg-success/15 relative flex flex-col gap-4 rounded-xl border p-5 sm:flex-row sm:items-center sm:justify-between\"\n    >\n      <div class=\"flex flex-wrap items-start gap-3.5\">\n        <div class=\"bg-success/20 text-success mt-0.5 flex size-9 shrink-0 items-center justify-center rounded-full\">\n          <CheckCircle2 class=\"size-5\" />\n        </div>\n        <div class=\"space-y-1\">\n          <div class=\"flex flex-wrap items-center gap-2\">\n            <h3 class=\"text-foreground text-base font-semibold\">Reservation Confirmed · Reference #RC-884920</h3>\n            <Badge wrap variant=\"outline\" class=\"border-success/40 text-success text-xs font-semibold\">\n              Guaranteed Direct\n            </Badge>\n          </div>\n          <p class=\"text-muted-foreground text-xs sm:text-sm\">\n            A confirmation voucher and check-in barcode have been sent to your registered email. No cancellation penalty\n            applies before {{ cancellationDeadline }}.\n          </p>\n        </div>\n      </div>\n      <Button variant=\"outline\" size=\"sm\" class=\"shrink-0 font-medium\" @click=\"resetBooking\">\n        <RotateCcw class=\"size-3.5\" />\n        Modify Reservation\n      </Button>\n    </div>\n\n    <!-- Room Hero Header Card -->\n    <Card class=\"border-border overflow-hidden shadow-xs\">\n      <div class=\"grid grid-cols-1 gap-6 p-5 sm:p-6 lg:grid-cols-12 lg:gap-8\">\n        <!-- Room Photo Showcase -->\n        <div class=\"space-y-3 lg:col-span-6\">\n          <div class=\"border-border bg-muted/40 relative aspect-16/10 w-full overflow-hidden rounded-xl border\">\n            <img\n              :src=\"roomPhotos[activePhotoIndex]?.url\"\n              :alt=\"roomPhotos[activePhotoIndex]?.title\"\n              class=\"size-full object-cover transition-colors duration-300\"\n            />\n            <div\n              class=\"pointer-events-none absolute inset-0 bg-gradient-to-t from-black/70 via-transparent to-black/20\"\n            />\n            <div class=\"absolute top-3 left-3 flex flex-wrap gap-1.5\">\n              <Badge\n                wrap\n                variant=\"secondary\"\n                class=\"bg-background/90 text-foreground text-xs font-medium backdrop-blur-xs\"\n              >\n                Oceanfront View\n              </Badge>\n              <Badge\n                wrap\n                variant=\"outline\"\n                class=\"bg-background/80 text-foreground border-white/20 text-xs backdrop-blur-xs\"\n              >\n                Floor 16\n              </Badge>\n            </div>\n            <div class=\"absolute top-3 right-3 flex items-center gap-1.5\">\n              <button\n                type=\"button\"\n                aria-label=\"Save to favorites\"\n                class=\"bg-background/80 hover:bg-background text-foreground flex size-8 items-center justify-center rounded-full backdrop-blur-xs transition-colors\"\n                @click=\"isSaved = !isSaved\"\n              >\n                <Heart\n                  :class=\"\n                    cn('size-4 transition-colors', isSaved ? 'fill-destructive text-destructive' : 'text-foreground')\n                  \"\n                />\n              </button>\n              <button\n                type=\"button\"\n                aria-label=\"Share suite\"\n                class=\"bg-background/80 hover:bg-background text-foreground flex size-8 items-center justify-center rounded-full backdrop-blur-xs transition-colors\"\n              >\n                <Share2 class=\"size-4\" />\n              </button>\n            </div>\n            <div class=\"absolute right-3 bottom-3 left-3 flex items-center justify-between text-xs text-white\">\n              <span class=\"font-medium drop-shadow-xs\">{{ roomPhotos[activePhotoIndex]?.title }}</span>\n              <span class=\"rounded bg-black/60 px-2 py-0.5 font-mono text-xs backdrop-blur-xs\">\n                {{ activePhotoIndex + 1 }} / {{ roomPhotos.length }}\n              </span>\n            </div>\n          </div>\n\n          <!-- Mini Thumbnail Selector -->\n          <div class=\"grid grid-cols-4 gap-2\">\n            <button\n              v-for=\"(photo, idx) in roomPhotos\"\n              :key=\"idx\"\n              type=\"button\"\n              :aria-label=\"photo.title\"\n              :class=\"\n                cn(\n                  'border-border relative aspect-16/10 overflow-hidden rounded-lg border transition-colors',\n                  activePhotoIndex === idx ? 'ring-primary border-primary ring-2' : 'opacity-70 hover:opacity-100',\n                )\n              \"\n              @click=\"activePhotoIndex = idx\"\n            >\n              <img :src=\"photo.url\" :alt=\"photo.title\" class=\"size-full object-cover\" />\n            </button>\n          </div>\n        </div>\n\n        <!-- Room Meta & Overview Information -->\n        <div class=\"flex flex-col justify-between space-y-4 lg:col-span-6\">\n          <div class=\"space-y-3\">\n            <div class=\"flex flex-wrap items-center justify-between gap-2\">\n              <div class=\"text-warning flex items-center gap-1.5 text-xs font-medium\">\n                <Star class=\"fill-warning text-warning size-4\" />\n                <span class=\"font-bold tabular-nums\">{{ rating.toFixed(1) }}</span>\n                <span class=\"text-muted-foreground underline underline-offset-2\"\n                  >{{ reviewsCount }} verified guest reviews</span\n                >\n              </div>\n              <Badge wrap variant=\"outline\" class=\"border-primary/30 bg-primary/5 text-primary text-xs font-medium\">\n                Official Best Rate Guarantee\n              </Badge>\n            </div>\n\n            <div class=\"space-y-1\">\n              <h1 class=\"text-foreground text-2xl font-bold tracking-tight sm:text-3xl\">\n                {{ roomTitle }}\n              </h1>\n              <div class=\"text-muted-foreground flex items-center gap-1.5 text-xs sm:text-sm\">\n                <Building2 class=\"text-primary size-4 shrink-0\" />\n                <span class=\"text-foreground font-medium\">{{ hotelName }}</span>\n              </div>\n              <div class=\"text-muted-foreground flex items-center gap-1.5 text-xs\">\n                <MapPin class=\"size-3.5 shrink-0\" />\n                <span>{{ location }}</span>\n              </div>\n            </div>\n\n            <p class=\"text-muted-foreground text-xs leading-relaxed sm:text-sm\">\n              Expansive oceanfront sanctuary featuring custom King pillowtop bedding, floor-to-ceiling glass doors\n              opening onto an oversized private balcony with sweeping Atlantic panoramas, freestanding soaking tub, and\n              bespoke in-room dining.\n            </p>\n\n            <!-- Room Key Amenities Grid -->\n            <div class=\"grid grid-cols-1 gap-2 pt-1 sm:grid-cols-2 md:grid-cols-3\">\n              <div class=\"border-border/60 bg-muted/20 flex items-center gap-2 rounded-md border p-2 text-xs\">\n                <Maximize2 class=\"text-muted-foreground size-3.5 shrink-0\" />\n                <span class=\"text-foreground font-medium\">680 sq ft / 63 m²</span>\n              </div>\n              <div class=\"border-border/60 bg-muted/20 flex items-center gap-2 rounded-md border p-2 text-xs\">\n                <BedDouble class=\"text-muted-foreground size-3.5 shrink-0\" />\n                <span class=\"text-foreground font-medium\">1 King Bed</span>\n              </div>\n              <div class=\"border-border/60 bg-muted/20 flex items-center gap-2 rounded-md border p-2 text-xs\">\n                <Waves class=\"text-muted-foreground size-3.5 shrink-0\" />\n                <span class=\"text-foreground font-medium\">Ocean Balcony</span>\n              </div>\n              <div class=\"border-border/60 bg-muted/20 flex items-center gap-2 rounded-md border p-2 text-xs\">\n                <Bath class=\"text-muted-foreground size-3.5 shrink-0\" />\n                <span class=\"text-foreground font-medium\">Marble Soaking Tub</span>\n              </div>\n              <div class=\"border-border/60 bg-muted/20 flex items-center gap-2 rounded-md border p-2 text-xs\">\n                <Wifi class=\"text-muted-foreground size-3.5 shrink-0\" />\n                <span class=\"text-foreground font-medium\">Fast Fiber WiFi</span>\n              </div>\n              <div class=\"border-border/60 bg-muted/20 flex items-center gap-2 rounded-md border p-2 text-xs\">\n                <Coffee class=\"text-muted-foreground size-3.5 shrink-0\" />\n                <span class=\"text-foreground font-medium\">Nespresso Machine</span>\n              </div>\n            </div>\n          </div>\n\n          <div\n            class=\"border-border/80 bg-muted/30 flex flex-wrap items-center justify-between gap-3 rounded-xl border p-3.5 sm:p-4\"\n          >\n            <div>\n              <span class=\"text-muted-foreground block text-xs font-medium tracking-wider uppercase\"\n                >Direct Member Rate</span\n              >\n              <div class=\"flex flex-wrap items-baseline gap-2\">\n                <span class=\"text-foreground text-2xl font-bold tracking-tight tabular-nums sm:text-3xl\">\n                  {{ formatCurrency(basePrice) }}\n                </span>\n                <span class=\"text-muted-foreground text-xs font-normal sm:text-sm\">/ night</span>\n                <span class=\"text-muted-foreground text-xs tabular-nums line-through sm:text-sm\">$560.00</span>\n              </div>\n            </div>\n            <Badge wrap variant=\"secondary\" class=\"border-success/20 bg-success/10 text-success text-xs font-semibold\">\n              Save 13% Direct\n            </Badge>\n          </div>\n        </div>\n      </div>\n    </Card>\n\n    <!-- Interactive 2-Column Booking Configuration & Price Breakdown Grid -->\n    <div class=\"grid grid-cols-1 gap-8 lg:grid-cols-12 lg:items-start\">\n      <!-- Left Column: Reservation Inputs, Guests & Upgrades -->\n      <div class=\"space-y-6 lg:col-span-7\">\n        <!-- Stay Dates Selection -->\n        <Card class=\"shadow-xs\">\n          <CardHeader>\n            <div class=\"flex items-center justify-between\">\n              <div class=\"space-y-0.5\">\n                <CardTitle class=\"text-lg\">Stay Dates &amp; Duration</CardTitle>\n                <CardDescription\n                  >Select your check-in and check-out dates to calculate live availability.</CardDescription\n                >\n              </div>\n              <Badge wrap variant=\"outline\" class=\"gap-1 text-xs font-medium\">\n                <CalendarDays class=\"text-primary size-3.5\" />\n                {{ nights }} {{ nights === 1 ? 'Night' : 'Nights' }}\n              </Badge>\n            </div>\n          </CardHeader>\n          <CardContent class=\"space-y-5\">\n            <!-- Date Inputs -->\n            <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n              <div class=\"space-y-2\">\n                <label for=\"check-in-date\" class=\"text-foreground flex items-center gap-1.5 text-xs font-semibold\">\n                  <Calendar class=\"text-primary size-3.5\" />\n                  Check-in Date (3:00 PM)\n                </label>\n                <Input\n                  id=\"check-in-date\"\n                  type=\"date\"\n                  :model-value=\"checkInDate\"\n                  @update:model-value=\"(val) => (checkInDate = String(val))\"\n                />\n              </div>\n\n              <div class=\"space-y-2\">\n                <label for=\"check-out-date\" class=\"text-foreground flex items-center gap-1.5 text-xs font-semibold\">\n                  <Calendar class=\"text-primary size-3.5\" />\n                  Check-out Date (12:00 PM)\n                </label>\n                <Input\n                  id=\"check-out-date\"\n                  type=\"date\"\n                  :model-value=\"checkOutDate\"\n                  @update:model-value=\"(val) => (checkOutDate = String(val))\"\n                />\n              </div>\n            </div>\n\n            <!-- Stay Summary Highlight & Quick Length Presets -->\n            <div\n              class=\"border-border/60 bg-muted/30 flex flex-col gap-3 rounded-lg border p-3 sm:flex-row sm:items-center sm:justify-between\"\n            >\n              <div class=\"text-foreground text-xs font-medium\">\n                <span class=\"text-muted-foreground\">Selected Stay: </span>\n                <span class=\"font-semibold\">{{ formattedRange }}</span>\n              </div>\n              <div class=\"flex flex-wrap items-center gap-1.5\">\n                <span class=\"text-muted-foreground mr-1 text-xs\">Quick:</span>\n                <Button\n                  v-for=\"preset in [3, 5, 7, 10]\"\n                  :key=\"preset\"\n                  variant=\"outline\"\n                  size=\"xs\"\n                  :class=\"\n                    nights === preset ? 'bg-primary text-primary-foreground border-primary hover:bg-primary/90' : ''\n                  \"\n                  @click=\"setDuration(preset)\"\n                >\n                  {{ preset }}N\n                </Button>\n              </div>\n            </div>\n          </CardContent>\n        </Card>\n\n        <!-- Guests & Rooms Steppers -->\n        <Card class=\"shadow-xs\">\n          <CardHeader>\n            <CardTitle class=\"text-lg\">Guests &amp; Rooms</CardTitle>\n            <CardDescription>Configure the number of adults, children, and suites requested.</CardDescription>\n          </CardHeader>\n          <CardContent class=\"space-y-4\">\n            <!-- Adults Stepper -->\n            <div class=\"border-border/60 flex flex-wrap items-center justify-between rounded-lg border p-3.5\">\n              <div class=\"flex items-center gap-3\">\n                <div\n                  class=\"bg-primary/10 text-primary border-primary/20 flex size-9 shrink-0 items-center justify-center rounded-lg border\"\n                >\n                  <Users class=\"size-4\" />\n                </div>\n                <div class=\"space-y-0.5\">\n                  <span class=\"text-foreground text-sm font-medium\">Adults</span>\n                  <p class=\"text-muted-foreground text-xs\">Ages 13 and above</p>\n                </div>\n              </div>\n              <div class=\"flex items-center gap-3\">\n                <Button\n                  variant=\"outline\"\n                  size=\"icon-sm\"\n                  :disabled=\"adults <= 1\"\n                  aria-label=\"Decrease adults\"\n                  @click=\"updateAdults(-1)\"\n                >\n                  <Minus class=\"size-3.5\" />\n                </Button>\n                <span class=\"text-foreground w-6 text-center text-sm font-bold tabular-nums\">{{ adults }}</span>\n                <Button\n                  variant=\"outline\"\n                  size=\"icon-sm\"\n                  :disabled=\"adults >= 8\"\n                  aria-label=\"Increase adults\"\n                  @click=\"updateAdults(1)\"\n                >\n                  <Plus class=\"size-3.5\" />\n                </Button>\n              </div>\n            </div>\n\n            <!-- Children Stepper -->\n            <div class=\"border-border/60 flex flex-wrap items-center justify-between rounded-lg border p-3.5\">\n              <div class=\"flex items-center gap-3\">\n                <div\n                  class=\"bg-primary/10 text-primary border-primary/20 flex size-9 shrink-0 items-center justify-center rounded-lg border\"\n                >\n                  <Baby class=\"size-4\" />\n                </div>\n                <div class=\"space-y-0.5\">\n                  <span class=\"text-foreground text-sm font-medium\">Children</span>\n                  <p class=\"text-muted-foreground text-xs\">Ages 0 to 12 years</p>\n                </div>\n              </div>\n              <div class=\"flex items-center gap-3\">\n                <Button\n                  variant=\"outline\"\n                  size=\"icon-sm\"\n                  :disabled=\"children <= 0\"\n                  aria-label=\"Decrease children\"\n                  @click=\"updateChildren(-1)\"\n                >\n                  <Minus class=\"size-3.5\" />\n                </Button>\n                <span class=\"text-foreground w-6 text-center text-sm font-bold tabular-nums\">{{ children }}</span>\n                <Button\n                  variant=\"outline\"\n                  size=\"icon-sm\"\n                  :disabled=\"children >= 6\"\n                  aria-label=\"Increase children\"\n                  @click=\"updateChildren(1)\"\n                >\n                  <Plus class=\"size-3.5\" />\n                </Button>\n              </div>\n            </div>\n\n            <!-- Rooms Stepper -->\n            <div class=\"border-border/60 flex flex-wrap items-center justify-between rounded-lg border p-3.5\">\n              <div class=\"flex items-center gap-3\">\n                <div\n                  class=\"bg-primary/10 text-primary border-primary/20 flex size-9 shrink-0 items-center justify-center rounded-lg border\"\n                >\n                  <BedDouble class=\"size-4\" />\n                </div>\n                <div class=\"space-y-0.5\">\n                  <span class=\"text-foreground text-sm font-medium\">Suites / Rooms</span>\n                  <p class=\"text-muted-foreground text-xs\">Max 4 guests per suite</p>\n                </div>\n              </div>\n              <div class=\"flex items-center gap-3\">\n                <Button\n                  variant=\"outline\"\n                  size=\"icon-sm\"\n                  :disabled=\"rooms <= 1\"\n                  aria-label=\"Decrease rooms\"\n                  @click=\"updateRooms(-1)\"\n                >\n                  <Minus class=\"size-3.5\" />\n                </Button>\n                <span class=\"text-foreground w-6 text-center text-sm font-bold tabular-nums\">{{ rooms }}</span>\n                <Button\n                  variant=\"outline\"\n                  size=\"icon-sm\"\n                  :disabled=\"rooms >= 4\"\n                  aria-label=\"Increase rooms\"\n                  @click=\"updateRooms(1)\"\n                >\n                  <Plus class=\"size-3.5\" />\n                </Button>\n              </div>\n            </div>\n          </CardContent>\n        </Card>\n\n        <!-- Room Upgrades & Add-ons -->\n        <Card class=\"shadow-xs\">\n          <CardHeader>\n            <div class=\"flex items-center justify-between\">\n              <div class=\"space-y-0.5\">\n                <CardTitle class=\"text-lg\">Room Upgrades &amp; Exclusive Services</CardTitle>\n                <CardDescription\n                  >Tailor your stay with luxury amenities and curated hotel enhancements.</CardDescription\n                >\n              </div>\n              <Badge wrap variant=\"secondary\" class=\"text-xs\"> {{ selectedUpgrades.length }} Selected </Badge>\n            </div>\n          </CardHeader>\n          <CardContent class=\"space-y-3\">\n            <!-- Upgrade 1: Oceanfront Balcony -->\n            <div\n              role=\"button\"\n              tabindex=\"0\"\n              :class=\"\n                cn(\n                  'border-border focus-visible:ring-ring flex cursor-pointer items-start justify-between gap-4 rounded-xl border p-4 transition-colors select-none focus-visible:ring-2 focus-visible:outline-none',\n                  selectedUpgrades.includes('balcony')\n                    ? 'border-primary/40 bg-primary/5 shadow-xs'\n                    : 'bg-card hover:border-border/80 opacity-80 hover:opacity-100',\n                )\n              \"\n              @click=\"toggleUpgrade('balcony')\"\n              @keydown.space.prevent=\"toggleUpgrade('balcony')\"\n              @keydown.enter.prevent=\"toggleUpgrade('balcony')\"\n            >\n              <div class=\"flex flex-wrap items-start gap-3.5\">\n                <Checkbox\n                  id=\"upgrade-balcony\"\n                  :model-value=\"selectedUpgrades.includes('balcony')\"\n                  class=\"pointer-events-none mt-1\"\n                  tabindex=\"-1\"\n                />\n                <div class=\"space-y-1\">\n                  <div class=\"flex flex-wrap items-center gap-2\">\n                    <span class=\"text-foreground text-sm font-semibold\">Oceanfront High-Floor Balcony</span>\n                    <Badge wrap variant=\"outline\" class=\"text-xs font-medium\">+$50 / night</Badge>\n                  </div>\n                  <p class=\"text-muted-foreground text-xs leading-relaxed\">\n                    Guaranteed unobstructed 180° Atlantic Ocean sunrise view on floors 15+ with premium teak deck\n                    loungers.\n                  </p>\n                </div>\n              </div>\n              <div class=\"shrink-0 text-right\">\n                <span class=\"text-foreground text-sm font-bold tabular-nums\">\n                  +{{ formatCurrency(50 * nights * rooms) }}\n                </span>\n                <span class=\"text-muted-foreground block text-xs\">for {{ nights }} nights</span>\n              </div>\n            </div>\n\n            <!-- Upgrade 2: Gourmet Breakfast -->\n            <div\n              role=\"button\"\n              tabindex=\"0\"\n              :class=\"\n                cn(\n                  'border-border focus-visible:ring-ring flex cursor-pointer items-start justify-between gap-4 rounded-xl border p-4 transition-colors select-none focus-visible:ring-2 focus-visible:outline-none',\n                  selectedUpgrades.includes('breakfast')\n                    ? 'border-primary/40 bg-primary/5 shadow-xs'\n                    : 'bg-card hover:border-border/80 opacity-80 hover:opacity-100',\n                )\n              \"\n              @click=\"toggleUpgrade('breakfast')\"\n              @keydown.space.prevent=\"toggleUpgrade('breakfast')\"\n              @keydown.enter.prevent=\"toggleUpgrade('breakfast')\"\n            >\n              <div class=\"flex flex-wrap items-start gap-3.5\">\n                <Checkbox\n                  id=\"upgrade-breakfast\"\n                  :model-value=\"selectedUpgrades.includes('breakfast')\"\n                  class=\"pointer-events-none mt-1\"\n                  tabindex=\"-1\"\n                />\n                <div class=\"space-y-1\">\n                  <div class=\"flex flex-wrap items-center gap-2\">\n                    <span class=\"text-foreground text-sm font-semibold\">Daily Gourmet Breakfast</span>\n                    <Badge wrap variant=\"outline\" class=\"text-xs font-medium\">+$35 / person / day</Badge>\n                  </div>\n                  <p class=\"text-muted-foreground text-xs leading-relaxed\">\n                    Artisanal morning buffet at Artisan Beach House or private veranda in-room breakfast with fresh\n                    juices.\n                  </p>\n                  <!-- Guest selection when active -->\n                  <div\n                    v-if=\"selectedUpgrades.includes('breakfast')\"\n                    class=\"flex flex-wrap items-center gap-2 pt-1.5 text-xs\"\n                    @click.stop\n                  >\n                    <span class=\"text-muted-foreground\">Breakfast plan for:</span>\n                    <div class=\"flex flex-wrap items-center gap-1.5\">\n                      <Button\n                        v-for=\"count in [1, 2]\"\n                        :key=\"count\"\n                        variant=\"outline\"\n                        size=\"xs\"\n                        :class=\"breakfastGuests === count ? 'bg-primary text-primary-foreground border-primary' : ''\"\n                        @click=\"breakfastGuests = count\"\n                      >\n                        {{ count }} {{ count === 1 ? 'Guest' : 'Guests' }}\n                      </Button>\n                    </div>\n                  </div>\n                </div>\n              </div>\n              <div class=\"shrink-0 text-right\">\n                <span class=\"text-foreground text-sm font-bold tabular-nums\">\n                  +{{ formatCurrency(35 * breakfastGuests * nights) }}\n                </span>\n                <span class=\"text-muted-foreground block text-xs\">\n                  {{ breakfastGuests }} {{ breakfastGuests === 1 ? 'guest' : 'guests' }} · {{ nights }}d\n                </span>\n              </div>\n            </div>\n\n            <!-- Upgrade 3: Airport Chauffeur -->\n            <div\n              role=\"button\"\n              tabindex=\"0\"\n              :class=\"\n                cn(\n                  'border-border focus-visible:ring-ring flex cursor-pointer items-start justify-between gap-4 rounded-xl border p-4 transition-colors select-none focus-visible:ring-2 focus-visible:outline-none',\n                  selectedUpgrades.includes('chauffeur')\n                    ? 'border-primary/40 bg-primary/5 shadow-xs'\n                    : 'bg-card hover:border-border/80 opacity-80 hover:opacity-100',\n                )\n              \"\n              @click=\"toggleUpgrade('chauffeur')\"\n              @keydown.space.prevent=\"toggleUpgrade('chauffeur')\"\n              @keydown.enter.prevent=\"toggleUpgrade('chauffeur')\"\n            >\n              <div class=\"flex flex-wrap items-start gap-3.5\">\n                <Checkbox\n                  id=\"upgrade-chauffeur\"\n                  :model-value=\"selectedUpgrades.includes('chauffeur')\"\n                  class=\"pointer-events-none mt-1\"\n                  tabindex=\"-1\"\n                />\n                <div class=\"space-y-1\">\n                  <div class=\"flex flex-wrap items-center gap-2\">\n                    <span class=\"text-foreground text-sm font-semibold\">Private Airport Luxury Chauffeur</span>\n                    <Badge wrap variant=\"outline\" class=\"text-xs font-medium\">+$120 one-time</Badge>\n                  </div>\n                  <p class=\"text-muted-foreground text-xs leading-relaxed\">\n                    Curbside meet-and-greet with dedicated Cadillac Escalade or Mercedes S-Class transfer from MIA or\n                    FLL.\n                  </p>\n                </div>\n              </div>\n              <div class=\"shrink-0 text-right\">\n                <span class=\"text-foreground text-sm font-bold tabular-nums\">+$120.00</span>\n                <span class=\"text-muted-foreground block text-xs\">flat one-time</span>\n              </div>\n            </div>\n          </CardContent>\n        </Card>\n\n        <!-- Special Requests Card -->\n        <Card class=\"shadow-xs\">\n          <CardHeader class=\"pb-3\">\n            <CardTitle class=\"text-base\">Special Requests &amp; Arrival Notes</CardTitle>\n            <CardDescription\n              >Let us know if you are celebrating a special occasion or require early check-in.</CardDescription\n            >\n          </CardHeader>\n          <CardContent>\n            <Input\n              id=\"special-requests\"\n              v-model=\"specialRequests\"\n              placeholder=\"e.g., Honeymoon celebration, feather-free bedding, quiet high floor...\"\n              maxlength=\"200\"\n              show-count\n            />\n          </CardContent>\n        </Card>\n      </div>\n\n      <!-- Right Column: Total Price Breakdown & Checkout Card (Sticky) -->\n      <div class=\"lg:sticky lg:top-8 lg:col-span-5\">\n        <Card class=\"border-border bg-card shadow-xs\">\n          <CardHeader class=\"pb-4\">\n            <div class=\"flex items-center justify-between\">\n              <span class=\"text-muted-foreground text-xs font-semibold tracking-wider uppercase\">\n                Stay Price Breakdown\n              </span>\n              <Badge\n                wrap\n                variant=\"secondary\"\n                class=\"bg-primary/10 text-primary border-primary/20 gap-1 text-xs font-medium\"\n              >\n                <CheckCircle2 class=\"size-3\" />\n                Instant Confirmation\n              </Badge>\n            </div>\n\n            <div class=\"mt-3 space-y-1\">\n              <div class=\"text-muted-foreground text-xs\">Total Stay Price (USD)</div>\n              <div class=\"flex items-baseline gap-2\">\n                <span class=\"text-foreground text-3xl font-bold tracking-tight tabular-nums sm:text-4xl\">\n                  {{ formatCurrency(totalStayPrice) }}\n                </span>\n              </div>\n              <p class=\"text-muted-foreground text-xs\">\n                Total for <span class=\"text-foreground font-medium\">{{ nights }} nights</span> · {{ rooms }} suite ·\n                {{ adults + children }} guests\n              </p>\n            </div>\n          </CardHeader>\n\n          <CardContent class=\"space-y-4\">\n            <Separator />\n\n            <!-- Itemized Pricing Breakdown -->\n            <div class=\"space-y-2.5\">\n              <!-- Base Room Subtotal -->\n              <div class=\"flex items-center justify-between text-sm\">\n                <span class=\"text-muted-foreground\">\n                  Room subtotal ({{ formatCurrency(basePrice) }} × {{ nights }} {{ nights === 1 ? 'night' : 'nights'\n                  }}{{ rooms > 1 ? ` × ${rooms} rooms` : '' }})\n                </span>\n                <span class=\"text-foreground font-semibold tabular-nums\">{{ formatCurrency(roomSubtotal) }}</span>\n              </div>\n\n              <!-- Selected Add-ons summary / itemized -->\n              <div class=\"space-y-1.5\">\n                <div class=\"flex items-center justify-between text-sm\">\n                  <span class=\"text-muted-foreground\"> Selected Add-ons ({{ selectedUpgrades.length }} active) </span>\n                  <span class=\"text-foreground font-semibold tabular-nums\">{{\n                    formatCurrency(selectedAddonsTotal)\n                  }}</span>\n                </div>\n\n                <!-- Addon sub-items -->\n                <div\n                  v-if=\"selectedUpgrades.length > 0\"\n                  class=\"border-border/60 bg-muted/20 space-y-1 rounded-md border p-2.5 text-xs\"\n                >\n                  <div\n                    v-if=\"selectedUpgrades.includes('balcony')\"\n                    class=\"text-muted-foreground flex items-center justify-between\"\n                  >\n                    <span>• Oceanfront Balcony ({{ formatCurrency(50) }} × {{ nights }}n)</span>\n                    <span class=\"text-foreground font-medium tabular-nums\">{{ formatCurrency(balconyCost) }}</span>\n                  </div>\n                  <div\n                    v-if=\"selectedUpgrades.includes('breakfast')\"\n                    class=\"text-muted-foreground flex items-center justify-between\"\n                  >\n                    <span>• Gourmet Breakfast ({{ formatCurrency(35) }} × {{ breakfastGuests }}g × {{ nights }}d)</span>\n                    <span class=\"text-foreground font-medium tabular-nums\">{{ formatCurrency(breakfastCost) }}</span>\n                  </div>\n                  <div\n                    v-if=\"selectedUpgrades.includes('chauffeur')\"\n                    class=\"text-muted-foreground flex items-center justify-between\"\n                  >\n                    <span>• Luxury Airport Chauffeur (one-time)</span>\n                    <span class=\"text-foreground font-medium tabular-nums\">{{ formatCurrency(chauffeurCost) }}</span>\n                  </div>\n                  <div\n                    v-if=\"selectedUpgrades.includes('spa')\"\n                    class=\"text-muted-foreground flex items-center justify-between\"\n                  >\n                    <span>• Thermal Spa Pass ({{ formatCurrency(65) }} × {{ adults }} guests)</span>\n                    <span class=\"text-foreground font-medium tabular-nums\">{{ formatCurrency(spaCost) }}</span>\n                  </div>\n                </div>\n              </div>\n\n              <!-- Resort Fee -->\n              <div class=\"flex items-center justify-between text-sm\">\n                <div class=\"flex items-center gap-1\">\n                  <span class=\"text-muted-foreground\">Resort &amp; Hospitality Fee</span>\n                  <Info class=\"text-muted-foreground/70 size-3.5 cursor-help\" />\n                </div>\n                <span class=\"text-foreground font-semibold tabular-nums\">{{ formatCurrency(resortFee) }}</span>\n              </div>\n              <div class=\"text-muted-foreground pl-0.5 text-xs\">\n                $30.00 / night · Beach loungers, high-speed WiFi, welcome champagne\n              </div>\n\n              <!-- Estimated Taxes -->\n              <div class=\"flex items-center justify-between text-sm\">\n                <span class=\"text-muted-foreground\">Estimated Taxes &amp; Tourism Surcharge (14%)</span>\n                <span class=\"text-foreground font-semibold tabular-nums\">{{ formatCurrency(estimatedTaxes) }}</span>\n              </div>\n            </div>\n\n            <Separator />\n\n            <!-- Cancellation Policy Banner -->\n            <div class=\"border-success/20 bg-success/10 bg-success/15 space-y-1 rounded-xl border p-3.5\">\n              <div class=\"flex items-center gap-2\">\n                <ShieldCheck class=\"text-success size-4 shrink-0\" />\n                <span class=\"text-foreground text-xs font-semibold\"\n                  >Free cancellation until 48 hours before check-in</span\n                >\n              </div>\n              <p class=\"text-muted-foreground pl-6 text-xs leading-normal\">\n                Cancel before <span class=\"text-foreground font-medium\">{{ cancellationDeadline }}</span> for a 100%\n                full refund with zero fees.\n              </p>\n            </div>\n\n            <!-- Trust Bullet Points -->\n            <ul class=\"text-muted-foreground space-y-2 text-xs\">\n              <li class=\"flex items-center gap-2\">\n                <Check class=\"text-primary size-3.5 shrink-0\" />\n                <span>No upfront booking fees or surprise service surcharges</span>\n              </li>\n              <li class=\"flex items-center gap-2\">\n                <Check class=\"text-primary size-3.5 shrink-0\" />\n                <span>Official Ritz-Carlton direct member rewards applied</span>\n              </li>\n              <li class=\"flex items-center gap-2\">\n                <Lock class=\"text-primary size-3.5 shrink-0\" />\n                <span>256-bit encrypted secure bank checkout</span>\n              </li>\n            </ul>\n          </CardContent>\n\n          <CardFooter class=\"flex flex-col gap-2.5 pt-2\">\n            <Button class=\"w-full gap-2 font-semibold shadow-xs\" size=\"lg\" @click=\"handleReserve\">\n              <CreditCard class=\"size-4\" />\n              <span>Reserve &amp; Pay Now ({{ formatCurrency(totalStayPrice) }})</span>\n            </Button>\n            <Button variant=\"outline\" class=\"w-full text-xs font-medium\" size=\"default\" @click=\"handleReserve\">\n              Hold Room · Pay at Check-in\n            </Button>\n            <p class=\"text-muted-foreground text-center text-xs\">\n              You won't be charged yet. Final confirmation is sent instantly.\n            </p>\n          </CardFooter>\n        </Card>\n      </div>\n    </div>\n  </div>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/HotelBookingReservation.vue"
    }
  ],
  "dependencies": [
    "lucide-vue-next"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/vue/badge.json",
    "https://uipkge.dev/r/vue/button.json",
    "https://uipkge.dev/r/vue/card.json",
    "https://uipkge.dev/r/vue/checkbox.json",
    "https://uipkge.dev/r/vue/input.json",
    "https://uipkge.dev/r/vue/separator.json"
  ],
  "description": "Luxury hotel room booking and reservation widget with interactive date range picker, guest & room steppers, room upgrade checkboxes, live reactive pricing breakdown, and instant reservation checkout.",
  "categories": [
    "commerce",
    "hospitality",
    "booking",
    "ecommerce",
    "app"
  ]
}