// sections.jsx — Deepstrat landing sections (monochromatic + brand highlights) const { useState: useStateS, useEffect: useEffectS, useRef: useRefS } = React; // ─────────── Icon physics for the BrandSpinBand background ─────────── // Animates the Odoo module icons floating behind the lockup with Brownian // drift, mouse-cursor repulsion, a spring force pulling them back to their // base position, and friction. Runs as a single global rAF loop — NOT tied // to React's effect lifecycle, so a hydration error elsewhere (e.g. inside // Spotlight) can't cancel it. Idempotent: a flag prevents double-starts. function installIconPhysics() { if (typeof window === 'undefined' || window.__bsbIconsBooted) return; const PUSH_RADIUS = 130; // smaller halo const PUSH_STRENGTH = 900; // gentler shove (~38% of previous) const DRIFT_STRENGTH = 140; const RETURN_STRENGTH = 2.2; const DAMPING_PER_S = 0.10; let mouseX = -1e6, mouseY = -1e6; window.addEventListener('mousemove', (e) => { mouseX = e.clientX; mouseY = e.clientY; }, { passive: true }); document.addEventListener('mouseleave', () => { mouseX = -1e6; mouseY = -1e6; }); let imgs = []; let states = []; let last = performance.now(); const findIcons = () => { // Lazy: pick up the icons whenever they exist in the DOM. This lets the // loop survive React hydration churn — even if BrandSpinBand unmounts // and remounts, the SSR'd elements are stable in the DOM. const layer = document.querySelector('[data-bsb-icons]'); if (!layer) { imgs = []; return; } const next = Array.from(layer.querySelectorAll('img')); if (next.length !== imgs.length) { imgs = next; states = imgs.map(() => ({ x: 0, y: 0, vx: 0, vy: 0 })); } else { imgs = next; } }; const tick = () => { findIcons(); const now = performance.now(); const dt = Math.min(0.05, (now - last) / 1000); last = now; const dampFactor = Math.pow(DAMPING_PER_S, dt); for (let i = 0; i < imgs.length; i++) { const img = imgs[i]; const s = states[i]; const rect = img.getBoundingClientRect(); if (!rect.width) continue; const cx = rect.left + rect.width / 2; const cy = rect.top + rect.height / 2; const dx = cx - mouseX; const dy = cy - mouseY; const d2 = dx * dx + dy * dy; if (d2 < PUSH_RADIUS * PUSH_RADIUS && d2 > 1) { const d = Math.sqrt(d2); const f = (1 - d / PUSH_RADIUS) * PUSH_STRENGTH; s.vx += (dx / d) * f * dt; s.vy += (dy / d) * f * dt; } s.vx += (Math.random() - 0.5) * DRIFT_STRENGTH * dt; s.vy += (Math.random() - 0.5) * DRIFT_STRENGTH * dt; s.vx -= s.x * RETURN_STRENGTH * dt; s.vy -= s.y * RETURN_STRENGTH * dt; s.vx *= dampFactor; s.vy *= dampFactor; s.x += s.vx * dt; s.y += s.vy * dt; img.style.transform = 'translate(calc(-50% + ' + s.x.toFixed(2) + 'px), calc(-50% + ' + s.y.toFixed(2) + 'px))'; } requestAnimationFrame(tick); }; requestAnimationFrame(tick); window.__bsbIconsBooted = true; } // ───────────────────────── NAV ───────────────────────── function Nav() { const [scrolled, setScrolled] = useStateS(false); const [open, setOpen] = useStateS(false); useEffectS(() => { const onScroll = () => setScrolled(window.scrollY > 20); window.addEventListener('scroll', onScroll, { passive: true }); onScroll(); return () => window.removeEventListener('scroll', onScroll); }, []); useEffectS(() => { document.body.style.overflow = open ? 'hidden' : ''; return () => {document.body.style.overflow = '';}; }, [open]); const sections = [ { href: '#odoo', label: 'Odoo' }, { href: '#ia', label: 'IA' }, { href: '#modulos', label: 'Módulos' }, { href: '#implementacao', label: 'Implementação' }, { href: '#comparativo', label: 'Comparativo' }, { href: '#blog', label: 'Blog' }]; return (
setOpen(false)}>
Agendar demo
{/* Mobile drawer */}
{sections.map((s) => setOpen(false)} className="py-3 text-[16px] text-ink-900 font-medium border-b border-ink-100 last:border-b-0 flex items-center justify-between group"> {s.label} )} setOpen(false)} className="mt-4 justify-center"> Agendar demonstração
); } // ───────────────────────── HERO ───────────────────────── function Hero({ headline = 'O primeiro ERP que você opera conversando', showPartnerBadge = true, highlight = 'conversando' }) { // Apply highlight to a single word/phrase in the headline if present. function renderHeadline(text) { if (!highlight) return text; const idx = text.toLowerCase().indexOf(highlight.toLowerCase()); if (idx < 0) return text; return ( <> {text.slice(0, idx)} {text.slice(idx, idx + highlight.length)} {text.slice(idx + highlight.length)} ); } return (
{/* Floating Odoo apps backdrop */}
{/* Palantir-style subtle gridline */}
{/* left column */}
{showPartnerBadge &&
// Parceira Oficial Odoo · Brasil
}

{renderHeadline(headline)}

Reconstruímos a metodologia de implantação do Odoo em torno de IA. Sua equipe controla pedidos, financeiro, RH e estoque pelo ChatGPT, Claude ou Gemini, sem precisar aprender uma tela nova.

