Pular para o conteúdo

Design system — Hub Central

PH SILVA · lido de globals.css

A lei visual do Hub Central

Esta página é o design system e nada além dele. Os valores não estão escritos aqui: são lidos de src/app/globals.css em tempo de build, pelo mesmo módulo que alimenta o npm run verifica:contraste. O documento normativo é harness/Referência/06 - Design System.md; conflito entre os dois é defeito a relatar, não escolha a fazer.

Fundamento

Uma frase decide toda dúvida deste sistema: isso reduz ou aumenta a carga de função executiva? Não é metáfora. Hierarquia fraca, densidade alta e ruído visual custam atenção que o usuário deste sistema não tem sobrando — por isso contraste, foco e teclado aparecem como requisito de componente, e não como capítulo de polimento no fim.

O calendário responde quando. O Hub responde o quê.

Amostra da voz e da tipografia juntas: segunda pessoa, verbo na frente, sem emoji e sem exclamação. O sistema é uma ferramenta pessoal, não um app que precisa agradar.

Switzer400 · 500 · 60043 KB, todos os pesos

Nunca uma folha em branco

Toda tela de trabalho abre com uma resposta já dada. Escolher o que fazer é o trabalho mais caro do dia.

Nunca preso ao palpite

A decisão automática é mostrada como decisão e desfeita em um clique, sem abrir painel.

Uma pergunta por vez

Divulgação progressiva vence formulário completo. Capturar mostra um campo; processar mostra um item.

O teste de saída

Alguém fluente em Linear, Notion ou Raycast senta nesta interface e confia nela de primeira, ou hesita a cada componente? A régua é familiaridade conquistada: a ferramenta deve sumir dentro da tarefa.

Cor

Estratégia contida: neutros levemente azulados e um único acento, tudo derivado do azul da marca PH SILVA. A cor pertence ao ALERTA — a área de vida está escrita na tela, e continua colorida apenas no evento publicado no Google, onde a cor é a única legenda possível (AD-030).

Evidência

Todo par abaixo é calculado, não estimado: OKLCH → sRGB → luminância relativa → razão WCAG. O mesmo módulo alimenta esta página e o npm run verifica:contraste, que trava o commit quando um par reprova.

774 pares verificados nos dois temas — 515 de token contra token e 259 de superfície composta, aquela que só existe na tela quando um token semitransparente pousa sobre outro.

34 pares compostos estão abaixo do piso e aguardam decisão do Líder. Não travam o commit porque a correção mora no componente, não no token. Rode npm run verifica:contraste para ver cada um com a correção proposta.

Superfícies

Três papéis: conteúdo (background, card), estrutura (sidebar) e apoio (muted, accent, secondary). No tema escuro o card é MAIS CLARO que a página — por isso ele, e não o fundo, é o pior caso nos cálculos.

Tema claro

--background

#ffffff · L 1

--card

#ffffff · L 1

--sidebar

#f6f7fa · L 0.977

--muted

#f2f4f8 · L 0.968

--accent

#ebf0f8 · L 0.955

--secondary

#f2f4f8 · L 0.968

--popover

#ffffff · L 1

Tema escuro

--background

#10141a · L 0.19

--card

#191d25 · L 0.23

--sidebar

#0b0e14 · L 0.165

--muted

#242932 · L 0.28

--accent

#29313d · L 0.31

--secondary

#242932 · L 0.28

--popover

#191d25 · L 0.23

Marca e controles

O azul da marca PH SILVA é o único acento, reservado a ação primária, seleção e estado corrente. --border é divisória decorativa e não tem piso; --input é o contorno que IDENTIFICA um controle e por isso precisa de 3:1.

Tema claro

--primary

#165abd · L 0.487

--destructive

#c13c3b · L 0.55

--input

#828995 · L 0.628

--ring

#165abd · L 0.487

--border

#e1e4e8 · L 0.918

Tema escuro

--primary

#5a97f6 · L 0.68

--destructive

#f2716a · L 0.7

--input

#727a85 · L 0.576

--ring

#5a97f6 · L 0.68

--border

pode ter alfa — sem piso

Alertas

Oito estados do RN-04.3, dois tokens cada. A TINTA é sempre texto e ícone; o SUAVE é sempre preenchimento. Inverter os papéis produz um bloco saturado e é defeito de revisão.

Tema claro

Atrasado#c03b3a · pior 4.60:1
Vence hoje#b44c0d · pior 4.61:1
Vence amanhã#9a6100 · pior 4.61:1
Vence esta semana#7c6f1c · pior 4.61:1
Semana que vem#14769a · pior 4.61:1
A qualquer momento#666b73 · pior 4.86:1
Defina essa ação#746097 · pior 4.88:1
Concluído#187c49 · pior 4.68:1

Tema escuro

Atrasado#f2716a · pior 4.87:1
Vence hoje#f68f5f · pior 5.95:1
Vence amanhã#ebb25f · pior 7.24:1
Vence esta semana#cdc072 · pior 7.59:1
Semana que vem#5bb0d7 · pior 5.77:1
A qualquer momento#a0a5ae · pior 5.79:1
Defina essa ação#ad99d2 · pior 5.43:1
Concluído#59b47d · pior 5.45:1

