/* Sea La Vie — shared chrome: nav, footer, hero, marquee, logo, modals */ const { useState: useS, useEffect: useE, useMemo: useM } = React; /* ────── Brand Logo (SVG) ────── */ function BrandLogo({ compact, tiny, onDark }) { const navy = onDark ? "#f6f1e7" : "#0e2a4e"; const sky = "#7ba3d1"; const skyDeep = onDark ? "#9fc0e0" : "#4f7eb2"; const width = tiny ? 130 : compact ? 200 : 280; return ( SEA LA VIE {/* wave under LA */} {/* LUXURY RESIDENCES DIANI subtitle */} LUXURY RESIDENCES DIANI ); } /* ────── Utility Bar ────── */ function UtilityBar({ onSearch, onLogin }) { const [currency, setCurrency] = useCurrency(); const [session, setSess] = useS(() => { try { return JSON.parse(localStorage.getItem("slv_session_v1") || "null"); } catch(e) { return null; } }); useE(() => { function onSess(e) { setSess(e.detail); } window.addEventListener("slv:session", onSess); return () => window.removeEventListener("slv:session", onSess); }, []); const firstName = session && session.name ? session.name.split(" ")[0] : null; return (
Diani, Kenya
{Object.keys(CURRENCIES).map(c => ( ))}
{CONTACT.phone} Travel Advisors {session ? {firstName} · My Stay : }
); } /* ────── Main Nav (with mobile drawer) ────── */ function MainNav({ current, onSearch, onLogin }) { const [open, setOpen] = useS(false); const links = [ { l: "Residences", h: "residences.html" }, { l: "Availability", h: "availability.html" }, { l: "Experiences", h: "experiences.html" } ]; const right = [ { l: "Cuisine", h: "cuisine.html" }, { l: "Wellness", h: "wellness.html" }, { l: "Journal", h: "journal.html" } ]; useE(() => { document.body.style.overflow = open ? "hidden" : ""; return () => { document.body.style.overflow = ""; }; }, [open]); return ( <>
setOpen(false)}>
{CONTACT.phone} {CONTACT.email} { e.preventDefault(); setOpen(false); onSearch && onSearch(); }}>⌕ Search { e.preventDefault(); setOpen(false); onLogin && onLogin(); }}>Sign in
); } function MobileCurrency() { const [currency, setCurrency] = useS(getStoredCurrency()); function pick(c) { setCurrency(c); setStoredCurrency(c); } return (
Currency
{Object.keys(CURRENCIES).map(c => ( ))}
); } /* ────── Hero ────── */ function Hero() { return (
Opening November 2026 · Diani Beach, Kenya

The Indian Ocean,
privately yours.

Four exclusive residences set within indigenous coastal forest, one hundred metres from the warm shallows of Diani Beach. A refined coastal escape designed around privacy, space, and a slower rhythm of living.

Reserve a residence Our story
Scroll
); } /* ────── Location Map (shared) ────── */ function LocationMapSection({ compact, dark }) { return (
Location

On the south coast,
seven minutes from the runway.

Sea La Vie sits on Galu Beach, the southern stretch of Diani — a quiet, broad arc of white sand at the lower end of Kenya's south coast. Ukunda Airstrip (UKA) is a seven-minute drive away; Moi International, Mombasa (MBA), is forty-five.

Ukunda (UKA)
7 min by car
Mombasa (MBA)
45 min by car
Diani village
5 min by car
The ocean
100 metres
Open in Google Maps Get directions
); } /* ────── Page Head (for interior pages) ────── */ function PageHead({ eyebrow, title, titleEm, blurb, img, crumb }) { return (
{eyebrow}

{title} {titleEm && {titleEm}}

{blurb &&

{blurb}

} {crumb && (
Home·{crumb}
)}
); } /* ────── Marquee ────── */ function Marquee() { const items = [ "Opening November 2026", "Hidden within indigenous coastal forest", "One hundred metres from the Indian Ocean", "Four exclusive residences", "One staff member for every two guests", "Diani Beach · Kwale County · Kenya" ]; const repeated = [...items, ...items, ...items]; return (
{repeated.map((it, i) => ( {it} ))}
); } /* ────── Footer ────── */ function Footer() { return ( ); } function NewsletterForm() { const [email, setEmail] = useS(""); const [done, setDone] = useS(false); async function submit(e) { e.preventDefault(); if (!email.trim()) return; try { await apiEnquiry({ name: "Newsletter", email: email.trim(), subject: "The Letter — subscribe", message: "Please add me to The Letter." }); } catch(e) {} setDone(true); } return (
{done ? (
Thank you — see you on the coast.
) : ( <> setEmail(e.target.value)} /> )}
); } /* ────── Login Modal ────── */ function LoginModal({ onClose, onSwitchToSignup, isSignup, onSwitchToLogin }) { return (
e.stopPropagation()}>
The Guest Register

{isSignup ? "Begin your" : "Welcome"} {isSignup ? "register" : "back"}

{isSignup ? "Open a Guest Register to receive priority access to the opening season, private rates, and a dedicated travel curator." : "Sign in to view held reservations, your travel curator's recommendations, and the inner pages of the journal."}

"Karibu, rafiki — welcome home."
— Sea La Vie
{isSignup ? "Create an account" : "Sign in"}

{isSignup ? "Open the" : "Enter your"} register

{isSignup ? "Two minutes. No commitment." : "We'll remember where you left off."}

or
{isSignup ? <>Already registered? {e.preventDefault(); onSwitchToLogin();}}>Sign in : <>Not yet a guest? {e.preventDefault(); onSwitchToSignup();}}>Open a register }
); } function LoginForm({ isSignup, onClose }) { const [form, setForm] = useS({ name: "", email: "", password: "" }); const [busy, setBusy] = useS(false); const [err, setErr] = useS(""); function up(k, v) { setForm(prev => ({ ...prev, [k]: v })); } async function submit(e) { e.preventDefault(); setErr(""); if (!form.email || !form.password || (isSignup && !form.name)) { setErr("Please fill every field."); return; } setBusy(true); const r = isSignup ? await acctRegister({ name: form.name, email: form.email, password: form.password }) : await acctLogin({ email: form.email, password: form.password }); setBusy(false); if (!r.ok) { setErr(r.error || "Something went wrong."); return; } // Success → go to the portal window.location.href = "account.html"; } return (
{isSignup && (
up("name", e.target.value)} />
)}
up("email", e.target.value)} />
up("password", e.target.value)} />
{!isSignup && (
Forgotten?
)} {err &&
{err}
}

