# Contrato · Documento

> Implementado em `app/src/componentes/Documento/Documento.tsx`, com CSS em
> `estilo/12-v3-terreno.css` (`.doc`) — a **mesma** folha que o protótipo
> carrega.

**Sexto dos 7 componentes da Fase 1 a ganhar código.** `ds/gera.py` (`FASE_1`)
e `app/src/paginas/Layout.tsx` (`COMPONENTES`) estão travados por teste em
exatamente sete nomes — Documento é um deles. Falta só `Numero`.

Linha de lei ou documento anexado ao estudo. Hoje usada nas duas seções
"Leis e incentivos do estudo" e "Documentos do estudo" de
`prototipo/index.html`, e é o mais composto dos 7: usa `Icone` (o `.fi`) e
compõe com `Badge` via um slot livre, em vez de reimplementar badge aqui.

## Anatomia

| Parte | Classe | O que é |
|---|---|---|
| ícone | `.doc .fi` | acompanha o tipo do item (`book` para lei, `file-text`/`mail` para documento) |
| nome | `.doc .nm` | o nome da lei ou do arquivo |
| extra | `.doc .ex` | metadado secundário, opcional |
| marcar | `.doc-chk .ok-selo` | alterna considerado/desconsiderado. Selo de check quando ligado, vazio quando não |
| apagar | `.doc-del` | **só na linha adicionada pelo usuário** (`.doc-nova`). Item de base não tem lixeira |
| selo | slot livre | ex. `<Badge tom="atencao">Lendo</Badge>` para item recém-anexado, ainda sendo processado |

## Três anatomias reais, medidas no protótipo

Não é uma peça com um único visual — são três combinações reais, cada uma
com um trecho correspondente em `prototipo/index.html`:

1. **Lei/documento de base pública** (`#leis-novas`/`#docs-novos` semeados
   no HTML): nome + extra + marcar. Nunca se apaga, só se desconsidera —
   decisão de produto já registrada em comentário no CSS original
   (`estilo/12-v3-terreno.css:620-624`).
2. **Lei adicionada pelo usuário** (função que popula `#leis-novas`): nome +
   extra + selo "Lendo" + apagar. **Sem** botão marcar — ainda não tem
   estado de consideração enquanto está sendo lida.
3. **Documento adicionado pelo usuário** (função que popula `#docs-novos`):
   nome + extra + marcar **e** apagar juntos — a única combinação do
   protótipo com os dois controles ao mesmo tempo.

## Props

| Prop | Tipo | Obrigatória | Observação |
|---|---|---|---|
| `icone` | `NomeIcone` | sim | ícone do `.fi` |
| `nome` | `string` | sim | |
| `extra` | `ReactNode` | não | só renderiza `.ex` se definido |
| `considerado` | `boolean` | não* | par com `aoAlternar` — ver abaixo |
| `aoAlternar` | `(proximo: boolean) => void` | não* | par com `considerado` |
| `aoApagar` | `() => void` | não | presença decide se `.doc-del` existe, e aplica `.doc-nova` na linha |
| `rotuloApagar` | `string` | não | default `` `Remover ${nome}` `` |
| `selo` | `ReactNode` | não | slot livre, ex. `Badge` |

\* `considerado`/`aoAlternar` são **um par**: os dois juntos, ou nenhum dos
dois. Não existe combinação de tipo que aceite só um — e há uma rede de
segurança em runtime (`import.meta.env.DEV`, mesmo critério do `rotulo`
obrigatório do `Toggle`) para o caso de o tipo ser burlado.

## Por que props opcionais, não uma prop `variante`

A alternativa óbvia seria `variante: 'base' | 'lei-nova' | 'doc-novo'`
enumerando as três anatomias. Rejeitada: é o mesmo sintoma que a Regra 7
descreve — "a prop nova que você quer adicionar é um booleano [aqui,
enumerado] que muda layout". As três anatomias já saem certas combinando
`considerado`/`aoAlternar` (existem ou não) com `aoApagar` (existe ou não)
com `selo` (existe ou não). Composição, não configuração.

## Controlado, sem estado interno

Mesma filosofia de `Toggle`, `Numero` e `Badge`: o componente não decide se
está considerado, só mostra e avisa. Nenhum outro componente deste sistema
tem duas formas de usar a mesma peça (controlado vs. não-controlado com
default interno).

