# Tinyx Design System

Documentação oficial e fonte de verdade da biblioteca. Se o Design System mudou,
**este arquivo muda junto**: a regra é absoluta e está detalhada em
[Manutenção](#manutenção).

Este documento é escrito para pessoas **e** para agentes de IA. Cada componente tem
um bloco `AI Context` que descreve quando usá-lo, quando não usá-lo e com o que
combiná-lo.

---

## Sumário

1. [Visão geral](#visão-geral)
2. [Princípios](#princípios)
3. [Arquitetura](#arquitetura)
4. [Tokens](#tokens)
5. [Theme / Tenant Configuration](#theme--tenant-configuration)
6. [Light e Dark Theme](#light-e-dark-theme)
7. [Foundations](#foundations)
8. [Componentes](#componentes): Primitives · Controls · Composite · Patterns · Templates
9. [Acessibilidade](#acessibilidade)
10. [Responsividade](#responsividade)
11. [Motion](#motion)
12. [Estados de conteúdo](#estados-de-conteúdo)
13. [Convenções de nomenclatura](#convenções-de-nomenclatura)
14. [Manutenção](#manutenção)
15. [Changelog](#changelog)

---

## Visão geral

O Tinyx Design System é a **infraestrutura de interface do ecossistema Tinyx**. Ele não
pertence a nenhuma marca, produto ou tenant: é uma camada neutra e parametrizável que
vários produtos consomem ao mesmo tempo.

O que ele entrega:

- uma biblioteca de componentes componíveis, organizada em cinco setores;
- uma arquitetura de tokens em três camadas, de marca a componente;
- temas claro e escuro nativos, sem duplicar um único componente;
- personalização por tenant a partir de **quatro cores**;
- contexto de IA em todo componente;
- esta documentação, sincronizada com a biblioteca.

O que ele **não** é: um tema, uma marca, uma paleta institucional ou um produto. A
biblioteca sai de fábrica acromática de propósito.

### Como consumir

```html
<link rel="stylesheet" href="styles.css">
```

`styles.css` é o único caminho fixo. Ele importa fontes, ícones e todas as camadas de
token, nesta ordem: `brand → scales → typography → spacing → shape → elevation →
motion → layout → semantic → theme-dark → components → base`.

---

## Princípios

1. **O componente nunca pertence ao tenant.** Existe um `Button`. O que muda entre
   marcas é o tema, nunca o componente.
2. **Estrutura e identidade são camadas separadas.** Nenhum componente escreve um hex.
   Ele lê um token semântico, que lê um token de marca.
3. **Compor antes de criar.** Se um componente pode ser montado com peças existentes,
   ele é montado: `SearchInput` usa `Input`, `Pagination` usa os mesmos botões, `Field`
   embrulha qualquer controle.
4. **Variante antes de duplicata.** Diferença pequena vira propriedade, variante ou
   slot; nunca um componente novo.
5. **Hierarquia por tamanho e cor, não por peso.** A tipografia roda em um peso só nas
   superfícies de aplicação.
6. **Todo estado é declarado.** Carregando, vazio, erro, sem permissão e sem conexão são
   estados de primeira classe, com componente próprio.
7. **Movimento com propósito.** Animação contínua só onde algo está de fato acontecendo.
8. **Acessível por construção.** Contraste, foco visível, alvo mínimo e feedback que não
   depende só de cor fazem parte da definição de pronto.

---

## Arquitetura

```
Tenant configuration      4 cores
        ↓
Brand tokens              tokens/brand.css
        ↓
Derived scales            tokens/scales.css        50 → 900, por color-mix em oklab
        ↓
Semantic tokens           tokens/semantic.css      + tokens/theme-dark.css
        ↓
Component tokens          tokens/components.css    geometria e densidade
        ↓
Components                primitives → controls → composite → patterns → templates
        ↓
Product                   telas de qualquer produto do ecossistema
```

### Os cinco setores

| Setor | O que é | Pasta |
|---|---|---|
| **01 · Primitives** | Elementos fundamentais, sem lógica de negócio | `components/primitives/` |
| **02 · Controls** | Elementos interativos e de entrada | `components/controls/` |
| **03 · Composite** | Construídos a partir de outros componentes | `components/composite/` |
| **04 · Patterns** | Estruturas recorrentes completas | `components/patterns/` |
| **05 · Templates** | Estruturas de página e casca de aplicação | `components/templates/` |

Regra de dependência: um setor só importa de setores **anteriores** ou do próprio. Um
Primitive nunca importa um Pattern.

### Arquivos de um componente

```
<Nome>.jsx          implementação (React, sem dependências externas)
<Nome>.d.ts         contrato de propriedades
<Nome>.prompt.md    o que é, quando usar, exemplo
<setor>.card.html   uma galeria por pasta, com os estados visíveis
```

---

## Tokens

### Camada 1 · Brand (`tokens/brand.css`)

As únicas entradas que um tenant define.

| Token | Papel |
|---|---|
| `--brand-primary` | Ação principal: botão primário, item ativo, foco, seleção, link |
| `--brand-secondary` | Ações complementares, categorias, segunda série de dados |
| `--brand-neutral` | Base da escala estrutural: fundos, superfícies, bordas, textos |
| `--brand-accent` | Destaques, indicadores, dados |
| `--brand-success` `--brand-warning` `--brand-error` `--brand-info` | Estado. Comunicam significado, não identidade; mudam pouco entre marcas. |

### Camada 2 · Scales (`tokens/scales.css`)

Dez degraus por entrada: `--primary-50` … `--primary-900`, idem para secondary,
neutral e accent: derivados por `color-mix(in oklab, …)` com branco e preto. São
tokens **internos**: componentes não os consomem.

### Camada 3 · Semantic (`tokens/semantic.css`, `tokens/theme-dark.css`)

O que os componentes leem. Famílias:

| Família | Exemplos |
|---|---|
| Fundo e superfície | `--background-page` `--background-surface` `--background-elevated` `--background-subtle` `--background-sunken` `--background-inverse` `--overlay-scrim` |
| Texto | `--foreground-primary` `--foreground-secondary` `--foreground-muted` `--foreground-subtle` `--foreground-strong` `--foreground-link` `--foreground-on-inverse` |
| Texto sobre a barra lateral | `--foreground-on-sidebar` e variantes `-secondary` `-muted` `-subtle` |
| Canais RGB | `--channel-foreground` `--channel-border` `--channel-shadow` `--channel-on-sidebar` |
| Borda | `--border-subtle` `--border-default` `--border-strong` `--border-field` |
| Ação | `--action-primary` `-hover` `-active` `-foreground` `-gradient` `-surface` `-border` `-shadow`; `--action-secondary` e variantes |
| Acento | `--accent` `-hover` `-strong` `-foreground` `-surface` `-surface-strong` `-border` |
| Estado | `--status-success` `--status-warning` `--status-error` `--status-info` `--status-neutral`, cada um com `-surface` |
| Foco | `--focus-ring` `--focus-border` `--focus-outline` |
| Halo | `--halo-1` … `--halo-5`, `--halo-opacity` |
| Dados | `--chart-primary` `--chart-secondary` `--chart-empty` `--chart-compress` `--chart-radius` `--chart-gap` |

### Camada 4 · Component (`tokens/components.css`)

Geometria e densidade por componente: `--button-h`, `--field-h`, `--card-radius`,
`--nav-item-radius`, `--table-row-py`, `--avatar-md`, `--spinner-size` etc. Não contêm
cor. Um componente que precisa de um valor novo ganha um token aqui: nunca um número
solto no estilo.

---

## Theme / Tenant Configuration

Criar um tenant é um procedimento de seis passos:

1. **Definir quatro cores.**
2. **Gerar os tokens de marca**: sobrescrever as quatro variáveis.
3. **Gerar os tokens semânticos**: automático, nada a fazer.
4. **Validar contraste**: o Theme Builder mostra as quatro razões críticas.
5. **Escolher Light ou Dark**: ou deixar os dois disponíveis.
6. **Aplicar.**

```css
/* tema-acme.css */
:root {
  --brand-primary:   #1E3A5F;
  --brand-secondary: #3E5C76;
  --brand-neutral:   #6B7A8F;
  --brand-accent:    #2F6F8F;
}
```

Ou por escopo, quando a mesma aplicação serve vários tenants:

```css
[data-tenant="acme"] { --brand-primary: #1E3A5F; /* … */ }
```

**`Theme Builder.html`** é a página de configuração: quatro controles de cor, alternância
Light/Dark, presets, escalas derivadas ao vivo, leitura de contraste e o CSS pronto para
copiar. O preview cobre tipografia, superfícies, ações, entrada de dados, estado, tabela,
navegação, modal e gráfico: ao mudar uma cor, tudo responde.

### O que NÃO fazer

- Não criar `Button Tenant A`. Existe `Button` e existe tema.
- Não escrever hex em componente, em tela ou em documentação de componente.
- Não usar um degrau de escala direto (`--primary-400`) num componente: use o semântico.
- Não criar uma quinta cor de marca sem antes provar que nenhuma das quatro resolve.

---

## Light e Dark Theme

Ative com `data-theme="dark"` em `<html>` ou em qualquer contêiner: inclusive dois temas
lado a lado na mesma página.

O escuro **não é inversão automática**. Regras próprias:

| Aspecto | Light | Dark |
|---|---|---|
| Fundo × superfície | superfície mais clara que a página | superfície mais **clara** que a página, elevação sobe com luz |
| Borda | 0,14 de opacidade | 0,18: some se mantiver 0,14 |
| Texto | `neutral-900` sobre `neutral-50` | `neutral-50` sobre `neutral-950`; nunca branco puro sobre preto puro |
| Ação | `--primary-500` | `--primary-300`, um degrau mais claro, senão perde contraste |
| Texto sobre a ação | branco | quase preto (`--neutral-950`) |
| Rebaixado | tinta escura translúcida | preto translúcido |
| Sombra | canal neutro a 40% | preto puro, mais opaco |
| Halo | 0,34 de opacidade, degraus claros | 0,5, degraus escuros |

Nenhum componente consulta o tema. Todos leem os mesmos nomes.

---

## Foundations

| Fundação | Regra | Cartão |
|---|---|---|
| **Tipografia** | Instrument Sans local. 400 em tudo; 500 apenas em números grandes e botões. Hierarquia por tamanho e cor. Escala: display `clamp(38–62)` → título 34 → número 30–34 → título de cartão 16 → corpo 13,5–15 → metadado 12,5 → rótulo 11 caixa alta `.14em`. | `guidelines/type-*.html` |
| **Espaçamento** | Resolução de 2px. Gaps por contexto: 8 em botão, 11 em item de menu, 14 dentro de cartão, 12–18 entre cartões, 22–24 entre blocos. | `guidelines/spacing-*.html` |
| **Forma** | 10 chip · 12 botão e campo · 13 item de menu · 16 linha ativa · 18 linha de lista · 20–22 cartão · 24 cartão grande · 26 casca. 999px só em pílulas de estado e trilhas. | `guidelines/shape-radius.html` |
| **Elevação** | Sombra difusa, deslocada para baixo, com raio negativo. Painel rebaixado não tem sombra. | `guidelines/shape-elevation.html` |
| **Superfície** | `background` + `backdrop-filter: blur(30px) saturate(160%)` + borda de 1px + sombra difusa. Blur só em casca fixa e superfície flutuante. | `guidelines/shape-glass.html` |
| **Movimento** | Interface .2–.32s `cubic-bezier(.4,0,.2,1)`; layout .4s `cubic-bezier(.22,.61,.36,1)`; dado .5–.6s `cubic-bezier(.33,1,.68,1)` em cascata. | `guidelines/motion-*.html` |
| **Iconografia** | Tabler Icons, webfont local, `<i className="ti ti-nome" />`. Tamanhos fixos: 13 selo · 15 chip · 16 botão · 17 navegação · 18 padrão · 20–21 cabeçalho. Sem emoji, sem SVG desenhado à mão. | `guidelines/icons-tabler.html` |
| **Z-index** | 0 halo · 10 conteúdo · 15 cabeçalho de página · 30 topbar · 31 scrim · 32 sidebar · 40/45 popovers · 60 modal · 70 toast. | `guidelines/layout-zindex.html` |

---

## Componentes

Cada entrada segue a mesma estrutura: **Description · AI Context · Anatomy · Variants ·
Sizes · States · Dependencies · Composition · Usage · Do / Don't**.

Quando um campo não se aplica, ele é omitido: nunca preenchido com texto vago.

---

### Setor 01 · Primitives

#### Surface

**Description.** Superfície de conteúdo do sistema: translúcida, desfocada, borda de 1px,
sombra difusa.

**AI Context.** Use para delimitar qualquer bloco de conteúdo de uma tela. É o contêiner
padrão; se um conteúdo precisa de moldura, ele vai numa Surface. Use `variant="accent"`
quando o bloco carrega um dado ou uma informação, e `variant="inverse"` para um painel que
precisa se destacar do resto da página. Não aninhe uma Surface dentro de outra: para um
bloco interno use `SunkenPanel`, porque sombra dentro de sombra destrói a leitura de
profundidade. Um único acento por Surface: se o cartão precisa de dois destaques, são dois
cartões.

**Anatomy.** Contêiner · conteúdo em coluna com `--card-gap`.
**Variants.** `glass` (padrão) · `accent` · `solid` · `inverse`.
**Properties.** `variant` `radius` `padding` `interactive` `as` `style`.
**States.** Default · Hover (só com `interactive`: borda tingida).
**Dependencies.** Tokens de superfície, borda, elevação e forma.
**Composition.** Aceita qualquer coisa como filho; é o contêiner de quase todo Pattern.
**Do.** Radius 22 por padrão; 24 em cartão grande.
**Don't.** Não use para um bloco interno; não aplique `transform` de elevação em superfície de aplicação.

#### SunkenPanel

**Description.** Bloco rebaixado dentro de uma Surface.

**AI Context.** Use para agrupar conteúdo **dentro** de um cartão, e como trilho de fundo
de abas, cluster de paginação e grupos de campo. Nunca tem sombra: a profundidade vem do
preenchimento mais escuro. Se o bloco precisa flutuar sobre a página, ele não é um
SunkenPanel: é uma Surface ou um Popover.

**Properties.** `level` (1–4) · `radius` · `padding` · `as`.
**Dependencies.** `--background-sunken*`, `--border-subtle`.

#### Badge

**Description.** Marca curta de status, categoria ou metadado. Não interativa.

**AI Context.** Use para representar informação curta: estado, categoria, classificação,
contagem, metadado. Não use como ação: se o elemento executa algo ao ser clicado, use
`Button` (ação) ou `Chip` (filtro). `tone="action"` é a única com gradiente e serve para
marcar "agora/ativo"; `tone="accent"` para informação; `tone="quiet"` para o que ainda não
existe ("Em breve"); `success/warning/error` só quando o significado for resultado, nunca
decoração.

**Variants.** `action` `accent` `neutral` `module` `quiet` `success` `warn` `danger`.
**Properties.** `tone` `icon` `pill` `live` `children`.
**States.** Default · Live (ponto pulsante, só quando algo chega de fato).
**Do.** Texto em sentence case, uma ou duas palavras.
**Don't.** Não empilhe três badges na mesma linha de conteúdo.

#### Avatar

**Description.** Marca de pessoa ou entidade; foto quando existe, iniciais quando não.

**AI Context.** Use em linha de lista, cabeçalho de perfil, rodapé de navegação e
comentários. Nunca mostre silhueta genérica: sem foto, o componente deriva iniciais. Use
`shape="round"` apenas em superfícies de conteúdo público; em aplicação o padrão é
quadrado arredondado.

**Sizes.** `xs` 28 · `sm` 34 · `md` 38 · `lg` 44.
**Properties.** `src` `name` `size` `shape` `tone`.

#### Spinner · LoadingDots

**Description.** Dois vocabulários de carregamento, separados por papel.

**AI Context.** `Spinner` indica uma **operação pontual**: salvar, importar, recalcular.
`LoadingDots` indica uma **etapa em andamento**: um processo que já está rodando e tem
duração própria. Não use nenhum dos dois sobre dado que já está na tela: nesse caso o valor
deve interpolar até o novo número. Para a primeira carga de um bloco, use `Skeleton`. Dentro
de um botão, use `<Button loading>`, que preserva a largura e bloqueia cliques repetidos.

**Properties.** Spinner: `size` `label` `inline`. LoadingDots: `label` `tone`.
**Dependencies.** Keyframes `ds-spin` e `ds-dots`.

#### Skeleton

**Description.** Marcador de primeira carga com a geometria do conteúdo real.

**AI Context.** Use **apenas na primeira carga** de um bloco, tabela, lista ou imagem. O
skeleton deve ter a mesma forma e a mesma contagem de linhas do conteúdo esperado, para que
nada salte quando o dado chegar. Atualizar dado que já está na tela não mostra skeleton.

**Variants.** `text` `card` `table` `image` `block`.
**Properties.** `variant` `width` `height` `lines` `radius`.

#### Meter

**Description.** Trilha de progresso arredondada de 6px (5px na variante compacta).

**AI Context.** Use para progresso contínuo e legível de relance: conclusão, preenchimento
de cadastro, upload. Para proporção comparável entre itens ou para meta atingida/não
atingida, prefira `BlockMeter`, que distingue os dois casos sem depender de vermelho e
verde. Não use Meter para representar quantidade absoluta: isso é `MetricCard`.

**Properties.** `value` (0–100) `label` `caption` `size` `tone`.
**States.** Default · Warn · Action.
**Acessibilidade.** `role="progressbar"` com `aria-valuenow`.

---

### Setor 02 · Controls

#### Button

**Description.** Controle de ação do sistema.

**AI Context.** Use para executar uma ação explícita do usuário. `primary` representa a
ação principal disponível no contexto atual: evite dois primários competindo na mesma
tela. `secondary` para ações complementares, `ghost` para ações de baixa ênfase como
cancelar, `accent` para ações informativas (ver relatório, exportar dado), `danger` para
ações destrutivas. Use `loading` durante operação assíncrona: o botão mantém a largura,
marca `aria-busy` e engole cliques repetidos. Use `disabled` apenas quando houver motivo
claro para impedir a interação, e mantenha o botão visível no lugar. Não use Button para
navegar entre páginas quando um link resolve: passe `href`, que o componente renderiza
`<a>`.

**Anatomy.** Contêiner · ícone à esquerda ou à direita · rótulo · indicador de carregamento.
**Variants.** `primary` `secondary` `ghost` `accent` `danger`.
**Sizes.** `sm` 32 · `md` 38 · `lg` 46 · `cta` 54.
**States.** Default · Hover · Focus-visible · Pressed · Loading · Disabled.
**Properties.** `variant` `size` `icon` `iconPosition` `loading` `disabled` `fullWidth` `href` `type` `onClick`.
**Dependencies.** Tokens de ação, `--button-*`, keyframe `ds-spin`, Tabler Icons.
**Do.** Rótulo verbo, uma ou duas palavras, sentence case.
**Don't.** Não esconda um botão bloqueado; não use `primary` mais de uma vez por contexto.

#### IconButton

**Description.** Ação sem rótulo visível, em um quadrado de 38px.

**AI Context.** Use para ações reconhecíveis por ícone em barras e linhas de tabela. O
`label` é obrigatório: vira `title` e nome acessível. Se a ação não é óbvia pelo ícone, ela
não é um IconButton: use `Button` com rótulo. `badge` mostra o ponto de não lido.

**Properties.** `icon` `label` (obrigatório) `size` `variant` `badge` `loading` `disabled`.

#### Chip

**Description.** Pílula clicável de filtro com contador sempre visível.

**AI Context.** Use para filtrar uma lista, tabela ou grade. O contador mostra quantos itens
**aquele filtro** devolve, nunca o total geral. Marque o selecionado com `selected`, que
também define `aria-pressed`. Para informação não clicável, use `Badge`; para escolha única
em lista longa, use `Select`.

**States.** Default · Hover · Selected · Disabled.
**Properties.** `icon` `label` `count` `selected` `disabled` `onClick`.

#### Input

**Description.** Campo de texto de linha única, 40px.

**AI Context.** Use sempre dentro de um `Field`, que cuida de rótulo, ajuda e erro. Use
`invalid` junto com a mensagem no Field: nunca sinalize erro só pela borda. `loading` é
para validação assíncrona, não para envio. `readOnly` remove o preenchimento para o valor
ler como texto, e não como campo editável.

**States.** Default · Hover · Focus · Invalid · ReadOnly · Disabled · Loading.
**Properties.** `invalid` `disabled` `readOnly` `loading` `icon` + atributos nativos.

#### Select

**Description.** Escolha única a partir de uma lista curta, em `<select>` nativo.

**AI Context.** Use para uma escolha entre poucas opções conhecidas. É nativo de propósito:
entrega teclado, busca por digitação e seletor de sistema no mobile. Se o objetivo é filtrar
uma lista e mostrar quantidades, prefira `Chip`. Para muitas opções com busca, componha
`SearchInput` + lista.

**Properties.** `options` `value` `onChange` `placeholder` `invalid` `disabled`.

#### Switch

**Description.** Liga/desliga com efeito imediato.

**AI Context.** Use para uma configuração que se aplica na hora, sem botão de salvar. Se a
mudança precisa de confirmação, de um passo adicional ou de um "Salvar", não é um Switch:
é um `Button`. Expõe `role="switch"` e `aria-checked`.

**Properties.** `checked` `onChange` `disabled` `label`.

---

### Setor 03 · Composite

#### Field

**Description.** Embrulho de rótulo, controle, ajuda e erro.

**AI Context.** Use em volta de **todo** controle de formulário, para que rótulo, texto de
apoio e mensagem de erro saiam iguais em qualquer tela. O erro substitui a ajuda, aparece
com ícone e `role="alert"`: feedback nunca depende só de cor. Mensagem de erro é uma frase
completa, na voz direta do produto.

**Composition.** `Input` · `Select` · `Switch` · `SearchInput` · qualquer controle.
**Properties.** `label` `hint` `error` `required` `htmlFor`.

#### SearchInput

**Description.** Busca com lupa à esquerda e limpar ou atalho à direita.

**AI Context.** Use para busca sobre uma lista, tabela ou catálogo. Composto sobre `Input`,
não reimplementado. Busca sem resultado **não é erro**: combine com
`<EmptyState variant="no-results" term={termo} />`, que devolve o termo na mensagem.

**Dependencies.** `Input`.
**Properties.** `value` `onChange` `onClear` `placeholder` `shortcut` `loading`.

#### TabRail

**Description.** Até quatro abas ricas num trilho rebaixado.

**AI Context.** Use para alternar seções dentro de uma mesma página, quando cada seção
merece uma linha de apoio e um contador. Máximo de quatro abas: acima disso, vire navegação
lateral. Trocar de aba não pode mover o cabeçalho nem reiniciar a rolagem. O contador diz
quantos itens existem naquela aba; use `tone="alert"` quando o número for um problema.

**Properties.** `tabs` (`id` `icon` `label` `sub` `count` `countIcon` `tone`) `value` `onChange`.
**States.** Default · Hover · Selected.

#### Pagination

**Description.** Cinco controles num trilho rebaixado, com campo de página editável.

**AI Context.** Use abaixo de qualquer lista ou tabela paginada. Botão no limite fica
**desabilitado no lugar**, nunca escondido. Com uma página só, o componente devolve `null`:
não envolva em condicional própria. O resumo à esquerda usa números tabulares.

**Properties.** `page` `pages` `total` `perPage` `itemLabel` `icon` `onChange`.

#### Popover

**Description.** Painel flutuante ancorado, com linhas de 66px (`PopoverRow`).

**AI Context.** Use para notificações, menu de conta e listas curtas de ação disparadas por
um controle. Superfície sólida, porque flutua sobre superfícies translúcidas. Cada linha
leva a algum lugar; uma mensagem que não leva a lugar nenhum é `Toast`, não notificação.

**Composition.** `PopoverRow` · `Button` · qualquer conteúdo.
**Properties.** Popover: `open` `title` `action` `footer` `anchor` `width`. PopoverRow: `icon` `tone` `title` `detail` `time` `unread` `href`.

#### Accordion

**Description.** Lista de seções expansíveis com itens internos.

**AI Context.** Use para conteúdo longo dividido em seções: currículo, etapas, agrupamento
de configurações. Várias seções podem ficar abertas ao mesmo tempo. Para uma única pergunta
e resposta isolada, use `Disclosure`. O ícone do item carrega o estado: concluído, liberado
ou bloqueado.

**Properties.** `modules` (`title` `sub` `duration` `lessons`) `defaultOpen`.
**States.** Collapsed · Expanded.

#### Disclosure

**Description.** Uma pergunta e sua resposta, separadas por fio.

**AI Context.** Use em FAQ e em blocos de ajuda. Várias podem abrir ao mesmo tempo. O sinal
de mais gira 45°, nunca troca de glifo. Resposta é um parágrafo curto, na voz direta.

**Properties.** `question` `defaultOpen` `children`.

---

### Setor 04 · Patterns

#### PageHeader

**Description.** Topo do corpo de uma página: eyebrow, título, apoio e ações.

**AI Context.** Primeiro bloco dentro de `<main>`. Use `size="greeting"` apenas quando a
tela se dirige a uma pessoa pelo nome. Ações de página ficam aqui; a ação primária global
fica na `Topbar`.

**Properties.** `eyebrow` `title` `lead` `actions` `size`.

#### SectionHeading

**Description.** Cabeçalho de uma seção dentro de um cartão: título, apoio e um link.

**AI Context.** Um link de saída por seção, sempre com seta. Controles locais (alternância
de período, por exemplo) entram como `children`, à esquerda do link.

**Properties.** `kicker` `title` `sub` `link` `href` `level` `children`.

#### MetricCard

**Description.** Cartão de indicador com anatomia fixa de quatro linhas.

**AI Context.** Use na faixa superior de um painel para números que respondem "como
estamos". Todos os cartões de uma faixa devem receber o mesmo conjunto de props, o que
mantém a altura idêntica. O valor chega **já formatado**: o componente não formata. O chip
de variação reserva 84px para o layout não deslizar entre dois e três dígitos. Use
`offline` quando não há leitura: o número vira travessão, a variação some e a legenda
explica. Para a evolução no tempo do mesmo número, combine com `AreaChart` ou `BlockColumns`.

**Anatomy.** Rótulo + ícone · número + acessório · faixa de dado opcional · legenda.
**Properties.** `label` `icon` `tone` `value` `accessory` `delta` `deltaDirection` `caption` `band` `loading` `offline`.
**States.** Default · Loading · Offline.
**Composition.** `band` aceita `BlockMeter`, `AreaChart` ou barras de pulso.

#### Table

**Description.** Tabela em grade dentro de um cartão, com estados próprios.

**AI Context.** Use para qualquer lista de registros com mais de duas colunas. Carregando,
vazio e erro são estados **da tabela**: o cabeçalho e o rodapé não se movem. Passe um
`EmptyState` em `empty` e um `Pagination` em `footer`. Células truncam por reticências: uma
linha tem uma linha de altura. Marque colunas numéricas com `numeric` para alinhar os
dígitos.

**Properties.** `columns` (`key` `label` `width` `align` `numeric` `wrap` `render`) `rows` `loading` `skeletonRows` `empty` `footer` `onRowClick`.
**Composition.** `Badge` nas células de estado · `Avatar` na coluna de identificação · `Pagination` no rodapé.

#### BlockColumns · BlockGrid · BlockMeter · BlockSplit

**Description.** A família de gráficos em bloco: volume por período, proporção de um total,
medidor de 20 blocos e comparação de duas populações a partir do centro.

**AI Context.** Use blocos, e não curvas, para **quantidade, proporção e cobertura**.
`BlockColumns` para volume por período: passe `compare` com o período anterior, que é o que
transforma volume em comparação; a escala é comprimida pela potência 0,62 de propósito, para
que um período fraco ao lado do pico não vire coluna vazia. `BlockGrid` substitui rosca e
pizza, e sempre acompanha uma nota de leitura. `BlockMeter` substitui barra arredondada
quando importa distinguir dentro/fora da meta sem usar vermelho e verde. `BlockSplit` compara
duas populações de tamanhos muito diferentes, cada lado com escala própria. Para tendência em
faixa estreita, onde 1 ponto percentual importa, **não** use blocos: use `AreaChart`.

**Properties.** BlockColumns: `values` `compare` `labels` `current` `rows` `height` `tone` `note`. BlockGrid: `total` `columns` `segments` `note` `legend`. BlockMeter: `value` `blocks` `onTarget` `label` `display`. BlockSplit: `left` `right` `blocks` `height`.
**Dependencies.** `--chart-*`, cascata de 9–16ms por bloco.

#### AreaChart

**Description.** Gráfico de linha com área e linha de meta opcional.

**AI Context.** Use em três casos: tendência em faixa estreita, duas séries comparadas no
tempo e linha de meta. Todo o resto do sistema usa blocos. Dê um `id` único por instância:
o gradiente é referenciado por id.

**Properties.** `values` `labels` `height` `target` `gridLines` `showPoints` `loading` `id`.

#### LiveMetric · ActivityFeed

**Description.** Número que está chegando agora, com histórico de pulso; e a fita de
leituras.

**AI Context.** Use quando o dado chega continuamente. O número **persegue** o alvo em vez
de saltar, reserva largura fixa e usa números tabulares. Declare sempre a cadência e a hora
da última leitura na legenda. `offline` é estado de primeira classe, não erro: travessão,
barras achatadas, animação parada e explicação de desde quando. `ActivityFeed` desliza uma
linha de 56px em vez de reordenar; passe um evento a mais do que as linhas visíveis.

**Properties.** LiveMetric: `target` `bars` `live` `offline` `delta` `label` `caption`. ActivityFeed: `events` `rows` `offline`.

#### StatusPill

**Description.** Declara em qual dos três estados de dado a tela está.

**AI Context.** Toda tela com dado que muda mostra um. `live` pulsa; `consolidated` e
`offline` são estáticos. `offline` comunica ausência de sinal, não falha do sistema: para
falha de carregamento use `EmptyState variant="error"`.

**Variants.** `live` `consolidated` `offline`.

#### Callout

**Description.** Mensagem persistente na página, com a ação que a resolve.

**AI Context.** Use para algo que precisa da atenção do usuário e permanece até ser
resolvido: pendência, aviso, limite próximo. Sempre entregue a `action` que resolve,
um número pendente sem botão é só um número triste. Para confirmação momentânea de algo que
o usuário acabou de fazer, use `Toast`. Para ausência de conteúdo, use `EmptyState`.

**Variants.** `info` `action` `warn` `neutral` `positive`.
**Properties.** `tone` `icon` `title` `action` `onActionClick` `progress` `children`.

#### Toast

**Description.** Confirmação momentânea, centralizada na base.

**AI Context.** Use para confirmar uma ação que o usuário acabou de executar. Uma linha, no
passado, some em ~1,8s. Se a mensagem precisa persistir, é `Callout`. Se precisa levar a
algum lugar, é uma linha de notificação no `Popover`.

**Properties.** `open` `icon` `tone` `onClose`.

#### EmptyState

**Description.** Os seis estados de conteúdo do sistema.

**AI Context.** Use quando uma área não tem conteúdo para mostrar, e diga **por quê**.
Escolha a variante pelo motivo: `empty` (ainda não há), `first-run` (primeiro acesso),
`no-results` (busca sem resultado: passe `term` e o componente devolve o termo),
`error` (falha de carregamento, com `role="alert"`), `forbidden` (sem permissão),
`offline` (sem conexão). Não use `empty` para erro nem para falta de permissão: cada um tem
sua variante e sua saída.

**Properties.** `variant` `icon` `title` `body` `term` `action` `secondary`.

#### Card · TileCard · PersonCard · OfferPanel · Quote · RatingStars

**Description.** A família de cartões de conteúdo, montada sobre `Surface`.

**AI Context.** `Card` é o cartão de conteúdo com mídia: capa, selo, título, autor, meta,
preço e avaliação: use para item de catálogo, publicação ou qualquer objeto com imagem.
`TileCard` é o azulejo compacto de categoria ou atalho, com ícone e contagem. `PersonCard`
apresenta uma pessoa, em `tile` (grade) ou `profile` (página). `OfferPanel` é o painel de
oferta com prévia, preço, CTA e lista de inclusos: só em superfície de conteúdo público.
`Quote` é um depoimento; `RatingStars` é a avaliação em estrelas, com nome acessível que
soletra o valor. Antes de criar um cartão novo, verifique se `Card` com outros slots resolve.

**Properties.** ver os arquivos `.d.ts` de cada um.
**Composition.** Todos usam `Surface`, `Avatar`, `Badge` ou `RatingStars`.

---

### Setor 05 · Templates

#### AppShell

**Description.** Moldura completa de aplicação: fundo, barra superior, navegação lateral e
`<main>` com faixa de conteúdo.

**AI Context.** Toda tela de aplicação começa aqui: uma tela é um `AppShell` com filhos.
Ele publica as variáveis de layout em `:root` e ajusta a faixa de conteúdo conforme a
preferência fixada da barra lateral, nunca conforme o hover, para que passar o mouse não
reposicione a página. Passe `collapsible={false}` quando a navegação deve ficar sempre
aberta. Não recrie topbar e sidebar por página.

**Composition.** `HaloBackground` + `Topbar` + `SidebarNav` + conteúdo.
**Properties.** `logo` `brand` `breadcrumb` `tenant` `action` `notifications` `groups` `active` `user` `collapsible` `halos` `maxWidth`.

#### Topbar · Breadcrumb · SidebarNav · NavItem

**Description.** As peças da casca.

**AI Context.** `Topbar` carrega marca, trilha, seletor de contexto, notificações e **uma**
ação primária. `Breadcrumb` mostra no máximo três níveis e some abaixo de 1024px.
`SidebarNav` agrupa `NavItem` por setor, com legendas em caixa alta, e recolhe para 77px
mantendo o ícone na mesma coordenada: recolher só estreita e apaga rótulos, nunca
recentraliza. `NavItem` marca `aria-current="page"` no item ativo; item indisponível é um
`<span>`, não um link morto.

**Properties.** ver os `.d.ts`.

#### HaloBackground

**Description.** Campo de cor difuso atrás da interface.

**AI Context.** Primeiro filho de uma tela, antes da casca. Três a cinco círculos de
340–640px, desfoque 1,5× o do vidro, `pointer-events: none` e `aria-hidden`. Nunca anime os
halos: o que se move é o vidro por cima. As cores saem de `--halo-1…5`, derivadas da marca
do tenant.

---

## Acessibilidade

- **Contraste.** Texto 4,5:1; texto em escala de título 3:1. A escada de texto é calculada
  contra o fundo **mais claro** em que cada nível pode cair, não contra a página: `subtle`
  é o token de legenda e metadado, e legenda costuma sentar sobre preenchimento
  translúcido ou painel rebaixado. Pior caso medido no claro: 6,21:1 sobre
  `rgba(var(--channel-foreground),.06)`; no escuro, 7,13:1. O Theme Builder mede as
  quatro razões críticas a cada mudança de cor.
- **Foco visível.** `--focus-ring` (2px) **e** mudança de borda em campos: o anel sozinho
  some sobre fundo movimentado.
- **Alvo mínimo.** 32px em controles compactos, 38–44px no padrão; linhas de popover têm
  66px de altura mínima.
- **Nunca só cor.** Erro leva ícone e texto; dentro/fora de meta em gráficos é distinguido
  por cor **e** por preenchimento, nunca por vermelho/verde.
- **Nome acessível.** `IconButton` exige `label`; `RatingStars` soletra o valor;
  `Avatar` sem foto expõe o nome.
- **Estados nativos.** `aria-pressed` em Chip e aba, `aria-current` em navegação,
  `role="switch"`, `role="progressbar"`, `role="alert"` em erro, `aria-live="polite"` em
  feed e toast, `aria-busy` em ação assíncrona.
- **Teclado.** Controles são elementos nativos (`button`, `input`, `select`), então ordem de
  tabulação, Enter/Espaço e type-ahead funcionam sem código extra.
- **Movimento.** `prefers-reduced-motion` desliga animação e transição em `tokens/base.css`.

---

## Responsividade

| Faixa | Comportamento |
|---|---|
| Desktop ≥ 1024px | Barra lateral recolhida em 77px; hover expande para 266px **sobre** o conteúdo; a faixa acompanha só a preferência fixada (142px / 314px); topo 112px |
| Notebook 1024–1050px | Grades de 4 caem para 3; painéis laterais estreitam |
| Tablet < 1024px | Barra lateral vira gaveta com scrim; trilha some; faixa cai para 16px; topo 84px; título 27px |
| Mobile < 800px | Navegação de conteúdo público vira menu; grades rolam na horizontal com snap; painel de oferta sai do modo fixo e vai para o topo, com barra de ação na base |

Responsividade não é redução proporcional: muda layout, grade, navegação, ordenação,
visibilidade e agrupamento.

---

## Motion

| Categoria | Duração | Curva | Uso |
|---|---|---|---|
| Interface | .2–.32s | `cubic-bezier(.4,0,.2,1)` | hover, foco, abrir popover, trocar estado |
| Layout | .4s | `cubic-bezier(.22,.61,.36,1)` | largura da barra lateral, rótulos, faixa |
| Dado | .5–.6s | `cubic-bezier(.33,1,.68,1)` | blocos de gráfico, em cascata de 9–16ms |

Keyframes, todos em `tokens/motion.css`: `ds-spin` (operação), `ds-dots` (etapa),
`ds-pulse` (sinal), `ds-halo` + `ds-blink` (ponto ao vivo), `ds-rise` / `ds-rise-x`
(entrada de conteúdo), `ds-sweep` (varredura de cartão ao vivo), `ds-shimmer` (skeleton),
`ds-enter` (popover), `ds-scan`, `ds-float`, `ds-fade`.

Nunca: recarregar a página inteira, piscar um cartão a cada leitura, reordenar lista sem
transição, spinner sobre dado já visível, relógio em fonte não tabular.

---

## Estados de conteúdo

| Estado | Componente |
|---|---|
| Conteúdo disponível | o próprio componente |
| Nenhum conteúdo | `EmptyState variant="empty"` |
| Primeiro acesso | `EmptyState variant="first-run"` |
| Busca sem resultado | `EmptyState variant="no-results"` com `term` |
| Erro de carregamento | `EmptyState variant="error"` |
| Erro de permissão | `EmptyState variant="forbidden"` |
| Conexão perdida | `EmptyState variant="offline"` |
| Sem sinal de dado | `StatusPill state="offline"` + `MetricCard offline` |
| Carregando (primeira vez) | `Skeleton` |
| Carregando (operação) | `Spinner` ou `<Button loading>` |
| Carregando (etapa) | `LoadingDots` |
| Ação concluída | `Toast` |
| Ação pendente | `Callout` com `action` |

---

## Convenções de nomenclatura

- **Componentes:** PascalCase, substantivo, em inglês (`MetricCard`, `SidebarNav`).
- **Props:** camelCase; booleanas afirmativas (`disabled`, não `notEnabled`).
- **Tokens:** kebab-case em três níveis: `--<família>-<papel>-<modificador>`
  (`--action-primary-hover`, `--background-sunken-2`).
- **Setores:** `primitives` · `controls` · `composite` · `patterns` · `templates`.
- **Keyframes:** prefixo `ds-`.
- **Arquivos:** `<Nome>.jsx`, `<Nome>.d.ts`, `<Nome>.prompt.md`, `<setor>.card.html`.
- **Copy da interface:** pt-BR, voz direta, sentence case; caixa alta só em rótulo de seção
  (11px `.14em`) e legenda de grupo (10,5px `.13em`). Sem emoji.

---

## Manutenção

> **Regra permanente do ecossistema Tinyx: se o Design System mudou, este arquivo muda
> junto.** Biblioteca, tokens, comportamento, contexto de IA e documentação representam
> sempre a mesma realidade.

Isso vale para: criar ou remover componente, mudança visual ou estrutural, novo estado, nova
propriedade, nova variante, mudança de comportamento, mudança de token, renomeação, mudança
de acessibilidade, mudança de dependência, criação de padrão, alteração de tema.

**Qualquer agente de IA** que criar, alterar, remover ou reorganizar qualquer parte do
Design System deve revisar e atualizar este Markdown **antes** de considerar a tarefa
concluída.

### Definition of Done

Uma alteração só está concluída quando:

- [ ] implementação feita
- [ ] estados revisados
- [ ] variantes revisadas
- [ ] propriedades revisadas
- [ ] dependências revisadas
- [ ] acessibilidade revisada
- [ ] Light Theme revisado
- [ ] Dark Theme revisado
- [ ] AI Context atualizado
- [ ] documentação neste Markdown atualizada
- [ ] Changelog atualizado

---

## Changelog

### v1.0.0 · 2026-09-22 · Primeira versão estável

Marco zero versionado no GitHub (tag `v1.0.0`). Inclui tudo o que está listado abaixo.

#### Added
- `index.html`: página inicial da documentação publicada, com links para Biblioteca, Visão geral, Theme Builder e esta documentação.

### 2026-09-22 · Revisão UX/UI da Biblioteca

#### Changed
- `--accent-surface` 10% → 14% e `--accent-border` 26% → 32%: o tom `accent` de Badge, Surface e Chip era invisível sobre a página.
- `--chart-secondary` passa a ler `--secondary-500` (antes `--action-primary`): a segunda série de dados agora é a cor secundária do tenant, distinta da ação.
- `Toast`: tom `positive` renomeado para `success`, alinhado a Badge e Callout (`positive` segue aceito como alias).
- `Badge`: a chave interna `data` passa a `accent`, como a API já declarava, o tom renderizava sem estilo. `data` e `positive` seguem como aliases; tom desconhecido cai em `neutral`, nunca em texto nu.
- `MetricCard`: a faixa de dado (`band`) recebe `flex: 1`, um filho flex sem largura encolhia até zero e sumia.
- `LiveMetric` e `ActivityFeed`: intensidade das barras e da linha nova por `color-mix`, não mais `rgba()` sobre uma cor completa (inválido).
- `AreaChart`: área sob a linha mais leve (10% → 0).
- `Card`: sem capa, mostra um marcador honesto (listras sutis + legenda mono) em vez de um bloco vazio; o rodapé quebra linha em vez de partir o preço.
- `PersonCard`: sem foto, cai para iniciais em ambos os formatos, nunca um círculo vazio; a coluna de foto do `profile` passa a 110–170px.
- Biblioteca: bloco de AI Context mais discreto (fio lateral, sem preenchimento), para o componente ser o protagonista; grade de quatro colunas para famílias de quatro variantes; demos de Meter, Skeleton, TabRail e Card reorganizadas por anatomia.

#### Regra nova
- **Uma cor de token é uma cor completa.** Nunca a use dentro de `rgba()`; para intensidade, `color-mix(in oklab, var(--token) N%, transparent)`.

### 2026-09-16

#### Added
- `Biblioteca Tinyx.html`: a biblioteca inteira renderizada no fluxo da página, sem moldura, sem escala, sem recorte, com o bloco de **AI Context** visível em cada um dos 46 componentes, lido direto dos arquivos `.prompt.md`.
- Arquitetura de tokens em quatro camadas: `brand` → `scales` → `semantic` → `components`.
- `tokens/brand.css` com as quatro entradas de tenant (`--brand-primary`, `--brand-secondary`, `--brand-neutral`, `--brand-accent`) + quatro cores de estado.
- `tokens/scales.css`: dez degraus por entrada, derivados por `color-mix(in oklab, …)`.
- `tokens/theme-dark.css`: Dark Theme com regras próprias, não inversão automática.
- `Theme Builder.html`: configuração de tenant com quatro controles de cor, Light/Dark, presets, escalas ao vivo, leitura de contraste e CSS para copiar.
- Setorização da biblioteca em cinco níveis: Primitives, Controls, Composite, Patterns, Templates.
- Bloco **AI Context** em todo componente, neste documento.
- `DESIGN_SYSTEM.md` como fonte de verdade documental.
- Cartões de fundação neutros: escalas derivadas, papéis semânticos, Light × Dark.

#### Changed
- Escada de texto reequilibrada: `secondary` → mistura 800/700, `muted` → 700,
  `subtle` → 600. Em `--neutral-500`, `subtle` media 4,17:1 sobre preenchimento a 6%:
  abaixo dos 4,5:1 que a própria documentação exige, e esse é justamente o fundo de
  `Badge quiet`, `Chip` não selecionado, cabeçalho de `Table` e todo `SunkenPanel`.
- Escala neutra: a ponta escura (950/900/800) subiu para 32/44/56%, porque `color-mix` em oklab com percentuais baixos colapsava para preto e a escada de superfícies do tema escuro desaparecia.
- Tema escuro: superfície e elevado passaram a clarear sobre a página (elevação por luz), e os rebaixados viraram tinta clara a 3–6% em vez de sobreposição preta.
- A biblioteca deixou de ter identidade visual própria: o estado de fábrica é acromático.
- Tokens renomeados para vocabulário semântico neutro (`--foreground-*`, `--background-*`, `--action-*`, `--accent-*`, `--status-*`, `--chart-*`).
- Componentes renomeados para vocabulário neutro: `GlassCard → Surface`, `DataTable → Table`, `ProgressBar → Meter`, `Mosaic* → Block*`, `SparkArea → AreaChart`, `LiveNumber → LiveMetric`, `LiveFeed → ActivityFeed`, `CourseCard → Card`, `CategoryCard → TileCard`, `CreatorCard → PersonCard`, `PurchaseCard → OfferPanel`, `ModuleAccordion → Accordion`, `FaqItem → Disclosure`, `Testimonial → Quote`.
- Variantes renomeadas: `Badge tone="soon" → "quiet"`, `tone="positive" → "success"`; `Surface variant="data" → "accent"`, `"dark" → "inverse"`; `Button variant="data" → "accent"`.
- Keyframes renomeados de `om-*` para `ds-*`.
- Gráficos em bloco passaram a receber uma cor completa e derivar intensidade por `color-mix`, em vez de um trio de canais fixo.
- Todos os `var(--token, fallback)` perderam o fallback: o fallback carregava paleta.

#### Removed
- Escalas de marca fixas e escopos por produto.
- UI kits e cartões de fundação vinculados a produtos específicos.
- Qualquer referência a paleta institucional na documentação e nos componentes.
