← Biblioteca componentes/prova/stats-contador-regua/ficha.md CódigoTela cheia
prova/stats-contador-regua

Régua de números com contagem

🟢 estavel complexidade média prefixo stat- prova-social numeros contador metricas resultados count-up intersection-observer

Incluir · as linhas que se colam num site novo, depois do core (CLAUDE.md §10)

<link rel="stylesheet" href="componentes/prova/stats-contador-regua/estilo.css">
<script src="componentes/prova/stats-contador-regua/script.js"></script>

markup.html · 67 linhas · 3,4 KB

<!-- ==========================================================================
     RÉGUA DE NÚMEROS COM CONTAGEM
     Prefixo: stat-
     Requer: core (tokens, base, motion.css, motion.js) + estilo.css e script.js
     Sem lib.

     Cada número declara o alvo em `data-count` e, se precisar, `data-prefix`,
     `data-suffix` e `data-dec`. O script não conhece nenhum destes números:
     mude o markup e a contagem acompanha, sem tocar no JS.

     O TEXTO ESCRITO AQUI É O VALOR FINAL, não o zero. É ele que fica na tela
     de quem abriu a página sem JS — e uma régua escrita "0%" seria afirmação
     falsa. Com o script rodando, ele zera antes da primeira pintura e conta a
     partir daí; sob `prefers-reduced-motion` ele reescreve o valor final e não
     conta. Ou seja: o texto daqui é fallback, nunca fonte da verdade — a fonte
     é o `data-count`.

     O `.stat-foot` (pílula de data + botão) é opcional: apague o bloco inteiro
     se não houver o que dizer. A régua fica de pé sozinha. O `.sec-head` acima
     também é opcional — sem ele a faixa vira a versão nua, que foi a forma de
     origem.

     Conteúdo fictício, só para dimensionar o layout. Ao usar, siga o "padrão
     editorial" da ficha.
     ========================================================================== -->

<section class="sec-deep sec-pad" id="numeros">
  <div class="wrap">
    <div class="sec-head stat-head">
      <span class="eyebrow" data-rv>Em números</span>
      <h2 class="sec-title ttl">O trabalho, <em>medido</em></h2>
      <p class="sec-lead" data-rv data-d="1">Uma frase de apoio dizendo de onde vêm estes números e de quando são. Duas linhas no máximo: quem parou aqui parou pelos números, não pelo texto.</p>
    </div>

    <!-- CONTEÚDO ILUSTRATIVO. Os três números abaixo são exemplo redondo para
         dimensionar a régua — não são dado apurado de nenhuma casa. Ao usar,
         troque pelo número real e ponha a data da apuração na pílula do pé. -->
    <div class="stat-band" data-stats data-rv data-d="2">
      <!-- Prefixo e decimal no mesmo item. O data-prefix entra colado no que
           o script escreve, então o espaço depois do "R$" mora dentro do
           próprio atributo — e o data-suffix começa por espaço pelo mesmo
           motivo. O data-count vai com PONTO (número de máquina) e a tela
           recebe vírgula; as casas saem do próprio data-count, então "2.4"
           conta com uma casa. -->
      <div class="stat-item">
        <p class="stat-num" data-count="2.4" data-prefix="R$ " data-suffix=" bi">R$ 2,4 bi</p>
        <p class="stat-label">Patrimônio sob assessoria</p>
      </div>
      <div class="stat-item">
        <p class="stat-num" data-count="340" data-suffix="+">340+</p>
        <p class="stat-label">Famílias e empresários</p>
      </div>
      <div class="stat-item">
        <p class="stat-num" data-count="98" data-suffix="%">98%</p>
        <p class="stat-label">Retenção em três anos</p>
      </div>
    </div>

    <div class="stat-foot" data-rv data-d="3">
      <span class="pill">Apurado em 01/2026</span>
      <a href="#estrutura" class="btn btn-ghost">
        Conhecer a estrutura
        <svg width="13" height="13" viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M2 7H12M8 3L12 7L8 11"/></svg>
      </a>
    </div>
  </div>
</section>

estilo.css · 123 linhas · 5,8 KB

