@andespindola/crow-skills 0.41.0 → 0.42.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD-PARTY-NOTICES.md +28 -2
- package/catalog.json +4 -2
- package/crow_skills/__init__.py +1 -1
- package/crow_skills/broadcast.py +5 -2
- package/crow_skills/cli.py +1 -1
- package/package.json +1 -1
- package/release.json +135 -10
- package/skills/crow-design/NOTICE.md +26 -0
- package/skills/crow-design/SKILL.md +38 -9
- package/skills/crow-design/licenses/Apache-2.0.txt +191 -0
- package/skills/crow-design/licenses/Impeccable-NOTICE.md +11 -0
- package/skills/crow-design/licenses/design-system-MIT.txt +26 -0
- package/skills/crow-design/licenses/platform-design-MIT.txt +21 -0
- package/skills/crow-design/licenses/taste-skill-MIT.txt +21 -0
- package/skills/crow-design/references/aceite-e-pre-voo.md +267 -0
- package/skills/crow-design/references/adaptacao.md +152 -0
- package/skills/crow-design/references/anti-padroes.md +187 -0
- package/skills/crow-design/references/componentes-e-estados.md +312 -0
- package/skills/crow-design/references/contrato.md +2 -1
- package/skills/crow-design/references/cor.md +151 -0
- package/skills/crow-design/references/dados-e-densidade.md +194 -0
- package/skills/crow-design/references/direcao-estetica.md +209 -0
- package/skills/crow-design/references/documento-do-sistema.md +175 -0
- package/skills/crow-design/references/layout-e-espaco.md +134 -0
- package/skills/crow-design/references/leitura-do-brief.md +158 -0
- package/skills/crow-design/references/movimento.md +144 -0
- package/skills/crow-design/references/redesign-e-sistemas-existentes.md +91 -0
- package/skills/crow-design/references/registro-premium.md +154 -0
- package/skills/crow-design/references/sistema-de-tokens.md +264 -0
- package/skills/crow-design/references/superficie-e-profundidade.md +153 -0
- package/skills/crow-design/references/texto-e-conteudo.md +149 -0
- package/skills/crow-design/references/tipografia.md +139 -0
- package/skills/crow-design/scripts/validar_tokens.py +654 -0
- package/skills/crow-design/templates/tokens.exemplo.json +197 -0
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
<!-- Derivado de Impeccable (Apache-2.0, Paul Bakaus), design-taste-frontend e high-end-visual-design (MIT, Leonxlnx), design-system (MIT, claudekit) e platform-design-skills (MIT, ehmo); reescrito e modificado pelo Crow em 2026-11-13. Ver ../NOTICE.md. -->
|
|
2
|
+
# Sistema de tokens
|
|
3
|
+
|
|
4
|
+
Leia quando o contrato precisar fixar valores: criar ou estender tokens, definir modos (claro, escuro, alto contraste), mapear para CSS ou Tailwind, exportar, versionar ou validar. O formato de referência é o [template de tokens](../templates/tokens.exemplo.json).
|
|
5
|
+
|
|
6
|
+
## Três camadas
|
|
7
|
+
|
|
8
|
+
- **Primitivo:** valores crus, sem significado de uso (`color.neutral.900`, `space.4`, `duration.200`). Nunca referencia outro token. Muda raramente: quando a marca muda ou uma rampa é corrigida.
|
|
9
|
+
- **Semântico:** papéis (`surface.canvas`, `text.secondary`, `action.primary.bg`, `focus.ring`). Referencia só primitivos. É a camada que os modos sobrescrevem; trocar de tema é remapear semânticos.
|
|
10
|
+
- **Componente:** decisões de um componente (`button.primary.bg`, `input.border`). Referencia semânticos. Existe quando o componente precisa de um ponto de customização próprio; não se cria token de componente por reflexo.
|
|
11
|
+
|
|
12
|
+
Código de interface consome semântico ou componente, nunca primitivo nem valor literal. Um componente que pula a camada semântica (`card.bg` apontando direto para `color.neutral.0`) não acompanha a troca de modo; o validador avisa cada caso. Para categorias de dimensão (padding, altura de controle), crie semânticos de densidade (`density.control.padding-inline`) em vez de apontar o componente para a escala crua; se o projeto decidir permitir o salto em alguma categoria, isso é exceção registrada.
|
|
13
|
+
|
|
14
|
+
Migrar um sistema achatado (`--button-primary-bg: #2563eb` direto) para três camadas: extraia os valores únicos para primitivos, dê a cada uso repetido um papel semântico, faça os componentes apontarem para os semânticos e só então crie os modos.
|
|
15
|
+
|
|
16
|
+
## Convenção de nomes, uma só
|
|
17
|
+
|
|
18
|
+
O caminho JSON é a identidade do token. O nome de saída é derivado dele por uma regra única, documentada e gerada, para que documentação e código nunca divirjam:
|
|
19
|
+
|
|
20
|
+
- **Segmentos:** minúsculas ASCII em kebab-case. Primitivo: `{categoria}.{família}.{passo}` (`color.accent.600`, `radius.md`). Semântico: `{papel}.{variante}.{propriedade}` (`action.primary.bg`). Componente: `{componente}.{variante}.{propriedade}` (`button.primary.bg`).
|
|
21
|
+
- **Estado é sufixo da propriedade**, nunca filho de um token: `action.primary.bg-hover`, `action.primary.bg-active`, `button.primary.fg-disabled`. Um token com `$value` não pode ter filhos.
|
|
22
|
+
- **Nome CSS:** `--{prefixo}-{caminho sem o nome da camada, com pontos virando hífens}`. Com prefixo `ds`: `color.neutral.50` vira `--ds-color-neutral-50`; `surface.canvas` vira `--ds-surface-canvas`; `button.primary.bg` vira `--ds-button-primary-bg`. O prefixo é escolhido uma vez por projeto (curto, registrado no documento do sistema) e existe para não colidir com variáveis de bibliotecas, inclusive os namespaces do Tailwind (`--color-*`, `--radius-*`, `--spacing-*`).
|
|
23
|
+
- **Unicidade:** o caminho sem camada precisa ser único entre as três camadas. Se um semântico colidir com um primitivo, renomeie o semântico.
|
|
24
|
+
|
|
25
|
+
## Categorias
|
|
26
|
+
|
|
27
|
+
Um sistema de produto cobre todas as categorias abaixo; um sistema de landing pode omitir as que não usa, dizendo que omitiu.
|
|
28
|
+
|
|
29
|
+
- **Cor:** superfícies (canvas, elevada, afundada, inversa), texto (primário, secundário, desabilitado informativo, sobre ação, sobre status), bordas (`border.default` decorativa, forte, e `border.control` com 3:1), ação (primária, secundária, destrutiva, com hover e ativo opacos), foco, seleção (`::selection`, item selecionado), overlay (scrim de diálogo por modo), status (sucesso, aviso, erro, informação, cada um com fundo, primeiro plano e borda) e dados. Detalhe em [cor](cor.md).
|
|
30
|
+
- **Cores de dados:** categórica (passos distinguíveis entre si e contra o fundo, validados em simulação de daltonismo, nunca o único canal de informação), sequencial (luminosidade monotônica), divergente (dois matizes com ponto médio neutro). Ver [dados e densidade](dados-e-densidade.md).
|
|
31
|
+
- **Tipografia:** primitivos de família, tamanho, entrelinha, peso, tracking e recursos OpenType; semânticos compostos por papel (`display`, `headline`, `title`, `body`, `label`, `caption`, `code`; os cinco primeiros são os papéis do DESIGN.md comum, ver [documento do sistema](documento-do-sistema.md)), cada um com família, tamanho, entrelinha, peso, tracking e `font-feature-settings` (por exemplo `tnum` em `label` de dado). Ver [tipografia](tipografia.md).
|
|
32
|
+
- **Espaço:** escala base 4 nos primitivos; semânticos de componente e de seção por densidade (tabela canônica de padding de seção abaixo).
|
|
33
|
+
- **Raio:** escala nos primitivos; semânticos por tipo de forma (controle, contêiner, mídia) com a regra concêntrica: raio interno = raio externo − padding.
|
|
34
|
+
- **Elevação:** escala de sombras tingidas nos primitivos; semânticos por nível (repouso, elevado, sobreposto) ou declaração de que o sistema usa borda em vez de sombra. Ver [superfície e profundidade](superficie-e-profundidade.md).
|
|
35
|
+
- **Movimento:** primitivos nomeados por valor (duração) e por forma (curva); semânticos por propósito (`duration.instant/state/layout/focal`, `easing.enter/exit`, scrub e mola) e transições compostas por propriedade. Valores abaixo; uso em [movimento](movimento.md).
|
|
36
|
+
- **Densidade:** altura de controle, padding de controle, altura de linha de tabela, padding de seção por faixa do botão DENSIDADE (tabela canônica abaixo), alvo mínimo em `pointer: coarse`.
|
|
37
|
+
- **Breakpoints:** ditados pelo conteúdo, com container queries onde o componente é que muda; 640/768/1024/1280/1536px aparecem só como exemplo marcado.
|
|
38
|
+
- **Camadas (z):** escala nomeada, nada arbitrário; a escala canônica está em [superfície e profundidade](superficie-e-profundidade.md).
|
|
39
|
+
- **Foco:** largura do anel (2px), offset (2px), cor por modo com 3:1 contra os dois lados.
|
|
40
|
+
- **Opacidade:** só para efeitos sem texto (scrim, sombra); estado desabilitado usa cores próprias, não opacidade sobre texto.
|
|
41
|
+
|
|
42
|
+
**Borda de controle é papel próprio.** `border.control` é o limite de campo e de controle (input, select, checkbox, radio, botão contornado, card clicável): 3:1 ou mais contra a superfície adjacente em todos os modos, com os pares declarados em `$contrast`. `border.default` é divisória decorativa e não serve como único limite de nada interativo; o token de componente de um campo (`input.border`) aponta para `border.control`, nunca para `border.default`. Pares e números em [cor](cor.md).
|
|
43
|
+
|
|
44
|
+
## Valores primitivos úteis, já corrigidos
|
|
45
|
+
|
|
46
|
+
Referência para projetos sem escala própria; uma marca existente substitui qualquer um deles.
|
|
47
|
+
|
|
48
|
+
**Espaço (base 4):** 0, 1px, 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 36, 40, 48, 56, 64, 80, 96, 128, 160, 192px. Semânticos de partida: componente 4/8/12/16px (xs, sm, base, lg); seção pela tabela de densidade abaixo; margem lateral de página (page-x) 16px no celular; espaço vertical de página (page-y, entre o cromo e o primeiro bloco e antes do rodapé) 24px.
|
|
49
|
+
|
|
50
|
+
**Padding vertical de seção por DENSIDADE (tabela canônica).** As outras referências ([layout e espaço](layout-e-espaco.md), [direção estética](direcao-estetica.md), [registro premium](registro-premium.md)) citam esta tabela em vez de repetir faixas próprias; mudar um número é mudar aqui.
|
|
51
|
+
|
|
52
|
+
| DENSIDADE | Faixa | Padding vertical de seção (desktop) | Componente | Observação |
|
|
53
|
+
|---|---|---|---|---|
|
|
54
|
+
| 1–3 | arejada (galeria) | 128–192px (8–12rem) | folgado | Faixa do registro premium |
|
|
55
|
+
| 4–7 | padrão | 64–96px (4–6rem) | padrão | Ainda admite cards quando a elevação comunica hierarquia |
|
|
56
|
+
| 8–10 | cockpit | 24–48px (1.5–3rem) | justo | Sem cards genéricos, divisórias de 1px, números com `tabular-nums` |
|
|
57
|
+
|
|
58
|
+
Qual faixa vale para cada tipo de superfície vem do botão DENSIDADE declarado no Design Read, com os sinais e presets de [direção estética](direcao-estetica.md) (painel e produto denso, por exemplo, ficam entre 6 e 8); esta tabela só converte o valor do botão em espaço. O registro premium usa a faixa arejada; uma tabela, um formulário ou uma lista de preços dentro dele mantêm a densidade que a tarefa exige. Os números são ponto de partida que a marca ajusta, sempre por token. No celular a faixa encolhe pelo token de densidade do breakpoint, nunca por valor solto na seção. Um único conjunto de tokens de densidade por superfície e nenhum padding mínimo fixo "para toda seção".
|
|
59
|
+
|
|
60
|
+
**Tamanho de fonte:** 12, 14, 16, 18, 20, 24, 30, 36, 48px e display até 6rem (96px). Entrelinha: 1, 1.25, 1.375, 1.5, 1.625, 2. Pesos: 400, 500, 600, 700. Tracking: −0.04em (mínimo, só display latino), −0.025em, 0, 0.025em, 0.05em, 0.075em, 0.1em (de 0.05 a 0.1em só em caixa alta latina, ver [tipografia](tipografia.md)).
|
|
61
|
+
|
|
62
|
+
**Raio:** 0, 2, 4, 6, 8, 12, 16, 24px e `radius.full` 9999px (pílula), o único nome para pílula em todo o pacote. Uma escala só por projeto, com regra de mistura documentada quando houver (por exemplo, botões em pílula, cards em 16px, campos em 8px).
|
|
63
|
+
|
|
64
|
+
**Sombras (geometria com cor tingida):** a cor da sombra é um token derivado do matiz da superfície com luminosidade baixa (por exemplo `oklch(0.25 0.02 <matiz> / α)`), nunca preto puro em fundo claro; no escuro, a elevação vem mais de superfície mais clara que de sombra.
|
|
65
|
+
|
|
66
|
+
| Nível | Geometria | Alfa |
|
|
67
|
+
|---|---|---|
|
|
68
|
+
| sm | `0 1px 2px 0` | .05 |
|
|
69
|
+
| base | `0 1px 3px 0`, `0 1px 2px -1px` | .10 |
|
|
70
|
+
| md | `0 4px 6px -1px`, `0 2px 4px -2px` | .10 |
|
|
71
|
+
| lg | `0 10px 15px -3px`, `0 4px 6px -4px` | .10 |
|
|
72
|
+
| xl | `0 20px 25px -5px`, `0 8px 10px -6px` | .10 |
|
|
73
|
+
| 2xl | `0 25px 50px -12px` | .25 |
|
|
74
|
+
| inner | `inset 0 2px 4px 0` | .05 |
|
|
75
|
+
|
|
76
|
+
**Movimento: primitivos por valor, semânticos por propósito.**
|
|
77
|
+
|
|
78
|
+
- **Durações primitivas, nomeadas pelo valor:** `duration.75`, `duration.100`, `duration.150`, `duration.200`, `duration.300`, `duration.500`, `duration.700`, `duration.1000` (ms).
|
|
79
|
+
- **Curvas primitivas, nomeadas pela forma:** `easing.out-expo` `cubic-bezier(0.16, 1, 0.3, 1)`; `easing.standard` `cubic-bezier(0.2, 0, 0, 1)`; `easing.out-quart` `cubic-bezier(0.25, 1, 0.5, 1)`; `easing.in` `cubic-bezier(0.3, 0, 1, 1)`; `easing.none` `linear` (o `ease: none` das bibliotecas). A curva longa do registro premium (`cubic-bezier(0.32, 0.72, 0, 1)`) entra como primitivo próprio, nomeado pela forma, quando o registro a adota.
|
|
80
|
+
- **Durações semânticas, por propósito:** `duration.instant` (feedback de pressão, toggle e hover, 100–150ms); `duration.state` (mudança de estado de rotina, 150–300ms; 150–250ms em Operar); `duration.layout` (layout, overlay, transição de view, 300–500ms; **em Operar, 250ms no máximo**, apontando para `duration.200`); `duration.focal` (entrada focal, 500–800ms, só em Persuadir e Experienciar; não existe em Operar).
|
|
81
|
+
- **Easing semântico:** `easing.enter` aponta para `easing.out-expo` (ou `easing.standard` em UI de produto); `easing.exit` aponta para `easing.in` e a saída é mais curta que a entrada; scrub e progresso usam a curva nula; mola (rigidez e amortecimento) só onde há gesto ou interrupção. Os nomes semânticos completos, inclusive o de scrub e o de mola, estão em [movimento](movimento.md).
|
|
82
|
+
- **Sob movimento reduzido,** os semânticos de deslocamento colapsam para 0 ou para crossfade curto; cor e opacidade continuam.
|
|
83
|
+
|
|
84
|
+
**Mapa de transição por propriedade (transições de estado de controle: hover, foco, pressão, seleção).** São semânticos compostos que apontam para primitivos; layout, overlay e entrada focal usam `duration.layout` e `duration.focal`.
|
|
85
|
+
|
|
86
|
+
| Propriedades | Token composto | Duração | Easing |
|
|
87
|
+
|---|---|---|---|
|
|
88
|
+
| `color`, `background-color`, `border-color`, `outline-color`, `text-decoration-color` | `transition.color` | 150ms (`duration.150`) | `easing.enter` ao entrar no estado, `easing.exit` ao sair |
|
|
89
|
+
| `transform` | `transition.transform` | 200ms (`duration.200`) | idem |
|
|
90
|
+
| `opacity` | `transition.opacity` | 150ms (`duration.150`) | idem |
|
|
91
|
+
| `box-shadow` | `transition.shadow` | 200ms (`duration.200`) | idem |
|
|
92
|
+
|
|
93
|
+
Corrigido da origem: lá a cor usava `ease-in-out`, a opacidade `ease` e o transform `ease-out`, sem distinguir chegada de saída; aqui o easing vem do propósito (uma troca simétrica de cor pode usar a mesma curva nos dois sentidos). A transição lista as propriedades (`transition-property` explícito, nunca `all`). Sob movimento reduzido, `transition.transform` colapsa para 0; as de cor e opacidade permanecem.
|
|
94
|
+
|
|
95
|
+
**Camadas:** a escala canônica (ordem, nomes e valores espaçados) está em [superfície e profundidade](superficie-e-profundidade.md); aqui ela só vira tokens `z.*` com os mesmos nomes. Uma camada nova entra na escala, não no componente.
|
|
96
|
+
|
|
97
|
+
**Densidade de tabela e controle:** linha compacta 40px, padrão 48px, confortável 56px; controle pequeno 32px, padrão 40px, grande 48px; em `pointer: coarse`, alvo efetivo de 44px.
|
|
98
|
+
|
|
99
|
+
**Diálogo de partida (dado da origem, corrigido):** padding interno de 24px; sombra `lg` da escala acima, tingida; raio `lg` da escala do projeto (a própria origem diverge, 8px numa tabela e 12px noutra: escolha um e registre); largura máxima da ordem de 32rem; fundo, texto e borda pelos semânticos de superfície elevada; scrim pelo token de overlay do modo, não um preto a 50% fixo. Comportamento (foco, Esc, retorno de foco) em [componentes e estados](componentes-e-estados.md).
|
|
100
|
+
|
|
101
|
+
**Paleta de referência comum e defaults de contraste corrigidos.** Muitos projetos já usam a paleta cinza/azul/verde/vermelho do Tailwind (cinza 50–950: `#F9FAFB #F3F4F6 #E5E7EB #D1D5DB #9CA3AF #6B7280 #4B5563 #374151 #1F2937 #111827 #030712`). Paleta nova na web nasce em OKLCH (ver [cor](cor.md)). Sobre essa paleta, os mapeamentos usuais reprovam em vários pares; os corrigidos (razões WCAG 2.x calculadas):
|
|
102
|
+
|
|
103
|
+
| Papel | Comum e reprovado | Corrigido |
|
|
104
|
+
|---|---|---|
|
|
105
|
+
| ação primária, texto branco | blue-500 `#3B82F6`: 3.68 | blue-600 `#2563EB`: 5.17 (hover blue-700 `#1D4ED8`: 6.70) |
|
|
106
|
+
| informação, texto branco | blue-500: 3.68 | blue-600: 5.17 |
|
|
107
|
+
| sucesso, texto branco | green-600 `#16A34A`: 3.30 | green-700 `#15803D`: 5.02 |
|
|
108
|
+
| destrutivo, texto branco | red-500 `#EF4444`: 3.76 | red-600 `#DC2626`: 4.83 |
|
|
109
|
+
| texto atenuado sobre `#F3F4F6` | gray-500 `#6B7280`: 4.39 | gray-600 `#4B5563`: 6.87 |
|
|
110
|
+
| borda de campo sobre branco | gray-200 `#E5E7EB`: 1.24 | gray-500 `#6B7280`: 4.83 (≥3:1) |
|
|
111
|
+
| borda de campo no escuro, sobre `#030712` | gray-800 `#1F2937`: 1.37 | gray-500: 4.16 |
|
|
112
|
+
| sucesso, texto branco (green-500 `#22C55E` da origem) | green-500: 2.28 | green-700 `#15803D`: 5.02; ou green-500 com texto gray-900: 7.79 |
|
|
113
|
+
| aviso | yellow-500 `#EAB308` com texto gray-900 `#111827`: 9.25 (mantém) | — |
|
|
114
|
+
| aviso, texto branco (yellow-600 `#CA8A04` da origem) | yellow-600: 2.94 | yellow-600 com texto gray-900: 6.04 (ou yellow-500 com gray-900: 9.25) |
|
|
115
|
+
| informação declarada como `blue-500` no arquivo de primitivos (origem) | semântico na camada errada e 3.68 com branco | semântico `status.info` apontando para blue-600: 5.17 |
|
|
116
|
+
|
|
117
|
+
**Rampa azul da origem, com contraste calculado** (razões WCAG 2.x; "reprova" = abaixo de 4.5 como texto normal):
|
|
118
|
+
|
|
119
|
+
| Passo | Hex | Com texto branco | Com texto gray-900 `#111827` |
|
|
120
|
+
|---|---|---|---|
|
|
121
|
+
| 50 | `#EFF6FF` | 1.09 reprova | 16.30 |
|
|
122
|
+
| 100 | `#DBEAFE` | 1.22 reprova | 14.54 |
|
|
123
|
+
| 200 | `#BFDBFE` | 1.42 reprova | 12.48 |
|
|
124
|
+
| 300 | `#93C5FD` | 1.80 reprova | 9.84 |
|
|
125
|
+
| 400 | `#60A5FA` | 2.54 reprova | 6.98 |
|
|
126
|
+
| 500 | `#3B82F6` | 3.68 reprova | 4.82 |
|
|
127
|
+
| 600 | `#2563EB` | 5.17 | 3.43 reprova |
|
|
128
|
+
| 700 | `#1D4ED8` | 6.70 | 2.65 reprova |
|
|
129
|
+
| 800 | `#1E40AF` | 8.72 | 2.03 reprova |
|
|
130
|
+
| 900 | `#1E3A8A` | 10.36 | 1.71 reprova |
|
|
131
|
+
|
|
132
|
+
No escuro, sobre gray-950 `#030712`, blue-500 dá 5.47 e blue-400 dá 7.92 como texto ou ação. São dados da origem para quem já usa essa paleta, não recomendação de matiz.
|
|
133
|
+
|
|
134
|
+
"Branco" aqui é o token de texto sobre ação; quando o sistema evita `#fff` puro, recalcule com o quase-branco escolhido. O modo escuro sobrescreve também ação, foco, status e destrutivo, não só fundo e texto: um primário que passa no claro não passa automaticamente no escuro.
|
|
135
|
+
|
|
136
|
+
## Modos com paridade
|
|
137
|
+
|
|
138
|
+
Os modos existentes (claro, escuro, alto contraste, ou só um) são decisão do contrato com o dono. Quando há mais de um:
|
|
139
|
+
|
|
140
|
+
- Cada semântico que depende de luz tem valor em cada modo; o que um modo não sobrescreve herda o valor base, e essa herança precisa ser intencional.
|
|
141
|
+
- Os pares de contraste são declarados uma vez e verificados em todos os modos.
|
|
142
|
+
- Escuro não é inversão: superfícies elevadas ficam mais claras, croma cai, sombras pesam menos.
|
|
143
|
+
- **Alto contraste** é modo de tokens próprio (bordas fortes, texto de contraste máximo, foco espesso), ativado por escolha explícita e por `prefers-contrast: more`. **`forced-colors: active`** é outra coisa: o navegador impõe as cores do sistema e os tokens de cor deixam de valer; a especificação garante borda e `outline` reais (nada que dependa só de `box-shadow` ou de fundo) e usa palavras-chave de cor de sistema (`Canvas`, `CanvasText`, `LinkText`, `ButtonText`, `Highlight`, `GrayText`) onde for preciso.
|
|
144
|
+
- `color-scheme` acompanha o modo, para que controles nativos e barras de rolagem combinem.
|
|
145
|
+
|
|
146
|
+
## Estado com alvo opaco
|
|
147
|
+
|
|
148
|
+
Hover, ativo, selecionado e desabilitado têm tokens próprios com cor opaca (`action.primary.bg-hover`), nunca o mesmo token com alfa (`/90`, `/80`) ou "mais escuro" calculado no componente. Alfa muda o contraste conforme o fundo e não é verificável no par fg/bg; o validador recusa cor translúcida em par de contraste. Seleção em linha de tabela é um fundo opaco do modo, não o primário a 10%.
|
|
149
|
+
|
|
150
|
+
## Saída: aliases, nunca literais resolvidos
|
|
151
|
+
|
|
152
|
+
Toda saída preserva a referência entre camadas como alias. Na saída CSS, semânticos e componentes são `var()` de outra variável, nunca o valor resolvido; se o gerador gravar `--ds-button-primary-bg: #2563eb`, o modo escuro troca o semântico e o botão continua claro. Critério de aceite para quem implementa: trocar o modo e verificar que o valor computado de um token de componente mudou junto.
|
|
153
|
+
|
|
154
|
+
### CSS custom properties
|
|
155
|
+
|
|
156
|
+
Exemplo sintético a partir do template (prefixo `ds`, valores do template):
|
|
157
|
+
|
|
158
|
+
```css
|
|
159
|
+
:root {
|
|
160
|
+
color-scheme: light;
|
|
161
|
+
--ds-color-neutral-0: oklch(1 0 0);
|
|
162
|
+
--ds-color-neutral-50: oklch(0.98 0.004 240);
|
|
163
|
+
--ds-color-neutral-900: oklch(0.21 0.008 240);
|
|
164
|
+
--ds-color-neutral-950: oklch(0.15 0.006 240);
|
|
165
|
+
--ds-color-accent-300: oklch(0.82 0.085 195);
|
|
166
|
+
--ds-color-accent-700: oklch(0.42 0.058 195);
|
|
167
|
+
|
|
168
|
+
--ds-surface-canvas: var(--ds-color-neutral-50);
|
|
169
|
+
--ds-text-primary: var(--ds-color-neutral-900);
|
|
170
|
+
--ds-action-primary-bg: var(--ds-color-accent-700);
|
|
171
|
+
--ds-action-primary-fg: var(--ds-color-neutral-0);
|
|
172
|
+
|
|
173
|
+
--ds-button-primary-bg: var(--ds-action-primary-bg);
|
|
174
|
+
--ds-button-primary-fg: var(--ds-action-primary-fg);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
[data-theme="dark"] {
|
|
178
|
+
color-scheme: dark;
|
|
179
|
+
--ds-surface-canvas: var(--ds-color-neutral-950);
|
|
180
|
+
--ds-text-primary: var(--ds-color-neutral-50);
|
|
181
|
+
--ds-action-primary-bg: var(--ds-color-accent-300);
|
|
182
|
+
--ds-action-primary-fg: var(--ds-color-neutral-950);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
@media (prefers-color-scheme: dark) {
|
|
186
|
+
:root:not([data-theme]) { /* mesmas sobrescritas do bloco dark */ }
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
O modo de alto contraste segue o mesmo desenho com `[data-theme="high-contrast"]` e `@media (prefers-contrast: more)`. O tema escolhido pelo usuário é aplicado antes da primeira pintura (script curto no `<head>` que lê a preferência salva), e a página escuta a mudança da preferência do sistema; sem isso, a página pisca no tema errado e ignora a troca do sistema operacional.
|
|
191
|
+
|
|
192
|
+
### Tailwind v4
|
|
193
|
+
|
|
194
|
+
Detecte a versão antes: `@import "tailwindcss"` com blocos `@theme` é v4; `tailwind.config.*` com `@tailwind base` é v3. Não misture sintaxes. Na v4, os tokens continuam nas custom properties com prefixo próprio, e o tema do Tailwind só mapeia nomes de utilitário para elas:
|
|
195
|
+
|
|
196
|
+
```css
|
|
197
|
+
@import "tailwindcss";
|
|
198
|
+
|
|
199
|
+
@theme {
|
|
200
|
+
--color-*: initial; /* sem paleta crua: nada de bg-blue-600 fora do sistema */
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
@theme inline {
|
|
204
|
+
--color-canvas: var(--ds-surface-canvas);
|
|
205
|
+
--color-fg: var(--ds-text-primary);
|
|
206
|
+
--color-action: var(--ds-action-primary-bg);
|
|
207
|
+
--color-on-action: var(--ds-action-primary-fg);
|
|
208
|
+
--radius-control: var(--ds-radius-control);
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
`@theme inline` faz o utilitário referenciar a variável, de modo que `bg-action` acompanha o modo sem variante `dark:`. Com tokens semânticos, `dark:` fica para exceções; escolha uma estratégia, não as duas. A sintaxe exata (`@theme inline`, o reset com `initial`, `@custom-variant`) é conferida na documentação da versão instalada por quem implementa.
|
|
213
|
+
|
|
214
|
+
### Tailwind v3
|
|
215
|
+
|
|
216
|
+
Mapeie em `theme.extend` com objetos aninhados e valores `var()`: `colors: { canvas: 'var(--ds-surface-canvas)', action: { DEFAULT: 'var(--ds-action-primary-bg)', hover: 'var(--ds-action-primary-bg-hover)' } }`. Chaves com ponto (`'primary.hover'`) não geram classe utilizável. Modificador de opacidade (`bg-action/50`) não funciona com `var()` de cor completa na v3, o que é mais um motivo para os tokens de estado opacos.
|
|
217
|
+
|
|
218
|
+
### Exportação DTCG
|
|
219
|
+
|
|
220
|
+
O template segue a estrutura do formato de tokens de design (DTCG): folhas com `$value` e `$type`, referência `{caminho.do.token}`, grupos aninhados. Para entregar a ferramentas que leem DTCG estrito (Style Dictionary, Tokens Studio e afins), exporte cada modo como um conjunto separado (a chave `modes` do template não é parte do formato; modos e temas no DTCG são conjuntos combinados por um resolvedor) e confira, na versão da especificação e da ferramenta de destino, se dimensão e duração precisam ser objeto de valor mais unidade, se cor precisa de espaço de cor e componentes, e se sombra, tipografia e transição são tipos compostos. O template usa strings por legibilidade; a conversão é da exportação, não do arquivo-fonte.
|
|
221
|
+
|
|
222
|
+
## Governança
|
|
223
|
+
|
|
224
|
+
- **Versão semântica do sistema** em `$meta.version`. MAJOR: remoção ou renomeação de token, mudança de significado de um semântico, remoção de modo. MINOR: token, modo ou variante novos, compatíveis. PATCH: ajuste de valor que mantém o significado e continua passando nos pares de contraste.
|
|
225
|
+
- **Depreciação com alias e prazo:** o nome antigo continua existindo como referência ao novo (`{semantic.action.primary.bg}`), marcado com `"$deprecated"` e com `$description` dizendo o substituto e a versão de remoção. A marca é obrigatória: o validador só aceita semântico apontando para semântico quando ela existe, e avisa "use <alvo>". Se a ferramenta de destino não lê `$deprecated`, a exportação a converte; o arquivo-fonte a mantém. A remoção só acontece no próximo MAJOR.
|
|
226
|
+
- **Changelog** por versão: adicionado, alterado, depreciado, removido, cada linha com motivo e, quando mexe em cor, a razão de contraste resultante. Vive no [documento do sistema](documento-do-sistema.md).
|
|
227
|
+
- **Dono:** um papel nomeado (pessoa ou equipe) aprova mudanças. Fluxo: proposta (o que muda, por quê) → impacto (consumidores, modos, pares de contraste) → aprovação → incremento de versão → changelog.
|
|
228
|
+
- **Exceções** com dono, motivo, escopo (qual token ou componente), validade (data ou versão) e plano de remoção, registradas no documento do sistema. Exceção sem validade vira regra escondida.
|
|
229
|
+
- **Mapeamento design ↔ código:** tabela de token → variável CSS → utilitário, gerada da mesma fonte.
|
|
230
|
+
- **Multimarca:** cada marca é um conjunto de sobrescritas semânticas sobre primitivos próprios ou compartilhados, validado como arquivo próprio ou como modos nomeados (`marca-a-claro`, `marca-a-escuro`), com a mesma paridade.
|
|
231
|
+
- **Uma fonte de verdade:** o arquivo de tokens é normativo. Documento e saídas são gerados dele ou conferidos contra ele; nunca há duas fontes editadas à mão.
|
|
232
|
+
|
|
233
|
+
## Validar
|
|
234
|
+
|
|
235
|
+
Na pasta da skill (caminho relativo):
|
|
236
|
+
|
|
237
|
+
```
|
|
238
|
+
python3 scripts/validar_tokens.py <arquivo>
|
|
239
|
+
python3 scripts/validar_tokens.py <arquivo> --json
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Saída 0 sem erros, 1 com erros, 2 para erro de uso ou de estrutura (arquivo ausente, JSON inválido ou aninhado demais, camada obrigatória ausente, `defaultMode`, `modes`, `$contrast` ou `min` malformados). O script lê só o arquivo indicado, não acessa rede e não escreve nada. Rodado sobre o template, sai com 0 e imprime o resumo `0 erro(s), 0 aviso(s); N par(es) de contraste verificados em N modo(s)`.
|
|
243
|
+
|
|
244
|
+
**O que ele checa:**
|
|
245
|
+
- presença das camadas `primitive`, `semantic` e `component` e `$meta.version` em semver;
|
|
246
|
+
- referências `{a.b.c}` que não resolvem, inclusive dentro de `$value` composto (objeto ou lista, como sombra, tipografia e transição), e ciclos de referência, na base e em cada modo;
|
|
247
|
+
- direção das camadas, para cada referência de cada token e de cada sobrescrita de modo: primitivo não referencia nada; semântico só referencia primitivo; componente não referencia componente; componente apontando para primitivo gera aviso; valor literal em semântico ou componente gera aviso. Semântico apontando para semântico é erro, salvo quando o token antigo traz `"$deprecated"` (alias de depreciação): aí passa com o aviso "use <alvo>";
|
|
248
|
+
- estrutura: nó com `$value` não pode ter filhos (erro, inclusive dentro de `modes`); segmento de nome com ponto é erro, porque colide com o caminho; JSON aninhado além de 100 níveis é estrutura inválida;
|
|
249
|
+
- modos: sobrescritas em `modes` só podem apontar para semântico existente (os caminhos dentro de um modo são relativos a `semantic`);
|
|
250
|
+
- contraste WCAG 2.x de cada par declarado em `$contrast` (`fg` e `bg` como caminhos de token sem chaves, `label` opcional), comparando a razão exata, sem arredondar (arredonda só na exibição), com o modo de `$meta.defaultMode` como base. `min` é número (padrão 4.5) ou objeto por modo, por exemplo `{"default": 4.5, "high-contrast": 7}`, em que `default` vale para os modos não listados; `modes` opcional no par restringe a verificação a esses modos; modo desconhecido é erro;
|
|
251
|
+
- cores: hex, `rgb()`/`rgba()`, `hsl()`/`hsla()`, `oklch()` (L em número ou %, C em número ou %, matiz em `deg`, `turn`, `rad`, `grad` ou `none`), `color(display-p3 …)` convertida para sRGB, e objeto DTCG (`colorSpace` `srgb` ou `oklch`, `components`, `alpha` opcional). Alfa abaixo de 1 num par e valores não finitos são rejeitados; fora do gamut sRGB gera aviso e a cor é recortada.
|
|
252
|
+
|
|
253
|
+
Tokens do template úteis para conferir o formato: `semantic.border.control`, `semantic.duration.instant`, `semantic.duration.state`, `semantic.duration.layout`, `semantic.duration.focal`, `semantic.easing.enter`, `semantic.easing.exit`, e os primitivos `duration.100`, `duration.200`, `duration.300`, `duration.500`, `easing.out-expo`, `easing.standard` e `easing.in` (o template traz só esse subconjunto da escala acima).
|
|
254
|
+
|
|
255
|
+
**O que ele não checa** (fica com você, no pré-voo):
|
|
256
|
+
- o significado dos nomes, nem se um token nomeado por propósito está na camada certa: ele só confere a direção das referências, então um `semantic.color.blue` passa;
|
|
257
|
+
- a convenção de nomes, a unicidade dos nomes CSS e o prefixo;
|
|
258
|
+
- a completude das categorias e a paridade de modos (um semântico não sobrescrito herda o valor base em silêncio);
|
|
259
|
+
- contraste de pares não declarados em `$contrast`: declare todos os pares reais (texto, texto secundário, texto sobre ação e status, `focus.ring` contra cada superfície que ele toca, `border.control` contra cada superfície, estados de hover e seleção);
|
|
260
|
+
- `$type` contra `$value`, o formato de valores que não são cor e referências embutidas no meio de uma string maior;
|
|
261
|
+
- gamut P3 como alvo (uma cor P3 é convertida e avaliada em sRGB), contraste APCA, `forced-colors` e o uso dos tokens no código (literal em componente, `var()` sem definição);
|
|
262
|
+
- se o incremento de versão corresponde às mudanças e se aliases depreciados têm prazo.
|
|
263
|
+
|
|
264
|
+
Tokens válidos são gate do contrato (ver [aceite e pré-voo](aceite-e-pre-voo.md)): o contrato não fecha com o validador saindo com 1 ou 2.
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
<!-- Derivado de Impeccable (Apache-2.0, Paul Bakaus), design-taste-frontend e high-end-visual-design (MIT, Leonxlnx), design-system (MIT, claudekit) e platform-design-skills (MIT, ehmo); reescrito e modificado pelo Crow em 2026-11-13. Ver ../NOTICE.md. -->
|
|
2
|
+
# Superfície e profundidade
|
|
3
|
+
|
|
4
|
+
Leia quando o contrato for decidir cards, bordas, sombras, raio, camadas (z-index), vidro, textura, fundo, ícones ou as superfícies do navegador (seleção, cursor, barra de rolagem).
|
|
5
|
+
|
|
6
|
+
## Card é decisão de hierarquia
|
|
7
|
+
|
|
8
|
+
Card só existe quando a elevação comunica hierarquia real: um objeto que se move, se seleciona, se arrasta ou precisa se distinguir do resto. Fora disso, a separação vem de espaço, de uma borda no topo entre blocos (`border-block-start`) ou de divisórias entre itens. Com densidade acima de 7, cards genéricos não entram: linhas de 1px e alinhamento fazem o trabalho. Card dentro de card não entra. Três cards iguais com ícone, título e texto como estrutura de página é o template mais reconhecível que existe.
|
|
9
|
+
|
|
10
|
+
## Elevação: borda ou sombra, declarada uma vez
|
|
11
|
+
|
|
12
|
+
O sistema escolhe **borda ou sombra** como linguagem de elevação e declara qual. Borda de 1px sob uma sombra larga e suave é o **card fantasma**: duas linguagens dizendo a mesma coisa, nenhuma decidindo.
|
|
13
|
+
|
|
14
|
+
**Sombra** tem deslocamento vertical e desfoque suave, e é **tingida** pelo matiz da superfície em que cai (um escuro do próprio matiz com alfa baixo), nunca preto puro em fundo claro, que suja. Escala de referência, para trocar a cor pelo matiz do sistema:
|
|
15
|
+
|
|
16
|
+
| Nível | Valor de referência |
|
|
17
|
+
|---|---|
|
|
18
|
+
| sm | `0 1px 2px 0` a 5% |
|
|
19
|
+
| base | `0 1px 3px 0` a 10% + `0 1px 2px -1px` a 10% |
|
|
20
|
+
| md | `0 4px 6px -1px` a 10% + `0 2px 4px -2px` a 10% |
|
|
21
|
+
| lg | `0 10px 15px -3px` a 10% + `0 4px 6px -4px` a 10% |
|
|
22
|
+
| xl | `0 20px 25px -5px` a 10% + `0 8px 10px -6px` a 10% |
|
|
23
|
+
| 2xl | `0 25px 50px -12px` a 25% |
|
|
24
|
+
| inner | `inset 0 2px 4px 0` a 5% |
|
|
25
|
+
|
|
26
|
+
A cor é, por exemplo, `oklch(0.25 0.02 H / α)` com o H da superfície. Alfa em sombra é aceitável porque sombra não carrega texto; o limite de componente não pode depender dela.
|
|
27
|
+
|
|
28
|
+
**Vícios de sombra:**
|
|
29
|
+
|
|
30
|
+
- **Halo colorido sem deslocamento** (glow) é decoração, não profundidade, e quase sempre puxa para o cluster neon.
|
|
31
|
+
- **Sombra dura deslocada sem desfoque** (`4px 4px 0`) só num mundo que é de fato neobrutalista, aplicada com coerência.
|
|
32
|
+
- Sombra genérica de biblioteca (`shadow-md`) em tudo, ou preto a 30%, achata o sistema numa única elevação.
|
|
33
|
+
|
|
34
|
+
**No escuro,** a elevação sobe pela luminosidade da superfície (mais alto, um pouco mais claro), não por sombras mais fortes, que quase não se veem. No Android, isso é a elevação tonal do Material.
|
|
35
|
+
|
|
36
|
+
## Limite de componente interativo
|
|
37
|
+
|
|
38
|
+
Quando a borda é o único limite de um controle interativo (input, select, checkbox, botão contornado, card clicável), ela precisa de **3:1** contra o fundo adjacente, em cada modo. Hairlines com alfa muito baixo (preto a 5% sobre branco dá 1.12:1; branco a 10% sobre quase-preto, 1.22:1) servem só em superfície decorativa e não interativa. Card puramente decorativo não exige 3:1, mas, se a separação some (card branco sobre canvas quase branco dá 1.05:1), escolha tint, sombra calculada ou borda real em vez de uma borda invisível. Pares e números em [cor](cor.md).
|
|
39
|
+
|
|
40
|
+
## Raio como sistema
|
|
41
|
+
|
|
42
|
+
O raio é uma escala com regra de mistura, não um valor aplicado a tudo, e não há valor imposto pela ferramenta: cada mundo escolhe o seu.
|
|
43
|
+
|
|
44
|
+
**Trava de forma.** O sistema declara uma das opções: tudo reto (0), tudo médio (12 a 16px), ou pílula nos interativos com o resto em outra regra. Mistura só com regra escrita, por exemplo "botões em pílula, cards 16px, inputs 8px". Raio decidido componente a componente é ruído.
|
|
45
|
+
|
|
46
|
+
- **Escala de referência:** 0, 2, 4, 6, 8, 12, 16, 24px e pílula pelo token `radius.full` (9999px); toda receita em pílula deste pacote usa esse token, não um número solto.
|
|
47
|
+
- **Card de 12 a 16px** é um default sugerido para mundos neutros, não regra: um mundo técnico pode ser reto, um mundo infantil pode ser muito redondo.
|
|
48
|
+
- **Pílula** fica para controles pequenos (botão, chip, badge, toggle), não para cards e contêineres grandes, salvo regra declarada.
|
|
49
|
+
- **Raio concêntrico:** elemento dentro de outro com padding usa raio interno igual ao externo menos o padding (externo 2rem com padding de 0.375rem dá interno `calc(2rem - 0.375rem)`). Mesmo raio dentro e fora parece desalinhado.
|
|
50
|
+
|
|
51
|
+
## Camadas (z-index)
|
|
52
|
+
|
|
53
|
+
A escala é token, documentada num lugar só; nenhum componente inventa `z-index: 50` ou `9999`. Ordem de referência, de baixo para cima: base, elevado, sticky (nav e cabeçalhos fixos), dropdown, overlay (scrim), modal, popover e tooltip, toast, grão (textura decorativa, sempre com `pointer-events: none`). Valores espaçados (0, 100, 200 e assim por diante) permitem inserir uma camada sem renumerar. `<dialog>` modal e a API de popover vão para a camada superior do navegador e dispensam a escala; o contrato diz o que convive com eles. A camada de cada overlay e a árvore de decisão entre inline, disclosure, popover e modal estão em [layout e espaço](layout-e-espaco.md).
|
|
54
|
+
|
|
55
|
+
## Vidro e translucidez
|
|
56
|
+
|
|
57
|
+
Vidro é efeito com lugar certo, não decoração geral:
|
|
58
|
+
|
|
59
|
+
- **Onde:** só em camada fixa ou sobreposta (nav, overlay, controle sobre mídia, menu em tela cheia). Nunca em card de conteúdo que rola nem em área grande: `backdrop-filter` em área que rola custa caro em celular e borra a leitura.
|
|
60
|
+
- **Quando:** briefs que pedem (premium consumer, adjacência à Apple, luxo, overlay de mídia). Nunca em dashboard, setor público ou B2B sóbrio.
|
|
61
|
+
- **Receita de referência:** fundo da superfície com alfa (da ordem de 60 a 80% sobre mídia; mais opaco quando há texto pequeno), `backdrop-filter: blur(24px)` a `blur(40px)` (64px no menu de tela cheia, que também escurece ou clareia o fundo a cerca de 80%), contorno de 1px em branco a 10%, brilho interno `inset 0 1px 0` em branco a 10%.
|
|
62
|
+
|
|
63
|
+
Fallbacks obrigatórios, **por modo**:
|
|
64
|
+
|
|
65
|
+
```css
|
|
66
|
+
/* H = matiz da superfície do sistema; valores ilustrativos de formato */
|
|
67
|
+
.vidro { /* claro */
|
|
68
|
+
background: oklch(0.98 0.004 H / 0.72);
|
|
69
|
+
backdrop-filter: blur(24px) saturate(160%);
|
|
70
|
+
border: 1px solid rgb(255 255 255 / 0.1);
|
|
71
|
+
box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.1);
|
|
72
|
+
}
|
|
73
|
+
@media (prefers-color-scheme: dark) {
|
|
74
|
+
.vidro { background: oklch(0.2 0.01 H / 0.64); }
|
|
75
|
+
}
|
|
76
|
+
@supports not (backdrop-filter: blur(1px)) {
|
|
77
|
+
.vidro { background: oklch(0.98 0.004 H); }
|
|
78
|
+
@media (prefers-color-scheme: dark) { .vidro { background: oklch(0.2 0.01 H); } }
|
|
79
|
+
}
|
|
80
|
+
@media (prefers-reduced-transparency: reduce) {
|
|
81
|
+
.vidro { background: oklch(0.98 0.004 H); backdrop-filter: none; }
|
|
82
|
+
}
|
|
83
|
+
@media (prefers-reduced-transparency: reduce) and (prefers-color-scheme: dark) {
|
|
84
|
+
.vidro { background: oklch(0.2 0.01 H); }
|
|
85
|
+
}
|
|
86
|
+
@media (forced-colors: active) {
|
|
87
|
+
.vidro { border: 1px solid CanvasText; }
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
O fallback de transparência reduzida usa a superfície opaca **do próprio modo**. Forçar uma superfície clara também no escuro (o erro da receita de origem) deixa texto claro sobre fundo quase branco justamente para quem pediu acessibilidade. O contraste é verificado nos quatro cenários: claro, escuro, e cada um com transparência reduzida; e sem nenhum desfoque, porque o texto precisa passar mesmo sobre a pior parte da mídia por trás. Quando o tema é trocado por classe ou atributo, os mesmos blocos se repetem com o seletor do tema.
|
|
92
|
+
|
|
93
|
+
### Aproximação de Liquid Glass
|
|
94
|
+
|
|
95
|
+
Não existe folha CSS oficial de Liquid Glass para a web: o material pertence às APIs das plataformas Apple. Quando o brief pede o efeito na web, ele é uma **aproximação rotulada como tal** no contrato e no código. Valores de referência:
|
|
96
|
+
|
|
97
|
+
- **Base (claro):** `border-radius: var(--ds-radius-full)` (token `radius.full`); `position: relative; isolation: isolate; overflow: hidden`; `border: 1px solid rgb(255 255 255 / .32)`; fundo `linear-gradient(135deg, rgb(255 255 255 / .30), rgb(255 255 255 / .08)), rgb(255 255 255 / .12)`; `backdrop-filter: blur(24px) saturate(180%) contrast(1.05)` (com o prefixo `-webkit-`); sombras `inset 0 1px 0 rgb(255 255 255 / .48)`, `inset 0 -1px 0 rgb(255 255 255 / .12)` e uma sombra ampla `0 18px 60px oklch(0.25 0.02 H / .18)`, **tingida pelo matiz H da superfície** sobre a qual o vidro flutua, nunca `rgb(0 0 0 / …)` em fundo claro (a origem usava preto puro, que suja).
|
|
98
|
+
- **`::before`** (brilho, `z-index: -1`, `pointer-events: none`): `radial-gradient(circle at 20% 0%, rgb(255 255 255 / .55), transparent 34%)` mais `linear-gradient(90deg, rgb(255 255 255 / .18), transparent 42%, rgb(255 255 255 / .14))`.
|
|
99
|
+
- **`::after`** (contorno interno): `inset: 1px`, `border: 1px solid rgb(255 255 255 / .14)`, raio herdado.
|
|
100
|
+
- **Escuro:** borda branca a .18; fundo `linear-gradient(135deg, rgb(255 255 255 / .16), rgb(255 255 255 / .04))` sobre `rgb(15 23 42 / .42)`; sombras `inset 0 1px 0 rgb(255 255 255 / .22)` e a ampla `0 18px 60px oklch(0.12 0.02 H / .42)`, também tingida pelo matiz da superfície. O valor `rgb(15 23 42)` é o dado da origem: o tom do fundo escuro deriva do matiz da superfície do sistema e não deve cair no cluster da ardósia azul-preta.
|
|
101
|
+
- **Transparência reduzida:** superfície **opaca de verdade** (alfa 1) do próprio modo: o semântico de superfície elevada clara no claro e o escuro no escuro, sem desfoque e sem os gradientes translúcidos. Branco a .96 não é opaco e não serve (a origem o usava).
|
|
102
|
+
- **`forced-colors`:** borda real com `CanvasText`.
|
|
103
|
+
|
|
104
|
+
O suporte de `prefers-reduced-transparency` e de `backdrop-filter` com vários filtros é desigual entre navegadores; o contraste precisa passar mesmo sem desfoque. Esta é a receita canônica de vidro e de Liquid Glass do pacote; [direção estética](direcao-estetica.md) e [registro premium](registro-premium.md) linkam aqui em vez de repetir valores.
|
|
105
|
+
|
|
106
|
+
## Moldura dupla (Double-Bezel)
|
|
107
|
+
|
|
108
|
+
Técnica opcional para mídia de destaque e hero, nunca em input (duas bordas confundem o limite do campo) e nunca em todo card:
|
|
109
|
+
|
|
110
|
+
- **Casca externa:** fundo com alfa muito baixo (preto a 5% no claro, branco a 5% no escuro), contorno de 1px (preto a 5% ou branco a 10%), padding de 6 a 8px, raio de 2rem.
|
|
111
|
+
- **Núcleo:** fundo próprio, brilho interno `inset 0 1px 1px rgb(255 255 255 / .15)`, raio concêntrico `calc(2rem - 0.375rem)`.
|
|
112
|
+
|
|
113
|
+
A hairline da casca é decorativa; se o elemento é interativo, o limite real precisa de 3:1. Uso no registro premium em [registro premium](registro-premium.md).
|
|
114
|
+
|
|
115
|
+
## Fundo, textura e imagem
|
|
116
|
+
|
|
117
|
+
Fundo é superfície, e a textura vem do mundo do assunto.
|
|
118
|
+
|
|
119
|
+
- **Grão e ruído:** textura estática numa camada fixa de tela inteira (`position: fixed; inset: 0; pointer-events: none`), na posição de grão da escala de camadas, com opacidade muito baixa (da ordem de 3%). Nunca num contêiner que rola (repinta a cada quadro) e nunca animado. Use uma textura pré-renderizada leve em mosaico. Grão decorativo gerado ao vivo por filtro de turbulência (`feTurbulence`) lê como amador e custa caro; distorção **funcional** com filtro SVG (deslocamento, máscara que serve à ideia) é permitida com orçamento de desempenho declarado.
|
|
120
|
+
- **Listras e grades:** `repeating-linear-gradient` e grades sobrepostas em dois eixos só quando existe de fato um canvas, mapa, planta ou instrumento de medida por baixo. Linhas de grade ou miras como enfeite não entram.
|
|
121
|
+
- **Fisicalidade falsa:** bisel, relevo, metal estampado, giz ou couro feitos em CSS imitando material leem como imitação. Se o mundo pede material, use asset real (foto, render) ou abstraia.
|
|
122
|
+
- **Máscaras geométricas no lugar de recorte orgânico:** círculo, polígono ou recorte radial imitando o contorno de um sujeito fotográfico é a versão barata. Use matte com alfa derivado da imagem ou recorte real. `clip-path` com muitos vértices onde deveria haver um asset é o mesmo erro.
|
|
123
|
+
- **Raster enterrado:** imagem com opacidade quase zero ou atrás de um véu que a apaga não é decisão de imagem; ou ela aparece, ou sai.
|
|
124
|
+
- **Ilustração é real ou não existe:** cena SVG em estilo esboço não substitui ilustração. SVG fazendo geometria (formas exatas, diagramas, desenho de linha) é legítimo. SVG inline acima de algo como 64px ou com mais que alguns paths está fazendo papel de ilustração e pede asset próprio.
|
|
125
|
+
- **Hero precisa de visual real:** texto sobre uma bolha de gradiente não é hero. Interface de produto falsa montada com `<div>` não substitui screenshot real, componente real ou foto. Origem, licença e rótulo de asset em [texto e conteúdo](texto-e-conteudo.md).
|
|
126
|
+
|
|
127
|
+
## Ícones
|
|
128
|
+
|
|
129
|
+
- **Uma biblioteca por projeto**, com **uma espessura** de traço global que acompanha o peso do texto ao lado (por exemplo 1.5 com texto regular, 2 com texto semibold). Traço ultrafino em tamanho pequeno perde legibilidade e contraste.
|
|
130
|
+
- **Contraste não-texto de 3:1** para ícones que informam (status, ação sem rótulo). Ícone ao lado de rótulo é decorativo e sai da árvore de acessibilidade; ícone sozinho precisa de nome acessível.
|
|
131
|
+
- **Tamanho:** 16 a 24px em interface, alinhados à altura de versal do texto e não à caixa.
|
|
132
|
+
- **SVG autoral** só quando é uma marca geométrica simples ou um ícone que a biblioteca não tem, desenhado na mesma grade e espessura.
|
|
133
|
+
- **Emoji e caracteres Unicode** (setas, estrelas, marcadores) não são sistema de ícones: renderizam diferente em cada plataforma e não seguem cor, peso nem tamanho. Emoji só em conteúdo de voz deliberadamente informal, com parcimônia.
|
|
134
|
+
- **Bibliotecas citadas como opções** (nenhuma é obrigatória e todas têm o nome a conferir no registro de pacotes na hora da implementação): Phosphor (`@phosphor-icons/react`), Hugeicons (o pacote para React mudou de nome entre versões), Radix Icons (`@radix-ui/react-icons`), Tabler (`@tabler/icons-react`), Lucide (`lucide-react`), Remix Icon. Se o projeto já tem uma, ela vence.
|
|
135
|
+
- Ícones direcionais espelham em RTL. Navegação só com ícones, sem rótulo, falha para quem não reconhece o símbolo.
|
|
136
|
+
|
|
137
|
+
## Superfícies do navegador
|
|
138
|
+
|
|
139
|
+
As partes que ninguém desenhou também carregam o design; o contrato as tematiza a partir da paleta:
|
|
140
|
+
|
|
141
|
+
- **Seleção de texto** (`::selection`) com par de cor que mantém 4.5:1.
|
|
142
|
+
- **Cursor de inserção** (`caret-color`) na cor de ação.
|
|
143
|
+
- **Barra de rolagem:** muda-se a cor (`scrollbar-color`, `scrollbar-width`), nunca o comportamento. Barra customizada que some, encolhe a área de toque ou rola diferente é reinvenção de affordance; em Operar, a affordance nativa é preservada.
|
|
144
|
+
- **Sublinhado de link** com `text-underline-offset` e espessura decididos, sem remover o sublinhado no meio de texto.
|
|
145
|
+
- **Numerais tabulares em dado** (`font-variant-numeric: tabular-nums`) em tabela, métrica e coluna que se compara; regras em [dados e densidade](dados-e-densidade.md).
|
|
146
|
+
- **Controles nativos** (checkbox, radio, range) com `accent-color` antes de qualquer reimplementação.
|
|
147
|
+
- **`color-scheme`** declarado para que formulários e barras nativas acompanhem o modo.
|
|
148
|
+
- **Anel de foco** com `outline` real (ou `box-shadow` mais `outline: 2px solid transparent`) para sobreviver a `forced-colors`; especificação em [componentes e estados](componentes-e-estados.md).
|
|
149
|
+
- **Cursor customizado** é default recusável (ver [anti-padrões](anti-padroes.md)): só em Experienciar, quando o cursor é parte da obra, com o cursor do sistema preservado sobre controles e texto e sem atraso de seguimento sob movimento reduzido. Fora disso, atrapalha quem depende do cursor do sistema (tamanho, contraste) e não traz informação.
|
|
150
|
+
|
|
151
|
+
## `forced-colors`
|
|
152
|
+
|
|
153
|
+
Em `forced-colors: active`, sombras, gradientes e fundos translúcidos somem. Todo limite de componente, estado selecionado e indicador de foco que dependia deles ganha `border` ou `outline` reais. Ícones SVG usam `currentColor`. Não tente reimpor a paleta da marca nesse modo: o sistema decide as cores.
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
<!-- Derivado de Impeccable (Apache-2.0, Paul Bakaus), design-taste-frontend e high-end-visual-design (MIT, Leonxlnx), design-system (MIT, claudekit) e platform-design-skills (MIT, ehmo); reescrito e modificado pelo Crow em 2026-11-13. Ver ../NOTICE.md. -->
|
|
2
|
+
# Texto e conteúdo
|
|
3
|
+
|
|
4
|
+
Leia quando o contrato for especificar o vocabulário da interface, mensagens de estado, formulários, pontuação, tradução, conteúdo de exemplo, imagens, logos, depoimentos ou qualquer asset que vai para a entrega.
|
|
5
|
+
|
|
6
|
+
## Texto é conteúdo de projeto
|
|
7
|
+
|
|
8
|
+
O contrato especifica o vocabulário com o mesmo cuidado que especifica espaçamento. Texto que fica para depois é escrito na pressa da implementação, uma tela de cada jeito.
|
|
9
|
+
|
|
10
|
+
- **Nome pelo que a pessoa entende, não pela implementação.** Alguém gerencia notificações, não configura webhooks; arquiva uma conversa, não muda o status para 3.
|
|
11
|
+
- **Uma ação, um nome, do começo ao fim.** O botão "Publicar" produz a confirmação "Publicado" e o filtro "Publicados"; não "Postar" num lugar, "Enviar" no outro e "Ativo" no terceiro. A mesma palavra para o mesmo conceito em toda a superfície; em interface, variar o termo por elegância literária é defeito.
|
|
12
|
+
- **Verbo mais objeto, descrevendo o resultado,** quando o resultado não é óbvio: "Salvar alterações", "Enviar convite", "Exportar CSV". O rótulo diz o que vai acontecer, não o gesto ("Clique aqui").
|
|
13
|
+
- **Destrutiva nomeia o objeto e a consequência:** "Excluir projeto e as 14 tarefas dele". Quando a recuperação é segura, **desfazer vem antes de confirmação**: excluir na hora e oferecer "Desfazer" é mais rápido e mais honesto do que perguntar "Tem certeza?". Quando a confirmação é necessária, a pergunta e o botão repetem a ação ("Excluir projeto?" / "Excluir projeto").
|
|
14
|
+
- **Nada de Sim, Não, OK, Enviar genéricos.** Eles obrigam a ler a pergunta de novo para saber o que cada um faz.
|
|
15
|
+
- **Voz ativa, caixa de frase, a língua do produto.** Caixa alta só em sigla. Um registro de texto por página: nada de manifesto num bloco e manual técnico no seguinte.
|
|
16
|
+
- **Cada ideia é dita uma vez.** Se o título já explica o estado, a introdução traz informação nova ou some.
|
|
17
|
+
|
|
18
|
+
A voz é constante; o tom se adapta ao momento (mais seco num erro de pagamento, mais leve num primeiro uso). Linguagem simples sem achatar o termo técnico que o público de fato conhece. Um glossário curto fixa os termos quando a inconsistência atravessa o produto.
|
|
19
|
+
|
|
20
|
+
## Hierarquia da mensagem
|
|
21
|
+
|
|
22
|
+
Para cada estado, o contrato decide, nesta ordem:
|
|
23
|
+
|
|
24
|
+
1. **O fato agora:** a única coisa que a pessoa precisa saber.
|
|
25
|
+
2. **A próxima ação:** o que ela pode fazer.
|
|
26
|
+
3. **O contexto que muda a decisão:** só o que altera a escolha (prazo, custo, o que se perde).
|
|
27
|
+
4. **O tom** adequado ao momento.
|
|
28
|
+
|
|
29
|
+
## Mensagens por tipo
|
|
30
|
+
|
|
31
|
+
**Erro.** Responde três perguntas: o que falhou; por quê, quando se sabe e ajuda; como recuperar ou que alternativa resta. Exemplo: "Não foi possível enviar a fatura. O e-mail do cliente está vazio. Adicione um e-mail e envie de novo." Sem código interno como mensagem principal (o código pode ir num detalhe para o suporte). Sem culpar a pessoa ("Você digitou errado"). Sem prometer causa ou solução que o sistema não conhece ("O servidor está em manutenção" quando só houve timeout). Privacidade, pagamento, exclusão, perda de acesso e trabalho bloqueado são tratados com seriedade: calor humano é bem-vindo, piada não. Erro perto da causa, sem apagar o que foi digitado.
|
|
32
|
+
|
|
33
|
+
**Carregando.** Nomeia a operação real ("Gerando relatório de outubro") e cria expectativa honesta quando a espera é significativa ("Costuma levar menos de um minuto" só se for verdade). Progresso determinado quando existe; nunca progresso inventado, nunca barra que anda sozinha até 90% e para.
|
|
34
|
+
|
|
35
|
+
**Vazio.** Diferencia os seis tipos canônicos (primeiro uso; limpo pelo usuário; sem resultado de busca; filtro sem resultado; sem permissão; falha ao carregar), e cada um explica o estado e oferece a próxima ação útil (lista e formas completas em [componentes e estados](componentes-e-estados.md#estado-vazio)). "Nenhum resultado" sozinho é beco sem saída: diga qual consulta, sugira ajuste, ofereça limpar.
|
|
36
|
+
|
|
37
|
+
**Sucesso.** Confirma o resultado concluído, curto: "Convite enviado." Menciona a próxima consequência só quando muda o que a pessoa deve fazer ("Convite enviado. Ele expira em 7 dias."). Sucesso rotineiro não grita nem comemora.
|
|
38
|
+
|
|
39
|
+
**Permissão.** Diz que o recurso existe, por que não está acessível e quem concede: "Este relatório é restrito à equipe financeira. Peça acesso a quem administra a conta."
|
|
40
|
+
|
|
41
|
+
**Ajuda e instrução.** O texto de ajuda responde a pergunta implícita em vez de repetir o controle ("Usamos o telefone só para recuperar a conta", não "Digite seu telefone"). Detalhe incomum fica atrás de revelação progressiva. Texto de link faz sentido fora de contexto ("Ver política de reembolso", não "Clique aqui" nem "Saiba mais" repetido cinco vezes). Controle só com ícone tem nome acessível.
|
|
42
|
+
|
|
43
|
+
## Formulários
|
|
44
|
+
|
|
45
|
+
- Rótulo persistente; placeholder é exemplo do formato, não rótulo.
|
|
46
|
+
- Requisitos de formato e elegibilidade antes do envio, junto do campo.
|
|
47
|
+
- Dizer por que a informação é pedida só quando não é óbvio.
|
|
48
|
+
- Obrigatório e opcional com tratamento consistente.
|
|
49
|
+
- Validação diz o que precisa de atenção e como corrigir, sem culpar, perto do campo, anunciada de forma acessível (mecânica em [componentes e estados](componentes-e-estados.md)).
|
|
50
|
+
|
|
51
|
+
## Como auditar o texto que o contrato propõe
|
|
52
|
+
|
|
53
|
+
Leia o fluxo inteiro, não strings soltas, e passe por oito perguntas: há ambiguidade (substantivo, verbo, ação)? jargão ou conhecimento suposto? rótulo, resultado ou estado vago? falta a consequência, a recuperação ou o prazo? a terminologia ou a caixa é inconsistente? há redundância (título, introdução, ajuda e confirmação dizendo o mesmo)? o texto quebra em largura realista ou traduzido? o tom ignora estresse, risco, sucesso ou urgência?
|
|
54
|
+
|
|
55
|
+
Depois, para copy **gerada**, uma releitura de cada string: reescreva o que estiver gramaticalmente quebrado, com referente obscuro, com cara de alucinação ou de texto tentando soar profundo. O texto final é o mais curto possível sem perder sentido nem recuperação; cortar não é meta, é consequência.
|
|
56
|
+
|
|
57
|
+
Verificação do texto no contrato: compreensível sem conhecimento escondido do produto; acionável em erros, vazios e pontos de decisão; factualmente correto; consistente; varrível nas larguras alvo e com zoom de 200%; resistente a nome longo, expansão de tradução, plural e valor dinâmico; nomes acessíveis e anúncios de estado definidos; tom proporcional à consequência.
|
|
58
|
+
|
|
59
|
+
## Texto fornecido e claims
|
|
60
|
+
|
|
61
|
+
A heurística anti-clichê e a releitura valem para copy que você está gerando. **Texto fornecido pelo dono ou pelo cliente não é reescrito**: ele entra como veio, e qualquer sugestão vai separada, como proposta. Pergunte antes de mudar uma alegação factual, um sentido jurídico, um termo que pode ser de domínio ou um número. Quando há uma composição aprovada com texto, as palavras dela entram literalmente; reescrever é decisão declarada. Textos legais, de consentimento e de cookies não mudam sem aprovação.
|
|
62
|
+
|
|
63
|
+
## Pontuação por locale
|
|
64
|
+
|
|
65
|
+
A pontuação segue as convenções do idioma do produto, e o contrato escreve os caracteres reais, não os aproximados do teclado:
|
|
66
|
+
|
|
67
|
+
- **Português do Brasil:** o travessão (—) é legítimo em diálogo, aposto e inciso; o meia-risca (–) é o caractere certo para intervalos ("2018–2026", "R$ 40–80 mil", "segunda–sexta"); aspas curvas “ ” e, dentro delas, ‘ ’; reticências como caractere (…) em estados de carregamento.
|
|
68
|
+
- **Inglês:** as mesmas aspas curvas “ ” ‘ ’, meia-risca em intervalos, travessão conforme o guia de estilo adotado.
|
|
69
|
+
- **Francês e outros locales que usam guillemets:** « » com o espaço que a norma local pede.
|
|
70
|
+
- Aspas retas (" ') não são aspas tipográficas; exemplo de aspas tipográficas escrito com aspas retas ensina o erro.
|
|
71
|
+
|
|
72
|
+
Há um vício de texto gerado, sobretudo em inglês, que usa travessão como muleta para emendar frases. A heurística contra ele vale **só para copy gerada** e consiste em preferir pontuação mais simples quando o travessão não está fazendo trabalho gramatical. Ela nunca reescreve texto fornecido, nunca proíbe o caractere, nunca troca o meia-risca de um intervalo por hífen e nunca se sobrepõe ao locale. O ponto médio (·) como separador de metadados é usado com parcimônia: no máximo um por linha.
|
|
73
|
+
|
|
74
|
+
## i18n das strings
|
|
75
|
+
|
|
76
|
+
- Mensagens inteiras traduzíveis; nada de concatenar fragmentos ("Você tem " + n + " novas " + "mensagens") que impedem a tradução de reordenar a frase.
|
|
77
|
+
- Variáveis e números estruturados com nome, para que o tradutor possa movê-los ("{count} faturas vencem em {date}").
|
|
78
|
+
- Plural pelas regras do idioma (há idiomas com mais de duas formas), não por "s" condicional.
|
|
79
|
+
- Espaço para expansão de 30 a 40% em vez de abreviar cedo; nenhum contêiner de texto com largura fixa.
|
|
80
|
+
- Datas, horas, números e moedas formatados pelo locale.
|
|
81
|
+
- Glossário de termos por idioma, para que "projeto" não vire três palavras diferentes na tradução.
|
|
82
|
+
- Nada de texto embutido em imagem.
|
|
83
|
+
|
|
84
|
+
## Limites por medida visual
|
|
85
|
+
|
|
86
|
+
Limites de tamanho de texto são definidos pela composição, em linhas e largura, e testados com a tradução mais longa; contagem de palavras em inglês não serve para português, alemão ou qualquer outro idioma. Como heurísticas de composição, com motivo e escape:
|
|
87
|
+
|
|
88
|
+
- **Título do hero:** até duas linhas no desktop. Quatro linhas costumam ser erro de tamanho de fonte, não de texto. Cede quando o mundo da direção é tipográfico e o título é a própria peça.
|
|
89
|
+
- **Subtítulo do hero:** até três ou quatro linhas na largura de leitura.
|
|
90
|
+
- **Título de seção:** uma ou duas linhas; subtítulo curto o suficiente para ser lido de relance.
|
|
91
|
+
- **CTA:** uma linha no desktop, sem `max-width` que force quebra.
|
|
92
|
+
- **Citação:** até três linhas na composição.
|
|
93
|
+
- **Texto corrido:** medida de 45–75ch, alvo 60–70ch.
|
|
94
|
+
|
|
95
|
+
Quando o texto real ou traduzido não cabe, o contrato muda a composição ou o tamanho; não corta o texto em silêncio.
|
|
96
|
+
|
|
97
|
+
## Clichês gerados a evitar
|
|
98
|
+
|
|
99
|
+
Valem para copy gerada. Se o dono ou a marca usam uma dessas palavras de propósito, ela fica.
|
|
100
|
+
|
|
101
|
+
- **Verbos e adjetivos de enchimento:** "elevar", "potencializar", "alavancar", "sem atrito", "sem complicação", "desbloquear", "liberar o potencial", "revolucionar", "próxima geração", "de ponta", "transformar a forma como você…", "tudo em um só lugar", "feito para você"; em inglês, *elevate*, *seamless*, *unleash*, *unlock*, *next-gen*, *revolutionize*, *supercharge*, *empower*, *effortless*, *cutting-edge*, *game-changer*.
|
|
102
|
+
- **Prova social ensaiada:** "silenciosamente usado por", "a escolha discreta de", *quietly in use at*, *quietly trusted by*, *trusted by teams at* sem relação comprovada.
|
|
103
|
+
- **Rótulos poéticos acima do conteúdo:** "Do campo", "Notas de campo", "Na bancada agora", "Na nossa mesa", "Pranchas soltas"; *From the field*, *Field notes*, *Currently on the bench*, *On our desks*, *Loose plates*.
|
|
104
|
+
- **Humildade encenada:** referências fingidamente modestas ("Respeitamos os franceses", *We respect the French ones*).
|
|
105
|
+
- **Micro-frase meta** sob um rótulo, explicando a seção em vez de ser a seção ("Cada um destes é um recurso que entregamos hoje…").
|
|
106
|
+
- **Rótulo de etapa genérico:** "Etapa 1", "Passo 01", "Fase um", *Stage 1*, *Step 1*, *Phase 01*, *Pass One*; use o verbo da etapa ("Conecte sua conta").
|
|
107
|
+
- **Faixa decorativa de palavras** no pé do hero ("MARCA. MOVIMENTO. ESPAÇO.", "DESENHAR · CONSTRUIR · ENTREGAR").
|
|
108
|
+
- **Cromo de metadado:** rótulo de versão no hero ("v2.0", "BETA", "ACESSO ANTECIPADO") fora de um lançamento real; rodapé de versão ou build em página de marketing; contador de estoque decorativo ("Reserva 412 de 800"); faixa de cidade, hora e clima ("LIS 14:23 · 18°C") salvo estúdio distribuído, marca de viagem ou local físico real; sub-rótulo "Marca · Nº 01"; intervalo de anos como rótulo ("Índice de trabalhos, 2018–2026"); chamada para rolar ("Role para explorar", seta, ícone de mouse); "PALAVRA — fragmento" como padrão de rótulo.
|
|
109
|
+
- **CTAs de mesma intenção duplicados** na mesma página: "Fale conosco", "Entre em contato", "Vamos conversar", "Comece um projeto", *Get in touch*, *Contact us*, *Let's talk*, *Reach out* são todos contato; "Teste grátis", "Começar", "Cadastre-se grátis", *Try free*, *Get started*, *Sign up free* são todos cadastro; "Ver trabalhos", "Ver projetos selecionados", *View work*, *Browse projects* são todos portfólio. Um rótulo por intenção.
|
|
110
|
+
- **Nomes de template:** empresas Acme, Nexus, SmartFlow, Cloudly e afins; pessoas "Fulano de Tal", "João Silva", *Jane Doe*, *John Smith*.
|
|
111
|
+
|
|
112
|
+
## Honestidade de conteúdo e assets
|
|
113
|
+
|
|
114
|
+
**Conteúdo real primeiro.** O contrato usa o conteúdo real que existe. Quando falta, o conteúdo de exemplo é rascunho plausível **rotulado como ilustrativo**: no protótipo, por um atributo ou componente de placeholder visível (não só um comentário no código), e no contrato, numa **lista de substituição** entregue ao dono, com onde está cada mock e o que precisa entrar no lugar. A lista é **bloqueante**: nada é publicado enquanto ela tiver itens abertos.
|
|
115
|
+
|
|
116
|
+
**Proibido, sob qualquer brief:**
|
|
117
|
+
- Depoimento, pessoa, cargo, cliente, avatar ou logo de terceiro inventados com cara de reais.
|
|
118
|
+
- Métrica, percentual, preço, contagem de clientes, benchmark, prêmio ou data inventados com aparência de medidos. Precisão falsa ("47,2%", "4,1×", "48 mil", "13,4 kg") é aceitável só quando vem de dado real ou está visivelmente rotulada como exemplo; "dado orgânico e bagunçado" inventado para parecer real é a mesma falsificação, mais convincente.
|
|
119
|
+
- Screenshot de produto falso montado com divs, rodapé de versão inventado dentro dele ("v0.6.2-rc.1"), "última sincronização há 4s". Use captura real, preview com o componente real ou foto editorial rotulada.
|
|
120
|
+
- Telefone, e-mail ou endereço que podem pertencer a alguém. E-mail em domínio reservado e marcado como exemplo: `nome@example.com` (também `example.org`, `example.net`) ou o TLD `.test` (`contato@exemplo.test`). Telefone: o Brasil **não tem faixa reservada para ficção** (prefixos de aparência fictícia costumam ser válidos e discáveis), então use placeholder não discável e rotulado, como `(00) 0000-0000` com a etiqueta "exemplo"; a faixa 555-0100 a 555-0199 só vale para números dos EUA.
|
|
121
|
+
- Nome de exemplo com aparência de pessoa real sem rótulo. Quando o mock precisa de nome, use um plausível para o locale e rotule.
|
|
122
|
+
|
|
123
|
+
**Logos de terceiros** só com relação comprovada (cliente, parceiro, integração real), seguindo as diretrizes de uso de cada marca. Quando a relação existe, a parede de logos mostra só os logos, sem rótulo de categoria embaixo (o nome vai no `alt`), legíveis nos dois modos, abaixo do hero e não dentro dele. Fontes de SVG de marca: Simple Icons e devicon, usados só com relação comprovada, apenas o logo (sem compor com outros elementos), com `alt` e legível nos dois modos; as diretrizes da própria marca prevalecem sobre a versão do repositório. Para marca inventada em protótipo, um monograma simples rotulado como provisório. O logo do próprio produto vem do dono.
|
|
124
|
+
|
|
125
|
+
**Imagens:**
|
|
126
|
+
- Prioridade: asset real do dono ou cliente; depois asset licenciado com origem registrada; depois placeholder rotulado nas dimensões certas.
|
|
127
|
+
- **Placeholder** (serviço de imagem aleatória como o picsum, retângulo cinza com dimensões) nunca é entregável final; leva rótulo visível e entra na lista de substituição com tamanho e assunto ("foto de produto em uso, 1600×1200").
|
|
128
|
+
- **Imagem gerada** só com consentimento do dono, para mood, textura ou ilustração, rotulada como gerada, com prompt ou origem registrados, e **nunca representando o produto real**, pessoa real ou resultado prometido.
|
|
129
|
+
- **Referência colhida em busca, pin ou feed** serve para conversar sobre direção e não entra no entregável.
|
|
130
|
+
- **Fotos de pessoas** de banco de imagens têm restrições de licença comuns: pessoa identificável não pode aparecer endossando produto, nem em contexto sensível (saúde, finanças, política) sem autorização de modelo; marcas visíveis na foto têm direitos próprios. "Grátis para usar" não quer dizer "grátis para qualquer uso".
|
|
131
|
+
- **Proveniência por asset:** todo asset que entra (imagem, ícone, ilustração, fonte, vídeo, som) tem origem, licença, uso permitido e, quando gerado, o prompt registrados no contrato. Fonte: a da marca primeiro; depois livre (OFL, Fontshare) ou comercial com licença declarada e um fallback livre equivalente; nunca supor que uma fonte comercial "está disponível".
|
|
132
|
+
|
|
133
|
+
**Página só de texto.** Quando o assunto pede imagem, texto puro não é minimalismo e um hero de texto com mancha de gradiente não é hero: duas ou três imagens reais (hero, produto ou uso, apoio) costumam bastar. Quando o modo é Ler e a direção é tipográfica, texto puro é decisão legítima. SVG decorativo desenhado à mão é desencorajado; entra quando pedido, quando é marca geométrica simples ou geometria exata (diagrama, forma, linha animada).
|
|
134
|
+
|
|
135
|
+
**Emoji** não entra em interface, markup ou texto por padrão; uma voz lúdica, social ou de chat pode liberar com parcimônia, nunca como ícone e nunca no `alt`.
|
|
136
|
+
|
|
137
|
+
**Depoimentos e citações** só reais e autorizados, com nome, cargo e, quando houver, empresa, em aspas tipográficas do locale, até três linhas na composição.
|
|
138
|
+
|
|
139
|
+
## Alt text e nome acessível
|
|
140
|
+
|
|
141
|
+
- **Imagem informativa:** o `alt` transmite a informação que a imagem carrega no contexto ("Gráfico: vendas cresceram 12% de setembro a outubro"), não a descrição da foto ("gráfico azul"). Imagem com texto tem o texto no `alt`.
|
|
142
|
+
- **Imagem decorativa:** `alt=""` (vazio, presente), para o leitor de tela pular.
|
|
143
|
+
- **Imagem que é link ou botão:** o `alt` diz o destino ou a ação.
|
|
144
|
+
- **Nome acessível igual ao rótulo visível:** o nome que o leitor de tela anuncia contém o rótulo visível, de preferência começando por ele (quem usa comando de voz diz o que vê: "clicar Salvar alterações"). Um botão que mostra "Salvar" e anuncia "Enviar formulário" quebra isso.
|
|
145
|
+
- Pontuação, cor ou ícone sozinhos não carregam a mensagem.
|
|
146
|
+
|
|
147
|
+
## Protótipo não é publicação
|
|
148
|
+
|
|
149
|
+
Protótipo, composição ou mock não é código integrado nem autorização para publicar conteúdo. Canvas ou geração externa entram só quando o pedido exige e a ferramenta está disponível, com contexto mínimo e não sensível. Imagens temporárias seguem a política de retenção do projeto.
|