# Tokens e temas

A fonte autoral é `src/css/style.css`. O comando `npm run tokens` (ou `node scripts/generate-design-system.mjs`) gera `design-system/tokens.css`, `tokens.json` e `troca-pontos.css`, com hash da fonte no JSON. Não edite exports. `npm run check:design-system` detecta dessincronização, calcula os pares de contraste documentados (26 pares nos dois temas), recusa `var(--tp-*)` sem declaração e token `--tp-*` declarado fora de `TP:SEMANTICS` (os locais de `TP:GRAPHICS` e `TP:BRIDGE` são exceção) e confere o catálogo estático do portal (`tokens-catalogo.html`) contra `tokens.json`. O catálogo é copiado à mão: quando um valor muda, a linha dele muda junto.

## Três níveis

| Nível | Contrato | Origem |
| --- | --- | --- |
| Primitivos | `--color-brand-primary/dark/mid/accent/soft`, `--color-palette-*` | HEX conferidos no manual pp.26–34 |
| Semânticos | `--tp-text`, `--tp-muted`, `--tp-page`, `--tp-surface`, `--tp-action`, `--tp-on-action`, `--tp-border-strong`, `--tp-focus`, estados e gráficos | Aplicações digitais e extensões de engenharia |
| Contexto | `--tp-control-height`, `--tp-cell-padding`, `--tp-card-radius`, `--tp-logo-width/protection` | Propostas reversíveis para ERP, institucional e proteção da marca |

### Escalas 1.0.0

Além dos nomes históricos compatíveis, a versão 1.0.0 publica aliases formais para consumo novo:

| Grupo | Exemplos |
| --- | --- |
| Superfície/texto/borda | `--tp-surface-page`, `--tp-surface-card`, `--tp-text-primary`, `--tp-text-secondary`, `--tp-border-default` |
| Ação e estados | `--tp-action-primary`, `--tp-action-primary-hover`, `--tp-status-success-*`, `--tp-status-warning-*`, `--tp-status-danger-*`, `--tp-status-info-*` |
| Tipografia | `--tp-type-display-lg-*`, `--tp-type-heading-lg-*`, `--tp-type-body-md-*`, `--tp-type-label-md-*`, `--tp-type-caption-*` |
| Espaço/forma | `--tp-space-0` a `--tp-space-9`, `--tp-radius-none` a `--tp-radius-full`, `--tp-elevation-0` a `--tp-elevation-overlay` |
| Motion/layout | `--tp-duration-fast/normal/slow`, easing semântico e `--tp-breakpoint-mobile/tablet/desktop/wide` |
| Componente | `--tp-component-button-*`, `--tp-component-field-min-height`, `--tp-component-message-max-width`, `--tp-component-composer-min-height` |

Cada token tipográfico publica família, tamanho, peso, line-height e letter-spacing como propriedades separadas. O `tokens.json` é a referência legível por ferramenta; o CSS continua sendo a fonte de verdade.

As escalas `brand-25…950`, `gray-*`, `blue-light-*`, `success-*`, `error-*`, `warning-*`, `orange-*` preservam contratos legados. `blue-light` passa a apontar para a família de roxos em componentes internos. Nomes históricos não representam outra identidade. Escalas intermediárias são derivados técnicos, não novas cores oficiais. Os 25 primitivos secundários/cinzas continuam exatamente como no PDF.

## Uso das cores secundárias

O manual repete a mesma frase nas pp.27, 28, 29, 30, 31 e 32: "Utilize as cores secundárias **apenas** em materiais específicos que necessitem desse uso, como gráficos, tabelas e planilhas." As pp.27–30 acrescentam que "essas cores só podem ser utilizadas em materiais com fundo da paleta de roxos institucionais ou fundos claros"; as pp.31–32 reescrevem a mesma regra como "fundos claros ou escuros, **exceto a cor Russian violet, que não deve ser aplicada em fundo escuro**".

Em termos de token:

| Grupo | Tokens | O que a norma permite |
| --- | --- | --- |
| Primárias (p.26) | `--color-brand-primary/dark/mid/accent/soft` | Todos os materiais gráficos e digitais. `--color-brand-dark` é Russian violet e carrega a exceção das pp.31–32: não aplicar em fundo escuro |
| Secundárias (pp.27–32) | os 20 `--color-palette-*` de Orange a Azure | Apenas gráficos, tabelas, planilhas e materiais equivalentes, sobre fundo de roxo institucional ou fundo claro. Não são cor de superfície, de marca nem de interface |
| Cinzas (p.33) | `--color-palette-davys/battleship/silver/platinum/smoke` | Chamadas, textos, elementos de interface e áreas de fundo. **Não** estão sujeitos à restrição das secundárias |

