// Landing.jsx — public showcase landing page for ConstructHub.
// Revolut-style relaunch: dark cinematic hero, scroll-driven feature
// chapters powered by the live demos in ./demos/, dark AI band, dark
// newsletter finale. Madeira-first copy per the 2026-06-11 relaunch spec
// (no "ERP" wording, no beta/registration — newsletter is the single CTA).
//
// i18n: PT (canonical) / EN / ES via the I18N dictionary below and the
// switcher in the nav pill. Language persists in localStorage ('ch-lang')
// and can be forced with ?lang=en. The product demos stay PT-PT — they
// show real Portuguese documents (faturas, NIFs, ATCUD), which is the
// honest representation of the product.
//
// Hosts: showcase.html (design-canvas artboard) and home.html (standalone
// full page). Demo components are read from window[name] with a graceful
// placeholder, so the page still renders if a demo script isn't loaded.

const INDIGO = '#4F6EF7';
const INDIGO_SOFT = '#EEF1FF';
const DISPLAY_FONT = "'Archivo', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif";

const INVITE_EMAIL = 'equipa@constructhub.services';
function mailtoHref({ subject, body }) {
  return `mailto:${INVITE_EMAIL}?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body.join('\r\n'))}`;
}

// ─── Copy — PT is canonical; EN/ES mirror it ──────────────────────────
const I18N = {
  pt: {
    nav: { links: [['Produto', '#produto'], ['Assistente IA', '#ia'], ['Planos', '#planos'], ['FAQ', '#faq']], cta: 'Receber novidades' },
    hero: {
      chip: 'Lançamento · outono de 2026 · Madeira primeiro',
      rotor: ['stock', 'encomendas', 'faturação', 'obras'],
      h1Pre: 'Gestão de', h1Mid: 'pensada para quem', h1End: 'constrói na Madeira.',
      sub: <>Stock em tempo real, encomendas sem papel e <strong className="text-white font-semibold">faturação AT com ATCUD, QR e SAF-T</strong> — uma plataforma de gestão feita de raiz para distribuidores e retalhistas de materiais de construção.</>,
      ctaProduct: 'Ver o produto', ctaNews: 'Receber novidades',
      trust: ['AT e-fatura', 'SAF-T PT', 'PT · EN · ES', 'RGPD'],
      frame: 'ConstructHub · Faturação',
    },
    badge: 'demo',
    numbers: [
      { n: 'PT·EN·ES', l: 'disponível em três idiomas' },
      { n: '4/12/22', l: 'IVA da Madeira nativo' },
      { n: '1 clique', l: 'exportação SAF-T PT' },
      { n: '0 €', l: 'para começar, sem cartão' },
    ],
    problem: {
      kicker: 'O problema',
      h2: 'Software genérico não percebe o seu negócio.',
      p1: 'As plataformas internacionais foram desenhadas para vender livros ou software — não cimento, areia ou aço. Não falam com a AT, não exportam SAF-T PT, não percebem IVA reduzido em obras de reabilitação, e tratam um empreiteiro como se fosse um consumidor final.',
      p2: 'Os sistemas antigos portugueses falam o idioma — mas vivem em janelas Windows dos anos 2000, não funcionam no telemóvel do chefe de obra, e o catálogo é uma folha de Excel.',
      p3: 'O ConstructHub é uma terceira opção. Uma plataforma de gestão moderna, na nuvem, em PT-PT, feita de raiz para a forma como o sector trabalha — a começar pela Madeira.',
    },
    chaptersIntro: {
      chip: 'Produto',
      h2: 'O ConstructHub em ação.',
      sub: 'Seis demonstrações dos fluxos principais — do orçamento à fatura pronta para a AT. Para o ver com os dados da sua empresa, peça uma demonstração.',
      cta: 'Pedir uma demonstração',
    },
    chapters: [
      { kicker: 'Faturação AT', title: 'Da venda ao ATCUD em segundos.',
        body: 'E-fatura nativo, sem exportações nem software intermédio. Cada documento sai com série registada na AT, hash imutável e QR — pronto para a AT.',
        points: ['Séries registadas na AT e hash RSA imutável', 'ATCUD + QR em cada documento', 'SAF-T PT num clique'] },
      { kicker: 'Stock multi-armazém', title: 'Stock em que pode confiar.',
        body: 'Cada movimento fica registado num livro-razão imutável. Transferências entre lojas, armazéns e estaleiros com pedido e aprovação — e visão em tempo real do que existe em cada local.',
        points: ['Multi-loja, multi-armazém, estaleiros', 'Transferências com pedido e aprovação', 'Movimentos auditáveis, em tempo real'] },
      { kicker: 'Fluxo de vendas', title: 'Do orçamento à fatura, sem reescrever.',
        body: 'Um documento, quatro estados — orçamento, encomenda, guia e fatura. Os dados seguem o negócio; ninguém volta a introduzi-los.',
        points: ['Orçamento → encomenda → guia → fatura', 'Sem reintroduzir dados em cada passo', 'Margem visível em todas as fases'] },
      { kicker: 'Pipeline comercial', title: 'O funil de vendas, à vista de todos.',
        body: 'Oportunidades arrastam-se entre fases — contagens e totais atualizam ao largar. A equipa comercial sabe sempre o que está em jogo.',
        points: ['Fases configuráveis por equipa', 'Totais e contagens em tempo real', 'Do contacto à encomenda ganha'] },
      { kicker: 'Calendários de obra', title: 'A obra manda no calendário.',
        body: 'Semanas de trabalho, folgas e feriados regionais — mude o calendário e o agendamento reorganiza as atividades da obra automaticamente.',
        points: ['Feriados do Continente, Madeira e Açores', 'Agendamento CPM que reage a mudanças', 'Equipas e cargas de trabalho visíveis'] },
      { kicker: 'Portal B2B · em desenvolvimento', title: 'Os seus clientes encomendam sozinhos.',
        body: 'Empreiteiros e construtoras entram no portal, vêem os preços acordados e o stock em tempo real, e encomendam sem um único telefonema.',
        points: ['Preços por contrato, por cliente', 'Stock em tempo real', 'Histórico e estado das entregas'] },
    ],
    ai: {
      chip: 'Assistente IA',
      h2a: 'Pergunte em português.', h2b: 'Ele conhece as suas obras.',
      sub: 'O assistente tem contexto das suas encomendas, faturas, fornecedores e obras. Pergunte naturalmente. Peça-lhe para agir. Confirma sempre antes de escrever.',
      frame: 'ConstructHub · Assistente',
      points: [
        { i: 'message-circle-question', t: 'Pergunte qualquer coisa', s: '“Que obra teve mais margem no último trimestre?” “Quem aprovou a EC-0241?”' },
        { i: 'wand-2', t: 'Peça acções', s: '“Repete a encomenda do Machico para a próxima semana.” “Compõe email à Tabique sobre o IVA.”' },
        { i: 'shield-check', t: 'Privado por padrão', s: 'O assistente vê apenas os módulos que autorizar, definidos por papel.' },
        { i: 'check-circle-2', t: 'Confirma antes de escrever', s: 'Encomendas, faturas, emails — o resultado é-lhe sempre apresentado para aprovação.' },
      ],
    },
    pricing: {
      kicker: 'Planos', h2: 'Três planos. Sem surpresas.',
      sub: <>Os preços finais serão anunciados com o lançamento público, no <strong>outono de 2026</strong>. Subscreva as novidades e seja o primeiro a saber.</>,
      price: 'Sob consulta', priceNote: 'A anunciar no lançamento',
      ctaNews: 'Receber novidades', ctaTalk: 'Falar connosco', recommended: 'Recomendado',
      footnote: 'Todos os planos incluem AT e-fatura, SAF-T PT, RGPD, suporte em português, actualizações grátis.',
      plans: [
        { name: 'Loja', sub: 'Para uma loja única, equipa pequena.',
          points: ['Build + Portal', 'Facturação AT', 'Assistente IA — uso básico', 'Suporte por email'] },
        { name: 'Distribuidor', sub: 'Multi-armazém, multi-loja.', recommended: true,
          points: ['Tudo do plano Loja', 'Equipa alargada', 'Multi-armazém', 'Assistente IA — uso intensivo', 'Suporte prioritário'] },
        { name: 'Grupo', sub: 'Cadeias e grupos com SLA dedicado.',
          points: ['Implementação acompanhada', 'Assistente IA dedicado', 'Suporte dedicado', 'SLA contratual'] },
      ],
    },
    faq: {
      kicker: 'Perguntas frequentes', h2: 'Tudo o que precisa de saber.',
      qs: [
        { q: 'Funciona com a Autoridade Tributária?', a: 'Sim. Comunicação directa com a AT — séries, faturas e guias de transporte — com ATCUD e QR em cada documento e SAF-T PT exportável em 1 clique. A certificação de software AT está em curso para o lançamento.' },
        { q: 'Posso migrar do Primavera / Sage / PHC?', a: 'A migração é acompanhada pela equipa: importamos catálogo e clientes a partir de Excel durante o onboarding. Ligações directas a Primavera, Sage ou PHC estão no roadmap.' },
        { q: 'O assistente IA vê os meus dados?', a: 'Apenas o que autoriza. Pode definir por papel a que módulos o assistente tem acesso — e antes de qualquer alteração, o assistente apresenta-lhe sempre o resultado para aprovação.' },
        { q: 'Funciona offline na obra?', a: 'É uma aplicação web leve, pensada para o 3G/4G da obra. O modo offline do Portal está no roadmap.' },
        { q: 'Quantos utilizadores posso ter?', a: 'Os limites por plano serão anunciados com os preços, no lançamento. Em todos os planos terá papéis e permissões — admin, comprador, chefe de obra, financeiro.' },
      ],
    },
    news: {
      chip: 'Novidades · lançamento',
      h2a: 'Avisamos quando', h2b: 'lançarmos.',
      sub: <>O ConstructHub chega no <strong className="text-white">outono de 2026</strong> — primeiro na Madeira. Deixe o seu email para receber as novidades do produto e a data de lançamento. Sem spam; pode cancelar a qualquer momento.</>,
      placeholder: 'o-seu@email.pt', button: 'Avisar-me', sending: '…',
      consent: 'Aceito receber novidades por email (RGPD). Pode cancelar a qualquer momento.',
      done: 'Verifique o seu email para confirmar a subscrição.',
      error: 'Verifique o email e o consentimento.',
      prefer: 'Prefere falar connosco?', book: 'Marcar 30 minutos',
    },
    footer: {
      tagline: 'A plataforma de gestão para quem vende materiais de construção. Feita na Madeira, em português.',
      cols: [
        { t: 'Produto', items: [['Faturação AT', '#produto'], ['Stock multi-armazém', '#produto'], ['Portal B2B', '#produto'], ['Assistente IA', '#ia'], ['Planos', '#planos']] },
        { t: 'Sector', items: [['Distribuidores', '#'], ['Retalhistas', '#'], ['Fabricantes', '#'], ['Empreiteiros', '#'], ['Sucessos', '#']] },
        { t: 'Empresa', items: [['Sobre nós', '#'], ['Carreiras', '#'], ['Imprensa', '#'], ['Contacto', '#novidades'], ['Novidades', '#novidades']] },
        { t: 'Legal', items: [['Privacidade', '#'], ['Termos', '#'], ['RGPD', '#'], ['Segurança', '#'], ['SAF-T PT', '#']] },
      ],
      copyright: '© 2026 ConstructHub · Madeira, Portugal',
      status: 'Sistema operacional',
    },
    mail: {
      demo: { subject: 'ConstructHub · pedido de demonstração',
        body: ['Olá equipa ConstructHub,', '', 'Gostaria de marcar uma demonstração do produto.', '', 'Nome: ', 'Empresa: ', 'Disponibilidade (datas/horas): ', 'Telefone (opcional): ', '', 'Obrigado.'] },
      talk: { subject: 'ConstructHub · marcar 30 minutos',
        body: ['Olá equipa ConstructHub,', '', 'Gostaria de marcar uma conversa de 30 minutos para conhecer melhor o produto.', '', 'Nome: ', 'Empresa: ', 'Disponibilidade (datas/horas): ', 'Telefone (opcional): ', '', 'Obrigado.'] },
    },
  },

  en: {
    nav: { links: [['Product', '#produto'], ['AI Assistant', '#ia'], ['Plans', '#planos'], ['FAQ', '#faq']], cta: 'Get updates' },
    hero: {
      chip: 'Launching · autumn 2026 · Madeira first',
      rotor: ['stock', 'orders', 'invoicing', 'projects'],
      h1Pre: 'Managing', h1Mid: 'built for those who', h1End: 'build in Madeira.',
      sub: <>Real-time stock, paperless ordering and <strong className="text-white font-semibold">AT invoicing with ATCUD, QR and SAF-T</strong> — a management platform built from scratch for construction-material distributors and retailers.</>,
      ctaProduct: 'See the product', ctaNews: 'Get updates',
      trust: ['AT e-fatura', 'SAF-T PT', 'PT · EN · ES', 'GDPR'],
      frame: 'ConstructHub · Invoicing',
    },
    badge: 'demo',
    numbers: [
      { n: 'PT·EN·ES', l: 'available in three languages' },
      { n: '4/12/22', l: 'native Madeira VAT rates' },
      { n: '1 click', l: 'SAF-T PT export' },
      { n: '€0', l: 'to get started, no card' },
    ],
    problem: {
      kicker: 'The problem',
      h2: 'Generic software doesn’t understand your business.',
      p1: 'International platforms were designed to sell books or software — not cement, sand or steel. They don’t talk to the Portuguese tax authority (AT), don’t export SAF-T PT, don’t understand reduced VAT on renovation work, and treat a contractor like a retail consumer.',
      p2: 'The legacy Portuguese systems speak the language — but they live in Windows-2000-era screens, don’t work on a site manager’s phone, and the catalogue is an Excel sheet.',
      p3: 'ConstructHub is a third option. A modern, cloud-based management platform in European Portuguese, built from scratch for how the sector works — starting in Madeira.',
    },
    chaptersIntro: {
      chip: 'Product',
      h2: 'ConstructHub in action.',
      sub: 'Six demos of the core flows — from quote to AT-ready invoice. To see it with your company’s data, request a demo.',
      cta: 'Request a demo',
    },
    chapters: [
      { kicker: 'AT invoicing', title: 'From sale to ATCUD in seconds.',
        body: 'Native e-fatura — no exports, no middleware. Every document ships with an AT-registered series, immutable hash and QR code, ready for the tax authority.',
        points: ['AT-registered series with immutable RSA hash', 'ATCUD + QR on every document', 'SAF-T PT in one click'] },
      { kicker: 'Multi-warehouse stock', title: 'Stock you can trust.',
        body: 'Every movement is recorded in an immutable ledger. Transfers between stores, warehouses and site yards with request and approval — and a live view of what’s where.',
        points: ['Multi-store, multi-warehouse, site yards', 'Transfers with request and approval', 'Auditable movements, in real time'] },
      { kicker: 'Sales flow', title: 'From quote to invoice, nothing retyped.',
        body: 'One document, four states — quote, order, delivery note, invoice. The data follows the deal; nobody enters it twice.',
        points: ['Quote → order → delivery note → invoice', 'No re-entering data at any step', 'Margin visible at every stage'] },
      { kicker: 'Sales pipeline', title: 'The sales funnel, visible to everyone.',
        body: 'Drag opportunities between stages — counts and totals update on drop. The sales team always knows what’s in play.',
        points: ['Stages configurable per team', 'Live totals and counts', 'From first contact to won order'] },
      { kicker: 'Project calendars', title: 'The job site sets the schedule.',
        body: 'Working weeks, days off and regional holidays — change the calendar and the schedule reorganises the project’s activities automatically.',
        points: ['Mainland, Madeira and Azores holidays', 'CPM scheduling that reacts to change', 'Teams and workloads at a glance'] },
      { kicker: 'B2B portal · in development', title: 'Your customers order by themselves.',
        body: 'Contractors and builders log into the portal, see their agreed prices and live stock, and place orders without a single phone call.',
        points: ['Contract pricing per customer', 'Real-time stock', 'Order history and delivery status'] },
    ],
    ai: {
      chip: 'AI Assistant',
      h2a: 'Ask in plain language.', h2b: 'It knows your projects.',
      sub: 'The assistant has context on your orders, invoices, suppliers and projects. Ask naturally. Ask it to act. It always confirms before writing anything.',
      frame: 'ConstructHub · Assistant',
      points: [
        { i: 'message-circle-question', t: 'Ask anything', s: '“Which project had the best margin last quarter?” “Who approved EC-0241?”' },
        { i: 'wand-2', t: 'Ask for actions', s: '“Repeat the Machico order for next week.” “Draft an email to Tabique about the VAT.”' },
        { i: 'shield-check', t: 'Private by default', s: 'The assistant only sees the modules you authorise, defined per role.' },
        { i: 'check-circle-2', t: 'Confirms before writing', s: 'Orders, invoices, emails — the result is always shown to you for approval first.' },
      ],
    },
    pricing: {
      kicker: 'Plans', h2: 'Three plans. No surprises.',
      sub: <>Final pricing will be announced at the public launch, in <strong>autumn 2026</strong>. Subscribe to updates and be the first to know.</>,
      price: 'On request', priceNote: 'Announced at launch',
      ctaNews: 'Get updates', ctaTalk: 'Talk to us', recommended: 'Recommended',
      footnote: 'All plans include AT e-fatura, SAF-T PT, GDPR, support in Portuguese, free updates.',
      plans: [
        { name: 'Store', sub: 'For a single store, small team.',
          points: ['Build + Portal', 'AT invoicing', 'AI Assistant — basic usage', 'Email support'] },
        { name: 'Distributor', sub: 'Multi-warehouse, multi-store.', recommended: true,
          points: ['Everything in Store', 'Larger team', 'Multi-warehouse', 'AI Assistant — heavy usage', 'Priority support'] },
        { name: 'Group', sub: 'Chains and groups with a dedicated SLA.',
          points: ['Guided implementation', 'Dedicated AI Assistant', 'Dedicated support', 'Contractual SLA'] },
      ],
    },
    faq: {
      kicker: 'Frequently asked questions', h2: 'Everything you need to know.',
      qs: [
        { q: 'Does it work with the Portuguese tax authority (AT)?', a: 'Yes. Direct communication with the AT — series, invoices and transport documents — with ATCUD and QR on every document and SAF-T PT exportable in one click. AT software certification is underway for launch.' },
        { q: 'Can I migrate from Primavera / Sage / PHC?', a: 'Migration is guided by our team: we import your catalogue and customers from Excel during onboarding. Direct connections to Primavera, Sage or PHC are on the roadmap.' },
        { q: 'Does the AI assistant see my data?', a: 'Only what you authorise. You can define per role which modules the assistant can access — and before any change, the assistant always shows you the result for approval.' },
        { q: 'Does it work offline on site?', a: 'It’s a lightweight web app, built for the 3G/4G you get on site. Offline mode for the Portal is on the roadmap.' },
        { q: 'How many users can I have?', a: 'Per-plan limits will be announced with pricing at launch. Every plan includes roles and permissions — admin, buyer, site manager, finance.' },
      ],
    },
    news: {
      chip: 'Updates · launch',
      h2a: 'We’ll let you know', h2b: 'when we launch.',
      sub: <>ConstructHub arrives in <strong className="text-white">autumn 2026</strong> — Madeira first. Leave your email to get product updates and the launch date. No spam; unsubscribe anytime.</>,
      placeholder: 'your@email.com', button: 'Notify me', sending: '…',
      consent: 'I agree to receive updates by email (GDPR). You can unsubscribe at any time.',
      done: 'Check your inbox to confirm the subscription.',
      error: 'Please check the email and the consent box.',
      prefer: 'Prefer to talk to us?', book: 'Book 30 minutes',
    },
    footer: {
      tagline: 'The management platform for construction-material sellers. Made in Madeira, in Portuguese.',
      cols: [
        { t: 'Product', items: [['AT invoicing', '#produto'], ['Multi-warehouse stock', '#produto'], ['B2B portal', '#produto'], ['AI Assistant', '#ia'], ['Plans', '#planos']] },
        { t: 'Sector', items: [['Distributors', '#'], ['Retailers', '#'], ['Manufacturers', '#'], ['Contractors', '#'], ['Stories', '#']] },
        { t: 'Company', items: [['About us', '#'], ['Careers', '#'], ['Press', '#'], ['Contact', '#novidades'], ['Updates', '#novidades']] },
        { t: 'Legal', items: [['Privacy', '#'], ['Terms', '#'], ['GDPR', '#'], ['Security', '#'], ['SAF-T PT', '#']] },
      ],
      copyright: '© 2026 ConstructHub · Madeira, Portugal',
      status: 'All systems operational',
    },
    mail: {
      demo: { subject: 'ConstructHub · demo request',
        body: ['Hello ConstructHub team,', '', 'I would like to book a product demo.', '', 'Name: ', 'Company: ', 'Availability (dates/times): ', 'Phone (optional): ', '', 'Thank you.'] },
      talk: { subject: 'ConstructHub · book 30 minutes',
        body: ['Hello ConstructHub team,', '', 'I would like to book a 30-minute call to learn more about the product.', '', 'Name: ', 'Company: ', 'Availability (dates/times): ', 'Phone (optional): ', '', 'Thank you.'] },
    },
  },

  es: {
    nav: { links: [['Producto', '#produto'], ['Asistente IA', '#ia'], ['Planes', '#planos'], ['FAQ', '#faq']], cta: 'Recibir novedades' },
    hero: {
      chip: 'Lanzamiento · otoño de 2026 · Madeira primero',
      rotor: ['stock', 'pedidos', 'facturación', 'obras'],
      h1Pre: 'Gestión de', h1Mid: 'pensada para quien', h1End: 'construye en Madeira.',
      sub: <>Stock en tiempo real, pedidos sin papel y <strong className="text-white font-semibold">facturación AT con ATCUD, QR y SAF-T</strong> — una plataforma de gestión hecha desde cero para distribuidores y minoristas de materiales de construcción.</>,
      ctaProduct: 'Ver el producto', ctaNews: 'Recibir novedades',
      trust: ['AT e-fatura', 'SAF-T PT', 'PT · EN · ES', 'RGPD'],
      frame: 'ConstructHub · Facturación',
    },
    badge: 'demo',
    numbers: [
      { n: 'PT·EN·ES', l: 'disponible en tres idiomas' },
      { n: '4/12/22', l: 'IVA de Madeira nativo' },
      { n: '1 clic', l: 'exportación SAF-T PT' },
      { n: '0 €', l: 'para empezar, sin tarjeta' },
    ],
    problem: {
      kicker: 'El problema',
      h2: 'El software genérico no entiende su negocio.',
      p1: 'Las plataformas internacionales fueron diseñadas para vender libros o software — no cemento, arena o acero. No hablan con la agencia tributaria portuguesa (AT), no exportan SAF-T PT, no entienden el IVA reducido en obras de rehabilitación, y tratan a un contratista como si fuera un consumidor final.',
      p2: 'Los sistemas portugueses antiguos hablan el idioma — pero viven en ventanas de Windows de los años 2000, no funcionan en el móvil del jefe de obra, y el catálogo es una hoja de Excel.',
      p3: 'ConstructHub es una tercera opción. Una plataforma de gestión moderna, en la nube, hecha desde cero para la forma en que trabaja el sector — empezando por Madeira.',
    },
    chaptersIntro: {
      chip: 'Producto',
      h2: 'ConstructHub en acción.',
      sub: 'Seis demostraciones de los flujos principales — del presupuesto a la factura lista para la AT. Para verlo con los datos de su empresa, pida una demostración.',
      cta: 'Pedir una demostración',
    },
    chapters: [
      { kicker: 'Facturación AT', title: 'De la venta al ATCUD en segundos.',
        body: 'E-fatura nativo, sin exportaciones ni software intermedio. Cada documento sale con serie registrada en la AT, hash inmutable y QR — listo para la AT.',
        points: ['Series registradas en la AT y hash RSA inmutable', 'ATCUD + QR en cada documento', 'SAF-T PT en un clic'] },
      { kicker: 'Stock multi-almacén', title: 'Stock fiable.',
        body: 'Cada movimiento queda registrado en un libro mayor inmutable. Transferencias entre tiendas, almacenes y obras con solicitud y aprobación — y visión en tiempo real de lo que hay en cada sitio.',
        points: ['Multi-tienda, multi-almacén, obras', 'Transferencias con solicitud y aprobación', 'Movimientos auditables, en tiempo real'] },
      { kicker: 'Flujo de ventas', title: 'Del presupuesto a la factura, sin reescribir.',
        body: 'Un documento, cuatro estados — presupuesto, pedido, albarán y factura. Los datos siguen al negocio; nadie vuelve a introducirlos.',
        points: ['Presupuesto → pedido → albarán → factura', 'Sin reintroducir datos en cada paso', 'Margen visible en todas las fases'] },
      { kicker: 'Pipeline comercial', title: 'El embudo de ventas, a la vista de todos.',
        body: 'Las oportunidades se arrastran entre fases — los recuentos y totales se actualizan al soltar. El equipo comercial siempre sabe qué está en juego.',
        points: ['Fases configurables por equipo', 'Totales y recuentos en tiempo real', 'Del contacto al pedido ganado'] },
      { kicker: 'Calendarios de obra', title: 'La obra manda en el calendario.',
        body: 'Semanas de trabajo, descansos y festivos regionales — cambie el calendario y la planificación reorganiza las actividades de la obra automáticamente.',
        points: ['Festivos del continente, Madeira y Azores', 'Planificación CPM que reacciona a los cambios', 'Equipos y cargas de trabajo visibles'] },
      { kicker: 'Portal B2B · en desarrollo', title: 'Sus clientes piden solos.',
        body: 'Contratistas y constructoras entran en el portal, ven los precios acordados y el stock en tiempo real, y hacen pedidos sin una sola llamada.',
        points: ['Precios por contrato, por cliente', 'Stock en tiempo real', 'Histórico y estado de las entregas'] },
    ],
    ai: {
      chip: 'Asistente IA',
      h2a: 'Pregunte con naturalidad.', h2b: 'Conoce sus obras.',
      sub: 'El asistente tiene contexto de sus pedidos, facturas, proveedores y obras. Pregunte con naturalidad. Pídale que actúe. Siempre confirma antes de escribir.',
      frame: 'ConstructHub · Asistente',
      points: [
        { i: 'message-circle-question', t: 'Pregunte cualquier cosa', s: '“¿Qué obra tuvo más margen el último trimestre?” “¿Quién aprobó la EC-0241?”' },
        { i: 'wand-2', t: 'Pida acciones', s: '“Repite el pedido de Machico para la próxima semana.” “Redacta un email a Tabique sobre el IVA.”' },
        { i: 'shield-check', t: 'Privado por defecto', s: 'El asistente solo ve los módulos que usted autorice, definidos por rol.' },
        { i: 'check-circle-2', t: 'Confirma antes de escribir', s: 'Pedidos, facturas, emails — el resultado siempre se le presenta para su aprobación.' },
      ],
    },
    pricing: {
      kicker: 'Planes', h2: 'Tres planes. Sin sorpresas.',
      sub: <>Los precios finales se anunciarán con el lanzamiento público, en <strong>otoño de 2026</strong>. Suscríbase a las novedades y sea el primero en saberlo.</>,
      price: 'A consultar', priceNote: 'Se anunciará en el lanzamiento',
      ctaNews: 'Recibir novedades', ctaTalk: 'Hablar con nosotros', recommended: 'Recomendado',
      footnote: 'Todos los planes incluyen AT e-fatura, SAF-T PT, RGPD, soporte en portugués y actualizaciones gratis.',
      plans: [
        { name: 'Tienda', sub: 'Para una tienda única, equipo pequeño.',
          points: ['Build + Portal', 'Facturación AT', 'Asistente IA — uso básico', 'Soporte por email'] },
        { name: 'Distribuidor', sub: 'Multi-almacén, multi-tienda.', recommended: true,
          points: ['Todo lo del plan Tienda', 'Equipo ampliado', 'Multi-almacén', 'Asistente IA — uso intensivo', 'Soporte prioritario'] },
        { name: 'Grupo', sub: 'Cadenas y grupos con SLA dedicado.',
          points: ['Implantación acompañada', 'Asistente IA dedicado', 'Soporte dedicado', 'SLA contractual'] },
      ],
    },
    faq: {
      kicker: 'Preguntas frecuentes', h2: 'Todo lo que necesita saber.',
      qs: [
        { q: '¿Funciona con la agencia tributaria portuguesa (AT)?', a: 'Sí. Comunicación directa con la AT — series, facturas y documentos de transporte — con ATCUD y QR en cada documento y SAF-T PT exportable en un clic. La certificación de software AT está en curso para el lanzamiento.' },
        { q: '¿Puedo migrar desde Primavera / Sage / PHC?', a: 'La migración la acompaña nuestro equipo: importamos el catálogo y los clientes desde Excel durante el onboarding. Las conexiones directas a Primavera, Sage o PHC están en el roadmap.' },
        { q: '¿El asistente IA ve mis datos?', a: 'Solo lo que usted autorice. Puede definir por rol a qué módulos accede el asistente — y antes de cualquier cambio, el asistente siempre le presenta el resultado para su aprobación.' },
        { q: '¿Funciona sin conexión en la obra?', a: 'Es una aplicación web ligera, pensada para el 3G/4G de la obra. El modo sin conexión del Portal está en el roadmap.' },
        { q: '¿Cuántos usuarios puedo tener?', a: 'Los límites por plan se anunciarán con los precios, en el lanzamiento. Todos los planes incluyen roles y permisos — admin, comprador, jefe de obra, financiero.' },
      ],
    },
    news: {
      chip: 'Novedades · lanzamiento',
      h2a: 'Le avisamos cuando', h2b: 'lancemos.',
      sub: <>ConstructHub llega en <strong className="text-white">otoño de 2026</strong> — primero en Madeira. Deje su email para recibir las novedades del producto y la fecha de lanzamiento. Sin spam; puede cancelar en cualquier momento.</>,
      placeholder: 'su@email.es', button: 'Avisarme', sending: '…',
      consent: 'Acepto recibir novedades por email (RGPD). Puede cancelar en cualquier momento.',
      done: 'Revise su email para confirmar la suscripción.',
      error: 'Compruebe el email y el consentimiento.',
      prefer: '¿Prefiere hablar con nosotros?', book: 'Reservar 30 minutos',
    },
    footer: {
      tagline: 'La plataforma de gestión para quien vende materiales de construcción. Hecha en Madeira, en portugués.',
      cols: [
        { t: 'Producto', items: [['Facturación AT', '#produto'], ['Stock multi-almacén', '#produto'], ['Portal B2B', '#produto'], ['Asistente IA', '#ia'], ['Planes', '#planos']] },
        { t: 'Sector', items: [['Distribuidores', '#'], ['Minoristas', '#'], ['Fabricantes', '#'], ['Contratistas', '#'], ['Casos', '#']] },
        { t: 'Empresa', items: [['Sobre nosotros', '#'], ['Empleo', '#'], ['Prensa', '#'], ['Contacto', '#novidades'], ['Novedades', '#novidades']] },
        { t: 'Legal', items: [['Privacidad', '#'], ['Términos', '#'], ['RGPD', '#'], ['Seguridad', '#'], ['SAF-T PT', '#']] },
      ],
      copyright: '© 2026 ConstructHub · Madeira, Portugal',
      status: 'Sistema en funcionamiento',
    },
    mail: {
      demo: { subject: 'ConstructHub · solicitud de demostración',
        body: ['Hola equipo de ConstructHub,', '', 'Me gustaría reservar una demostración del producto.', '', 'Nombre: ', 'Empresa: ', 'Disponibilidad (fechas/horas): ', 'Teléfono (opcional): ', '', 'Gracias.'] },
      talk: { subject: 'ConstructHub · reservar 30 minutos',
        body: ['Hola equipo de ConstructHub,', '', 'Me gustaría reservar una llamada de 30 minutos para conocer mejor el producto.', '', 'Nombre: ', 'Empresa: ', 'Disponibilidad (fechas/horas): ', 'Teléfono (opcional): ', '', 'Gracias.'] },
    },
  },
};

