← Biblioteca componentes/conteudo/trio-cards-ui-simulada/ficha.md CódigoTela cheia
conteudo/trio-cards-ui-simulada

Trio de cards com interface simulada

🟢 estavel complexidade alta prefixo trio- cards tres-colunas recursos interface-simulada mockup rodizio grafico barras seletor-de-periodo pilula produto saas card-claro

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

<link rel="stylesheet" href="componentes/conteudo/trio-cards-ui-simulada/estilo.css">
<script src="componentes/conteudo/trio-cards-ui-simulada/script.js"></script>

markup.html · 279 linhas · 14,9 KB

<!-- ==========================================================================
     TRIO DE CARDS COM INTERFACE SIMULADA
     Prefixo: trio-
     Requer: core (tokens, base, motion.css, motion.js) + estilo.css e script.js
     Sem lib.

     A DOBRA. Cabeçalho em duas colunas — título e botão de um lado, apoio do
     outro — e embaixo três cards altos, de mesma altura, cada um com um
     PEDAÇO DE INTERFACE dentro. O card não descreve o recurso: mostra o
     recurso funcionando, em miniatura.

     AS TRÊS PEÇAS, e o que cada uma prova:
       1. fila de classes de ativo que rotaciona sozinha    -> "atravessa tudo"
       2. foto com pílulas de imposto evitado trocando      -> "a estrutura paga"
       3. card claro com seletor de período e gráfico       -> "você acompanha"

     PAINEL CORTADO. A peça do card 1 e a foto do card 2 encostam no rodapé do
     card e só têm canto arredondado EM CIMA. É o que faz a interface parecer
     continuar para fora do quadro em vez de ser um adesivo colado dentro
     dele. Quem corta é o overflow:hidden do próprio card.

     CARD CLARO EM DOBRA ESCURA. O terceiro card declara .sec-light nele
     mesmo. Sem isso, o texto de dentro leria o --fg da seção — que ali é
     claro — e sumiria no fundo areia. A classe de escopo troca --fg, --fg-2 e
     --fg-muted para o par escuro, e nenhuma regra do componente precisa
     escrever cor de texto (contrato §3).

     ESTADO INICIAL NO MARKUP. Cada peça já nasce no primeiro estado: o
     primeiro método com .is-on, as duas primeiras pílulas com .is-on e
     .is-next, o primeiro período com .is-on e aria-pressed. Assim a dobra
     está correta antes do script rodar — e continua correta se ele não
     rodar, seja por movimento reduzido, seja porque alguém colou só o HTML.

     ENTRADA. data-rv + data-d do core, um card por vez. Nada aqui
     reimplementa reveal.
     ========================================================================== -->