A restrição viaja com o token, não só com este texto. `design-system/tokens.json` publica um campo `restriction` ao lado de `origin` em cada `--color-palette-*` e em `--color-brand-dark`, com a página do manual citada. `src/js/brand-tokens.js` traz a mesma regra em `secondaryUse`, com a lista das 20 chaves sujeitas a ela, para quem consome a paleta por JavaScript.

Onde o projeto usa secundárias fora desse recorte — estados de sucesso, erro e alerta, CTA amarelo, escalas `orange-*`, `success-*`, `error-*`, `warning-*` — trata-se de extensão digital registrada, não de aplicação da norma. Essas extensões continuam pendentes de homologação e devem ser lidas junto com `decisoes-e-divergencias.md`.

### Gradientes

A p.34 define cinco pares e o projeto publica os cinco, sempre por token de marca e nunca por hexadecimal literal.

**Corrigido em 22/09/2026: três dos cinco estavam invertidos.** A p.34 em vetor desenha cada par como uma coluna que corre de cima para baixo. Lidos os `stop` do SVG — `y1` no pé da coluna, `y2` no topo —, as paradas de topo e de base são:

| Token | Topo (primeira parada) | Base | Estava documentado como | |
| --- | --- | --- | --- | --- |
| `--tp-gradient-deep` | Purple `#6B0080` | Russian violet `#4B005A` | Russian violet → Purple | **invertido** |
| `--tp-gradient-primary` | Mauveine `#81009B` | Purple `#6B0080` | Purple → Mauveine | **invertido** |
| `--tp-gradient-vivid` | Phlox `#D500FF` | Mauveine `#81009B` | Mauveine → Phlox | **invertido** |
| `--tp-gradient-royal` | Mauveine `#81009B` | Russian violet `#4B005A` | Mauveine → Russian violet | confere |
| `--tp-gradient-bright` | Phlox `#D500FF` | Purple `#6B0080` | Phlox → Purple | confere |

O CSS seguia esta tabela, então os três também estavam invertidos ali. Os cinco passam agora a começar pela **ponta clara** da rampa, que é a leitura da prancha e o extremo de que a regra de contraste abaixo depende. `fundamentos-de-marca.md` já listava os cinco pares na ordem certa.

| Token | Par do manual (topo → base) | Utilitário |
| --- | --- | --- |
| `--tp-gradient-deep` | Purple → Russian violet | `bg-tp-gradient-deep` |
| `--tp-gradient-primary` | Mauveine → Purple | `bg-tp-gradient` |
| `--tp-gradient-vivid` | Phlox → Mauveine | `bg-tp-gradient-vivid` |
| `--tp-gradient-royal` | Mauveine → Russian violet | `bg-tp-gradient-royal` |
| `--tp-gradient-bright` | Phlox → Purple | `bg-tp-gradient-bright` |

Inverter a direção não muda o par de cores, só qual extremo fica claro — nenhum par de contraste medido mudou de valor com a correção.

O manual pede gradientes sutis, como complemento das primárias. Texto sobre gradiente depende da parada mais clara: os grafismos institucionais param em Mauveine porque Phlox como fundo derruba o texto branco abaixo de AA.

### A rampa de roxos das pp.08 e 21, e o fundo de prova da p.32

Duas coisas que as pranchas trazem e que não são cor de paleta:

| Tokens | O que são |
| --- | --- |
| `--color-brand-ramp-1..5` (`#4B005A`, `#65007A`, `#7E0098`, `#9700B5`, `#AF00D1`) | Os **cinco fundos autorizados** da versão secundária negativa (p.08), e os mesmos cinco fundos dos ícones na p.21. Os passos 2–4 são interpolações que só existem nesta rampa; não são cor de interface, de marca nem de superfície, e não entram na paleta de 30. A p.08 desenha a quinta parada em `#B000D3` e outras quatro pranchas em `#AF00D1` — mesma parada, arredondamento do Illustrator |
| `--color-brand-proof-dark` (`#40004F`) | O retângulo escuro da p.32, o fundo contra o qual o manual valida as 25 secundárias e proíbe o Russian violet. Existe para que o teste do manual possa ser reproduzido com a mesma tinta; **não** é fundo de página nem token escuro do tema |

