Uma grade de quatro a seis células. Em cada uma: o valor em corpo grande, o rótulo em caixa alta, a variação com seta e palavra, e o período em que ela foi apurada. Acima da grade, uma barra com a data de referência e a procedência; abaixo, a ressalva. Não há controle nenhum — a peça é leitura, não ferramenta. CSS puro, sem script.js.
O que ela resolve que uma régua de números não resolve: a variação. "R$ 4,8 bi" é uma afirmação estática; "R$ 4,8 bi, alta de 11,6% em 12 meses, posição de 31/08/2026" é dado com tempo dentro — tem magnitude, direção, janela e validade. É a diferença entre dizer quanto e dizer quanto, e para onde.
Quando usar
- Abertura de relatório, ou dobra de "a casa em números" em que a mudança é parte do argumento: patrimônio sob assessoria e quanto ele cresceu, famílias atendidas e quantas entraram, prazo de um processo e quanto ele caiu.
- Painel de cenário: quatro a seis indicadores de mercado com a variação no período (IPCA em 12 meses, Selic, câmbio). Aqui a fonte deixa de ser opcional — ver Compliance.
- Quando existe data de apuração e existe janela. Sem uma das duas, a peça é a errada: falta metade do que ela mostra.
- Quatro a seis itens. Com três, a régua do
prova/stats-contador-reguadesenha melhor; com sete ou mais, é tabela.
Quando não usar
- Quando não há variação, ou ela não é confiável. Use
prova/stats-contador-regua: três ou quatro números gigantes que contam ao entrar, sem direção e sem janela. Ele ganha quando o número é a afirmação inteira e a mudança não é o assunto — e ganha também em corpo: 92px contra os 44px daqui, porque a célula dele não precisa acomodar duas linhas de variação. - Quando a pessoa precisa mexer para descobrir. Use
dados/painel-patrimonio: dashboard simulado com abas de janela (7d · 30d · 12m) que recalculam número, rosca, barras e linha. Ele é interface; esta grade é leitura. Se a pergunta é "e nos últimos 30 dias?", quem responde é ele. - Quando são critérios contra abordagens. Use
listas/tabela-comparativa. Uma grade de indicadores tem um eixo; matriz tem dois. - Quando o número precisa de contexto calculado. Use
dados/comparador-cenariospara custo de dois modelos em faixa, ouconversao/calculadora-projecaopara projeção. Esta grade não calcula nada: ela exibe o que já foi apurado. - Acima da dobra. A grade tem quatro linhas de texto por célula e uma ressalva no pé: é peça de leitura pausada, não de primeira impressão. Para régua no hero existe a de
hero/full-bleed-media. - Com indicador de rentabilidade de carteira, própria ou de cliente. Isso não é ajuste de conteúdo — é vedado. Ver Compliance.
Padrão editorial
| Slot | Regra |
|---|---|
Olho (.eyebrow) |
1 a 3 palavras. "Indicadores", "A casa em números". Opcional. |
Título (.sec-title) |
4 a 9 palavras, uma em <em>. Nomeia o que a grade mede e que houve mudança: "Onde a casa está, e o que mudou". Não repete nenhum dos números. |
Apoio (.sec-lead) |
1 parágrafo, 15 a 32 palavras. Diz de onde vêm os números e por que cada um traz janela. Opcional, mas é aqui que a grade ganha credibilidade. |
Data de referência (.ind-data) |
12 a 26 caracteres. "Posição de 31/08/2026". Obrigatória, em toda variação. |
Fonte (.ind-fonte) |
3 a 9 palavras. Diz de onde o número vem, enquanto a data diz de quando ele é. Opcional só quando tudo é apuração própria. |
Valor (.ind-valor) |
1 a 9 caracteres. 312, 4,52%, R$ 4,8 bi. Nove glifos é o teto medido. Não quebra linha. Unidade longa ("dias") mora no rótulo ou na variação, nunca aqui. |
Rótulo (.ind-rotulo) |
2 a 6 palavras. Substantivo, sem verbo: "Patrimônio sob assessoria", não "Já assessoramos". Minúsculas no HTML — a caixa alta é do CSS. |
Direção (data-ind-dir no .ind-var) |
alta, queda ou estavel. Não é texto: é o gancho de estado. Ausente ou com typo cai no neutro. |
Palavra da direção (.ind-var-dir) |
1 a 3 palavras. "alta de", "queda de", "sem mudança". Não é opcional — ver gotchas. |
Variação (.ind-var-num) |
1 a 10 caracteres. "11,6%", "2,4 p.p.", "3 dias". Ausente quando o indicador está parado. Sem sinal por padrão: a palavra já diz a direção. |
Período (.ind-var-per) |
2 a 4 palavras. "em 12 meses", "no trimestre". |
Ressalva (.ind-nota) |
2 a 3 frases, no pé do componente. |
O que mantém a grade coesa é o paralelismo das quatro linhas: todo indicador tem valor, rótulo, direção e janela, e nenhum tem duas janelas diferentes na mesma célula. Misturar "em 12 meses" com "no trimestre" entre células é legítimo e comum (nem tudo se apura no mesmo ritmo); o que não pode é uma célula sem janela nenhuma.
Uma grade por página, duas no máximo, e a segunda só quando os assuntos são distintos e nomeados (a casa numa, o cenário na outra). Duas grades do mesmo assunto viram uma tabela partida em duas.
O rótulo é o único slot elástico, e isso é estrutural, não conselho: a folga de altura entre as células é absorvida ali (uma a três linhas), e é por isso que os valores continuam alinhados. Escrever rótulos de tamanho parecido melhora a mancha, mas não é o que segura o alinhamento — ver "Como usar".
O que entra na grade, e o que não entra
| Serve | Não serve |
|---|---|
| estoque: patrimônio sob assessoria, famílias, assessores, instituições | rentabilidade de carteira, própria ou de cliente |
| mercado, com fonte: IPCA em 12 meses, Selic, câmbio | comparação implícita com concorrente ("2× mais que a média") |
| operação: prazo até a política, cobertura do comitê | número sem data de apuração |
| custo: taxa média de honorários acordada | número sem janela de variação |
Especificação dos assets
Nenhum. A peça é tipografia, um filete por célula e uma seta de 12px em SVG inline, desenhada com currentColor — não há imagem, ícone de terceiro nem fonte extra.
- Formato e dimensão mínima: —
- Peso alvo: —
- Composição / enquadramento: —
- O que não pode ter: logo de instituição real (nem no rótulo), marca de índice proprietário, print de plataforma.
Como usar
<link rel="stylesheet" href="core/tokens.css">
<link rel="stylesheet" href="core/temas/<projeto>.css">
<link rel="stylesheet" href="core/base.css">
<link rel="stylesheet" href="core/motion.css">
<link rel="stylesheet" href="componentes/dados/grade-indicadores/estilo.css">
...
<script src="core/motion.js"></script>
Cole o markup.html, troque os números, os rótulos e a data. Não há script.js. Depende do core e de mais nada.
O alinhamento, e por que ele não usa subgrid
Número que dança na vertical estraga a leitura das seis células de uma vez. O que faz um número dançar é o rótulo acima dele quebrar em duas linhas numa célula e em uma noutra. Havia duas saídas:
grid-template-rows: subgrid, com cada célula assinando as linhas do pai;- ordenar a célula de modo que o vão elástico fique depois do valor.
Está feito pelo segundo caminho, e o motivo não é suporte de navegador — é que ele alinha as duas pontas de graça:
- o valor abre a célula, então o topo dele é o topo da célula, que é o mesmo em todas (item de grade nasce
stretch); - a variação leva
margin-top:auto, então o pé dela também é comum; - sobra o rótulo no meio, e é ele que absorve a folga.
Medido a 1440 no tema liberta-wealth, com o rótulo da quarta célula quebrando em duas linhas e os outros três em uma:
| célula 1 | célula 2 | célula 3 | célula 4 | |
|---|---|---|---|---|
topo do .ind-valor |
488,06 | 488,06 | 488,06 | 488,06 |
linhas do .ind-rotulo |
1 | 1 | 1 | 2 |
topo do .ind-var |
579,66 | 579,66 | 579,66 | 579,66 |
pé do .ind-var |
616,54 | 616,54 | 616,54 | 616,54 |
Subgrid resolveria o mesmo, com uma dependência de versão de navegador e um grid-row: span 3 que precisaria ser mantido em sincronia com o número de filhos da célula — e que quebraria em silêncio no dia em que alguém acrescentasse uma quinta linha à célula.
O filete de border-top vive na célula, não na grade, e é ele que desenha a linha em que os valores se alinham. Fica cortado pelo vão entre colunas de propósito: um filete por coluna lê como cabeçalho de tabela de relatório, que é o registro certo aqui. Filete corrido de ponta a ponta somado aos verticais fecharia uma moldura, e a peça passaria a ler como tabela de verdade — o mesmo alerta que a ficha do stats-contador-regua faz.
O gancho de estado
Um só, e vive no .ind-var:
<p class="ind-var" data-ind-dir="alta">
<span class="ind-var-seta" aria-hidden="true"><svg …/></span>
<span class="ind-var-dir">alta de</span>
<span class="ind-var-num">11,6%</span>
</p>
<p class="ind-var-per">em 12 meses</p>
data-ind-dir |
seta | cor da linha |
|---|---|---|
alta |
0° (para cima) | --ind-alta, default var(--accent) |
queda |
180° (para baixo) | --ind-queda, default var(--accent-2) |
estavel |
90° (de lado) | --ind-estavel, default var(--fg-muted) |
| ausente, ou escrito errado | 90° | --ind-estavel |
Uma seta no markup, três direções no CSS. O <svg> é sempre a mesma flecha para cima; o ângulo sai de --ind-seta, que as regras de atributo escrevem. Como cor e ângulo vêm do mesmo atributo, os dois nunca podem divergir.
Variáveis locais
As três cores entram como fallback dentro do var(), e não como declaração em .ind — mesma forma do --display-xl do core. Declaradas num ancestral, elas venceriam um --ind-alta que o tema pusesse no :root, e o parafuso pareceria não funcionar. Assim as duas portas ficam abertas: tema no :root, ou instância no .ind.
| Variável | Default | O quê |
|---|---|---|
--ind-alta |
var(--accent) |
cor da linha de variação em alta |
--ind-queda |
var(--accent-2) |
cor da linha em queda |
--ind-estavel |
var(--fg-muted) |
cor da linha parada, e o neutro de segurança |
No .ind-grade:
| Variável | Default | O quê |
|---|---|---|
--ind-cols |
4 |
colunas no desktop. 3 para seis indicadores |
--ind-gap-col |
clamp(18px,2.4vw,34px) |
vão entre colunas |
--ind-gap-row |
clamp(34px,4.6vh,54px) |
vão entre fileiras — maior de propósito |
--ind-valor-fs |
clamp(28px,3.2vw,44px) |
corpo do valor |
Variações
| Variação | Como |
|---|---|
| 6 indicadores | --ind-cols:3. Medido a 1440: três colunas de 342,7px, duas fileiras, topo do valor batendo dentro de cada fileira (488,06 e 686,18) |
| 5 indicadores | deixe --ind-cols:4. A quinta abre a segunda fileira sozinha e lê como continuação, porque o filete dela nasce no mesmo lugar da coluna 1 |
| Forma compacta, só com o sinal | escreva o sinal no .ind-var-num (+11,6%) e ponha class="ind-var-dir visually-hidden" na palavra. Nunca apague o .ind-var-dir |
| Convenção verde/vermelho | --ind-alta e --ind-queda no tema. Só é honesto quando toda a grade tem a mesma valência — ver Compliance |
| Valores que contam ao entrar | data-stats no .ind-grade e data-count em cada .ind-valor, mais o script.js do prova/stats-contador-regua (ele não conhece nenhuma classe stat-). Não recomendado — ver gotchas |
Compliance
A peça exibe número, e por isso pisa em terreno regulado. Antes de publicar, o consumidor tem de trocar quatro coisas e conferir uma quinta.
1. Os números. Os quatro do markup.html são ilustrativos — números redondos de exemplo, marcados como tal em comentário HTML e na ressalva visível. Não são apuração de casa nenhuma.
2. A data de referência. .ind-data é obrigatória e não é opcional em nenhuma variação. Indicador sem data envelhece em silêncio: no dia seguinte à apuração ele ainda está certo, três trimestres depois ele é informação errada exibida com confiança, e nada na página acusa. Ela fica na peça, encostada na grade, e não na letra miúda do rodapé.
3. A fonte, quando o número vem de fora. Com qualquer série externa — IPCA, Selic, câmbio, índice de mercado — o .ind-fonte deixa de ser opcional e nomeia a série e o divulgador. Apuração própria pode dispensar, mas dizer "apuração interna" já é informação.
4. O que pode ser indicador. Estoque (patrimônio sob assessoria, famílias, assessores, instituições), mercado com fonte (IPCA, Selic, câmbio), operação (prazo até a política, cobertura do comitê) e custo (taxa média de honorários acordada). Nunca rentabilidade de carteira, própria ou de cliente, nem em uma célula. Uma grade de rentabilidade com seta verde é promessa de resultado com cara de dado, que é o pior formato possível para ela.
5. A ressalva, no pé do componente. Duas frases obrigatórias: que os números não representam carteira, resultado de cliente nem recomendação, e que variação apurada é fato passado e não indica desempenho futuro.
Por que o default não é verde e vermelho
Não é (só) daltonismo. O par verde/vermelho falha em três lugares, e o terceiro é o que decide:
- para quem não distingue as duas matizes — a deficiência mais comum, em torno de 8% dos homens;
- em impressão monocromática, que é como um relatório de assessoria costuma chegar impresso;
- quando "para cima" não quer dizer "bom" — e é o caso na maioria das grades honestas.
Na grade de exemplo o patrimônio sobe (boa notícia) e o prazo do diagnóstico cai (boa notícia também). Numa grade de mercado, o IPCA subindo é notícia ruim e a Selic subindo é notícia mista. Direção não é veredito. Um par verde/vermelho afirmaria um julgamento que o dado não carrega — e essa é uma questão de compliance antes de ser de acessibilidade: pintar "IPCA +0,4 p.p." de verde é induzir leitura favorável de um indicador desfavorável.
Por isso os defaults saem de --accent e --accent-2, as duas matizes que todo tema já tem de definir: duas direções, duas cores de marca, nenhum veredito. E por isso a direção viaja em quatro canais redundantes — palavra, seta, cor e período —, com a cor sendo o quarto e nunca o primeiro.
Se o projeto quiser mesmo a convenção, ela é honesta em um caso: quando todos os indicadores da grade têm a mesma valência (um painel só de estoque da casa, em que subir é sempre bom). Aí são duas variáveis no tema, e o dever de conferir contraste passa a ser dele.
Contraste, medido
A cor de direção cai em texto, não num ícone: o tema deve contraste a ela. Medido a 1440 no liberta-wealth, com a seção em .sec-deep (fundo rgb(24,24,24)):
| Elemento | Cor | Contraste |
|---|---|---|
.ind-valor |
--fg |
15,6:1 |
.ind-var em alta |
--accent (sage) |
10,8:1 |
.ind-var em queda |
--accent-2 (tan) |
6,1:1 |
.ind-var parado |
--fg-muted |
5,4:1 |
.ind-rotulo, .ind-nota |
--fg-muted |
5,4:1 |
Todos acima de 4,5:1. A conferência não é dispensável em outro tema: o --accent-2 do core/tokens.css é um cinza de espera (#6e6e6e) e dá 3,64:1 sobre o .sec-deep neutro (#131313) — abaixo de AA para 13,5px. Isso é propriedade do placeholder, não do componente (todo uso de --accent na biblioteca depende do tema), mas o efeito aqui é pior que o normal, porque o texto tingido é justamente o dado. Projeto cujo --accent-2 seja fraco tem duas saídas: melhorar o token, ou --ind-queda:var(--fg) — a seta e a palavra continuam dando a direção, e só a matiz se perde.
Gotchas
-
.ind-var-dirnão é opcional, e é o único slot do componente que não pode ser apagado. É o canal que não depende de cor nem de forma: é o que sobra para quem não distingue as matizes, para o relatório impresso em preto e branco e para o leitor de tela. A forma compacta existe (class="ind-var-dir visually-hidden"), e ela mantém o texto na árvore de acessibilidade — apagar o elemento, não. Medido: o.ind-varinteiro lê "alta de 11,6%" / "sem mudança" / "queda de 3 dias" como texto real, semaria-labelnenhum. -
data-ind-dire a palavra do.ind-var-dirtêm de concordar, e nada acusa se divergirem. É a única divergência que o componente não consegue impedir por construção: cor e ângulo saem do mesmo atributo (e por isso nunca discordam entre si), mas a palavra é texto que alguém escreve. O sintoma é cruel — seta para baixo, cor de queda, e o leitor de tela anunciando "alta de". Ao trocar a direção de uma célula, troque as duas coisas. Umdata-ind-dirausente é mais seguro que um errado: cai no neutro. -
O typo cai no neutro, de propósito. O default do seletor é
estavel(seta de lado, cor apagada), e as regras dealtaequedasão as exceções. Medido: comdata-ind-dir="ALTA-com-typo"e sem o atributo, a linha computargb(145,142,134)e a setarotate(90deg)nos dois casos. Um atributo escrito errado nunca inventa uma alta — que seria a falha caríssima nesta peça. -
A rotação da seta vive num descendente, e isso é o §5 do contrato em ação. O
[data-rv]está no.ind-grade; a seta é três níveis abaixo. Se odata-rvestivesse no.ind-var, o[data-rv].in{transform:none}do core — que vale (0,2,0) — apagaria a rotação em silêncio no instante em que a dobra entrasse, e todas as setas passariam a apontar para cima. Medido nos dois modos: com movimento normal e sobprefers-reduced-motion:reduce(onde o core usatransform:none!important), as setas seguem emrotate(90deg)erotate(180deg). A direção sobrevive ao movimento reduzido, que é o comportamento certo: ela é informação, não animação. -
O valor não quebra linha (
white-space:nowrap), e o teto é nove glifos. Medido:R$ 4,8 biocupa 169,8px de uma célula de 248,5px a 1440, e 92,6px de uma de 125,5px a 320 — sempre com sobra. Acima disso transborda a célula, e o transbordo é intencional: serve de alarme para encurtar o valor. Unidade longa vai para o rótulo ("Dias até a política de investimentos", com o valor em12) ou para a variação ("queda de 3 dias"). -
Não há separador de milhar, porque não há script.
12480é escrito assim mesmo. O ponto brasileiro colide com o decimal, e em quatro colunas o milhar agrupado vira parede de dígito. Escreva12,5e ponha "mil" no rótulo — a mesma decisão doprova/stats-contador-regua, por razões diferentes (lá era a contagem, aqui é a coluna estreita). -
Duas colunas no celular, não uma, e as colunas vão cravadas na media query. Indicador é curto: em coluna única cada célula gasta a largura inteira do aparelho para mostrar "312", e uma grade de seis viraria uma rolagem de seis telas. Medido a 390: duas colunas de 167,2px, vão de 15,6px, valor a 27,3px,
R$ 4,8 biocupando 105,3px — 61,9px de sobra, zero overflow horizontal. A 320 ainda são duas colunas de 125,5px. Ogrid-template-columnsda media query não passa por--ind-cols, e é de propósito: estilo inline vence media query, então quem escrevesse--ind-cols:4nostylede uma instância quebraria o mobile sem querer. Já o corpo do valor segue por variável, porque ali o ajuste por projeto é legítimo — é medida, não estrutura. Mesma divisão que ostats-contador-reguafaz. -
Não existe
@media(prefers-reduced-motion)noestilo.css, e a ausência é deliberada. Não há transição, animação nem transform animado para desligar: a rotação da seta é estática (ela nunca interpola de um ângulo para outro) e a única entrada é o[data-rv]do core, que ocore/motion.cssjá desliga. Medido sob--reduce:transition-duration0s em todos os revelados, zero animações em curso, e a altura da seção idêntica à do modo normal (841,03px nos dois). -
Nada é focável dentro do componente, e isso não é omissão. Medido: zero elementos em
a[href], button, input, select, textarea, [tabindex]. A peça é leitura — não há o queTabalcance, o queEnteracione nem o queEscfeche. Um link para o relatório completo é acréscimo legítimo do consumidor (a primitiva.btndo core resolve), e aí ele passa a ser o único ponto de parada de teclado da dobra. -
A célula parada não tem número, e escrever
+0,0%seria pior..ind-var-numsimplesmente não existe naquela célula: a palavra "sem mudança" ocupa o lugar. Precisão falsa num indicador parado é o tipo de detalhe que corrói a confiança no resto da grade. No blocoeditorialisso aparece comopor_item+exigido:false— "no máximo um por item", nunca "um em cada". -
Contar não é opção aqui, e a porta está aberta de propósito. O
script.jsdoprova/stats-contador-reguaprocura[data-count]dentro de[data-stats]e não conhece uma única classestat-: dois atributos e um<script>fazem os valores desta grade contarem, sem uma linha de CSS. A recomendação é não usar, e o motivo é o mesmo que aquela ficha dá sobre o hero: a variação não pode contar (ela não é quantidade acumulada, é diferença apurada), e meia célula animando enquanto a outra metade fica parada lê como bug, não como decisão. Fica registrado para não ser redescoberto. -
<dl>foi considerado e recusado, pelo mesmo motivo do irmão. Valor e rótulo formam par termo/descrição, mas<dt>tem de vir antes de<dd>e aqui o valor vem primeiro na tela — e a ordem visual é justamente o que segura o alinhamento. Inverter por CSS estragaria a ordem de leitura para quem a semântica serviria. Ficou<ul role="list">com<li>, que é o que a peça é: uma lista de indicadores. Oroleexplícito devolve a semântica que olist-style:nonedo core tira no Safari.
Histórico
| Projeto | Onde | Data | Diferenças |
|---|---|---|---|
| autoral | — | 2026-09-09 | Construído do zero na biblioteca. Sem referência única e sem uma linha copiada. |
O padrão — grade de quatro a seis células com cifra, rótulo curto e a mudança no período — é o cabeçalho padrão de relatório de gestora e de banco privado, o "KPI card com delta" de painel de BI (Tableau, Looker, Metabase) e a página de fatos e números de casa de investimento. As famílias de exemplo entraram como proporção e ritmo de leitura; nada mais.
Normalizações aplicadas na tradução para o contrato:
| Nas famílias de exemplo | Aqui | Por quê |
|---|---|---|
| delta em verde/vermelho, só cor | palavra + seta + cor + janela, quatro canais | daltonismo, impressão monocromática e, sobretudo, direção não ser veredito (ver Compliance) |
| token semântico de sucesso/erro | --ind-alta / --ind-queda / --ind-estavel, com default em var(--accent) / var(--accent-2) / var(--fg-muted) |
a biblioteca não tem --pos/--neg, e criar um é decisão de arquitetura (§3). Ficou em aberto — ver abaixo |
alinhamento por subgrid ou por script medindo altura |
ordem da célula + margin-top:auto |
alinha as duas pontas sem dependência de versão de navegador e sem um span N para manter em sincronia |
| data de apuração em rodapé, ou ausente | .ind-data obrigatória, na barra da grade |
indicador sem data envelhece em silêncio |
| ícone por indicador (cofre, casa, pessoas) | nenhum | ícone de dashboard não é a voz da casa, e o rótulo já diz o que o número é |
| card com fundo e sombra por célula | um filete de border-top por célula |
o filete desenha a linha em que os valores se alinham; card e sombra não pertencem a um tema flat |
| cifra contando ao carregar | nenhuma contagem | a variação não conta, e meia célula animando lê como bug. A porta continua aberta em duas linhas |
| cor crua no delta | só token | §3 |
Divergências conhecidas vs. produção: nenhuma — o componente nasceu aqui.
Em aberto — token semântico de positivo/negativo
A biblioteca não tem --pos/--neg, e o overlay/toast-aviso esbarrou no mesmo buraco antes: resolveu sem cor nenhuma, diferenciando os tons por ícone e por role de acessibilidade, e registrou na ficha que --tst-ok/--tst-atencao seriam "cor crua disfarçada de variável".
Este componente não pode repetir aquela solução, e a diferença é real: o toast tem três tons de aviso, e a informação do aviso é o texto; aqui a direção é parte do dado, e a convenção de tingi-la existe em todo painel de indicador do mundo. Então a saída foi a intermediária: custom property prefixada, com default derivado de tokens que já existem (--accent, --accent-2, --fg-muted), nenhuma cor crua, e a direção legível sem cor nenhuma.
A recomendação para a casa, relatada e não implementada: um par --pos/--neg global provavelmente não vale a pena, por três motivos:
- Ele nomearia uma coisa que a biblioteca não tem.
--accenté cor de marca, e "bom" não é uma categoria de marca. Um--posglobal obrigaria todo tema a decidir o que é "bom" em abstrato. - Direção não é valência, e um token chamado
--posempurra o consumidor exatamente para o erro que a seção Compliance descreve — pintar de verde um IPCA em alta. - Duas peças, duas necessidades diferentes. O toast quer tom de aviso (sucesso/erro), esta grade quer direção de movimento. Um token só serviria mal às duas.
O que talvez valha, se uma terceira peça pedir: um par --dir-up/--dir-down — nomeando direção, não julgamento. Com duas peças, ainda não bateu o gatilho de três do §6. Fica registrado.