Componente que nasceu aqui, sem projeto de origem e sem uma referência externa única. O que entra é um padrão de interação que aparece em muitos sites premium — o anel 3D arrastável, a faixa horizontal pinada, a lista cuja imagem segue o cursor — reescrito do zero dentro do contrato.
| Como entra | construído do zero, em token, prefixo, primitiva do core e gancho do motion.js — nenhuma linha copiada de lugar nenhum |
| Por quê | o padrão é de domínio comum; o que faz dele um componente nosso é a tradução para o contrato: o que vira variável, o que ganha teclado, o que acontece sem hover e com movimento reduzido |
| Status inicial | estavel — normalizado ao contrato, auditado pela conformidade e medido no Chrome headless |
Registro no componente.json |
origem[].projeto = "autoral", ancora nomeia o padrão, nota cita as famílias de exemplo e as decisões de tradução |
A diferença para o clone de referência é só de registro: não há URL. A regra de ouro continua valendo — antes de construir, procure no catalogo.json — e cada ficha diz qual irmão catalogado ela substitui e em que caso.
A leva de 2026-09-03: carrosséis e movimento
Pedido: olhar a biblioteca com o olhar de quem já fez site de banco e de marca de esporte, e trazer as opções de carrossel que faltavam — imagens grandes e pequenas, girando, passando, atravessando — mais o que dá o "uau" de entrada sem quebrar o contrato. Tudo já na voz da Liberta (assessoria de investimentos), porque a biblioteca vai virar produto para clientes do ramo financeiro.
O que faltava (mapa de lacunas)
O que existia antes desta leva, em movimento de imagem: prova/marquee-logos (logos em esteira), prova/carrossel-depoimentos (cards de texto em esteira), midia/carrossel-perfis (trilho infinito com arrasto), midia/galeria-scroll-horizontal (scroll-snap alinhado à coluna), midia/galeria-pasta (pilha que abre em leque), hero/duas-colunas-produto (slider manual de setas), listas/baralho-sticky (cards que grudam ao rolar), conteudo/apresentacao-foto-alternada (fusão de três fotos). Boa base — e estas eram as lacunas:
| Lacuna | O que não existia | O que entrou |
|---|---|---|
| Profundidade 3D | nenhum componente usava perspective/preserve-3d |
midia/carrossel-anel-3d (cilindro que gira) · efeitos/inclinacao-3d (card que inclina para o ponteiro) |
| Rolagem vertical virando movimento horizontal | o baralho gruda, mas nada atravessa a tela para o lado | midia/faixa-horizontal-pinada |
| Imagem dirigida pela leitura | nenhum painel troca de foto conforme o texto passa | conteudo/rolagem-sincronizada |
| Hero com ritmo | full-bleed-media é uma foto só, parada |
hero/slideshow-cinematico (Ken Burns, fusão com blur, abas com progresso) |
| Carrossel de produto centrado | o galeria-scroll-horizontal alinha ao início; nada tem o card ativo no centro e os vizinhos recuados |
midia/carrossel-foco-central |
| Gesto de swipe | a galeria-pasta abre e fecha; nada descarta um card para revelar o de baixo |
midia/pilha-swipe |
| Esteira de imagem grande | as esteiras eram de logo e de texto | midia/esteira-dupla-imagens (duas fileiras opostas, reagindo à rolagem) · midia/colunas-cascata (parede vertical de fotos, CSS puro) |
| Imagem que segue a mão | o cursor-anotacao é roteirizado; nada responde ao ponteiro |
listas/lista-imagem-flutuante |
| Linha do tempo | nenhuma forma para "ano a ano" | midia/roda-de-cards (arco que gira, com início e fim) |
O que entrou
| Componente | Padrão | O que ele resolve que nenhum irmão resolvia |
|---|---|---|
midia/colunas-cascata |
parede de fotos em esteiras verticais opostas sob texto parado | dobra de presença quando o material são oito fotos boas e nenhuma extraordinária — a foto única do hero/full-bleed-media precisa de uma imagem que aguente a tela sozinha |
midia/faixa-horizontal-pinada |
seção pinada com trilho horizontal preso à rolagem | a rolagem vertical vira deslocamento horizontal; o listas/baralho-sticky gruda, mas nada atravessava a tela para o lado |
midia/carrossel-foco-central |
carrossel com o card ativo no meio | o midia/galeria-scroll-horizontal alinha ao início da coluna; aqui o ativo fica centrado, em escala cheia, com os vizinhos recuados |
midia/carrossel-anel-3d |
anel 3D arrastável | primeira profundidade real da biblioteca: nenhum componente usava perspective/preserve-3d, e o midia/carrossel-perfis resolve o trilho plano |
efeitos/inclinacao-3d |
card que inclina em 3D na direção do ponteiro | a outra metade da profundidade que faltava: o midia/carrossel-anel-3d gira um cilindro inteiro, e aqui o 3D é primitiva de efeito — [data-tilt] em qualquer card, sem o componente saber o que é |
midia/pilha-swipe |
pilha de cards com descarte por gesto | a midia/galeria-pasta abre e fecha um leque; nada descartava um card para revelar o de baixo |
midia/esteira-dupla-imagens |
esteira dupla em sentidos opostos, com velocidade acoplada à rolagem | as esteiras da casa eram de logo e de texto, em ritmo fixo; esta é de foto grande e reage a quem rola |
listas/lista-imagem-flutuante |
lista com imagem que segue o cursor | o efeitos/cursor-anotacao é roteirizado, com âncoras fixas; aqui a imagem responde à mão em tempo real |
hero/slideshow-cinematico |
abertura de tela cheia em três slides, com Ken Burns e abas de progresso | o hero/full-bleed-media é uma foto só, parada; este é o primeiro hero com ritmo, e o relógio para no ponteiro, no foco, na aba oculta e no botão de pausa — retomando do ponto exato |
conteudo/rolagem-sincronizada |
duas colunas com painel de mídia pinado trocando conforme o texto passa | nenhum irmão deixa a leitura dirigir a imagem: o listas/baralho-sticky gruda os cards ao rolar, mas nada respondia ao bloco de texto que está sendo lido |
midia/roda-de-cards |
roda-gigante de cards com o cubo abaixo da dobra | primeira forma da biblioteca para "ano a ano": a roda tem começo e fim, e nenhuma esteira ou carrossel da casa sabia parar nas pontas em vez de dar a volta |
Princípios que valeram para todos
O "uau" não é quantidade de efeito. É uma ideia de movimento clara, com timing certo, que continua funcionando sem mouse, sem hover, com "reduzir movimento" ligado e em 390px. Cada componente desta leva foi medido nessas quatro condições antes de entrar, e a ficha registra os números.
- Sem GSAP. Nenhum dos onze pediu timeline encadeada nem
scrub. O que é preso ao scroll usaLIB.onScroll(o laço único do core) com fallback próprio; o que é contínuo usa umrequestAnimationFramepor instância, que dorme fora da tela. - Tempo, não quadro. Velocidade em px/s ou graus/s multiplicada por
dt, com teto de 50ms — 60Hz e 120Hz andam igual, e voltar de uma aba em segundo plano não salta. - Toque não tem hover. Tudo que depende de hover nasce visível em
@media(hover:none)ou tem alternativa (miniatura inline, botões). - Movimento reduzido desliga o que anda sozinho, nunca o que a pessoa pediu: arrasto e setas continuam, sem inércia.
- Medido, não suposto. O
bin/medir.js(Chrome headless) foi a régua: transform antes e depois do arrasto, classe ativa após a tecla,scrollWidthcontraclientWidth, console limpo.
A leva de 2026-09-03/04: ferramentas interativas
Segundo pedido do dono, na mesma noite, depois de ver o conteudo/trio-cards-ui-simulada rodando: mais peças com movimento, patrimônio e gráfico, e em especial ferramentas — coisas que a pessoa usa antes de falar com um assessor, para servirem de mote em campanha. A referência de forma que ele mandou foi o simulador de carteira do avenue.us: um assistente de quatro passos sobre uma foto, que pergunta objetivo, composição, faixa e conhecimento, e devolve uma leitura.
A diferença para a leva anterior é o que a peça entrega. Lá era movimento; aqui é interação com resultado.
| Componente | O que a pessoa faz | O que recebe |
|---|---|---|
conversao/simulador-carteira |
responde quatro passos | uma rosca de alocação e uma conversa |
conversao/calculadora-projecao |
move três controles | uma faixa de cenários desenhada |
dados/painel-patrimonio |
troca o período | o relatório consolidado, encenado |
dados/comparador-cenarios |
ajusta patrimônio e anos | o custo de dois modelos de remuneração |
As sete, entregues
| Componente | O que faz | O que ele resolve que nenhum irmão resolvia |
|---|---|---|
conversao/simulador-carteira |
assistente de quatro passos com rosca de alocação | a peça que nasceu do pedido; nenhum irmão fazia entrada de dados em vários passos terminando em gráfico |
conversao/calculadora-projecao |
três controles e uma faixa de cenários | a prova/stats-contador-regua conta números prontos; aqui o número é recalculado pela pessoa |
dados/painel-patrimonio |
o portal do cliente encenado numa dobra | irmão maior do conteudo/trio-cards-ui-simulada, que faz o mesmo em três cards pequenos |
dados/comparador-cenarios |
custo de dois modelos de remuneração ao longo dos anos | o argumento comercial que a biblioteca só sabia dizer em texto |
conversao/calculadora-sucessao |
inventário contra holding, com as parcelas visíveis | o gancho de campanha mais forte do setor, e o que nenhuma peça cobria |
conversao/diagnostico-perfil |
cinco perguntas tipográficas, uma por tela | forma oposta à do simulador: sem foto, sem painel, a pergunta é a peça gráfica |
dados/regua-liquidez |
objetivos arrastáveis numa linha do tempo de 30 anos | primeira peça em que o dado de entrada é a POSIÇÃO de um objeto, não um campo |
Todas com 0 alertas de conformidade, console limpo, sem estouro horizontal em desktop e celular, e um estado honesto sem JavaScript.
A regra que governa a família inteira: compliance vem antes da forma
Ferramenta que devolve número em site de assessoria pisa em terreno regulado, e isso decidiu o desenho, não só o texto:
- A calculadora desenha uma faixa, não uma linha. Linha única diz "seu dinheiro vai chegar aqui". Faixa diz "o resultado mora nesta região, e ela é larga".
- O comparador compara custo, nunca resultado. Custo é aritmética verificável a partir de premissa declarada; resultado é promessa.
- O simulador mostra alocação, nunca rentabilidade.
- A premissa fica visível na peça, não em letra miúda: comparador que esconde a premissa é propaganda, não ferramenta.
- Ressalva no passo do resultado, onde a pessoa lê o número — não no rodapé da página.
- Nenhuma ferramenta coleta dado pessoal e nenhuma grava em
localStorage. As respostas vivem em memória e morrem no recarregamento. Quem captura é oconversao/cta-formulario-lead, para onde o botão final aponta.
Cada ficha desta família tem uma seção ## Compliance dizendo o que o consumidor precisa trocar antes de publicar.
O brief que os agentes seguiram e o estudo de tokens que dimensionou as ondas estão fora do repositório, no scratchpad da sessão.
A leva de 2026-09-04: cinco da fila, e o elemento nativo como método
Cinco dos padrões que estavam previstos na fila autoral saíram dela. O sexto, o ticker de índices, ficou — e ficou pela razão que a própria fila registrava: valor de cotação fictício num site financeiro é problema, não placeholder. Ele entra quando houver feed real e data.
(Saiu em 2026-09-10 — e o que o destravou foi outra coisa: ver a leva abaixo.)
| Componente | Padrão | O que ele resolve que nenhum irmão resolvia |
|---|---|---|
midia/comparador-antes-depois |
duas imagens do mesmo enquadramento com divisor arrastável | a categoria previa e nada existia: a biblioteca sabia mostrar imagem e sabia comparar número (dados/comparador-cenarios), mas não sabia sobrepor duas fotos para a diferença aparecer no mesmo pixel |
midia/showreel-expansivel |
capa de vídeo que cresce até a tela e entrega os controles nativos | o overlay/card-expansivel-fullscreen faz a mesma expansão, mas para texto, foto e CTA; vídeo pede barra, volume, velocidade, legenda e picture-in-picture, que não se reimplementam bem |
efeitos/selo-circular |
texto curvo em rotação contínua | primeira tipografia em curva da casa, e o único componente de movimento contínuo que não precisa de uma linha de script |
navegacao/progresso-leitura |
filete no topo acompanhando a rolagem | a categoria previa e nada existia: nav-fixa-vidro diz onde você pode ir, e nada dizia onde você está |
efeitos/cursor-disco |
anel que segue o ponteiro e cresce sobre alvo | o efeitos/cursor-anotacao é roteirizado, com âncoras fixas, e o listas/lista-imagem-flutuante responde à mão dentro de uma lista; nada acompanhava o ponteiro pela página inteira |
prova/manchetes-imprensa |
citação de imprensa em card, no lugar do print de matéria | a prova/marquee-logos mostra de quem se falou sem dizer o quê, e a prova/carrossel-depoimentos traz citação de pessoa com retrato; faltava a citação de veículo, com logo, data e link — que é o que transforma menção em prova verificável |
O componente que nasceu de um print
A prova/manchetes-imprensa não veio de padrão de mercado: veio de uma copy
da casa em que as menções de jornal estavam como captura de tela. Print não
escala, não quebra no celular, não tem alt, o buscador não lê e o texto
amarela no dia em que o veículo troca de layout.
Duas coisas ficaram registradas nela:
-
Data e link são estrutura, não opção. Um card com o logo de um jornal de verdade e uma manchete sem data nem link não é peça de marketing, é notícia falsa atribuída a um veículo. Com os dois, é citação. A ficha tem uma seção
## Compliancesó sobre isso, no mesmo formato das ferramentas financeiras. -
A tipografia não imita a do veículo. Cada jornal tem a própria fonte, e fonte de terceiro não atravessa (§1). Quem diz de onde veio a manchete é o logo — imitar a letra seria, além de ilegal, a parte errada da imitação.
A terceira medição da leva: transição trava tom
O realce de hover do card começou como transition: background-color. Trocar o
escopo da seção de .sec-paper para .sec-dark deixava o fundo preso no
valor antigo: --bg resolvia certo no computado, o fio e o texto invertiam,
e só o background ficava para trás. Medido no Chrome — com a transição,
rgb(237,233,227); removendo-a na hora, rgb(10,10,10).
Transição sobre propriedade que lê custom property não acompanha a troca da
própria variável. Como o tom vir da seção é justamente a promessa deste
componente, quem saiu foi a transição: o realce virou véu em opacidade num
::before, que não depende de --bg. Vale para qualquer componente da casa
que queira animar algo lido de token de escopo.
O método que apareceu nesta leva: usar o elemento nativo
Dois dos cinco tomaram a mesma decisão, e ela vale como regra daqui para a frente: quando existe um elemento HTML que já faz o comportamento, use ele em vez de reimplementar.
O comparador-antes-depois podia ter o arraste escrito à mão, com
pointerdown, pointermove, pointerup e captura de ponteiro — é o que
quase toda implementação do padrão faz. Em vez disso o controle é um
<input type="range"> invisível sobre a imagem, e daí vieram prontos e
testados o arraste, o toque, as setas, Home, End, PageUp/PageDown e o
anúncio de porcentagem para leitor de tela. O script ficou com vinte linhas e
uma responsabilidade: copiar o valor para uma custom property.
O showreel-expansivel fez o mesmo com <dialog> e showModal(): foco preso
dentro, Esc que fecha, foco que volta ao botão que abriu e página inerte para
tecnologia assistiva. Quatro comportamentos, zero linhas. O irmão
overlay/card-expansivel-fullscreen nasceu antes e escreve os quatro à mão —
não é erro dele, é data de nascimento.
O que se ganha não é economia de código, é correção de graça: o comportamento nativo já foi testado em navegador, em leitor de tela e em teclado por gente que faz isso em tempo integral.
Duas medições que mudaram o desenho
-
textLengthé ignorado em<textPath>. Noselo-circular, a saída óbvia para encaixar o texto no arco seria pedir ao SVG que ajustasse o espaçamento. Medido no Chrome: o texto continuou com 363,5 unidades depois de recebertextLength="232.5". A conta virou manual, e o texto padrão foi escolhido pela medida —Patrimônio · Estratégia ·repetido dá 221,1 num arco de 232,5, e a folga de 11,4 é o vão entre a última letra e a primeira. -
Um
requestAnimationFramenão basta para o FLIP. Noshowreel-expansivel, com uma única espera entre escrever o transform inicial e removê-lo, o navegador às vezes agrupa as duas escritas e a transição não acontece: o quadro aparece direto no lugar final. São dois.
O que os três elementos de página têm em comum
progresso-leitura, cursor-disco e o <dialog> do showreel vivem fora de
qualquer [data-rv], e não por estilo: o core termina todo reveal em
filter:blur(0), blur(0) continua sendo um filtro, e elemento com filtro
vira bloco de contenção para descendente position:fixed. Dentro de uma dobra
revelada, os três passariam a se posicionar em relação à dobra em vez da
janela — e só depois que ela entrasse na tela. Está no MANUAL §5, e agora
tem três precedentes.
A leva de 2026-09-06: as categorias que a própria descrição prometia
Esta leva não saiu de um padrão de mercado nem de uma referência. Saiu de uma
auditoria da distribuição: midia tinha 12 componentes e overlay tinha 1,
e a descrição de duas categorias prometia, por escrito, peças que nunca foram
construídas.
| Categoria | O que a descrição promete | O que existia |
|---|---|---|
overlay |
"modal, drawer de conteúdo, toast, aviso de cookies" | só card-expansivel-fullscreen |
conversao |
"CTA, formulário, agendamento, planos, campos de formulário" | nenhum de planos, nenhum de agendamento |
listas |
"serviços, etapas, perguntas" | nenhuma linha do tempo, nenhuma tabela |
Categoria não é cota — mas descrição que promete e não entrega é dívida, e quem
consome a biblioteca descobre isso no pior momento: no meio de um projeto, com
o componente faltando e o prazo correndo. Todas as oito peças abaixo seriam
improvisadas à mão em cada site, que é exatamente como se escreve um banner de
LGPD errado ou uma tabela de comparação que é div.
| Componente | Padrão | O que ele resolve que nenhum irmão resolvia |
|---|---|---|
overlay/modal-dialogo |
modal de texto longo sobre <dialog> nativo |
o overlay/card-expansivel-fullscreen pressupõe um card de trilho e carrega o detalhe nos data-* dele — não há onde pôr quatro parágrafos e uma lista de prosa escrita à mão |
overlay/drawer-lateral |
painel lateral de detalhe, com o contexto visível atrás | detalhar um item mantendo o lugar na página: o navegacao/drawer-fullscreen é menu e leva a pessoa embora; o card expansível cobre a tela inteira |
overlay/aviso-cookies |
consentimento em dois níveis, com preferências granulares | as sobreposições da casa prendem o foco e travam a página — e é justamente esse bloqueio que um banner de LGPD não pode ter |
overlay/toast-aviso |
pilha de avisos efêmeros com régua de tempo | retorno de ação sem navegação (envio, cópia, erro); modal e drawer pedem decisão, e o aviso de cookies precisa persistir até escolha explícita |
conversao/planos-honorarios |
colunas de modelo com alternância entre conjuntos | a escolha em colunas, com faixa de entrada, honorário em faixa e um botão por modelo — o dados/comparador-cenarios faz a aritmética, a matriz explica o mercado, e nenhum dos dois oferece o lugar da pessoa dentro dele |
conversao/agendamento-reuniao |
dia, horário e formulário, nesta ordem | é o único componente da casa em que a pessoa escolhe quando antes de dizer quem — o cta-formulario-lead captura sem data, o diagnostico-perfil qualifica sem coletar |
listas/linha-do-tempo-etapas |
linha do tempo vertical com filete preenchido pela rolagem | o "como funciona" com prazo por etapa num lugar fixo do desenho; o baralho-sticky força a sequência e custa uma tela por etapa, a roda-de-cards é cronologia de anos com gesto |
listas/tabela-comparativa |
matriz de critérios × abordagens | a única <table> semântica da biblioteca: comparação é dado tabular, e dado tabular não é div |
Duas regras de forma que a leva firmou
Recusar tem de ser tão fácil quanto aceitar, e isso é layout. No
aviso-cookies, os dois caminhos do primeiro nível não só usam a mesma
primitiva como dividem uma grade de duas colunas iguais. Medido: numa fila
comum, "Aceitar todos" saía com 158px contra 230px de "Recusar não essenciais",
e a pílula mais curta lia como a secundária. Mesmo estilo não bastava.
Comparação honesta perde pelo menos uma linha. A tabela-comparativa
destaca a coluna da casa, mas há um critério em que a alternativa empata ou
ganha. Uma matriz em que o outro caminho só tem "não" é propaganda, e o leitor
sente — a credibilidade da peça inteira depende dessa linha.
O que a leva devolveu ao core
Duas correções, as duas achadas por medição e nenhuma prevista no plano:
.btnnão zeravabackgroundnemappearance. Comcolor-scheme:only light, todo<button class="btn btn-ghost">pintava o cromo cinza do sistema sob texto claro: medido emrgb(240,240,240)contrargb(242,240,236)noconversao/diagnostico-perfil, que já estava assim no catálogo. Passou despercebido porque quase todo uso da primitiva é<a class="btn">, e âncora não tem cromo nativo.html{scroll-behavior:smooth}não tinha exceção parareduce. Toda âncora de todo componente atravessava a página rolando para quem pediu menos movimento, e cada script que rolava por conta própria contornava combehavior:'instant'. O contrato promete quereducedesliga tudo; agora o caso nativo também está coberto.
A leva de 2026-09-09: as tags magras, e o que elas revelaram
A vitrine passou a se organizar por tag e não por categoria (bin/tags.json),
e a primeira coisa que o levantamento fez foi apontar onde a biblioteca era
magra: videos tinha um componente, 4 colunas tinha um, big numbers
tinha um. Nove peças depois: 4, 3 e 3.
| Componente | Padrão | O que ele resolve que nenhum irmão resolvia |
|---|---|---|
hero/video-fundo |
vídeo em loop como superfície da primeira dobra | a única peça em que vídeo é superfície e não conteúdo; o full-bleed-media tem a mesma anatomia com foto e continua ganhando sempre que não houver um loop editado de propósito |
prova/depoimento-video |
grade de retratos que abrem em <dialog>, com a citação legível fora do vídeo |
depoimento gravado com atribuição e legenda declarada; o carrossel-depoimentos não tem vídeo, o showreel não tem nem atribuição nem grade |
midia/faixa-videos |
índice de série: capas com duração e episódio, um <dialog> com um <video> que troca de src |
escolher um vídeo entre vários — o showreel é de um só, e a galeria horizontal é foto que leva a outra página |
prova/numero-gigante |
a cifra única em corpo de dobra, com fonte e data impressas na peça | quando um dado carrega o argumento inteiro; a régua e a grade o diluem entre iguais. A escala é aritmética: --ngig-glifos divide o corpo e a figura fica constante de 19 a R$ 1.240 mi |
dados/grade-indicadores |
4 a 6 indicadores com variação e a janela em que foi apurada | dado com tempo dentro: a régua afirma o número sem direção nem período, e o painel é interface com abas |
conteudo/grade-servicos-icone |
quatro serviços com ícone de traço, título curto e uma frase | a dobra de serviços sem material fotográfico — o único asset é um SVG de 24×24 no próprio markup, em currentColor |
midia/grade-cases-foto |
grade estática de cards de foto, cada um um <a> inteiro |
um conjunto fechado todo à vista; o trilho horizontal esconde de propósito o que está fora da tela |
conteudo/abertura-tipografica |
abertura de capítulo feita só de tipografia | é a única que não tem nada embaixo: o .sec-head do core é rótulo de um miolo que vem em seguida, e vem com .sec-pad simétrico. O que ela traz é o ritmo assimétrico (2 vãos acima, 1,4 abaixo) |
dados/fluxo-conectado |
cadeia de caixas ligadas, traço no vão da grade, zero JavaScript | estrutura no espaço: o diagrama-hub desenha convergência e paga com SVG calculado sobre o DOM; a linha do tempo conta um processo no tempo |
O que a leva devolveu ao core
Três correções, e nenhuma estava no plano — todas saíram de alguém medindo o próprio trabalho e olhando para o lado.
--accent-ink: a cor de marca não é cor de texto. O core pintava o realce
em itálico do título com --accent. Sobre o escuro isso dá 12:1; sobre o creme
do .sec-paper, 1,36:1 — e já era assim em quatro componentes publicados.
A mistura com a tinta do escopo resolve no claro (4,59:1) e não se aplica no
escuro, onde clarearia e apagaria a marca.
Três heros perdiam a headline sem JavaScript. O @media(scripting:none) do
core cobre [data-rv], .w e .ttl — e não alcança quem revela por classe
própria. O full-bleed-media, que é destaque 3, mostrava foto e mais nada.
Varridos os 70: treze usam classe própria, dez estavam certos (ali o script
liga o comportamento e o CSS não esconde nada), e só os três heros escondiam
argumento.
--sem-js no bin/medir.js. Três agentes escreveram
javaScriptEnabled:false à mão antes de virar opção — e é ela que fez o defeito
acima aparecer. A distinção importa: desligar o JS faz o Chrome casar
scripting:none; apenas apagar as tags de script mede o outro caso, o
script que não carrega com o JS ligado, onde nem o media query casa.
Uma recusa que vale mais que uma peça
Pedi a três agentes que parassem e relatassem se achassem que o irmão já
resolvia. Nenhum parou — mas o da abertura tipográfica quase: a investigação
mostrou que a versão centrada seria duplicata do bloco de texto do
colunas-cascata, e a peça só se justificou depois de mudar de forma. É o
resultado que a regra de ouro existe para produzir.
A leva de 2026-09-10: cotações, e uma forma descartada no caminho
Um componente só: o dados/cards-cotacoes
— o painel de cotações que a fila autoral segurava desde 2026-08 sob o nome
"ticker de índices", com a trava escrita no próprio registro: valor de cotação
fictício num site financeiro é problema, não placeholder.
A fila estava certa em segurá-lo. Um painel de cotação construído do jeito comum é um componente que mente por padrão, porque o estado natural de um feed é morrer sem avisar — e a página segue mostrando a cotação de terça na sexta, sem que ninguém perceba.
O que destravou não foi um aviso na ficha
Foi inverter a pergunta. Em vez de "como avisar que o dado pode estar velho?", que é pergunta de documentação, "o que faz este componente afirmar que o dado é novo?" — que é pergunta de forma.
O que saiu disso, e é o motor do componente:
- O script não anima nada. Ele compara
data-emcomdata-validadee escrevedata-estadona raiz. O CSS lê o estado. - A
.coto-fonte— provedor, instante e atraso — é parte obrigatória do bloco. Sem provedor e sem instante, o preço acima não é cotação: é um número grande. - Vencido, o preço sai do DOM — texto e atributo
value— e odata-dirsai junto. Apagar por CSS deixaria a cotação retirada intacta na árvore de acessibilidade, e uma seta de alta sobre um traço vazio continuaria afirmando alta. - O selo "ao vivo" é concedido, não escrito. Ele só é exibido sob
[data-estado="vivo"]— não adianta pô-lo no markup. É a afirmação visual de que o número é de agora. - Data no futuro conta como vencida, e
data-validade="0"é a saída honesta de quem publica um fechamento em vez de tempo real.
A primeira forma foi construída inteira, e reprovada
A construção original era uma faixa em esteira, no padrão de ticker de
bolsa: símbolo, valor e variação correndo de lado, com a regra "movimento é
uma afirmação de que o dado está vivo" — a esteira só andava no estado vivo,
e o clone que fechava o laço era criado pelo script, para que sem JavaScript
não houvesse laço nem afirmação.
Funcionava, passava na conformidade e tinha ficha inteira. Foi reprovada na revisão pela forma, não pelo motor:
Em faixa, a pessoa espera o papel dela passar. Em card, ela procura.
Numa página institucional, quem abre a dobra de mercado quer conferir um papel específico — e a faixa transforma isso em espera. A forma que ficou é a do app de Ações do iPhone e a do painel do Google Finance, que é a leitura que o público já sabe fazer.
O motor de validade migrou inteiro. O que se perdeu foi a esteira — e o selo "ao vivo" ocupou o lugar que o movimento tinha como afirmação de liveness. Vale registrar porque é barato de esquecer: o mesmo motor serve às duas formas, e a escolha entre elas é de leitura, não de arquitetura. Se um projeto pedir a faixa um dia, o que se reconstrói é o CSS.
O método, e onde ele já tinha aparecido
É o mesmo raciocínio da prova/manchetes-imprensa,
de seis dias antes: lá, <time datetime> e o href da matéria entraram no
markup como estrutura, não como opção, porque um card com o logo de um
jornal real e uma manchete sem data nem link não é peça de marketing — é
notícia falsa atribuída a um veículo.
Vale escrever como método, porque os dois casos são o mesmo caso:
Quando a peça faz uma afirmação que ela não pode sustentar sozinha, o que falta vira estrutura do markup — não linha da ficha.
Ficha ninguém lê na hora de colar. Estrutura, sim: ela está no arquivo que a pessoa copia, e some junto se for apagada.
Duas medições que mudaram desenho
-
preserveAspectRatio="none"pedevector-effect:non-scaling-stroke. O minigráfico estica até a largura do card, seja ela 230px ou 400px — é o que permite a mesma série servir a qualquer coluna. O preço é uma escala anisotrópica: sem ovector-effect, o traço engorda na horizontal e afina na vertical, e o gráfico do card largo fica visivelmente mais gordo que o do estreito. -
SVG não tem
z-index. A área preenchida tem de vir antes da linha na ordem do documento; quem pinta por último fica por cima. Invertido, o preenchimento cobre metade do traço e o gráfico perde o contorno.
O que ficou de fora, e por quê
Verde e vermelho não ficaram de fora — viraram token do core. É a única
mudança que esta leva fez fora da pasta do componente, e ela passou pela
conversa que o §3 exige antes de criar nome novo no vocabulário da casa. A
alternativa, deixar as duas cores como parafuso local, adiava o problema para
o próximo que precisasse: o pill-status-pulsante está na fila do
gabriel-rocha-studio esperando exatamente isso.
Duas decisões saíram junto, e as duas são do token, não do componente:
- O nome fala do papel, não do pigmento.
--altae--baixa, não--verdee--vermelho. Um projeto pode trocá-los por âmbar e azul sem que nenhum componente fique mentindo no próprio código. - Os valores são redefinidos por escopo de tom, e isso foi medido: nenhum
verde único alcança 4,5:1 contra
#0a0a0ae contra#ffffff. O par calibrado para o escuro (#57bd82) cai para 2,3:1 sobre papel. Então.sec-dark/.sec-deeptêm um par e.sec-paper/.sec-lighttêm outro, como já acontece com--fge--rule. Os valores em:rootsão só o fallback de quem usar o token fora de uma seção com escopo.
E uma regra veio anexada ao token, escrita no tokens.css e no §3: cor nunca
é o único portador da direção. O par verde/vermelho é exatamente o que 8% dos
homens não distinguem. No cards-cotacoes a direção está na seta, no sinal e
por extenso em .visually-hidden — o painel continua legível em preto e branco.
Papéis reais. Os do markup e do preview são fictícios de propósito — MRD3,
ALT4, NBY11 e QDR3, das casas inventadas Meridiano, Altamira, Northbay e
Quadrant, os mesmos nomes que a prova/manchetes-imprensa já usa. Papel
inventado com preço inventado é demonstração; papel real com preço inventado
é informação financeira falsa, e nenhum desenho de componente conserta isso.
Linha reta por falta de dado. Card sem série fica sem minigráfico, e não com uma curva plana. Linha reta desenhada por ausência de dado é a mesma mentira do preço vencido, em forma de gráfico.
A leva de 2026-09-29: o que as bibliotecas grandes têm e a casa não tinha
Pedido do dono: carta branca para melhorar a biblioteca — ler tudo, testar, pesquisar bibliotecas externas, criar elementos novos. A leva começou por uma comparação com a taxonomia das grandes bibliotecas de seção (Relume organiza a dela em Hero, Header, Feature, CTA, Contact, Pricing, FAQ, Testimonial, Logo, Blog, Gallery, Banner; Aceternity e Magic UI puxam para efeito de texto e de fundo) e com o que um site de assessoria precisa de fato. Três lacunas eram de tipo de conteúdo, e não de efeito:
| Lacuna | O que não existia |
|---|---|
| Conteúdo com data | nenhuma forma para carta mensal, análise ou evento — a casa sabia citar a imprensa (manchetes-imprensa) e não sabia publicar a própria voz |
| Contato direto | formulário, agendamento e CTA, e nenhum lugar para endereço, telefone e horário |
| Âncoras | a descrição da categoria navegacao promete "âncoras" desde o primeiro dia |
| Componente | Padrão | O que ele resolve que nenhum irmão resolvia |
|---|---|---|
navegacao/indice-ancoras |
barra "nesta página" que gruda e marca a seção em leitura | a âncora que a categoria prometia: o nav-fixa-vidro diz para onde ir no site, este diz onde você está na página |
listas/grade-artigos |
um artigo em destaque com foto, e uma lista tipográfica ao lado | a primeira forma para a voz editorial da casa; o selo "Novo" é concedido pela data e some sozinho |
listas/agenda-eventos |
eventos com a data grande e inscrição | o convite que expira: depois do fim, o botão sai do DOM e entra "Encerrado" ou a gravação |
conversao/contato-escritorios |
canais em corpo grande e um card por escritório | o caminho curto para quem já decidiu; "aberto agora" lido no relógio do fuso do escritório |
conversao/faixa-newsletter |
e-mail, botão e consentimento desmarcado | o primeiro formulário da casa que não finge sucesso: sem action, avisa que é demonstração |
O método que atravessou a leva inteira
Quatro dos cinco são o motor do dados/cards-cotacoes aplicado a objetos
diferentes — o que a peça afirma e não pode sustentar sozinha vira estrutura:
| Afirmação | Quem a sustenta | O que acontece quando ela deixa de valer |
|---|---|---|
| "Novo" | a <time datetime> do artigo |
o selo não é criado |
| "Inscreva-se" | data-agn-inicio/fim, com fuso |
o botão sai do DOM |
| "Aberto agora" | data-ctt-horario, lido no fuso do escritório |
o selo diz "Fechado · abre às…" |
| "Pronto, inscrito" | a resposta do action do formulário |
sem action, diz "demonstração, nada foi enviado" |
E nos quatro, sem JavaScript a afirmação não aparece: o span nasce vazio, o selo não é escrito, o botão fica como foi publicado. A peça nunca diz o que não consegue conferir.
Três que ficaram de fora, e por quê
-
Texto que acende com a rolagem. Foi construído, medido e publicado no branch — e saiu no merge com a
main, onde a leva do SkinBoost de 2026-09-21 já tinha trazido oefeitos/destaque-texto-scroll: o mesmo padrão, mais maduro (acende por linha ou por palavra, variação pinada, seção de compliance). Duas sessões em paralelo chegaram à mesma peça sem uma ver a outra, e a regra de ouro decidiu sozinha: antes de inventar, procure no catálogo — inclusive no catálogo que chegou depois. Ficou a lição de processo: numa sessão longa,git fetche reler ocatalogo.jsondamainantes de catalogar, não só antes de começar. -
Faixa de anúncio no topo ("novo relatório →", com prazo de validade). Construída na cabeça, reprovada no encaixe: o
navegacao/nav-fixa-vidroéposition:fixedno topo, e uma faixa em fluxo acima dele nasce coberta pelo menu. Resolver pede que o menu leia a altura da faixa — mexer no componente do menu para caber no vizinho, que é o que o §10 proíbe. Foi para a fila com a nota. - Brilho que segue o ponteiro (o spotlight card da Aceternity e da Magic UI). Descartado pela regra que entrou no mesmo dia: hover não mexe em nada (CLAUDE.md §6). O brilho não desloca nada, mas é efeito de passagem de mouse, e a razão do dono para a regra — "sempre acaba quebrando as páginas" — pede menos efeito de hover, não um novo.
O que a leva devolveu à casa
bin/varredura.js— os previews inteiros no Chrome, em quatro cenários. Na primeira passada achou três defeitos publicados que nenhum validador de código via (MANUAL §9, README).- A regra do hover e a verificação dela no
conformidade.py, com dez zooms de foto e cinco botões que saltavam removidos (MANUAL §6). - A ficha com o componente rodando — palco com largura de tela e tema
trocáveis, código com realce e cópia exata (
bin/realce.py). - Dois termos no vocabulário editorial (
publicacao-datada,canais-contato) e uma tag de vitrine (Artigos e agenda).
Fila autoral
Padrões mapeados e ainda não construídos. Entram quando um site real pedir — categoria não é cota.
| Padrão | Categoria | O que é | Situação |
|---|---|---|---|
| Faixa de anúncio no topo | navegacao |
aviso de uma linha acima do menu, com prazo de validade (data-ate) e fechar |
travada em 2026-09-29: o menu fixo a cobre. Entra junto de uma variação do nav-fixa-vidro que leia --ann-h — decisão de arquitetura, não de componente |
| Mosaico que embaralha | midia |
grade de miniaturas trocando de célula (o grade-logos-miolo faz com logos) |
previsto |
| Mapa SVG desenhado | dados |
idem | previsto |