<section class="trio sec-dark sec-pad" data-trio>
  <div class="wrap">

    <!-- ---------------------------------------------------------------------
         CABEÇALHO EM DUAS COLUNAS
         Título e ação à esquerda, apoio à direita, os dois alinhados pelo
         topo. Não é o .sec-head do core: aquele é centralizado e de coluna
         única, e aqui a assimetria é o desenho.
         -------------------------------------------------------------------- -->
    <div class="trio-head">

      <div class="trio-head-col">
        <h2 class="sec-title trio-title ttl">Uma estrutura montada antes da primeira conversa</h2>
        <a class="btn btn-primary trio-cta" href="#" data-rv data-d="1">Agende seu diagnóstico</a>
      </div>

      <p class="trio-lead" data-rv data-d="1">
        Carteira, proteção, relatório e sucessão no mesmo lugar. Você decide o
        rumo — a estrutura técnica fica por nossa conta.
      </p>

    </div>

    <div class="trio-grid">

      <!-- =================================================================
           CARD 1 — a carteira que atravessa instituições
           O fundo é a primitiva .glass do core: o brilho radial vindo do
           canto de cima e a borda tênue são exatamente os dela. Só os
           parafusos mudam, no estilo.css.
           ================================================================= -->
      <article class="glass trio-card trio-card-a" data-rv>

        <div class="trio-copy">
          <h3 class="trio-card-title">Uma carteira que atravessa instituições</h3>
          <p class="trio-card-text">
            Cada classe de ativo entra na carteira pela instituição que paga melhor
            por ela, sem vínculo e sem taxa escondida.
          </p>
        </div>

        <!-- Painel ancorado no rodapé do card. A fila de dentro tem NOVE
             itens e a janela mostra três e meio: o corte embaixo é o que
             sugere que a lista continua. O script duplica os primeiros
             itens para o laço fechar sem buraco — as cópias saem marcadas
             com aria-hidden, para o leitor de tela ouvir nove classes de
             ativo e não treze. -->
        <div class="trio-panel">
          <ul class="trio-methods" role="list" data-trio-methods
              aria-label="Classes de ativo cobertas">

            <li class="trio-method is-on">
              <span class="trio-ico" aria-hidden="true">
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="2.5" y="5.5" width="19" height="13" rx="2.5"/><path d="M2.5 10h19"/></svg>
              </span>
              <span class="trio-method-name">Renda fixa</span>
            </li>

            <li class="trio-method">
              <span class="trio-ico" aria-hidden="true">
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="2.5" y="5.5" width="19" height="13" rx="2.5"/><path d="M2.5 10h19"/><path d="M6 14.5h4"/></svg>
              </span>
              <span class="trio-method-name">Crédito privado</span>
            </li>

            <li class="trio-method">
              <span class="trio-ico" aria-hidden="true">
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M13 2.6 5.6 13.4h5.2l-.8 8 7.6-11h-5z"/></svg>
              </span>
              <span class="trio-method-name">Fundos multimercado</span>
            </li>

            <li class="trio-method">
              <span class="trio-ico" aria-hidden="true">
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="8.6"/><path d="M12 7.4V12l3.1 2"/></svg>
              </span>
              <span class="trio-method-name">Previdência privada</span>
            </li>

            <li class="trio-method">
              <span class="trio-ico" aria-hidden="true">
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M4 6.4v11.2M7.2 6.4v11.2M10.4 6.4v11.2M13.6 6.4v11.2M16.8 6.4v11.2M20 6.4v11.2"/></svg>
              </span>
              <span class="trio-method-name">Fundos imobiliários</span>
            </li>

            <li class="trio-method">
              <span class="trio-ico" aria-hidden="true">
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="2.6" y="6" width="18.8" height="12.5" rx="2.6"/><path d="M2.6 9.6h12M16.6 12.3h2.6"/></svg>
              </span>
              <span class="trio-method-name">Ações e ETFs</span>
            </li>

            <li class="trio-method">
              <span class="trio-ico" aria-hidden="true">
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="8.6"/><circle cx="12" cy="12" r="3.6"/></svg>
              </span>
              <span class="trio-method-name">Estrutura offshore</span>
            </li>

            <li class="trio-method">
              <span class="trio-ico" aria-hidden="true">
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="3.6" y="9.2" width="16.8" height="10.8" rx="2"/><path d="M2.6 9.2h18.8M12 9.2V20M12 9.2S10.6 4.2 8.2 4.2a2.3 2.3 0 0 0 0 5m3.8 0s1.4-5 3.8-5a2.3 2.3 0 0 1 0 5"/></svg>
              </span>
              <span class="trio-method-name">Câmbio e proteção</span>
            </li>

            <li class="trio-method">
              <span class="trio-ico" aria-hidden="true">
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3.6 20.4 9H3.6zM5.4 9v8.4M9.8 9v8.4M14.2 9v8.4M18.6 9v8.4M3.2 19.4h17.6"/></svg>
              </span>
              <span class="trio-method-name">Private equity</span>
            </li>

          </ul>
        </div>

      </article>

      <!-- =================================================================
           CARD 2 — as camadas que protegem o patrimônio
           Foto encostada no rodapé e, por cima dela, um rotador vertical de
           três pílulas. Duas ficam à vista: a de cima é a destacada, a de
           baixo é a próxima. A terceira espera fora, transparente.
           ================================================================= -->
      <article class="trio-card trio-card-b" data-rv data-d="1">

        <div class="trio-copy">
          <h3 class="trio-card-title">Camadas que protegem o patrimônio</h3>
          <p class="trio-card-text">
            Uma holding para organizar, um seguro para blindar e uma reserva
            para não vender ativo na hora errada.
          </p>
          <ul class="trio-chips" role="list">
            <li class="trio-chip">Holding</li>
            <li class="trio-chip">Seguro</li>
            <li class="trio-chip">Reserva</li>
          </ul>
        </div>

        <!-- A foto é ilustração de produto, não conteúdo: alt vazio. O
             rotador inteiro sai do alcance do leitor de tela — três valores
             ilustrativos de imposto evitado lidos em sequência não informam
             nada, e o que a peça diz já está no título e no parágrafo
             acima. Conteúdo ilustrativo: nenhum destes números é apurado. -->
        <div class="trio-shot">
          <img class="trio-shot-img" src="../../../showroom/demo/ph-5.webp"
               alt="" aria-hidden="true" loading="lazy" decoding="async">

          <div class="trio-offers" data-trio-offers aria-hidden="true">
            <span class="trio-offer is-on">
              <span class="trio-offer-dot">
                <svg viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M2.6 6.3 4.9 8.6 9.4 3.7"/></svg>
              </span>
              Imposto evitado: <b class="trio-offer-val">R$ 340 mil</b>
            </span>
            <span class="trio-offer is-next">
              <span class="trio-offer-dot">
                <svg viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M2.6 6.3 4.9 8.6 9.4 3.7"/></svg>
              </span>
              Imposto evitado: <b class="trio-offer-val">R$ 96 mil</b>
            </span>
            <span class="trio-offer">
              <span class="trio-offer-dot">
                <svg viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M2.6 6.3 4.9 8.6 9.4 3.7"/></svg>
              </span>
              Imposto evitado: <b class="trio-offer-val">R$ 18,4 mi</b>
            </span>
          </div>
        </div>

      </article>

      <!-- =================================================================
           CARD 3 — o relatório consolidado
           Card CLARO dentro de dobra escura: o .sec-light aqui é o que dá o
           par de tinta escura para o que está dentro. O fundo areia vem de
           --accent-2 do tema, no estilo.css.

           As três alturas de cada barra viajam no style da própria barra
           (--trio-h-a/b/c, em porcentagem da altura do gráfico). Trocar de
           período é trocar UMA classe no gráfico: o CSS reescolhe a altura
           e a transição faz a barra crescer. O script não escreve altura
           nenhuma — e por isso o card já nasce certo no período 7d, mesmo
           sem script.
           ================================================================= -->
      <article class="trio-card trio-card-c sec-light" data-rv data-d="2">

        <div class="trio-card-head">
          <h3 class="trio-card-title trio-card-title-c">Seu patrimônio consolidado</h3>

          <div class="trio-track" role="group" aria-label="Janela do relatório">
            <button class="trio-per is-on" type="button" aria-pressed="true" data-trio-per>7d</button>
            <button class="trio-per" type="button" aria-pressed="false" data-trio-per>30d</button>
            <button class="trio-per" type="button" aria-pressed="false" data-trio-per>12m</button>
          </div>
        </div>

        <div class="trio-chart" data-trio-chart aria-hidden="true">
          <span class="trio-bar" style="--trio-h-a:33%;--trio-h-b:21%;--trio-h-c:18%"><span class="trio-bar-fill"></span></span>
          <span class="trio-bar" style="--trio-h-a:16%;--trio-h-b:44%;--trio-h-c:34%"><span class="trio-bar-fill"></span></span>
          <span class="trio-bar" style="--trio-h-a:72%;--trio-h-b:30%;--trio-h-c:27%"><span class="trio-bar-fill"></span></span>
          <span class="trio-bar" style="--trio-h-a:36%;--trio-h-b:62%;--trio-h-c:52%"><span class="trio-bar-fill"></span></span>
          <span class="trio-bar" style="--trio-h-a:88%;--trio-h-b:47%;--trio-h-c:61%"><span class="trio-bar-fill"></span></span>
          <span class="trio-bar" style="--trio-h-a:22%;--trio-h-b:88%;--trio-h-c:88%"><span class="trio-bar-fill"></span></span>
        </div>

        <!-- Os três números ficam empilhados na mesma célula de grade: o bloco
             tem a altura do mais alto e nada salta na troca. O que não está em
             cena leva visibility:hidden, e some também do leitor de tela — sem
             isso, ele leria os três valores em sequência.

             OS TRÊS SÃO DE ESTOQUE E DE ESTRUTURA — patrimônio, distribuição,
             liquidez. NENHUM é de resultado, e isso não é escolha de redação:
             é a mesma regra que o irmão conteudo/lista-beneficios-palco
             declara na ficha dele com estas palavras — "rentabilidade, ganho,
             comparação com índice: nada disso entra". As duas peças são
             interface simulada na mesma voz, e a regra é a mesma nas duas.
             Até 2026-09-08 este card mostrava "+R$ 620 mil de resultado no
             trimestre" e "14,6% de retorno em 12 meses". Números ILUSTRATIVOS
             em qualquer caso — trocar antes de publicar. -->
        <div class="trio-figs" data-trio-figs>
          <p class="trio-fig is-on">
            <b class="trio-fig-val">R$ 18,4 mi</b>
            <span class="trio-fig-lab">sob assessoria, 4 instituições</span>
          </p>
          <p class="trio-fig">
            <b class="trio-fig-val">R$ 3,1 mi</b>
            <span class="trio-fig-lab">com liquidez em até 30 dias</span>
          </p>
          <p class="trio-fig">
            <b class="trio-fig-val">5 classes</b>
            <span class="trio-fig-lab">de ativo na carteira consolidada</span>
          </p>
        </div>

      </article>

    </div>

  </div>