Energia

Rampa de cinco degraus dentro do matiz da marca. Piso de 3:1 porque é elemento gráfico, não texto — a informação está na contagem de barras, e a cor só reforça.

Tema claro

1

3.48:1passa, piso 3

2

4.37:1passa, piso 3

3

5.57:1passa, piso 3

4

7.19:1passa, piso 3

5

9.35:1passa, piso 3

Tema escuro

1

3.92:1passa, piso 3

2

4.89:1passa, piso 3

3

6.06:1passa, piso 3

4

7.40:1passa, piso 3

5

8.94:1passa, piso 3

Distinguibilidade dos selos

Contraste diz se dá para LER o selo; distância diz se dá para DIFERENCIAR um do outro. A régua é o par hoje × amanhã, que já convivia na paleta sem objeção (AD-030).

Tema claro · régua 0.1410

  • atrasado × hoje0.0858
  • amanha × semana0.1324
  • hoje × amanha0.1410
  • livre × nao-processado0.1482

Tema escuro · régua 0.1944

  • atrasado × hoje0.1197
  • hoje × amanha0.1944
  • amanha × semana0.2412
  • livre × nao-processado0.2429

Matriz dos pares de token

Token contra token, um a um. Os pares de superfície composta ficam de fora porque o eixo desta tabela é token × token, e um fundo composto não é um token — eles saem inteiros no npm run verifica:contraste. Fica recolhida porque é referência de conferência, não leitura corrida: divulgação progressiva vale também para a documentação.

Ver a matriz dos 515 pares de token

Tema claro

Texto sobre superfície · piso 4,5:1

Texto sobre superfície · piso 4,5:1 — razão de contraste de cada par
tokenbackgroundcardsidebarmutedaccentsecondarypopover
foreground17.31:1passa, piso 4.517.31:1passa, piso 4.516.20:1passa, piso 4.515.78:1passa, piso 4.515.19:1passa, piso 4.515.78:1passa, piso 4.517.31:1passa, piso 4.5
foreground-secundario9.21:1passa, piso 4.59.21:1passa, piso 4.58.62:1passa, piso 4.58.39:1passa, piso 4.58.08:1passa, piso 4.58.39:1passa, piso 4.59.21:1passa, piso 4.5
muted-foreground5.28:1passa, piso 4.55.28:1passa, piso 4.54.94:1passa, piso 4.54.81:1passa, piso 4.54.63:1passa, piso 4.54.81:1passa, piso 4.55.28:1passa, piso 4.5
primary6.50:1passa, piso 4.56.50:1passa, piso 4.56.09:1passa, piso 4.55.93:1passa, piso 4.55.71:1passa, piso 4.55.93:1passa, piso 4.56.50:1passa, piso 4.5
destructive5.29:1passa, piso 4.55.29:1passa, piso 4.54.95:1passa, piso 4.54.82:1passa, piso 4.54.64:1passa, piso 4.54.82:1passa, piso 4.55.29:1passa, piso 4.5
positivo5.66:1passa, piso 4.55.66:1passa, piso 4.55.29:1passa, piso 4.55.16:1passa, piso 4.54.96:1passa, piso 4.55.16:1passa, piso 4.55.66:1passa, piso 4.5
atencao6.15:1passa, piso 4.56.15:1passa, piso 4.55.75:1passa, piso 4.55.61:1passa, piso 4.55.39:1passa, piso 4.55.61:1passa, piso 4.56.15:1passa, piso 4.5
negativo6.05:1passa, piso 4.56.05:1passa, piso 4.55.66:1passa, piso 4.55.51:1passa, piso 4.55.31:1passa, piso 4.55.51:1passa, piso 4.56.05:1passa, piso 4.5
accent-foreground12.70:1passa, piso 4.512.70:1passa, piso 4.511.88:1passa, piso 4.511.57:1passa, piso 4.511.14:1passa, piso 4.511.57:1passa, piso 4.512.70:1passa, piso 4.5
secondary-foreground14.59:1passa, piso 4.514.59:1passa, piso 4.513.66:1passa, piso 4.513.30:1passa, piso 4.512.80:1passa, piso 4.513.30:1passa, piso 4.514.59:1passa, piso 4.5
sidebar-foreground17.31:1passa, piso 4.517.31:1passa, piso 4.516.20:1passa, piso 4.515.78:1passa, piso 4.515.19:1passa, piso 4.515.78:1passa, piso 4.517.31:1passa, piso 4.5
sidebar-accent-foreground14.60:1passa, piso 4.514.60:1passa, piso 4.513.66:1passa, piso 4.513.31:1passa, piso 4.512.81:1passa, piso 4.513.31:1passa, piso 4.514.60:1passa, piso 4.5
card-foreground17.31:1passa, piso 4.517.31:1passa, piso 4.516.20:1passa, piso 4.515.78:1passa, piso 4.515.19:1passa, piso 4.515.78:1passa, piso 4.517.31:1passa, piso 4.5
popover-foreground17.31:1passa, piso 4.517.31:1passa, piso 4.516.20:1passa, piso 4.515.78:1passa, piso 4.515.19:1passa, piso 4.515.78:1passa, piso 4.517.31:1passa, piso 4.5

