// Sonq'o Wasi — SPA app const { useState, useEffect, useMemo, useRef } = React; // ── Assets ──────────────────────────────────────────────────────── const EMBLEM = "media/emblem.png"; const SPACE = (n) => "media/space/p" + String(n).padStart(2, "0") + ".jpg"; // Curated atmospheric photos of the house — every slot is a UNIQUE photo (no repeats site-wide) const PHOTOS = { homeStrip: 11, homeBand: 25, events: [41, 46, 51], // home event posters houseOrigin: 43, houseGallery: [4, 73, 79], weddings: [0, 82], posts: [6, 13, 30, 76], // journal covers }; // Therapist portrait → cropped from each person's composite card, matched by Instagram handle const FACE_BY_HANDLE = { "@natashallerena": 0, "@somosnossacasa": 1, "@niceemariejourdan": 2, "@marianaguimaraes_alquimias": 3, "@sabrinaramosalquimia": 4, "@marinaalmeidamayan": 5, "@lucianaportellaterapeuta": 6, "@liviapaesbemestar": 7, "@ecodelica_art": 8, "@andreelkind": 10, "@alcirblondet": 11, "@fala.mohana": 12, "@alexandraflaviodoutoraufrj": 13, "@frpassarelli": 14, "@du.alecrim": 15, "@eu.fernandatelles": 16, "@ginecologianatural": 17, "@bebelclark": 18, "@caroljourdan.essencial": 19, }; const FACE = (h) => h in FACE_BY_HANDLE ? "media/faces/f" + String(FACE_BY_HANDLE[h]).padStart(2, "0") + ".jpg" : null; // Therapist filter categories + tags (by handle) const CATEGORIES = [ { key: "all", label: { pt: "Todos", es: "Todas", en: "All" } }, { key: "corpo", label: { pt: "Corpo & Movimento", es: "Cuerpo & Movimiento", en: "Body & Movement" } }, { key: "som", label: { pt: "Som & Voz", es: "Sonido & Voz", en: "Sound & Voice" } }, { key: "feminino", label: { pt: "Feminino", es: "Femenino", en: "Feminine" } }, { key: "alquimia", label: { pt: "Alquimia & Ervas", es: "Alquimia & Hierbas", en: "Alchemy & Herbs" } }, { key: "ritual", label: { pt: "Rituais & Medicinas", es: "Rituales & Medicinas", en: "Ritual & Medicine" } }, { key: "energia", label: { pt: "Energia & Oráculos", es: "Energía & Oráculos", en: "Energy & Oracles" } }, { key: "mente", label: { pt: "Mente & Espírito", es: "Mente & Espíritu", en: "Mind & Spirit" } }, { key: "casa", label: { pt: "Casa & Espaço", es: "Casa & Espacio", en: "Home & Space" } }, ]; const TAGS_BY_HANDLE = { "@somosnossacasa": ["casa"], "@natashallerena": ["som"], "@sabrinaramosalquimia": ["alquimia"], "@niceemariejourdan": ["energia", "mente"], "@marianaguimaraes_alquimias": ["alquimia"], "@marinaalmeidamayan": ["feminino", "ritual"], "@ecodelica_art": ["energia", "ritual"], "@lucianaportellaterapeuta": ["som", "feminino", "ritual"], "@liviapaesbemestar": ["corpo"], "@andreelkind": ["mente"], "@alexandraflaviodoutoraufrj": ["mente", "ritual"], "@alcirblondet": ["ritual", "corpo", "alquimia"], "@fala.mohana": ["corpo"], "@eu.fernandatelles": ["corpo", "feminino", "alquimia"], "@frpassarelli": ["energia"], "@du.alecrim": ["alquimia", "feminino", "energia"], "@caroljourdan.essencial": ["feminino", "corpo"], "@ginecologianatural": ["feminino"], "@bebelclark": ["feminino", "energia", "mente"], }; // ── Hooks ───────────────────────────────────────────────────────── function useHashRoute() { const [route, setRoute] = useState(() => (window.location.hash.replace("#/", "") || "home")); useEffect(() => { const handler = () => { const next = window.location.hash.replace("#/", "") || "home"; setRoute(next); window.scrollTo({ top: 0, behavior: "instant" }); }; window.addEventListener("hashchange", handler); return () => window.removeEventListener("hashchange", handler); }, []); return [route, (r) => { window.location.hash = "#/" + r; }]; } function useLang() { const [lang, setLang] = useState(() => localStorage.getItem("sonqo_lang") || "pt"); useEffect(() => { localStorage.setItem("sonqo_lang", lang); document.documentElement.lang = lang; }, [lang]); return [lang, setLang]; } // ── Atoms ───────────────────────────────────────────────────────── function Glyph({ size = 24 }) { return ( ); } function Arrow({ size = 14 }) { return ( ); } function WhatsAppIcon() { return ( ); } function InstagramIcon() { return ( ); } // Ornamental ring echoing the ouroboros of the identity mark function SerpentRing({ className }) { const ticks = Array.from({ length: 72 }, (_, i) => { const a = (i / 72) * Math.PI * 2; const r2 = i % 6 === 0 ? 80 : 85; return ( ); }); return ( ); } function Nav({ route, go, lang, setLang }) { const t = window.SONQO_I18N[lang]; const [open, setOpen] = useState(false); const items = [ ["home", t.nav.home], ["house", t.nav.house], ["manifesto", t.nav.manifesto], ["therapists", t.nav.therapists], ["events", t.nav.events], ["weddings", t.nav.weddings], ["join", t.nav.join], ["journal", t.nav.journal], ["contact", t.nav.contact], ["directions", t.nav.directions], ]; // Início lives on the emblem (click → home). Seja Associado stays in the mobile // menu + footer; the desktop bar carries a lean 3-left / 4-right split. const link = ([key, label]) => ( setOpen(false)}>{label} ); const left = [items[1], items[2], items[3], items[4]]; // A Casa · Manifesto · Terapeutas · Eventos const right = [items[5], items[7], items[8], items[9]]; // Casamentos · Diário · Contato · Como Chegar return ( ); } function PageHero({ crumb, scriptText, serifText, lede, lang }) { const t = window.SONQO_I18N[lang]; return (
Sonq'o Wasi/{crumb}