</section>

estilo.css · 411 linhas · 15,9 KB

/* ==========================================================================
   TRIO DE CARDS COM INTERFACE SIMULADA — prefixo trio-
   Cabeçalho em duas colunas e três cards altos, cada um com uma peça de
   interface funcionando dentro.

   Tokens usados:
     --display             família dos títulos e dos números
     --ease                curva única, em toda transição daqui
     --fg --fg-2 --fg-muted   tinta, herdada do escopo de tom de cada card
     --accent              cor de ação (bolinha de confirmação, hachura)
     --accent-2            superfície areia do card claro
     --dark --dark-2 --light --light-2   as superfícies do projeto
     --radius-media        canto do painel e da foto (o card usa 1.5x isto)
     --radius-pill         canto de pílula e de botão de período
     --sec-gap             respiro vertical, via .sec-pad do core

   TRÊS SUPERFÍCIES, TRÊS CAMINHOS. O card 1 é a primitiva .glass do core
   com os parafusos dela trocados; o card 2 é um dark um passo mais claro,
   feito por color-mix sobre --dark-2; o card 3 é o areia de --accent-2 e
   declara .sec-light nele mesmo, para a tinta de dentro virar escura.
   Nenhum dos três escreve cor crua e nenhum sobrescreve --fg.

   PORQUÊ O .glass NO CARD 1. A medição da referência descreve o fundo dele
   como cor sólida mais um radial-gradient a partir do topo — que é, linha
   por linha, o desenho da primitiva. Recopiar seria a terceira cópia da
   mesma regra, exatamente o que o §6 do contrato manda promover em vez de
   repetir. O que muda vem pelos ganchos que a própria primitiva expõe:
   --glass-bg vira a segunda superfície escura do tema (a referência mede
   #161616, que é o --dark-2 da Kirvano) e --glass-blur vai a zero, porque
   sobre um fundo opaco não há o que desfocar atrás.

   O JS não escreve estilo de aparência: ele troca classe. Altura de barra,
   posição de pílula e destaque de linha estão todos aqui.
   ========================================================================== */

.trio{
  /* Altura dos cards. É medida e não proporção: as três peças de interface
     de dentro têm altura fixa em px, e um card em aspect-ratio faria a peça
     descolar do rodapé em telas estreitas. */
  --trio-card-h:520px;

  /* Canto do card. A referência mede 24 num projeto de canto 16 — o card de
     dobra é uma vez e meia o canto de mídia do tema. Projeto flat
     (--radius-media:0) devolve 0 aqui, e os cards ficam retos, que é o
     comportamento certo: quem decide a forma é o tema. */
  --trio-radius:calc(var(--radius-media) * 1.5);

  --trio-gap:30px;
  --trio-panel-h:240px;
  --trio-row-h:56px;
  --trio-row-gap:8px;
  --trio-shot-h:240px;
  --trio-chart-h:170px;

  /* A terceira superfície escura do conjunto: um passo acima de --dark-2,
     ainda dentro da regra do tom vizinho do §3. Serve ao card 2 e ao botão
     de período aceso do card 3 — dois lugares, uma fonte só. */
  --trio-surface-2:color-mix(in srgb,var(--light) 7%,var(--dark-2));

  /* Os três tempos, em SEGUNDOS, lidos pelo script com parseFloat. Ficam
     aqui, e não no JS, porque são ajuste de ritmo da dobra e não lógica:
     quem acha a fila de pagamentos apressada mexe numa linha de CSS.
     Valor em ms quebraria a conta — a unidade é parte do contrato. */
  --trio-metodo-hold:1.9s;
  --trio-oferta-hold:2.5s;
  --trio-periodo-hold:4.26s;
}


/* ==========================================================================
   CABEÇALHO EM DUAS COLUNAS
   Não é o .sec-head do core: aquele é centralizado e de coluna única, e o
   que dá caráter a esta dobra é justamente a assimetria — título e ação
   pesando à esquerda, apoio leve à direita, os dois alinhados pelo topo.
   ========================================================================== */

.trio-head{
  display:flex;flex-wrap:wrap;
  align-items:flex-start;justify-content:space-between;
  gap:clamp(28px,4.4vw,64px);
}

/* 480 e 520 são as duas caixas medidas na referência. flex-basis e não
   width: com o gap, as duas cabem na coluna de 1136 e encolhem juntas antes
   de quebrar. */
.trio-head-col{flex:0 1 480px}
.trio-lead{
  flex:0 1 520px;
  font-size:clamp(16px,1.25vw,18px);line-height:1.55;
  color:var(--fg-2);
}

/* Dois ajustes no h2.sec-title do core, e nenhuma regra dele reescrita:
   sem o olho por cima, o margin-top de 16 desalinharia o título do
   parágrafo vizinho; e o teto de 22ch é estreito demais para a caixa de
   480 desta dobra. Dois seletores de classe vencem o "h2.sec-title" do
   core sem precisar de peso artificial. */
