apiVersion: v1 kind: ConfigMap metadata: name: frontend-publico-texto namespace: plataforma-prod annotations: argocd.argoproj.io/sync-options: ServerSideApply=true data: _estilo.css: | /* Estilo mínimo, embutido nas páginas públicas. Sem fonte externa e sem CDN: uma página que declara cuidado com dado pessoal não deveria, ela própria, avisar um terceiro de que você a abriu. */ :root { --navy:#0B2C3D; --orange:#F58220; --paper:#F6F5F3; --muted:#5b6b75; --line:#e3e0dc; } * { box-sizing: border-box; } body { margin:0; background:var(--paper); color:var(--navy); font-family: 'Segoe UI', system-ui, -apple-system, Roboto, Helvetica, Arial, sans-serif; line-height:1.65; } header { background:var(--navy); color:#fff; padding:1.5rem 1rem; } header .marca { max-width:52rem; margin:0 auto; font-weight:700; letter-spacing:.02em; } header .marca span { color:var(--orange); } main { max-width:52rem; margin:0 auto; padding:2rem 1rem 4rem; } h1 { font-size:1.9rem; line-height:1.2; margin:.5rem 0 .25rem; } h2 { font-size:1.25rem; margin:2rem 0 .5rem; border-bottom:2px solid var(--line); padding-bottom:.3rem; } h3 { font-size:1.05rem; margin:1.5rem 0 .4rem; } .data { color:var(--muted); font-size:.9rem; margin-bottom:1.5rem; } table { border-collapse:collapse; width:100%; margin:1rem 0; font-size:.95rem; } th, td { border:1px solid var(--line); padding:.5rem .6rem; text-align:left; vertical-align:top; } th { background:#fff; } .destaque { background:#fff; border-left:4px solid var(--orange); padding:1rem 1.2rem; margin:1.5rem 0; } .minuta { background:#fff4e5; border:2px solid var(--orange); padding:1rem 1.2rem; margin:0 0 2rem; } .minuta strong { display:block; margin-bottom:.4rem; } .pendente { background:#ffe8e8; border:2px dashed #c62828; padding:1rem 1.2rem; margin:1.5rem 0; } footer { border-top:1px solid var(--line); margin-top:3rem; padding-top:1rem; color:var(--muted); font-size:.9rem; } a { color:#1565c0; } @media (max-width:40rem) { body { font-size:.97rem; } h1 { font-size:1.5rem; } } consentimento.js: | /* =========================================================================== * P2.9 — o portão de consentimento, antes de qualquer rastreamento de terceiro. * * ── POR QUE ISTO EXISTE ──────────────────────────────────────────────────── * * A política de privacidade que publicamos diz, em §8: * * "Não usamos cookies de publicidade nem de rastreamento de terceiros." * * No instante em que o Meta Pixel entrar no ar, essa frase vira **falsa** — e * ela não é marketing, é declaração pública de conformidade (LGPD art. 9º). * Preencher o `PIXEL_ID` sem resolver isto não publica um pixel: publica uma * mentira assinada. * * As duas saídas eram corrigir a política ou pedir consentimento. Este arquivo * é a segunda, que é a que mantém a promessa de pé. * * ── A REGRA QUE GOVERNA TUDO AQUI: FALHA FECHADA ─────────────────────────── * * Em toda dúvida, NÃO rastreia. Sem decisão, não rastreia. Com o localStorage * quebrado, não rastreia. Com o banner falhando ao montar, não rastreia. * * O contrário — rastrear por omissão — é exatamente o defeito que a LGPD trata, * e é o que acontece sozinho se ninguém escrever este arquivo. * * ── O QUE ESTE ARQUIVO NÃO COBRE ─────────────────────────────────────────── * * A LP carrega `fonts.googleapis.com` no ``, **antes de tudo isto**, e * isso entrega o IP do visitante ao Google sem consentimento. Não dá para * consertar daqui: o `` é servido no HTML. O conserto é hospedar a fonte * junto (`publico/fontes/`), e está no diário como pendência própria. * =========================================================================== */ (function (global) { 'use strict'; var CHAVE = 'atm.consentimento.v1'; var ACEITO = 'aceito'; var RECUSADO = 'recusado'; /* O localStorage joga exceção — e não devolve null — em janela anônima com * cookies bloqueados. Um `getItem` solto aqui derrubaria o script inteiro, e * com ele o formulário de lead, que é o que a página existe para fazer. */ function ler() { try { return global.localStorage.getItem(CHAVE); } catch (e) { return null; } } function gravar(valor) { try { global.localStorage.setItem(CHAVE, valor); } catch (e) { /* segue sem lembrar */ } } var decisao = ler(); var pendentes = []; /* `aoAceitar` é o único caminho por onde código de terceiro entra na página. * Quem chamar isto sem decisão tomada fica na fila; quem chamar depois de uma * recusa nunca roda. */ function aoAceitar(callback) { if (decisao === ACEITO) { callback(); return; } if (decisao === RECUSADO) { return; } pendentes.push(callback); } function decidir(valor) { decisao = valor; gravar(valor); var fila = pendentes; pendentes = []; if (valor === ACEITO) { for (var i = 0; i < fila.length; i++) { fila[i](); } } var banner = global.document.getElementById('atm-consentimento'); if (banner && banner.parentNode) { banner.parentNode.removeChild(banner); } } /* Recusar NÃO desfaz o que já carregou: o fbq já injetado continua na página * até o recarregamento. Por isso a recusa recarrega — é a única forma honesta * de "parar de rastrear" sem fingir que um `delete window.fbq` apaga o que já * foi para o servidor do terceiro. */ function recusar() { var jaCarregou = decisao === ACEITO && (global.fbq || global.gtag); decidir(RECUSADO); if (jaCarregou && global.location && global.location.reload) { global.location.reload(); } } var ESTILO_BOTAO = 'font:600 14px/1 inherit;padding:10px 18px;border-radius:8px;cursor:pointer;border:0;'; /** * Monta o banner. Não faz nada se já houver decisão — inclusive recusa: quem * disse não uma vez não é perguntado de novo a cada visita. */ function montarBanner(doc) { doc = doc || global.document; if (decisao === ACEITO || decisao === RECUSADO) { return null; } if (doc.getElementById('atm-consentimento')) { return null; } var caixa = doc.createElement('div'); caixa.id = 'atm-consentimento'; caixa.setAttribute('role', 'dialog'); caixa.setAttribute('aria-label', 'Consentimento para medição'); caixa.style.cssText = 'position:fixed;left:0;right:0;bottom:0;z-index:9999;background:#12161c;' + 'color:#e8edf4;padding:18px 20px;display:flex;flex-wrap:wrap;gap:14px;' + 'align-items:center;justify-content:center;box-shadow:0 -2px 18px rgba(0,0,0,.35);' + 'font:400 14px/1.5 system-ui,sans-serif;'; var texto = doc.createElement('p'); texto.style.cssText = 'margin:0;max-width:60ch;'; texto.innerHTML = 'Usamos medição do Meta e do Google só para saber se nossos anúncios ' + 'funcionam. Sem isso a página funciona igual, e o seu contato chega ' + 'do mesmo jeito. Política de ' + 'privacidade.'; /* Os dois botões são o MESMO elemento, com o mesmo tamanho e no mesmo lugar. * Recusa escondida atrás de "preferências", ou em cinza claro sobre branco, * é consentimento arrancado — e a ANPD trata como consentimento inválido. */ var aceitar = doc.createElement('button'); aceitar.type = 'button'; aceitar.id = 'atm-consentimento-aceitar'; aceitar.textContent = 'Aceitar'; aceitar.style.cssText = ESTILO_BOTAO + 'background:#28c76f;color:#06210f;'; var negar = doc.createElement('button'); negar.type = 'button'; negar.id = 'atm-consentimento-recusar'; negar.textContent = 'Recusar'; negar.style.cssText = ESTILO_BOTAO + 'background:#39434f;color:#e8edf4;'; aceitar.addEventListener('click', function () { decidir(ACEITO); }); negar.addEventListener('click', function () { decidir(RECUSADO); }); caixa.appendChild(texto); caixa.appendChild(aceitar); caixa.appendChild(negar); (doc.body || doc.documentElement).appendChild(caixa); return caixa; } /** Para o link no rodapé: permite mudar de ideia nos dois sentidos. */ function reabrir(doc) { decisao = null; try { global.localStorage.removeItem(CHAVE); } catch (e) { /* idem */ } return montarBanner(doc); } global.AtmConsentimento = { ACEITO: ACEITO, RECUSADO: RECUSADO, estado: function () { return decisao; }, aoAceitar: aoAceitar, aceitar: function () { decidir(ACEITO); }, recusar: recusar, montarBanner: montarBanner, reabrir: reabrir }; })(typeof window !== 'undefined' ? window : this); contratar.css: | /* A pagina /contratar. Arquivo proprio, e nao

Estamos preparando sua conta

Recebemos seu pagamento e estamos comecando.

Pode fechar esta pagina: o acesso tambem chega por e-mail, com um link para voce definir sua senha.

preparando.js: | /* =========================================================================== * P5.8 — a tela "estamos preparando sua conta". * * ── POR QUE ESTE SCRIPT NAO E INLINE ───────────────────────────────────────── * * A CSP servida pelo nginx diz `script-src 'self'`. Um