Agendar demonstração
{/* right column — phone mock */}
); } // Official Odoo Partner stamp logo — used in Modules section and Footer. // The PNG lives at assets/odoo_partner_logo_stamp.png (horizontal lockup). function OdooPartnerStamp({ height = 44 }) { return ( Odoo Ready Partner, parceira oficial); } function HeroMock() { return (
); } // Three conversation scenarios — cycles between Vendas/CRM, Financeiro, RH. // Plain Portuguese, no API jargon. const PHONE_SCENARIOS = [ { tag: 'Vendas', bubbles: [ { who: 'me', text: 'Olá, pode lançar mais um pedido para o meu cliente Lumen? Ele quer 12 unidades da peça com código A-204. Pode parcelar em 30/60/90.' }, { who: 'ai', text: 'Claro! ✅ Criei o pedido SO-1042 para a Lumen, R$ 28.440 em 3x, ainda como rascunho aguardando sua confirmação. Já mando a cobrança por e-mail?' }, { who: 'me', text: 'Manda sim' }, { who: 'ai', text: 'Cobrança enviada 📨 Aproveitei pra olhar a margem dessa venda: 31%, acima da média dos últimos 90 dias.' }, { who: 'ai', chart: 'sales-margin' }] }, { tag: 'Financeiro', bubbles: [ { who: 'me', text: 'Como foi nosso faturamento em outubro? Queria comparar com setembro.' }, { who: 'ai', text: 'Em outubro fechamos R$ 1.247.300 📊 cerca de 18% acima de setembro. Maior cliente do mês foi a Lumen, com R$ 184k em compras.' }, { who: 'me', text: 'E tem alguém com pagamento atrasado há mais de 30 dias?' }, { who: 'ai', text: 'Sim, 3 clientes ⚠️ totalizando R$ 47.200 em aberto. Quer que eu reenvie os boletos por e-mail e aplique juros de mora?' }, { who: 'ai', chart: 'finance-aging' }] }, { tag: 'RH', bubbles: [ { who: 'me', text: 'Pode marcar as férias do Bruno do dia 15 a 30 de janeiro, por favor?' }, { who: 'ai', text: 'Marcado! 🗓️ O Bruno tem 22 dias acumulados e vai usar 15 nessas férias. Já avisei o gestor dele por e-mail.' }, { who: 'me', text: 'Quantas pessoas entram esse mês?' }, { who: 'ai', text: 'Duas pessoas começam em novembro 👥 Marina (Comercial) no dia 06 e Pedro (TI) no dia 18. Quer que eu prepare o onboarding delas?' }, { who: 'ai', chart: 'hr-hires' }] }]; // Small inline charts that the AI "sends" as the last message in each scenario. // Designed to fit in ~200px width inside the phone bubble. function ChatChart({ kind }) { if (kind === 'sales-margin') { const bars = [22, 28, 24, 30, 26, 31]; const max = 36; const avg = 26; return (
Margem · últimas 6 vendas
méd {avg}%
{/* Average reference line */}
{bars.map((v, i) => { const isLatest = i === bars.length - 1; return (
{v}%
); })}
#1037 #1038 #1039 #1040 #1041 #1042
); } if (kind === 'finance-aging') { const clients = [ { n: 'Acme', v: 18500 }, { n: 'Vértice', v: 16200 }, { n: 'Nexo', v: 12500 }]; const max = 20000; return (
Inadimplência {'>'} 30 dias
{clients.map((c, i) =>
{c.n}
R${(c.v / 1000).toFixed(1)}k
)}
); } if (kind === 'hr-hires') { return (
Contratações · Novembro
2 novas
{/* Timeline */}
{[1, 8, 15, 22, 29].map((d) =>
)}
01 15 30
{/* Hire cards */}
06/11 Marina
Comercial
18/11 Pedro
TI
); } return null; } function PhoneChat({ className = '', style }) { const [idx, setIdx] = useStateS(0); const [visible, setVisible] = useStateS(true); const bubblesRef = React.useRef(null); const SCENARIO_MS = 13000; // Auto-advance — each scenario stays ~13s so users can actually read it. useEffectS(() => { const t1 = setTimeout(() => setVisible(false), SCENARIO_MS - 600); const t2 = setTimeout(() => { setIdx((i) => (i + 1) % PHONE_SCENARIOS.length); setVisible(true); }, SCENARIO_MS - 300); return () => {clearTimeout(t1);clearTimeout(t2);}; }, [idx]); // Keep the latest bubble (incl. the chart) in view as they animate in. useEffectS(() => { const el = bubblesRef.current; if (!el) return; const bubbleCount = PHONE_SCENARIOS[idx].bubbles.length; const lastBubbleTime = 0.15 + (bubbleCount - 1) * 0.45; const scrollers = []; for (let i = 0; i < bubbleCount; i++) { const t = (0.15 + i * 0.45 + 0.4) * 1000; scrollers.push(setTimeout(() => { el.scrollTo({ top: el.scrollHeight, behavior: 'smooth' }); }, t)); } return () => scrollers.forEach(clearTimeout); }, [idx]); const scenario = PHONE_SCENARIOS[idx]; return (
{/* Status bar */}
9:41
{/* App header — with scenario tag */}
ChatGPT
conversando com Odoo · {scenario.tag}
{/* Scenario tabs — clearly clickable */}
{PHONE_SCENARIOS.map((s, i) => )} toque
{/* Progress bar — fills over the scenario duration */}
{/* Bubbles */}
{scenario.bubbles.map((b, i) =>
{b.chart ? : b.text}
)}
{/* Composer */}
Pergunte qualquer coisa…
{/* Home indicator */}
); } // ───────────────────────── PAIN ───────────────────────── function Pain() { const items = [ { tag: 'planilhas', t: 'Planilhas que não escalam', d: 'Você cresceu mais rápido que o Excel. Reconciliação manual, retrabalho, números que ninguém confia.', icon: }, { tag: 'erp simples', t: 'ERPs simples que travam no crescimento', d: 'Sistemas baratos resolvem até certo ponto. Depois disso, você está integrando vários softwares na mão, com retrabalho e dado divergente em cada um.', icon: }, { tag: 'enterprise pesado', t: 'Plataformas enterprise pesadas', d: 'Cotação em centenas de milhares, projeto que se arrasta por mais de um ano, customização que depende de consultor especializado pra qualquer coisa.', icon: }]; return (
{/* Background video — local grok-style clips that cycle in a loop. Stays muted, plays inline, behind a dark overlay so text is legible. */} {/* Coordinate labels on section edges — matches Why/Spotlight pattern */}
{`> diagnose(pme.br) # 3 estágios · 1 travamento`}
{`stage=stuck · layer=middle`}

Você sabe onde está travado

