/* Sub-pages: Services, Memberships, Gallery, Team, Reviews, Book */ const { useState: _S, useEffect: _E, useMemo: _M, useRef: _R } = React; // --- Generic page header --- function PageHead({ eyebrow, title, italic, sub }) { return (
{eyebrow}

{title} {italic && {italic}}

{sub &&

{sub}

}
); } // ===================== SERVICES ===================== function ServicesPage({ openBookingFor }) { const [active, setActive] = _S(D.categories[0].id); // observe category in view _E(() => { const sections = D.categories.map(c => document.getElementById(`svc-${c.id}`)).filter(Boolean); const onScroll = () => { const y = window.scrollY + 160; let curr = sections[0]?.id; for (const s of sections) { if (s.offsetTop <= y) curr = s.id; } if (curr) setActive(curr.replace("svc-", "")); }; window.addEventListener("scroll", onScroll, { passive: true }); return () => window.removeEventListener("scroll", onScroll); }, []); const jumpTo = (id) => { const el = document.getElementById(`svc-${id}`); if (el) window.scrollTo({ top: el.offsetTop - 130, behavior: "smooth" }); }; return (
{D.categories.map(c => ( ))}
{D.categories.map(c => (
{c.icon}

{c.title}

{c.copy}

{c.items.map((it, i) => (
{it.name}
{it.duration}{it.flag && {it.flag}}
{it.price !== null ? ( <> {it.was && AED {it.was}} AED {it.price}
{it.note}
) : ( {it.note} )}
))}
))}
Don't see a price? It sits inside Fresha's booking flow. Confirm at checkout, or WhatsApp us for a quick quote.
); } // ===================== MEMBERSHIPS / OFFERS ===================== function MembershipsPage({ openBookingFor }) { // Proposed memberships — explicitly flagged as proposal, not invented standing menu const proposals = [ { name: "The Blowdry Card", tier: "Proposal — client to confirm", colour: "var(--cream)", price: "—", priceUnit: "8 blowdries", perks: ["Save vs walk-in", "Any stylist, any time", "Transferable to a friend"], }, { name: "The Glow Membership", tier: "Proposal — client to confirm", colour: "var(--plum)", textColour: "var(--ivory)", price: "—", priceUnit: "monthly", perks: ["1 blowdry + 1 mani per month", "10% off all add-ons", "Priority Happy-Hour booking"], featured: true, }, { name: "The Bridal Block", tier: "Proposal — client to confirm", colour: "var(--cream)", price: "—", priceUnit: "package", perks: ["Hair + makeup + lashes + Moroccan bath", "Dedicated team on the day", "Trial session included"], }, ]; return (
Live & verified
{D.offers.map((o, i) => (
{o.kicker}
{o.saving && {o.saving}}

{o.name}

{o.duration}
AED {o.price} {o.was && was {o.was}}

{o.copy}

))}
Proposed memberships
{proposals.map((p, i) => (
{p.featured && Most popular}
{p.tier}

{p.name}

{p.price} {p.priceUnit}
    {p.perks.map((perk, k) => (
  • {perk}
  • ))}
))}

Memberships shown above are draft proposals for the new website — pricing and inclusions to be confirmed by Blo Out.

); } // ===================== GALLERY ===================== function GalleryPage() { const [filter, setFilter] = _S("all"); const [lb, setLb] = _S(null); const all = _M(() => { return [ ...D.gallery.work.map(f => ({ f, kind: "work" })), ...D.gallery.venue.map(f => ({ f, kind: "venue" })), ]; }, []); const filtered = filter === "all" ? all : all.filter(x => x.kind === filter); const images = filtered.map(x => x.f); return (
{["all","work","venue"].map(f => ( ))}
{filtered.map((g, i) => (
setLb(i)}>
))}

Phase 2: live Instagram feed (@blooutbeauty).

setLb(null)} setIndex={setLb}/>
); } // ===================== TEAM ===================== function TeamPage({ openBookingFor }) { const [filter, setFilter] = _S("all"); const groups = [ { id: "all", label: "Everyone" }, { id: "lashes", label: "Lashes" }, { id: "hair", label: "Hair" }, { id: "nails", label: "Nails" }, { id: "spa", label: "Spa & Brows" }, ]; const matchesGroup = (t) => { if (filter === "all") return true; if (filter === "lashes") return /Lash/i.test(t.role); if (filter === "hair") return /Hair|Color/i.test(t.role); if (filter === "nails") return /Nail/i.test(t.role); if (filter === "spa") return /Brow|Facial|Moroccan/i.test(t.role); }; return (
{groups.map(g => ( ))}
{D.team.filter(matchesGroup).map(t => (
openBookingFor(`${t.name} — ${t.role}`)}>
{t.name}/
{t.rating}
{t.name}
{t.role}
{!t.confirmed && photo: stand-in}
))}
A note on portraits

Only three name-to-photo mappings are confirmed (Gemma, Fouzia, Perveen). The other portraits are stand-ins from Blo Out's own staff gallery while we collect consented headshots mapped to each specialist.

); } // ===================== REVIEWS ===================== function ReviewsPage() { return (
{D.brand.rating}
★★★★★
From {D.brand.reviewCount.toLocaleString()} reviews on Fresha

Most-praised: Moroccan Bath, Lashes, Nails.

Fresha rating re-pulled {D.brand.reviewLatest}. The aggregate is a moving target — we'll refresh on launch day.
Moroccan Bath Lash Lift Nail Art Caviar Treatment Friendly staff
{D.reviews.map((r, i) => (
{"★★★★★".slice(0, r.stars)}{"☆☆☆☆☆".slice(0, 5 - r.stars)}
{r.text}
{r.name} · {r.date} {r.source}
))}
What to expect

A tiny minority of low reviews flag colour expectations and Moroccan-bath glove add-ons. We pre-empt that by always consulting on colour first and listing what's included in every Moroccan-bath booking on the booking page. Honest expectations, every time.

); } // ===================== BOOK (visit) ===================== function BookPage({ openBooking }) { return (
Online

Book online.

MVP deep-links to our Fresha listing. Pick service, specialist, time — confirmed by SMS.

Fastest

WhatsApp.

Send the service and your preferred day. Most replies inside 15 minutes during opening hours.

Open WhatsApp →
Old-fashioned

Call us.

Speak to the front desk for bridal blocks, group bookings, or to hold a Moroccan-bath room mid-Happy-Hour.

{D.brand.phone}
); } // Small map block used on Book page (no h2 wrapper) function MapSectionLite() { return (
Find us

Villa 710, the Light House.

On Jumeirah Beach Road, Umm Suqeim 2 — opposite the beach, minutes from Madinat Jumeirah.
Blo Out Beauty LoungeVilla 710
Address
Villa 710, Jumeirah Beach Road
Umm Suqeim 2, Dubai
Hours
Daily 09:00 — 21:00
Phone
{D.brand.phone}
WhatsApp
{D.brand.whatsapp}candidate — confirm
Map
{D.brand.coords.lat}, {D.brand.coords.lng}
); } Object.assign(window, { ServicesPage, MembershipsPage, GalleryPage, TeamPage, ReviewsPage, BookPage });