// Main app — composes sections, manages global state (locale, mega menu, tweaks). const { useState: useStateApp, useEffect: useEffectApp, useRef: useRefApp } = React; const { NovaMark, TopBar, MainNav, Hero, Icon } = window.NovaSections1; const { TreatmentsBlock, WellnessBlock, DoctorsBlock } = window.NovaSections2; const { BeforeAfterBlock, LocationsBlock, BookingBlock, AboutBlock, Footer } = window.NovaSections3; // ============ TWEAKS ============ const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "palette": "sage", "displayFont": "Fraunces", "bookingOpenedAt": 0 }/*EDITMODE-END*/; const PALETTES = { sage: { label: 'Sage + Brass', desc: 'Wellness clinical green + warm brass. Default — leans into the longevity arm.', vars: { '--paper': '#FBFAF6', '--paper-warm': '#F4EFE6', '--mist': '#EEF1ED', '--sage': '#5E7D71', '--sage-deep': '#3F5950', '--sage-tint': '#E8EEEA', '--brass': '#B89B5E', '--brass-deep': '#8A7240', '--brass-tint': '#F1E9D4', '--ink': '#1A1F24', '--ink-soft': '#3B4148', '--muted': '#7C8079', '--line': '#DED9CE', '--line-soft': '#ECE7DC', } }, ivory: { label: 'Ivory + Clay', desc: 'Lighter, warmer — interior-photo aligned cream with terracotta-clay highlight.', vars: { '--paper': '#FAF6EE', '--paper-warm': '#EFE5D2', '--mist': '#F1ECE0', '--sage': '#A56848', '--sage-deep': '#7A4226', '--sage-tint': '#F0E0D3', '--brass': '#C9A876', '--brass-deep': '#8E6A3C', '--brass-tint': '#EFE3CC', '--ink': '#241D17', '--ink-soft': '#4A3F35', '--muted': '#857667', '--line': '#DED2BD', '--line-soft': '#EAE0CD', } }, teal: { label: 'Deep Teal', desc: 'Cooler, more medical — deep teal as the primary; brass dialled back.', vars: { '--paper': '#F8F8F6', '--paper-warm': '#EEEDE8', '--mist': '#E8EBEA', '--sage': '#2E7D7B', '--sage-deep': '#1F5957', '--sage-tint': '#D9E8E7', '--brass': '#9C8964', '--brass-deep': '#736245', '--brass-tint': '#E8E0CC', '--ink': '#15201F', '--ink-soft': '#384242', '--muted': '#717975', '--line': '#D5D5CF', '--line-soft': '#E5E5DF', } }, graphite: { label: 'Graphite', desc: 'Editorial mono — paper, ink and a single brass accent. Most restrained.', vars: { '--paper': '#F6F4F0', '--paper-warm': '#E8E4DA', '--mist': '#EAE7E0', '--sage': '#3D4544', '--sage-deep': '#1F2424', '--sage-tint': '#E0E0DC', '--brass': '#B89B5E', '--brass-deep': '#7A6238', '--brass-tint': '#EDE5D0', '--ink': '#161616', '--ink-soft': '#3A3A38', '--muted': '#7B7873', '--line': '#D6D2C7', '--line-soft': '#E8E3D6', } }, }; const FONT_OPTIONS = { Fraunces: 'Fraunces, "Times New Roman", serif', Cormorant: '"Cormorant Garamond", "Times New Roman", serif', Newsreader: 'Newsreader, "Times New Roman", serif', Manrope: 'Manrope, system-ui, sans-serif', }; function applyPalette(name) { const p = PALETTES[name] || PALETTES.sage; Object.entries(p.vars).forEach(([k,v]) => document.documentElement.style.setProperty(k, v)); } function applyDisplayFont(name) { const stack = FONT_OPTIONS[name] || FONT_OPTIONS.Fraunces; document.documentElement.style.setProperty('--display-font', stack); // restyle .serif let s = document.getElementById('__tweak-font-style'); if (!s) { s = document.createElement('style'); s.id = '__tweak-font-style'; document.head.appendChild(s); } s.textContent = `.serif { font-family: ${stack} !important; }`; } // Load extra display fonts on demand function ensureFontLoaded(name) { if (document.getElementById('__font-' + name)) return; const link = document.createElement('link'); link.id = '__font-' + name; link.rel = 'stylesheet'; if (name === 'Cormorant') link.href = 'https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,500;1,400&display=swap'; if (name === 'Newsreader') link.href = 'https://fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,300;0,6..72,400;1,6..72,300&display=swap'; if (link.href) document.head.appendChild(link); } function NovaTweaks({ tweaks, setTweak }) { return ( { setTweak('palette', v); applyPalette(v); }} options={Object.entries(PALETTES).map(([k, v]) => ({ value: k, label: v.label }))} />
{PALETTES[tweaks.palette].desc}
{ setTweak('displayFont', v); ensureFontLoaded(v); applyDisplayFont(v); }} options={[ { value: 'Fraunces', label: 'Fraunces (default)' }, { value: 'Cormorant', label: 'Cormorant Garamond' }, { value: 'Newsreader', label: 'Newsreader' }, { value: 'Manrope', label: 'Manrope (sans)' }, ]} />
); } // ============ APP ============ function App() { const [locale, setLocale] = useStateApp('EN'); const [openMega, setOpenMega] = useStateApp(null); const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS); const [bookingOpen, setBookingOpen] = useStateApp(0); // Apply palette + font on mount + change useEffectApp(() => { applyPalette(tweaks.palette); }, [tweaks.palette]); useEffectApp(() => { ensureFontLoaded(tweaks.displayFont); applyDisplayFont(tweaks.displayFont); }, [tweaks.displayFont]); // RTL useEffectApp(() => { document.documentElement.dir = locale === 'AR' ? 'rtl' : 'ltr'; document.documentElement.lang = locale.toLowerCase(); }, [locale]); const goBook = () => setBookingOpen(n => n + 1); return (
); } const root = ReactDOM.createRoot(document.getElementById('root')); root.render();