const LANGS = ['pt', 'en', 'es'];
const HTML_LANG = { pt: 'pt-PT', en: 'en', es: 'es' };

const LangCtx = React.createContext({ lang: 'pt', t: I18N.pt, setLang: () => {} });
function useT() { return React.useContext(LangCtx); }

function initialLang() {
  try {
    const q = new URLSearchParams(window.location.search).get('lang');
    if (q && LANGS.includes(q)) return q;
    const saved = window.localStorage.getItem('ch-lang');
    if (saved && LANGS.includes(saved)) return saved;
  } catch (_) { /* sandboxed iframe etc. */ }
  return 'pt';
}

// ─── Page-scoped CSS ──────────────────────────────────────────────────
// Lives inside the component tree so every host (artboard or full page)
// gets the motion primitives — including the demo-* keyframes the ./demos
// components require — without editing the host's <head>.
function LandingStyles() {
  return (
    <style>{`
      .ch-display { font-family: ${DISPLAY_FONT}; }
      html, .dc-landing { scroll-behavior: smooth; }
      section[id], header[id] { scroll-margin-top: 76px; }

      /* scroll-reveal */
      .ch-reveal { opacity: 0; transform: translateY(26px); }
      .ch-reveal.ch-on { opacity: 1; transform: none; transition: opacity .8s ease, transform .8s cubic-bezier(.2,.8,.2,1); }
      @media (prefers-reduced-motion: reduce) {
        .ch-reveal { opacity: 1; transform: none; }
      }

      /* hero glows drift slowly */
      @keyframes ch-glow { from { transform: translate(0,0) scale(1); } to { transform: translate(-40px,30px) scale(1.15); } }
      .ch-glow { animation: ch-glow 14s ease-in-out infinite alternate; }
      @keyframes ch-glow-alt { from { transform: translate(0,0) scale(1.1); } to { transform: translate(50px,-25px) scale(0.95); } }
      .ch-glow-alt { animation: ch-glow-alt 18s ease-in-out infinite alternate; }

      /* hero product frame: gentle float (no rotation — tilting rasterizes
         the demo text off the pixel grid and it goes blurry) */
      @keyframes ch-float { from { transform: translateY(0); } to { transform: translateY(-10px); } }
      .ch-float { animation: ch-float 6s ease-in-out infinite alternate; }
      @media (prefers-reduced-motion: reduce) { .ch-glow, .ch-glow-alt, .ch-float { animation: none; } }

      /* rotating hero word */
      .ch-rotor { display: inline-grid; overflow: hidden; vertical-align: bottom; }
      .ch-rotor > span { grid-area: 1 / 1; transition: transform .55s cubic-bezier(.3,.8,.2,1), opacity .4s; will-change: transform; }

      /* pulsing status dot */
      @keyframes ch-pulse { 0%,100% { opacity: 1; } 50% { opacity: .35; } }
      [data-pulse] { animation: ch-pulse 2.2s ease-in-out infinite; }

      /* ── demo motion primitives (required by ./demos components) ── */
      .demo-caret { display: inline-block; width: 1.5px; height: 14px; margin-left: 1px; animation: demo-blink 1s steps(2) infinite; }
      @keyframes demo-blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }
      .demo-rise { animation: demo-rise .45s cubic-bezier(.2,.8,.2,1) both; }
      @keyframes demo-rise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
      .demo-stamp { animation: demo-stamp .5s cubic-bezier(.2,1.4,.3,1) both; transform: rotate(-4deg); }
      @keyframes demo-stamp { from { opacity: 0; transform: rotate(-4deg) scale(1.6); } to { opacity: 1; transform: rotate(-4deg) scale(1); } }
      .demo-ripple { position: absolute; left: -14px; top: -16px; width: 36px; height: 36px; border-radius: 9999px; border: 2px solid #4F6EF7; animation: demo-ripple .55s ease-out both; pointer-events: none; }
      @keyframes demo-ripple { from { opacity: .9; transform: scale(.3); } to { opacity: 0; transform: scale(1); } }
      .demo-pulse { animation: demo-pulse .6s ease-out both; }
      @keyframes demo-pulse { from { box-shadow: 0 0 0 0 rgba(16,185,129,.45); } to { box-shadow: 0 0 0 14px rgba(16,185,129,0); } }
      .demo-dot { width: 5px; height: 5px; border-radius: 9999px; background: #A1A1AA; display: inline-block; animation: demo-dot 1s infinite ease-in-out; }
      @keyframes demo-dot { 0%,100% { opacity: .3; transform: translateY(0); } 50% { opacity: 1; transform: translateY(-3px); } }
    `}</style>
  );
}

