"use client";
/* eslint-disable @next/next/no-img-element -- served through /api/media with our own responsive variants */

import * as React from "react";
import Link from "next/link";
import { useConvex, useQuery } from "convex/react";
import { AnimatePresence, motion, useReducedMotion } from "motion/react";
import { ArrowRight, BadgeCheck, Bath, BedDouble, Building2, ChevronDown, Flame, Lock, LogIn, Mail, MapPin, Minus, Phone, Plus, Search, Sparkles, Users, X, Zap } from "lucide-react";
import { api } from "../../../convex/_generated/api";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { LoginForm } from "@/app/(auth)/login/login-form";
import { ApartmentSheet } from "./apartment-sheet";
import { ContactDock } from "./contact-dock";
import { LeadForm } from "./lead-form";
import { ReviewsSection, GoogleRatingChip, useGoogleReviews } from "./reviews-section";
import { BookingFlow } from "./booking-flow";
import { PulseToasts, type Pulse } from "./pulse-toasts";
import { ExitNudge } from "./exit-nudge";
import { FacebookPixel, track } from "./fb-pixel";
import { captureAttribution } from "@/lib/attribution";
import { AnimatedText } from "@/components/motion/animated-number";
import { fmtMoney, fmtPhone } from "@/lib/format";
import { addDays, dayKey, fmtDate, nightsBetween, parseDay } from "@/lib/dates";

export interface Apartment {
  id: string;
  code: string;
  name: string;
  city: string;
  building: string | null;
  floor: string | null;
  bedrooms: number;
  beds: number;
  bathrooms: number;
  maxGuests: number;
  basePrice: number;
  weekendPrice: number | null;
  amenities: string[];
  images: { id: string; caption: string | null; category: string }[];
}
export interface Business {
  name: string;
  phone: string;
  whatsapp: string;
  email: string;
  address: string;
  currency: string;
  checkInTime: string;
  checkOutTime: string;
  weekendDays: number[];
  replyMinutes: number;
  reviewUrl: string;
  mapsUrl: string;
  hasGooglePlace: boolean;
  fbPixelId: string;
}
export interface Catalog {
  business: Business;
  apartments: Apartment[];
}
export interface Avail {
  id: string;
  available: boolean;
  nights: number;
  subtotal: number;
  nightlyPrice: number;
}

const src = (id: string, w: number) => `/api/media/${id}?w=${w}`;
const HERO_MS = 7000;
const ease = [0.16, 1, 0.3, 1] as const;

function useIsPhone() {
  const [phone, setPhone] = React.useState(false);
  React.useEffect(() => {
    const mq = window.matchMedia("(max-width: 767px)");
    const on = () => setPhone(mq.matches);
    on();
    mq.addEventListener("change", on);
    return () => mq.removeEventListener("change", on);
  }, []);
  return phone;
}

/**
 * Public showroom + staff entrance. A cinematic hero cycles through the
 * apartments, a date bar checks live availability, cards show what is free
 * and for how much, and the staff sign-in slides in only when asked for.
 */