.trio-head .trio-title{margin-top:0;max-width:none}

.trio-cta{margin-top:32px}


/* ==========================================================================
   A GRADE
   ========================================================================== */

.trio-grid{
  display:grid;grid-template-columns:repeat(3,1fr);
  gap:var(--trio-gap);
  margin-top:clamp(40px,4.6vw,64px);
}

/* isolation:isolate dá contexto de empilhamento próprio a cada card: as
   pílulas flutuantes do card 2 não têm como passar por cima do vizinho.
   O overflow:hidden é o que CORTA a peça de interface no rodapé — é ele
   quem arredonda o canto de baixo do painel e da foto. */
.trio-card{
  position:relative;display:flex;flex-direction:column;
  min-height:var(--trio-card-h);
  border-radius:var(--trio-radius);
  overflow:hidden;isolation:isolate;
}

/* Os dois cards de topo têm o mesmo respiro de cabeça; a peça de baixo é
   empurrada pelo margin-top:auto de cada uma. O card 3 tem outro desenho e
   traz o próprio padding. */
.trio-card-a,.trio-card-b{padding-top:48px}

.trio-copy{padding-inline:24px;text-align:center}

.trio-card-title{
  font-family:var(--display);font-weight:500;
  font-size:clamp(21px,2vw,30px);line-height:1.25;letter-spacing:-.02em;
  color:var(--fg);
}
.trio-card-text{
  margin-top:24px;
  font-size:16px;line-height:1.5;
  color:var(--fg-muted);
}


/* ==========================================================================
   CARD 1 — fila de meios de pagamento
   ========================================================================== */

/* Os parafusos da primitiva .glass. Ver o cabeçalho deste arquivo para o
   porquê de cada um. */
.trio-card-a{
  --glass-bg:var(--dark-2);
  --glass-line:color-mix(in srgb,var(--light) 6%,transparent);
  --glass-blur:0px;
}

/* margin:auto 20px 0 — o auto em cima é o que ancora o painel no rodapé do
   card, sem posicionamento absoluto: assim, se o parágrafo crescer, o card
   cresce junto e o texto nunca corre por baixo do painel.
   A borda de baixo sai: ela cairia exatamente sobre a aresta do card e
   apareceria como um risco de 1px atravessando o canto arredondado. */
.trio-panel{
  margin:auto 20px 0;
  height:var(--trio-panel-h);
  overflow:hidden;
  padding:12px 12px 0;
  border:1px solid color-mix(in srgb,var(--light) 5%,transparent);
  border-bottom:0;
  border-radius:var(--radius-media) var(--radius-media) 0 0;
  background:color-mix(in srgb,var(--light) 5%,transparent);
}

/* A fila inteira é UM elemento que translada. O script move em múltiplos de
   (altura da linha + vão), e o painel recorta. */
.trio-methods{
  display:flex;flex-direction:column;gap:var(--trio-row-gap);
  will-change:transform;
  transition:transform .55s var(--ease);
}

/* flex-basis fixo além da altura: numa coluna flex, uma linha sem base
   encolhe para caber, e a conta do passo do script deixa de fechar. */
.trio-method{
  display:flex;align-items:center;gap:12px;
  flex:0 0 var(--trio-row-h);height:var(--trio-row-h);
  padding-inline:10px;
  border-radius:12px;
  background:transparent;
  transition:background .45s var(--ease);
}
.trio-method.is-on{background:color-mix(in srgb,var(--light) 5%,transparent)}

.trio-ico{
  flex:0 0 36px;width:36px;height:36px;
  display:flex;align-items:center;justify-content:center;
  border-radius:8px;
  border:1px solid color-mix(in srgb,var(--light) 10%,transparent);
  background:color-mix(in srgb,var(--light) 6%,transparent);
  color:var(--fg-2);
}
.trio-ico svg{width:18px;height:18px}

.trio-method-name{font-size:14px;line-height:1.4;color:var(--fg-2)}


/* ==========================================================================
   CARD 2 — foto no rodapé e pílulas de comissão girando
   ========================================================================== */

.trio-card-b{background:var(--trio-surface-2)}

.trio-chips{
  display:flex;flex-wrap:wrap;justify-content:center;gap:8px;
  margin-top:16px;
}
.trio-chip{
  height:24px;padding-inline:10px;
  font-size:12px;line-height:24px;
  border-radius:6px;
  color:var(--fg-2);
  background:color-mix(in srgb,var(--light) 10%,transparent);
}

/* A foto não recorta a si mesma por overflow: o canto vive na própria
   imagem. É o que deixa as pílulas vazarem para fora da largura dela
   quando o valor é longo — quem corta continua sendo o card. */
.trio-shot{
  position:relative;
  margin-top:auto;align-self:center;
  width:64%;
}
.trio-shot-img{
  width:100%;height:var(--trio-shot-h);
  object-fit:cover;
  border-radius:var(--radius-media) var(--radius-media) 0 0;
}

/* O rotador é uma célula de grade só, com as três pílulas empilhadas nela.
   Assim a caixa tem a largura da mais larga, as três nascem centradas e o
   deslocamento de cada uma é só o próprio translateY — sem left/top e sem
   uma conta de posição por pílula. */
.trio-offers{
  position:absolute;top:34px;left:50%;
  transform:translateX(-50%);
  display:grid;justify-items:center;
}

/* Três estados, um por posição do rotador:
     .is-on    em cima, destacada
     .is-next  logo abaixo, a próxima da fila
     nenhuma   fora de cena, mais abaixo e transparente
   O ciclo é on -> fora -> next -> on. Quem sai DESCE e apaga; quem entra
   sobe da posição de fora, acende no meio do caminho e assume o destaque.
   A cor do texto é --dark porque a pílula é uma superfície clara sobre foto,
   e não texto de seção: seguir --fg aqui a deixaria ilegível em dobra
   escura. Mesmo caso do .pil-title do conteudo/pilares-texto-na-foto. */
.trio-offer{
  grid-area:1/1;
  display:inline-flex;align-items:center;gap:6px;
  height:32px;padding:0 14px 0 6px;
  border-radius:var(--radius-pill);
  white-space:nowrap;letter-spacing:normal;
  font-size:12px;font-weight:500;line-height:1;
  color:var(--dark);
  background:color-mix(in srgb,var(--light) 95%,transparent);
  opacity:0;transform:translateY(96px);
  transition:opacity .6s var(--ease),transform .6s var(--ease);
}
.trio-offer.is-next{opacity:1;transform:translateY(48px)}
.trio-offer.is-on{opacity:1;transform:translateY(0)}