// ─── Motion helpers ───────────────────────────────────────────────────
// Adds .ch-on when the element enters the viewport (once). Children get
// the .ch-reveal class; `delay` staggers via transition-delay.
function Reveal({ as = 'div', className = '', delay = 0, children, ...rest }) {
  const ref = React.useRef(null);
  React.useEffect(() => {
    const el = ref.current;
    if (!el) return;
    if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) { el.classList.add('ch-on'); return; }
    const io = new IntersectionObserver(([e]) => {
      if (!e.isIntersecting) return;
      io.disconnect();
      el.classList.add('ch-on');
    }, { threshold: 0.15 });
    io.observe(el);
    return () => io.disconnect();
  }, []);
  return React.createElement(as, {
    ref,
    className: 'ch-reveal ' + className,
    style: delay ? { transitionDelay: delay + 'ms' } : undefined,
    ...rest,
  }, children);
}

// Counts from 0 when scrolled into view; honours prefers-reduced-motion.
function CountUp({ to, render, duration = 1400 }) {
  const ref = React.useRef(null);
  const [val, setVal] = React.useState(0);
  React.useEffect(() => {
    const el = ref.current;
    if (!el) return;
    if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) { setVal(to); return; }
    const io = new IntersectionObserver(([e]) => {
      if (!e.isIntersecting) return;
      io.disconnect();
      const t0 = performance.now();
      const tick = (t) => {
        const p = Math.min(1, (t - t0) / duration);
        setVal(Math.round(to * (1 - Math.pow(1 - p, 3))));
        if (p < 1) requestAnimationFrame(tick);
      };
      requestAnimationFrame(tick);
    }, { threshold: 0.4 });
    io.observe(el);
    return () => io.disconnect();
  }, [to, duration]);
  return <span ref={ref}>{render(val)}</span>;
}