Tinta de selo · piso 4,5:1

Tinta de selo · piso 4,5:1 — razão de contraste de cada par
tokenbackgroundcardsidebaro próprio suave
alerta-atrasado5.36:1passa, piso 4.55.36:1passa, piso 4.55.01:1passa, piso 4.54.60:1passa, piso 4.5
alerta-hoje5.27:1passa, piso 4.55.27:1passa, piso 4.54.94:1passa, piso 4.54.61:1passa, piso 4.5
alerta-amanha5.12:1passa, piso 4.55.12:1passa, piso 4.54.79:1passa, piso 4.54.61:1passa, piso 4.5
alerta-semana5.09:1passa, piso 4.55.09:1passa, piso 4.54.77:1passa, piso 4.54.61:1passa, piso 4.5
alerta-proxima-semana5.15:1passa, piso 4.55.15:1passa, piso 4.54.82:1passa, piso 4.54.61:1passa, piso 4.5
alerta-livre5.37:1passa, piso 4.55.37:1passa, piso 4.55.02:1passa, piso 4.54.86:1passa, piso 4.5
alerta-nao-processado5.46:1passa, piso 4.55.46:1passa, piso 4.55.11:1passa, piso 4.54.88:1passa, piso 4.5
alerta-concluido5.20:1passa, piso 4.55.20:1passa, piso 4.54.86:1passa, piso 4.54.68:1passa, piso 4.5

Energia e controles · piso 3:1

Energia e controles · piso 3:1 — razão de contraste de cada par
tokenbackgroundcardsidebar
energia-13.48:1passa, piso 33.48:1passa, piso 33.26:1passa, piso 3
energia-24.37:1passa, piso 34.37:1passa, piso 34.09:1passa, piso 3
energia-35.57:1passa, piso 35.57:1passa, piso 35.22:1passa, piso 3
energia-47.19:1passa, piso 37.19:1passa, piso 36.73:1passa, piso 3
energia-59.35:1passa, piso 39.35:1passa, piso 38.75:1passa, piso 3
input3.53:1passa, piso 33.53:1passa, piso 33.30:1passa, piso 3
ring6.50:1passa, piso 36.50:1passa, piso 36.09:1passa, piso 3
sidebar-ring6.50:1passa, piso 36.50:1passa, piso 36.09:1passa, piso 3

Tema escuro

Texto sobre superfície · piso 4,5:1

Texto sobre superfície · piso 4,5:1 — razão de contraste de cada par
tokenbackgroundcardsidebarmutedaccentsecondarypopover
foreground15.96:1passa, piso 4.514.60:1passa, piso 4.516.65:1passa, piso 4.512.61:1passa, piso 4.511.37:1passa, piso 4.512.61:1passa, piso 4.514.60:1passa, piso 4.5
foreground-secundario10.58:1passa, piso 4.59.68:1passa, piso 4.511.04:1passa, piso 4.58.36:1passa, piso 4.57.54:1passa, piso 4.58.36:1passa, piso 4.59.68:1passa, piso 4.5
muted-foreground6.91:1passa, piso 4.56.32:1passa, piso 4.57.21:1passa, piso 4.55.46:1passa, piso 4.54.93:1passa, piso 4.55.46:1passa, piso 4.56.32:1passa, piso 4.5
primary6.35:1passa, piso 4.55.80:1passa, piso 4.56.62:1passa, piso 4.55.01:1passa, piso 4.54.52:1passa, piso 4.55.01:1passa, piso 4.55.80:1passa, piso 4.5
destructive6.44:1passa, piso 4.55.89:1passa, piso 4.56.72:1passa, piso 4.55.09:1passa, piso 4.54.59:1passa, piso 4.55.09:1passa, piso 4.55.89:1passa, piso 4.5
positivo8.45:1passa, piso 4.57.73:1passa, piso 4.58.82:1passa, piso 4.56.68:1passa, piso 4.56.02:1passa, piso 4.56.68:1passa, piso 4.57.73:1passa, piso 4.5
atencao10.50:1passa, piso 4.59.61:1passa, piso 4.510.96:1passa, piso 4.58.30:1passa, piso 4.57.49:1passa, piso 4.58.30:1passa, piso 4.59.61:1passa, piso 4.5
negativo6.94:1passa, piso 4.56.35:1passa, piso 4.57.25:1passa, piso 4.55.49:1passa, piso 4.54.95:1passa, piso 4.55.49:1passa, piso 4.56.35:1passa, piso 4.5
accent-foreground15.96:1passa, piso 4.514.60:1passa, piso 4.516.65:1passa, piso 4.512.61:1passa, piso 4.511.37:1passa, piso 4.512.61:1passa, piso 4.514.60:1passa, piso 4.5
secondary-foreground15.96:1passa, piso 4.514.60:1passa, piso 4.516.65:1passa, piso 4.512.61:1passa, piso 4.511.37:1passa, piso 4.512.61:1passa, piso 4.514.60:1passa, piso 4.5
sidebar-foreground15.96:1passa, piso 4.514.60:1passa, piso 4.516.65:1passa, piso 4.512.61:1passa, piso 4.511.37:1passa, piso 4.512.61:1passa, piso 4.514.60:1passa, piso 4.5
sidebar-accent-foreground15.96:1passa, piso 4.514.60:1passa, piso 4.516.65:1passa, piso 4.512.61:1passa, piso 4.511.37:1passa, piso 4.512.61:1passa, piso 4.514.60:1passa, piso 4.5
card-foreground15.96:1passa, piso 4.514.60:1passa, piso 4.516.65:1passa, piso 4.512.61:1passa, piso 4.511.37:1passa, piso 4.512.61:1passa, piso 4.514.60:1passa, piso 4.5
popover-foreground15.96:1passa, piso 4.514.60:1passa, piso 4.516.65:1passa, piso 4.512.61:1passa, piso 4.511.37:1passa, piso 4.512.61:1passa, piso 4.514.60:1passa, piso 4.5

