EntrelaçosPsi v1.0
Bíblia / Componentes / 13 · Stats
13Componentes

Quatro pilares. Counter animado no scroll.

Use stats em grupos de 4, mono no número, mono em CAPS no label. O counter anima de 0 ao valor com cubic-out 1.8s no momento que entra no viewport.

Grupo padrão de 4

0ANOS DE CLÍNICA
0PSICÓLOGAS IMPACTADAS
0PERTENCIMENTO
0VERTICAIS DE ATUAÇÃO

Quando usar

  • Hero: 4 stats logo após CTAs primários, ancoram autoridade rápido.
  • Comunidade: 4 stats sobre a rede (cidades, encontros, pertencimento).
  • Co-fundadoras: 2 stats por fundadora (anos de clínica, formação, etc.).

Variante numérica vs textual

Use .stat-num-text em italic-serif quando o "número" é uma credencial mais forte que um valor (ex: "USP", "CRP 06/117883", "Mestra"). Mantém o ritmo visual.

Honestidade dos números. Nunca arredondar para enganar (3.000+ é honesto se há 2.847; 5.000+ não). Stats da Entrelaços são verificáveis.

Snippet · pronto pra colar

HTML · cole no seu projeto
<div class="e-stats">
  <div class="e-stat">
    <span class="stat-num" data-count="11">0</span>
    <span class="stat-label">ANOS DE CLÍNICA</span>
  </div>
  <div class="e-stat">
    <span class="stat-num" data-count="3000" data-suffix="+">0</span>
    <span class="stat-label">PSICÓLOGAS IMPACTADAS</span>
  </div>
  <div class="e-stat">
    <span class="stat-num" data-count="98" data-suffix="%">0</span>
    <span class="stat-label">PERTENCIMENTO</span>
  </div>
  <div class="e-stat">
    <span class="stat-num-text">USP</span>
    <span class="stat-label">FORMAÇÃO · DOUTORADO</span>
  </div>
</div>

<script>
// Counter animado on-scroll (cubic-out 1800ms)
const animateCount = (el) => {
  const target = parseInt(el.dataset.count);
  const suffix = el.dataset.suffix || '';
  const dur = 1800;
  const start = performance.now();
  const tick = (now) => {
    const t = Math.min((now - start) / dur, 1);
    const eased = 1 - Math.pow(1 - t, 3);
    const v = Math.round(target * eased);
    el.textContent = (target >= 1000 ? v.toLocaleString('pt-BR') : v) + suffix;
    if (t < 1) requestAnimationFrame(tick);
  };
  requestAnimationFrame(tick);
};
const ioCounter = new IntersectionObserver(es =>
  es.forEach(en => en.isIntersecting && (animateCount(en.target), ioCounter.unobserve(en.target))),
  { threshold: 0.4 }
);
document.querySelectorAll('[data-count]').forEach(el => ioCounter.observe(el));
</script>