// Vertically rotating word for the hero H1.
function RotorWord({ words, interval = 2600 }) {
  const [i, setI] = React.useState(0);
  React.useEffect(() => {
    setI(0); // restart cleanly when the language (word list) changes
    if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
    const id = setInterval(() => setI((v) => (v + 1) % words.length), interval);
    return () => clearInterval(id);
  }, [words, interval]);
  return (
    <span className="ch-rotor" aria-live="off">
      {words.map((w, k) => (
        <span key={w} aria-hidden={k !== i}
              style={{
                transform: 'translateY(' + (k === i ? 0 : (k < i ? -110 : 110)) + '%)',
                opacity: k === i ? 1 : 0,
                color: INDIGO,
              }}>{w}</span>
      ))}
    </span>
  );
}

// Live demo from ./demos, read off window with a graceful placeholder.
function LiveDemo({ name }) {
  const C = window[name];
  if (typeof C !== 'function') {
    return (
      <div className="h-[320px] grid place-items-center text-[12px] text-zinc-400 bg-zinc-50">
        demo «{name}» não carregada
      </div>
    );
  }
  return <C />;
}

// Browser-style frame around a demo, with the "demo" badge.
function DemoFrame({ title, name, badge }) {
  return (
    <React.Fragment>
      <div className="h-9 px-3.5 flex items-center gap-2 border-b border-zinc-100 bg-zinc-50">
        <span className="h-2.5 w-2.5 rounded-full bg-zinc-200"></span>
        <span className="h-2.5 w-2.5 rounded-full bg-zinc-200"></span>
        <span className="h-2.5 w-2.5 rounded-full bg-zinc-200"></span>
        <span className="text-[11px] text-zinc-500 ml-1.5 font-medium">{title}</span>
        <span className="ml-auto inline-flex items-center gap-1.5 text-[10px] font-semibold uppercase tracking-[0.1em] text-emerald-600">
          <span data-pulse className="h-1.5 w-1.5 rounded-full bg-emerald-500"></span>
          {badge}
        </span>
      </div>
      <LiveDemo name={name} />
    </React.Fragment>
  );
}