{scriptText} {serifText}

{lede &&

{lede}

}
); } // ── Pages ───────────────────────────────────────────────────────── function HomePage({ go, lang }) { const t = window.SONQO_I18N[lang]; const events = window.SONQO_EVENTS.slice(0, 3); return (
{t.home.meta1}

{t.home.script} {t.home.serif}

{t.home.hero_tagline}

{t.home.sub}

{t.home.meta2} {t.home.meta3}
Coração que se transforma em casa — símbolo de Sonq'o Wasi
01 / {t.home.pillars_eyebrow}

{t.home.pillars_title}

{t.home.pillars_lede}

i

{t.home.pillar1_t}

{t.home.pillar1_d}

{t.common.learn_more}
ii

{t.home.pillar2_t}

{t.home.pillar2_d}

{t.common.learn_more}
iii

{t.home.pillar3_t}

{t.home.pillar3_d}

{t.common.learn_more}
Altar à luz de velas em Sonq'o Wasi
02 / {t.home.house_eyebrow}

{t.home.house_title_a}
{t.home.house_title_script}

{t.home.house_p1}

{t.home.house_p2}

{t.home.house_cta}
03 / {t.home.events_eyebrow}

{t.home.events_title}

{t.home.events_lede}

{events.map((ev, i) => (
{ev.tag[lang]}
{ev.date.day} {ev.date.month[lang]} {ev.time}

{ev.title[lang]}

{ev.desc[lang]}

{ev.by} · {t.events.ig_link}
))}
{t.common.see_all}
Roda à luz de velas em Sonq'o Wasi
{t.home.script} {t.home.serif}