.trio-offer-val{font-weight:600}

.trio-offer-dot{
  flex:0 0 20px;width:20px;height:20px;
  display:flex;align-items:center;justify-content:center;
  border-radius:50%;
  background:var(--accent);color:var(--dark);
}
.trio-offer-dot svg{width:11px;height:11px}


/* ==========================================================================
   CARD 3 — painel claro de vendas
   O fundo areia é --accent-2, o apoio de marca do tema. A tinta escura vem
   do .sec-light declarado no próprio card, no markup: aqui não se escreve
   cor de texto nenhuma, e por isso o card acompanha qualquer tema.
   ========================================================================== */

.trio-card-c{background:var(--accent-2);padding:24px}

.trio-card-head{
  display:flex;flex-wrap:wrap;
  align-items:flex-start;justify-content:space-between;
  gap:12px;
}
.trio-card-title-c{flex:1 1 140px}

.trio-track{
  flex:0 0 auto;
  display:flex;gap:2px;padding:4px;
  border-radius:var(--radius-pill);
  background:color-mix(in srgb,var(--dark) 6%,transparent);
}
.trio-per{
  height:24px;padding-inline:11px;
  border:0;border-radius:var(--radius-pill);
  background:transparent;color:var(--fg-2);
  font-size:12px;font-weight:500;line-height:1;letter-spacing:normal;
  transition:background .4s var(--ease),color .4s var(--ease);
}
.trio-per.is-on{background:var(--trio-surface-2);color:var(--light-2)}

/* margin-top:auto empurra o gráfico para o pé do card e deixa o vão morto no
   meio — que é o desenho da referência, não sobra: o número embaixo precisa
   de silêncio em volta para pesar. */
.trio-chart{
  margin-top:auto;
  height:var(--trio-chart-h);
  display:flex;align-items:flex-end;gap:8px;
}

/* A altura de cada barra em cada período viaja no style da própria barra,
   como --trio-h-a/b/c. Trocar de período é trocar UMA classe no gráfico: o
   CSS reescolhe qual das três ler, e a transição faz a barra crescer. O
   script não escreve altura — e sem script o cartão fica no período 7d,
   correto e legível. */
.trio-bar{
  position:relative;flex:1 1 0;
  height:var(--trio-h-a,40%);
  border-radius:8px;
  background:color-mix(in srgb,var(--dark) 88%,transparent);
  transition:height .7s var(--ease);
}
.trio-chart.is-p1 .trio-bar{height:var(--trio-h-b,40%)}
.trio-chart.is-p2 .trio-bar{height:var(--trio-h-c,40%)}

/* As seis barras não crescem juntas: um atraso curto por posição transforma
   a troca de período em varredura da esquerda para a direita, que é o que
   faz o gráfico parecer estar recalculando. */
.trio-bar:nth-child(2){transition-delay:.05s}
.trio-bar:nth-child(3){transition-delay:.1s}
.trio-bar:nth-child(4){transition-delay:.15s}
.trio-bar:nth-child(5){transition-delay:.2s}
.trio-bar:nth-child(6){transition-delay:.25s}

/* Preenchimento hachurado, 3px menor em cima e embaixo — 6px no total, como
   na referência. É o que impede a barra de ler como bloco chapado e dá a
   ela a textura de dado projetado. */
.trio-bar-fill{
  position:absolute;left:0;right:0;top:3px;bottom:3px;
  border-radius:6px;
  background-image:repeating-linear-gradient(135deg,
    color-mix(in srgb,var(--accent) 34%,transparent) 0 2px,
    transparent 2px 6px);
}

/* Os três resultados na MESMA célula de grade: a caixa fica com a altura do
   mais alto e nada salta na troca. visibility, além da opacidade, para o
   que está fora de cena sair também do leitor de tela — sem ela, os três
   valores seriam lidos em sequência. O atraso de 0s na saída é o truque de
   sempre: a visibilidade só cai depois da fusão terminar. */
.trio-figs{display:grid;margin-top:28px}
.trio-fig{
  grid-area:1/1;
  display:flex;flex-wrap:wrap;align-items:baseline;gap:8px;
  opacity:0;filter:blur(8px);visibility:hidden;
  transition:opacity .5s var(--ease),filter .5s var(--ease),visibility 0s .5s;
}
.trio-fig.is-on{
  opacity:1;filter:blur(0);visibility:visible;
  transition:opacity .5s var(--ease),filter .5s var(--ease),visibility 0s;
}
.trio-fig-val{
  font-family:var(--display);font-weight:600;letter-spacing:-.02em;
  font-size:clamp(24px,2.2vw,32px);line-height:1.1;
  color:var(--fg);
}
.trio-fig-lab{font-size:14px;line-height:1.4;color:var(--fg-2)}

/* ---------------------------------------------------------------- movimento reduzido */
/* O script nem liga o rodízio quando a preferência está ativa — o que sobra
   aqui é o caso do botão de período, que continua clicável de propósito
   (botão morto na tela é defeito). Sem transição, a troca é instantânea. */
@media(prefers-reduced-motion:reduce){
  .trio-methods,.trio-method,.trio-offer,.trio-per,.trio-bar,.trio-fig{transition:none}
  .trio-fig{filter:none}
}


/* ---------------------------------------------------------------- mobile */

/* Três colunas de 359 pedem 1137 de coluna útil. Abaixo disso a grade vira
   duas, e o card do gráfico ocupa a linha inteira: é o único dos três que
   melhora ao ficar largo, porque o gráfico ganha respiro entre as barras. */
@media(max-width:1080px){
  .trio-grid{grid-template-columns:repeat(2,1fr)}
  .trio-card-c{grid-column:span 2}
}

@media(max-width:900px){
  .trio-head{flex-direction:column}
  .trio-head-col,.trio-lead{flex:1 1 auto;max-width:100%}
}