// ─── Floating nav pill (with language switcher) ───────────────────────
function LangSwitch() {
  const { lang, setLang } = useT();
  return (
    <div className="flex items-center rounded-full border border-white/10 bg-white/[0.06] p-0.5 ml-1">
      {LANGS.map((l) => (
        <button key={l} onClick={() => setLang(l)}
                aria-pressed={l === lang}
                className={'h-7 px-2.5 rounded-full text-[11px] font-semibold uppercase tracking-wide transition-colors ' +
                  (l === lang ? 'text-zinc-950 bg-white' : 'text-white/55 hover:text-white')}>
          {l}
        </button>
      ))}
    </div>
  );
}

function NavPill() {
  const { t } = useT();
  return (
    <div className="sticky top-3 z-50 flex justify-center px-4 pointer-events-none">
      <nav className="pointer-events-auto flex items-center gap-1 h-12 pl-3 pr-1.5 rounded-full border border-white/10 backdrop-blur-xl"
           style={{ background: 'rgba(9,9,12,0.82)', boxShadow: '0 12px 32px -12px rgba(0,0,0,0.5)' }}>
        <a href="#topo" className="flex items-center gap-2 mr-2">
          <span className="h-7 w-7 rounded-md grid place-items-center font-bold text-[12px]" style={{ background: 'white', color: '#0B0B0F' }}>CH</span>
          <span className="text-[13.5px] font-semibold tracking-tight text-white hidden sm:inline">ConstructHub</span>
        </a>
        <div className="hidden md:flex items-center">
          {t.nav.links.map(([label, href]) => (
            <a key={href} href={href} className="h-9 px-3.5 rounded-full inline-flex items-center text-[12.5px] font-medium text-white/65 hover:text-white hover:bg-white/10 transition-colors">{label}</a>
          ))}
        </div>
        <LangSwitch />
        <a href="#novidades"
           className="ml-1 h-9 px-4 rounded-full text-[12.5px] font-semibold inline-flex items-center gap-1.5 text-white transition-all hover:brightness-110"
           style={{ background: INDIGO }}>
          {t.nav.cta}
          <L name="arrow-right" className="w-3.5 h-3.5" />
        </a>
      </nav>
    </div>
  );
}

