// La Vida Es Bella — single-page mobile landing // Mobile-first column, letterboxed on desktop. Tweakable palette / type / layout / imagery. const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "palette": "warm-gold", "type": "didone", "layout": "centered", "imagery": "ingredients", "noteShape": "arch", "showInspiredBy": true, "showTrustStrip": true, "showFAQ": true, "showReviews": false, "showUrgency": false }/*EDITMODE-END*/; // ─── tokens ───────────────────────────────────────────────────────────────── const PALETTES = { "warm-gold": { bg: "#f4ecdd", surface: "#efe4cf", fg: "#28201a", fgSoft: "#4a3f33", muted: "#8a7b66", rule: "rgba(40,32,26,.14)", accent: "#c79a4b", ctaBg: "#28201a", ctaFg: "#f4ecdd", onDark: false, swatch: ["#f4ecdd","#28201a","#c79a4b"], }, "editorial": { bg: "#f6f3ec", surface: "#efeae0", fg: "#141210", fgSoft: "#3a3530", muted: "#8a8278", rule: "rgba(20,18,16,.12)", accent: "#141210", ctaBg: "#141210", ctaFg: "#f6f3ec", onDark: false, swatch: ["#f6f3ec","#141210","#8a8278"], }, "champagne": { bg: "#eadfca", surface: "#e3d5ba", fg: "#3a2d20", fgSoft: "#5a4838", muted: "#9a8870", rule: "rgba(58,45,32,.14)", accent: "#a87f4a", ctaBg: "#3a2d20", ctaFg: "#eadfca", onDark: false, swatch: ["#eadfca","#3a2d20","#a87f4a"], }, "dark-luxe": { bg: "#15110d", surface: "#1f1812", fg: "#ece1cb", fgSoft: "#b8ab94", muted: "#7a6e5b", rule: "rgba(236,225,203,.12)", accent: "#c79a4b", ctaBg: "#ece1cb", ctaFg: "#15110d", onDark: true, swatch: ["#15110d","#ece1cb","#c79a4b"], }, }; const TYPES = { "didone": { display: '"Bodoni Moda", serif', body: '"DM Sans", sans-serif', dw: 400, dtrack: "-0.01em" }, "oldstyle": { display: '"Cormorant Garamond", serif', body: '"DM Sans", sans-serif', dw: 400, dtrack: "0em" }, "modern-sans":{ display: '"Manrope", sans-serif', body: '"Manrope", sans-serif', dw: 300, dtrack: "-0.03em" }, "mix": { display: '"Italiana", serif', body: '"DM Sans", sans-serif', dw: 400, dtrack: "0.005em" }, }; // ─── data ─────────────────────────────────────────────────────────────────── const PRODUCT = { house: "Fragrance World", name: "La Vida Es Bella", type: "Eau de Parfum", size: "100 ml", price: "€29.99", tagline: "Уханието на радостта от живота.", pitch: "Сочен касис, пудрен ирис и кадифена ванилия — аромат за жената, която не се извинява за своята женственост.", inspired: "Вдъхновен от Lancôme", ctaLabel: "Поръчай сега", trust: [ { icon: "→", label: "Доставка 1–2 дни" }, { icon: "↻", label: "14-дневно връщане" }, { icon: "○", label: "Сигурно плащане" }, ], rating: { stars: 4.8, count: 1247 }, urgency: "Ограничено количество · 27 бутилки на склад", notes: { top: { label: "Връхни нотки", items: ["Касис", "Круша"], hint: "Сочно, игриво, пролетно" }, heart: { label: "Сърце", items: ["Ирис", "Жасмин", "Портокалов цвят"], hint: "Пудрено, цветно, изискано" }, base: { label: "База", items: ["Ванилия", "Пралине", "Пачули"], hint: "Кадифено, кехлибарено, дълготрайно" }, }, story: "Свежа експлозия от касис и круша, която разцъфва в букет от ирис, жасмин и портокалов цвят — за да завърши в топлата прегръдка на ванилия, пралине и пачули. Аромат, който се помни.", forWho: "Подходящ за пролетта и есента — когато въздухът е най-романтичен.", faq: [ { q: "Колко се задържа ароматът?", a: "6–8 часа на кожата и до 24 часа върху дрехите." }, { q: "Каква е концентрацията?", a: "Eau de Parfum — 18% ароматни масла. Изразен и дълготраен." }, { q: "Кога ще пристигне поръчката?", a: "1–2 работни дни за България. Безплатна доставка над €40." }, { q: "Мога ли да върна поръчката?", a: "Да — в рамките на 14 дни от получаването, при условие че продуктът е неотворен (целофанът на опаковката не е премахнат)." }, ], stripeUrl: "#checkout", }; // ─── helpers ──────────────────────────────────────────────────────────────── function applyTheme(p, t) { const r = document.documentElement; r.style.setProperty("--bg", p.bg); r.style.setProperty("--surface", p.surface); r.style.setProperty("--fg", p.fg); r.style.setProperty("--fg-soft", p.fgSoft); r.style.setProperty("--muted", p.muted); r.style.setProperty("--rule", p.rule); r.style.setProperty("--accent", p.accent); r.style.setProperty("--cta-bg", p.ctaBg); r.style.setProperty("--cta-fg", p.ctaFg); r.style.setProperty("--font-display", t.display); r.style.setProperty("--font-body", t.body); r.style.setProperty("--display-weight", String(t.dw)); r.style.setProperty("--display-tracking", t.dtrack); document.body.style.background = p.onDark ? "#0a0805" : "#0c0a08"; } // ─── pieces ───────────────────────────────────────────────────────────────── function Hero({ palette, layout }) { // Bottle hero — composition shifts subtly by layout const onDark = palette.onDark; if (layout === "asymmetric") { return (
{PRODUCT.house}
Eau de Parfum
100 ml

