Dobra clara com o cabeçalho encostado à esquerda e, abaixo, uma grade de três colunas em duas linhas de peso diferente. Em cima, um card largo de duas colunas onde uma foto ocupa o card inteiro: um grupo de cartõezinhos de interface flutua no canto superior esquerdo e o título e o parágrafo ficam ancorados no rodapé, dentro da imagem, sobre gradiente e desfoque mascarado. Ao lado dele, um card escuro estreito com título em duas linhas, três itens com ícone de check e um botão no pé. Embaixo, três cards escuros iguais, foto no topo e corpo em baixo, cada um com um botão redondo de chevron que abre o parágrafo.
Resolve a dobra de "o que o produto faz" quando os recursos não têm o mesmo peso. Uma grade regular de seis cards afirma que as seis coisas valem o mesmo; o bento hierarquiza sem escrever "principal" em lugar nenhum — a linha 1 diz o que o produto é, a linha 2 lista o que ele faz. E o parágrafo que abre no clique dá aos cards de baixo o espaço de duas linhas na página e o de dez para quem quiser.
Quando usar
- Página de produto ou de plano, na dobra que enumera recursos — de quatro a seis, sendo um ou dois claramente mais importantes.
- Quando há uma foto de abertura à altura de ocupar 751 × 460: a linha 1 é metade do argumento, e ela cai com foto fraca.
- Quando cada recurso de baixo tem um parágrafo de verdade a dizer, e não uma frase de efeito. O gatilho de expansão só faz sentido se houver o que expandir.
- Em página escura que precisa de um respiro claro no meio (a dobra é
.sec-light, com os cards escuros por dentro).
Quando não usar
- Recursos todos do mesmo peso: a assimetria vira ruído. Use
conteudo/pilares-texto-na-fotoouconteudo/grid-entidades. - Sem foto: o card largo fica com um retângulo cinza e um scrim sobre nada.
- Quando o assunto é pergunta e resposta e só uma de cada vez interessa:
listas/acordeao-faq, que fecha as irmãs ao abrir uma. - Quando cada recurso precisa levar a uma página própria: o card daqui não é link, e transformá-lo em
<a>colide com o<button>que abre o texto. - Mais de seis recursos: a linha 2 passa de quatro colunas, o título de cada card fica com 12 caracteres e o bento vira tabela.
Padrão editorial
| Slot | Regra |
|---|---|
| Título da dobra | Até 40 caracteres — o max-width:22ch do .sec-title do core o quebra em duas linhas a partir de ~25. Entra palavra a palavra (data-split), e frase longa demora a assentar. |
| Apoio da dobra | Duas a três linhas. Diz o que as seis coisas têm em comum, não o que cada uma é. |
| Pílula de status | Duas a três palavras, no presente e já concluído ("Adicionado à carteira"). É a encenação de um estado, não um botão. |
| Cartão de ativo | Nome até 22 caracteres (corta com reticências) + valor. Dois cartões, nunca três: o terceiro esbarra no texto do rodapé. |
| Título do card largo | 35 a 50 caracteres, duas linhas. É a promessa do produto inteiro. |
| Parágrafo do card largo | Duas a três linhas. Termina antes da borda do título, e é isso que dá o degrau. |
| Título do card escuro | Duas linhas curtas, quebra escrita no <br>. |
| Itens da lista | Três, sempre. Até 30 caracteres cada — dois deles quebrando em duas linhas desalinha a coluna toda. |
| Botão | Verbo na primeira pessoa ("Criar minha área"). Texto do core, em caixa alta pelo .btn. |
| Título dos cards de baixo | Duas ou três palavras. É rótulo de recurso, não frase. |
| Parágrafo dos cards de baixo | 180 a 260 caracteres. Abaixo de 180 ele cabe nas duas linhas fechadas e o botão abre para nada; acima de 260 o card aberto fica desproporcional em relação aos irmãos. |
O que mantém a dobra coesa é o paralelismo dos três de baixo: se um parágrafo começa explicando o que a pessoa faz, todos começam. Os três títulos têm de ter o mesmo número de palavras — é a única coisa que impede a fila de baixo de parecer improvisada.
Especificação dos assets
- Card largo — 1 foto paisagem, 1600 × 900 ou maior, WebP. Quadro exibido 1.63. Peso alvo: até 220 KB.
- Cards da linha 2 — 3 fotos paisagem, 1600 × 900 ou maior. Quadro exibido 1.55. Até 160 KB cada.
- Miniaturas dos cartões de produto — 2 imagens quadradas, 200 × 200 ou maior, exibidas a 40 × 40.
- Composição / enquadramento: o terço inferior de todas as fotos é coberto por scrim, véu ou degradê. Nada de rosto, texto ou detalhe importante ali. Foto de baixo contraste na metade de baixo é o alvo; foto com céu claro embaixo obriga a subir a opacidade do scrim e o card fica sujo.
- O que não pode ter: captura de tela real de outra ferramenta, logo de terceiro, marca de instituição identificável ou foto clara demais no rodapé (o texto branco some).
- Os ícones — o da pílula de status, o check e os dois chevrons — são SVG inline desenhados na hora, genéricos, sem dependência de biblioteca de ícones.
Como usar
<link rel="stylesheet" href="componentes/conteudo/bento-recursos-expansivel/estilo.css">
<script src="componentes/conteudo/bento-recursos-expansivel/script.js"></script>
Os quatro cards escuros declaram o próprio escopo de tom no markup — class="sec-dark" no da linha 1 e class="sec-deep" nos três de baixo. Sem isso eles herdariam o --fg escuro da seção clara e o texto sumiria dentro deles. O CSS do componente não sobrescreve --fg em lugar nenhum: só lê --bg e --fg de quem cada card declarou ser.
Ganchos
| Gancho | Papel |
|---|---|
[data-bento] |
Raiz. O script parte daqui, nunca do documento. |
[data-bento-card] |
Card da linha 2 que tem parágrafo expansível. |
[data-bento-toggle] |
O <button> redondo. Leva aria-expanded e aria-controls. |
[data-bento-text] |
O parágrafo que abre. É o alvo do aria-controls. |
--bento-gap |
Vão da grade. clamp(12px,1.4vw,20px). |
--bento-radius |
Raio dos cards, derivado de --radius-media × 1.5. Em tema flat vira 0 sozinho. |
--bento-tall |
Altura da linha 1. clamp(360px,32vw,460px). |
--bento-card-h |
Piso de altura dos cards da linha 2. clamp(380px,33vw,472px). A folga que sobra é para onde o parágrafo cresce. |
--bento-media-h |
Altura da foto no topo dos cards de baixo. clamp(170px,16.4vw,236px) — metade do card. |
--bento-pad / --bento-pad-wide |
Respiro dos cards da linha 2 e dos da linha 1. |
--bento-float |
Largura do grupo de cartõezinhos. 328px. |
--bento-head-max |
Largura do cabeçalho. 760px. |
--bento-lh / --bento-lines |
Entrelinha e número de linhas visíveis do parágrafo fechado (1.55 e 3). A altura fechada é a multiplicação das duas. |
--bento-pos |
object-position de cada foto, no style da própria <img>. |
.is-open |
No card da linha 2, enquanto o parágrafo está aberto. Quem põe e tira é o script. |
Variações
- sem o card largo — apague
.bento-wide. Sobram quatro cards iguais e o bento vira grade comum; só vale sem foto de abertura à altura. - quatro recursos embaixo —
repeat(4,minmax(0,1fr))na grade espan 3no card largo. - parágrafo inteiro sempre aberto —
--bento-lines:99e remova os.bento-toggle. Funciona sem JavaScript nenhum. Quem apaga o.is-opendo desenho tem de apagar também o.bento-text::after: sem o script para pôr a classe, o esmaecer fica parado por cima da última linha do texto inteiro. - duas linhas fechadas —
--bento-lines:2, para texto mais longo. Esconde mais e aumenta a folga dentro do card. - em dobra escura —
.sec-darkna seção e tire o.sec-darkdo.bento-side, senão o card some no fundo.
Gotchas
- Os cards escuros declaram o escopo no markup, não no CSS.
class="sec-dark"eclass="sec-deep"são classes do core, e é por elas que--bg,--fg,--fg-2e--rule-2viram os valores escuros dentro de uma dobra clara. Se alguém "limpar" o markup tirando essas classes, o card deixa de ser card:background:var(--bg)passa a ler o--bgda seção clara e ele fica creme sobre creme, com o texto escuro da dobra por cima — legível, e invisível como card. O contrato §3 proíbe o componente sobrescrever--fgpor conta própria — declarar em qual escopo o card vive é o caminho que ele deixa aberto. - O grupo de cartões e o texto do rodapé estão no FLUXO, não posicionados sobre a foto. Quem é absoluta é a foto. Na referência os dois são absolutos e o card tem altura fixa; traduzido assim, uma coluna estreita faria o grupo de cima e o texto de baixo crescerem um por cima do outro. Com
justify-content:space-betweenemin-height(piso, não teto), o card cresce e a sobreposição não pode acontecer. O visual a 1440 é idêntico. - A largura do grupo de cartões é declarada de propósito. Os cartões lá dentro têm
width:min(100%,279px); se a caixa se dimensionasse pelos filhos e os filhos por ela, a conta seria circular. O navegador resolve — mas por um caminho que ninguém previu, e a largura muda conforme o texto do nome do produto. Com--bento-floatescrito, os100%dos filhos têm de quê ser 100%. - O grupo flutuante é
aria-hidden="true". É a encenação de uma interface, não conteúdo: quem ouve a página receberia "Adicionado à carteira, CRA — agro, IPCA + 7,1%, R$ 800 mil" sem contexto nenhum, enquanto o título e o parágrafo logo abaixo já dizem o que o recurso é. Não há nada focável lá dentro — se alguém transformar um cartãozinho em link, oaria-hiddentem de sair junto, porque foco dentro de subárvore escondida é erro de acessibilidade. - A expansão é clique, e não hover. A referência troca o card inteiro por uma versão com o texto completo quando o ponteiro entra. Aqui o gatilho é um
<button>de verdade: teclado, toque e leitor de tela vêm de graça, o estado é anunciado peloaria-expandede não existe "recurso que só quem tem mouse descobre". - Abrir um card não fecha os outros, ao contrário do
listas/acordeao-faq. Lá a resposta aberta é o assunto da vez; aqui são três recursos paralelos, e comparar dois abertos lado a lado é uso legítimo. A consequência é que a linha inteira cresce até a altura do maior — o que é o comportamento certo da grade, e não um defeito. - A folga no pé dos cards da linha 2 não é sobra: é para onde o parágrafo cresce.
--bento-card-hé piso, e o conteúdo fechado não chega nele — os primeiros cliques abrem dentro do card, sem empurrar a página, e só quando o texto passa da folga é que a dobra cede altura. Quem "consertar" o vão baixando o piso devolve o pulo da página ao primeiro clique. O piso também é o que mantém as duas linhas do bento com a mesma altura (460 e 472 na referência) — sem ele a linha de baixo fica 100px mais curta e o conjunto lê como duas dobras empilhadas. - A altura é medida com o parágrafo FECHADO, e o teto nunca é suspenso.
scrollHeightlido num elemento comoverflow:hiddendevolve a altura do conteúdo, não a da caixa — é para isso que ooverflowestá lá. A tentação é pôrmax-height:noneantes de medir, e é uma armadilha: lerscrollHeightforça o navegador a assentar o estilo, e ele assentaria onone, que não interpola com comprimento nenhum. A transição seguinte sairia de um valor não animável e o parágrafo abriria seco. Medir fechado é o que mantém a animação de pé. - No
resize, remedir é fechar-medir-reabrir, com a transição fora do caminho. Janela mais estreita pede mais linhas e o número congelado no clique cortaria o fim do texto; janela mais larga pede menos, e o card ficaria alto à toa (scrollHeightnunca devolve menos que a caixa atual, então medir por cima do valor aberto não resolveria). A transição é desligada no estilo inline durante a operação, e devolvida depois de um segundo assentamento — sem esse segundo, ela voltaria a valer no mesmo assentamento em que a altura muda, e o parágrafo piscaria fechando e abrindo a cada arrasto da borda da janela. Os seis passos estão numerados noscript.js; mexer na ordem traz o pisco de volta. - Com movimento reduzido, o parágrafo aberto recebe
max-height:none, e não um número. Não é só economia: com a transição desligada pelo CSS não há o que animar, e um valor em pixels congelado voltaria a cortar o texto na primeira reflow — fonte que chega atrasada, zoom, coluna que muda. Sem número, não há o que ficar velho. - Os
iddoaria-controlssão únicos na PÁGINA, não no componente. Duas dobras destas na mesma página pedem renumeração debento-detalhe-1..3. O script não depende deles (ele acha o parágrafo pelo[data-bento-text]dentro do card), mas o leitor de tela depende. --bento-radiusé multiplicação, não valor cravado. O tema define o card em--radius-media; o painel de dobra da referência é uma vez e meia isso. Em projeto flat--radius-mediaé0, e0 × 1.5é0: a dobra sai reta sem uma media query nem um token novo.- O degradê do pé da foto e o esmaecer do parágrafo leem
var(--bg). São sempre exatamente a cor do card embaixo deles, inclusive se o tema mudar. Trocar por uma cor escrita à mão descola os dois na primeira troca de tema. - O terço inferior de toda foto é área morta. Scrim, véu e degradê passam por cima. Foto com o assunto embaixo é foto perdida aqui.
- O
.sec-titledo core perde omargin-topnesta dobra. Aquele vão existe para a distância até o.eyebrow, e esta dobra não tem olho — sem zerar, sobra um degrau solto no topo. Ao acrescentar um.eyebrow, devolva omargin-top.
Histórico
| Projeto | Onde | Data | Diferenças |
|---|---|---|---|
| referência: Kirvano | https://www.kirvano.com/ — dobra "Recursos poderosos e gratuitos" | 2026-09-01 | referência visual, não origem de código |
Origem. Escrito do zero a partir da observação da dobra de recursos de kirvano.com, medida no navegador a 1440 × 900 com getComputedStyle e getBoundingClientRect. Nada foi copiado: o site não declara licença, e o que veio de lá foi a medida e a ideia de hierarquizar recursos por tamanho de card. Status externo — nunca rodou em produção nossa. O primeiro site que usar promove, e a ficha registra qual foi. A referência está registrada em projetos/referencias-externas.md.
Medido na referência: seção padding:96px 0 sobre #f1ece1; cabeçalho max-width:760 com margin-bottom:48, H2 32px/1.1 com as palavras em span e P a 20 de distância, 18px; grade repeat(3,1fr) com gap:20 numa coluna de 1136. Linha 1 — card A span 2, 751 × 460, raio 24, overflow:hidden, foto cobrindo mais scrim, grupo flutuante 328 × 176 no topo-esquerda com gap:12 (pílula rgb(13,122,59) de 154 × 32, cartão branco 279 × 60 em rgba(255,255,255,.95) com raio 16, segundo cartão 209 × 60 em rgba(255,255,255,.9) com margin-left:32) e, no rodapé, H3 28px/1.1 em caixa 600 × 77 mais P a 16 de distância, 16px, rgba(255,255,255,.7), caixa 540; card B 365 × 460, #111, raio 24, padding:32, H3 30px/1.05 em duas linhas com <br>, ul a 28 com gap:14 e itens de 24 (gap:10, ícone de check), CTA a margin-top:auto, 178 × 52, menta, raio 12, com chevron. Linha 2 — três cards 365 × 472 em #131313, raio 24, overflow:hidden, mídia de 236 no topo com degradê inferior de 96, corpo p-7 pt-4 de 236 com fila 309 × 50 (H3 20px leading-tight mais botão circular 32 × 32, borda rgba(255,255,255,.2), raio 50%, chevron para baixo) e P a 12 de distância, 16px, 309 de largura; camada de hover absoluta em z-index:20, opacity de 0 a 1 em .3s cubic-bezier(.4,0,.2,1), mostrando a versão com o texto completo.
Normalizações aplicadas na tradução:
- Cores cruas trocadas por token: fundo
#f1ece1→ escopo.sec-light(o creme vem de--light-2do tema);#111do card B →.sec-dark(que lê--dark, e no tema kirvano é exatamente#111);#131313dos cards de baixo →.sec-deep, que lê--dark-2—#131313no core, mas#161616no tema kirvano, porque o tema tem UM segundo escuro só e ele foi calibrado pelo card da dobra D2 da mesma referência. Três pontos de diferença, dentro da regra do tom vizinho; scrim →rgba(var(--dark-rgb),…); cartõezinhosrgba(255,255,255,.95)e.9→color-mix(in srgb,var(--light) 95%,transparent); bordargba(255,255,255,.2)do gatilho →--rule-2; texto do rodapérgba(255,255,255,.7)→color-mixsobre--light. - Raio 24 cravado →
calc(var(--radius-media) * 1.5), como o próprio tema manda. - Medidas fixas viraram variável:
460→--bento-tall;236→--bento-media-h;20de vão →--bento-gap;328→--bento-float;760→--bento-head-max;28e32de respiro →--bento-pade--bento-pad-wide. - Texto sobre a foto refeito pela receita do contrato §6 (img → scrim → véu mascarado → texto). A referência só tem scrim; sem o véu, o parágrafo a 70% de opacidade fica sobre o detalhe da foto.
- Entrada por
data-rv/data-d/data-splitdo core — com blur, que a referência não tem (§5). - Acessibilidade que não existia: gatilho é
<button>comaria-expandedearia-controls, grupo de interface comaria-hidden, ícones comfocusable="false".
Divergências conhecidas vs. a referência:
- O respiro vertical é
--sec-gap, e não os 96px medidos. O contrato §4 tem uma fonte única para o ritmo entre dobras, e um número solto aqui a quebraria. A dobra fica mais alta que o original. - A pílula de status é
--accentcom texto em--dark, e não o verdergb(13,122,59)do original. Não temos token para aquele verde e criar um seria decisão de arquitetura (§3); a pílula é uma ilha de marca, e ler a cor de ação do tema é o comportamento que atravessa projeto. - O botão do card escuro é a pílula do core, não o retângulo de raio 12 e 178 × 52 do original.
.btn/.btn-primaryé primitiva e §10.5 manda editar o tema, não o componente. Num tema com--radius-pillmenor o botão volta a ser retangular. - O título da dobra é o
h2.sec-titledo core (clamp(26px,3.4vw,40px)), e chega a 40px onde o original tem 32. E o parágrafo de apoio respeita os60chdo.sec-leadem vez de encher os 760 do cabeçalho — linha de 85 caracteres cansa. - A expansão substitui a camada de hover. Ver o gotcha: o original troca o card inteiro por uma cópia com o texto completo, o que é invisível no toque e no teclado.
- O parágrafo fechado tem três linhas, e não as ~5 medidas na referência. Lá o corpo do card tem 236 de altura com 130 de parágrafo, e o hover revela o resto — o que quase não é revelação, porque já se leu quase tudo. Três linhas mostram o assunto e cortam no argumento. Em compensação sobra folga no pé do card, e é ela que absorve a expansão (ver o gotcha).
- Abrir um card cresce a linha inteira depois que a folga acaba. No original a camada de hover é absoluta e o card nunca muda de tamanho — ao custo de o texto expandido tapar a foto.
- O grupo de cartões e o texto do rodapé estão no fluxo, e não posicionados sobre a foto. Ver o gotcha sobre sobreposição em coluna estreita.
- Miudezas que não foram atrás do número medido, e ficam registradas para ninguém as "consertar" achando que são engano: o parágrafo de apoio é o
.sec-leaddo core (17px,margin-top:18) contra os18pxa20de distância do original; o título dos cards de baixo temline-height:1.15contra oleading-tight(1.25) de lá; o item de lista do card escuro fecha em ~21px de altura contra os 24 medidos, porque a altura ali é a da linha de texto e não um número escrito; a pílula de status fecha em 28px de altura contra 32, pelo mesmo motivo; e o parágrafo do rodapé da foto está a 72% de--lightcontra os 70% do original — 72 é onde o texto se solta do véu nas três fotos do preview. Nenhuma passa de dois ou três pixels, e todas são consequência de a medida vir do conteúdo em vez de ser cravada. - Nada da marca da referência atravessou (§11): nome, fontes (Inter Tight e a display proprietária), fotos, ícones e qualquer meio de pagamento identificável ficaram de fora. Os textos são reescritos e genéricos, a marca é a fictícia "Liberta", as fotos são os placeholders de
showroom/demo/e os ícones são SVG desenhados na hora.