/* ==========================================================================
   RÉGUA DE NÚMEROS COM CONTAGEM — prefixo stat-
   Números gigantes lado a lado, separados por filete vertical, com um rótulo
   curto em caixa alta embaixo. A contagem é do script; aqui não há um único
   keyframe.

   Tokens usados: --fg --fg-muted --rule --accent --display --sans --radius-media
   Primitivas do core (usadas, não recopiadas): .wrap .sec-pad .sec-head
   .eyebrow h2.sec-title .sec-lead .pill .btn / .btn-ghost — e .glass na
   variação .stat-band--card.

   Não existe @media(prefers-reduced-motion) neste arquivo, e a ausência é
   deliberada: a entrada da faixa é [data-rv], que o core já desliga, e a
   contagem é texto trocado pelo JS, que a desliga por conta própria. Não
   sobrou movimento em CSS para desligar.
   ========================================================================== */

/* Só a largura e a centralização dos filhos: o resto vem de .sec-head. */
.stat-head{--head-max:680px}
.stat-head .eyebrow,
.stat-head .sec-title,
.stat-head .sec-lead{margin-inline:auto}

/* ---------------------------------------------------------------- a régua */
/* --stat-cols é o único ajuste de quantidade. Três é o padrão; quatro pede
   --stat-size menor (a ficha traz o valor). O empilhamento do mobile NÃO lê
   esta variável de propósito: assim quem escrever --stat-cols:4 num style
   inline não consegue quebrar o mobile sem querer.

   Sem filete horizontal por padrão. O que separa a régua do cabeçalho é o
   respiro; filete em cima e embaixo mais os verticais fecha uma moldura e a
   faixa deixa de ler como régua e passa a ler como tabela. */
.stat-band{
  --stat-cols:3;
  --stat-gap:clamp(16px,2.5vw,44px);    /* respiro interno de cada célula */
  --stat-size:clamp(52px,7.5vw,92px);   /* corpo do número */
  margin-top:clamp(38px,6vh,64px);
  display:grid;
  grid-template-columns:repeat(var(--stat-cols),minmax(0,1fr));
}

.stat-item{padding:0 var(--stat-gap)}
/* Primeiro e último encostam na coluna: a régua tem de nascer e morrer
   alinhada ao .wrap, senão parece um bloco solto dentro do grid. */
.stat-item:first-child{padding-left:0}
.stat-item:last-child{padding-right:0}
/* O filete. Vive no :not(:last-child) — dois filetes para três itens. */
.stat-item:not(:last-child){border-right:1px solid var(--rule)}

/* ---------------------------------------------------------------- o número */
.stat-num{
  font-family:var(--display);font-weight:700;
  font-size:var(--stat-size);
  line-height:.88;letter-spacing:-.04em;
  color:var(--fg);

  /* OBRIGATÓRIO, não é refinamento. Na maioria das fontes proporcionais cada
     algarismo tem avanço próprio — o 1 é estreito, o 8 é largo. Sem
     tabular-nums o número treme lateralmente a cada frame da contagem, porque
     a largura muda a cada troca de dígito. Com ele, todo algarismo ocupa o
     mesmo avanço e a largura só cresce quando entra um dígito NOVO: o número
     cresce, não vibra. Se a --display do tema não tiver algarismos tabulares,
     veja o gotcha da ficha antes de desistir do componente. */
  font-variant-numeric:tabular-nums;

  /* Nunca quebra linha. Se quebrasse no meio da contagem — de "99" para
     "1.240" — o rótulo saltaria para baixo junto. Número comprido demais
     transborda a célula, e transbordar é para ser visto e corrigido. */
  white-space:nowrap;
}

.stat-label{
  font-family:var(--sans);
  font-size:11.5px;line-height:1.5;letter-spacing:.14em;text-transform:uppercase;
  color:var(--fg-muted);
  margin-top:clamp(12px,1.6vh,18px);
  /* Guarda-corpo, não regra de quebra: um rótulo de 2 a 4 palavras cabe numa
     linha e é assim que ele lê melhor, embaixo de um número de 92px. O teto
     existe só para o rótulo longo demais não atravessar uma célula larga
     (--stat-cols:2) como se fosse parágrafo. Precisa quebrar em ponto certo?
     Ponha um <br> no markup, como faz a régua do hero. */
  max-width:36ch;
}