@media(max-width:720px){
  .trio{--trio-card-h:470px;--trio-gap:16px}
  .trio-grid{grid-template-columns:1fr}
  .trio-card-c{grid-column:auto}
  /* Card estreito e foto em 64% viram um selo pequeno demais no meio do
     quadro; em uma coluna a foto ocupa quase a largura toda. */
  .trio-shot{width:78%}
}

script.js · 293 linhas · 11,2 KB

/* ==========================================================================
   TRIO DE CARDS COM INTERFACE SIMULADA — os três rodízios.

   Três peças, três ritmos, UM laço. Cada peça devolve { espera, tique } e o
   laço decide de quem é a vez a cada quadro. Três setInterval fariam a mesma
   coisa, mas cada um continuaria contando com a aba em segundo plano e a
   dobra fora da tela; um requestAnimationFrame só dorme com a aba e é
   desligado pelo IntersectionObserver quando a dobra sai de vista.

   O que cada peça faz:
     1. MÉTODOS  — translada a fila e marca a linha do topo com .is-on.
                   A fila é duplicada no início para o laço fechar sem buraco.
     2. OFERTAS  — gira .is-on / .is-next entre as três pílulas.
     3. PERÍODO  — troca a classe do gráfico, do botão e do resultado.

   O script NÃO escreve aparência. Altura de barra, posição de pílula e
   destaque de linha estão todos no estilo.css; aqui só se troca classe. A
   única exceção é o transform da fila do card 1, que depende de uma medida
   feita no navegador e não teria como morar no CSS.

   TEMPOS NO CSS. Os três intervalos são custom properties da raiz do
   componente (--trio-metodo-hold e companhia), em segundos. Mesmo padrão do
   --apres-hold do conteudo/apresentacao-foto-alternada: ritmo é ajuste de
   desenho, e ajuste de desenho mora na folha de estilo.

   MOVIMENTO REDUZIDO. Nada cicla: as três peças ficam no primeiro estado, que
   o markup já traz. O laço nem chega a ser criado. O que continua vivo é o
   clique nos botões de período — botão que ignora o clique é defeito, não
   acessibilidade — e a troca, sem transição, é instantânea (ver o
   @media(prefers-reduced-motion) do estilo.css).

   Sem listener de scroll: quem observa a entrada é o IntersectionObserver.
   ========================================================================== */

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

  /* A flag do core é a fonte. O fallback existe para o componente colado
     sozinho, sem motion.js — e repete a regra do ?motion=on. */
  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;
  }

  /* getPropertyValue devolve " 1.9s"; parseFloat resolve o espaço e a
     unidade de uma vez. O CSS documenta que o valor é em segundos — em ms a
     conta sairia mil vezes maior e a peça pareceria travada. */
  function espera(raiz, nome, padrao) {
    var v = parseFloat(getComputedStyle(raiz).getPropertyValue(nome));
    return (v > 0 ? v : padrao) * 1000;
  }

  /* ---------------------------------------------------------- 1. métodos */

  function pecaMetodos(raiz, reduz) {
    var trilho = raiz.querySelector('[data-trio-methods]');
    if (!trilho) return null;

    var originais = [].slice.call(trilho.children);
    if (originais.length < 3) return null;

    /* Com movimento reduzido a fila fica parada na primeira linha, e então
       não há por que clonar: sai antes de tocar no DOM. */
    if (reduz) return null;

    /* A fila é duplicada INTEIRA, e não só o tanto que cabe na janela do
       painel. É o que torna a volta do laço independente de medida: na
       posição n = 9 o que está no topo é a cópia do item 0, e a partir dali
       a janela mostra cópias dos itens 0, 1, 2… qualquer que seja a altura
       do painel ou da linha. Clonar "o que cabe" obrigaria a recontar as
       cópias a cada mudança de tela.
       As cópias saem com aria-hidden: quem usa leitor de tela ouve nove
       meios de pagamento, não dezoito. */
    for (var c = 0; c < originais.length; c++) {
      var copia = originais[c].cloneNode(true);
      copia.setAttribute('aria-hidden', 'true');
      trilho.appendChild(copia);
    }

    var itens = [].slice.call(trilho.children);
    var total = originais.length;
    var passo = 0;
    var n = 0;

    /* A distância de uma linha à seguinte, medida no navegador — inclui o
       vão automaticamente. Somar altura mais gap na mão erraria toda vez que
       o CSS mexesse em um dos dois. */
    function remedir() {
      passo = itens.length > 1 ? itens[1].offsetTop - itens[0].offsetTop : 0;
      trilho.style.transition = 'none';
      posicionar();
      void trilho.offsetHeight;
      trilho.style.transition = '';
    }

    function posicionar() {
      trilho.style.transform = 'translate3d(0,' + (-n * passo) + 'px,0)';
    }

    /* Acende a linha que está (ou vai ficar) no topo, e também a cópia dela:
       na volta do laço quem aparece é a cópia, e é ela que precisa do
       destaque. A que estiver fora da janela não custa nada. */
    function marcar() {
      var alvo = n % total;
      for (var i = 0; i < itens.length; i++) {
        if (i === alvo || i === alvo + total) itens[i].classList.add('is-on');
        else itens[i].classList.remove('is-on');
      }
    }

    function tique() {
      /* Chegamos ao fim da fila original: a posição n = total desenha
         exatamente o mesmo que a posição 0, então dá para voltar ao começo
         sem transição e sem ninguém ver. O reflow no meio é o que sela o
         salto antes de a transição ser religada — sem ele o navegador junta
         as duas escritas e anima a volta inteira. */
      if (n >= total) {
        trilho.style.transition = 'none';
        n = 0;
        posicionar();
        void trilho.offsetHeight;
        trilho.style.transition = '';
      }
      n++;
      posicionar();
      marcar();
    }

    remedir();
    return {
      espera: espera(raiz, '--trio-metodo-hold', 1.9),
      tique: tique,
      remedir: remedir
    };
  }

  /* ---------------------------------------------------------- 2. ofertas */

  function pecaOfertas(raiz, reduz) {
    var caixa = raiz.querySelector('[data-trio-offers]');
    if (!caixa) return null;

    var pilulas = [].slice.call(caixa.children);
    if (pilulas.length < 3 || reduz) return null;

    var atual = 0;

    /* Um passo do rotador: a próxima assume o destaque, a de trás dela vira
       a próxima, e a que estava em cima fica sem classe — o estilo.css a
       manda descer e apagar. */
    function tique() {
      atual = (atual + 1) % pilulas.length;
      for (var i = 0; i < pilulas.length; i++) {
        pilulas[i].classList.remove('is-on');
        pilulas[i].classList.remove('is-next');
      }
      pilulas[atual].classList.add('is-on');
      pilulas[(atual + 1) % pilulas.length].classList.add('is-next');
    }

    return { espera: espera(raiz, '--trio-oferta-hold', 2.5), tique: tique };
  }

  /* ---------------------------------------------------------- 3. período */

  /* Esta peça é construída SEMPRE, inclusive com movimento reduzido: é ela
     que liga o clique dos botões. O que o movimento reduzido desliga é o
     rodízio automático, e isso quem decide é o laço lá embaixo. */
  function pecaPeriodo(raiz) {
    var grafico = raiz.querySelector('[data-trio-chart]');
    var caixaFig = raiz.querySelector('[data-trio-figs]');
    var botoes = [].slice.call(raiz.querySelectorAll('[data-trio-per]'));
    if (!grafico || !caixaFig || botoes.length < 2) return null;

    var figuras = [].slice.call(caixaFig.children);
    var atual = 0;
    var manual = false;

    function mostrar(i) {
      atual = i;
      for (var b = 0; b < botoes.length; b++) {
        if (b === i) botoes[b].classList.add('is-on');
        else botoes[b].classList.remove('is-on');
        botoes[b].setAttribute('aria-pressed', b === i ? 'true' : 'false');
      }
      for (var f = 0; f < figuras.length; f++) {
        if (f === i) figuras[f].classList.add('is-on');
        else figuras[f].classList.remove('is-on');
      }
      /* O primeiro período é o estado sem classe: é ele que o CSS desenha
         por omissão, e é por isso que o card já nasce certo sem script. */
      for (var g = 0; g < botoes.length; g++) grafico.classList.remove('is-p' + g);
      if (i > 0) grafico.classList.add('is-p' + i);
    }

    for (var k = 0; k < botoes.length; k++) {
      (function (i) {
        botoes[i].addEventListener('click', function () {
          /* A pessoa assumiu o controle: o rodízio automático não volta a
             mexer no card. Um seletor que continua girando sozinho depois de
             ser clicado é um seletor que ninguém consegue usar. */
          manual = true;
          mostrar(i);
        });
      })(k);
    }

    function tique() {
      if (manual) return;
      mostrar((atual + 1) % botoes.length);
    }

    return { espera: espera(raiz, '--trio-periodo-hold', 4.26), tique: tique };
  }

  /* ---------------------------------------------------------------- laço */

  function iniciar(raiz) {
    var reduz = reduzido();

    var metodos = pecaMetodos(raiz, reduz);
    var ofertas = pecaOfertas(raiz, reduz);
    var periodo = pecaPeriodo(raiz);          /* construído sempre: liga os botões */

    /* Daqui para baixo é só rodízio automático. Com movimento reduzido a
       dobra fica inteira e legível no primeiro estado de cada card, sem
       temporizador e sem observador para desligar depois. */
    if (reduz) return;

    var pecas = [];
    if (metodos) pecas.push(metodos);
    if (ofertas) pecas.push(ofertas);
    if (periodo) pecas.push(periodo);
    if (!pecas.length) return;

    var laco = 0;
    var dentro = false;

    /* Cada peça guarda a marca do próprio último tique. O quadro só compara
       relógios — quando não há nada vencido, custa três subtrações. */
    function quadro(agora) {
      for (var i = 0; i < pecas.length; i++) {
        var p = pecas[i];
        if (!p.marca) p.marca = agora;
        if (agora - p.marca >= p.espera) {
          p.marca = agora;
          p.tique();
        }
      }
      laco = dentro ? requestAnimationFrame(quadro) : 0;
    }

    /* Zerar as marcas ao religar é o que impede a dobra de disparar os três
       rodízios de uma vez quando volta à tela depois de um tempo fora. */
    function ligar() {
      if (laco || !dentro) return;
      for (var i = 0; i < pecas.length; i++) pecas[i].marca = 0;
      laco = requestAnimationFrame(quadro);
    }

    function desligar() {
      if (!laco) return;
      cancelAnimationFrame(laco);
      laco = 0;
    }

    /* Uma medida por quadro: remedir() lê layout, e fazer isso a cada evento
       de resize trava a janela ao redimensionar. */
    var pedido = 0;
    addEventListener('resize', function () {
      if (pedido || !metodos) return;
      pedido = requestAnimationFrame(function () {
        pedido = 0;
        metodos.remedir();
      });
    }, { passive: true });

    /* Limiar baixo de propósito: os rodízios têm de já estar rodando quando
       a dobra termina de subir, não começar depois que ela parou. */
    var io = new IntersectionObserver(function (entradas) {
      for (var i = 0; i < entradas.length; i++) {
        dentro = entradas[i].isIntersecting;
        if (dentro) ligar(); else desligar();
      }
    }, { threshold: .12 });

    io.observe(raiz);
  }

  for (var r = 0; r < raizes.length; r++) iniciar(raizes[r]);
})();

