// narrative.jsx — camada narrativa da landing (PAS: dor → virada → jornada → prova)
//
// Estrutura de leitura, não de decoração:
// 1. Agitação — as 3 mentiras que contaram pro vendedor + a negação
// 2. Problema/Diagnóstico — dois blocos rotulados, tipografia diferente no rótulo
// 3. Diferenciador — "a maioria das ferramentas" vs "o Comissa"
// 4. Jornada — 01/02/03 com a linha preenchendo conforme o scroll
// 5. Segmentos — cards por ICP
// 6. Garantia + FAQ — remove risco e responde objeção real
//
// FORA DA PÁGINA (definidos aqui, não chamados por ninguém): PlataformasStrip
// e MobPlataformas — a faixa "Integrações nativas" com os 12 logos, removida a
// pedido. Ficam no arquivo porque voltar é uma linha em landing-page.jsx /
// mobile-site.jsx; o mesmo tratamento que VendedorTicker e SegmentosSection.
//
// COR: nada de paleta nova. A virada emocional usa o que o site já tem —
// o fundo desce pra um preto mais fechado na dor (#F1F5F9) e volta pro
// --bg-2 com glow índigo (o mesmo --indigo/--cyan da barra de progresso)
// na resolução. Rosa (--rose) marca o que está errado; verde (--green) o que
// está certo. Tudo já existia no tema.
const { useEffect: nFx, useRef: nRefHook, useState: nSt } = React;
// ── Motion helpers ───────────────────────────────────────────
// Uma checagem só de prefers-reduced-motion, compartilhada por tudo aqui.
function useCalmMotion() {
const [calm, setCalm] = nSt(false);
nFx(() => {
const mq = window.matchMedia('(prefers-reduced-motion: reduce)');
const on = () => setCalm(mq.matches);
on();
mq.addEventListener ? mq.addEventListener('change', on) : mq.addListener(on);
return () => { mq.removeEventListener ? mq.removeEventListener('change', on) : mq.removeListener(on); };
}, []);
return calm;
}
// Progresso 0→1 de um elemento atravessando a viewport.
// `trigger` = altura (fração da viewport) onde a conta começa;
// `span` = quanto da altura do elemento precisa passar pra chegar em 1.
function useScrollPass(ref, { trigger = 0.8, span = 0.85 } = {}) {
const [p, setP] = nSt(0);
nFx(() => {
const el = ref.current; if (!el) return;
let raf = 0;
const calc = () => {
const r = el.getBoundingClientRect();
const vh = window.innerHeight || 1;
const line = vh * trigger;
const total = Math.max(1, r.height * span);
const v = (line - r.top) / total;
setP(v < 0 ? 0 : v > 1 ? 1 : v);
};
const onScroll = () => { cancelAnimationFrame(raf); raf = requestAnimationFrame(calc); };
window.addEventListener('scroll', onScroll, { passive: true });
window.addEventListener('resize', onScroll);
calc();
return () => {
window.removeEventListener('scroll', onScroll);
window.removeEventListener('resize', onScroll);
cancelAnimationFrame(raf);
};
}, [trigger, span]);
return p;
}
// Reveal escalonado — fade + translateY(16px), 90ms entre irmãos.
// Cada filho entra sozinho; o gatilho é a entrada do container.
//
// `stretch` só pra quando o Stagger embrulha UM card que precisa herdar a
// altura da linha do grid pai (a Virada, os Segmentos). Fora desse caso o
// `height: 100%` é veneno: num grid item esticado, filho com altura
// percentual e linha de altura automática se resolvem em círculo, o wrapper
// colapsa e o texto que passa dele fica cortado por baixo — era isso que
// comia a segunda linha de "Ninguém rastreia a venda. Todo mundo…".
// Qual item da lista está na faixa de leitura (o meio da tela). Existe pra a
// seção poder acender UM item por vez conforme o visitante desce: o olho é
// levado item a item em vez de bater numa parede de três blocos iguais.
function useItemNaFaixa(n) {
const refs = nRefHook([]);
const [ativo, setAtivo] = nSt(-1);
nFx(() => {
const els = refs.current.filter(Boolean);
if (!els.length) return;
// Sem animação: acende tudo e não observa nada.
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
setAtivo(n - 1);
return;
}
const io = new IntersectionObserver((entradas) => {
entradas.forEach((e) => {
if (e.isIntersecting) setAtivo(Number(e.target.dataset.idx));
});
}, { rootMargin: '-40% 0px -40% 0px', threshold: 0 });
els.forEach((el) => io.observe(el));
return () => io.disconnect();
}, [n]);
return [refs, ativo];
}
function Stagger({ children, step = 90, y = 16, delay = 0, style, stretch = false }) {
const ref = nRefHook(null);
const [shown, setShown] = nSt(false);
const calm = useCalmMotion();
nFx(() => {
const el = ref.current; if (!el) return;
const io = new IntersectionObserver((es) => {
es.forEach((e) => { if (e.isIntersecting) { setShown(true); io.unobserve(el); } });
// Antes disparava com 15% do bloco visível e a borda de baixo puxada em
// 8%: na prática, a animação rodava quando só a primeira linha tinha
// aparecido no rodapé da tela — quem descia via o bloco JÁ montado, sem
// nunca ter visto a entrada. Puxando a borda de baixo em 26%, o gatilho
// só acontece quando o bloco entrou de verdade no campo de leitura.
}, { threshold: 0, rootMargin: '0px 0px -26% 0px' });
io.observe(el);
return () => io.disconnect();
}, []);
const items = React.Children.toArray(children);
return (
{items.map((c, i) => (
{c}
))}
);
}
// Rótulo que nomeia a etapa antes do parágrafo ("PROBLEMA", "DIAGNÓSTICO").
// Placa de sinalização: o leitor sabe o que vem antes de ler a frase.
function NarrLabel({ children, tone = 'muted' }) {
// Rótulo é texto de 11px com tracking largo — o caso mais frágil que existe
// pra contraste. Todos os tons vêm da escala `-text`, não da de
// preenchimento: em `--cyan` puro este rótulo dava 2:1 e sumia.
const color = tone === 'rose' ? 'var(--rose-text)'
: tone === 'indigo' ? 'var(--indigo-text)'
: tone === 'cyan' ? 'var(--cyan-text)'
: 'var(--muted-2)';
return (
{/* Saiu o tracinho de 18px que vinha antes do rótulo. Não era caractere,
era uma com fundo, mas lia como travessão na tela ("— A MENTIRA")
e era exatamente disso que o Arthur reclamou. O rótulo se vira sozinho
com o uppercase e o tracking. */}
{children}
);
}
// ─────────────────────────────────────────────────────────────
// 1. Agitação — "Comissão não é sorte"
// Fundo mais fechado que o resto da página: a dor é o ponto mais escuro
// da narrativa, e a virada logo depois é sentida antes de ser lida.
// ─────────────────────────────────────────────────────────────
const MENTIRAS = [
{
n: '01',
t: 'vender mais',
d: 'Como se o buraco fosse o volume, e não o que some entre fechar a venda e receber por ela.',
},
{
n: '02',
t: 'confiar na planilha do financeiro',
d: 'A planilha que ninguém confere, todo mundo edita e nenhuma pessoa assina embaixo.',
},
{
n: '03',
t: 'esperar o fechamento do mês',
d: 'Trinta dias no escuro pra saber o valor exatamente no dia em que já não dá pra contestar.',
},
];
function AgitacaoSection() {
// O palco: três mentiras, uma por vez, presas no meio da tela enquanto o
// visitante rola. Cada volta do scroll risca a que ele acabou de ler e traz
// a próxima. É leitura forçada em ordem — impossível pular — e o risco
// acontece na frente dele, que é o que faz a negação pesar.
const palcoRef = nRefHook(null);
const calm = useCalmMotion();
// `span` casa com a janela em que o bloco fica grudado: 0 quando ele cola no
// topo, 1 quando descola. Sem isso a conta gastava metade do percurso antes
// de o sticky sequer engatar, e a primeira mentira passava batida.
const p = useScrollPass(palcoRef, { trigger: 0.14, span: 0.75 });
const idx = calm ? MENTIRAS.length - 1
: Math.max(0, Math.min(MENTIRAS.length - 1, Math.floor(p * MENTIRAS.length * 0.999)));
return (
{/* vinheta rosa entrando de cima o mesmo --rose dos indicadores negativos.
Presa às bordas laterais (sem os -10%) porque a seção não pode mais
recortar o próprio conteúdo: `overflow` diferente de `visible` —
`hidden` OU `clip` — tira o palco sticky das mentiras do relógio da
janela e ele para de grudar. */}
A mentira
Comissão não é sorte. Você só foi treinado pra torcer.
Toda vez que o número veio menor, a resposta foi a mesma: o problema é você.
Bastava:
{/* 260vh e não 170vh: o palco preso só dura `altura - altura do filho`,
então 170vh deixava ~600px de curso pra três passos — 200px por
mentira, menos de um giro de roda, e a 02 passava sem ser vista.
Com 260vh cada passo ganha ~330px, e o span 0.75 faz o último
fechar no mesmo instante em que o sticky solta (sem seção vazia
depois). */}
{/* contador: quantas já caíram */}
{MENTIRAS.map((m, i) => (
))}
{MENTIRAS.map((m, i) => {
const passou = i < idx;
const atual = i === idx;
return (
{m.n}
{/* O risco corre da esquerda pra direita no instante em que
o visitante rola pra próxima: ele vê a frase ser riscada,
não encontra uma frase já riscada. */}
{m.t}
{m.d}
);
})}
E quando a comissão vinha errada, a culpa voltava pra você: {' '}
“deve ter anotado errado”.
{/* A conta que dá nome ao prejuízo. Sem número, a seção é reclamação;
com número, é uma perda que o leitor consegue reconhecer na
própria carteira. Hipótese declarada, não estatística. */}
Uma venda não contada por mês, a 3% de um ticket de {' '}
R$ 8.000,
são {' '}
R$ 2.880 {' '}
por ano que você nunca vai cobrar, porque nunca soube que existiu.
);
}
// ─────────────────────────────────────────────────────────────
// 2. Problema — uma frase só
// ─────────────────────────────────────────────────────────────
// Eram duas colunas rotuladas "Problema" e "Diagnóstico" com um título grande
// cada. Lado a lado elas competiam, e a segunda só fazia sentido depois da
// primeira — ou seja, era uma frase quebrada em duas caixas. Agora é uma
// sentença só, que é como ela se lê em voz alta.
function ProblemaDiagnostico() {
return (
O problema
Ninguém rastreia a venda — todo mundo lança a venda.
E conta certa em cima de dado digitado herda o erro do dado.
Lançar é memória, e memória falha. Quando falha, quem paga a conta é sempre quem
vendeu: é a sua palavra contra uma célula de planilha. Por isso comissão certa não
começa na fórmula — começa no clique que gerou a venda.
);
}
// ─────────────────────────────────────────────────────────────
// 3. Diferenciador — a virada.
// Aqui o fundo muda: sai do preto fechado da dor e volta pro --bg-2 com
// um glow índigo que cresce conforme a seção entra. O corpo sente a virada
// antes do cérebro processar que o argumento mudou.
// ─────────────────────────────────────────────────────────────
function ViradaGlow({ progress }) {
return (
);
}
function DiferenciadorSection() {
const ref = nRefHook(null);
const calm = useCalmMotion();
const p = useScrollPass(ref, { trigger: 0.9, span: 0.6 });
// A seção entra com UM lado só: a planilha que o vendedor já conhece.
// O lado do Comissa só existe depois que o leitor desce — ele precisa
// terminar de sentir o problema antes de receber a resposta, senão a
// comparação vira duas caixas lado a lado e ninguém lê a da esquerda.
//
// O gatilho é medido no grid, não na seção: o `p` da seção começa a contar
// com o título ainda entrando, e a essa altura a planilha nem apareceu.
// Aqui o lado direito só nasce quando o esquerdo já está no meio da tela.
const gridRef = nRefHook(null);
// A comparação volta a ter dois tempos, mas agora com folga pra ler: o lado
// do Comissa só entra depois que a planilha já passou pelo meio da tela.
// Quem desce lê a planilha, sente o erro, e só então a resposta sobe ao lado.
// O quadro do Comissa entra antes da metade do percurso: quem chega na seção
// deve encontrar a comparação pronta pra ler, não esperar por ela.
const pGrid = useScrollPass(gridRef, { trigger: 0.62, span: 0.8 });
const revelado = calm || pGrid >= 0.12;
// Os dois lados falam da MESMA venda (Honda Civic, R$ 118.900). Na planilha
// ela aparece com a comissão errada e um comentário de quem desconfia; no
// Comissa, com o rastro que prova o número. Mesmo caso dos dois lados é o
// que faz a comparação morder, em vez de virar duas listas genéricas.
const PLANILHA = [
{ c: '14', p: 'Curso Trading Pro', v: '2.970,00', com: '891,00' },
{ c: '15', p: 'Honda Civic 2024', v: '118.900,00', com: '2.378,00', erro: true },
{ c: '16', p: 'Rolex Submariner', v: '89.400,00', com: '2.682,00' },
];
const RASTRO = [
{ t: 'Clique no seu link', carimbo: '14:02 · Fortaleza · Instagram', v: '#a91f' },
{ t: 'Checkout na Hotmart', carimbo: '14:09 · cartão 3x', v: 'R$ 118.900' },
{ t: 'Pagamento aprovado', carimbo: '14:11 · webhook da plataforma', v: 'confirmado' },
{ t: 'Comissão 3% calculada', carimbo: 'na hora, sem ninguém digitar', v: 'R$ 3.567', destaque: true },
];
return (
A virada
A conta certa em cima do dado errado continua errada.
{/* Três colunas, não duas: a do meio é o conector que desenha quando o
lado do Comissa entra. É a virada acontecendo na tela — o único
movimento que esta seção se dá o direito de fazer. */}
{/* Antes eram duas listas simétricas de ✗ contra ✓, que é o cartão de
comparação que toda landing tem e por isso lê como template.
Agora cada lado mostra o ARTEFATO de verdade: aqui, o pedaço de
planilha que o vendedor conhece, com a célula divergente e o
comentário de quem não confia nela. Concreto vence adjetivo. */}
Hoje, na planilha
Alguém digita, no fim do mês, torcendo pra não ter errado.
Três vendas, três chances de errar. E a linha que sai errada nunca é
a do financeiro.
{/* Cabeçalho de planilha de verdade. Sem ele a tabela é uma
lista de números; com ele o leitor reconhece o artefato e
consegue apontar QUAL célula está errada. */}
#ProdutoValorComissão
{PLANILHA.map((l, i) => (
{l.c}{l.p}{l.v}{l.com}
))}
{/* O prejuízo com nome e valor. A tabela acima já contém a prova
(2.378 é 2% de 118.900; a regra do produto é 3%), mas número
sozinho não acusa ninguém — esta linha faz a conta pro leitor. */}
Linha 15: a regra é 3%, foi digitado 2%. Faltam {' '}
R$ 1.189 nessa venda — e a planilha não vai avisar.
Comentário na célula: “esse valor tá certo? confere aí”
{/* O gradiente daqui terminava em rgba(22,19,31,0.9), herança do tema
escuro: no tema claro virava um bloco quase preto com texto
`--ink` (escuro) por cima, ilegível. Agora é superfície clara com
o calor do acento só na borda e no topo.
E o conteúdo deixou de ser lista de ✓: é a MESMA venda da planilha
ao lado, mostrada como rastro, com carimbo de origem em cada
passo. O argumento da seção é "o dado certo", então o lado certo
precisa mostrar de onde o dado veio. */}
{/* O conector. Risco que desenha da planilha até o Comissa no
momento em que o segundo lado entra: a virada acontecendo, não
ilustrada. Rosa de um lado, índigo do outro. */}
No Comissa, a mesma venda
Ninguém digita. Cada passo deixa carimbo, e a comissão nasce do rastro.
{RASTRO.map((r, i) => (
{i < RASTRO.length - 1 && (
)}
{r.t}
{r.carimbo}
{r.v}
))}
Mesma venda da planilha ao lado, {' '}
R$ 1.189 de diferença — só que aqui
cada passo tem carimbo, então o número não depende da palavra de ninguém.
);
}
// ─────────────────────────────────────────────────────────────
// 4. Jornada — 01/02/03.
// A linha preenche em índigo→ciano conforme o scroll: o "rastreio"
// acontecendo na tela, não uma decoração. O traço pontilhado por trás
// segue o cursor de leve (parallax ~12px) — mesma ideia.
// ─────────────────────────────────────────────────────────────
const ETAPAS = [
{
n: '01',
t: 'Seu link',
d: 'Você gera o link rastreável do produto ou recebe o link já vinculado pela empresa. Cada clique entra identificado, com origem e horário.',
code: 'track-click',
},
{
n: '02',
t: 'A venda acontece',
d: 'Hotmart, Kiwify, Eduzz, Guru, Cakto, Asaas e outras: a própria plataforma avisa quando o pagamento é aprovado. Você não precisa contar pra ninguém.',
code: 'webhook → sale_events',
},
{
n: '03',
t: 'Comissão rastreada',
d: 'Ela aparece no painel com origem, valor e status antes mesmo do dinheiro cair. Se for estornada, o mesmo caminho desfaz sozinho.',
code: 'resolve_commission',
},
];
function JornadaSection() {
const ref = nRefHook(null);
const pilhaRef = nRefHook(null);
const fill = useScrollPass(pilhaRef, { trigger: 0.12, span: 0.75 });
const calm = useCalmMotion();
return (
Como o dado anda
Do clique ao valor na sua tela, em três passos que rodam sem você.
{/* 900 e não 1120: o card mais longo tem duas linhas de texto, e numa
caixa de 1050px de largura elas viram uma faixa fina no meio de um
deserto branco. */}
{/* O empilhamento é UM elemento grudado com três cards dentro, movidos
pelo progresso do scroll — e não três `position: sticky` irmãos.
Sticky irmão no mesmo container não se sobrepõe: o navegador empurra
o de cima pra fora pra não encostar no de baixo, que é o oposto do
que esta seção precisa (a etapa 02 tem que COBRIR a 01, e a 03 a
02). Com um palco só, quem manda é a conta abaixo. */}
{ETAPAS.map((e, i) => {
// Cada etapa entra por baixo e para em cima da anterior, deixando
// à vista só a faixa superior dela. O passo de 0.42 espalha as
// três por quase todo o curso do sticky — com 0.3 tudo terminava
// em 60% dele e o resto era rolagem morta.
const t = calm ? 1 : Math.max(0, Math.min(1, (fill - (i - 1) * 0.42) / 0.42));
const on = t > 0.6;
return (
{/* O nó do trilho. Fica fora do card, encostado na linha,
pra ligar visualmente o card ao caminho. */}
{/* O numeral é o único marcador de ordem que sobrou.
O rótulo "Etapa 01" repetia exatamente o que este
número já dizia, duas vezes na mesma linha. */}
{e.n}
{e.t}
{/* O carimbo técnico: o nome real da peça que roda esse
passo. Vive no canto, como etiqueta de equipamento —
é prova de que existe código atrás, não um chip
colorido de enfeite no meio do texto. */}
{e.code}
{e.d}
);
})}
Não é fluxograma de apresentação: é o caminho que o dado percorre de verdade
dentro do Comissa. Os três carimbos acima são as três peças que fazem isso rodar.
);
}
// ─────────────────────────────────────────────────────────────
// 5. Marquee de plataformas — loop infinito, pausa no hover.
// Quem tem logo próprio usa BrandLogo; o resto entra como monograma
// no mesmo formato. Tudo dessaturado até o hover, pra não virar
// carnaval de cor no meio de uma página índigo.
// ─────────────────────────────────────────────────────────────
const PLATAFORMAS = [
{ id: 'hotmart', n: 'Hotmart' },
{ id: 'kiwify', n: 'Kiwify' },
{ id: null, n: 'Eduzz', c: '#F5A623' },
{ id: null, n: 'Guru', c: '#00C2A8' },
{ id: null, n: 'Cakto', c: '#7C6BFF' },
{ id: null, n: 'Monetizze', c: '#00A0DF' },
{ id: null, n: 'Ticto', c: '#2563EB' },
{ id: 'asaas', n: 'Asaas' },
{ id: 'mercadopago', n: 'Mercado Pago' },
{ id: null, n: 'Pagar.me', c: '#65A300' },
{ id: null, n: 'Stripe', c: '#635BFF' },
{ id: 'pix', n: 'Pix' },
];
function PlatformMark({ p }) {
if (p.id) return ;
return (
{p.n[0]}
);
}
// Faixa de plataformas — logo abaixo do hero.
//
// Era um marquee infinito no MEIO da página, com um rótulo de 11px ("a venda
// confirma sozinha em") como única explicação. Duas coisas mudaram:
//
// • Subiu pro começo. É a prova mais concreta que a página tem — o visitante
// que chega pelo anúncio quer saber "funciona com a MINHA plataforma?"
// antes de ler qualquer narrativa. Deixar isso na metade da página é
// responder tarde.
// • Parou de andar. Logo abaixo do hero, texto correndo sozinho disputa
// atenção com a headline em vez de sustentá-la — e a barra de progresso do
// topo saiu pelo mesmo motivo. Grade estática lê mais rápido que marquee:
// dá pra procurar a própria plataforma com o olho parado.
//
// A frase virou afirmação com explicação ao lado, não rótulo solto: "confirma
// sozinha" sem dizer COMO é promessa; com o webhook explicado, é mecanismo.
function PlataformasStrip() {
return (
Integrações nativas
A venda confirma sozinha.
O webhook oficial da plataforma avisa o Comissa no segundo em que o
pagamento é aprovado. A venda entra paga, com o valor, a taxa retida
e a sua comissão já calculada — você não digita nada.
{PLATAFORMAS.map((p) => (
{p.n}
))}
);
}
// ─────────────────────────────────────────────────────────────
// 6. Segmentos — cards por ICP, cada um com a dor específica
// ─────────────────────────────────────────────────────────────
function SegmentosSection() {
const segs = [
{
icon: ,
t: 'Representante autônomo',
dor: 'Vende por 4 plataformas e não sabe qual pagou o quê.',
fix: 'Um painel só, com a origem de cada venda e a data prevista de cada repasse.',
},
{
icon: ,
t: 'Corretor de seguros',
dor: 'Comissão parcelada por 12 meses e renovação que ninguém lembra.',
fix: 'Parcela por parcela no calendário, com a que ainda está em aberto marcada.',
},
{
icon: ,
t: 'Corretor de imóveis',
dor: 'Uma venda grande, várias mãos: quanto sobra pra você mesmo?',
fix: 'Divisão registrada na venda e contrato preenchido com o seu documento.',
},
{
icon: ,
t: 'Closer / SDR comissionado',
dor: 'A meta muda no meio do mês e o cálculo do variável some.',
fix: 'Meta, atingimento e comissão na mesma tela atualizando a cada venda paga.',
},
];
return (
{segs.map((s, i) => (
{s.icon}
{s.t}
{s.dor}
{s.fix}
))}
);
}
// ─────────────────────────────────────────────────────────────
// 7. Custo diário + garantia — sem ancoragem de desconto (isso é curso).
// O framing é de custo por dia comparado ao que uma comissão perdida custa.
// ─────────────────────────────────────────────────────────────
function CustoDiario() {
return (
R$ 1,60por dia
É o que custa o Comissa Pro {' '}
R$ 47,90/mês.
Uma comissão perdida por falta de rastreio costuma pagar o ano inteiro.
);
}
function GarantiaSection() {
return (
Sem risco
14 dias grátis, sem cartão.
Você entra, conecta uma plataforma e vê a primeira venda chegar sozinha. Se não fizer
sentido pro seu dia, você não paga nada — não existe cobrança pra cancelar depois.
{['Sem cartão pra começar', 'Sem fidelidade', 'Cancela em um clique'].map((x) => (
{x}
))}
);
}
// ─────────────────────────────────────────────────────────────
// 8. FAQ — objeção real de configuração e uso, não pergunta de vitrine
// ─────────────────────────────────────────────────────────────
const FAQ = [
{
q: 'Preciso trocar minha plataforma de pagamento?',
a: 'Não. Hotmart, Kiwify, Eduzz, Guru, Cakto, Monetizze, Ticto, Asaas, Mercado Pago, Pagar.me e Stripe funcionam do jeito que já estão: você cola a URL de webhook do Comissa no painel da plataforma e pronto. Nada muda pro seu comprador.',
},
{
q: 'E se eu vender fora de plataforma — Pix na mão, carro, imóvel?',
a: 'Aí a venda entra manual, em três campos, e a comissão sai igual. O rastreio por link é pra quem vende online; quem vende de perto usa o mesmo painel de comissão, meta e follow-up sem precisar de link nenhum.',
},
{
q: 'Quanto tempo pra deixar configurado?',
a: 'Cerca de cinco minutos: cadastra o produto, define a regra de comissão (percentual, valor fixo ou por forma de pagamento) e gera o link. A partir daí a venda entra sozinha.',
},
{
q: 'A empresa em que eu vendo precisa usar o Comissa?',
a: 'Não. Você pode usar sozinho e acompanhar a sua comissão. Se a empresa também usar, ela te manda um link único de acesso: você entra já vinculado e os dois lados olham pro mesmo número, sem conferir planilha um do outro.',
},
{
q: 'E quando a venda é estornada?',
a: 'A mesma plataforma que avisou a aprovação avisa o estorno. O Comissa marca a venda como estornada e desfaz a comissão sem você precisar caçar o lançamento pra corrigir na mão.',
},
{
q: 'Meus dados de venda ficam visíveis pra outra pessoa?',
a: 'Cada conta enxerga só o que é dela. Vendedor comissionado vê a própria comissão e o próprio histórico; a empresa vê o time dela. Não existe painel comum entre contas diferentes.',
},
];
function FaqItem({ item, open, onToggle }) {
return (
{/* `inert` na resposta fechada: `max-height: 0` com `overflow: hidden`
esconde do olho, mas o texto continua na árvore de acessibilidade —
um leitor de tela lia as onze respostas seguidas, como se o acordeão
estivesse todo aberto. O `aria-expanded` do botão acima já diz o
estado; isto faz o conteúdo obedecer. */}
);
}
// ─────────────────────────────────────────────────────────────
// Versão mobile da mesma narrativa.
// Mesmo texto e mesma virada de fundo; o que sai é o que depende de
// cursor (parallax) e de duas colunas. O marquee vira dois grupos de
// chips estáticos — em tela pequena, logo correndo só atrapalha a leitura.
// ─────────────────────────────────────────────────────────────
function MobAgitacao() {
return (
A mentira
Comissão não é sorte. Você só foi treinado pra torcer.
Toda vez que o número veio menor, a resposta foi a mesma: o problema é você. Bastava:
{MENTIRAS.map((m) => (
{m.n}{m.t}
{m.d}
))}
E quando a comissão vinha errada, a culpa voltava pra você: {' '}
“deve ter anotado errado”.
Uma venda não contada por mês, a 3% de um ticket de {' '}
R$ 8.000, são {' '}
R$ 2.880 {' '}
por ano que você nunca vai cobrar.
Mentiram pra você.
);
}
function MobProblemaDiagnostico() {
const blocos = [
{ label: 'Problema', tone: 'muted', t: 'Ninguém rastreia a venda. Todo mundo lança a venda.', d: 'Lançar é memória, e memória falha. Quando falha, quem paga a conta é sempre quem vendeu.' },
{ label: 'Diagnóstico', tone: 'cyan', t: 'O erro não está na conta. Está na origem do dado.', d: 'Comissão certa não começa na fórmula — começa no clique que gerou a venda.' },
];
return (
A conta certa em cima do dado errado continua errada.
A maioria das ferramentas
Calculam em cima do que alguém lançou na mão, no fim do mês, torcendo pra não ter erro.
O Comissa
Rastreia a venda desde o link — clique, plataforma, confirmação de pagamento — e a comissão já nasce calculada certa.
);
}
function MobJornada() {
const ref = nRefHook(null);
const fill = useScrollPass(ref, { trigger: 0.75, span: 0.85 });
return (
Como o dado anda
Do clique ao valor na sua tela, em três passos que rodam sem você.
{ETAPAS.map((e, i) => {
const on = fill >= (i + 0.15) / ETAPAS.length;
return (
{/* Mesmo corte do desktop: o "Etapa 01" repetia o numeral que
o marcador do trilho já dá. Aqui sobra o número, discreto,
colado no título. */}
{e.n}
{e.t}
{e.d}
{e.code}
);
})}
);
}
function MobPlataformas() {
return (
{/* Mesma mudança do desktop (ver PlataformasStrip): o rótulo virou
afirmação com o mecanismo explicado, e a faixa subiu pra logo depois
do hero. */}
Integrações nativas
A venda confirma sozinha.
O webhook oficial avisa o Comissa quando o pagamento é aprovado — a
venda entra paga, com taxa e comissão já calculadas.
{PLATAFORMAS.map((p) => (
{p.n}
))}
);
}
function MobGarantiaFaq() {
return (
Sem risco
14 dias grátis, sem cartão.
Se não fizer sentido pro seu dia, você não paga nada — não existe cobrança pra cancelar depois.