Tinta de selo · piso 4,5:1

Tinta de selo · piso 4,5:1 — razão de contraste de cada par
tokenbackgroundcardsidebaro próprio suave
alerta-atrasado6.44:1passa, piso 4.55.89:1passa, piso 4.56.72:1passa, piso 4.54.87:1passa, piso 4.5
alerta-hoje7.92:1passa, piso 4.57.24:1passa, piso 4.58.26:1passa, piso 4.55.95:1passa, piso 4.5
alerta-amanha9.74:1passa, piso 4.58.91:1passa, piso 4.510.16:1passa, piso 4.57.24:1passa, piso 4.5
alerta-semana9.96:1passa, piso 4.59.11:1passa, piso 4.510.39:1passa, piso 4.57.59:1passa, piso 4.5
alerta-proxima-semana7.61:1passa, piso 4.56.96:1passa, piso 4.57.94:1passa, piso 4.55.77:1passa, piso 4.5
alerta-livre7.45:1passa, piso 4.56.81:1passa, piso 4.57.77:1passa, piso 4.55.79:1passa, piso 4.5
alerta-nao-processado7.25:1passa, piso 4.56.63:1passa, piso 4.57.56:1passa, piso 4.55.43:1passa, piso 4.5
alerta-concluido7.28:1passa, piso 4.56.66:1passa, piso 4.57.60:1passa, piso 4.55.45:1passa, piso 4.5

Energia e controles · piso 3:1

Energia e controles · piso 3:1 — razão de contraste de cada par
tokenbackgroundcardsidebar
energia-14.28:1passa, piso 33.92:1passa, piso 34.47:1passa, piso 3
energia-25.35:1passa, piso 34.89:1passa, piso 35.58:1passa, piso 3
energia-36.63:1passa, piso 36.06:1passa, piso 36.92:1passa, piso 3
energia-48.09:1passa, piso 37.40:1passa, piso 38.44:1passa, piso 3
energia-59.77:1passa, piso 38.94:1passa, piso 310.19:1passa, piso 3
input4.24:1passa, piso 33.88:1passa, piso 34.43:1passa, piso 3
ring6.35:1passa, piso 35.80:1passa, piso 36.62:1passa, piso 3
sidebar-ring6.35:1passa, piso 35.80:1passa, piso 36.62:1passa, piso 3

Tipografia

Switzer variável, uma família só. UI de produto não precisa de par display/corpo: contraste tipográfico exagerado vira ruído quando a tela tem muitos elementos de texto.

Escala — fixa em rem, nunca fluida

clamp() não serve a UI de produto: o usuário trabalha em DPI consistente, e um título que encolhe dentro de uma coluna fica pior, não melhor. Razão entre degraus de 1,125 a 1,2. Acima de text-2xl, nada.

text-xs · 0,75remProcessar e organizarmetadados, selos, rótulos de apoio
text-sm · 0,875remProcessar e organizarcorpo padrão da UI
text-base · 1remProcessar e organizartítulo de card, item em foco
text-lg · 1,125remProcessar e organizartítulo do bloco corrente
text-xl · 1,25remProcessar e organizartítulo de página (celular)
text-2xl · 1,5remProcessar e organizartítulo de página · item único do processamento

Pesos

400 corpo · 500 títulos e ênfase · 600 título de página. 700 não é usado: font-medium faz aqui o trabalho que bold faria em outro produto.

400 — corpo do texto

500 — título e ênfase

600 — título de página

Números tabulares

Obrigatórios em horário, contador e duração, pelo atributo data-numerico. Sem isso a agenda dança quando 08:15 vira 09:00 — repare na coluna de baixo.

Com data-numerico

08:15 → 09:00
11:11 → 12:44

Sem o atributo

08:15 → 09:00
11:11 → 12:44