/* ---------------------------------------------------------------- rodapé */
/* Onde mora a data de apuração e, se houver, um botão. Número sem data é
   promessa; a pílula é o lugar barato de resolver isso. Centralizado porque
   o cabeçalho padrão é centralizado — sem .sec-head, troque para
   justify-content:flex-start no tema. */
.stat-foot{
  margin-top:clamp(28px,4.5vh,48px);
  display:flex;flex-wrap:wrap;align-items:center;justify-content:center;
  gap:clamp(14px,2vw,24px);
}

/* ---------------------------------------------------------------- variações */
/* Números na cor de marca. Use quando a régua É o assunto da dobra; em página
   que já gasta accent em título e botão, deixe em --fg. */
.stat-band--accent .stat-num{color:var(--accent)}

/* Régua dentro de card de vidro. Compõe a primitiva .glass do core — junte as
   duas classes no mesmo elemento (class="glass stat-band stat-band--card"),
   não recopie a superfície. Os filetes ficam: dentro do card eles continuam
   sendo a estrutura. */
.stat-band--card{
  padding:clamp(24px,3.4vw,44px);
  border-radius:var(--radius-media);
}

/* ---------------------------------------------------------------- mobile */
/* Empilha e o filete troca de eixo: mesma função, outra direção.
   O seletor é IDÊNTICO ao do desktop (.stat-item:not(:last-child)), com a
   mesma especificidade e mais adiante na folha — é assim que se troca uma
   borda sem forçar prioridade. O original resolvia marcando o border-right:0
   como importante, que o contrato §6 não aceita. */
@media(max-width:860px){
  .stat-band{grid-template-columns:1fr}
  .stat-item{padding:clamp(24px,4vh,34px) 0}
  .stat-item:first-child{padding-top:0}
  .stat-item:last-child{padding-bottom:0}
  .stat-item:not(:last-child){border-right:0;border-bottom:1px solid var(--rule)}
  .stat-band--card{padding:clamp(20px,5vw,30px)}
}

script.js · 113 linhas · 5,0 KB

/* ==========================================================================
   RÉGUA DE NÚMEROS — a contagem.

   No site de origem isto era GSAP: `gsap.to({val:0}, …)` como tweener de um
   número e um `ScrollTrigger` só para saber a hora. Nenhum dos dois é timeline
   encadeada nem scrub — não passam no teste do contrato §1. Aqui a hora é
   IntersectionObserver e o tween é requestAnimationFrame, com easeOutCubic
   (1 - (1-t)³) no lugar do power3.out, que é a mesma curva.

   O script não sabe nada do layout: procura [data-count] dentro de
   [data-stats] e troca textContent. Qualquer outro bloco da página pode pedir
   a contagem pondo os mesmos dois atributos, sem uma linha de CSS a mais —
   é o único acoplamento que existe entre este arquivo e o estilo.css.
   ========================================================================== */