A dor que resolvemos
{items.map((it, i) =>
{it.icon}

{it.t}

{it.d}

)}
); } // Background video crossfader — renders all clips stacked, looping // independently. Only one is visible at a time; switching crossfades via // opacity transition so there's no black frame between clips. function PainBackgroundVideo() { const clips = ['assets/grok-video-1.mp4', 'assets/grok-video-2.mp4', 'assets/grok-video-4.mp4']; const [idx, setIdx] = useStateS(0); const SWITCH_MS = 5000; useEffectS(() => { const t = setInterval(() => setIdx((i) => (i + 1) % clips.length), SWITCH_MS); return () => clearInterval(t); }, []); return ( <> {clips.map((src, i) => ( ))} ); } // ───────────────────────── MODULES ───────────────────────── function OdooModuleIcon({ id, name }) { return (
{name}
); } function Modules() { const mods = [ { n: 'Vendas', odoo: 'sale' }, { n: 'CRM', odoo: 'crm' }, { n: 'Compras', odoo: 'purchase' }, { n: 'Estoque', odoo: 'stock' }, { n: 'Contábil', odoo: 'account' }, { n: 'RH', odoo: 'hr' }, { n: 'Manufatura', odoo: 'mrp' }, { n: 'Projetos', odoo: 'project' }, { n: 'E-commerce', odoo: 'website_sale' }, { n: 'Marketing', odoo: 'mass_mailing' }, { n: 'Helpdesk', odoo: 'helpdesk' }, { n: 'Documentos', odoo: 'documents' }]; return (
{/* LEFT: bold typographic statement + body + CTAs */}
O que o Odoo entrega

O seu negócio inteiro
em uma plataforma

Cada sistema separado é mais uma mensalidade, mais um login, mais uma integração que pode quebrar. Com o Odoo, sua operação inteira roda em uma plataforma só: vendas, finanças, estoque, RH, projetos, e-commerce.

Agendar demonstração
{/* RIGHT: dramatic dark feature card with overlay seal */}
{/* Module tile grid */}
{mods.map((m, i) =>
{m.n}
)}
); } // Photo feature card — full-bleed photo of people working with computers // (Odoo / ERP in action). Subtle dark overlay at the bottom carries a small // brand caption so the card still feels intentional, not stock. function ModulesFeatureCard() { // Real photo loaded from Unsplash CDN. Replace the URL anytime with your own // hosted photo (same aspect ratio works best). const photoUrl = 'https://images.unsplash.com/photo-1573164713988-8665fc963095?auto=format&fit=crop&w=1200&q=80'; return (
{/* Photo */} Equipe trabalhando com o ERP Odoo {/* Gradient overlay — darkens the bottom for caption legibility */}
{/* Corner brackets — technical frame, consistent with rest of design */} {/* Bottom caption */}
Uma fonte da verdade
Sua operação toda no mesmo lugar, visível pra quem precisa, e em tempo real.
); } // ───────────────────────── SPOTLIGHT (rotating module carousel) ───────────────────────── // Auto-rotating spotlight: each slide highlights a different ERP module with // concrete features. Arrows + progress bar + dot indicators make navigation obvious. const SPOTLIGHT_SLIDES = [ { id: 'vendas', odooIds: [{ id: 'sale', name: 'Sales' }, { id: 'crm', name: 'CRM' }], iconLabel: 'Vendas', chip: 'CRM e Vendas', headline: 'Do primeiro contato', headlineDim: 'ao pedido fechado', cols: [ { label: 'Pipeline visual', body: 'acompanhe cada oportunidade por etapa, com previsão de receita e probabilidade de fechamento em tempo real' }, { label: 'Propostas e cotações', body: 'gere orçamentos profissionais em minutos, com aprovação eletrônica e conversão automática em pedido de venda' }, { label: 'Histórico unificado', body: 'e-mails, ligações, reuniões e documentos centralizados na ficha. Nada se perde quando o vendedor sai' }], illust: 'pipeline' }, { id: 'financeiro', odooIds: [{ id: 'account', name: 'Accounting' }], iconLabel: 'Financeiro', chip: 'Financeiro e Contabilidade', headline: 'Gestão financeira integrada,', headlineDim: 'com visibilidade em tempo real.', cols: [ { label: 'Contas a pagar e receber', body: 'boletos, PIX, conciliação bancária e gestão de inadimplência sem planilhas paralelas' }, { label: 'Conciliação automática', body: 'importação OFX e sugestão inteligente de match com lançamentos. Fechamento em horas, não em dias' }, { label: 'Relatórios gerenciais', body: 'DRE, fluxo de caixa e balanço gerados a partir dos mesmos lançamentos operacionais' }], illust: 'cash' }, { id: 'estoque', odooIds: [{ id: 'stock', name: 'Inventory' }, { id: 'purchase', name: 'Purchase' }], iconLabel: 'Inventário', chip: 'Estoque e Logística', headline: 'Saber o que tem,', headlineDim: 'onde tem e para onde vai.', cols: [ { label: 'Múltiplos armazéns', body: 'controle inventário em filiais, lojas e centros de distribuição com rastreabilidade ponta a ponta' }, { label: 'Lotes e validades', body: 'rastreie cada item da entrada à saída. Essencial para alimentos, farma, eletrônicos e industriais' }, { label: 'Inventário em tempo real', body: 'saldos atualizados a cada movimentação, com aplicativo de coletor de dados integrado' }], illust: 'warehouse' }, { id: 'contabil', odooIds: [{ id: 'account', name: 'Accounting' }, { id: 'l10n_br', name: 'Brazil' }], iconLabel: 'Fiscal', chip: 'Faturamento Fiscal Brasil', headline: 'Conformidade fiscal', headlineDim: 'sem dor de cabeça.', cols: [ { label: 'Cálculo automático de impostos', body: 'ICMS, IPI, PIS, COFINS e ISS calculados em tempo real conforme NCM, CFOP e regime tributário da operação' }, { label: 'Emissão de NF-e e NFS-e', body: 'notas fiscais de mercadorias e serviços emitidas direto do sistema, com transmissão e validação junto à SEFAZ e prefeituras' }, { label: 'Regras fiscais por operação', body: 'o sistema reconhece o tipo de operação e aplica a tributação certa automaticamente, evitando erros que geram multa' }], illust: 'docs' }, { id: 'manufatura', odooIds: [{ id: 'mrp', name: 'Manufacturing' }], iconLabel: 'Manufatura', chip: 'Fabricação', headline: 'Da ordem de produção', headlineDim: 'ao produto pronto.', cols: [ { label: 'Listas técnicas e roteiros', body: 'defina insumos, etapas e centros de trabalho. O sistema calcula custo e tempo de produção' }, { label: 'Ordens de produção', body: 'apontamento de chão de fábrica em tablets, com status, paradas e produtividade em tempo real' }, { label: 'MRP integrado', body: 'planejamento de necessidades cruza vendas, estoque e compras para nunca faltar matéria-prima' }], illust: 'factory' }, { id: 'rh', odooIds: [{ id: 'hr', name: 'Employees' }, { id: 'hr_recruitment', name: 'Recruitment' }], iconLabel: 'RH', chip: 'Recursos Humanos', headline: 'Pessoas no centro', headlineDim: 'da operação.', cols: [ { label: 'Cadastro e ciclo de vida', body: 'admissão, férias, ausências e desligamento documentados, com fluxos de aprovação configuráveis' }, { label: 'Recrutamento e seleção', body: 'vagas publicadas no site, candidatos rastreados no pipeline e entrevistas agendadas direto no sistema' }, { label: 'Avaliações e desenvolvimento', body: 'feedbacks 360°, metas e planos de carreira ligados aos resultados da operação' }], illust: 'people' }, { id: 'compras', odooIds: [{ id: 'purchase', name: 'Purchase' }], iconLabel: 'Compras', chip: 'Compras e Fornecedores', headline: 'Comprar melhor,', headlineDim: 'com previsibilidade.', cols: [ { label: 'Requisições e cotações', body: 'solicite preços a múltiplos fornecedores e compare propostas lado a lado antes de aprovar' }, { label: 'Reposição automática', body: 'regras de estoque mínimo disparam pedidos de compra sozinhas, evitando ruptura e excesso de capital parado' }, { label: 'Avaliação de fornecedores', body: 'histórico de prazos, preços e qualidade ajuda a decidir com quem vale a pena seguir comprando' }], illust: 'purchase' }, { id: 'projetos', odooIds: [{ id: 'project', name: 'Project' }, { id: 'hr_timesheet', name: 'Timesheets' }], iconLabel: 'Projetos', chip: 'Projetos e Serviços', headline: 'Entregar no prazo,', headlineDim: 'no escopo e no orçamento.', cols: [ { label: 'Tarefas e Kanban', body: 'organize entregas por sprint, cliente ou equipe, com responsáveis, prazos e dependências claros' }, { label: 'Apontamento de horas', body: 'time-sheet integrado ao faturamento: horas trabalhadas viram fatura sem retrabalho' }, { label: 'Rentabilidade por projeto', body: 'custos, horas e receitas consolidados em um único painel. Você sabe quais clientes dão lucro' }], illust: 'projects' }, { id: 'marketing', odooIds: [{ id: 'website', name: 'Website' }, { id: 'mass_mailing', name: 'Marketing' }], iconLabel: 'Marketing', chip: 'Marketing, Site e E-commerce', headline: 'Crescer', headlineDim: 'com a casa em ordem.', cols: [ { label: 'Site e loja virtual', body: 'construa páginas e produtos com drag-and-drop, totalmente integrados ao estoque e ao CRM' }, { label: 'Automação de marketing', body: 'e-mail, SMS e WhatsApp disparados por jornadas baseadas no comportamento do cliente' }, { label: 'SEO e analytics nativos', body: 'métricas de tráfego, conversão e ROI por campanha em painéis prontos para uso' }], illust: 'marketing' }, { id: 'posvenda', odooIds: [{ id: 'helpdesk', name: 'Helpdesk' }, { id: 'sale_subscription', name: 'Subscriptions' }], iconLabel: 'Help Desk', chip: 'Pós-venda e Atendimento', headline: 'Excelência no atendimento', headlineDim: 'com pós-venda profissionalizado.', cols: [ { label: 'Helpdesk e SLA', body: 'tickets organizados por equipe, prioridade e prazo, com base de conhecimento integrada' }, { label: 'Assinaturas e recorrência', body: 'cobrança automática, gestão de contratos e renovações para modelos SaaS e de serviço continuado' }, { label: 'Pesquisas de satisfação', body: 'NPS e CSAT aplicados em pontos-chave da jornada, com dashboards de evolução' }], illust: 'helpdesk' }]; function Spotlight() { const [idx, setIdx] = useStateS(0); const [prev, setPrev] = useStateS(0); const [dir, setDir] = useStateS(1); // 1 = forward, -1 = back const [paused, setPaused] = useStateS(false); const [userInteracted, setUserInteracted] = useStateS(false); const [inView, setInView] = useStateS(false); const sectionRef = useRefS(null); const ROTATE_MS = 4500; // Helper that wraps setIdx with direction tracking. // Pass fromUser=true on any click handler to permanently stop the auto rotation. const goTo = (next, fromUser = false) => { if (fromUser) setUserInteracted(true); setIdx((cur) => { const n = (next % SPOTLIGHT_SLIDES.length + SPOTLIGHT_SLIDES.length) % SPOTLIGHT_SLIDES.length; setPrev(cur); setDir(n > cur || cur === SPOTLIGHT_SLIDES.length - 1 && n === 0 ? 1 : -1); return n; }); }; // Start rotating once the section enters the viewport — IntersectionObserver // is the primary trigger, with a fallback timer so the carousel still starts // in headless / non-IO environments. useEffectS(() => { if (!sectionRef.current) return; let stopped = false; const io = new IntersectionObserver( (entries) => { entries.forEach((e) => { if (e.isIntersecting && !stopped) { stopped = true; setInView(true); io.disconnect(); } }); }, { threshold: 0.25 } ); io.observe(sectionRef.current); // Fallback: kick off after 2s if IO hasn't triggered (some headless envs // never fire IO; in the real browser this is a no-op because IO wins). const fallback = setTimeout(() => { if (!stopped) { stopped = true; setInView(true); io.disconnect(); } }, 2000); return () => { io.disconnect(); clearTimeout(fallback); }; }, []); useEffectS(() => { if (paused || userInteracted || !inView) return; const t = setInterval(() => goTo(idx + 1), ROTATE_MS); return () => clearInterval(t); }, [paused, userInteracted, inView, idx]); const cur = SPOTLIGHT_SLIDES[idx]; return (
{/* Section header — concise */}
Os módulos em ação

