Ir ao conteúdo
SEED engenhariaDesign System

Componentes

93. MATERIAL — vidro e metal

seed-componentes.md v1.48 · §93seção 99 de 9993-material-vidro-e-metal-emitido-em-gate-f10-4.md · MD5 62a78247

Título completo no canon: MATERIAL — vidro e metal · emitido · em gate (F10.4) (2026-09-12, F10.2) · MA1–MA12 · tokens seed-tokens.md §3d (v1.24 · v1.25) · módulo 06-validacao/ferramentas/material_bloco.py · régua 06-validacao/contraste/contraste-raster.mjs (contrato RC) · guarda guarda-material.py no rito de fechamento · aplicado em tela-shell.html v0.9 e tela-painel.html v0.16

Para quem lê sem ter visto a conversa. Em 2026-09-12 o decisor do design system, Rafael Sant'Ana, escreveu que as telas feitas com o DS estavam "muito básicas, botões, barras, menus etc. ta faltando alguma coisa" e pediu pesquisa sobre "liquid Glass metalizado em DS de grandes empresas" com dois exemplos lado a lado. A pesquisa (13 fontes datadas, em 09-pesquisa/material-vidro-metal-2026-09-12/pesquisa.md) e o par renderizado foram ao gate no mesmo dia; o veredito dele, verbatim, está no MANIFESTO §204.4: V-1 = B (adotar a proposta inteira), V-2 opacidade do vidro 80 % no claro · 72 % no escuro · desfoque 18 px · movimento ligado, V-3 "fundo com luz · barra superior em vidro · rail em metal escovado · cartões em vidro · botões primários em metal · números KPI com brilho · barras e pílulas com luz · micro-movimento"a sidebar não foi marcada e fica opaca (MA-P4, exposta a veto). Os valores viraram tokens na F10.1 (seed-tokens.md §3d), a régua que mede texto sobre vidro nasceu na F10.3 (o instrumento anterior lia o fundo por CSS, e vidro não é uma cor), e esta seção é a regra (F10.2): onde a camada vai, onde não vai, como se emite e como se mede. A F10.4 aplicou a regra nas duas primeiras telas no mesmo dia; o gate visual dele decide se ela vira estável.

Vocabulário desta seção (para quem chega por uma fatia): material = o acabamento da superfície (translucidez, desfoque, luz de borda, reflexo), sem mudar cor, tipografia nem logo · vidro = superfície translúcida que desfoca e satura o que está atrás (backdrop-filter) · metal = superfície opaca com reflexos de luz em gradiente por cima da cor do token · casca = o contêiner da aplicação (o .app do shell; numa tela-documento, a página) · canvas = o fundo sobre o qual as peças assentam (CP1 do seed-composicao.md) · pior pixel = a menor razão de contraste entre a tinta do texto e qualquer pixel de fundo atrás de um glifo (régua RC, F10.3) · piso = 4,5 para texto normal e 3,0 para texto grande (WCAG 2.2 SC 1.4.3, nível AA).

93.1 Natureza e fronteira#

Material é camada transversal de acabamento, não componente e não pattern: ela veste peças que os §1–§92 já especificam, sem criar nenhuma. Vale para toda tela que declare data-material="vidro-metal" no <html> — sem o atributo, nada muda um pixel (o interruptor é o que permite a mesma tela existir "como hoje" e "com material" sem duas árvores). Mesma marca: cor, tipografia e logo continuam os do DS; a camada só mexe em material, profundidade (sombras em camadas, fundo com luz) e movimento (dois micro-movimentos, desligáveis). Aposta da casa, não prática de mercado — a pesquisa leu oito sistemas corporativos e nenhum usa metal em controles; ele decidiu sabendo disso (§204.5).

93.2 Decisões MA1–MA12#