(function () {
  var bandas = document.querySelectorAll('[data-stats]');
  if (!bandas.length) return;                          /* guard */

  var DUR    = 1800;   /* ms — o mesmo 1,8s do original */
  var LIMIAR = .3;     /* fração da faixa visível que dispara. Mais tarde que
                          o .16 do [data-rv] de propósito: número contando
                          dentro do blur da entrada é contagem desperdiçada. */

  /* A flag é do core (contrato §7.5). O fallback existe porque a promessa de
     acessibilidade não pode depender da ordem dos <script>: colado num lugar
     sem motion.js, o componente ainda respeita quem reduz movimento. */
  var reduzir = window.LIB
    ? window.LIB.reduce
    : (matchMedia('(prefers-reduced-motion: reduce)').matches &&
       !/[?&]motion=on/.test(location.search));

  for (var b = 0; b < bandas.length; b++) ligar(bandas[b]);

  /* ------------------------------------------------------------ por faixa */
  function ligar(banda) {
    var nums = banda.querySelectorAll('[data-count]');   /* parte da raiz, §7.6 */
    if (!nums.length) return;

    var partidas = [];
    for (var i = 0; i < nums.length; i++) {
      var p = preparar(nums[i]);
      if (p) partidas.push(p);
    }
    if (!partidas.length) return;   /* sob reduce ninguém volta: nada a observar */

    /* Um observer por faixa. A página tem uma ou duas, e assim o disparo fecha
       em closure — sem mapa de elementos e sem propriedade pendurada no DOM.
       Se um dia forem muitas faixas, um observer só com mapa passa a valer. */
    var io = new IntersectionObserver(function (entradas) {
      for (var j = 0; j < entradas.length; j++) {
        if (!entradas[j].isIntersecting) continue;
        io.unobserve(entradas[j].target);               /* uma vez só */
        /* A faixa conta inteira, de uma vez: os três números são uma régua,
           não três animações independentes. */
        for (var k = 0; k < partidas.length; k++) partidas[k]();
      }
    }, { threshold: LIMIAR });

    io.observe(banda);
  }

  /* ------------------------------------------------------------ por número */
  /* Lê o alvo, normaliza o texto e devolve a função que dispara a contagem.
     Devolve null quando não há o que contar — data-count que não é número, ou
     movimento reduzido. Nos dois casos o número fica no valor final, nunca em
     branco e nunca "NaN". */
  function preparar(el) {
    var bruto = el.getAttribute('data-count');
    var alvo  = parseFloat(bruto);
    if (isNaN(alvo)) return null;

    /* As casas decimais saem do PRÓPRIO data-count: "98.5" conta com uma casa,
       "12" conta inteiro. O original fazia parseFloat + Math.round e engolia
       qualquer decimal — 4.9 chegava na tela como 5. */
    var ponto = bruto.indexOf('.');
    var casas = ponto < 0 ? 0 : bruto.length - ponto - 1;

    var antes  = el.getAttribute('data-prefix') || '';
    var depois = el.getAttribute('data-suffix') || '';

    /* data-count é número de máquina e vai sempre com ponto — é o que o
       parseFloat entende. O separador que aparece na tela é outro assunto:
       nasce vírgula, porque a biblioteca escreve em português. data-dec="."
       devolve o ponto para projeto em inglês. */
    var sep = el.getAttribute('data-dec') || ',';

    function escrever(v) {
      var t = v.toFixed(casas);
      if (sep !== '.') t = t.replace('.', sep);
      el.textContent = antes + t + depois;
    }

    /* Escreve já, na execução do script, antes da primeira pintura: sob reduce
       fica o valor final, senão zera para a contagem ter de onde partir. O
       texto que veio no markup é só o fallback de quem carregou sem JS — a
       fonte da verdade é o data-count, e reescrever aqui garante que os dois
       nunca divirjam na tela. */
    escrever(reduzir ? alvo : 0);
    if (reduzir) return null;

    return function iniciar() {
      var t0 = 0;
      function passo(agora) {
        if (!t0) t0 = agora;
        var t = Math.min((agora - t0) / DUR, 1);
        escrever(alvo * (1 - Math.pow(1 - t, 3)));      /* easeOutCubic */
        if (t < 1) requestAnimationFrame(passo);
      }
      requestAnimationFrame(passo);
    };
  }
})();

Uma faixa com números gigantes lado a lado, separados por filete vertical, cada um com um rótulo curto em caixa alta embaixo. Quando a faixa entra na tela, os números sobem de zero até o alvo em 1,8 segundos e param — uma vez só, nunca de novo. No mobile a régua vira pilha e o filete troca de eixo.

A contagem é IntersectionObserver + requestAnimationFrame, ~30 linhas. Nenhuma lib.


Quando usar

Quando não usar


Padrão editorial

Slot Regra
Olho (.eyebrow) 1 a 3 palavras. "Em números", "Resultados", "Desde 2014". Opcional.
Título (.sec-title) 1 linha, uma palavra em <em>. Nomeia a medida, não repete os números: "O trabalho, medido".
Apoio (.sec-lead) 1 parágrafo, 15 a 30 palavras. Diz de onde vêm os números e de quando são. Opcional, mas é aqui que a régua ganha credibilidade.
Número (.stat-num) Curto: 340+, 98%, R$ 2,4 bi. Nove glifos com afixo ainda cabem — medido, R$ 2,4 bi ocupa 328px de uma célula de 365. Acima disso transborda de propósito.
Rótulo (.stat-label) 2 a 4 palavras, no máximo duas linhas. Substantivo, sem verbo: "Patrimônio sob assessoria", não "Já assessoramos". Minúsculas no HTML — a caixa alta é do CSS.
Pílula do rodapé (.pill) A data da apuração. "Apurado em 01/2026". Número sem data é promessa.
Botão (.btn) 1, no máximo. Leva ao lugar onde o número se comprova (a estrutura da casa, o relatório). Opcional.