Cada módulo, na prática

setPaused(true)} onMouseLeave={() => setPaused(false)}> {/* Slide progress bar — accent color, more visible */}
{/* Inline keyframes for the progress bar AND slide transitions */} {/* Top row: label card + wireframe illustration */}
0 ? 'slIdInRight' : 'slIdInLeft' }}> {/* Label card — animated re-mount per slide */}
{/* Subtle accent corner */}
{cur.chip}

{cur.headline}
{cur.headlineDim}

{/* Wireframe illustration */}
{/* Unified nav row: prev arrow + icons + next arrow + counter */}
{SPOTLIGHT_SLIDES.map((s, i) => { const primary = s.odooIds[0]; const active = i === idx; return ( ); })}
{/* Counter + ring + status — single thin line below nav */}
{String(idx + 1).padStart(2, '0')} / {String(SPOTLIGHT_SLIDES.length).padStart(2, '0')} {!inView ? 'aguardando' : userInteracted ? 'manual' : paused ? 'pausado' : 'auto'}
{/* Thin horizontal rule — hidden on mobile to save space */}
{/* Three info columns — stagger in from the bottom on slide change */}
{cur.cols.map((c, i) =>
→ {c.label}
{c.body}
)}
); } // Module-specific wireframe illustrations. Pure line drawings. function SpotlightIllustration({ kind }) { const stroke = "rgba(255,255,255,.85)"; const wrap = (children) =>
; if (kind === 'pipeline') { // Kanban — 3 colunas sem moldura externa (mais limpo, sem sobreposição) return wrap( {/* 3 columns laid out horizontally */} {[0, 1, 2].map((c) => { const x = 240 + c * 150; return ( {/* column header underline */} {['LEAD', 'QUALIFICADO', 'FECHADO'][c]} {/* card count badge */} {3 - c} {/* cards */} {Array.from({ length: 3 - c }, (_, r) => {/* tiny status tag */} )} ); })} {/* Labels */} Pipeline visual Cards drag-and-drop Automação por etapa ); } if (kind === 'warehouse') { // Warehouse shelves with boxes return wrap( {/* Shelves */} {[0, 1, 2].map((r) => {/* Boxes */} {[0, 1, 2, 3, 4].map((b) => )} )} {/* Floor */} Depósito A Depósito B Em trânsito ); } if (kind === 'docs') { // Stack of fiscal documents + calculator return wrap( {/* Doc stack */} {[0, 1, 2].map((d) => NFe )} {/* Calculator */} {[0, 1, 2].map((r) => [0, 1, 2].map((c) => ))} NFe / NFSe Conciliação DRE em tempo real ); } if (kind === 'factory') { // Production line: BOM tree + assembly conveyor return wrap( {/* BOM tree top */} Produto {[60, 160, 260].map((x, i) => Comp {i + 1} )} {/* Conveyor */} {[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map((i) => )} {[0, 1, 2, 3].map((i) => )} BOM multinível Linha de produção Rastreabilidade ); } if (kind === 'cash') { // Cash flow: bar chart + bills + line trend return wrap( {/* Trend chart container */} {/* gridlines */} {[0, 1, 2, 3].map((i) => )} {/* bars */} {[110, 80, 130, 95, 145, 70, 160, 100, 175, 90, 185].map((h, i) => )} {/* trend line */} Fluxo de caixa · 11 meses {/* Bills stack */} {[0, 1, 2].map((b) => R$ )} {/* Labels with leader lines */} Previsto x realizado Boletos · pix · ted Conciliação bancária ); } if (kind === 'people') { // People grid (RH directory) return wrap( {[0, 1, 2].map((r) => [0, 1, 2, 3].map((c) => { const x = c * 92; const y = r * 92; return ( {/* head */} {/* body */} {/* name line */} ); }))} Colaboradores Departamentos Folha + ponto ); } if (kind === 'purchase') { // Supplier RFQ comparison → selected card → generated purchase order return wrap( {/* 3 supplier cards */} {[ { price: '1.240', label: 'Forn. A' }, { price: '980', label: 'Forn. B' }, { price: '1.115', label: 'Forn. C' } ].map((s, i) => {/* logo placeholder */} {s.label} {/* price */} R$ {s.price} {/* detail rows */} {/* selected check (only forn B) */} {i === 1 && } )} {/* Down arrow → PO */} {/* Generated PO bar */} Pedido de compra · #PO-0421 {/* Labels on the left */} Cotações em paralelo Melhor proposta Pedido gerado ); } if (kind === 'projects') { // Gantt timeline + tasks + hours timer return wrap( {/* Gantt panel */} {/* week dividers */} {[0, 1, 2, 3, 4, 5, 6].map((i) => )} {/* week labels */} {[1, 2, 3, 4, 5, 6, 7].map((w, i) => W{w} )} {/* task labels on the inside-left */} {['Descoberta', 'Config', 'Migração', 'Testes', 'Go-live'].map((t, i) => {t} )} {/* task bars */} {/* today marker */} today {/* Hours timer card */} HORAS · HOJE 04:42 {/* running dot */} rodando {/* Labels */} Cronograma do projeto Tarefas por sprint Apontamento de horas ); } if (kind === 'marketing') { // Website mockup + email funnel + analytics bars return wrap( {/* Browser/site mockup */} {/* browser chrome */} {/* hero image + text */} {/* product grid */} {[0, 1, 2].map((i) => )} {/* Email sequence */} {[0, 1, 2].map((i) => )} {[0, 1].map((i) => )} {/* Analytics bars */} // CONVERSÃO {[36, 52, 28, 64, 44, 72, 56, 80].map((h, i) => )} {/* trend line */} {/* Labels */} Site / e-commerce E-mail + automação Analytics nativos ); } if (kind === 'helpdesk') { // Ticket list + SLA ring + chat bubble return wrap( {/* Ticket list */} // CHAMADOS {[ { t: '#1042 · Importação NFe', m: 'urgente · novo', emph: true }, { t: '#1041 · Configurar SLA', m: 'alta · andamento' }, { t: '#1039 · Layout fatura', m: 'média · andamento' }, { t: '#1038 · Treinamento', m: 'média · aguardando' }, { t: '#1035 · Relatório custom', m: 'baixa · fechado' }]. map((r, i) => {r.t} {r.m} {i < 4 && } )} {/* SLA ring */} 2h14 SLA {/* Chat bubble */} {/* CSAT mini */} NPS +72 {/* Labels */} Tickets priorizados Conversa + SLA NPS · CSAT ); } if (kind === 'placeholder') { // Fallback (no longer used by any slide but kept for safety) return wrap( // ILLUSTRATION_PENDING placeholder ); } return wrap(null); } // ───────────────────────── WHY DEEPSTRAT ───────────────────────── // Palantir-influenced: full dark, technical grid, bracket corners, // coordinate labels, animated bars, word-by-word reveal of headline. function RevealText({ children, delay = 0, className = '' }) { // Word-by-word reveal driven by IntersectionObserver via .fade-up handler. // We split into words and stagger their `.in` class. const ref = useRefS(null); useEffectS(() => { const el = ref.current; if (!el) return; const io = new IntersectionObserver((entries) => { entries.forEach((e) => { if (e.isIntersecting) { const ws = el.querySelectorAll('.reveal-w'); ws.forEach((w, i) => { setTimeout(() => w.classList.add('in'), delay + i * 55); }); io.disconnect(); } }); }, { threshold: 0.25 }); io.observe(el); return () => io.disconnect(); }, [delay]); const text = typeof children === 'string' ? children : ''; return ( {text.split(' ').map((w, i) => {w} )} ); } function CornerCoords({ tl, tr, bl, br }) { return ( <> {tl &&
{tl}
} {tr &&
{tr}
} {bl &&
{bl}
} {br &&
{br}
} ); } // FlowCards — three responsive cards showing the architecture: // 01 You ask · 02 Deepstrat translates · 03 ERP executes. // Each card has a small animated visual that loops while visible. // BrandColorBand — subtle atmospheric divider between sections. // Just a purple/blue aurora + faint grain. Strong top/bottom fades so the band // melts into the surrounding ink-950 sections, creating a soft overlap. // The spinning Deepstrat symbol is layered on top (handled by parent section). function BrandColorBand() { // Vertical mask that fades ALL band content (background + aurora + grid + // grain) gradually at top and bottom. The middle 30% is fully opaque, then // long gradual fades on each side. Because we mask the *content* (not overlay // darkness on top), the band can sit over other sections without dimming them. const verticalFade = 'linear-gradient(to bottom, transparent 0%, #000 10%, #000 85%, transparent 100%)'; const maskStyle = { maskImage: verticalFade, WebkitMaskImage: verticalFade }; return (
{/* Solid dark base — gives the band depth so aurora reads as glow, not just colored haze. Masked along with everything else. */}
{/* Soft aurora — purple + blue, muted */}
{/* Very faint grid — barely there, just enough texture */}
{/* Subtle grain texture */}
); } function FlowCards() { const stages = [ { n: '01', tag: 'entrada', title: 'Você pergunta', body: 'Use ChatGPT, Claude ou Gemini em português, do celular ou do desktop. Sem decorar menu, sem trocar de ferramenta.', illust: 'chat', accent: false }, { n: '02', tag: 'orquestração', title: 'Deepstrat traduz', body: 'A camada que entende o seu pedido em linguagem natural e converte em chamadas reais no Odoo, com permissões, log e auditoria.', illust: 'orchestrate', accent: true }, { n: '03', tag: 'execução', title: 'Tudo acontece no ERP', body: 'Pedido lançado, NFe emitida, férias agendadas, caixa atualizado. Resultado real no mesmo Odoo que sua equipe já opera.', illust: 'modules', accent: false }]; return (
{stages.map((s, i) => {/* Connector arrow — visible between cards on desktop; vertical chevron on mobile. Black bg + accent border + glow para destacar o fluxo entre os estagios. */} {i < stages.length - 1 &&
} {i < stages.length - 1 && }
)}
); } function FlowCard({ stage, index }) { const ref = useRefS(null); const [armed, setArmed] = useStateS(false); useEffectS(() => { const el = ref.current; if (!el) return; const io = new IntersectionObserver((es) => { es.forEach((e) => { if (e.isIntersecting) {setArmed(true);io.disconnect();} }); }, { threshold: 0.25 }); io.observe(el); return () => io.disconnect(); }, []); return (
{stage.n} · {stage.tag} {armed ? 'ativo' : '...'}

{stage.title}

{stage.body}

{/* Animated illustration block */}
{stage.illust === 'chat' && } {stage.illust === 'orchestrate' && } {stage.illust === 'modules' && }
); } // — Illustration 1: chat scenarios cycling through different departments — function ChatIllust({ armed, accent }) { const scenarios = [ { dept: 'vendas', bubbles: [ { who: 'you', text: 'cria pedido pra Loja Vila Madá: 80 camisetas P pretas, prazo 30 dias' }, { who: 'ai', text: 'pronto · #1042 · R$ 2.880. confirmação por e-mail?' }, { who: 'you', text: 'manda' }] }, { dept: 'financeiro', bubbles: [ { who: 'you', text: 'como tá o caixa essa semana?' }, { who: 'ai', text: 'entradas R$ 12.4k · saídas R$ 8.2k · saldo +R$ 4.2k' }, { who: 'ai', text: '⚠︎ 3 boletos vencendo amanhã (R$ 2.180)' }] }, { dept: 'estoque', bubbles: [ { who: 'you', text: 'tô com pouca camiseta P preta?' }, { who: 'ai', text: 'sim · 42 un · mínimo 100. gero ordem de compra?' }, { who: 'you', text: 'sim, 200 unidades' }] }, { dept: 'rh', bubbles: [ { who: 'you', text: 'marca férias da Mariana em janeiro' }, { who: 'ai', text: '30 dias acumulados. sugiro 15 a 30/01. confirma?' }, { who: 'you', text: 'isso · gestor avisado' }] }, { dept: 'compras', bubbles: [ { who: 'you', text: 'compra 200m malha branca · melhor fornecedor' }, { who: 'ai', text: 'Têxtil ABC · R$ 8/m · prazo 5 dias · histórico ok' }, { who: 'you', text: 'manda pedido' }] }]; const [idx, setIdx] = useStateS(0); useEffectS(() => { if (!armed) return; const t = setInterval(() => setIdx((i) => (i + 1) % scenarios.length), 6500); return () => clearInterval(t); }, [armed]); const cur = scenarios[idx]; return (
{/* Department label (top-left) — animates with each scenario change */}
{cur.dept}
{/* Live indicator (top-right) */}
ao vivo
{/* Bubbles — re-mounted on every scenario change so they re-animate */} {cur.bubbles.map((b, i) =>
{b.text}
)}
); } // — Illustration 2: Big spinning Deepstrat symbol — pulses, glows, with // counter-rotating dashed ring, concentric pulse rings, and background // data waves flowing entrada → ação behind it. function OrchestrateIllust({ armed, accent }) { const waveStroke = accent ? 'rgba(10,10,11,.32)' : 'rgba(255,255,255,.32)'; const waveStrokeSoft = accent ? 'rgba(10,10,11,.18)' : 'rgba(255,255,255,.20)'; // Two sine waves, each 8 full cycles across viewBox 0–400. SVG renders at // 200% width and translates by -50% → wraps seamlessly (integer wavelengths). const cycles = 16; // half-cycles const upperWave = 'M 0 20 Q 12.5 4, 25 20 ' + Array.from({ length: cycles - 1 }, (_, i) => `T ${(i + 2) * 25} 20`).join(' '); const lowerWave = 'M 0 20 Q 12.5 36, 25 20 ' + Array.from({ length: cycles - 1 }, (_, i) => `T ${(i + 2) * 25} 20`).join(' '); return (
{/* Background data waves — flow entrada → ação behind the logo. Two layers at different speeds give a sense of multiple streams orchestrated in parallel. Edges fade via orch-wave-mask. */}
{/* Pulsing concentric rings — expand out from behind the logo */} {[0, 1, 2].map((i) => )} {/* Outer dashed ring — slowly counter-rotates */} {/* The symbol — large, spinning, with a soft pulse glow */}
{/* Mini flow labels at top/bottom edges */}
entrada →
→ ação
); } // — Illustration 3: live "ops log" — actions ticking off across modules, // like a system showing what's actually executing. Loops continuously. function ModulesIllust({ armed, accent }) { const ops = [ { mod: 'Vendas', text: 'pedido #1042 · R$ 2.880' }, { mod: 'Estoque', text: '−80 camisetas P · saldo 42' }, { mod: 'Contábil', text: 'NFe 0218 emitida' }, { mod: 'Financeiro', text: 'cobrança enviada · 30 dias' }, { mod: 'RH', text: 'férias · Mariana · 15→30 jan' }]; return (
{/* Header — like a log title */}
ops · ao vivo
+5 ações
{/* Rows */}
{ops.map((op, i) => { const delay = i * 0.7; return (
{/* Checkmark — animated stroke */} {op.mod} {op.text}
); })}
); } function Why() { return (
{/* Solid ink-950 background. */}
{/* Multi-layer tech background */}
{/* Coordinate label on section edges */}
{`> from deepstrat import orchestrator # mcp · v0.4`}
{`runtime=prod · llm=* · stream=on`}
Por que Deepstrat

A camada que conecta IA ao seu ERP

{'// 00 · arquitetura'} 3 camadas · 1 ERP
); } function ImplementationCarousel() { const slides = [ { Comp: WhyAI, label: 'Implementação' }, { Comp: WhyMCP, label: 'Operação' }, { Comp: WhyMethod, label: 'Metodologia' }, ]; const total = slides.length; const [idx, setIdx] = useStateS(0); const go = (i) => setIdx(((i % total) + total) % total); useEffectS(() => { const onKey = (e) => { if (e.key === 'ArrowLeft') go(idx - 1); if (e.key === 'ArrowRight') go(idx + 1); }; window.addEventListener('keydown', onKey); return () => window.removeEventListener('keydown', onKey); }, [idx]); // Touch swipe const touchX = useRefS(0); const onTouchStart = (e) => { touchX.current = e.touches[0].clientX; }; const onTouchEnd = (e) => { const dx = e.changedTouches[0].clientX - touchX.current; if (Math.abs(dx) > 40) go(dx < 0 ? idx + 1 : idx - 1); }; return (
{/* Header — Title + Subtitle */}
{'// 01 · como entregamos'} {String(idx + 1).padStart(2, '0')} / {String(total).padStart(2, '0')} · {slides[idx].label}

Por dentro da implementação

{/* Mobile stack — all 3 cards sequentially, no carousel */}
{slides.map(({ Comp }, i) => (
))}
{/* Carousel viewport — desktop only, fixed standard card height */}
{/* Arrows */} {/* Slides track — all slides same width/height */}
{slides.map(({ Comp }, i) => (
))}
{/* Navigation strip — desktop only */}
← / → · arraste · clique
{slides.map((s, i) => ( ))}
{String(idx + 1).padStart(2, '0')} / {String(total).padStart(2, '0')}
); } function TechBlockShell({ number, label, title, children, accent = false }) { return (
{/* Header strip */}
{number} {label}
{/* Heading */}

{title}

{/* Body */}
{children}
); } function WhyAI() { return ( IA não é um diferencial. É a fundação da nossa metodologia.}>

Reconstruímos cada etapa do projeto em torno de IA: requisitos, mapeamento, configuração, migração, testes e treinamento.

O consultor passa de execução para supervisão, e implementações que tradicionalmente levavam mais de um ano são{' '} entregues em semanas, com custo proporcional.

); } function ImplementationSteps() { const steps = [ 'Levantamento de requisitos', 'Mapeamento de processos', 'Configuração e workflows', 'Migração de dados', 'Testes e treinamento', ]; return (
{/* Vertical connector */}
{steps.map((label, i) => (
{/* Step dot */}
{String(i + 1).padStart(2, '0')}
{/* Label + IA badge */}
{label} IA
))}
execução assistida por IA · supervisão humana
); } function WhyMCP() { // Clients that can drive the ERP. User clicks a tab → mock UI of that app // operating Odoo appears in the right column. const clients = [ { id: 'chatgpt', label: 'ChatGPT' }, { id: 'claude', label: 'Claude' }, { id: 'gemini', label: 'Gemini' }, { id: 'openclaw', label: 'OpenClaw' }, ]; const [active, setActive] = useStateS('chatgpt'); return ( Após o go-live, a operação acontece em linguagem natural.}>

O ERP é entregue conectado às plataformas de IA já adotadas pela sua equipe (ChatGPT, Claude, Gemini, Telegram).

Pedidos, consultas, propostas e alertas são executados em linguagem natural via uma única instrução, e a operação{' '} escala sem ampliação proporcional de equipe.

{clients.map((c) => ( ))}

↑ selecione para visualizar a interface

{/* Right column — interactive client preview */}
); } // ClientPreview — renders a small mock interface of one of the supported // AI clients operating the ERP. Each preview is just-enough detail to be // recognizable without copying the actual product UI. function ClientPreview({ kind }) { return (
{kind === 'chatgpt' && } {kind === 'claude' && } {kind === 'gemini' && } {kind === 'openclaw' && }
); } function ChatGPTPreview() { return (
{/* App bar */}
ChatGPT
deepstrat-mcp
{/* Messages */}
qual foi nosso faturamento de outubro?
G
R$ 1.247.300 em outubro. 18% acima de setembro.
Maior cliente: Lumen com R$ 184k.
Quer que eu detalhe por cliente?
{/* Composer */}
Pergunte qualquer coisa…
); } function ClaudePreview() { return (
{/* App bar */}
Claude
deepstrat-mcp
{/* Messages */}
crie uma proposta pra Acme nos termos padrão
Proposta P-217 montada e anexada no e-mail deles.
Inclui os 3 itens que você costuma cotar com a Acme.
Validade: 30 dias. Posso ajustar?
{/* Composer */}
Replique a Claude…
); } function GeminiPreview() { return (
{/* App bar */}
Gemini
deepstrat-mcp
{/* Messages */}
me avisa se algum cliente passar de 60 dias em atraso
Combinado.
Vou monitorar o módulo financeiro e te avisar aqui assim que acontecer.
alerta criado
{/* Composer */}
Pergunte ao Gemini…
); } function OpenClawTelegramPreview() { return (
{/* App bar — Telegram-style */}
OC
OpenClaw · ERP bot
online · conectado ao Odoo
via Telegram
{/* Messages */}
qual o estoque de camiseta P preta?
14:32 ✓✓
📦 42 unidades
⚠️ abaixo do mínimo (100)
Gerar ordem de compra?
14:32
sim, 200 unidades
14:33 ✓✓
{/* Composer */}
📎
Mensagem
); } function WhyMethod() { const phases = [ { n: '01', t: 'Diagnóstico', tag: 'Fase de descoberta', lead: 'Imersão estruturada na operação do cliente: mapeamento de processos, dados, integrações e lacunas técnicas.', detail: 'A entrega contempla plano executivo, escopo consolidado e estimativa de custo fundamentada em análise específica.' }, { n: '02', t: 'Implementação', tag: 'Cronograma reduzido', lead: 'Configuração, customizações e migração executadas em paralelo.', detail: 'A automação por IA assume o trabalho repetitivo, e a equipe Deepstrat conduz as decisões estruturais. Acompanhamento em ambiente real desde a primeira entrega.' }, { n: '03', t: 'Hypercare', tag: '60 dias inclusos', lead: 'Os 60 dias após o go-live são acompanhados por equipe dedicada: ajustes finos, treinamento contínuo e plantão para incidentes.', detail: 'Encerrado o período, suporte recorrente fica disponível conforme a operação evolui.' }]; return ( Metodologia clara e previsível}>
{phases.map((p, i) =>
{i > 0 &&
}
PHASE_{p.n} {p.tag}

{p.t}

{p.lead}

{p.detail}

)}
); } // ───────────────────────── COMPARE ───────────────────────── function Compare() { const cols = [ { tier: 'Entry-level', name: 'ERPs simplificados', tone: 'plain', price: 'R$ 100–500 / mês', setup: 'Plug-and-play', dx: 'Limitado', good: ['Barato e simples', 'Fácil de começar'], bad: ['Trava no crescimento', 'Integrações frágeis', 'Customização zero'] }, { tier: 'O ponto certo', name: 'Odoo + Deepstrat', tone: 'highlight', price: 'TCO 5–10x menor', setup: 'Meses, não anos', dx: '40+ aplicativos · integrados · operável por IA', good: ['Capacidade enterprise', 'Custo de PME', 'Operável por IA', 'Tudo em um único sistema'], bad: [] }, { tier: 'Enterprise', name: 'Plataformas enterprise', tone: 'plain', price: 'Centenas de milhares', setup: '6–18 meses', dx: 'Capaz, mas pesado', good: ['Cobertura completa', 'Mercado consolidado'], bad: ['Caro de manter', 'Implementação longa', 'Consultor caro pra tudo', 'Lock-in pesado'] }]; return (
Você não precisa escolher entre simples e capaz} sub="Há quem cobre barato e te deixe na mão quando crescer. Há quem cubra tudo, com cronograma de catedral e fatura à altura. E há o meio onde a Deepstrat opera." />
{cols.map((c, i) =>
{c.tone === 'highlight' && }
{c.tier}
{c.name}
{[['Custo', c.price], ['Implementação', c.setup], ['Capacidade', c.dx]].map(([k, v]) =>
{k}
{v}
)}
    {c.good.map((g) =>
  • {g}
  • )} {c.bad.map((b) =>
  • {b}
  • )}
{c.tone === 'highlight' && Agendar demonstração }
)}
); } // ───────────────────────── CTA / Cal.com popup ───────────────────────── // Loads the Cal.com element-click embed. Any element on the page that carries // the data-cal-link / data-cal-namespace attrs becomes a trigger for the popup. const CAL_LINK = 'deepstrat/demonstracao-odoo'; const CAL_NAMESPACE = 'demonstracao-odoo'; function useCalEmbed() { useEffectS(() => { if (window.__calBooted) return; window.__calBooted = true; (function (C, A, L) { let p = function (a, ar) {a.q.push(ar);}; let d = C.document; C.Cal = C.Cal || function () { let cal = C.Cal;let ar = arguments; if (!cal.loaded) {cal.ns = {};cal.q = cal.q || [];d.head.appendChild(d.createElement("script")).src = A;cal.loaded = true;} if (ar[0] === L) { const api = function () {p(api, arguments);}; const namespace = ar[1];api.q = api.q || []; if (typeof namespace === "string") {cal.ns[namespace] = cal.ns[namespace] || api;p(cal.ns[namespace], ar);p(cal, ["initNamespace", namespace]);} else p(cal, ar); return; } p(cal, ar); }; })(window, "https://app.cal.com/embed/embed.js", "init"); window.Cal("init", CAL_NAMESPACE, { origin: "https://app.cal.com" }); window.Cal.ns[CAL_NAMESPACE]("ui", { cssVarsPerTheme: { light: { "cal-brand": "#0a0a0b" }, dark: { "cal-brand": "#fafafa" } }, hideEventTypeDetails: false, layout: "month_view" }); }, []); } // Attributes to spread onto any clickable element to make it a popup trigger. const CAL_TRIGGER_ATTRS = { 'data-cal-link': CAL_LINK, 'data-cal-namespace': CAL_NAMESPACE, 'data-cal-config': JSON.stringify({ layout: 'month_view', useSlotsViewOnSmallScreen: 'true' }) }; function CTA() { useCalEmbed(); return (
{/* Left: selling copy + primary CTA */}
{/* Header strip — mesmo padrão do TechBlockShell */}
{'// 03'} Contato