Medida

Prosa limitada a 65–75ch. Listas e dados podem correr mais densos; prosa, não.

O calendário responde quando e em qual área. O Hub responde o que exatamente fazer. Essa divisão é a tese do sistema, e é o que justifica publicar no Google em vez de reconstruir um calendário aqui dentro — o gatilho externo é andaime de função executiva, e andaime que ninguém vê não sustenta nada.

Espaço, forma e camada

Escala do Tailwind, base 4pt. Superfícies planas com elevação por anel de 1px; sombra reservada a sobreposição. O responsivo é estrutural, não tipográfico — o PWA é o mesmo código.

Ritmo

Hierarquia vem de espaço e peso antes de vir de tamanho. Espaçamento uniforme na página inteira é ausência de hierarquia — varie de propósito. Valor arbitrário como p-[13px] é defeito de revisão.

gap-1 → gap-2.5
dentro de uma linha: título e seus metadados
gap-3 / gap-4
entre irmãos: campos de um formulário, chips
space-y-8 / 10
entre seções de uma página
p-4 → p-5
interno de painel (celular → ≥ sm)

Raio

Uma escala derivada de --radius. Misturar raios sem motivo é o tipo de inconsistência que o usuário não sabe nomear, mas sente.

rounded-sm

rounded-md

rounded-lg

rounded-xl

rounded-2xl

Elevação

Superfície em repouso usa anel de 1px, como no Notion. Sombra é reservada a sobreposição — se tudo flutua, nada flutua.

Em repouso

Anel de 1px. É assim que card, painel e faixa se separam do fundo.

Sobreposto

Sombra só aqui: diálogo, popover, menu, dica.

Camadas

Escala semântica, nunca valor arbitrário. z-[999] e z-[9999] são defeito: significam que alguém perdeu a disputa e apelou.

z-20
cabeçalho de celular, barra inferior
z-50
fundo de diálogo, diálogo, popover, menu
acima
toast, gerido pelo Sonner

Densidade e alvo de toque

Mínimo de 44×44 no que é tocado com frequência, mesmo quando o desenho é menor. A moldura tracejada mostra o alvo real da caixa de concluir.

16px de desenho, 44px de alvo.

Movimento

Movimento comunica estado: mudança, feedback, carregamento, revelação. Nada além disso, e nenhuma coreografia no carregamento da página — o Hub abre dentro de uma tarefa.

Curvas e duração

150–250 ms na maioria das transições: o usuário está em fluxo e não quer assistir à coreografia. Saída em curva exponencial — sai rápido, assenta devagar. Sem bounce: o sistema não faz piada.

Com prefers-reduced-motion ligado no sistema operacional, esse movimento vira troca instantânea — a garantia está em globals.css e vale para toda a aplicação, inclusive para as animações que vêm da biblioteca de UI. Não é lembrete por componente.

Componentes base

shadcn/ui no estilo base-nova, sobre @base-ui/react. Não instale uma segunda biblioteca e não introduza um segundo conjunto de ícones — lucide-react é o conjunto do projeto.

Variantes

Uma forma de botão em todo o sistema. Se o botão de salvar tem aparência diferente em duas telas, uma das duas está errada.

Tamanhos

Estados

Os oito estados não são opcionais. O erro clássico é desenhar hover e esquecer foco — quem navega por teclado nunca vê hover. Tabule pelos botões abaixo para conferir o anel.

Campos

Rótulo visível sempre. Placeholder não é rótulo: some quando o campo é preenchido, e some justamente para quem mais precisaria dele.

Controles

Alvo de toque de 44px mesmo quando o desenho tem 16 — e aqui o alvo é o RÓTULO, não o desenho. A caixa de concluir tem 16px e o `after:` a leva a 40×32; quem fecha os 44 é o `<label>` em volta, como a LinhaItem faz com `size-11`. Esticar o `after:` até 44 faria as áreas de linhas vizinhas se sobreporem numa lista densa, que é justamente onde o gesto mais se repete.

Sobreposições

Diálogo é último recurso — esgote inline e divulgação progressiva antes. Todos portalizam, então nunca são cortados por um contêiner com overflow.

Componentes do domínio

Vivem em src/components/dominio/ e são o contrato entre design e implementação. Nenhum deles calcula: recebem valores já derivados no servidor. Se um dia precisarem de uma data para decidir um alerta, a regra vazou para o lugar errado.

Os oito estados

Matiz, ícone e palavra, sempre juntos. No tema claro as oito tintas vivem na mesma faixa de luminosidade por exigência de contraste — a cor sozinha não diz a urgência, e por isso ícone e palavra são obrigatórios, não enfeite.

AtrasadoVence hojeVence amanhãVence esta semanaSemana que vemA qualquer momentoDefina essa açãoConcluído

Prazo concreto

Quando existe um prazo real, ele substitui a palavra na tela — e o rótulo canônico continua indo para o leitor de tela. O dado extra soma, não troca.

há 3 dias — Atrasadohá 2 semanas — Atrasadoàs 18h — Vence hoje

