const { useEffect, useRef, useState } = React; const mountRoot = typeof ReactDOM.createRoot === 'function' ? ReactDOM.createRoot(document.getElementById('root')) : { render(element) { ReactDOM.render(element, document.getElementById('root')); } }; const defaultData = { settings: { company_name: 'Atelier Struktur', hero_badge: 'Konstruksi bangunan modern', hero_title_line_1: 'Bangun ruang', hero_title_line_2: 'yang terasa presisi.', hero_description: 'Dari rumah tinggal sampai proyek komersial, kami merancang, membangun, dan merapikan detail agar hasilnya kuat, efisien, dan enak dipandang.', hero_primary_cta_label: 'Mulai konsultasi', hero_primary_cta_url: '#kontak', hero_secondary_cta_label: 'Lihat proyek', hero_secondary_cta_url: '#proyek', about_title: 'Struktur rapi, progres jelas, hasil terasa mahal.', about_description: 'Kami menyatukan perencanaan teknis, kontrol lapangan, dan ritme eksekusi yang disiplin. Fokusnya sederhana: bangunan harus kokoh, timeline terkendali, dan kualitas akhir tetap bersih hingga serah terima.', contact_phone: '+62 812 0000 0000', contact_email: 'halo@atelierstruktur.com', contact_address: 'Makassar, Sulawesi Selatan', cta_title: 'Punya lahan atau proyek yang siap dimulai?', cta_description: 'Kirim kebutuhan Anda, lalu kami bantu mapping konsep, estimasi, dan tahapan pembangunan yang paling realistis.', footer_note: 'Membangun dengan disiplin, detail, dan komunikasi yang enak diajak kerja.' }, stats: [ { id: 1, value_label: '120+', label: 'proyek selesai tepat target', sort_order: 1 }, { id: 2, value_label: '14', label: 'tahun pengalaman tim inti', sort_order: 2 }, { id: 3, value_label: '98%', label: 'retensi klien dan referral', sort_order: 3 }, { id: 4, value_label: '24/7', label: 'monitoring progres lapangan', sort_order: 4 } ], services: [ { id: 1, title: 'Desain & build', description: 'Satu alur dari konsep, gambar kerja, anggaran, sampai eksekusi lapangan.', icon: 'DB', sort_order: 1 }, { id: 2, title: 'Konstruksi komersial', description: 'Ruko, kantor, showroom, dan ruang usaha dengan ritme kerja yang tertata.', icon: 'CM', sort_order: 2 }, { id: 3, title: 'Renovasi struktural', description: 'Upgrade tampilan dan kekuatan bangunan lama tanpa kehilangan efisiensi biaya.', icon: 'RV', sort_order: 3 } ], projects: [ { id: 1, title: 'Residensi Karebosi', category: 'Hunian premium', location: 'Makassar', year_label: '2025', size_label: '780 m2', summary: 'Hunian tiga lantai dengan struktur bersih, bukaan lebar, dan pengerjaan interior terkontrol.', image_url: 'https://images.unsplash.com/photo-1511818966892-d7d671e672a2?auto=format&fit=crop&w=1400&q=80', accent_color: '#d38841', is_featured: 1, sort_order: 1 }, { id: 2, title: 'Ruang Niaga Panakkukang', category: 'Komersial', location: 'Makassar', year_label: '2024', size_label: '1.240 m2', summary: 'Showroom dan kantor operasional dengan fasad tegas dan alur pengunjung yang efisien.', image_url: 'https://images.unsplash.com/photo-1486406146926-c627a92ad1ab?auto=format&fit=crop&w=1400&q=80', accent_color: '#bf6d2f', is_featured: 1, sort_order: 2 }, { id: 3, title: 'Villa Tebing Selatan', category: 'Hospitality', location: 'Maros', year_label: '2026', size_label: '960 m2', summary: 'Konstruksi vila lanskap dengan detailing batu, beton ekspos, dan area publik yang dramatis.', image_url: 'https://images.unsplash.com/photo-1460317442991-0ec209397118?auto=format&fit=crop&w=1400&q=80', accent_color: '#ad5f28', is_featured: 1, sort_order: 3 } ] }; const processSteps = [ { index: '01', title: 'Kebutuhan dipetakan', description: 'Kami bedah target ruang, budget, dan timeline supaya keputusan awal tetap realistis.' }, { index: '02', title: 'Eksekusi dikunci rapi', description: 'Gambar kerja, jadwal, material, dan kontrol lapangan disusun agar progres selalu terukur.' }, { index: '03', title: 'Serah terima percaya diri', description: 'Finishing dirapikan, punch list diselesaikan, lalu bangunan siap dipakai tanpa drama.' } ]; function normalizePayload(payload) { return { settings: { ...defaultData.settings, ...(payload?.settings ?? {}) }, stats: Array.isArray(payload?.stats) && payload.stats.length ? payload.stats : defaultData.stats, services: Array.isArray(payload?.services) && payload.services.length ? payload.services : defaultData.services, projects: Array.isArray(payload?.projects) && payload.projects.length ? payload.projects : defaultData.projects }; } function useReveal() { const ref = useRef(null); const [visible, setVisible] = useState(false); useEffect(() => { if (!ref.current) { return undefined; } const observer = new IntersectionObserver( (entries) => { if (entries.some((entry) => entry.isIntersecting)) { setVisible(true); observer.disconnect(); } }, { threshold: 0.18 } ); observer.observe(ref.current); return () => observer.disconnect(); }, []); return [ref, visible]; } function Reveal({ children }) { const [ref, visible] = useReveal(); return (
{settings.hero_description}
{loading ?{description}
{service.description}
{project.summary}
{step.description}
{settings.cta_description}