## Estados (Regra 4)

| Estado | Como | Observação |
|---|---|---|
| considerado | `considerado={true}` | ícone de check aparece no `.ok-selo` |
| desconsiderado | `considerado={false}` | aplica `.desconsid`, que esmaece só o ícone (`.fi{opacity:.5}`) — ver "Achado construindo" abaixo |
| foco (marcar/apagar) | `:focus-visible` | anel global do sistema, nenhum CSS de foco próprio — mesma regra do Botão, Badge e Toggle |
| hover do apagar | `:hover` | `.doc-del:hover` tinge de vermelho (`--no-t`/`--no-tx`), existe no CSS original |
| hover do marcar | **não existe** | `.doc-chk` não tem regra de `:hover` no CSS original — mesmo achado do `Toggle` (`.tgl` sem hover): documentado, não inventado |

## Achado construindo, não estava no CSS

No protótipo, `.doc-chk`/`.doc-del` são `<button>` só com `title`, sem
`aria-label` nem `aria-pressed` — o leitor de tela não anuncia nome nem
estado, e numa lista de várias linhas "Remover" repetido não diz qual linha
está sendo removida. Corrigido na raiz aqui: `aria-pressed` reflete
`considerado`, e os dois botões levam o `nome` do item no rótulo acessível.

**Contraste, medido pelo `test:vitrine` (axe em Chromium real) construindo
este componente, não estimado.** `.doc.desconsid{opacity:.4}` original
aplicava à linha inteira, texto incluso — e não existe cor de texto que
sobreviva a 40% de opacidade sobre `--mundo` e ainda passe 4,5:1 (o teto
matemático fica perto de 2,6:1, medido). `.doc .ex` também reprovava sozinho,
independente da opacidade: usava `--t4` (4,19:1). Corrigido em
`estilo/12-v3-terreno.css`: `.doc .ex` foi para `--t2` (7,95:1), e
`.doc.desconsid` foi de esmaecer a linha pra esmaecer só `.fi` (o ícone,
`opacity:.5`) — o selo vazio já sinaliza "não considerado" funcionalmente, e
o texto continua legível. **É mudança de tratamento visual num CSS que o
board já aprovou, não validada com design ainda** — ver "Pendências" abaixo.

## Acessibilidade

- `aria-pressed={considerado}` no botão marcar — padrão ARIA para botão que
  alterna entre dois estados persistentes.
- `aria-label` no marcar inclui o nome do item e o efeito do clique (mesmo
  texto que hoje é só `title` no protótipo, promovido a rótulo acessível de
  verdade).
- `aria-label` no apagar inclui o nome do item por padrão
  (`` `Remover ${nome}` ``), sobrescrevível via `rotuloApagar`.

## Fora do contrato

- **`.doc-tg` (a variante com `Toggle` no lugar do marcar) não é coberta por
  este componente.** No protótipo ela aparece em "Fachada ativa no térreo"
  (dentro do seletor de cenário, não nas seções de leis/documentos), reusa a
  classe `.doc` só para o layout de ícone+texto, e troca o controle inteiro
  por uma chave liga/desliga — semântica diferente (ligado/desligado, não
  considerado/desconsiderado; nunca se apaga). É melhor modelada compondo o
  `Toggle` já existente ao lado de um `.doc` simples no lugar de origem do
  que adicionando uma terceira anatomia de controle a este componente.

## Pendências deste componente

- **Hover do marcar não tem estilo próprio** — ver "Estados" acima. Se um
  dia o produto quiser um hover real, o CSS precisa mudar primeiro (é o
  protótipo que manda, não o componente).
- **O esmaecimento do ícone em `.desconsid` é decisão de interim, não
  validada com design.** Resolve o defeito de contraste real (ver
  "Contraste, medido" acima), mas troca o tratamento visual de "linha
  inteira esmaecida" pra "só o ícone", num CSS que o board já tinha
  aprovado. Vale revisão visual antes de considerar definitivo.
- **`prototipo/index.html` continua com a implementação original em
  vanilla JS**, não consome este componente ainda — é pendência de
  integração, registrada no `CHANGELOG.md`, não deste contrato.