La Vida
es Bella

{onDark ?
:
} La Vida Es Bella eau de parfum
); } if (layout === "full-bleed") { return (
{PRODUCT.house}
N°01
{onDark ?
:
} La Vida Es Bella eau de parfum

La Vida es Bella

{PRODUCT.type} · {PRODUCT.size}
); } // centered (default) return (
{PRODUCT.house}
{onDark ?
:
} La Vida Es Bella eau de parfum

La Vida
es Bella


{PRODUCT.type} · {PRODUCT.size}
); } function BuyBlock({ showInspiredBy, showReviews, showUrgency, showTrustStrip }) { return (

{PRODUCT.tagline}

{PRODUCT.pitch}

{showReviews && (
{PRODUCT.rating.stars.toFixed(1)} · {PRODUCT.rating.count.toLocaleString("bg-BG")} отзива
)} {showInspiredBy && (
{PRODUCT.inspired}
)} {/* primary conversion block — price + CTA in one tight unit */}
{PRODUCT.price}
{PRODUCT.size}
{PRODUCT.ctaLabel} {showUrgency && (
• {PRODUCT.urgency}
)} {showTrustStrip && (
{PRODUCT.trust.map((tr, i) => (
{tr.icon} {tr.label}
))}
)}
); } function Stars({ value }) { const full = Math.floor(value); const half = value - full >= 0.4 && value - full < 0.9; return ( {[0,1,2,3,4].map(i => { const ch = i < full ? "★" : (i === full && half ? "☆" : "☆"); return {ch}; })} ); } function NotesPyramid() { const rows = [ { ...PRODUCT.notes.top, tier: "TOP", width: 56 }, { ...PRODUCT.notes.heart, tier: "HEART", width: 78 }, { ...PRODUCT.notes.base, tier: "BASE", width: 100 }, ]; return (
Композиция

Ароматна пирамида

{rows.map((r, i) => (
{r.tier}
{r.items.join(" · ")}
{r.hint}
))}
); } function Story() { return (

Историята

{PRODUCT.story}

{PRODUCT.forWho}

); } function FAQ() { const [open, setOpen] = React.useState(null); return (

Чести въпроси
); } function Imagery({ kind, palette, noteShape }) { if (kind === "bottle-only") return null; if (kind === "mood") { return (
lifestyle / mood shot
За жената, която живее със сърце
); } if (kind === "ingredients") { const tiles = [ { tier: "TOP", label: "Касис · Круша", cls: "ing-top" }, { tier: "HEART", label: "Ирис · Жасмин", cls: "ing-heart" }, { tier: "BASE", label: "Ванилия · Пралине", cls: "ing-base" }, ]; return (
Палитра на нотките
{tiles.map(it => (
{it.tier}
{it.label}
))}
); } if (kind === "angle") { return (
side angle
cap detail
); } return null; } function SecondaryCTA() { return (

Готова ли си?

{PRODUCT.ctaLabel} · {PRODUCT.price}
Сигурно плащане · Stripe
); } function StickyCTA() { return (
{PRODUCT.ctaLabel} · {PRODUCT.price}
); } function Footer() { return ( ); } // ─── tweaks panel ─────────────────────────────────────────────────────────── function Panel({ t, setTweak }) { return ( PALETTES[k].swatch)} onChange={(v) => { const match = Object.keys(PALETTES).find(k => PALETTES[k].swatch.every((c, i) => c === v[i]) ); if (match) setTweak("palette", match); }} /> setTweak("palette", v)} /> setTweak("type", v)} /> setTweak("layout", v)} /> setTweak("imagery", v)} /> setTweak("noteShape", v)} /> setTweak("showInspiredBy", v)} /> setTweak("showTrustStrip", v)} /> setTweak("showFAQ", v)} /> setTweak("showReviews", v)} /> setTweak("showUrgency", v)} /> ); } // ─── app ──────────────────────────────────────────────────────────────────── function App() { const [t, setTweak] = useTweaks(TWEAK_DEFAULTS); const palette = PALETTES[t.palette] || PALETTES["warm-gold"]; const type = TYPES[t.type] || TYPES["didone"]; React.useEffect(() => { applyTheme(palette, type); }, [palette, type]); return (
{t.imagery !== "bottle-only" && } {t.showFAQ && }
); } ReactDOM.createRoot(document.getElementById("root")).render();