// ─── Hero — dark, cinematic, with the live invoice demo ──────────────
function HeroDark() {
  const { t } = useT();
  return (
    <header id="topo" className="relative w-full overflow-hidden -mt-[60px]" style={{ background: '#09090C', color: 'white' }}>
      {/* blueprint grid */}
      <svg className="absolute inset-0 w-full h-full pointer-events-none" aria-hidden="true"
           style={{ opacity: 0.10, maskImage: 'radial-gradient(ellipse 90% 70% at 50% 0%, black 35%, transparent 80%)' }}>
        <defs>
          <pattern id="ch-bp-grid" width="44" height="44" patternUnits="userSpaceOnUse">
            <path d="M 44 0 L 0 0 0 44" fill="none" stroke="white" strokeWidth="1" />
          </pattern>
        </defs>
        <rect width="100%" height="100%" fill="url(#ch-bp-grid)" />
      </svg>
      {/* drifting glows */}
      <div className="absolute -top-40 -right-24 w-[640px] h-[640px] rounded-full pointer-events-none ch-glow"
           style={{ background: 'radial-gradient(circle, rgba(79,110,247,0.45) 0%, transparent 62%)' }}></div>
      <div className="absolute -bottom-48 -left-48 w-[560px] h-[560px] rounded-full pointer-events-none ch-glow-alt"
           style={{ background: 'radial-gradient(circle, rgba(45,212,191,0.16) 0%, transparent 60%)' }}></div>

      <div className="relative max-w-[1200px] mx-auto px-5 sm:px-8 pt-28 sm:pt-32 pb-16 sm:pb-20">
        <div className="grid lg:grid-cols-12 gap-12 lg:gap-8 items-center">
          {/* Copy */}
          <div className="lg:col-span-6">
            <Reveal>
              <div className="inline-flex items-center gap-2 h-7 px-3 rounded-full border border-white/15 bg-white/[0.06] text-[11px] font-semibold uppercase tracking-[0.14em] text-white/75">
                <span data-pulse className="h-1.5 w-1.5 rounded-full" style={{ background: INDIGO }}></span>
                {t.hero.chip}
              </div>
            </Reveal>
            <Reveal delay={90}>
              <h1 className="ch-display text-[40px] sm:text-[56px] lg:text-[64px] leading-[1.02] font-bold tracking-[-0.03em] text-white mt-6">
                {t.hero.h1Pre}{' '}
                <RotorWord words={t.hero.rotor} />
                <br className="hidden sm:block" />{' '}
                <span className="text-white/45">{t.hero.h1Mid}</span>{' '}
                {t.hero.h1End}
              </h1>
            </Reveal>
            <Reveal delay={180}>
              <p className="text-[15.5px] sm:text-[17px] text-white/65 leading-relaxed mt-6 max-w-[540px]">
                {t.hero.sub}
              </p>
            </Reveal>
            <Reveal delay={270}>
              <div className="mt-8 flex flex-col sm:flex-row sm:items-center gap-3">
                <a href="#produto"
                   className="group h-12 px-6 rounded-full bg-white text-zinc-950 text-[14px] font-semibold inline-flex items-center justify-center gap-2 transition-all hover:shadow-[0_8px_30px_rgba(255,255,255,0.25)] hover:-translate-y-0.5">
                  <L name="play-circle" className="w-4 h-4 transition-transform group-hover:scale-110" />
                  {t.hero.ctaProduct}
                </a>
                <a href="#novidades"
                   className="group h-12 px-6 rounded-full border border-white/20 text-white text-[14px] font-medium inline-flex items-center justify-center gap-2 hover:bg-white/5 hover:border-white/40 transition-colors">
                  {t.hero.ctaNews}
                  <L name="arrow-right" className="w-4 h-4 transition-transform group-hover:translate-x-1" />
                </a>
              </div>
            </Reveal>
            <Reveal delay={360}>
              <div className="mt-10 flex flex-wrap items-center gap-x-6 gap-y-3 text-[11.5px] text-white/45">
                {[['shield-check', t.hero.trust[0]], ['file-text', t.hero.trust[1]], ['languages', t.hero.trust[2]], ['lock', t.hero.trust[3]]].map(([icon, label]) => (
                  <span key={label} className="inline-flex items-center gap-1.5"><L name={icon} className="w-3.5 h-3.5" />{label}</span>
                ))}
              </div>
            </Reveal>
          </div>

          {/* Live invoice demo, floating */}
          <div className="lg:col-span-6">
            <Reveal delay={200}>
              <div className="relative">
                <div className="absolute inset-0 rounded-3xl pointer-events-none"
                     style={{ background: 'radial-gradient(ellipse at 50% 40%, rgba(79,110,247,0.28), transparent 70%)', filter: 'blur(30px)' }}></div>
                <div className="relative ch-float rounded-2xl border border-white/12 overflow-hidden bg-white"
                     style={{ boxShadow: '0 60px 120px -30px rgba(0,0,0,0.7), 0 0 0 1px rgba(255,255,255,0.04)' }}>
                  <DemoFrame title={t.hero.frame} name="DemoFatura" badge={t.badge} />
                </div>
              </div>
            </Reveal>
          </div>
        </div>
      </div>
    </header>
  );
}

// ─── Numbers strip (counts up on scroll) ──────────────────────────────
function Numbers() {
  const { t } = useT();
  return (
    <section className="border-b border-zinc-100 bg-white">
      <div className="max-w-[1200px] mx-auto px-5 sm:px-8 py-14 lg:py-16 grid grid-cols-2 lg:grid-cols-4 gap-8">
        {t.numbers.map((s, i) => (
          <Reveal key={s.l} delay={i * 80}>
            <div className="ch-display text-[34px] sm:text-[40px] font-bold tracking-tight tabular-nums text-zinc-900">
              {s.to ? <CountUp to={s.to} render={s.fmt} /> : s.n}
            </div>
            <div className="text-[12.5px] text-zinc-500 mt-1">{s.l}</div>
          </Reveal>
        ))}
      </div>
    </section>
  );
}

// ─── Problem ──────────────────────────────────────────────────────────
function Problem() {
  const { t } = useT();
  return (
    <section className="border-b border-zinc-100 bg-white">
      <div className="max-w-[1200px] mx-auto px-5 sm:px-8 py-16 sm:py-20 lg:py-24">
        <div className="flex flex-col gap-8 lg:grid lg:grid-cols-12 lg:gap-12 lg:items-start">
          <Reveal className="lg:col-span-5">
            <div className="text-[11px] uppercase tracking-[0.16em] text-zinc-500 font-semibold mb-3">{t.problem.kicker}</div>
            <h2 className="ch-display text-[28px] sm:text-[34px] lg:text-[42px] leading-[1.08] font-bold tracking-tight text-zinc-900">
              {t.problem.h2}
            </h2>
          </Reveal>
          <Reveal delay={120} className="lg:col-span-7 text-[15px] sm:text-[16px] leading-relaxed text-zinc-600 space-y-4">
            <p>{t.problem.p1}</p>
            <p>{t.problem.p2}</p>
            <p className="text-zinc-900 font-medium">{t.problem.p3}</p>
          </Reveal>
        </div>
      </div>
    </section>
  );
}

// ─── Feature chapters — one live demo per section ─────────────────────
// Structural metadata; copy comes from t.chapters (same order).
const CHAPTER_META = [
  { n: '01', demo: 'DemoFatura',   icon: 'shield-check' },
  { n: '02', demo: 'DemoStock',    icon: 'sparkles', flip: true },
  { n: '03', demo: 'DemoVendas',   icon: 'arrow-right-left' },
  { n: '04', demo: 'DemoKanban',   icon: 'kanban', flip: true },
  { n: '05', demo: 'DemoCalendar', icon: 'calendar-days' },
  { n: '06', demo: 'DemoPortal',   icon: 'building-2', flip: true },
];

function Chapter({ meta, c, badge, first }) {
  return (
    <section id={first ? 'produto' : undefined}
             className={'relative overflow-hidden border-b border-zinc-100 ' + (meta.flip ? 'bg-zinc-50/60' : 'bg-white')}>
      {/* ghost chapter number */}
      <div aria-hidden="true"
           className={'ch-display absolute top-8 select-none pointer-events-none font-bold leading-none ' + (meta.flip ? 'right-6' : 'left-6')}
           style={{ fontSize: 200, color: 'transparent', WebkitTextStroke: '1px rgba(24,24,27,0.07)' }}>
        {meta.n}
      </div>
      <div className="relative max-w-[1200px] mx-auto px-5 sm:px-8 py-16 sm:py-20 lg:py-24">
        <div className={'flex flex-col gap-10 lg:grid lg:grid-cols-12 lg:gap-14 lg:items-center'}>
          {/* Copy */}
          <Reveal className={'lg:col-span-5 ' + (meta.flip ? 'lg:order-2' : '')}>
            <div className="flex items-center gap-2.5 text-[11px] uppercase tracking-[0.16em] font-semibold" style={{ color: INDIGO }}>
              <span className="ch-display text-[13px] font-bold tabular-nums">{meta.n}</span>
              <span className="h-px w-6" style={{ background: INDIGO }}></span>
              <span className="inline-flex items-center gap-1.5"><L name={meta.icon} className="w-3.5 h-3.5" />{c.kicker}</span>
            </div>
            <h2 className="ch-display text-[30px] sm:text-[36px] lg:text-[44px] leading-[1.05] font-bold tracking-[-0.02em] text-zinc-900 mt-4" style={{ textWrap: 'balance' }}>
              {c.title}
            </h2>
            <p className="text-[15px] sm:text-[16px] text-zinc-600 leading-relaxed mt-5 max-w-[460px]">{c.body}</p>
            <ul className="mt-6 space-y-2.5">
              {c.points.map((pt) => (
                <li key={pt} className="flex items-start gap-2.5 text-[13.5px] text-zinc-700">
                  <span className="h-5 w-5 rounded-full grid place-items-center shrink-0 mt-px" style={{ background: INDIGO_SOFT }}>
                    <L name="check" className="w-3 h-3" style={{ color: INDIGO }} />
                  </span>
                  {pt}
                </li>
              ))}
            </ul>
          </Reveal>

          {/* Live demo */}
          <Reveal delay={140} className={'lg:col-span-7 ' + (meta.flip ? 'lg:order-1' : '')}>
            <div className="group rounded-2xl border border-zinc-200 bg-white overflow-hidden transition-all hover:-translate-y-1.5 hover:shadow-2xl"
                 style={{ boxShadow: '0 24px 60px -28px rgba(24,24,27,0.25)' }}>
              <DemoFrame title={'ConstructHub · ' + c.kicker} name={meta.demo} badge={badge} />
            </div>
          </Reveal>
        </div>
      </div>
    </section>
  );
}