Só ícone — último recurso

A palavra some da tela, nunca do leitor de tela. Se você precisou disto em mais de um lugar, o problema é a densidade da lista, não o selo.

AtrasadoVence hojeVence amanhãVence esta semanaSemana que vemA qualquer momentoDefina essa açãoConcluído

Medidor de energia

A informação está na contagem de barras. A altura cresce junto e a cor reforça — três canais para o mesmo dado, porque num dia ruim ninguém compara matizes.

1

2

3

4

5

A escala é uma só

O medidor não tem variante grande. Na linha de metadados ele é um metadado entre outros, e o teto da escada é a altura óptica dos ícones ao lado — o ícone ocupa caixa de 12px, mas o traço desenha uns 10, e é com a tinta que o olho compara. Um componente com dois tamanhos convida a escolher o errado.

ClientesComputadorMarina

Variantes numa lista

Deliberadamente não é card: a tela de execução mostra dezenas destas, e card sobre card come altura útil. A separação é uma hairline; o agrupamento vem do espaço. Marque uma caixa para ver o estado concluído.

  • Fechar o escopo do orçamento da reforma

    Proposta — Construtora ValeClientesComputador

    há 3 dias — Atrasado
  • Revisar o roteiro da gravação de quinta

    Blazar Co.Computadorconteúdo

    Vence hoje
  • Confirmar a escala do louvor

    MinistérioCelularMarina

    Vence amanhã
  • Ler o capítulo 4 de Sistemas Distribuídos

    FaculdadeCasa

    Vence esta semana
  • Reorganizar a estrutura de pastas do Drive inteiro, incluindo os arquivos antigos da faculdade que nunca foram migrados e continuam ocupando espaço

    Desenvolvimento PessoalComputador

    A qualquer momento
  • Pagar

    Celular

    Defina essa ação
  • Enviar o contrato assinado

    Clientes

    Concluído

Casos de borda de texto

O título corta em duas linhas. Só quem passa disso ganha o “ver mais”, no fim da segunda linha — quem cabe não mostra botão, reticência nem espaço reservado. Reduza a janela: o mesmo título que cabe no desktop transborda no celular, e o botão aparece sozinho.

  • Ok

    A qualquer momento
  • Revisar a proposta da Construtora Vale antes da reunião de terça

    Computador

    Vence esta semana
  • Levantar com a coordenação do curso se a disciplina optativa de arquitetura de software conta como carga horária complementar para a segunda graduação, e se conta, quantas horas ela integraliza no histórico

    Fechamento do semestreComputador

    Semana que vem
  • Item sem nenhum metadado

    Defina essa ação

Título navegável — o alvo estendido da §5.3

Quando a linha leva a algum lugar, o título é o elo, porque é o maior alvo que a linha tem. O texto tem 19px de altura e o dedo precisa de 44: quem fecha a conta é um pseudo-elemento transparente que estende a área tocável sem engordar o desenho. Ele mora no elo; quem corta em duas linhas é o span de dentro — as duas coisas no mesmo elemento fariam o recorte comer o alvo, em silêncio. Aponte 8px acima do texto: o cursor vira mão.

Contexto e área — lista de seleção (AD-061)

Eram fileiras de chips. O Líder decidiu que contexto é vocabulário do dono, sem ícone, apresentado como lista de seleção; área veio junto, porque dois controles da mesma natureza a 40px de distância não podem ter formas diferentes. As opções vêm por prop, na ordem do servidor: renomear um termo não exige deploy.

Contexto: todos · Área: Clientes

O mesmo controle, no formulário

`uso` não é decoração: é o predicado. No filtro a opção neutra significa “não restrinja”; no formulário significa “este campo fica vazio”. A cópia acompanha, e a combinação errada deixa de ser expressável.

Onde esta tarefa pode ser feita. É por ele que a lista filtra quando você só tem o celular na mão.

Carregando — e por que `undefined` não é `[]`

A §5.1 exige os oito estados e diz que metade deles não é “quase pronto”: é não pronto. Este componente saiu sem `loading`, e os dois consumidores resolveram por fora, de formas diferentes — um inventou um esqueleto à mão, o outro afirmou “você ainda não tem contextos cadastrados” enquanto a consulta ainda estava em voo. A distinção mora no componente porque é ele quem garante que “não sei ainda” e “sei, e está vazio” não sejam ditos com a mesma frase. O esqueleto tem a altura EXATA do gatilho (44px), então o campo troca de conteúdo sem mover um pixel do que está abaixo.

Contexto

Carregando as opções de contexto.

Área

Sem rede, a lista de áreas não chegou. O filtro por área fica indisponível até a conexão voltar.

Vocabulário vazio

Lista vazia não vira menu vazio. Um gatilho que abre e não oferece nada é a tela mentindo que existe uma escolha — o componente troca o controle por uma frase que explica a ausência e diz que o item segue sem o campo (§9). Agora que o carregando existe, esta frase AFIRMA em vez de hedgear: ela só roda depois de a resposta ter chegado vazia.

Área

