<!-- ==========================================================================
Sucessão — calculadora de custo e prazo
Prefixo: suc-
Requer: core (tokens, base, motion.css, motion.js) + estilo.css e script.js
Três controles (patrimônio, estado, herdeiros) e dois cartões que se
recalculam: inventário judicial contra holding familiar com doação em
vida. Cada cartão soma parcelas VISÍVEIS — soma que não mostra as
parcelas é chute com aparência de conta.
COMPLIANCE — leia antes de publicar:
· Os percentuais são ILUSTRATIVOS, referência 2026, e vivem numa tabela
no topo do script.js. ITCMD, custas e honorários mudam por estado, por
ano e por caso: troque pela tabela conferida com o jurídico do cliente.
· O ITCMD aparece nos DOIS cartões, com o MESMO valor. É intencional:
holding não elimina imposto — antecipa e organiza. Tirar essa linha do
cartão "com estrutura" transformaria a peça numa promessa de isenção.
· Prazo é sempre FAIXA ("de 16 a 36 meses"), nunca número único.
· O texto nunca diz "você vai economizar". Diz "nesta simulação, a
diferença entre os dois caminhos é X".
· Nada aqui coleta nome, e-mail ou telefone, e nada vai para
localStorage. A captura é do conversao/cta-formulario-lead, para onde
o botão final aponta.
Sem JavaScript: os três controles continuam navegáveis e os cartões
mostram o caso inicial escrito no HTML (R$ 8.000.000 · São Paulo ·
3 herdeiros). O <noscript> avisa que os números não recalculam.
========================================================================== -->
<sectionclass="sec-paper sec-pad"id="sucessao">
<divclass="wrap">
<divclass="sec-head suc-head">
<spanclass="eyebrow"data-rv>Sucessão</span>
<h2class="sec-title ttl">O que custa <em>não</em> planejar</h2>
<pclass="sec-lead"data-rvdata-d="1">Transferir patrimônio tem custo e prazo nos dois caminhos.
O que muda é quando a conta é feita — em vida, com estrutura, ou depois, no inventário.</p>
</div>
<!-- CONTEÚDO ILUSTRATIVO — percentuais de exemplo, referência 2026 -->
<divclass="suc"data-suc>
<!-- ---------------------------------------------------- os controles -->
<divclass="suc-controls"data-rvdata-d="1">
<divclass="suc-field suc-field-wealth">
<labelclass="suc-label"for="suc-wealth">Patrimônio a transferir</label>
<outputclass="suc-value"for="suc-wealth"aria-hidden="true"data-suc-out="wealth">R$ 8.000.000</output>
<inputclass="suc-range"type="range"id="suc-wealth"min="1000000"max="50000000"step="500000"value="8000000"aria-valuetext="R$ 8.000.000"data-suc-wealth>
<pclass="suc-hint"aria-hidden="true"><spanclass="suc-hint-end">R$ 1 mi</span><spanclass="suc-hint-end">R$ 50 mi</span></p>
</div>
<divclass="suc-field suc-field-state">
<labelclass="suc-label"for="suc-state">Estado do inventário</label>
<spanclass="suc-select-box">
<selectclass="suc-select"id="suc-state"data-suc-state>
<optionvalue="SP"selected>São Paulo</option>
<optionvalue="RJ">Rio de Janeiro</option>
<optionvalue="MG">Minas Gerais</option>
<optionvalue="PR">Paraná</option>
<optionvalue="RS">Rio Grande do Sul</option>
<optionvalue="SC">Santa Catarina</option>
<optionvalue="BA">Bahia</option>
<optionvalue="DF">Distrito Federal</option>
</select>
</span>
<pclass="suc-hint suc-hint-solo">A alíquota de ITCMD é definida por cada estado.</p>
</div>
<divclass="suc-field suc-field-heirs"role="group"aria-labelledby="suc-heirs-label">
<spanclass="suc-label"id="suc-heirs-label">Herdeiros</span>
<divclass="suc-stepper">
<buttonclass="btn-disc suc-step"type="button"data-suc-heirs="-1"aria-label="Um herdeiro a menos"aria-disabled="false">−</button>
<spanclass="suc-stepper-read"aria-live="polite">
<spanclass="suc-stepper-value"data-suc-out="heirs">3</span>
<spanclass="suc-stepper-unit"data-suc-out="heirs-unit">herdeiros</span>
</span>
<buttonclass="btn-disc suc-step"type="button"data-suc-heirs="1"aria-label="Um herdeiro a mais"aria-disabled="false">+</button>
</div>
<pclass="suc-hint suc-hint-solo">Mais herdeiros, inventário mais longo.</p>
</div>
</div>
<!-- ------------------------------------------------- os dois cartões -->
<divclass="suc-cards"data-rvdata-d="2">
<articleclass="suc-card suc-card-raw">
<headerclass="suc-card-head">
<h3class="suc-card-title">Sem planejamento</h3>
<spanclass="pill">Inventário judicial</span>
</header>
<dlclass="suc-lines">
<divclass="suc-line">
<dtclass="suc-line-label">ITCMD
<spanclass="suc-line-note"data-suc-out="raw-rate">São Paulo, 4,0%</span></dt>
<ddclass="suc-line-value"data-suc-out="raw-tax">R$ 320.000</dd>
</div>
<divclass="suc-line">
<dtclass="suc-line-label">Custas e emolumentos
<spanclass="suc-line-note">1,0% do patrimônio</span></dt>
<ddclass="suc-line-value"data-suc-out="raw-fees">R$ 80.000</dd>
</div>
<divclass="suc-line">
<dtclass="suc-line-label">Honorários advocatícios
<spanclass="suc-line-note">6,0% do patrimônio</span></dt>
<ddclass="suc-line-value"data-suc-out="raw-legal">R$ 480.000</dd>
</div>
</dl>
<pclass="suc-total">
<spanclass="suc-total-label">Custo estimado</span>
<strongclass="suc-total-value"data-suc-out="raw-total">R$ 880.000</strong>
<spanclass="suc-flag">estimativa ilustrativa · muda por estado, por ano e por caso</span>
</p>
<divclass="suc-bar"aria-hidden="true">
<spanclass="suc-bar-fill suc-bar-raw"style="--suc-bar:.733"data-suc-bar="raw"></span>
</div>
<pclass="suc-term">
<spanclass="suc-term-label">Prazo estimado</span>
<strongclass="suc-term-value"data-suc-out="raw-term">de 16 a 36 meses</strong>
</p>
<pclass="suc-say">O processo corre em juízo e o patrimônio fica indisponível até o fim.</p>
</article>
<articleclass="suc-card suc-card-plan">
<headerclass="suc-card-head">
<h3class="suc-card-title">Com estrutura</h3>
<spanclass="pill">Holding e doação em vida</span>
</header>
<dlclass="suc-lines">
<divclass="suc-line">
<dtclass="suc-line-label">ITCMD
<spanclass="suc-line-note"data-suc-out="plan-rate">antecipado na doação · São Paulo, 4,0%</span></dt>
<ddclass="suc-line-value"data-suc-out="plan-tax">R$ 320.000</dd>
</div>
<divclass="suc-line">
<dtclass="suc-line-label">Constituição e registros
<spanclass="suc-line-note">0,4% do patrimônio</span></dt>
<ddclass="suc-line-value"data-suc-out="plan-fees">R$ 32.000</dd>
</div>
<divclass="suc-line">
<dtclass="suc-line-label">Honorários de estruturação
<spanclass="suc-line-note">1,2% do patrimônio</span></dt>
<ddclass="suc-line-value"data-suc-out="plan-legal">R$ 96.000</dd>
</div>
</dl>
<pclass="suc-total">
<spanclass="suc-total-label">Custo estimado</span>
<strongclass="suc-total-value"data-suc-out="plan-total">R$ 448.000</strong>
<spanclass="suc-flag">estimativa ilustrativa · muda por estado, por ano e por caso</span>
</p>
<divclass="suc-bar"aria-hidden="true">
<spanclass="suc-bar-fill suc-bar-plan"style="--suc-bar:.373"data-suc-bar="plan"></span>
</div>
<pclass="suc-term">
<spanclass="suc-term-label">Prazo estimado</span>
<strongclass="suc-term-value"data-suc-out="plan-term">de 3 a 8 meses</strong>
</p>
<pclass="suc-say">A holding não elimina o imposto: antecipa e organiza a transferência.</p>
</article>
</div>
<!-- ------------------------------------------------------ a diferença -->
<divclass="suc-delta"data-rvdata-d="3">
<pclass="suc-delta-line"aria-live="polite">Nesta simulação, a diferença de custo entre os dois caminhos é
<strongclass="suc-delta-value"data-suc-out="delta">R$ 432.000</strong>,
<spanclass="suc-delta-term">e o prazo estimado passa de
<spandata-suc-out="delta-raw-term">16 a 36 meses</span> para
<spandata-suc-out="delta-plan-term">3 a 8 meses</span>.</span></p>
</div>
<pclass="nota suc-nota"data-rvdata-d="3">Simulação ilustrativa, para orientar a conversa —
<strongclass="suc-nota-strong">não é orientação jurídica ou tributária</strong> nem recomendação
de investimento. Alíquotas de ITCMD, custas e honorários mudam por estado, por ano e por caso;
os percentuais usados aqui são de referência <spandata-suc-out="ano">2026</span>. Cada situação
exige análise de advogado e contador.</p>
<!-- O core esconde [data-rv] e .ttl (opacity:0) e só o motion.js os
revela: sem JavaScript, a dobra inteira ficaria em branco — casca
vazia, que é justamente o que não pode acontecer. Este <style> vive
dentro do <noscript> porque é a única regra que o navegador só pode
aplicar QUANDO NÃO HÁ script: um seletor equivalente em estilo.css
piscaria (visível, depois escondido pelo core, depois revelado).
Escopo no prefixo, para não desarmar o reveal do resto da página.
A saída definitiva é do core — ver o gotcha e a ficha. -->
<noscript>
<style>
.suc-head .ttl,
.suc-head [data-rv],
.suc [data-rv]{opacity:1;filter:none;transform:none}
</style>
<pclass="nota suc-nota suc-nota-static">Com o JavaScript desativado, os cartões acima mostram um caso
fixo — R$ 8.000.000, São Paulo, 3 herdeiros. Os controles continuam navegáveis, mas os números
não recalculam.</p>
</noscript>
<divclass="suc-cta"data-rvdata-d="3">
<aclass="btn btn-primary"href="#diagnostico">Falar sobre a sua estrutura</a>
</div>
</div>
</div>
</section>
estilo.css · 332 linhas · 12,7 KB
/* ==========================================================================
Sucessão — calculadora de custo e prazo
Prefixo: suc-
Tokens: --accent --display --ease --fg --fg-2 --fg-muted --radius-media
--radius-pill --rule --rule-2 --sans
Primitivas do core (usadas, não recopiadas): .wrap .sec-pad .sec-head
.eyebrow .sec-title .sec-lead .pill .btn .btn-primary .btn-disc
AJUSTES PÚBLICOS — todos na raiz .suc, todos com unidade e padrão:
--suc-gap respiro entre painel de controles e cartões (px)
--suc-card-pad respiro interno do cartão (px)
--suc-bar-h altura da barra de custo (px, padrão 8px)
--suc-thumb diâmetro do polegar da faixa (px, padrão 20px)
--suc-surface cor do painel de controles (calculada a partir de --fg)
--suc-line cor da borda de painel e cartão (idem)
--suc-mark a cor de marca em FORMA — polegar, trilho, barra, borda
--suc-mark-text a mesma marca em TEXTO — só o número da diferença
Os quatro saem de --fg, e não de um cinza fixo, para o componente
sobreviver a qualquer escopo de tom: em .sec-paper viram um véu escuro
sobre branco; em .sec-dark, um véu claro sobre preto. Não existe
--light-rgb no core, então color-mix é o único caminho honesto aqui.
========================================================================== */.suc{
--suc-gap:clamp(22px,3vw,32px);
--suc-card-pad:clamp(22px,2.6vw,34px);
--suc-bar-h:8px;
--suc-thumb:20px;
--suc-surface:color-mix(in srgb,var(--fg) 3.5%,transparent);
--suc-line:color-mix(in srgb,var(--fg) 13%,transparent);
/* MEDIDO, e a razão de --accent nunca aparecer puro aqui: o sage da
Liberta (#c6ceaa) contra o creme da dobra clara (#ede9e3) dá 1,32:1 —
some. Em .sec-dark o mesmo sage dá 9:1 e brilha. Um componente que só
vive no escuro pode usar --accent puro; este nasce em .sec-paper.
A saída é misturar a marca com o TEXTO da própria seção, e não com
transparente: escurece o sage sobre o creme e clareia o mesmo sage
sobre o preto, sem o componente saber em qual escopo caiu.
Duas dosagens medidas contra o creme: forma 50% -> 3,2:1 (o piso de
1.4.11 para controle e gráfico); texto 45% -> 4,6:1 (o piso de 1.4.3).
O <em> do título e o .pill continuam do core, e a peça não põe número
nenhum neles. */--suc-mark:color-mix(in srgb,var(--accent) 50%,var(--fg));
--suc-mark-text:color-mix(in srgb,var(--accent) 45%,var(--fg));
margin-top:clamp(38px,5.5vh,62px);
}
/* ------------------------------------------------------------ controles
Painel único para os três campos: eles pertencem à mesma pergunta, e
soltos na coluna leem como três blocos sem relação. */.suc-controls{
display:grid;
grid-template-columns:1.5fr1fr1fr;
gap:var(--suc-gap);
align-items:start;
padding:var(--suc-card-pad);
border:1px solid var(--suc-line);
border-radius:var(--radius-media);
background:var(--suc-surface);
}
.suc-label{
display:block;
font-family:var(--sans);font-weight:400;
font-size:11.5px;line-height:1.4;letter-spacing:.16em;text-transform:uppercase;
color:var(--fg-muted);
}
/* O valor grande é o mesmo desenho nos três campos — patrimônio, estado e
herdeiros — para a fileira ler como uma linha só. */.suc-value,
.suc-select,
.suc-stepper-value{
font-family:var(--display);font-weight:700;
letter-spacing:-.02em;color:var(--fg);
font-variant-numeric:tabular-nums;
}
.suc-value{
display:block;margin-top:12px;
font-size:clamp(24px,2.6vw,32px);line-height:1.1;
}
/* --------------------------------------------------------- faixa (range)
Altura de 20px na CAIXA e trilho de 3px pintado no ::track: a caixa é o
alvo do ponteiro, o trilho é só a linha. Um input de 3px de altura tem
alvo de clique de 3px — só o polegar é clicável. */.suc-range{
-webkit-appearance:none;appearance:none;
display:block;width:100%;
height:var(--suc-thumb);
margin-top:16px;
background:none;border:0;
/* fração já preenchida do trilho; o script reescreve a cada input.
14.3% = (8.000.000 − 1.000.000) / 49.000.000, o caso do markup. */--suc-fill:14.3%;
}
.suc-range::-webkit-slider-runnable-track{
height:3px;border-radius:var(--radius-pill);
background:linear-gradient(to right,
var(--suc-mark) 0var(--suc-fill),
var(--rule-2) var(--suc-fill) 100%);
}
.suc-range::-moz-range-track{
height:3px;border-radius:var(--radius-pill);
background:linear-gradient(to right,
var(--suc-mark) 0var(--suc-fill),
var(--rule-2) var(--suc-fill) 100%);
}
.suc-range::-webkit-slider-thumb{
-webkit-appearance:none;appearance:none;
width:var(--suc-thumb);height:var(--suc-thumb);
border:0;border-radius:50%;background:var(--suc-mark);
margin-top:calc((3px - var(--suc-thumb)) / 2);
transition:box-shadow .3svar(--ease);
}
.suc-range::-moz-range-thumb{
width:var(--suc-thumb);height:var(--suc-thumb);
border:0;border-radius:50%;background:var(--suc-mark);
transition:box-shadow .3svar(--ease);
}
/* Halo no arrasto: cresce o alvo visual sem mexer no layout. */.suc-range:hover::-webkit-slider-thumb,
.suc-range:active::-webkit-slider-thumb{
box-shadow:0007pxcolor-mix(in srgb,var(--accent) 20%,transparent);
}
.suc-range:hover::-moz-range-thumb,
.suc-range:active::-moz-range-thumb{
box-shadow:0007pxcolor-mix(in srgb,var(--accent) 20%,transparent);
}
@media(prefers-reduced-motion:reduce){
.suc-range::-webkit-slider-thumb{transition:none}
.suc-range::-moz-range-thumb{transition:none}
}
.suc-hint{
display:flex;justify-content:space-between;gap:12px;
margin-top:10px;
font-size:11.5px;line-height:1.5;letter-spacing:.06em;
color:var(--fg-muted);
}
/* Dica de uma frase só: volta a ser bloco, sem as duas pontas da régua. */.suc-hint-solo{display:block;max-width:34ch}
/* --------------------------------------------------------------- estado
<select> nativo, e não o conversao/select-custom: aqui a lista tem oito
itens curtos e nenhum desenho por item, e o nativo entrega o teclado, a
busca por letra e a roda do celular de graça. */.suc-select-box{position:relative;display:block;margin-top:16px}
.suc-select{
-webkit-appearance:none;appearance:none;
width:100%;font-size:17px;line-height:1.35;
padding:030px12px0;
background:none;border:0;border-bottom:1px solid var(--rule-2);border-radius:0;
cursor:pointer;
transition:border-color .3svar(--ease);
}
.suc-select:hover{border-bottom-color:var(--suc-mark)}
/* Seta desenhada com duas bordas, e não imagem: herda a cor do texto de
apoio e acompanha o tema sem um SVG com cor crua embutida. */.suc-select-box::after{
content:"";position:absolute;right:7px;top:7px;
width:8px;height:8px;
border-right:1px solid var(--fg-muted);
border-bottom:1px solid var(--fg-muted);
transform:rotate(45deg);
pointer-events:none;
}
/* ------------------------------------------------------------ herdeiros */.suc-stepper{display:flex;align-items:center;gap:14px;margin-top:12px}
.suc-step{font-family:var(--display);font-weight:700;font-size:19px;line-height:1}
.suc-stepper-read{display:flex;flex-direction:column;line-height:1.05}
.suc-stepper-value{font-size:clamp(24px,2.6vw,32px)}
.suc-stepper-unit{
margin-top:4px;
font-size:11.5px;line-height:1.4;letter-spacing:.14em;text-transform:uppercase;
color:var(--fg-muted);
}
/* ------------------------------------------------------- os dois cartões */.suc-cards{
display:grid;grid-template-columns:1fr1fr;
gap:var(--suc-gap);margin-top:var(--suc-gap);
}
.suc-card{
display:flex;flex-direction:column;
padding:var(--suc-card-pad);
border:1px solid var(--suc-line);
border-radius:var(--radius-media);
}
/* O caminho estruturado é o único marcado na cor de marca — borda e barra.
O outro fica em neutro: carregar o inventário na cor da casa inverteria
a leitura. */.suc-card-plan{border-color:var(--suc-mark)}
.suc-card-head{display:flex;flex-wrap:wrap;align-items:center;gap:10px14px}
.suc-card-title{
font-family:var(--display);font-weight:700;
font-size:19px;line-height:1.2;letter-spacing:-.02em;color:var(--fg);
}
/* ---------------------------------------------------------- as parcelas
Cada parcela com o percentual ao lado do nome. Soma que não mostra as
parcelas é chute com aparência de conta — e num número que fala de
imposto isso não é detalhe de estilo. */.suc-lines{margin:22px00;display:grid;gap:0}
.suc-line{
display:flex;justify-content:space-between;align-items:baseline;gap:16px;
padding:12px0;
border-bottom:1px solid var(--rule);
}
.suc-line-label{margin:0;font-size:14px;line-height:1.4;color:var(--fg-2)}
.suc-line-note{
display:block;margin-top:4px;
font-size:11.5px;line-height:1.4;letter-spacing:.05em;
color:var(--fg-muted);
}
.suc-line-value{
margin:0;white-space:nowrap;
font-family:var(--display);font-weight:700;
font-size:15px;letter-spacing:-.01em;color:var(--fg);
font-variant-numeric:tabular-nums;
}
/* margin-top:auto encosta o bloco do total no pé do cartão: os dois cartões
têm alturas de cabeçalho diferentes (a pílula da direita quebra em duas
linhas antes), e sem isto os dois totais não ficariam na mesma altura. */.suc-total{margin-top:auto;padding-top:22px}
.suc-total-label{
display:block;
font-size:11.5px;line-height:1.4;letter-spacing:.16em;text-transform:uppercase;
color:var(--fg-muted);
}
.suc-total-value{
display:block;margin-top:6px;
font-family:var(--display);font-weight:700;
font-size:clamp(28px,3.2vw,40px);line-height:1.05;letter-spacing:-.025em;
color:var(--fg);font-variant-numeric:tabular-nums;
}
/* A ressalva colada no número, não no rodapé: é aqui que a pessoa lê. */.suc-flag{
display:block;margin-top:8px;
font-size:11px;line-height:1.45;letter-spacing:.04em;
color:var(--fg-muted);
}
/* ------------------------------------------------------------- a barra
Decorativa (aria-hidden): quem usa leitor de tela recebe os números do
.suc-total e do .suc-term, não "gráfico". O raio fica no TRILHO, com
overflow:hidden — no preenchimento, scaleX esmagaria a ponta em elipse. */.suc-bar{
height:var(--suc-bar-h);margin-top:18px;
border-radius:var(--radius-pill);overflow:hidden;
background:color-mix(in srgb,var(--fg) 9%,transparent);
}
.suc-bar-fill{
display:block;width:100%;height:100%;
transform-origin:left center;
transform:scaleX(var(--suc-bar,1));
transition:transform .55svar(--ease);
}
.suc-bar-raw{background:color-mix(in srgb,var(--fg) 55%,transparent)}
.suc-bar-plan{background:var(--suc-mark)}
@media(prefers-reduced-motion:reduce){
.suc-bar-fill{transition:none}
}
.suc-term{
display:flex;justify-content:space-between;align-items:baseline;gap:14px;
margin-top:16px;
}
.suc-term-label{
font-size:11.5px;line-height:1.4;letter-spacing:.16em;text-transform:uppercase;
color:var(--fg-muted);
}
.suc-term-value{
font-family:var(--display);font-weight:700;
font-size:15px;letter-spacing:-.01em;color:var(--fg);white-space:nowrap;
}
.suc-say{
margin-top:16px;max-width:46ch;
font-size:13.5px;line-height:1.55;color:var(--fg-muted);
}
/* ---------------------------------------------------------- a diferença */.suc-delta{
margin-top:var(--suc-gap);
padding-top:clamp(22px,3vh,30px);
border-top:1px solid var(--suc-line);
}
.suc-delta-line{
max-width:72ch;
font-size:clamp(17px,1.7vw,21px);line-height:1.55;color:var(--fg);
}
.suc-delta-value{
font-family:var(--display);font-weight:700;
font-size:1.35em;letter-spacing:-.02em;color:var(--suc-mark-text);
font-variant-numeric:tabular-nums;
white-space:nowrap;
}
.suc-delta-term{color:var(--fg-2)}
/* ---------------------------------------------------------- a ressalva *//* Corpo, entrelinha e tinta vêm da primitiva .nota do core. Fica a posição e a
medida: 88ch porque esta ressalva é longa e acompanha a largura dos dois
cartões de cenário — em 74ch ela viraria um bloco estreito no meio deles. */.suc-nota{
margin-top:20px;
--nota-max:88ch;
}
.suc-nota-strong{font-weight:600;color:var(--fg-2)}
.suc-nota-static{margin-top:14px}
.suc-cta{margin-top:clamp(26px,3.5vh,38px)}
/* ============================================================== mobile */@media(max-width:980px){
.suc-controls{grid-template-columns:1fr1fr}
.suc-field-wealth{grid-column:1 / -1}
.suc-cards{grid-template-columns:1fr}
/* Empilhados, os dois totais já não se comparam lado a lado: o
margin-top:auto só gastaria respiro no fim do primeiro cartão. */.suc-total{margin-top:0}
}
@media(max-width:620px){
.suc-controls{grid-template-columns:1fr;gap:26px}
.suc-field-wealth{grid-column:auto}
.suc-line{flex-direction:column;align-items:flex-start;gap:6px}
.suc-term{flex-direction:column;align-items:flex-start;gap:4px}
.suc-delta-value{white-space:normal}
}
script.js · 259 linhas · 11,2 KB
/* ==========================================================================
Sucessão — calculadora de custo e prazo
Prefixo: suc-
Lê os três controles, recalcula os dois cartões e escreve o resultado no
texto que já está no HTML. Sem lib, sem gráfico em canvas: a única forma
é a barra, movida por scaleX numa custom property.
O que este script NÃO faz, de propósito: não guarda nada em localStorage,
não coleta nome, e-mail ou telefone e não manda nada para lugar nenhum.
São dados patrimoniais de alguém; a captura é do
conversao/cta-formulario-lead, para onde o botão final aponta.
========================================================================== */
(function () {
var raizes = document.querySelectorAll('[data-suc]');
if (!raizes.length) return;
/* ======================================================================
TABELA ILUSTRATIVA — REFERÊNCIA 2026
----------------------------------------------------------------------
ATENÇÃO, quem for publicar: estes percentuais são de EXEMPLO, para dar
ordem de grandeza a uma conversa. Não são tabela oficial.
· O ITCMD é estadual: cada unidade da federação fixa a sua alíquota, e
várias delas são PROGRESSIVAS por faixa de valor. O número abaixo é o
topo da progressiva onde ela existe — a leitura de patrimônio alto.
· Custas, emolumentos e honorários mudam por comarca, por tabela da
seccional da OAB e por complexidade do caso. Tabelas reais de
honorários costumam ser REGRESSIVAS (o percentual cai conforme o
espólio cresce); aqui são lineares, para a conta ficar auditável
linha a linha.
· Antes de ir ao ar, troque tudo isto pela tabela conferida com o
jurídico e o contábil do cliente, e atualize o ano na ressalva do
markup e no rótulo ANO_REF.
====================================================================== */var ANO_REF = '2026';
var ESTADOS = {
SP: { nome: 'São Paulo', itcmd: 4.0 },
RJ: { nome: 'Rio de Janeiro', itcmd: 8.0 },
MG: { nome: 'Minas Gerais', itcmd: 5.0 },
PR: { nome: 'Paraná', itcmd: 4.0 },
RS: { nome: 'Rio Grande do Sul', itcmd: 6.0 },
SC: { nome: 'Santa Catarina', itcmd: 8.0 },
BA: { nome: 'Bahia', itcmd: 8.0 },
DF: { nome: 'Distrito Federal', itcmd: 6.0 }
};
/* Percentuais sobre o patrimônio transferido. */var SEM = { custas: 1.0, honorarios: 6.0 }; /* inventário judicial */var COM = { custas: 0.4, honorarios: 1.2 }; /* holding + doação em vida *//* Prazo em MESES, sempre faixa. Mais herdeiros, inventário mais longo:
é o número de acordos a fechar, não o valor, que estica o processo. */function prazoSem(h) { return [12 + (h - 1) * 2, 24 + (h - 1) * 6]; }
function prazoCom(h) { return [3, 6 + (h - 1)]; }
var HERD_MIN = 1, HERD_MAX = 6;
var DUR_CONTA = 380; /* ms da contagem da diferença *//* Teto da tabela — usado SÓ como escala das duas barras, para que as duas
se movam quando o estado muda. Se a escala fosse o total do cartão da
esquerda, ele ficaria cheio para sempre e a troca de estado não
apareceria em forma nenhuma. */var TETO = 0;
for (var uf in ESTADOS) {
if (ESTADOS.hasOwnProperty(uf) && ESTADOS[uf].itcmd > TETO) TETO = ESTADOS[uf].itcmd;
}
var ESCALA_PCT = TETO + SEM.custas + SEM.honorarios;
/* ---------------------------------------------------------- formatação */function moeda(v) {
var s = String(Math.round(v)), saida = '', c = 0;
for (var i = s.length - 1; i >= 0; i--) {
saida = s.charAt(i) + saida;
c++;
if (c % 3 === 0 && i > 0) saida = '.' + saida;
}
return'R$ ' + saida;
}
function pct(v) { return v.toFixed(1).replace('.', ',') + '%'; }
function faixa(par) { return'de ' + par[0] + ' a ' + par[1] + ' meses'; }
/* A mesma faixa sem o "de" inicial: na frase da diferença ele já veio no
"passa DE ... para ...", e repetido sairia "para de 3 a 8 meses". */function faixaCurta(par) { return par[0] + ' a ' + par[1] + ' meses'; }
function reduzido() {
if (window.LIB && typeof window.LIB.reduce === 'boolean') return window.LIB.reduce;
return matchMedia('(prefers-reduced-motion: reduce)').matches &&
location.search.indexOf('motion=on') < 0;
}
/* ---------------------------------------------------------------- init */function iniciar(raiz) {
var range = raiz.querySelector('[data-suc-wealth]');
var select = raiz.querySelector('[data-suc-state]');
var passos = raiz.querySelectorAll('[data-suc-heirs]');
var barras = raiz.querySelectorAll('[data-suc-bar]');
if (!range || !select) return;
/* Mapa das saídas de texto, montado uma vez: o render não volta a
consultar o DOM. */var saida = {};
var alvos = raiz.querySelectorAll('[data-suc-out]');
for (var i = 0; i < alvos.length; i++) {
saida[alvos[i].getAttribute('data-suc-out')] = alvos[i];
}
var barra = {};
for (var b = 0; b < barras.length; b++) {
barra[barras[b].getAttribute('data-suc-bar')] = barras[b];
}
/* Estado em MEMÓRIA, e só. Morre no recarregamento — de propósito. */var est = {
wealth: parseFloat(range.value) || 8000000,
uf: select.value || 'SP',
herdeiros: parseInt((saida.heirs && saida.heirs.textContent) || '3', 10) || 3,
/* mostrado = o número que está PINTADO na tela, não o alvo. É o que
permite a contagem recomeçar de onde o olho parou em vez de saltar
para trás a cada quadro de arrasto. null na largada: o markup já
traz o valor certo e a primeira passada não conta nada. */
mostrado: null,
raf: 0
};
function escrever(chave, texto) {
var el = saida[chave];
if (el && el.textContent !== texto) el.textContent = texto;
}
/* ------------------------------------------------------- a contagem
Só a diferença conta; os totais dos cartões trocam secos, porque são
seis números ao mesmo tempo e seis contagens simultâneas viram ruído.
A contagem parte de est.mostrado — o valor PINTADO —, e não do alvo
anterior. Reiniciada a cada quadro de arrasto, ela vira um filtro:
cada quadro anda ~12% do que falta, o número persegue o polegar com
~130ms de atraso e assenta sozinho quando o arrasto para. Partindo do
alvo anterior, cada quadro daria um salto para trás. */function contar(el, para) {
if (est.raf) { cancelAnimationFrame(est.raf); est.raf = 0; }
/* Movimento reduzido: o número aparece no valor final, sem contagem.
Idem na primeira passada, quando não há de onde partir. */if (est.mostrado === null || reduzido()) {
est.mostrado = para;
el.textContent = moeda(para);
return;
}
var de = est.mostrado, t0 = 0;
function passo(agora) {
if (!t0) t0 = agora;
var t = Math.min(1, (agora - t0) / DUR_CONTA);
var e = 1 - Math.pow(1 - t, 3);
est.mostrado = de + (para - de) * e;
el.textContent = moeda(est.mostrado);
/* O laço dorme assim que chega ao fim: nada roda em repouso. */if (t < 1) { est.raf = requestAnimationFrame(passo); }
else { est.mostrado = para; est.raf = 0; }
}
est.raf = requestAnimationFrame(passo);
}
/* --------------------------------------------------------- o cálculo */function render() {
var p = est.wealth;
var uf = ESTADOS[est.uf] ? est.uf : 'SP';
var e = ESTADOS[uf];
var h = est.herdeiros;
var imposto = p * e.itcmd / 100; /* o MESMO nos dois lados */var semCustas = p * SEM.custas / 100;
var semHon = p * SEM.honorarios / 100;
var semTotal = imposto + semCustas + semHon;
var comCustas = p * COM.custas / 100;
var comHon = p * COM.honorarios / 100;
var comTotal = imposto + comCustas + comHon;
var pSem = prazoSem(h), pCom = prazoCom(h);
/* faixa (range) */var min = parseFloat(range.min), max = parseFloat(range.max);
range.style.setProperty('--suc-fill', ((p - min) / (max - min) * 100).toFixed(1) + '%');
range.setAttribute('aria-valuetext', moeda(p));
escrever('wealth', moeda(p));
/* herdeiros */
escrever('heirs', String(h));
escrever('heirs-unit', h === 1 ? 'herdeiro' : 'herdeiros');
for (var k = 0; k < passos.length; k++) {
var d = parseInt(passos[k].getAttribute('data-suc-heirs'), 10);
var trava = (d < 0 && h <= HERD_MIN) || (d > 0 && h >= HERD_MAX);
/* aria-disabled e não disabled: um botão desabilitado perde o foco
que já estava nele, e o teclado cai fora do grupo no meio do uso.
O core desenha o estado apagado para os dois. */
passos[k].setAttribute('aria-disabled', trava ? 'true' : 'false');
}
/* cartão sem planejamento */
escrever('raw-rate', e.nome + ', ' + pct(e.itcmd));
escrever('raw-tax', moeda(imposto));
escrever('raw-fees', moeda(semCustas));
escrever('raw-legal', moeda(semHon));
escrever('raw-total', moeda(semTotal));
escrever('raw-term', faixa(pSem));
/* cartão com estrutura — a linha de ITCMD repete o MESMO valor, e o
rótulo diz "antecipado na doação". Holding não elimina imposto;
apagar esta linha faria a peça prometer isenção. */
escrever('plan-rate', 'antecipado na doação · ' + e.nome + ', ' + pct(e.itcmd));
escrever('plan-tax', moeda(imposto));
escrever('plan-fees', moeda(comCustas));
escrever('plan-legal', moeda(comHon));
escrever('plan-total', moeda(comTotal));
escrever('plan-term', faixa(pCom));
/* as barras */var escala = p * ESCALA_PCT / 100;
if (barra.raw) barra.raw.style.setProperty('--suc-bar', (semTotal / escala).toFixed(3));
if (barra.plan) barra.plan.style.setProperty('--suc-bar', (comTotal / escala).toFixed(3));
/* a diferença — subtração dos dois totais, nunca "economia" */var dif = semTotal - comTotal;
if (saida.delta) contar(saida.delta, dif);
escrever('delta-raw-term', faixaCurta(pSem));
escrever('delta-plan-term', faixaCurta(pCom));
escrever('ano', ANO_REF);
}
/* ------------------------------------------------------- os controles */
range.addEventListener('input', function () {
est.wealth = parseFloat(range.value);
render();
});
select.addEventListener('change', function () {
est.uf = select.value;
render();
});
for (var j = 0; j < passos.length; j++) {
passos[j].addEventListener('click', function () {
var d = parseInt(this.getAttribute('data-suc-heirs'), 10);
var novo = Math.min(HERD_MAX, Math.max(HERD_MIN, est.herdeiros + d));
if (novo === est.herdeiros) return;
est.herdeiros = novo;
render();
});
}
/* Primeira passada sem contagem: o HTML já traz o caso inicial escrito,
e este render só confirma que o texto e o modelo dizem o mesmo. Se um
dia divergirem, o modelo vence — e o preview mostra a divergência. */
render();
}
for (var r = 0; r < raizes.length; r++) iniciar(raizes[r]);
})();
Dobra clara com três controles numa fileira — patrimônio em faixa, estado em select, herdeiros em passo-a-passo — e dois cartões que se recalculam lado a lado: inventário judicial contra holding familiar com doação em vida. Cada cartão soma parcelas visíveis (ITCMD, custas, honorários), mostra prazo em faixa e uma barra horizontal em scaleX, as duas na mesma escala. Abaixo, a diferença em destaque, contando quando muda.
O problema editorial é o de sempre em sucessão: ninguém age por um argumento abstrato sobre organização, mas quase todo mundo reage a uma ordem de grandeza. A peça troca o discurso por uma conta que a pessoa mesma monta — e por isso a conta tem de aparecer inteira, parcela a parcela. Soma que não mostra as parcelas é chute com aparência de conta, e num número que fala de imposto isso deixa de ser detalhe de estilo.
Quando usar
Numa página de planejamento patrimonial ou sucessório, depois do argumento e antes do formulário. É a peça que transforma "vale a pena conversar" em "quanto custa não conversar".
Como dobra clara de respiro no meio de uma página escura: a leitura é de relatório, não de campanha.
Quando o cliente já tem jurídico ou parceiro de sucessão para conferir a tabela. Sem isso, não publique.
Quando não usar
Para falar de rentabilidade ou de crescimento de carteira. Isso é conversao/calculadora-projecao, que desenha faixa entre cenários — aqui não há projeção nenhuma, só custo de transmissão.
Em página sem espaço para a ressalva inteira. A ressalva não encolhe.
Padrão editorial
Slot
Regra
Olho
Uma palavra — o assunto, não a promessa. "Sucessão".
Título
Até 6 palavras. O <em> marca a palavra que inverte o sentido ("não"), nunca um adjetivo.
Apoio
Duas linhas, ~30 palavras. Tem de dizer que os dois caminhos têm custo — é o que impede a dobra de ler como propaganda de holding.
Rótulo de controle
Substantivo, 2 a 4 palavras, caixa alta.
Dica sob o controle
Uma frase, teto de 34ch. Explica o parâmetro, não vende.
Nome do cartão
2 ou 3 palavras, sem adjetivo de valor: "Sem planejamento", não "O caminho caro".
Pílula
O nome do instrumento jurídico, não um slogan.
Parcela
Nome da despesa + o percentual visível ao lado. Parcela sem percentual não entra.
Frase do cartão
Uma frase, até 15 palavras. A do cartão estruturado tem de dizer o que a estrutura não faz.
Ressalva
Texto fixo. Encurtar é o único jeito de errar aqui.
Botão
Verbo + o assunto da conversa. Nunca "simular de novo".
Especificação dos assets
Nenhum. Sem foto, sem ícone, sem SVG de biblioteca. É deliberado: número que fala de imposto e de morte sobre foto de família feliz é exatamente o registro a evitar. As duas barras são <span> com transform:scaleX(), e não SVG, porque não há eixo, série nem caminho a desenhar — o dado é o texto do cartão, e as barras levam aria-hidden="true".
Compliance
Esta é a parte cara da peça. O que o consumidor tem de fazer antes de publicar:
Trocar a tabela.ESTADOS, SEM e COM, no topo do script.js, são ilustrativos, referência 2026. O ITCMD é estadual e várias unidades da federação são progressivas — o número ali é o topo da progressiva. Custas, emolumentos e honorários mudam por comarca, por tabela da seccional da OAB e por complexidade. Tabelas reais de honorários costumam ser regressivas; as daqui são lineares, para a conta ficar auditável linha a linha.
Atualizar o ano na constante ANO_REF do script (o markup lê a mesma constante em [data-suc-out="ano"], então os dois não divergem).
Passar pela área de compliance e pelo jurídico do cliente, com a tabela final, antes de ir ao ar.
Não mexer na ressalva. Ela diz, com estas palavras: simulação ilustrativa, não é orientação jurídica ou tributária, alíquotas e custas mudam por estado e por ano, cada caso exige análise de advogado e contador. Fora dela, cada total carrega um .suc-flag colado ao número — "estimativa ilustrativa · muda por estado, por ano e por caso" —, porque a ressalva tem de estar onde a pessoa lê o número, não no rodapé.
O que a peça já garante e não pode ser desfeito na adaptação:
O ITCMD aparece nos dois cartões, com o mesmo valor. Holding não elimina imposto: antecipa e organiza. Apagar essa linha do cartão estruturado transformaria a peça numa promessa de isenção.
O texto nunca diz "você vai economizar X". Diz "nesta simulação, a diferença de custo entre os dois caminhos é X".
Prazo é sempre faixa ("de 16 a 36 meses"), nunca número único.
Nenhum dado pessoal. Não coleta nome, e-mail nem telefone, não grava em localStorage e não manda nada para lugar nenhum. As respostas vivem em memória e morrem no recarregamento — são dados patrimoniais de alguém, e a captura é trabalho do conversao/cta-formulario-lead.
Os id do markup (suc-wealth, suc-state, suc-heirs-label) existem porque for e aria-labelledby exigem. O botão final aponta para #diagnostico: troque pela âncora do formulário do projeto.
Ganchos
[data-suc] a raiz · [data-suc-wealth] a faixa (min/max/step no markup) · [data-suc-state] o select · [data-suc-heirs="-1|1"] os dois botões · [data-suc-out="..."] as dezenove saídas de texto · [data-suc-bar="raw|plan"] as duas barras. Variáveis: --suc-gap--suc-card-pad--suc-bar-h--suc-thumb--suc-surface--suc-line--suc-mark--suc-mark-text na raiz, --suc-bar em cada barra, --suc-fill na faixa.
Variações
Sem o cartão comparativo — só o custo do inventário, para uma dobra que ainda não vai falar de holding. Some a frase da diferença junto.
Quatro parcelas — cabe uma quinta linha por cartão antes de o total sair da dobra em 1440×900.
Estado fixo — para quem atende uma praça só. A alíquota continua tendo de aparecer na linha de ITCMD.
Dobra escura — --suc-surface, --suc-line e --suc-mark já se viram sozinhos, porque saem de --fg. O ajuste que sobra é o <select>: a lista suspensa é do sistema e continua clara.
Gotchas
O ITCMD nos dois cartões tem uma consequência que confunde na primeira leitura. Como o imposto é o mesmo dos dois lados, a diferença é sempre 5,4% do patrimônio, em qualquer estado. Medido: SP → RJ move os dois totais (880.000 → 1.200.000 e 448.000 → 768.000) e não move a diferença (432.000). O estado muda o custo, não o valor de organizar. Se alguém pedir para "fazer o estado mexer na diferença", a única forma seria tirar o imposto de um dos lados — que é justamente o que não pode.
A escala das barras é o teto da tabela, não o cartão maior.escala = patrimônio × 15% (8% da maior alíquota + 1% + 6%). Em SP as barras ficam em .733 e .373; em RJ, 1.000 e .640. Com a escala no total da esquerda, ela ficaria em 1.000 para sempre e a troca de estado não apareceria em forma nenhuma. Efeito colateral aceito: mover o patrimônio não move as barras — com percentuais lineares, a proporção entre os dois caminhos não depende do tamanho do espólio.
A contagem parte do valor PINTADO, não do alvo anterior. Medido com DUR_CONTA de 380ms: 432.000 → 1.441.690 em 100ms → 2.160.000 em 400ms. Reiniciada a cada quadro de arrasto ela vira um filtro — cada quadro anda ~12% do que falta, ~130ms de atraso — e assenta sozinha quando o arrasto para. Partindo do alvo anterior, cada quadro daria um salto para trás.
--accent puro não sobrevive à dobra clara, e isso foi medido. Sage #c6ceaa contra o creme #ede9e3 dá 1,32:1. Daí --suc-mark (50% de accent sobre --fg) e --suc-mark-text (45%), medidos em 3,4:1 na barra e 4,6:1 no número da diferença. O <em> do título fica em 1,36:1 e é do core: a peça não põe número nenhum nele, mas se dobra clara virar padrão, o core precisa de um accent de tinta.
O <noscript><style> não é gambiarra, é o único lugar possível. O core traz [data-rv]{opacity:0} e só o motion.js devolve — sem script, a dobra inteira sairia em branco, que é a "casca vazia" proibida. Um seletor equivalente em estilo.css piscaria (visível, escondido pelo core, revelado). Verificado com javaScriptEnabled:false de verdade: os doze blocos aparecem, os sete números estão lá, as barras nascem em 339px e 172px e o aviso do <noscript> sai. Apagar as tags <script>não serve de teste — com scripting ligado, o miolo do <noscript> continua sendo texto.
aria-disabled, e não disabled, nas pontas do seletor de herdeiros. Um botão que vira disabled com o foco dentro dele joga o foco no <body>, e o teclado cai fora do grupo no meio do uso. O .btn-disc do core já desenha o apagado para os dois casos, e o script ignora o clique na trava.
A caixa da faixa tem 20px; o trilho, 3px. Um <input type=range> com 3px de altura tem alvo de ponteiro de 3px — só o polegar é clicável. Aqui o trilho é pintado no ::-webkit-slider-runnable-track e a caixa fica com a altura do polegar. Medido: .suc-range 412×20 no desktop, 304×20 no mobile.
aria-live na diferença anuncia a cada passo de seta — e é isso que se quer. No arrasto de ponteiro são ~30 mutações por segundo, mas região polite substitui o anúncio pendente em vez de empilhar fila, e quem arrasta com o mouse não está ouvindo. Com seta do teclado sai um anúncio por passo. O valor da faixa vai por aria-valuetext ("R$ 8.000.000"), e o <output> ao lado é aria-hidden para não dizer o mesmo número duas vezes.
Herdeiro mexe no prazo, nunca no imposto. Com 1: "de 12 a 24" e "de 3 a 6 meses". Com 6: "de 22 a 54" e "de 3 a 11". O ITCMD incide sobre o que se transmite, não sobre em quantas mãos — e inventar um acréscimo de imposto por herdeiro seria inventar direito tributário.
Percentuais lineares, e tabela real não é. Em 50 mi na Bahia a peça devolve R$ 7.500.000 de custo sem planejamento: ordem de grandeza correta, número específico não. É o primeiro item da lista de troca em ## Compliance.
Um por página, por causa dos id. O script parte de [data-suc] e aceita várias instâncias, mas suc-wealth, suc-state e suc-heirs-label colidiriam. Duas na mesma página pedem sufixo à mão em id, for e aria-labelledby.
--fg-muted fica em 4,37:1 na dobra clara (#726b5c sobre #ede9e3), e é onde vive toda a letra de apoio — inclusive a ressalva. Passa folgado em texto grande e fica 0,13 abaixo de AA em texto normal. É token do core, não decisão do componente.
Histórico
Projeto
Onde
Data
Diferenças
autoral
construído do zero na biblioteca
2026-09-03
—
Origem. Autoral, sem referência única e sem uma linha copiada. O padrão — comparar dois caminhos com as parcelas à vista — aparece em três famílias: a calculadora de custo de inventário dos escritórios de advocacia sucessória, o comparador "antes e depois" das gestoras de patrimônio e o simulador de custo de portabilidade dos bancos. Registro consolidado em projetos/autorais.md.
Decisões de tradução para o contrato. O gráfico virou duas barras em scaleX numa custom property, e não SVG, porque não há eixo, série nem caminho a desenhar. O ITCMD ficou nos dois cartões, com o mesmo valor, por compliance antes de por desenho. O prazo virou faixa. A contagem só existe num número, o da diferença — seis contagens simultâneas viram ruído. O estado vive em memória, sem localStorage. E a cor de marca entra sempre misturada com --fg, nunca pura, porque a dobra é clara.
Medições (Chrome headless, bin/medir.js). Desktop 1440×900: dobra 1602px, overflowX ok, console limpo, cartões 532×559 com os dois totais no mesmo top (930). Tablet 820: controles em duas colunas, patrimônio ocupando a fileira inteira (677px), cartões empilhados. Mobile 390: dobra 2676px, uma coluna, cartões 350×656, overflowX ok. Teclado: os quatro controles respondem a seta, Enter e Espaço, com :focus-visible em solid 2px offset 3px nos quatro. --reduce: transição da barra em 0s, filter:none no [data-rv], diferença escrita no valor final no mesmo tique. Aritmética conferida nos oito estados: parcelas somando o total exibido e diferença igual à subtração.