### A grade de desenho de ícone (pp.22–24)

| Token | Valor | Origem |
| --- | --- | --- |
| `--tp-icon-grid` | `24px` | “utilize o tamanho de 24x24 px” |
| `--tp-icon-artboard` | `48px` | “dentro de um artboard de 48x48 px” |
| `--tp-icon-stroke` | `2` | “considere 2 px para a espessura do traçado” |
| `--tp-icon-corner-min` / `-max` | `1px` / `4px` | “cantos arredondados entre 1 px e 4 px” |

`.tp-icon`, a família de ícone **da marca**, consome `--tp-icon-grid` e `--tp-icon-stroke`. A iconografia de interface herdada do TailAdmin é outra família, registrada em **D15** com a medição: 111 ícones de 24×24 nos partials, 98 abaixo de 2 px.

## Semântica acessível

`#25002D` é tinta reproduzida no guia, não sexto roxo oficial. Estados claros usam foregrounds derivados `#00664E`, `#B0003B` e `#765D00`; preservam as cores oficiais separadas porque sua combinação direta com branco nem sempre atende texto pequeno. Fundos claros e escuros, texto secundário, borda de campo, foco e tooltip são medidos em `evidencias/verificacao-estatica.json`. CTA amarelo é extensão demonstrada e pendente de homologação.

O tema claro usa ação Purple/branco; o escuro usa ação clara/tinta roxa. Aplique `.dark` ou `data-theme="dark"` no elemento raiz (`html`); no adaptador, o `body` Alpine sincroniza o raiz. Semânticos de gráficos e tooltip mudam em conjunto. Não inverter imagens ou logos por filtros.

## Onde aplicar tema, densidade e perfil

Os aliases (`--tp-surface-card`, `--tp-radius-md`, `--tp-component-*` e os demais nomes formais) são declarados no `:root`. Custom property é calculada no elemento que a declara: um contexto aplicado só a um contêiner troca o token de origem, mas o alias já chega calculado de cima.

| Contexto | Onde aplicar | Por quê |
| --- | --- | --- |
| Tema (`.dark`, `data-theme="dark"`) | Só no raiz | Com o tema num contêiner, `.tp-card` escurece, mas `.tp-button-primary`, `.tp-status-badge` e `.tp-toast` continuam claros; o nome em `.tp-cell-user` sobre `.tp-card` cai para 1,17:1 (medido). O bloco escuro redeclara só os aliases que precisam valer dentro dele: `--tp-chart-text`, `--tp-chart-grid` e `--tp-component-focus-ring`. A correção estrutural (declarar o bloco de aliases também nos seletores de contexto e ajustar o gerador) está planejada, não feita |
| Densidade (`data-density="compact"`) | Raiz ou contêiner | O bloco compacto redeclara os três aliases que leem `--tp-control-height`, e o tamanho padrão de `.tp-button` e `.tp-input` reduz o padding vertical. Medido em `padroes-erp.html`: botão e campo 44 → 36 px, célula 16 → 8 px |
| Perfil institucional (`data-profile="institutional"`) | Só no raiz | Não é aplicado em nenhuma página hoje. Os aliases `--tp-radius-md/lg` e as alturas de componente têm o mesmo limite do tema. No perfil, md (12 px) e lg (24 px) passam de xl (18 px) e a escala deixa de ser crescente |
| Superfície de marca (`.tp-hero`, `.tp-inverse-stage`, `.tp-journey`, `.tp-graphic-gradient`, `.tp-graphic-on-brand`, `.tp-brand-panel`) | Automático | O foco roxo some sobre o gradiente (1,15–1,34:1 no claro). Ali `--tp-focus` vira branco (11,8–14,5:1 nos dois temas) e o anel é redeclarado; `.tp-card` e `.tp-journey-card` dentro dessas superfícies voltam ao foco do tema |

Regra para contexto novo: se ele muda `--tp-focus`, redeclara `--tp-component-focus-ring` no mesmo bloco. O check recusa a ausência.

## Escalas e contexto