function Chapters() {
  const { t } = useT();
  return (
    <div>
      <section className="bg-white border-b border-zinc-100">
        <div className="max-w-[1200px] mx-auto px-5 sm:px-8 pt-16 sm:pt-20 lg:pt-24 pb-4 text-center">
          <Reveal>
            <div className="inline-flex items-center gap-2 h-7 px-3 rounded-full border border-zinc-200 text-[11px] font-semibold uppercase tracking-[0.14em] text-zinc-500">
              <span data-pulse className="h-1.5 w-1.5 rounded-full" style={{ background: INDIGO }}></span>
              {t.chaptersIntro.chip}
            </div>
            <h2 className="ch-display text-[32px] sm:text-[40px] lg:text-[48px] leading-[1.06] font-bold tracking-[-0.02em] text-zinc-900 mt-5 max-w-[760px] mx-auto" style={{ textWrap: 'balance' }}>
              {t.chaptersIntro.h2}
            </h2>
            <p className="text-[15.5px] text-zinc-500 leading-relaxed mt-4 max-w-[560px] mx-auto" style={{ textWrap: 'pretty' }}>
              {t.chaptersIntro.sub}
            </p>
            <div className="mt-7 flex flex-wrap items-center justify-center gap-3">
              <a href={mailtoHref(t.mail.demo)}
                 className="group h-11 px-5 rounded-full text-[13.5px] font-semibold inline-flex items-center gap-2 text-white transition-all hover:shadow-lg hover:-translate-y-0.5"
                 style={{ background: '#18181B' }}>
                <L name="calendar" className="w-4 h-4" />
                {t.chaptersIntro.cta}
              </a>
            </div>
          </Reveal>
        </div>
      </section>
      {CHAPTER_META.map((meta, i) => (
        <Chapter key={meta.n} meta={meta} c={t.chapters[i]} badge={t.badge} first={i === 0} />
      ))}
    </div>
  );
}

// ─── AI band — dark spotlight with the live chat demo ─────────────────
function AIBand() {
  const { t } = useT();
  return (
    <section id="ia" className="relative overflow-hidden text-white" style={{ background: '#09090C' }}>
      <div className="absolute inset-0 opacity-[0.05]" aria-hidden="true">
        <svg width="100%" height="100%">
          <defs>
            <pattern id="ch-ai-dots" width="32" height="32" patternUnits="userSpaceOnUse">
              <circle cx="2" cy="2" r="1" fill="white" />
            </pattern>
          </defs>
          <rect width="100%" height="100%" fill="url(#ch-ai-dots)" />
        </svg>
      </div>
      <div className="absolute -top-40 left-1/4 w-[560px] h-[560px] rounded-full pointer-events-none ch-glow"
           style={{ background: 'radial-gradient(circle, rgba(79,110,247,0.30) 0%, transparent 60%)' }}></div>

      <div className="relative max-w-[1200px] mx-auto px-5 sm:px-8 py-16 sm:py-20 lg:py-28 flex flex-col gap-12 lg:grid lg:grid-cols-12 lg:gap-12 lg:items-center">
        <div className="lg:col-span-5">
          <Reveal>
            <div className="inline-flex items-center gap-2 h-7 px-3 rounded-full text-[11.5px] font-semibold uppercase tracking-[0.12em]"
                 style={{ background: INDIGO, color: 'white' }}>
              <L name="sparkles" className="w-3 h-3" />
              {t.ai.chip}
            </div>
            <h2 className="ch-display text-white text-[32px] sm:text-[40px] lg:text-[48px] leading-[1.05] font-bold tracking-[-0.02em] mt-6">
              {t.ai.h2a}<br/>
              <span className="text-white/40">{t.ai.h2b}</span>
            </h2>
            <p className="text-[15px] sm:text-[16px] text-white/65 mt-6 leading-relaxed max-w-[440px]">
              {t.ai.sub}
            </p>
          </Reveal>
          <div className="mt-8 space-y-4">
            {t.ai.points.map((p, k) => (
              <Reveal key={p.t} delay={k * 90} className="flex items-start gap-4">
                <div className="h-9 w-9 rounded-md grid place-items-center shrink-0 bg-white/10">
                  <L name={p.i} className="w-4 h-4" />
                </div>
                <div className="min-w-0">
                  <div className="text-[14px] font-semibold">{p.t}</div>
                  <div className="text-[12.5px] text-white/55 mt-0.5">{p.s}</div>
                </div>
              </Reveal>
            ))}
          </div>
        </div>

        <Reveal delay={160} className="lg:col-span-7">
          <div className="rounded-2xl border border-white/12 overflow-hidden bg-white"
               style={{ boxShadow: '0 50px 110px -30px rgba(0,0,0,0.7)' }}>
            <DemoFrame title={t.ai.frame} name="DemoChat" badge={t.badge} />
          </div>
        </Reveal>
      </div>
    </section>
  );
}

// ─── Pricing tease ────────────────────────────────────────────────────
function Pricing() {
  const { t } = useT();
  return (
    <section id="planos" className="border-b border-zinc-100 bg-white">
      <div className="max-w-[1200px] mx-auto px-5 sm:px-8 py-16 sm:py-20 lg:py-24">
        <Reveal>
          <div className="text-[11px] uppercase tracking-[0.16em] text-zinc-500 font-semibold mb-3">{t.pricing.kicker}</div>
          <h2 className="ch-display text-[28px] sm:text-[34px] lg:text-[42px] leading-[1.08] font-bold tracking-tight text-zinc-900 mb-3">
            {t.pricing.h2}
          </h2>
          <p className="text-[15px] text-zinc-600 max-w-[600px] mb-10 lg:mb-12">{t.pricing.sub}</p>
        </Reveal>

        <div className="grid grid-cols-1 md:grid-cols-3 gap-5">
          {t.pricing.plans.map((p, i) => (
            <Reveal key={p.name} delay={i * 100}
                    className={'group rounded-2xl border bg-white p-7 relative transition-all hover:-translate-y-1 hover:shadow-xl ' + (p.recommended ? 'border-zinc-900' : 'border-zinc-200 hover:border-zinc-300')}>
              {p.recommended && (
                <span className="absolute -top-3 left-7 inline-flex items-center gap-1 h-6 px-2.5 rounded-full text-[10.5px] font-semibold uppercase tracking-[0.08em]" style={{ background: INDIGO, color: 'white' }}>
                  <L name="sparkles" className="w-3 h-3" />{t.pricing.recommended}
                </span>
              )}
              <div className="text-[18px] font-semibold tracking-tight">{p.name}</div>
              <div className="text-[12.5px] text-zinc-500 mt-1">{p.sub}</div>
              <div className="mt-6 flex items-baseline gap-1">
                <span className="ch-display text-[26px] font-bold tracking-tight">{t.pricing.price}</span>
              </div>
              <div className="text-[11.5px] text-zinc-500 mt-1">{t.pricing.priceNote}</div>
              <a href={i === 2 ? mailtoHref(t.mail.talk) : '#novidades'}
                 className={'mt-6 h-10 rounded-full font-medium text-[13px] inline-flex items-center justify-center gap-1.5 w-full transition-all ' +
                   (p.recommended ? 'hover:shadow-md' : 'border border-zinc-200 bg-white text-zinc-900 hover:bg-zinc-50 hover:border-zinc-300')}
                 style={p.recommended ? { background: '#18181B', color: 'white' } : {}}>
                {i === 2 ? t.pricing.ctaTalk : t.pricing.ctaNews}
                <L name="arrow-right" className="w-3.5 h-3.5" />
              </a>
              <ul className="mt-7 space-y-2.5 pt-6 border-t border-zinc-100">
                {p.points.map((pt) => (
                  <li key={pt} className="flex items-start gap-2 text-[12.5px] text-zinc-700">
                    <L name="check" className="w-3.5 h-3.5 mt-0.5 shrink-0" style={{ color: p.recommended ? INDIGO : '#10B981' }} />
                    {pt}
                  </li>
                ))}
              </ul>
            </Reveal>
          ))}
        </div>
        <div className="mt-8 text-[12.5px] text-zinc-500 text-center">{t.pricing.footnote}</div>
      </div>
    </section>
  );
}

// ─── FAQ ──────────────────────────────────────────────────────────────
function FAQ() {
  const { t } = useT();
  return (
    <section id="faq" className="border-b border-zinc-100 bg-white">
      <div className="max-w-[920px] mx-auto px-5 sm:px-8 py-16 sm:py-20 lg:py-24">
        <Reveal>
          <div className="text-[11px] uppercase tracking-[0.16em] text-zinc-500 font-semibold mb-3">{t.faq.kicker}</div>
          <h2 className="ch-display text-[26px] sm:text-[30px] lg:text-[38px] leading-[1.08] font-bold tracking-tight text-zinc-900 mb-8 lg:mb-10">
            {t.faq.h2}
          </h2>
        </Reveal>
        <Reveal delay={100} className="divide-y divide-zinc-100 border-y border-zinc-100">
          {t.faq.qs.map((it, i) => (
            <details key={i} className="group py-5">
              <summary className="flex items-center gap-3 cursor-pointer list-none">
                <span className="text-[15px] font-medium flex-1">{it.q}</span>
                <L name="plus" className="w-4 h-4 text-zinc-400 group-open:rotate-45 transition-transform" />
              </summary>
              <p className="text-[14px] text-zinc-600 leading-relaxed mt-3 pr-8">{it.a}</p>
            </details>
          ))}
        </Reveal>
      </div>
    </section>
  );
}

