import React, { useState, useMemo } from "react"; import { Compass, MapPin, CalendarDays, Users, Tent, Car, Plane, Send, Download, MessageCircle, SlidersHorizontal, CreditCard, Check, X, ChevronRight, Sparkles, Baby, Globe, Footprints, Waves } from "lucide-react"; /* ============================================================ WildTrail Tanzania — Build My Safari + Instant Quote (prototype) Sample rates verified against 2025/26 TANAPA & NCAA fee guidance. All rates are editable in the "Rates & Margin" panel — in production these are pulled from the supplier portal / admin database. ============================================================ */ const WHATSAPP = "255747108883"; const EMAIL = "info@reservationshub.org"; // destType: 'park' (game drives) | 'trek' | 'beach' | 'hub' const DESTINATIONS = [ { id: "tarangire", name: "Tarangire", region: "Northern", type: "park", order: 2, baseNights: 1, feeHigh: 50, feeLow: 45, childFee: 15, interior: false }, { id: "manyara", name: "Lake Manyara", region: "Northern", type: "park", order: 3, baseNights: 1, feeHigh: 50, feeLow: 45, childFee: 15, interior: false }, { id: "serengeti", name: "Serengeti", region: "Northern", type: "park", order: 4, baseNights: 2, feeHigh: 70, feeLow: 60, childFee: 20, interior: true }, { id: "ngorongoro", name: "Ngorongoro Crater", region: "Northern", type: "park", order: 5, baseNights: 1, feeHigh: 70.8,feeLow: 70.8, childFee: 23.6, interior: true, craterFee: 295 }, { id: "arushanp", name: "Arusha N.P.", region: "Northern", type: "park", order: 1, baseNights: 1, feeHigh: 50, feeLow: 45, childFee: 15, interior: false }, { id: "kilimanjaro",name: "Kilimanjaro Trek", region: "Northern", type: "trek", order: 0, baseNights: 6, trekPPPD: 240 }, { id: "nyerere", name: "Nyerere (Selous)", region: "Southern", type: "park", order: 6, baseNights: 2, feeHigh: 60, feeLow: 50, childFee: 20, interior: false }, { id: "ruaha", name: "Ruaha", region: "Southern", type: "park", order: 7, baseNights: 2, feeHigh: 30, feeLow: 30, childFee: 10, interior: false }, { id: "mikumi", name: "Mikumi", region: "Southern", type: "park", order: 8, baseNights: 1, feeHigh: 30, feeLow: 30, childFee: 10, interior: false }, { id: "zanzibar", name: "Zanzibar", region: "Coast", type: "beach", order: 9, baseNights: 3 }, ]; const STYLES = ["Budget", "Mid-Range", "Luxury", "Ultra-Luxury"]; const ACCOM = ["Camping", "Lodge", "Tented Camp", "Luxury Lodge"]; const TRANSPORT = ["Shared Safari", "Private Safari", "Fly-In Safari"]; const DEFAULT_RATES = { // per person per night (game lodges) by style lodge: { Budget: 90, "Mid-Range": 180, Luxury: 450, "Ultra-Luxury": 950 }, // per person per night (beach resorts) by style beach: { Budget: 70, "Mid-Range": 150, Luxury: 380, "Ultra-Luxury": 800 }, seasonMult: { Low: 0.85, High: 1.0, Peak: 1.25 }, vehiclePerDay: 230, // private Land Cruiser incl. driver-guide & fuel sharedPerPersonDay: 75, // seat-in-vehicle shared safari flightPerSector: 110, // domestic / bush flight per person per sector concessionPPPN: 59, // park-interior concession (luxury tiers) transfersFlat: 70, // airport transfers per group vatParkFees: 0.18, // 18% VAT on park fees margin: 20, // WildTrail margin % depositPct: 30, }; const seasonFor = (dateStr) => { const m = dateStr ? new Date(dateStr + "T00:00").getMonth() + 1 : new Date().getMonth() + 1; if ([7, 8, 9, 10, 12].includes(m)) return "Peak"; if ([6, 11, 1, 2].includes(m)) return "High"; return "Low"; }; const usd = (n) => "$" + Math.round(n).toLocaleString("en-US"); export default function App() { const [view, setView] = useState("build"); // build | quote const [showRates, setShowRates] = useState(false); const [showDeposit, setShowDeposit] = useState(false); const [rates, setRates] = useState(DEFAULT_RATES); const [form, setForm] = useState({ arrival: "", departure: "", adults: 2, children: 0, nationality: "Non-resident", style: "Mid-Range", accom: "Lodge", transport: "Private Safari", dests: ["tarangire", "serengeti", "ngorongoro"], }); const set = (k, v) => setForm((f) => ({ ...f, [k]: v })); const toggleDest = (id) => setForm((f) => ({ ...f, dests: f.dests.includes(id) ? f.dests.filter((d) => d !== id) : [...f.dests, id], })); const trip = useMemo(() => buildTrip(form, rates), [form, rates]); return (
{/* Header */}
WildTrail Tanzania
Where every trail tells a story
{view === "build" ? ( setView("quote")} /> ) : ( setView("build")} onDeposit={() => setShowDeposit(true)} /> )}
Prototype · {EMAIL} · WhatsApp +{WHATSAPP} Sample rates — configure in the admin panel
{showRates && setShowRates(false)} />} {showDeposit && setShowDeposit(false)} />}
); } /* ----------------------------- BUILD VIEW ----------------------------- */ function BuildView({ form, set, toggleDest, trip, onGenerate }) { const grouped = ["Northern", "Southern", "Coast"]; return (
} title="Travel information">
set("arrival", e.target.value)} style={S.input} /> set("departure", e.target.value)} style={S.input} />
set("adults", v)} icon={} /> set("children", v)} icon={} />
{["Non-resident", "Resident / Expat", "East African"].map((n) => ( ))}
} title="Safari style"> set("style", v)} />
set("accom", v)} small />
set("transport", v)} small icons={{ "Shared Safari": , "Private Safari": , "Fly-In Safari": }} />
} title="Destinations"> {grouped.map((g) => (
{g} circuit
{DESTINATIONS.filter((d) => d.region === g).map((d) => { const on = form.dests.includes(d.id); return ( ); })}
))}
{/* live preview */}
Estimated total
{usd(trip.total)}
{usd(trip.perPerson)} per person · {trip.season} season
{trip.totalDays} days {form.adults + form.children} {form.adults + form.children === 1 ? "traveller" : "travellers"} {form.style}
Instant — no email wait. {trip.warning && {trip.warning}}
); } /* ----------------------------- QUOTE VIEW ----------------------------- */ function QuoteView({ form, trip, rates, onBack, onDeposit }) { const pax = form.adults + form.children; const summary = `${trip.totalDays}-day ${form.style} Tanzania safari for ${pax} (${trip.dests.map((d) => d.name).join(", ")}). Estimated total ${usd(trip.total)} / ${usd(trip.perPerson)} pp.`; const wa = `https://wa.me/${WHATSAPP}?text=${encodeURIComponent("Hi WildTrail Tanzania! I built this safari on your site:\n\n" + summary + "\n\nCan we discuss?")}`; const mail = `mailto:${EMAIL}?subject=${encodeURIComponent("Safari booking request — " + trip.totalDays + " days")}&body=${encodeURIComponent("Hello WildTrail Tanzania,\n\nI'd like to request this safari:\n\n" + summary + "\n\nTravel dates: " + (form.arrival || "TBC") + " to " + (form.departure || "TBC") + "\nName:\nContact:\n")}`; return (
WildTrail Tanzania
Tailor-made safari proposal
{trip.totalDays}-day {form.style} safari
{form.arrival || "Dates TBC"} → {form.departure || ""}
{form.adults} adult{form.adults > 1 ? "s" : ""}{form.children ? `, ${form.children} child${form.children > 1 ? "ren" : ""}` : ""} · {trip.season} season
Total package price
{usd(trip.total)}
Per person{usd(trip.perPerson)}
Deposit ({rates.depositPct}%){usd(trip.deposit)}
{/* itinerary */}

Day-by-day itinerary

{trip.itinerary.map((d, i) => (
{d.day}
{d.title}
{d.note &&
{d.note}
}
))}
{/* breakdown + incl/excl */}

Price breakdown

{trip.breakdown.map((b, i) => (
{b.label}{usd(b.amount)}
))}
Subtotal{usd(trip.subtotal)}
WildTrail service & margin ({rates.margin}%){usd(trip.total - trip.subtotal)}
Total{usd(trip.total)}

What's included

    {["Accommodation as specified", "All park & conservation fees", "Professional driver-guide", "4×4 safari vehicle / transfers", "Drinking water on safari", "Game drives per itinerary"].map((x) => (
  • {x}
  • ))}

Excluded

    {["International flights", "Tanzania visa", "Travel insurance", "Tips & gratuities", "Personal expenses"].map((x) => (
  • {x}
  • ))}
A {rates.depositPct}% deposit confirms your booking; balance due 45 days before arrival. Quote valid 14 days, subject to availability. Prices in USD per the above party size and dates. Bank & payment details provided on the confirmation invoice.
{/* action buttons */}
Request booking WhatsApp consultant
); } /* ----------------------------- PANELS ----------------------------- */ function RatesPanel({ rates, setRates, onClose }) { const upd = (path, val) => { const v = parseFloat(val); setRates((r) => { const n = { ...r, lodge: { ...r.lodge }, beach: { ...r.beach } }; if (path[0] === "lodge" || path[0] === "beach") n[path[0]][path[1]] = isNaN(v) ? 0 : v; else n[path[0]] = isNaN(v) ? 0 : v; return n; }); }; return (
e.stopPropagation()}>
Rates & Margin
Admin · drives every quote
In production these sync from the supplier portal & TANAPA. Change a number and reopen a quote to see it recalculate.
{STYLES.map((s) => upd(["lodge", s], v)} />)} {STYLES.map((s) => upd(["beach", s], v)} />)} upd(["vehiclePerDay"], v)} /> upd(["sharedPerPersonDay"], v)} /> upd(["flightPerSector"], v)} /> setRates((r) => ({ ...r, vatParkFees: (parseFloat(v) || 0) / 100 }))} />
WildTrail margin{rates.margin}%
setRates((r) => ({ ...r, margin: parseInt(e.target.value) }))} style={{ width: "100%", accentColor: "var(--ochre)" }} />
5%40%
); } function DepositModal({ trip, rates, onClose }) { return (
e.stopPropagation()}>

Secure deposit

{rates.depositPct}% confirms your dates. In production this opens your gateway — Flutterwave, Pesapal, DPO, Selcom or card.

{usd(trip.deposit)}
{["Flutterwave", "Pesapal", "DPO Pay", "Visa", "Mastercard", "PayPal"].map((g) => ( {g} ))}
); } /* ----------------------------- SMALL PARTS ----------------------------- */ const Section = ({ icon, title, children }) => (
{icon}{title}
{children}
); const Field = ({ label, children }) => (
{label}
{children}
); const Pills = ({ options, value, onPick, small, icons }) => (
{options.map((o) => ( ))}
); const Stepper = ({ value, onChange, min = 0, icon }) => (
{icon} {value}
); const RateBlock = ({ title, children }) => (
{title}
{children}
); const RateInput = ({ label, value, onChange }) => ( ); /* ----------------------------- ENGINE ----------------------------- */ function buildTrip(form, rates) { const pax = form.adults + form.children; const season = seasonFor(form.arrival); const seasonMult = rates.seasonMult[season]; // total days let totalDays; let warning = ""; if (form.arrival && form.departure) { const a = new Date(form.arrival + "T00:00"), d = new Date(form.departure + "T00:00"); totalDays = Math.round((d - a) / 86400000) + 1; } const selected = DESTINATIONS.filter((x) => form.dests.includes(x.id)).sort((p, q) => p.order - q.order); const sumBase = selected.reduce((s, x) => s + x.baseNights, 0); if (!totalDays || totalDays < 2) { totalDays = sumBase + 2; warning = "Add dates for an exact quote."; } const nights = totalDays - 1; // sleeps let safariNights = nights - 1; // minus arrival night in Arusha if (safariNights < 0) safariNights = 0; // allocate nights across destinations (1 each, extras to higher baseNights) const alloc = {}; selected.forEach((d) => (alloc[d.id] = 0)); let left = safariNights; selected.forEach((d) => { if (left > 0) { alloc[d.id] = 1; left--; } }); // distribute remaining by baseNights weight (Serengeti etc. get more) const order = [...selected].sort((p, q) => q.baseNights - p.baseNights); let i = 0; while (left > 0 && order.length) { const d = order[i % order.length]; if (alloc[d.id] < d.baseNights + 2) { alloc[d.id]++; left--; } i++; if (i > 200) break; } // ---- build itinerary ---- const itinerary = [{ day: 1, title: "Arrival in Arusha", note: "Airport pickup & overnight; safari briefing." }]; let dayN = 1; selected.forEach((d) => { for (let k = 0; k < alloc[d.id]; k++) { dayN++; let title = d.name, note = ""; if (d.type === "park") { title = `${d.name} — game drives`; note = k === 0 ? "Full day exploring with your guide." : "Continue exploring the ecosystem."; } else if (d.type === "trek") { title = `${d.name} — ascent`; note = "Guided trekking with full mountain crew."; } else if (d.type === "beach") { title = `${d.name} — beach & leisure`; note = "Relax on the coast; optional excursions."; } itinerary.push({ day: dayN, title, note }); } }); itinerary.push({ day: totalDays, title: "Departure", note: "Transfer to the airport for your flight home." }); // ---- costs ---- const breakdown = []; // accommodation: arrival night + park/beach nights (trek nights are in the trek package) const trekNights = selected.filter((d) => d.type === "trek").reduce((s, d) => s + alloc[d.id], 0); const beachNights = selected.filter((d) => d.type === "beach").reduce((s, d) => s + alloc[d.id], 0); const lodgeNights = nights - trekNights - beachNights; // includes arrival night const lodgeRate = rates.lodge[form.style]; const beachRate = rates.beach[form.style]; const accomLodge = lodgeNights * lodgeRate * seasonMult * pax; const accomBeach = beachNights * beachRate * seasonMult * pax; if (accomLodge > 0) breakdown.push({ label: `Lodge / camp · ${lodgeNights} nt × ${pax} pax`, amount: accomLodge }); if (accomBeach > 0) breakdown.push({ label: `Beach resort · ${beachNights} nt × ${pax} pax`, amount: accomBeach }); // park fees (per night-in-park as a park day) + VAT, EAC/resident discounted const natFactor = form.nationality === "East African" ? 0.15 : form.nationality === "Resident / Expat" ? 0.5 : 1; let parkFeesRaw = 0, craterFees = 0, concession = 0; selected.filter((d) => d.type === "park").forEach((d) => { const fee = season === "Low" ? d.feeLow : d.feeHigh; parkFeesRaw += alloc[d.id] * (fee * form.adults + (d.childFee || 0) * form.children) * natFactor; if (d.craterFee) craterFees += d.craterFee * Math.max(1, Math.ceil(pax / 6)); if (d.interior && (form.style === "Luxury" || form.style === "Ultra-Luxury")) concession += alloc[d.id] * rates.concessionPPPN * pax; }); const parkFees = parkFeesRaw * (1 + rates.vatParkFees); if (parkFees > 0) breakdown.push({ label: "Park & conservation fees (incl. VAT)", amount: parkFees }); if (craterFees > 0) breakdown.push({ label: "Ngorongoro crater service fee", amount: craterFees }); if (concession > 0) breakdown.push({ label: "Park-interior concession fees", amount: concession }); // transport const parkNights = selected.filter((d) => d.type === "park").reduce((s, d) => s + alloc[d.id], 0); const landDays = totalDays - beachNights - trekNights; // vehicle present for the land safari let transport = 0; const clusters = selected.filter((d) => d.type === "park").length; if (form.transport === "Private Safari") { transport = Math.max(landDays, 1) * rates.vehiclePerDay; breakdown.push({ label: `Private 4×4 · ${Math.max(landDays, 1)} days`, amount: transport }); } else if (form.transport === "Shared Safari") { transport = Math.max(landDays, 1) * rates.sharedPerPersonDay * pax; breakdown.push({ label: `Shared safari · ${Math.max(landDays, 1)} days × ${pax}`, amount: transport }); } else { const sectors = Math.max(clusters, 1) + (beachNights > 0 ? 1 : 0); const flights = sectors * rates.flightPerSector * pax; const ground = parkNights * rates.vehiclePerDay * 0.7; transport = flights + ground; breakdown.push({ label: `Bush flights · ${sectors} sectors × ${pax}`, amount: flights }); if (ground > 0) breakdown.push({ label: "In-park game-drive vehicle", amount: ground }); } // beach transfer flight if (beachNights > 0 && form.transport !== "Fly-In Safari") { const znz = rates.flightPerSector * pax; transport += znz; breakdown.push({ label: `Zanzibar flight · ${pax} pax`, amount: znz }); } // trek package const trekCost = selected.filter((d) => d.type === "trek").reduce((s, d) => s + alloc[d.id] * (d.trekPPPD || 0) * pax, 0); if (trekCost > 0) breakdown.push({ label: "Kilimanjaro trek package", amount: trekCost }); // transfers breakdown.push({ label: "Airport transfers", amount: rates.transfersFlat }); const subtotal = breakdown.reduce((s, b) => s + b.amount, 0); const total = subtotal * (1 + rates.margin / 100); const perPerson = total / pax; const deposit = total * (rates.depositPct / 100); return { totalDays, nights, season, itinerary, breakdown, subtotal, total, perPerson, deposit, dests: selected, warning }; } /* ----------------------------- STYLES ----------------------------- */ const CSS = ` @import url('https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,400;9..144,500;9..144,600;9..144,700&family=Hanken+Grotesk:wght@400;500;600;700&display=swap'); :root{ --bg:#f5efe3; --paper:#fdfaf3; --ink:#2c2419; --muted:#6b5d4c; --line:#e6dcc8; --ochre:#bb5e2f; --ochre-d:#9d4d24; --green:#4a5d36; --gold:#b8902e; --display:'Fraunces',serif; --body:'Hanken Grotesk',sans-serif; } *{box-sizing:border-box;} .hov{transition:all .15s ease;cursor:pointer;} .hov:hover{filter:brightness(0.97);transform:translateY(-1px);} .cta{transition:all .18s ease;cursor:pointer;} .cta:hover{transform:translateY(-2px);box-shadow:0 10px 24px rgba(155,77,36,.28);} input[type=date]::-webkit-calendar-picker-indicator{cursor:pointer;opacity:.6;} @media print{ .no-print{display:none !important;} body{background:#fff !important;} #proposal{box-shadow:none !important;border:none !important;} } @media (max-width:760px){ .bgrid{grid-template-columns:1fr !important;} .tcol{grid-template-columns:1fr !important;} } `; const S = { shell: { fontFamily: "var(--body)", background: "var(--bg)", color: "var(--ink)", minHeight: "100vh", padding: "0 0 40px" }, header: { display: "flex", justifyContent: "space-between", alignItems: "center", padding: "18px 22px", borderBottom: "1px solid var(--line)", background: "var(--paper)", position: "sticky", top: 0, zIndex: 10 }, brandWrap: { display: "flex", alignItems: "center", gap: 12 }, logoMark: { width: 40, height: 40, borderRadius: 12, background: "linear-gradient(135deg,var(--ochre),var(--ochre-d))", color: "#fff", display: "flex", alignItems: "center", justifyContent: "center", boxShadow: "0 4px 12px rgba(155,77,36,.25)" }, brand: { fontFamily: "var(--display)", fontSize: 21, fontWeight: 600, letterSpacing: "-0.01em", lineHeight: 1 }, tag: { fontSize: 11.5, color: "var(--muted)", letterSpacing: ".02em", marginTop: 3 }, ghostBtn: { display: "flex", alignItems: "center", gap: 7, background: "transparent", border: "1px solid var(--line)", color: "var(--ink)", padding: "9px 14px", borderRadius: 10, fontSize: 13, fontWeight: 600, fontFamily: "var(--body)" }, main: { maxWidth: 1080, margin: "0 auto", padding: "26px 22px" }, buildGrid: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: 20 }, card: { background: "var(--paper)", border: "1px solid var(--line)", borderRadius: 16, padding: 18 }, cardHead: { fontFamily: "var(--display)", fontSize: 16, fontWeight: 600, display: "flex", alignItems: "center", gap: 9, marginBottom: 14 }, cardIcon: { color: "var(--ochre)", display: "flex" }, fieldLabel: { fontSize: 12, fontWeight: 600, color: "var(--muted)", marginBottom: 6, textTransform: "uppercase", letterSpacing: ".04em" }, row2: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }, input: { width: "100%", padding: "10px 12px", border: "1px solid var(--line)", borderRadius: 10, fontSize: 14, fontFamily: "var(--body)", background: "#fff", color: "var(--ink)" }, segment: { display: "flex", gap: 6, background: "#f0e8d8", padding: 4, borderRadius: 11 }, segBtn: { flex: 1, padding: "8px 6px", border: "none", background: "transparent", borderRadius: 8, fontSize: 12, fontWeight: 600, color: "var(--muted)", fontFamily: "var(--body)" }, segOn: { background: "#fff", color: "var(--ink)", boxShadow: "0 1px 4px rgba(0,0,0,.08)" }, chipWrap: { display: "flex", flexWrap: "wrap", gap: 8 }, chip: { display: "flex", alignItems: "center", gap: 6, padding: "9px 13px", border: "1px solid var(--line)", borderRadius: 999, background: "#fff", fontSize: 13, fontWeight: 600, color: "var(--ink)", fontFamily: "var(--body)" }, chipOn: { background: "var(--green)", borderColor: "var(--green)", color: "#fff" }, groupLabel: { fontSize: 11, fontWeight: 700, color: "var(--muted)", textTransform: "uppercase", letterSpacing: ".06em", marginBottom: 7 }, pill: { padding: "11px 16px", border: "1.5px solid var(--line)", borderRadius: 12, background: "#fff", fontSize: 14, fontWeight: 600, color: "var(--ink)", fontFamily: "var(--body)", display: "flex", alignItems: "center", gap: 6 }, pillSm: { padding: "8px 13px", border: "1.5px solid var(--line)", borderRadius: 10, background: "#fff", fontSize: 13, fontWeight: 600, color: "var(--ink)", fontFamily: "var(--body)", display: "flex", alignItems: "center", gap: 6 }, pillOn: { borderColor: "var(--ochre)", background: "#fbf1e9", color: "var(--ochre-d)" }, stepper: { display: "flex", alignItems: "center", gap: 10, border: "1px solid var(--line)", borderRadius: 10, padding: "6px 12px", background: "#fff" }, stepBtn: { width: 28, height: 28, borderRadius: 8, border: "1px solid var(--line)", background: "#faf6ee", fontSize: 18, lineHeight: 1, color: "var(--ink)", fontFamily: "var(--body)" }, stepVal: { flex: 1, textAlign: "center", fontSize: 16, fontWeight: 700 }, previewCard: { background: "linear-gradient(160deg,#fdfaf3,#f6eee0)", border: "1px solid var(--line)", borderRadius: 16, padding: 20, boxShadow: "0 8px 24px rgba(64,48,28,.07)" }, previewTop: { display: "flex", justifyContent: "space-between", alignItems: "flex-start", marginBottom: 16, gap: 12 }, previewKicker: { fontSize: 11, fontWeight: 700, color: "var(--muted)", textTransform: "uppercase", letterSpacing: ".06em" }, previewPrice: { fontFamily: "var(--display)", fontSize: 40, fontWeight: 600, lineHeight: 1.05, color: "var(--ink)", margin: "2px 0" }, previewPP: { fontSize: 13, color: "var(--muted)" }, previewMeta: { display: "flex", flexDirection: "column", gap: 4, alignItems: "flex-end", fontSize: 12.5, fontWeight: 600, color: "var(--muted)" }, cta: { width: "100%", padding: "15px", background: "linear-gradient(135deg,var(--ochre),var(--ochre-d))", color: "#fff", border: "none", borderRadius: 13, fontSize: 16, fontWeight: 700, fontFamily: "var(--body)", display: "flex", alignItems: "center", justifyContent: "center", gap: 8 }, previewNote: { fontSize: 12, color: "var(--muted)", textAlign: "center", marginTop: 10 }, quoteHead: { marginBottom: 14 }, backBtn: { background: "transparent", border: "1px solid var(--line)", padding: "9px 14px", borderRadius: 10, fontSize: 13, fontWeight: 600, fontFamily: "var(--body)", color: "var(--ink)" }, proposal: { background: "var(--paper)", border: "1px solid var(--line)", borderRadius: 18, padding: 28, boxShadow: "0 10px 30px rgba(64,48,28,.08)" }, propHeader: { display: "flex", justifyContent: "space-between", alignItems: "flex-start", paddingBottom: 18, borderBottom: "2px solid var(--line)", gap: 16, flexWrap: "wrap" }, propMeta: { textAlign: "right", fontSize: 13, color: "var(--muted)", lineHeight: 1.7 }, priceBanner: { display: "flex", justifyContent: "space-between", alignItems: "center", flexWrap: "wrap", gap: 16, background: "linear-gradient(135deg,var(--green),#3a4a2b)", color: "#fff", borderRadius: 14, padding: "20px 24px", margin: "20px 0" }, bannerKicker: { fontSize: 11.5, textTransform: "uppercase", letterSpacing: ".08em", opacity: 0.8 }, bannerPrice: { fontFamily: "var(--display)", fontSize: 42, fontWeight: 600, lineHeight: 1.05 }, bannerSplit: { display: "flex", gap: 28 }, bannerLabel: { display: "block", fontSize: 11.5, opacity: 0.8, textTransform: "uppercase", letterSpacing: ".05em" }, bannerVal: { display: "block", fontSize: 22, fontWeight: 700, fontFamily: "var(--display)" }, h3: { fontFamily: "var(--display)", fontSize: 18, fontWeight: 600, margin: "20px 0 12px", color: "var(--ink)" }, timeline: { display: "flex", flexDirection: "column" }, dayRow: { display: "grid", gridTemplateColumns: "44px 2px 1fr", gap: 14, paddingBottom: 16, alignItems: "start" }, dayNum: { width: 44, height: 44, borderRadius: 11, background: "#fbf1e9", color: "var(--ochre-d)", fontFamily: "var(--display)", fontWeight: 700, fontSize: 18, display: "flex", alignItems: "center", justifyContent: "center", border: "1px solid #f0ddcc" }, dayLine: { background: "var(--line)", width: 2, height: "100%", borderRadius: 2, marginLeft: 0 }, dayTitle: { fontWeight: 700, fontSize: 15 }, dayNote: { fontSize: 13, color: "var(--muted)", marginTop: 2 }, twoCol: { display: "grid", gridTemplateColumns: "1.1fr 1fr", gap: 28 }, breakdown: { border: "1px solid var(--line)", borderRadius: 12, overflow: "hidden" }, bRow: { display: "flex", justifyContent: "space-between", padding: "11px 14px", fontSize: 13.5, borderBottom: "1px solid var(--line)" }, bSub: { background: "#faf6ee", fontWeight: 600 }, bTotal: { background: "var(--ink)", color: "#fff", fontWeight: 700, fontSize: 16, fontFamily: "var(--display)", borderBottom: "none" }, list: { listStyle: "none", padding: 0, margin: 0, display: "flex", flexDirection: "column", gap: 8 }, li: { display: "flex", alignItems: "center", gap: 9, fontSize: 13.5 }, terms: { marginTop: 22, paddingTop: 16, borderTop: "1px solid var(--line)", fontSize: 12, color: "var(--muted)", lineHeight: 1.6 }, actions: { display: "grid", gridTemplateColumns: "repeat(4,1fr)", gap: 12, marginTop: 18 }, actBtn: { display: "flex", alignItems: "center", justifyContent: "center", gap: 8, padding: "14px", borderRadius: 12, fontSize: 14, fontWeight: 700, fontFamily: "var(--body)", textDecoration: "none", border: "none" }, actPrimary: { background: "linear-gradient(135deg,var(--ochre),var(--ochre-d))", color: "#fff" }, actDark: { background: "var(--ink)", color: "#fff" }, actGold: { background: "var(--gold)", color: "#fff" }, actWa: { background: "#1faf54", color: "#fff" }, footer: { maxWidth: 1080, margin: "26px auto 0", padding: "16px 22px 0", borderTop: "1px solid var(--line)", display: "flex", justifyContent: "space-between", fontSize: 12, color: "var(--muted)", flexWrap: "wrap", gap: 8 }, overlay: { position: "fixed", inset: 0, background: "rgba(40,30,18,.45)", backdropFilter: "blur(3px)", zIndex: 50, display: "flex", justifyContent: "flex-end" }, drawer: { width: "min(420px,94vw)", height: "100%", background: "var(--paper)", boxShadow: "-10px 0 40px rgba(0,0,0,.2)", display: "flex", flexDirection: "column" }, drawerHead: { display: "flex", justifyContent: "space-between", alignItems: "center", padding: 20, borderBottom: "1px solid var(--line)" }, drawerBody: { padding: 20, overflowY: "auto" }, iconBtn: { width: 34, height: 34, borderRadius: 9, border: "1px solid var(--line)", background: "#fff", display: "flex", alignItems: "center", justifyContent: "center", color: "var(--ink)" }, rateNote: { fontSize: 12.5, color: "var(--muted)", background: "#faf3e6", border: "1px solid var(--line)", borderRadius: 10, padding: "10px 12px", marginBottom: 18, lineHeight: 1.5 }, rateInputWrap: { display: "flex", flexDirection: "column", gap: 3 }, rateInput: { padding: "8px 10px", border: "1px solid var(--line)", borderRadius: 8, fontSize: 14, fontFamily: "var(--body)", background: "#fff", color: "var(--ink)" }, marginBox: { background: "#fbf1e9", border: "1px solid #f0ddcc", borderRadius: 12, padding: 16, marginTop: 8 }, modal: { width: "min(440px,92vw)", margin: "auto", background: "var(--paper)", borderRadius: 18, padding: 26, textAlign: "center", boxShadow: "0 20px 60px rgba(0,0,0,.3)" }, depositAmt: { fontFamily: "var(--display)", fontSize: 44, fontWeight: 600, color: "var(--green)", margin: "16px 0 4px" }, gateways: { display: "flex", flexWrap: "wrap", gap: 7, justifyContent: "center", marginTop: 8 }, gwChip: { fontSize: 11.5, fontWeight: 600, padding: "5px 10px", borderRadius: 999, background: "#f0e8d8", color: "var(--muted)" }, };