- Espaço: 4 px técnico; 8/12/16/24/32/48 px do guia. `--tp-section-mobile/tablet/desktop` (68/82/104 px) registram a referência da landing e **não estão aplicados**: `.tp-site-section` renderiza 48/64/80 px. Aplicar muda `institucional.html` e depende de aprovação.
- Institucional: container 1200 px, raios 12/18/24/32/42 px. Valores anteriores 1180/10/16 no guia foram superados pela especificação consolidada; não existem duas definições autorais concorrentes.
- ERP: controle confortável 44 px e compacto 36 px, células 16/8 px (`.tp-table` lê `--tp-cell-padding`), corpo 14/13 px. Vale no raiz ou num contêiner. Proposta de engenharia para densidade operacional; não usar automaticamente raios de hero em formulários.
- Raio: none 0, xs 4, sm 6, md 8, lg 12, xl 18, 2xl 20, 3xl 24, full. A direção dos aliases é esta: `--tp-radius-md` lê `--tp-radius` e `--tp-radius-lg` lê `--tp-card-radius`; os nomes de contexto são a origem porque é neles que o perfil institucional atua. `--tp-component-card-radius` aponta para `--tp-radius-xl`, o raio que o `.tp-card` usa. `--radius-editorial-sm/md/lg/xl` (12/18/24/32) repetem os sufixos com outros valores: não trocar um pelo outro. O passo 18 → 20 (xl → 2xl) é irregular e fica como está.
- Tipografia: fontes, pesos, tamanhos, entrelinha e tracking em `@theme` e semânticos. Números tabulares em `.tp-numeric` (que também impede a quebra: use em valor, não em frase).
- Foco: 3 px com afastamento de 3 px, lidos de `--tp-component-focus-ring`; bordas relevantes usam `--tp-border-strong`. Bordas decorativas podem ser mais suaves. Em item de largura total dentro de lista rolável (`.tp-inbox-item`, `.tp-template-item`, `summary` de `.tp-chart-data`) o afastamento é negativo: o anel é desenhado por dentro, porque o `overflow` cortava o anel externo.
- z-index por papel: `--tp-z-dropdown` (30) para menu e tooltip ancorados em componente (`.tp-menu`, `.tp-tooltip`); `--tp-z-popover` (35) para o mega menu e a CTA móvel; `--tp-z-sticky` (40) para o cabeçalho; `--tp-z-menu` (50) para os painéis do cabeçalho do portal e a dica do mapa de calor (`.tp-reference-panel`, `.tp-heatmap-tooltip`). Dropdown e menu fazem o mesmo papel com valores diferentes; não criar um terceiro. `--tp-z-overlay` (99999) é degrau de página: o véu de carga só o usa dentro do contexto de empilhamento que o host ocupado cria.
- Sinônimos: `--tp-text-muted` ≡ `--tp-text-secondary` e `--tp-elevation-overlay` ≡ `--tp-elevation-2` estão **depreciados** (use o segundo nome). `--tp-border-subtle` ≡ `--tp-border-default` nos dois temas: decidir se ele deve ser de fato mais suave antes de usar. `--tp-action-primary-hover` ≡ `--tp-action-primary-active` e `--tp-z-dialog` ≡ `--tp-z-drawer` são iguais hoje e podem divergir.
- `--tp-overlay` (tinta a 55%) não tem consumidor: `.tp-dialog::backdrop` usa Russian violet a 55% literal. Falta decidir a cor; depois o backdrop passa a ler o token (ver `decisoes-e-divergencias.md`, D22).
- Elevação, opacidade desabilitada, z-index, duração de 160 ms e easing são propostas técnicas. Movimento reduzido neutraliza transições e animações.
- Breakpoints semânticos do Design System: mobile 620 px, tablet 860 px, desktop 1120 px e wide 1440 px. Os breakpoints legados do TailAdmin continuam disponíveis para páginas preservadas; 320/390/620/860/1120/1440 são cenários de QA.

## JavaScript

`src/js/design-tokens.js` resolve custom properties para bibliotecas. O adaptador de gráficos guarda a instância, observa mudança de tema e atualiza opções visuais. Séries, cálculos e eventos mantêm seus dados. Trilhas de gráfico radial usam `var(--tp-chart-grid)`, o mesmo neutro das grades; `neutral()` de `brand-tokens.js` ficou sem consumidor (hex fora do CSS, lido uma vez só) e não deve voltar a ser usado. Cores de mapas de terceiros e logos de integração não devem ser trocadas como se fossem paleta interna.

## Distribuição

O núcleo CSS combina tokens, regras CORE e COMPONENTS; o bloco PORTAL não participa. O exemplo `examples/minimo/index.html` consome apenas o núcleo e JavaScript nativo. A versão completa dos componentes interativos depende de Alpine v3 já presente no projeto; HTML includes são resolvidos por Webpack, sem parâmetros fictícios.