// ─── Newsletter finale — the page's single conversion point ───────────
// POSTs to /api/newsletter (same backend as the Madeira relaunch);
// honeypot + RGPD consent kept. API base read from the optional
// <meta name="showcase-api-base"> so previews can point elsewhere.
function NewsletterForm() {
  const { t } = useT();
  const [email, setEmail] = React.useState('');
  const [consent, setConsent] = React.useState(false);
  const [hp, setHp] = React.useState('');
  const [state, setState] = React.useState('idle'); // idle | sending | done | error

  async function submit(e) {
    e.preventDefault();
    setState('sending');
    try {
      const m = document.querySelector('meta[name="showcase-api-base"]');
      const base = (m && m.content) || '';
      const res = await fetch(base + '/api/newsletter', {
        method: 'POST', headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email, consent, hp }),
      });
      setState(res.ok ? 'done' : 'error');
    } catch (_) { setState('error'); }
  }
  if (state === 'done') {
    return (
      <div className="inline-flex items-center gap-2 text-[13.5px] text-emerald-300">
        <L name="check-circle-2" className="w-4 h-4" />
        {t.news.done}
      </div>
    );
  }
  return (
    <form onSubmit={submit} className="flex flex-col gap-3 max-w-[440px] mx-auto">
      <div className="flex gap-2 p-1.5 rounded-full border border-white/15 bg-white/[0.06] backdrop-blur">
        <input required type="email" placeholder={t.news.placeholder} value={email} onChange={(e) => setEmail(e.target.value)}
               className="flex-1 h-10 px-4 rounded-full bg-transparent text-[14px] text-white placeholder-white/35 outline-none min-w-0" />
        <button type="submit" disabled={state === 'sending'}
                className="h-10 px-5 rounded-full text-[13.5px] font-semibold text-white disabled:opacity-60 transition-all hover:brightness-110 shrink-0"
                style={{ background: INDIGO }}>
          {state === 'sending' ? t.news.sending : t.news.button}
        </button>
      </div>
      <input tabIndex={-1} autoComplete="off" value={hp} onChange={(e) => setHp(e.target.value)}
             style={{ position: 'absolute', left: '-9999px' }} aria-hidden="true" />
      <label className="flex items-start justify-center gap-2 text-[11px] text-white/45">
        <input type="checkbox" checked={consent} onChange={(e) => setConsent(e.target.checked)} className="mt-0.5" />
        <span>{t.news.consent}</span>
      </label>
      {state === 'error' && <div className="text-[11.5px] text-red-300 text-center">{t.news.error}</div>}
    </form>
  );
}

function NewsletterFinale() {
  const { t } = useT();
  return (
    <section id="novidades" className="relative overflow-hidden text-white" style={{ background: '#09090C' }}>
      <div className="absolute -top-32 left-1/2 -translate-x-1/2 w-[760px] h-[560px] rounded-full pointer-events-none ch-glow"
           style={{ background: 'radial-gradient(circle, rgba(79,110,247,0.32) 0%, transparent 62%)' }}></div>
      <svg className="absolute inset-0 w-full h-full pointer-events-none" aria-hidden="true"
           style={{ opacity: 0.08, maskImage: 'radial-gradient(ellipse 80% 60% at 50% 100%, black 30%, transparent 80%)' }}>
        <defs>
          <pattern id="ch-news-grid" width="44" height="44" patternUnits="userSpaceOnUse">
            <path d="M 44 0 L 0 0 0 44" fill="none" stroke="white" strokeWidth="1" />
          </pattern>
        </defs>
        <rect width="100%" height="100%" fill="url(#ch-news-grid)" />
      </svg>

      <div className="relative max-w-[760px] mx-auto px-5 sm:px-8 py-20 sm:py-24 lg:py-32 text-center">
        <Reveal>
          <div className="inline-flex items-center gap-2 h-7 px-3 rounded-full border border-white/15 bg-white/[0.06] text-[11px] font-semibold uppercase tracking-[0.14em] text-white/75">
            <span data-pulse className="h-1.5 w-1.5 rounded-full" style={{ background: INDIGO }}></span>
            {t.news.chip}
          </div>
        </Reveal>
        <Reveal delay={90}>
          <h2 className="ch-display text-[36px] sm:text-[48px] lg:text-[60px] leading-[1.02] font-bold tracking-[-0.03em] text-white mt-6">
            {t.news.h2a}<br/>{t.news.h2b}
          </h2>
        </Reveal>
        <Reveal delay={180}>
          <p className="text-[15px] sm:text-[16.5px] text-white/60 mt-5 max-w-[480px] mx-auto leading-relaxed">
            {t.news.sub}
          </p>
        </Reveal>
        <Reveal delay={270}>
          <div className="mt-9">
            <NewsletterForm />
          </div>
          <div className="mt-9 pt-7 border-t border-white/10 flex flex-wrap items-center justify-center gap-3">
            <span className="text-[12.5px] text-white/55">{t.news.prefer}</span>
            <a href={mailtoHref(t.mail.talk)}
               className="h-10 px-4 rounded-full border border-white/20 text-[13px] font-medium inline-flex items-center gap-2 text-white hover:bg-white/5 transition-colors">
              <L name="calendar" className="w-4 h-4" />{t.news.book}
            </a>
          </div>
        </Reveal>
      </div>
    </section>
  );
}

// ─── Footer ───────────────────────────────────────────────────────────
function Footer() {
  const { t, lang, setLang } = useT();
  return (
    <footer className="bg-white">
      <div className="max-w-[1200px] mx-auto px-5 sm:px-8 py-12 lg:py-16 grid grid-cols-2 sm:grid-cols-4 lg:grid-cols-12 gap-x-6 gap-y-10 lg:gap-10">
        <div className="col-span-2 sm:col-span-4 lg:col-span-4">
          <div className="flex items-center gap-2.5 mb-4">
            <span className="h-7 w-7 rounded-md grid place-items-center text-white font-bold text-[13px]" style={{ background: '#18181B' }}>CH</span>
            <span className="text-[15px] font-semibold tracking-tight">ConstructHub</span>
          </div>
          <p className="text-[13px] text-zinc-600 leading-relaxed max-w-[280px]">{t.footer.tagline}</p>
          <div className="mt-6 flex items-center gap-2">
            {['briefcase', 'play-circle', 'mail'].map((s) => (
              <a key={s} href="#" className="h-8 w-8 rounded-md border border-zinc-200 grid place-items-center hover:bg-zinc-50">
                <L name={s} className="w-3.5 h-3.5 text-zinc-600" />
              </a>
            ))}
          </div>
        </div>
        {t.footer.cols.map((col) => (
          <div key={col.t} className="lg:col-span-2">
            <div className="text-[11px] uppercase tracking-[0.12em] text-zinc-900 font-semibold mb-4">{col.t}</div>
            <ul className="space-y-2.5">
              {col.items.map(([label, href]) => (
                <li key={label}><a href={href} className="text-[12.5px] text-zinc-600 hover:text-zinc-900">{label}</a></li>
              ))}
            </ul>
          </div>
        ))}
      </div>
      <div className="border-t border-zinc-100">
        <div className="max-w-[1200px] mx-auto px-5 sm:px-8 py-6 flex items-center justify-between text-[11.5px] text-zinc-500 flex-wrap gap-3">
          <div>{t.footer.copyright}</div>
          <div className="flex items-center gap-4">
            <span className="inline-flex items-center gap-1"><L name="check-circle-2" className="w-3 h-3 text-emerald-600" />{t.footer.status}</span>
            <span className="inline-flex items-center gap-1.5">
              {LANGS.map((l, i) => (
                <React.Fragment key={l}>
                  {i > 0 && <span className="text-zinc-300">·</span>}
                  <button onClick={() => setLang(l)}
                          className={'uppercase hover:text-zinc-900 ' + (l === lang ? 'text-zinc-900 font-semibold' : '')}>
                    {l}
                  </button>
                </React.Fragment>
              ))}
            </span>
          </div>
        </div>
      </div>
    </footer>
  );
}

// ─── Page ─────────────────────────────────────────────────────────────
function LandingPage() {
  const [lang, setLangState] = React.useState(initialLang);
  const setLang = React.useCallback((l) => {
    if (!LANGS.includes(l)) return;
    setLangState(l);
    try { window.localStorage.setItem('ch-lang', l); } catch (_) {}
  }, []);
  React.useEffect(() => {
    document.documentElement.lang = HTML_LANG[lang];
    // The ./demos components read this on every animation tick, so they
    // re-present in the selected language without remounting.
    window.__DEMO_LANG = lang;
  }, [lang]);
  const ctx = React.useMemo(() => ({ lang, t: I18N[lang], setLang }), [lang, setLang]);

  return (
    <LangCtx.Provider value={ctx}>
      <div className="w-full bg-white" style={{ fontFamily: 'system-ui, -apple-system, "Segoe UI", Roboto, sans-serif' }}>
        <LandingStyles />
        <NavPill />
        <HeroDark />
        <Numbers />
        <Problem />
        <Chapters />
        <AIBand />
        <Pricing />
        <FAQ />
        <NewsletterFinale />
        <Footer />
      </div>
    </LangCtx.Provider>
  );
}

Object.assign(window, { LandingPage });