Três é o padrão. Quatro cabe baixando --stat-size. Dois funciona, mas com dois itens o filete central vira eixo de simetria e a faixa fica parecendo comparação — cuidado se os números não forem comparáveis.

Todo número precisa ser verificável. A régua é o lugar da página onde uma afirmação vira dado; se ninguém consegue conferir, escreva prosa e não coloque em 92px.


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/prova/stats-contador-regua/estilo.css">
...
<script src="core/motion.js"></script>
<script src="componentes/prova/stats-contador-regua/script.js"></script>

Cole o markup.html, troque os números e os rótulos. Depende do core e de mais nada.

Os quatro atributos

Toda a parametrização mora no markup. O script não conhece nenhum número da sua página.

Atributo Onde O quê
data-stats na faixa (.stat-band) a raiz. O script aceita várias na mesma página
data-count em cada .stat-num o alvo. Sempre com ponto: 98.5, nunca 98,5
data-suffix opcional vem depois: +, %, mi, /5
data-prefix opcional vem antes: R$, +, ~
data-dec opcional separador decimal na tela. Padrão ,; use . em projeto em inglês
<p class="stat-num" data-count="98.5" data-suffix="%">98,5%</p>
<p class="stat-num" data-prefix="R$ " data-count="40" data-suffix=" mi">R$ 40 mi</p>

O texto escrito no HTML

O .stat-num traz o valor final escrito, não o zero. Isso é decisão, não descuido:

Ou seja: o texto do markup é fallback; a fonte da verdade é o data-count. Os dois não conseguem divergir na tela, porque o script sempre reescreve.

Variáveis locais

No .stat-band:

Variável Padrão O quê
--stat-cols 3 quantidade de colunas no desktop
--stat-gap clamp(16px,2.5vw,44px) respiro interno de cada célula
--stat-size clamp(52px,7.5vw,92px) corpo do número

Variações

Variação Como
4 números --stat-cols:4 e --stat-size:clamp(38px,5.4vw,64px)
Números na cor de marca .stat-band--accent
Régua em card de vidro class="glass stat-band stat-band--card" — compõe a primitiva do core
Faixa nua apague .sec-head e .stat-foot. Foi a forma de origem: uma faixa entre duas dobras, sem título
Filete horizontal fechando a régua border-block:1px solid var(--rule);padding-block:clamp(26px,4vh,40px) no tema. Experimente sem antes: os verticais já dão a estrutura, e os quatro juntos leem tabela
Sem contagem não carregue o script.js. O markup já está pronto e correto

A régua daqui e a régua do hero

O hero/full-bleed-media já embute uma régua de quatro números (.hero-stats / .hero-k / .hero-v). São coisas diferentes e devem continuar separadas.

hero/full-bleed-media prova/stats-contador-regua
Pergunta que responde por que confiar quanto
Conteúdo dos slots chaves, nem sempre numéricas: 100%, SP · POA, Global, CVM quantidades, sempre numéricas
Corpo 19px, cor --accent 52–92px, cor --fg
Separação um filete horizontal em cima, nada entre os itens filete vertical entre os itens
Itens 4 fixos 3 (2 a 4 por --stat-cols)
Entrada cascata do hero, delay .95s [data-rv] do core, e a contagem em cima
Movimento nenhum depois de entrar conta 1,8s
Onde vive dentro do hero, acima da dobra seção própria, abaixo da dobra

O hero deveria passar a compor este componente? Não, e por quatro motivos concretos:

  1. Metade dos slots do hero não é número. CVM e SP · POA não têm alvo. Numa régua onde dois itens contam e dois ficam parados, o resultado lê como falha, não como decisão.
  2. A contagem não cabe acima da dobra. A régua do hero entra em .95s, no fim de uma cascata que já tem headline em duas linhas, apoio e CTA. Somar 1,8s de contagem empurra o "a página assentou" para depois dos 2,7s e põe movimento competindo com a headline no momento em que ela é a única coisa que importa.
  3. 19px e 92px não são o mesmo objeto tipográfico. Fundir os dois exigiria transformar o corpo em variável e o componente perderia identidade: um "número gigante" de 19px não é este componente, é outro.
  4. A régua do hero são seis linhas de CSS. Trocá-las por um componente com --stat-cols, filetes, empilhamento e observer é mais código para fazer menos.