# Decisão Porquê / número medido Descartado
MA1 Vidro na camada de NAVEGAÇÃO e nas peças que FLUTUAM sobre o canvas: barra superior (§46 SH10), cartões do painel (§48 PN2/PN21a), cúpulas e pílulas de estado ("com luz": tinta do estado na opacidade do vidro + linha especular, sem desfoque). Receita única no módulo (vidro, vidro_cartao, pilula) Apple (HIG 2025) e Fluent (Acrylic): vidro é da navegação e do que flutua, nunca do conteúdo. A régua RC mediu a primeira aplicação: sobre vidro e luz, no claro, nenhum texto cai abaixo do piso (painel 298/298) vidro em tudo (o conteúdo branco anulava o efeito e vidro dentro de vidro reduz legibilidade — visionOS, Fluent) · pílula com backdrop-filter dentro de cartão de vidro (vidro dentro de vidro)
MA2 Metal no chrome e na ação primária: rail (§46 SH15, sobre --seed-rail-background), botão primário (§1, action-primary), avatar da barra. Regra de contraste do metal: o gradiente só vai do token para o lado ESCURO onde há texto CP20 (a tinta passa nos dois extremos, nunca na média): branco sobre action-primary já mede 4,60 no claro, o piso — clarear qualquer extremo reprovaria. Medido: o metal melhora o botão (4,60 → 4,91) e o rail fica em 4,73 no pior rótulo ("Compras", sob a faixa especular) com --seed-mat-metal em 1 metal que clareia o token (reprova por construção) · metal em superfície de dado (CP20 P1: gradiente jamais em dado)
MA3 O que FICA OPACO: a sidebar (V-3 dele não a marcou — MA-P4, exposta a veto), conteúdo denso (tabela §40, lista longa §92, a lente do painel com edição direta, texto corrido, formulário), diálogos e menus, e tudo que rola dentro de si Fluent proíbe acrílico em superfície grande e em painel vertical opaco; a leitura densa é onde a legibilidade paga primeiro (Apple recuou três vezes em um ano por isso). [inferência, a conferir na fonte]: backdrop-filter estabelece bloco de contenção para descendentes position: fixed, e a lente do painel abriga o menu de contexto fixo — mais um motivo para ela ficar fora vidro no conteúdo (o .conteudo do shell, a lente #lente-os do painel)
MA4 Fundo com luz SÓ na casca, uma por tela: --seed-mat-canvas pintado por dois pseudo-elementos da casca (um fixo, um que respira); a casca mantém surface-subtle como cor declarada — o canvas do CP1 continua lá O CP1 (canvas = surface-subtle) não é supersedido: a cor do canvas segue declarada e é o que as réguas por cor declarada leem (medido: casca transparente fazia o render-contraste.mjs medir texto contra o body, 1,79 falso); a luz é pintura por cima, e quem a mede é a régua RC no pixel. Luz na família da marca, derivada da rampa turquesa por color-mix — nenhum hex novo (§14.1) canvas dentro de peça · luz por gradiente de COR (CP20 proíbe fora do chrome; aqui é LUZ em alfa baixo, a classe do véu do PN21b) · casca transparente
MA5 Micro-movimento com função e desligável: (a) o reflexo do cartão e do hero desliza no sobrevoo (--seed-mat-sheen-duration, 700 ms); (b) o fundo respira (--seed-mat-breath-duration, 18 s, translação e escala de uma cópia do canvas a 35 % de opacidade); prefers-reduced-motion zera as duas durações no token e a cópia móvel some V-2 dele: movimento ligado. Movimento consome token (PN21h); os dois estados de sistema são respeitados pelo próprio gêmeo. A régua RC mede o estado de repouso com as animações congeladas — declarado no cabeçalho dela duração literal · movimento que não para com a preferência do sistema · movimento em dado
MA6 Fallbacks EXECUTÁVEIS no token — o consumidor consome só os derivados (--seed-mat-glass, --seed-mat-glass-filter, sombras, bordas), nunca escreve backdrop-filter: blur(18px) à mão Sem backdrop-filter ou com reduzir transparência o vidro vira sólido; mais contraste tira luz, grão e véu e põe borda forte; reduzir movimento zera as durações — tudo no gêmeo (§3d). Quem escreve o valor à mão perde os quatro. O módulo extrai os blocos condicionais do gêmeo e os embute no preview media query por consumidor (um esquece)
MA7 Régua obrigatória: toda tela com data-material passa na guarda RC (guarda-material.py, rito de fechamento) nos dois temas — veredito pelo PIOR PIXEL atrás de cada glifo HV1-c (§71): "quem cria um fundo novo cria a obrigação de medir o contraste sobre ele"; vidro é o fundo novo por definição. A guarda diz a cobertura ("2 de 2 telas medidas") — placar sem denominador não é placar aprovar por cor declarada (o instrumento que existia dizia "não medi" sobre vidro — MA-P1)
MA8 A camada é EMITIDA pelo módulo único material_bloco.py — receita por peça, nomeada; o gerador de cada tela passa só os seletores. Receita nova nasce no módulo; nunca CSS copiado no molde Regra da casa (uma implementação por peça): o estudo tinha a camada num CSS de 20 kB com literais; copiá-lo em dois moldes seria duas verdades. O módulo mede os --seed-mat-* no gêmeo (nunca lista à mão), extrai os fallbacks e aborta se o bloco do preview não emitir um token que a camada referencie (NV-01 mecanizado) CSS de material no molde · lista de tokens digitada
MA9 Dentro de cartão de vidro, a tinta de marca é a -strong: o escopo do cartão remapeia --seed-text-brand e --seed-text-link para --seed-text-brand-strong seed-tokens.md §5-g: text-brand mede 4,60 só contra o BRANCO PURO — o vidro nunca é branco puro. Medido pela régua RC no painel (2026-09-12): nove textos em text-brand sobre cartão de vidro em 4,42–4,49 (títulos-insight em itálico e os links "abrir →"); com o remapeamento, 298/298 no claro. text-link tem o mesmo valor de text-brand nos dois temas (gêmeo v1.24); no escuro os dois -strong já são iguais reescrever cada consumidor (o remapeamento por escopo é o precedente do [data-tinta="familia"] do §48) · afrouxar o piso
MA10 Nenhuma textura de período fixo em pixel: a textura do metal é grão aleatório (--seed-mat-grain, feTurbulence a 5 %) e reflexo contínuo O "escovado" de 1 px a cada 2 px do estudo virou moiré quando ele viu a folha a 39 % de escala (MA-P5, §204.6) — textura de período fixo não sobrevive a escala; grão aleatório e reflexo contínuo sobrevivem. Vale para tudo que será visto em miniatura (folha de gate, thumbnail, celular) traço repetido (repeating-linear-gradient de 1 px)
MA11 Calibração do metal por peça, com a régua na mesa: o único botão é --seed-mat-metal; calibrar no escopo de uma peça exige reemitir no escopo os tokens que multiplicam pelo botão (material_bloco.calibracao_metal(), texto lido do gêmeo); todo valor calibrado entra na tabela do §93.5 com o número medido Errata da v1.24 dos tokens (v1.25, §3d): o var() dentro do valor de uma custom property é resolvido onde ela é declarada (o :root), não onde é consumida — a régua devolveu os mesmos números em 1, 0,7 e 0,4 até o conserto. Medido no rail: 1 → 4,73 · 0,7 → 5,38 · 0,4 → 5,86 no pior rótulo sobrescrever só o botão no escopo (não faz nada) · declarar os tokens em * (sairia da paridade G2) · o 20 % do controle do gate (era reação ao moiré)
MA12 Alcance declarado: vidro fora do chrome e dos cartões do painel espera a medição de GPU em máquina de campo (MA-P2); telas sem gerador não recebem a camada antes de ganhar gerador (MA-P3, regra §14.4); e-mail e impresso: proibido — nenhum cliente de e-mail da casa suporta backdrop-filter [convenção nossa; a matriz de clientes do seed-email.md é a fonte] e sombra e gradiente não sobrevivem à impressão (CP20, DI §4c) Microsoft: acrílico é GPU-intensivo e desliga em economia de bateria; medir antes de espalhar é a regra "declarar um limite não é medi-lo" vidro em lista longa sem medir · material em e-mail

93.3 Receitas — o que cada peça consome (a fonte é o módulo; isto é a leitura humana)#

peça (chave no módulo) seletores hoje tokens consumidos
casca (casca) .app (shell) · .painel (painel) fundo declarado --seed-surface-subtle; pseudo-elementos com --seed-mat-canvas; respiração com --seed-mat-breath-duration; a casca é contexto de empilhamento (isolation: isolate) para a luz ficar acima do fundo e abaixo do conteúdo
vidro (vidro) .topbar --seed-mat-grain (ladrilho de 160 px, o tamanho do SVG) sobre --seed-mat-glass; backdrop-filter: var(--seed-mat-glass-filter); anel --seed-mat-glass-border + --seed-mat-glass-shadow
cartão de vidro (vidro_cartao) section.bloco:not(#lente-os) o mesmo, mais --seed-mat-metal-specular como camada que desliza (largura 220 %, posição 100 % → 0 no sobrevoo), --seed-mat-glass-shadow-hover, e o remapeamento MA9
metal do rail (metal_rail) .rail --seed-mat-grain, --seed-mat-metal-specular, --seed-mat-metal-sheen, --seed-mat-metal-curve sobre --seed-rail-background; arestas --seed-mat-metal-edge
metal da ação (metal_acao) .btn-prox, .btn-solucao (painel) · .avatar (shell) a cor continua o token de ação; background-image: var(--seed-mat-metal-action); --seed-mat-metal-action-edge; pressionado afunda (translateY(1px) scale(.985), HV1-b)
KPI com brilho (kpi) .kpi .valor tinta em gradiente text-primarytext-secondary (background-clip: text); em mais contraste volta a tinta lisa
pílula com luz (pilula) .pilula.pos (feedback-success-bg) · .pilula.neg (feedback-danger-bg) a cor do estado em --seed-mat-glass-alpha; linha --seed-mat-glass-specular; sem desfoque
trilho (trilho) · preenchimento (trilho_cheio) .prog-trilho, .brs .trilho, .trilho-r, .stack · os i de cada um anel --seed-mat-glass-border por dentro do sulco · linha --seed-mat-glass-specular no preenchimento
reflexo (reflexo) .hero só o reflexo deslizante (--seed-mat-metal-specular), em pseudo-elemento abaixo do texto (isolation: isolate)

Constantes estruturais do módulo (não são valor de marca, e cada uma carrega o motivo no código): ladrilho do grão = 160 px (o tamanho do próprio SVG), largura do reflexo = 220 % (para poder deslizar), opacidade da cópia móvel do fundo = 0,35 (baixa o bastante para não dobrar a luz; a régua mede com ela parada).

93.4 O que a régua mediu na primeira aplicação (2026-09-12, viewport 1440 px, dois temas)#

tela tema textos medidos pior pixel onde estado
tela-shell.html v0.9 claro 71 4,52 link "Comercial" da trilha (text-link sobre o conteúdo opaco, pré-existente) PASS
tela-shell.html v0.9 escuro 71 4,60 botão "1180" da barra de provas (instrumento, não a tela) PASS
tela-painel.html v0.16 claro 298 4,60 botão "Família (proposta)" da barra de provas PASS
tela-painel.html v0.16 escuro 299 4,58 micro-rótulo "Geração do mês" (text-secondary) do primeiro KPI, sob vidro no ponto mais quente da luz PASS

O caminho até esse placar mudou quatro coisas, todas registradas onde moram: (1) MA-P6 — o rótulo ativo do rail vazava 1 px da pílula (errata E-CF-06 no §46; conserto no gerador); (2) a tinta de marca no vidro media 4,42–4,49 → MA9; (3) a luz do canvas escuro derrubava o micro-rótulo do KPI a 4,41 → tokens v1.25 (a luz cai de 40 %/26 % para 26 %/18 %; o alfa do vidro, dele, não mudou); (4) a calibração por escopo não fazia nada → MA11 e a errata da v1.24. O que a régua NÃO mede está no cabeçalho dela: texto coberto por outro elemento, texto não pintado, componente inativo, estados fora do repouso.

93.5 Calibrações registradas#

peça --seed-mat-metal pior rótulo medido (régua RC) estado
rail do shell 1 (o token) "Compras" 4,73 (piso 4,5) aplicado; 0,7 (→ 5,38) e 0,4 (→ 5,86) renderizados lado a lado na folha do gate F10.4, decisão dele

93.6 Fronteiras e pendências#

MA-P2 (GPU do vidro em lista longa, máquina de campo) · MA-P3 (sete telas sem gerador esperam o gerador — F10.5) · MA-P4 (a sidebar, opaca até uma palavra dele) · SH-P9 (peso 800 sem face, §46) · a composição shell + painel é do produto (o ERP compõe: uma casca, um canvas; o conteúdo do shell fica transparente onde os cartões são vidro — supersede candidato do CP-P5 só para telas com material, a decidir no gate) · a suite-composicao.mjs exige canvas = surface-subtle em CAL-01 e continua verdadeira (MA4 mantém a cor declarada) · vitrine, registry e skill herdam a camada por geração na F10.6.

93.7 Os 8 testes#

  1. Interruptor: sem data-material no <html>, a tela é byte a byte a de antes na parte que não é token.
  2. Nenhum literal de marca na receita — só var(--seed-*); as constantes estruturais estão nomeadas no módulo.
  3. Pior pixel ≥ piso em toda tela com material, nos dois temas (guarda RC no rito, com cobertura impressa).
  4. Os quatro estados de sistema (sem backdrop-filter, reduzir transparência, mais contraste, reduzir movimento) resolvem no token, e a casca volta ao canvas do CP1 em mais contraste.
  5. Cor declarada da casca = surface-subtle — as réguas por cor declarada (render-contraste, contraste-composicao, CAL-01) continuam medindo o que sempre mediram.
  6. Sem vidro dentro de vidro; sem vidro em conteúdo denso; sidebar opaca (MA1, MA3).
  7. Tinta de marca no vidro é -strong (MA9) — a régua RC é quem confirma.
  8. Regeneração byte-idêntica das telas (duas gerações, mesmo MD5) e as suítes próprias verdes: suite-shell 72 · 0, render-shell 34 · 0, suite-painel 146 · 0, render-painel 37 · 0, render-edicao 142 · 0, render-contraste 6 · 0, guarda-colisao 4 · 0 (com a cláusula nova: fundo recortado por texto não é fronteira), guarda-valor-gemeo 2 · 0, guarda-forced-colors 4 · 0, TP1 2 · 0.

(Estado: emitido · em gate (F10.4) desde 2026-09-12. Vira estável com o veredito dele sobre a folha do gate F10.4 — shell e painel nos dois temas, a calibração do rail e a sidebar. As decisões MA1–MA12 nasceram da pesquisa, do veredito V-1..V-3 e das medições da primeira aplicação; o que ele vetar volta ao gerador, nunca ao HTML.)

Esc