Conheça o Odoo em uma demonstração guiada

Uma apresentação estruturada da plataforma, com foco nos módulos mais relevantes para a sua operação.

    {['Conversa de 30 minutos', 'Visão geral dos principais módulos', 'Espaço para tirar dúvidas sobre o projeto'].map((x) =>
  • {x}
  • )}
{/* Primary Cal.com trigger */} Agendar demonstração
Prefere conversar antes?{' '} WhatsApp {' '}ou{' '} e-mail.
{/* Right: visual scheduling preview (decorative, click to open Cal) */}
{/* Mock calendar */}
Novembro 2026
{['D', 'S', 'T', 'Q', 'Q', 'S', 'S'].map((d, i) =>
{d}
)}
{Array.from({ length: 35 }, (_, i) => { const day = i - 4; const isAvail = [3, 4, 5, 10, 11, 12, 17, 18, 19, 24, 25, 26].includes(day); const isToday = day === 6; return (
{day > 0 && day <= 30 ? day : ''}
); })}
{/* Time slots preview */}
{[ { d: 'Qua · 13 nov', t: '09:00, 10:30, 14:00, 16:00' }, { d: 'Qui · 14 nov', t: '11:00, 15:00' }, { d: 'Sex · 15 nov', t: '09:30, 13:00, 17:00' }]. map((s, i) =>
{s.d} {s.t}
)}
Clique para abrir a agenda
); } // ───────────────────────── BLOG ───────────────────────── // Tema Palantir: dark, tech-grid, coordenadas, brackets nos cards. function Blog() { const [posts, setPosts] = useStateS(null); // null = loading, [] = vazio, [...] = ok const [err, setErr] = useStateS(null); useEffectS(() => { let alive = true; fetch('/api/blog-posts.php') .then((r) => r.ok ? r.json() : Promise.reject(new Error('HTTP ' + r.status))) .then((d) => { if (alive) setPosts(d.posts || []); }) .catch((e) => { if (alive) setErr(e.message); }); return () => { alive = false; }; }, []); if (err || (Array.isArray(posts) && posts.length === 0)) return null; const formatDate = (iso) => { if (!iso) return ''; const d = new Date(iso.replace(' ', 'T') + 'Z'); if (isNaN(d)) return ''; return d.toLocaleDateString('pt-BR', { day: '2-digit', month: 'short', year: 'numeric' }); }; const count = Array.isArray(posts) ? posts.length : 3; return (
{/* Multi-layer tech background (mesmo padrao do Why/Implementation) */}
{/* Coordenadas nos cantos */}
{'> deepstrat/blog · feed=public'}
{`posts=${String(count).padStart(2,'0')} · refresh=10min · src=odoo`}
Blog