O que efetivamente compõe é o script, não o CSS. O script.js daqui procura [data-count] dentro de [data-stats] e troca textContent — ele não conhece uma única classe stat-. Um projeto que queira o hero contando adiciona data-stats no .hero-stats e data-count nos .hero-k numéricos, carrega este script, e pronto: zero CSS, zero alteração no hero. Essa costura existe de propósito e está documentada aqui para não ser redescoberta. A recomendação continua sendo não usar (motivo 2), mas a porta está aberta e é de duas linhas.

Se um dia um terceiro componente pedir a mesma dupla "chave grande + rótulo pequeno separados por filete", aí sim vale promover ao core como primitiva, conforme o §6 do contrato. Com dois, ainda não.


Gotchas


Histórico

Projeto Onde Data Diferenças
Gabriel Rocha Studio gabriel-rocha-studio-2.html, section.stats 2026-08 Origem. Site autoral, autocontido, com GSAP e ScrollTrigger carregados para a página inteira.

O que mudou na travessia:

No original Aqui Por quê
gsap.to({val:0}, …) como tweener e ScrollTrigger para a hora IntersectionObserver + requestAnimationFrame, easeOutCubic no lugar de power3.out Contrato §1: GSAP só entra em timeline encadeada ou ScrollTrigger com scrub. Isto não é nenhum dos dois — é um número subindo
parseFloat + Math.round casas derivadas do próprio data-count + toFixed 4.9 chegava na tela como 5. Agora 98.5 conta com uma casa e mostra 98,5
0 escrito no HTML valor final escrito no HTML, zerado pelo script antes da primeira pintura Sem JS, a régua inteira afirmava zero
.stat-item{border-right:0!important} no mobile mesmo seletor :not(:last-child), mesma especificidade, mais adiante na folha Contrato §6: zero !important. Especificidade igual + ordem resolve
var(--mono) no rótulo var(--sans) A biblioteca não tem token de fonte mono. Criar um é decisão de arquitetura (§3) e ficou em aberto — veja abaixo
Um observer global disparando por .stats um observer por [data-stats], partindo da raiz Contrato §7.6: o componente pode repetir na página
Cores cruas var(--line), var(--muted) do site --rule, --fg-muted, --fg Tokens da biblioteca, para rodar em qualquer tema
Sem tratamento de movimento reduzido valor final escrito, sem contagem, sem observer Exigência do contrato
Faixa nua entre duas seções ganhou .sec-head e .stat-foot opcionais A forma nua continua disponível apagando os dois blocos
Números afirmando fato sobre pessoa real conteúdo genérico de exemplo Regra da biblioteca: markup de componente é dimensionamento, não conteúdo

Em aberto — token de fonte mono

O site de origem usa --mono (DM Mono) em todo rótulo pequeno: olho, legenda de card, número de acordeão, ticker, rodapé. A biblioteca não tem esse token e este componente resolveu com var(--sans), que é o que .eyebrow e .marquee-label já fazem. Funciona e está consistente.

Mas se mais componentes desse site entrarem, a decisão volta: ou todos convertem mono em --sans (e a voz de rótulo do projeto se perde na travessia), ou a biblioteca ganha um --mono em core/tokens.css com fallback monospace. É decisão de arquitetura, fica registrada aqui e não foi tomada.

Em aberto — primitiva de rótulo

11px / caixa alta / tracking largo / --fg-muted já aparece em .eyebrow (com traço), .marquee-label, .fold-cap, .pill e agora .stat-label. Pelo §6 do contrato isso passou de três e é candidato a primitiva — um .label sem traço, do qual .eyebrow seria a variação com traço. Não promovi: mexer no core está fora do escopo desta extração, e a mudança toca cinco componentes. Fica registrado para quem for fazer a próxima varredura.

Calibragem no primeiro uso. Espere ajustar o corpo do número quando forem quatro colunas, e a fonte do rótulo.