{t.home.band_tagline}

); } function HousePage({ lang }) { const t = window.SONQO_I18N[lang].house; const tc = window.SONQO_I18N[lang]; return (
Interior da casa à luz de velas
{t.origin_eyebrow}

{t.origin_title_a}
{t.origin_title_script}

{t.origin_body_1}

{t.origin_body_2}

{t.origin_body_3}

{t.accent_tagline}

{t.principles_eyebrow}

{t.principles_title}

{[ [t.p1_t, t.p1_d], [t.p2_t, t.p2_d], [t.p3_t, t.p3_d], [t.p4_t, t.p4_d] ].map(([title, body], i) => (
{["I","II","III","IV"][i]}

{title}

{body}

))}
{PHOTOS.houseGallery.map((n, i) => (
))}
{t.visit_eyebrow}

{t.visit_title}

{t.visit_lede}

{tc.common.get_in_touch}
); } function ManifestoPage({ lang }) { const t = window.SONQO_I18N[lang]; const m = window.SONQO_MANIFESTO[lang]; return (
{m.body.map((b, i) => { if (b.kind === "lead") return

{b.text}

; if (b.kind === "verse") return (
{b.lines.map((l, j) => {l})}
); if (b.kind === "closing") return (
{b.lines.map((l, j) => {l})}
); return

{b.text}

; })}

{lang === "pt" && "Caminhe conosco"} {lang === "es" && "Camina con nosotras"} {lang === "en" && "Walk with us"}

{t.nav.join}
); } function TherapistsPage({ lang }) { const t = window.SONQO_I18N[lang].therapists; const tc = window.SONQO_I18N[lang]; const list = window.SONQO_THERAPISTS; const [filter, setFilter] = useState("all"); // only show category chips that actually have someone const cats = CATEGORIES.filter(c => c.key === "all" || list.some(th => (TAGS_BY_HANDLE[th.handle] || []).includes(c.key))); const shown = list.filter(th => filter === "all" || (TAGS_BY_HANDLE[th.handle] || []).includes(filter)); const countLabel = { pt: shown.length + (shown.length === 1 ? " terapeuta" : " terapeutas"), es: shown.length + (shown.length === 1 ? " terapeuta" : " terapeutas"), en: shown.length + (shown.length === 1 ? " practitioner" : " practitioners"), }[lang]; return (
{cats.map(c => ( ))}

{countLabel}

{shown.map((th, i) => { const phoneDigits = th.phone.replace(/\D/g, ""); const igHandle = th.handle.replace("@", ""); const initials = th.name.split(" ").map(n => n[0]).slice(0,2).join(""); const photo = th.photo || FACE(th.handle); return ( ); })}
); } function EventsPage({ lang }) { const t = window.SONQO_I18N[lang].events; const tc = window.SONQO_I18N[lang]; const events = window.SONQO_EVENTS; const agenda = window.SONQO_AGENDA || []; const ig = (window.SONQO_IG || []).slice(0, 8); const igLabel = { pt: "Últimas do Instagram", es: "Lo último de Instagram", en: "Latest from Instagram" }[lang]; const agendaTitle = { pt: "Agenda 2026", es: "Agenda 2026", en: "2026 calendar" }[lang]; const agendaEyebrow = { pt: "Calendário do ano", es: "Calendario del año", en: "Year calendar" }[lang]; const agendaLede = { pt: "Os encontros fixos da casa ao longo de 2026. As datas mensais exatas são confirmadas a cada mês no Instagram.", es: "Los encuentros fijos de la casa a lo largo de 2026. Las fechas mensuales exactas se confirman cada mes en Instagram.", en: "The house's recurring gatherings through 2026. Exact monthly dates are confirmed each month on Instagram.", }[lang]; return (
{t.cal_eyebrow}

{t.cal_title}

{t.ig_handle_label}

{agendaEyebrow}

{agendaTitle}

{agendaLede}

{agenda.map((group, gi) => (

{group.cat[lang]}

{group.items.length}
{group.items.map((it, ii) => (
{it.w[lang]}
{it.t} {it.note && {it.note[lang]}}
))}
))}
{ig.length > 0 && (
Instagram

{igLabel}

{t.ig_handle_label}

)}
{tc.common.instagram}

@sonqowasi_

{lang === "pt" && "Os eventos são atualizados primeiro pelo Instagram. Siga para receber lembretes e abrir as inscrições."} {lang === "es" && "Los eventos se actualizan primero en Instagram. Síguenos para recibir recordatorios y abrir las inscripciones."} {lang === "en" && "Events are updated first on Instagram. Follow to get reminders and open bookings."}

{t.ig_cta}
); } function WeddingsPage({ lang }) { const t = window.SONQO_I18N[lang].weddings; const tc = window.SONQO_I18N[lang]; return (
{t.what_eyebrow}

{t.what_title}

{[[t.i1_t, t.i1_d],[t.i2_t, t.i2_d],[t.i3_t, t.i3_d],[t.i4_t, t.i4_d]].map(([title, desc], i) => (
{["✦","◯","♪","❀"][i]}

{title}

{desc}

))}
{t.band_tagline}

{t.cta_t}

{t.cta_d}

{tc.common.get_in_touch}
); } function JoinPage({ lang }) { const t = window.SONQO_I18N[lang].join; return (
i
{t.track1_label}

{t.track1_t}

{t.track1_d}

  • {t.track1_b1}
  • {t.track1_b2}
  • {t.track1_b3}
  • {t.track1_b4}
{t.track1_cta}
ii
{t.track2_label}

{t.track2_t}

{t.track2_d}

  • {t.track2_b1}
  • {t.track2_b2}
  • {t.track2_b3}
  • {t.track2_b4}
{t.track2_cta}
); } function JournalPage({ lang }) { const t = window.SONQO_I18N[lang].journal; const posts = window.SONQO_POSTS; return (
); } function ContactPage({ lang }) { const t = window.SONQO_I18N[lang].contact; const [sent, setSent] = useState(false); return (
{t.direct_eyebrow}

{t.direct_title}

{t.whatsapp_label}
{t.ig_label}
{t.address_label}
{t.address_value}
{t.hours_label}
{t.hours_value}
{t.form_eyebrow}

{t.form_title}

{sent ? (
{t.sent}
) : (
{ e.preventDefault(); setSent(true); }}>