Nosso Blog

{/* Separator */}
{'// Últimos Posts'}
{/* Ver todos: link para a galeria completa */} {posts && posts.length > 0 ? : null}
); } // ───────────────────────── BRAND SPIN BAND ───────────────────────── // Self-contained band with the centered, slowly-spinning Deepstrat symbol // on a blueprint-style white background. Thin blue gridlines (Deepstrat // deep-direction blue, #2470db) evoke an engineering datasheet. Sits flush // above the footer; the all-white base flows naturally into both the white // CTA section above and the white footer below. function BrandSpinBand() { const BP_BLUE = '#2470db'; const BP_BLUE_INK = '#16407a'; const canvasRef = useRefS(null); const iconsLayerRef = useRefS(null); const [webgl, setWebgl] = useStateS(false); // Icon physics is bootstrapped via a window-level helper installed on the // first mount. The React effect just kicks it off (and doesn't tear it // down on unmount, so a hydration mismatch elsewhere can't kill it). The // helper itself is idempotent: a global flag ensures we only run one // animation loop even if BrandSpinBand mounts/unmounts repeatedly. useEffectS(() => { if (typeof window === 'undefined') return; installIconPhysics(); }, []); useEffectS(() => { if (typeof window === 'undefined') return; const THREE = window.THREE; const SVGLoader = THREE && THREE.SVGLoader; const canvas = canvasRef.current; if (!THREE || !SVGLoader || !canvas) return; // Probe WebGL — keep SVG fallback if WebGL isn't available. try { const probe = document.createElement('canvas').getContext('webgl') || document.createElement('canvas').getContext('experimental-webgl'); if (!probe) return; } catch (e) { return; } setWebgl(true); const w0 = canvas.clientWidth || 800; const h0 = canvas.clientHeight || 400; const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(35, w0 / h0, 0.1, 3000); camera.position.set(0, 0, 620); const renderer = new THREE.WebGLRenderer({ canvas, alpha: true, antialias: true }); renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2)); renderer.setSize(w0, h0, false); renderer.setClearColor(0x000000, 0); // Dramatic lighting on a polished-black surface: low ambient so the symbol // reads as a deep silhouette, with strong saturated grazing lights that // produce bright colored highlights along the bevels and edges. scene.add(new THREE.AmbientLight(0xffffff, 0.30)); // Cool blue key — primary highlight, slightly grazing from above-left const keyLight = new THREE.DirectionalLight(0x6ba3ff, 3.4); keyLight.position.set(-5, 6, 7); scene.add(keyLight); // Hot white fill — grazes the right side for crisp white highlights const fillLight = new THREE.DirectionalLight(0xffffff, 1.6); fillLight.position.set(7, -2, 3); scene.add(fillLight); // Purple rim — wraps the back edges in violet const rimLight = new THREE.DirectionalLight(0xb085ff, 2.2); rimLight.position.set(-2, -5, -5); scene.add(rimLight); // Top accent — pure white pop on the upper facets const topLight = new THREE.DirectionalLight(0xffffff, 1.4); topLight.position.set(0, 10, 1); scene.add(topLight); // Warm orange point — Deepstrat AI accent, off to the side for a hint of warmth const warmAccent = new THREE.PointLight(0xfcb865, 1.8, 700); warmAccent.position.set(180, 40, 220); scene.add(warmAccent); // Procedural environment map — gives the metallic surface something colored // to reflect (without it, high-metalness materials look dull/grey). const envScene = new THREE.Scene(); const envColors = [ { c: 0x6ba3ff, p: [0, 4, 0] }, // top — blue { c: 0xb085ff, p: [0, -4, 0] }, // bottom — purple { c: 0xffffff, p: [4, 0, 0] }, // right — white { c: 0xfcb865, p: [-4, 0, 0] }, // left — warm { c: 0x4a90ff, p: [0, 0, 4] }, // front — blue { c: 0x1a1a2a, p: [0, 0, -4] }, // back — near-black ]; envColors.forEach(({ c, p }) => { const m = new THREE.Mesh( new THREE.PlaneGeometry(8, 8), new THREE.MeshBasicMaterial({ color: c, side: THREE.DoubleSide }) ); m.position.set(...p); m.lookAt(0, 0, 0); envScene.add(m); }); const pmrem = new THREE.PMREMGenerator(renderer); const envTex = pmrem.fromScene(envScene, 0.04).texture; scene.environment = envTex; envScene.traverse(o => { if (o.geometry) o.geometry.dispose(); if (o.material) o.material.dispose(); }); pmrem.dispose(); // Brand assets — symbol (4-arm mark) + wordmark ("deep strat" letters). // Both inlined so we don't need a runtime fetch; both flipped on Y to // correct SVG's inverted coordinate system. const symbolSvg = '' + '' + '' + '' + '' + '' + ''; const wordmarkSvg = '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + ''; const loader = new SVGLoader(); const symbolData = loader.parse(symbolSvg); const wordmarkData = loader.parse(wordmarkSvg); // Two materials: // • symbolMaterial — polished obsidian (metalness + clearcoat) for the // 4-arm mark, so the colored env map paints highlights on its bevels. // • wordmarkMaterial — flat matte ink for the letters. Unlit // MeshBasicMaterial: no shine, no env-map reflections, no surface // texture. Clean, readable type. const symbolMaterial = new THREE.MeshPhysicalMaterial({ color: 0x07070a, metalness: 0.85, roughness: 0.22, clearcoat: 0.90, clearcoatRoughness: 0.15, reflectivity: 0.6, envMapIntensity: 1.4, side: THREE.DoubleSide, }); const wordmarkMaterial = new THREE.MeshBasicMaterial({ color: 0x0a0a0b, side: THREE.DoubleSide, }); // SVGLoader.createShapes() relies on auto-detection (winding direction or // ray-casting) to figure out which sub-paths are holes. For our wordmark // it fails — the bowls of d/e/p/a get filled as solid rectangles. // // We do hole assignment manually: for each , the sub-path with the // largest bounding-box area is the outer shape; every other sub-path is a // hole. This is robust for typographic glyphs (each letter has 1 outer // contour + 0..N counterforms, with the outer always being the largest). const pathToShapesWithHoles = (path) => { const sub = path.subPaths || []; if (!sub.length) return []; if (sub.length === 1) { const s = new THREE.Shape(); s.curves = sub[0].curves; return [s]; } // Bounding-box area per sub-path const bboxArea = sub.map((sp) => { const pts = sp.getPoints(); let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity; for (const p of pts) { if (p.x < minX) minX = p.x; if (p.y < minY) minY = p.y; if (p.x > maxX) maxX = p.x; if (p.y > maxY) maxY = p.y; } return (maxX - minX) * (maxY - minY); }); let outerIdx = 0; for (let i = 1; i < bboxArea.length; i++) { if (bboxArea[i] > bboxArea[outerIdx]) outerIdx = i; } const shape = new THREE.Shape(); shape.curves = sub[outerIdx].curves; for (let i = 0; i < sub.length; i++) { if (i === outerIdx) continue; const hole = new THREE.Path(); hole.curves = sub[i].curves; shape.holes.push(hole); } return [shape]; }; // Build an extruded group from parsed SVG path data; centers the group on // its bounding-box midpoint so subsequent positioning is relative to its // own center, not its top-left corner. Uses `shapeBuilder(path)` to convert // each parsed ShapePath into Shapes — callers can swap in a custom builder // (e.g. manual hole detection for glyphs). const buildExtruded = (svgData, extrudeOpts, mat, shapeBuilder) => { const buildShapes = shapeBuilder || ((p) => SVGLoader.createShapes(p)); const g = new THREE.Group(); svgData.paths.forEach((path) => { buildShapes(path).forEach((shape) => { g.add(new THREE.Mesh(new THREE.ExtrudeGeometry(shape, extrudeOpts), mat)); }); }); const box = new THREE.Box3().setFromObject(g); const c = box.getCenter(new THREE.Vector3()); const sz = box.getSize(new THREE.Vector3()); g.children.forEach((m) => m.position.sub(c)); return { group: g, size: sz }; }; const symbolBuilt = buildExtruded(symbolData, { depth: 26, bevelEnabled: true, bevelThickness: 2.0, bevelSize: 1.3, bevelSegments: 4, curveSegments: 24, }, symbolMaterial); // Wordmark is extruded WITHOUT bevel — letters with tight inner curves // (the counterforms of d/e/p/a) develop self-intersection artifacts when // beveled. Flat extrusion + the matte BasicMaterial reads as clean type. // Manual hole-detection is used here because SVGLoader.createShapes() // fails to identify the counterforms of d/e/p/a as holes. const wordmarkBuilt = buildExtruded(wordmarkData, { depth: 8, bevelEnabled: false, curveSegments: 16, }, wordmarkMaterial, pathToShapesWithHoles); // Proportions tuned to match the official brand lockup (logo-narrow.png, // aspect ~3.88:1, symbol section ~27% of total width). The wordmark width // is set as a multiple of the symbol display-height; this keeps the letters // reading at the correct visual weight relative to the mark. const SYMBOL_H = 90; // smaller overall lockup const WM_W_TO_SYM_H = 3.0; // wordmark width = 3x symbol height const symScale = SYMBOL_H / symbolBuilt.size.y; const wmDisplayWidth = SYMBOL_H * WM_W_TO_SYM_H; const wmScale = wmDisplayWidth / wordmarkBuilt.size.x; // scale.y is negative to flip SVG's downward Y axis. symbolBuilt.group.scale.set(symScale, -symScale, symScale); wordmarkBuilt.group.scale.set(wmScale, -wmScale, wmScale); const symW = symbolBuilt.size.x * symScale; const wmW = wordmarkBuilt.size.x * wmScale; const GAP = 14; const totalW = symW + GAP + wmW; // Position so the entire lockup is horizontally centered on origin. symbolBuilt.group.position.x = -totalW / 2 + symW / 2; wordmarkBuilt.group.position.x = totalW / 2 - wmW / 2; const lockup = new THREE.Group(); lockup.add(symbolBuilt.group); lockup.add(wordmarkBuilt.group); scene.add(lockup); // Fit the lockup to the visible viewport width — on narrow canvases (mobile) // it scales down so the wordmark doesn't get clipped at the edges. const naturalLockupWidth = totalW; const fitLockup = () => { const visibleH = 2 * Math.tan((camera.fov * Math.PI / 180) / 2) * camera.position.z; const visibleW = visibleH * camera.aspect; const target = visibleW * 0.65; const s = Math.min(1, target / naturalLockupWidth); lockup.scale.set(s, s, s); }; fitLockup(); // (Odoo module icons are rendered as DOM elements behind the canvas // — Three.js TextureLoader can't load them due to CORS on the Odoo CDN, // and DOM imgs don't need CORS for display. See the JSX render below.) // Mouse parallax (viewport-normalized). let targetX = 0, targetY = 0; const onMove = (e) => { targetX = ((e.clientX / window.innerWidth) - 0.5) * 0.7; targetY = ((e.clientY / window.innerHeight) - 0.5) * 0.4; }; window.addEventListener('mousemove', onMove, { passive: true }); // Resize handling — re-fit the lockup so the wordmark always stays inside // the visible viewport, regardless of canvas aspect. const resize = () => { const w = canvas.clientWidth, h = canvas.clientHeight; if (!w || !h) return; renderer.setSize(w, h, false); camera.aspect = w / h; camera.updateProjectionMatrix(); fitLockup(); }; const ro = (typeof ResizeObserver !== 'undefined') ? new ResizeObserver(resize) : null; if (ro) ro.observe(canvas); window.addEventListener('resize', resize); // Animate — lockup is completely static. The 3D scene only renders if // anything else needs it (e.g. layout/resize). One render pass on mount // is enough since nothing moves; we still keep the rAF loop running so // the canvas re-renders cleanly after resize/devicepixelratio changes. let raf = 0; const animate = () => { renderer.render(scene, camera); raf = requestAnimationFrame(animate); }; animate(); return () => { cancelAnimationFrame(raf); window.removeEventListener('mousemove', onMove); window.removeEventListener('resize', resize); if (ro) ro.disconnect(); renderer.dispose(); lockup.traverse((o) => { if (o.geometry) o.geometry.dispose(); }); symbolMaterial.dispose(); wordmarkMaterial.dispose(); }; }, []); return ( ); } // ───────────────────────── FOOTER ───────────────────────── function Footer({ showPartnerBadge = true }) { // Section heading with a small accent bar in brand blue — gives each column // a visual anchor without resorting to text-align tricks that hurt readability. const SectionHeading = ({ children }) => (
{children}
); return ( ); } Object.assign(window, { Nav, Hero, Pain, Modules, Why, ImplementationCarousel, Spotlight, Compare, Blog, CTA, BrandSpinBand, Footer });