Try the demo · demo@sealaviediani.com / demo

); } /* ────── Search Overlay ────── */ function SearchOverlay({ onClose }) { const [q, setQ] = useS(""); const suggestions = { "Residences": [["Kasi Villa","residences.html#kasi"],["Bahari Villa","residences.html#bahari"],["Pwani Villa","residences.html#pwani"],["Samaki Villa","residences.html#samaki"]], "Experiences": [["Kite Atelier","experiences.html"],["Jet Ski","experiences.html"],["Tandem Skydive","experiences.html"],["Parasail","experiences.html"],["Sundowner Dhow","experiences.html"],["Wasini Channel","experiences.html"],["Shimba Hills Safari","experiences.html"],["Colobus Conservation","wellness.html"]], "Cuisine": [["Ali Barbour's Cave","cuisine.html"],["Nomad Beach Bar","cuisine.html"],["The Salty Squid","cuisine.html"],["Leonardo's","cuisine.html"],["Sails Beach Bar","cuisine.html"],["Ozi's Bistro","cuisine.html"],["Shan-e-Punjab","cuisine.html"],["Kokkos Beach Bar","cuisine.html"],["Bonfire Table","cuisine.html"]], "Journal": [["A guide to Kaskazi season","journal.html"],["The dhows of Shimoni","journal.html"],["Twelve plates to know","journal.html"]], "Information": [["Opening November 2026","story.html"],["Getting here","contact.html#getting-here"],["Whole-estate buyouts","contact.html"],["The Guest Register","contact.html"]] }; const filtered = Object.fromEntries( Object.entries(suggestions).map(([cat, items]) => [cat, items.filter(([t]) => t.toLowerCase().includes(q.toLowerCase()))]) ); return (
Search Sea La Vie
setQ(e.target.value)} placeholder="Try 'kite atelier' or 'November availability'" />
{Object.entries(filtered).map(([cat, items]) => items.length > 0 && (
{cat}
    {items.map(([t, h]) => (
  • { window.location.href = h; }}> {t}View
  • ))}
))}
); } /* ────── Provenance (story snippet for home page) ────── */ function ProvenanceSection() { return (
Our Story

Set moments from the Indian Ocean.

Sea La Vie was created as a quiet coastal retreat designed around privacy, space, and a slower rhythm of living. Hidden within Diani's lush coastline, the residences bring together contemporary coastal design with the textures, materials, and craftsmanship of the Swahili coast — lime-washed walls, hand-carved details, natural timber, soft linen.

Every element has been intentionally considered to create an experience that feels calm, discreet, and deeply connected to place. More than a place to stay, Sea La Vie is designed to feel private, effortless, and removed from the pace of everyday life.

Opening
November 2026
From the airport
7 minutes
From the ocean
100 metres
Residences
Four
Read our full story
); } /* ────── Re-usable Grids ────── */ function ResidencesGrid() { const [currency] = useCurrency(); return (
{VILLAS.map(v => (
{v.badge}

{v.name[0]} {v.name[1]}

from {formatPrice(v.priceUSD, currency)}{v.period}

{v.desc}

{v.bedrooms}Bedrooms {v.baths}Baths {v.sqft}Sq Ft {v.sleeps}Sleeps
))}
); } function ExperiencesGrid({ kind }) { const list = EXPERIENCES[kind] || []; return (
{list.map((e, i) => (
{e.cat}
{e.provider &&
{e.provider}
}

{e.title[0]} {e.title[1]}

{e.meta.map((m, j) => {m})}

{e.desc}

From{e.from}
Book Now
))}
); } function CuisineGrid() { return (
{CUISINE.map((c, i) => (
{c.cat}
{c.provider &&
{c.provider}
}

{c.title[0]} {c.title[1]}

{c.meta.map((m, j) => {m})}

{c.desc}

{c.from.startsWith("$") ? <>From{c.from} : {c.from}}
Reserve
))}
); } /* ────── Availability Strip (live data, used on home + availability pages) ────── */ function AvailabilityStrip() { const [year, setYear] = useS(2026); const [month, setMonth] = useS(10); const [currency] = useCurrency(); const avail = useAvailability(); const dim = daysInMonth(year, month); function shift(delta) { let m = month + delta, y = year; while (m < 0) { m += 12; y -= 1; } while (m > 11) { m -= 12; y += 1; } setMonth(m); setYear(y); } function cellClass(villaId, day) { const key = dateKey(year, month, day); if (avail.isBooked(villaId, key)) return "ac booked"; return "ac avail"; } return (
Live Availability

See the season at a glance.

A live view of every residence across the calendar. Reserved cells are unavailable; tap any open cell to begin building your stay.

Residence availability

{MONTHS[month]} {year}
Residence
{Array.from({length: dim}, (_, i) => { const d = i + 1; const date = new Date(year, month, d); const dow = date.getDay(); return
{d}
; })}
{VILLAS.map(v => (
{v.name.join(" ")}
from {formatPrice(v.priceUSD, currency)}
{Array.from({length: dim}, (_, i) =>
)}
))}
Available Reserved Whole-estate buyouts available for parties of sixteen or more.
); } /* ────── Page Layout (wraps each page with header/footer + modal state) ────── */ function PageLayout({ current, children, withMarquee }) { const [showSearch, setShowSearch] = useS(false); return ( <>
setShowSearch(true)} onLogin={() => { window.location.href = "account.html"; }} /> setShowSearch(true)} onLogin={() => { window.location.href = "account.html"; }} /> {children} {withMarquee && }