Nenhuma área cadastrada. O Hub cria as suas no primeiro uso, então essa etapa falhou — vale avisar. Este item segue normalmente sem área.

Energia — dois componentes, não um com rótulo trocável (R-3)

Os dois têm a MESMA assinatura (`NivelEnergia | null`) e predicados diferentes: o filtro é limiar (≤ N), a atribuição é valor exato (= N). Um componente parametrizado por texto tornaria a combinação errada invisível ao TypeScript. Quando o tipo não distingue, o nome distingue.

FiltroDeEnergia — “mostre o que custa até N”

EscolhaDeEnergia — “esta tarefa custa N”

O chip neutro não usa o acento (A-1)

“Qualquer energia” e “Sem definir” significam nada escolhido. Pintá-los de azul cheio é acento em estado inativo, que a §2.10 proíbe pelo nome — e a AD-030 já tinha decidido a mesma coisa ao tirar o alerta `livre` do verde: ausência não é estado positivo, é ausência, e ausência é neutra. Marcado, o chip neutro se distingue por superfície, tinta e um ✓ — e é o ✓ que o separa de “sob o cursor”, porque o hover pousa na mesma superfície. Clique entre eles e compare com um degrau da escala.

Desativado

Energia mantém a fileira de chips mesmo depois da AD-061, e isso não é incoerência: escala ordinal de cinco degraus com medidor gráfico perde o canal que carrega a informação se for escondida dentro de um menu. Forma igual para coisas iguais; forma diferente para coisas diferentes.

Espaço entre cards

Um valor só, em qualquer largura: o que colapsa no celular é o número de colunas, nunca o espaço. Nunca gap-* solto entre cards — use GradeDeCards, PilhaDeCards ou a constante.

ESPACO_ENTRE_CARDS
gap-4 · 16px
RECUO_DO_CARD
p-4 sm:p-5 · 16px → 20px

Indicadores e card de página

Faixa de KPIs (2 × 2 no celular, em linha de lg em diante) e, abaixo, a composição 2/3 + 1/3. tom=acao marca o único card que pede uma ação agora.

O que pede ação

Atrasadas primeiro; depois, o que vence hoje.

Ver todas

O corpo do card é livre: lista, texto ou um número.

Próxima decisão

Um card sem destaque.

Mesmo raio, borda e recuo.

Estados de tela

Cinco obrigações. Não são polimento de fim de sprint: para quem tem TDAH, uma tela que não explica o que aconteceu não gera curiosidade, gera paralisia.

Vazio de partida

Ensina o próximo passo. “Nada por aqui” informa a ausência e não faz nada com ela — é defeito.

Seu Inbox está vazio

Capture qualquer coisa que esteja ocupando espaço na sua cabeça. Você decide o que ela é depois, no processamento.

C abre a captura, de qualquer tela.

Vazio de conquista

Havia itens e acabaram. É outro vazio, e confundir os dois faz o sistema parabenizar quem ainda não começou.

Nada vencendo hoje

Os itens com prazo para hoje já foram concluídos. O que sobra pode esperar — e essa é a informação útil.

C abre a captura, de qualquer tela.

Carregando

Skeleton que antecipa a forma da lista, nunca spinner solto. Salto de layout custa o foco inteiro de quem já está lutando para mantê-lo.

Carregando itens…

Erro

Três obrigações: o que falhou, o que NÃO foi perdido, e a saída. A segunda é a que mais some das mensagens de erro por aí.

Sem rede

A captura offline saiu do escopo (AD-021), então o sistema diz isso na cara. Um “salvo!” que evapora destrói a confiança que faz o usuário parar de reconferir tudo à mão.

Você está sem rede

O Hub precisa de conexão para capturar e salvar. Nada foi perdido: nenhuma alteração foi enviada. Assim que a rede voltar, esta faixa some sozinha.

Sincronização — o quinto estado

O canal do Google expira e o sync para sem gerar erro nenhum. Falha silenciosa não é problema de infraestrutura, é problema de interface. Note que o sinal é a MUDANÇA DE FORMA; a cor só acompanha.

Agenda sincronizada há 2 min

Lista longa