export function ShowroomPage({ initial, next, openSignIn, focus, presetIn, presetOut, presetGuests }: { initial: Catalog | null; next?: string; openSignIn?: boolean; /** apartment to open immediately (shared link) */ focus?: string; presetIn?: string; presetOut?: string; presetGuests?: number }) {
  const live = useQuery(api.showroom.catalog, {}) as Catalog | undefined;
  const catalog = live ?? initial;
  const apartments = React.useMemo(() => catalog?.apartments ?? [], [catalog]);
  const business: Business = catalog?.business ?? { name: "LocaJour", phone: "", whatsapp: "", email: "", address: "", currency: "MAD", checkInTime: "14:00", checkOutTime: "11:00", weekendDays: [5, 6], replyMinutes: 10, reviewUrl: "", mapsUrl: "", hasGooglePlace: false, fbPixelId: "" };
  const reduced = useReducedMotion();
  const phone = useIsPhone();

  const [today] = React.useState(() => dayKey(new Date()));
  const [checkIn, setCheckIn] = React.useState(presetIn && presetIn >= today ? presetIn : today);
  const [checkOut, setCheckOut] = React.useState(presetIn && presetOut && presetOut > presetIn && presetIn >= today ? presetOut : dayKey(addDays(new Date(), 2)));
  const [guests, setGuests] = React.useState(presetGuests ?? 2);
  const [onlyFree, setOnlyFree] = React.useState(false);
  const [hero, setHero] = React.useState(() => Math.max(0, (initial?.apartments ?? []).findIndex((a) => a.id === focus)));
  const [signIn, setSignIn] = React.useState(!!openSignIn);
  const [selected, setSelected] = React.useState<string | null>(focus ?? null);

  const nights = checkIn && checkOut ? nightsBetween(parseDay(checkIn), parseDay(checkOut)) : 0;
  const availData = useQuery(api.showroom.availability, nights > 0 ? { checkIn, checkOut } : "skip") as { items: Avail[] } | undefined;
  const avail = React.useMemo(() => new Map((availData?.items ?? []).map((a) => [a.id, a])), [availData]);
  const freeCount = apartments.filter((a) => avail.get(a.id)?.available && a.maxGuests >= guests).length;

  const [reviewsOk, setReviewsOk] = React.useState(false);
  const [booking, setBooking] = React.useState<string | null>(null);
  const google = useGoogleReviews(business.hasGooglePlace);
  // Social proof is read once per visit, not subscribed: as a live query every
  // reservation anyone books would re-run it for every visitor on the site.
  const convex = useConvex();
  const [pulse, setPulse] = React.useState<Pulse | undefined>(undefined);
  React.useEffect(() => {
    let alive = true;
    convex
      .query(api.showroom.pulse, {})
      .then((p) => alive && setPulse(p as Pulse))
      .catch(() => {});
    return () => {
      alive = false;
    };
  }, [convex]);
  const bookingApt = apartments.find((a) => a.id === booking) ?? null;
  const startBooking = (id: string) => {
    setSelected(null);
    setBooking(id);
  };
  const quickDates = (kind: "tonight" | "weekend" | "3n") => {
    const t = parseDay(today);
    if (kind === "tonight") setDates(today, dayKey(addDays(t, 1)));
    else if (kind === "3n") setDates(today, dayKey(addDays(t, 3)));
    else {
      const dow = t.getUTCDay();
      const fri = dow === 5 || dow === 6 ? t : addDays(t, (5 - dow + 7) % 7 || 7);
      setDates(dayKey(fri), dayKey(addDays(fri, 2)));
    }
    goResults();
  };
  React.useEffect(() => {
    captureAttribution();
  }, []);
  React.useEffect(() => {
    if (nights > 0 && availData) track("Search", { checkIn, checkOut, guests });
    // eslint-disable-next-line react-hooks/exhaustive-deps -- fire once per completed search
  }, [availData]);

  // Hero auto-advance
  React.useEffect(() => {
    if (reduced || apartments.length < 2 || selected || signIn || booking) return;
    const t = setInterval(() => setHero((h) => (h + 1) % apartments.length), HERO_MS);
    return () => clearInterval(t);
  }, [reduced, apartments.length, selected, signIn, booking, hero]);

  // Escape closes the sign-in panel
  React.useEffect(() => {
    if (!signIn) return;
    const onKey = (e: KeyboardEvent) => e.key === "Escape" && setSignIn(false);
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [signIn]);

  const cur = apartments[hero % Math.max(1, apartments.length)];
  const resultsRef = React.useRef<HTMLDivElement>(null);
  const goResults = () => {
    resultsRef.current?.scrollIntoView({ behavior: reduced ? "auto" : "smooth", block: "start" });
  };
  const setDates = (ci: string, co: string) => {
    setCheckIn(ci);
    setCheckOut(co);
  };
  const list = apartments.filter((a) => (!onlyFree || (avail.get(a.id)?.available ?? true)) && (guests <= 1 || a.maxGuests >= guests || !onlyFree));
  const selectedApt = apartments.find((a) => a.id === selected) ?? null;

  return (
    <div className="min-h-dvh bg-bg text-fg">
      {/* ── Hero ─────────────────────────────────────────────── */}
      <section className="relative h-[100svh] min-h-[600px] overflow-hidden bg-brand-950 text-white">
        <AnimatePresence mode="sync">
          {cur ? (
            <motion.img
              key={cur.id}
              src={src(cur.images[0].id, 1600)}
              srcSet={`${src(cur.images[0].id, 960)} 960w, ${src(cur.images[0].id, 1600)} 1600w`}
              sizes="100vw"
              alt=""
              initial={{ opacity: 0, scale: 1 }}
              animate={{ opacity: 1, scale: reduced ? 1 : 1.08 }}
              exit={{ opacity: 0 }}
              transition={{ opacity: { duration: 1.4, ease }, scale: { duration: HERO_MS / 1000 + 2, ease: "linear" } }}
              className="absolute inset-0 size-full object-cover"
            />
          ) : null}
        </AnimatePresence>
        <div className="absolute inset-0 bg-gradient-to-t from-brand-950 via-brand-950/35 to-brand-950/40" />
        <div className="absolute inset-0 bg-gradient-to-r from-brand-950/70 via-transparent to-transparent" />

        {/* Top bar */}
        <header className="absolute inset-x-0 top-0 z-20 flex items-center gap-3 px-5 pt-[calc(1rem+env(safe-area-inset-top))] sm:px-8 lg:px-12">
          <span className="flex size-10 items-center justify-center rounded-xl bg-white/12 ring-1 ring-white/25 backdrop-blur transition-transform duration-300 hover:rotate-[-6deg]">
            <Building2 className="size-5" />
          </span>
          <span className="font-display text-xl font-medium tracking-tight">{business.name}</span>
          <nav className="ml-8 hidden items-center gap-6 text-sm text-white/75 md:flex">
            <a href="#apartments" className="link-underline transition hover:text-white">Apartments</a>
            <a href="#availability" className="link-underline transition hover:text-white">Availability</a>
            <a href="#contact" className="link-underline transition hover:text-white">Contact</a>
          </nav>
          <button type="button" onClick={() => setSignIn(true)} className="group ml-auto flex h-10 items-center gap-2 rounded-full border border-white/25 bg-white/10 px-4 text-sm font-medium backdrop-blur transition-all duration-300 hover:border-white/50 hover:bg-white/20 hover:shadow-[0_0_0_4px_rgb(255_255_255/0.1)] active:scale-95">
            <LogIn className="size-4 transition-transform group-hover:translate-x-0.5" />
            <span className="hidden sm:inline">Staff sign in</span>
            <span className="sm:hidden">Sign in</span>
          </button>
        </header>

        {/* Hero copy */}
        <div className="absolute inset-x-0 bottom-0 z-10 px-5 pb-32 sm:px-8 sm:pb-36 lg:px-12 lg:pb-40">
          <AnimatePresence mode="wait">
            {cur ? (
              <motion.div key={cur.id} initial={{ opacity: 0, y: 18 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0, y: -10 }} transition={{ duration: 0.6, ease }} className="max-w-2xl">
                <p className="flex items-center gap-2 text-2xs font-semibold uppercase tracking-[0.24em] text-white/70">
                  <MapPin className="size-3" /> {cur.city}
                  {cur.building ? ` · ${cur.building}` : ""}
                </p>
                <h1 className="mt-2 font-display text-4xl font-medium leading-[1.05] tracking-tight sm:text-6xl">{cur.name}</h1>
                <p className="mt-3 flex flex-wrap items-center gap-x-4 gap-y-1 text-sm text-white/80">
                  <span className="flex items-center gap-1.5"><BedDouble className="size-4" /> {cur.bedrooms ? `${cur.bedrooms} bedroom${cur.bedrooms > 1 ? "s" : ""}` : "Studio"}</span>
                  <span className="flex items-center gap-1.5"><Bath className="size-4" /> {cur.bathrooms} bath</span>
                  <span className="flex items-center gap-1.5"><Users className="size-4" /> up to {cur.maxGuests} guests</span>
                  <span className="font-semibold text-white">
                    from {fmtMoney(cur.basePrice, business.currency, { whole: true })} <span className="font-normal text-white/70">/ night</span>
                  </span>
                </p>
                <div className="mt-3 flex flex-wrap items-center gap-2">
                  <GoogleRatingChip data={google} />
                  {pulse && pulse.bookings30 >= 3 ? <span className="inline-flex items-center gap-1.5 rounded-full border border-white/25 bg-white/10 px-2.5 py-1 text-xs font-semibold backdrop-blur"><Flame className="size-3.5 text-gold-400" /> {pulse.bookings30} bookings in the last 30 days</span> : null}
                  <span className="inline-flex items-center gap-1.5 rounded-full border border-white/25 bg-white/10 px-2.5 py-1 text-xs font-semibold backdrop-blur"><Lock className="size-3.5" /> No payment online</span>
                </div>
                <div className="mt-5 flex flex-wrap gap-2">
                  <Button size="lg" className="rounded-full shine" onClick={() => startBooking(cur.id)}>
                    <Zap /> Book now <ArrowRight />
                  </Button>
                  <Button size="lg" variant="secondary" className="rounded-full border-white/25 bg-white/10 text-white backdrop-blur hover:bg-white/20" onClick={() => setSelected(cur.id)}>
                    View apartment
                  </Button>
                </div>
              </motion.div>
            ) : null}
          </AnimatePresence>
        </div>

        {/* Thumbnail rail */}
        {apartments.length > 1 ? (
          <div className="absolute inset-x-0 bottom-[calc(4.5rem+env(safe-area-inset-bottom))] z-10 hidden md:block">
            <div className="flex gap-2 overflow-x-auto px-8 scrollbar-none lg:px-12">
              {apartments.map((a, i) => (
                <button key={a.id} type="button" onClick={() => setHero(i)} className={cn("group relative h-14 w-20 shrink-0 overflow-hidden rounded-lg ring-1 ring-white/20 transition-all duration-500", i === hero ? "w-28 ring-2 ring-white" : "opacity-60 hover:opacity-100")} aria-label={a.name}>
                  <img src={src(a.images[0].id, 320)} alt="" className="size-full object-cover" loading="lazy" />
                  {i === hero && !reduced ? <motion.span key={`p-${hero}`} initial={{ width: 0 }} animate={{ width: "100%" }} transition={{ duration: HERO_MS / 1000, ease: "linear" }} className="absolute bottom-0 left-0 h-0.5 bg-white" /> : null}
                </button>
              ))}
            </div>
          </div>
        ) : null}
        <a href="#availability" className="absolute bottom-[calc(1rem+env(safe-area-inset-bottom))] left-1/2 z-10 -translate-x-1/2 text-white/60 animate-float" aria-label="Scroll down">
          <ChevronDown className="size-6" />
        </a>
      </section>

      {/* ── Date bar ──────────────────────────────────────────── */}
      <section id="availability" className="relative z-20 -mt-16 scroll-mt-4 px-4 sm:px-8 lg:px-12">
        <motion.div initial={{ opacity: 0, y: 24 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} transition={{ duration: 0.6, ease }} className="glass mx-auto max-w-5xl rounded-2xl p-3 shadow-xl sm:p-4">
          <div className="grid gap-3 sm:grid-cols-[1fr_1fr_auto_auto] sm:items-end">
            <label className="block">
              <span className="eyebrow">Check-in</span>
              <Input type="date" min={today} value={checkIn} onChange={(e) => { setCheckIn(e.target.value); if (e.target.value >= checkOut) setCheckOut(dayKey(addDays(parseDay(e.target.value), 1))); }} className="mt-1 h-11 rounded-xl" />
            </label>
            <label className="block">
              <span className="eyebrow">Check-out</span>
              <Input type="date" min={checkIn} value={checkOut} onChange={(e) => setCheckOut(e.target.value)} className="mt-1 h-11 rounded-xl" />
            </label>
            <div>
              <span className="eyebrow">Guests</span>
              <div className="mt-1 flex h-11 items-center gap-1 rounded-xl border border-border bg-surface px-1.5">
                <button type="button" onClick={() => setGuests((g) => Math.max(1, g - 1))} className="flex size-8 items-center justify-center rounded-lg text-fg-muted transition hover:bg-surface-2 active:scale-90" aria-label="Fewer guests"><Minus className="size-4" /></button>
                <span key={guests} className="w-6 text-center text-sm font-semibold tabular animate-badge-pop">{guests}</span>
                <button type="button" onClick={() => setGuests((g) => Math.min(12, g + 1))} className="flex size-8 items-center justify-center rounded-lg text-fg-muted transition hover:bg-surface-2 active:scale-90" aria-label="More guests"><Plus className="size-4" /></button>
              </div>
            </div>
            <Button size="lg" className="h-11 rounded-xl" onClick={goResults}>
              <Search /> Show free apartments
            </Button>
          </div>
          <div className="mt-3 flex flex-wrap items-center gap-1.5">
            {[["tonight", "Tonight"], ["weekend", "This weekend"], ["3n", "3 nights"]].map(([k, l]) => (
              <button key={k} type="button" onClick={() => quickDates(k as "tonight" | "weekend" | "3n")} className="rounded-full border border-border px-3 py-1 text-xs font-medium text-fg-muted transition-all hover:border-primary/50 hover:text-fg active:scale-95">{l}</button>
            ))}
          </div>
          <p className="mt-3 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-fg-muted">
            <span className="live-dot" aria-label="Live" />
            {nights > 0 ? (
              availData ? (
                <>
                  <b className="text-fg"><AnimatedText text={`${freeCount} of ${apartments.length}`} /></b> apartments are free for {nights} night{nights > 1 ? "s" : ""} · {fmtDate(parseDay(checkIn), { style: "weekday" })} → {fmtDate(parseDay(checkOut), { style: "weekday" })}
                </>
              ) : (
                "Checking availability…"
              )
            ) : (
              "Choose your dates to see what is free."
            )}
          </p>
        </motion.div>
      </section>

      {/* ── Why book direct ───────────────────────────────────── */}
      <section className="px-4 pt-10 sm:px-8 lg:px-12">
        <ul className="mx-auto grid max-w-5xl gap-3 sm:grid-cols-3">
          {[
            { icon: Lock, t: "Nothing to pay online", d: "Book in 30 seconds, pay at check-in." },
            { icon: BadgeCheck, t: `Confirmed in ~${business.replyMinutes} min`, d: "A real person confirms on WhatsApp or by phone." },
            { icon: Sparkles, t: "Direct price, no fees", d: "You talk to the owner's team, not a platform." },
          ].map((x, i) => (
            <motion.li key={x.t} initial={reduced ? false : { opacity: 0, y: 14 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} transition={{ duration: 0.5, ease, delay: i * 0.08 }} className="flex items-center gap-3 rounded-2xl border border-border bg-surface p-3.5 shadow-xs hairline-top">
              <span className="flex size-10 shrink-0 items-center justify-center rounded-xl bg-primary/10 text-primary"><x.icon className="size-5" /></span>
              <span><span className="block text-sm font-semibold">{x.t}</span><span className="block text-xs text-fg-muted">{x.d}</span></span>
            </motion.li>
          ))}
        </ul>
      </section>

      {/* ── Apartments ────────────────────────────────────────── */}
      <section id="apartments" ref={resultsRef} className="scroll-mt-6 px-4 py-12 sm:px-8 lg:px-12">
        <div className="mx-auto max-w-6xl">
          <div className="mb-6 flex flex-wrap items-end justify-between gap-3">
            <div>
              <p className="eyebrow">The collection</p>
              <h2 className="font-display text-3xl font-medium tracking-tight sm:text-4xl">{apartments.length} apartment{apartments.length === 1 ? "" : "s"}, ready when you are</h2>
            </div>
            {nights > 0 ? (
              <button type="button" onClick={() => setOnlyFree((v) => !v)} className={cn("flex items-center gap-2 rounded-full border px-3.5 py-1.5 text-xs font-medium transition-all active:scale-95", onlyFree ? "border-primary bg-primary/10 text-primary" : "border-border text-fg-muted hover:border-border-strong")}>
                <span className={cn("size-2 rounded-full", onlyFree ? "bg-primary" : "bg-fg-subtle")} /> Only free for my dates
              </button>
            ) : null}
          </div>
          <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
            {list.map((a, i) => {
              const av = avail.get(a.id);
              const tooSmall = a.maxGuests < guests;
              return (
                <motion.article key={a.id} initial={reduced ? false : { opacity: 0, y: 22 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true, margin: "-40px" }} transition={{ duration: 0.55, ease, delay: (i % 3) * 0.08 }} className="group card-lift overflow-hidden rounded-2xl border border-border bg-surface shadow-xs hairline-top">
                  <button type="button" onClick={() => setSelected(a.id)} className="relative block aspect-[4/3] w-full overflow-hidden text-left">
                    <img src={src(a.images[0].id, 960)} alt={a.name} className="size-full object-cover transition-transform duration-700 [transition-timing-function:var(--ease-out-expo)] group-hover:scale-105" loading="lazy" />
                    <div className="absolute inset-0 bg-gradient-to-t from-stone-950/70 via-transparent to-transparent" />
                    <span className="absolute left-3 top-3 flex items-center gap-1.5">
                      <span className="rounded-md bg-stone-950/55 px-2 py-0.5 font-mono text-2xs font-semibold text-white backdrop-blur">{a.code}</span>
                      {(pulse?.byApartment[a.id] ?? 0) >= 2 ? <span className="inline-flex items-center gap-1 rounded-md bg-gold-500/90 px-2 py-0.5 text-2xs font-semibold text-stone-950 backdrop-blur"><Flame className="size-3" /> Booked {pulse!.byApartment[a.id]}× this month</span> : null}
                    </span>
                    {nights > 0 && av ? (
                      <span key={`${a.id}-${av.available}`} className={cn("absolute right-3 top-3 flex items-center gap-1.5 rounded-full px-2.5 py-1 text-2xs font-semibold backdrop-blur animate-badge-pop", av.available && !tooSmall ? "bg-positive-500/90 text-white" : "bg-stone-950/60 text-white/85")}>
                        <span className={cn("size-1.5 rounded-full", av.available && !tooSmall ? "bg-white" : "bg-negative-400")} />
                        {tooSmall ? `Up to ${a.maxGuests} guests` : av.available ? "Free for your dates" : "Booked"}
                      </span>
                    ) : null}
                    <span className="absolute inset-x-3 bottom-3 text-white">
                      <span className="block text-2xs font-semibold uppercase tracking-[0.18em] text-white/70">{a.city}{a.building ? ` · ${a.building}` : ""}</span>
                      <span className="block font-display text-xl font-medium leading-tight">{a.name}</span>
                    </span>
                  </button>
                  <div className="p-4">
                    <div className="flex items-center gap-3 text-xs text-fg-muted">
                      <span className="flex items-center gap-1"><BedDouble className="size-3.5" /> {a.bedrooms || "Studio"}</span>
                      <span className="flex items-center gap-1"><Bath className="size-3.5" /> {a.bathrooms}</span>
                      <span className="flex items-center gap-1"><Users className="size-3.5" /> {a.maxGuests}</span>
                      <span className="ml-auto text-sm font-semibold text-fg">{fmtMoney(a.basePrice, business.currency, { whole: true })}<span className="text-xs font-normal text-fg-muted">/night</span></span>
                    </div>
                    <div className="mt-3 flex items-center justify-between gap-2">
                      {nights > 0 && av?.available && !tooSmall ? (
                        <p className="text-xs text-fg-muted">
                          {av.nights} night{av.nights > 1 ? "s" : ""} · <b className="text-fg tabular"><AnimatedText text={fmtMoney(av.subtotal, business.currency, { whole: true })} /></b>
                        </p>
                      ) : (
                        <p className="text-xs text-fg-muted">{a.amenities.slice(0, 3).join(" · ")}</p>
                      )}
                      <span className="flex items-center gap-1.5">
                        <Button size="sm" variant="secondary" onClick={() => setSelected(a.id)}>
                          Details
                        </Button>
                        {!(nights > 0 && av && !av.available) ? (
                          <Button size="sm" className="shine" onClick={() => startBooking(a.id)}>
                            <Zap /> Book now
                          </Button>
                        ) : null}
                      </span>
                    </div>
                  </div>
                </motion.article>
              );
            })}
          </div>
          {list.length === 0 ? (
            <motion.div initial={{ opacity: 0, y: 12 }} animate={{ opacity: 1, y: 0 }} className="mx-auto max-w-lg rounded-3xl border border-border bg-surface p-5 shadow-sm hairline-top sm:p-6">
              <p className="eyebrow">Fully booked on these nights</p>
              <h3 className="font-display text-2xl font-medium leading-tight">Don&apos;t leave empty-handed.</h3>
              <p className="mt-1 text-sm text-fg-muted">Cancellations happen and we have partner apartments nearby. Leave your number: we call you the moment something opens for your dates.</p>
              <div className="mt-4">
                <LeadForm business={business} ctx={{ checkIn, checkOut, guests }} kind="WAITLIST" />
              </div>
            </motion.div>
          ) : null}
        </div>
      </section>

      <ReviewsSection business={business} data={google} onAvailable={setReviewsOk} />

      {/* ── Contact / footer ──────────────────────────────────── */}
      <footer id="contact" className="border-t border-border bg-surface/60 px-4 py-10 pb-28 sm:px-8 md:pb-10 lg:px-12">
        <div className="mx-auto grid max-w-6xl gap-6 md:grid-cols-[1.2fr_1fr] md:items-center">
          <div>
            <p className="eyebrow">Book directly</p>
            <h3 className="font-display text-2xl font-medium tracking-tight">Talk to {business.name}</h3>
            <p className="mt-1 max-w-md text-sm text-fg-muted">Pick an apartment and your dates above, then send us a message — we confirm within the hour during business hours.</p>
            <div className="mt-4 flex flex-wrap gap-2">
              {business.phone ? (
                <Button asChild>
                  <a href={`https://wa.me/${business.whatsapp.replace(/[^\d]/g, "")}?text=${encodeURIComponent(`Hello ${business.name}, I would like to book an apartment${nights > 0 ? ` from ${checkIn} to ${checkOut}` : ""}.`)}`} target="_blank" rel="noreferrer" onClick={() => track("Contact", { method: "whatsapp" })}>
                    <Phone /> {fmtPhone(business.phone)}
                  </a>
                </Button>
              ) : null}
              {business.email ? (
                <Button variant="secondary" asChild>
                  <a href={`mailto:${business.email}`}>
                    <Mail /> {business.email}
                  </a>
                </Button>
              ) : null}
            </div>
          </div>
          <div className="text-sm text-fg-muted md:text-right">
            {business.address ? <p className="flex items-center gap-1.5 md:justify-end"><MapPin className="size-4" /> {business.address}</p> : null}
            <p className="mt-1">Check-in from {business.checkInTime} · check-out by {business.checkOutTime}</p>
            <button type="button" onClick={() => setSignIn(true)} className="mt-4 inline-flex items-center gap-1.5 text-xs font-medium text-fg-subtle transition hover:text-fg">
              <LogIn className="size-3.5" /> Staff sign in
            </button>
          </div>
        </div>
      </footer>

      <ApartmentSheet apartment={selectedApt} business={business} avail={selectedApt ? avail.get(selectedApt.id) : undefined} checkIn={checkIn} checkOut={checkOut} guests={guests} onDates={setDates} onClose={() => setSelected(null)} today={today} onBook={startBooking} />
      <BookingFlow open={!!booking} apartment={bookingApt} business={business} checkIn={checkIn} checkOut={checkOut} guests={guests} today={today} onClose={() => setBooking(null)} onDates={setDates} />
      <PulseToasts pulse={pulse} suspended={!!selected || !!booking || signIn} onPick={(id) => setSelected(id)} />
      <ContactDock business={business} ctx={{ apartment: selectedApt ? { id: selectedApt.id, code: selectedApt.code, name: selectedApt.name } : null, checkIn: nights > 0 ? checkIn : undefined, checkOut: nights > 0 ? checkOut : undefined, guests }} onDates={() => document.getElementById("availability")?.scrollIntoView({ behavior: reduced ? "auto" : "smooth" })} reviewsAvailable={reviewsOk} />
      <ExitNudge business={business} ctx={{ checkIn: nights > 0 ? checkIn : undefined, checkOut: nights > 0 ? checkOut : undefined, guests }} suspended={!!selected || !!booking || signIn} />
      {business.fbPixelId ? <FacebookPixel id={business.fbPixelId} /> : null}

      {/* ── Staff sign-in panel ───────────────────────────────── */}
      <AnimatePresence>
        {signIn ? (
          <>
            <motion.div key="backdrop" initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} transition={{ duration: 0.3 }} className="fixed inset-0 z-40 bg-stone-950/50 backdrop-blur-[3px]" onClick={() => setSignIn(false)} />
            <motion.aside
              key="panel"
              role="dialog"
              aria-modal="true"
              aria-label="Staff sign in"
              initial={phone ? { y: "100%" } : { x: "100%" }}
              animate={phone ? { y: 0 } : { x: 0 }}
              exit={phone ? { y: "100%" } : { x: "100%" }}
              transition={{ type: "spring", stiffness: 380, damping: 38, mass: 0.9 }}
              className={cn("glass fixed z-50 flex flex-col shadow-2xl", phone ? "inset-x-0 bottom-0 max-h-[92dvh] rounded-t-3xl border-x-0 border-b-0" : "inset-y-0 right-0 w-full max-w-[440px] rounded-l-3xl border-y-0 border-r-0")}
            >
              {phone ? <div className="mx-auto mt-2 h-1 w-10 rounded-full bg-border-strong" /> : null}
              <div className="flex items-center justify-between px-6 pt-5">
                <div className="flex items-center gap-2.5">
                  <span className="brand-tile flex size-9 items-center justify-center rounded-lg text-white">
                    <Building2 className="size-4" />
                  </span>
                  <span className="font-display text-lg font-medium">{business.name}</span>
                </div>
                <button type="button" onClick={() => setSignIn(false)} className="flex size-9 items-center justify-center rounded-full text-fg-muted transition hover:rotate-90 hover:bg-surface-2 hover:text-fg" aria-label="Close">
                  <X className="size-4" />
                </button>
              </div>
              <div className="flex-1 overflow-y-auto px-6 pb-[calc(1.5rem+env(safe-area-inset-bottom))] pt-6 scrollbar-thin">
                <motion.div initial={{ opacity: 0, y: 12 }} animate={{ opacity: 1, y: 0 }} transition={{ delay: 0.15, duration: 0.45, ease }}>
                  <p className="eyebrow">Staff area</p>
                  <h2 className="font-display text-3xl font-medium tracking-tight">Sign in</h2>
                  <p className="mt-1 text-sm text-fg-muted">Private access for {business.name} staff.</p>
                  <LoginForm next={next} />
                  <p className="mt-8 text-center text-2xs text-fg-subtle">Accounts are created by the administrator. Login activity is recorded.</p>
                </motion.div>
              </div>
            </motion.aside>
          </>
        ) : null}
      </AnimatePresence>
      <span className="sr-only">
        <Link href="/forgot-password">Forgot password</Link>
      </span>
    </div>
  );
}
