/* ===== Growing Now — core components (nav, hero, squad, services) ===== */
(function () {
const { useState, useEffect, useRef } = React;
const Icon = window.Icon;
// reveal-on-scroll wrapper
function Reveal({ children, delay = 0, as = 'div', className = '', style = {} }) {
const ref = useRef(null);
useEffect(() => {
const el = ref.current;
const io = new IntersectionObserver((es) => {
es.forEach(e => { if (e.isIntersecting) { setTimeout(() => el.classList.add('in'), delay); io.unobserve(el); } });
}, { threshold: 0.15 });
io.observe(el);
return () => io.disconnect();
}, []);
return React.createElement(as, { ref, className: 'reveal ' + className, style }, children);
}
window.Reveal = Reveal;
function SectionHead({ eyebrow, title, sub, color = 'var(--blue)', align = 'center' }) {
return (
{eyebrow}
{title}
{sub && {sub}
}
);
}
window.SectionHead = SectionHead;
/* ---------- NAV ---------- */
function Nav({ L, lang, setLang }) {
const [scrolled, setScrolled] = useState(false);
const [open, setOpen] = useState(false);
useEffect(() => {
const f = () => setScrolled(window.scrollY > 30);
window.addEventListener('scroll', f); f(); return () => window.removeEventListener('scroll', f);
}, []);
const links = [['agents', L.nav_agents], ['services', L.nav_services], ['process', L.nav_process], ['about', L.nav_about], ['contact', L.nav_contact]];
const go = (id) => { setOpen(false); const el = document.getElementById(id); if (el) el.scrollIntoView({ behavior: 'smooth' }); };
return (
);
}
const navLink = { background: 'none', border: 'none', cursor: 'pointer', fontFamily: 'var(--font-display)', fontWeight: 500, fontSize: '.95rem', color: 'var(--ink)', padding: '8px 14px', borderRadius: 999, transition: 'background .2s' };
function LangToggle({ lang, setLang }) {
return (
);
}
window.Nav = Nav;
/* ---------- HERO ---------- */
function Hero({ L, lang, onChat, onAgent }) {
const agents = window.GN.agents;
const go = (id) => { const el = document.getElementById(id); if (el) el.scrollIntoView({ behavior: 'smooth' }); };
// floating cluster positions
const pos = [
{ t: '2%', l: '6%', s: 116, d: 0 }, { t: '0%', l: '54%', s: 96, d: .6 },
{ t: '34%', l: '78%', s: 134, d: 1.2 }, { t: '60%', l: '2%', s: 104, d: .9 },
{ t: '70%', l: '42%', s: 150, d: .3 }, { t: '40%', l: '30%', s: 88, d: 1.5 },
];
return (
{L.hero_eyebrow}
{L.hero_title_a} {L.hero_title_b}, {L.hero_title_c}
{L.hero_sub}
{agents.slice(0, 6).map((a, i) => (
))}
{L.hero_scroll}
{agents.map((a, i) => {
const p = pos[i];
return (
);
})}
);
}
window.Hero = Hero;
/* ---------- AGENT CARD + SQUAD ---------- */
function AgentCard({ a, lang, onOpen, delay, cardStyle = 'retrato' }) {
const more = window.I18N.STR[lang].card_more;
const hov = e => e.currentTarget.style.boxShadow = `0 28px 60px -22px ${a.accent}99`;
const out = e => e.currentTarget.style.boxShadow = '';
if (cardStyle === 'poster') {
return (
onOpen(a)} onMouseEnter={hov} onMouseLeave={out}>
{a.role[lang]}
{a.name}
{more}
);
}
if (cardStyle === 'compacto') {
return (
onOpen(a)} onMouseEnter={hov} onMouseLeave={out}>
{a.name}
{a.role[lang]}
{a.tagline[lang]}
);
}
// default: retrato
return (
onOpen(a)} onMouseEnter={hov} onMouseLeave={out}>
{a.role[lang]}
{a.name}
{a.tagline[lang]}
“{a.quote[lang]}”
{more}
);
}
function Squad({ L, lang, onOpen, cardStyle }) {
const cols = cardStyle === 'compacto' ? 'repeat(2,1fr)' : 'repeat(3,1fr)';
return (
{window.GN.agents.map((a, i) =>
)}
);
}
window.Squad = Squad;
/* ---------- AGENT MODAL ---------- */
function AgentModal({ a, lang, onClose, onChat, onAgentChat }) {
const L = window.I18N.STR[lang];
useEffect(() => {
document.body.classList.add('no-scroll');
const k = (e) => e.key === 'Escape' && onClose();
window.addEventListener('keydown', k);
return () => { document.body.classList.remove('no-scroll'); window.removeEventListener('keydown', k); };
}, []);
if (!a) return null;
return (
e.stopPropagation()}
style={{ maxWidth: 940, width: '100%', maxHeight: '90vh', overflowY: 'auto', borderRadius: 30, padding: 0, background: `linear-gradient(160deg,${a.tint},#fff 60%)` }}>
{a.role[lang]} · {a.animal[lang]}
{a.name}
{a.tagline[lang]}
“{a.quote[lang]}”
{L.helps_title}
{a.helps.map((h, i) => (
{h[lang]}
))}
{a.tags[lang].map(t => {t})}
);
}
window.AgentModal = AgentModal;
/* ---------- SERVICES ---------- */
function Services({ L, lang, onOpen }) {
const byId = window.GN.byId;
return (
{window.GN.services.map((s, i) => {
const a = byId[s.agent];
return (
onOpen(a)}
onMouseEnter={e => { e.currentTarget.style.transform = 'translateY(-8px)'; }}
onMouseLeave={e => { e.currentTarget.style.transform = ''; }}>
{s.t[lang]}
{s.d[lang]}
);
})}
);
}
window.Services = Services;
})();