Um cabeçalho assimétrico — título e botão pesando à esquerda, um parágrafo de apoio à direita — e embaixo três cards altos de mesma altura. O que faz a dobra não é a grade: é o que está dentro de cada card. Um traz uma fila de classes de ativo que sobe sozinha, um item a cada dois segundos, cortada pelo rodapé do quadro como se a lista continuasse para fora dele. Outro traz uma foto encostada no pé do card e, flutuando por cima, pílulas de valor que se revezam. O terceiro é um card claro dentro da dobra escura, com seletor de período e um gráfico de seis barras que se recalcula a cada troca.

Resolve a dobra de "o que a casa faz" sem lista de ícone e frase, que é o formato padrão e o que ninguém lê. A diferença é de prova: um card que afirma ser multicustódia pede confiança; um card que mostra nove classes de ativo passando, uma por vez, entrega a mesma informação já demonstrada. É caro de montar e por isso não serve para qualquer recurso — serve para os dois ou três que decidem a conversa.


Quando usar

Quando não usar


Padrão editorial

Slot Regra
Título da dobra Uma promessa, não uma categoria. Duas linhas na caixa de 480. Sem <br>: aqui a quebra automática está certa.
Apoio Três linhas. Enumera o que os três cards vão mostrar, na mesma ordem em que eles aparecem.
Botão Uma ação só, a mesma do hero. Se a dobra pedir uma segunda ação, ela não é desta dobra.
Título do card Duas linhas, no máximo trinta caracteres. É a frase que a peça de interface embaixo vai provar.
Apoio do card Três linhas, até cem caracteres. Diz o que a peça não consegue mostrar sozinha: preço, condição, ausência de plugin.
Itens da fila (card 1) Sete a doze. Menos que sete e o rodízio se repete rápido demais; mais que doze e ninguém chega ao fim. Rótulo curto, de uma linha ("Renda fixa", "Estrutura offshore"), e um ícone desenhado — nunca a marca de terceiro.
Pílulas (card 2) Exatamente três valores. Ordem irregular de propósito: três valores crescentes leem como gráfico, e a peça não é um gráfico.
Períodos (card 3) Três, do mais curto ao mais longo. O valor de cada um cresce junto, e o rótulo diz o recorte de tempo por extenso.