Rola dentro do próprio contêiner e termina com uma marca de fim. Sem ela o usuário rola mais um pouco só para conferir se acabou — atrito pequeno, repetido dezenas de vezes por dia.

  • Item 1 de uma lista que não cabe na tela

    Atrasado
  • Item 2 de uma lista que não cabe na tela

    Vence hoje
  • Item 3 de uma lista que não cabe na tela

    Vence amanhã
  • Item 4 de uma lista que não cabe na tela

    Vence esta semana
  • Item 5 de uma lista que não cabe na tela

    Semana que vem
  • Item 6 de uma lista que não cabe na tela

    A qualquer momento
  • Item 7 de uma lista que não cabe na tela

    Defina essa ação
  • Item 8 de uma lista que não cabe na tela

    Concluído
  • Item 9 de uma lista que não cabe na tela

    Atrasado
  • Item 10 de uma lista que não cabe na tela

    Vence hoje
  • Item 11 de uma lista que não cabe na tela

    Vence amanhã
  • Item 12 de uma lista que não cabe na tela

    Vence esta semana
  • Item 13 de uma lista que não cabe na tela

    Semana que vem
  • Item 14 de uma lista que não cabe na tela

    A qualquer momento
  • Item 15 de uma lista que não cabe na tela

    Defina essa ação
  • Item 16 de uma lista que não cabe na tela

    Concluído
  • Item 17 de uma lista que não cabe na tela

    Atrasado
  • Item 18 de uma lista que não cabe na tela

    Vence hoje
  • Item 19 de uma lista que não cabe na tela

    Vence amanhã
  • Item 20 de uma lista que não cabe na tela

    Vence esta semana
  • Item 21 de uma lista que não cabe na tela

    Semana que vem
  • Item 22 de uma lista que não cabe na tela

    A qualquer momento
  • Item 23 de uma lista que não cabe na tela

    Defina essa ação
  • Item 24 de uma lista que não cabe na tela

    Concluído
  • Item 25 de uma lista que não cabe na tela

    Atrasado
  • Item 26 de uma lista que não cabe na tela

    Vence hoje
  • Item 27 de uma lista que não cabe na tela

    Vence amanhã
  • Item 28 de uma lista que não cabe na tela

    Vence esta semana
  • Item 29 de uma lista que não cabe na tela

    Semana que vem
  • Item 30 de uma lista que não cabe na tela

    A qualquer momento
  • Item 31 de uma lista que não cabe na tela

    Defina essa ação
  • Item 32 de uma lista que não cabe na tela

    Concluído
  • Item 33 de uma lista que não cabe na tela

    Atrasado
  • Item 34 de uma lista que não cabe na tela

    Vence hoje
  • Item 35 de uma lista que não cabe na tela

    Vence amanhã
  • Item 36 de uma lista que não cabe na tela

    Vence esta semana
  • Item 37 de uma lista que não cabe na tela

    Semana que vem
  • Item 38 de uma lista que não cabe na tela

    A qualquer momento
  • Item 39 de uma lista que não cabe na tela

    Defina essa ação
  • Item 40 de uma lista que não cabe na tela

    Concluído

40 itens · fim da lista

Regras de auditoria

O que o Designer confere na entrega do Front-End, antes da revisão de segurança (AD-032). Duas severidades apenas: o que reprova bloqueia o merge; o apontamento entra na próxima passada. A aprovação final é sempre do Líder.

Reprova — bloqueia o merge

  • Cor literal (#hex, rgb(), oklch()) fora de globals.css.

  • Selo de alerta sem palavra, ou cor como único canal de significado.

  • Papéis de token invertidos: --alerta-X como fundo, --alerta-X-suave como texto.

  • outline: none sem substituto, ou elemento focável sem foco visível.

  • Percurso que não se completa só pelo teclado.

  • Contraste abaixo do piso — conferido por cálculo, não a olho.

  • Tela sem os estados de vazio, carregando, erro e sem rede.

  • Tela que não responde: como ela avisa que o dado pode estar velho?

  • Regra de negócio calculada no cliente (alerta, lista GTD, ordenação).

  • Alvo de toque abaixo de 44px no que é tocado com frequência.

  • Reordenação visual que quebra a ordem de tabulação.

  • Card dentro de card, ou grade de cards idênticos sem hierarquia (a faixa de KPIs e a composição 2/3 + 1/3 são o padrão declarado, SPEC-023 F2).

  • Valor de z-index arbitrário (z-[999], z-[9999]).

  • Emoji na interface, exclamação ou entusiasmo fabricado no texto.

  • Acento em saturação plena na opção que significa “nada escolhido”.

Apontamento — corrige na próxima passada

  • Espaçamento fora da escala do Tailwind sem justificativa em comentário.
  • Ritmo uniforme demais: a página inteira com o mesmo respiro.
  • Prosa passando de 75ch.
  • Horário, contador ou duração sem o atributo data-numerico.
  • font-semibold onde font-medium bastaria.
  • Movimento acima de 250 ms, ou que não comunica mudança de estado.
  • Vazio que informa a ausência sem ensinar o próximo passo.
  • Diálogo onde divulgação progressiva inline resolveria.

Como a auditoria é feita, nesta ordem

  1. npm run build, npm run lint, npm run verifica:contraste e npm run verifica:alvo — se algum falha, a auditoria para aqui. O de alvo mede no navegador, a 375px, e abre cada menu antes de medir: a opção de uma lista de seleção não existe no DOM enquanto ela está fechada, e foi assim que 28px sobreviveram a três sprints.
  2. Detector determinístico do estelar sobre os arquivos alterados.
  3. Percurso completo só pelo teclado, nos dois temas, em largura de celular e de desktop.
  4. Conferência item a item da lista de reprovação, com o achado escrito como problema, regra violada e correção proposta.
  5. Devolução ao Front-End. Divergência que persiste sobe para o Líder e vira AD-NNN — nunca é resolvida no código pelo Designer.