O que mantém a dobra coesa é o paralelismo dos três títulos: mesmo comprimento, mesma forma de frase, mesmo tempo verbal. Se um deles for uma pergunta e os outros dois afirmações, a grade desmancha antes de o olho chegar às peças de interface.

Compliance

Nenhum número desta peça é de resultado. Os três valores do card de relatório são de estoque e de estrutura — patrimônio sob assessoria, parcela com liquidez, número de classes na carteira. Rentabilidade, ganho no período e comparação com índice não entram, e a regra não é de redação: é a mesma que o irmão conteudo/lista-beneficios-palco declara com estas palavras. As duas peças são interface simulada na mesma voz de assessoria, e uma tela inventada que mostra rentabilidade é a forma mais convincente de insinuar retorno — justamente porque parece um extrato.

Até 2026-09-08 este card mostrava "+R$ 620 mil de resultado no trimestre" e "14,6% de retorno em 12 meses". A divergência só apareceu quando os dois componentes foram descritos no mesmo vocabulário editorial, lado a lado.

Antes de publicar: trocar os três números por dados do cliente, mantendo a natureza (estoque, não resultado), e conferir com a área técnica dele. Os valores do markup são ilustrativos e estão marcados como tal em comentário.

Especificação dos assets

O único asset real é a foto do card 2. Ícones e gráfico são SVG e CSS, desenhados aqui.


Como usar

<link rel="stylesheet" href="componentes/conteudo/trio-cards-ui-simulada/estilo.css">
<script src="componentes/conteudo/trio-cards-ui-simulada/script.js"></script>

O card 3 precisa da classe de escopo sec-light nele mesmo, junto de trio-card-c. Sem ela, o texto de dentro lê o --fg da seção — que numa dobra escura é claro — e some no fundo areia. Nenhuma regra do componente escreve cor de texto: quem faz o par é o escopo.

Ganchos

Gancho Papel
[data-trio] Raiz. O script parte daqui e nunca do documento — a dobra pode repetir na página.
[data-trio-methods] A fila do card 1. É este elemento que o script translada.
[data-trio-offers] O rotador de pílulas do card 2.
[data-trio-chart] O gráfico do card 3. Recebe .is-p1 / .is-p2 conforme o período.
[data-trio-figs] A caixa dos três resultados do card 3.
[data-trio-per] Cada botão de período. O script liga o clique de cada um.
--trio-card-h Altura dos cards. 520px no padrão.
--trio-radius Canto do card. calc(var(--radius-media) * 1.5) — 24 num tema de canto 16, 0 num tema flat.
--trio-gap Vão da grade. 30px.
--trio-panel-h · --trio-row-h · --trio-row-gap Painel e linhas do card 1. 240px, 56px, 8px.
--trio-shot-h Altura da foto do card 2. 240px.
--trio-chart-h Altura do gráfico do card 3. 170px.
--trio-surface-2 A terceira superfície escura: fundo do card 2 e do botão de período aceso.
--trio-metodo-hold Intervalo do rodízio da fila, em segundos. 1.9s.
--trio-oferta-hold Intervalo do rotador de pílulas, em segundos. 2.5s.
--trio-periodo-hold Intervalo da troca de período, em segundos. 4.26s.
--trio-h-a · --trio-h-b · --trio-h-c No style de cada barra: a altura dela em cada um dos três períodos, em porcentagem do gráfico.
.is-on Linha acesa da fila, pílula em destaque, botão de período ativo, resultado em cena.
.is-next A pílula que está logo abaixo da destacada, esperando a vez.
.is-p1 · .is-p2 No gráfico: qual dos três conjuntos de altura ler. O primeiro período é o estado sem classe.

Variações


Gotchas


Histórico

Projeto Onde Data Diferenças
referência: Kirvano kirvano.com — dobra "Tudo o que você precisa para escalar" 2026-09-01 Referência visual, não origem de código. Reescrito do zero (contrato §11).

O que foi medido na referência (navegador, 1440×900): seção com padding:120px 0 21px e coluna interna de 1136; cabeçalho em flex space-between com gap:64, caixa esquerda de 480 (título de duas linhas + 32 + CTA de 199×56) e parágrafo direito de 520 a 18px; grade de três colunas de 359 com gap:30, cards de 520 de altura e raio 24. Card 1: fundo #161616 mais radial-gradient(at 31% -7%, …), padding:48px 24px 0, painel de métodos de 319×240 ancorado no rodapé com raio 16 só em cima, linhas de 293×56 com gap:8, ícone de 36×36, rotação de um item a cada 1.9s sobre nove itens. Card 2: fundo #262626, chips de 24 de altura, foto de 64% × 240 no rodapé, duas pílulas claras de 30–32 de altura com bolinha menta de 20×20, rotador vertical de três posições a cada 2.5s. Card 3: fundo #d0c9b9 com texto escuro, seletor de 127×32 com três botões de 24, gráfico de seis barras de 45 com alturas 56/27/122/61/150/37 sobre 170 e preenchimento hachurado 6px menor, rodapé com valor de 32px, ciclo de 4.26s na ordem 7d → 30d → 12m.

Normalizações aplicadas na tradução:

Divergências conhecidas vs. a referência medida: