# Icon Button — contrato normativo v1.5

## Princípio

Icon Button é um comando interativo sem label visível. Ele não é “qualquer quadrado com ícone” e não escolhe shape ou tamanho por preferência visual.

Cinco eixos são independentes:

1. **densidade** define alvo e glyph;
2. **ênfase** define superfície e cor;
3. **comportamento** define ação ou toggle;
4. **shape** define Squircle ou Circle por contexto;
5. **contexto** decide se o elemento é Icon Button ou parte de um controle composto.

## Árvore de decisão

1. Há label visível permanente? Use Button, não Icon Button.
2. O item pertence a segmented, theme switch, paginação ou outro grupo conectado? Use a célula do componente composto.
3. É uma ação isolada ou de header/card/composer? Use tamanho `default`.
4. Está em toolbar densa de desktop ou button group? `compact` é permitido.
5. Está isolado em mobile/coarse ou exige alvo ampliado? Use `touch`.
6. Está em composer conversacional ou composição explicitamente radial? Circle é permitido; nos demais casos, mantenha Squircle.
7. Precisa de destaque? Troque a ênfase; nunca o tamanho ou shape.

## Densidade

| Papel | Classe | Alvo | Glyph | Uso |
|---|---|---:|---:|---|
| Compact | `.b-icon-btn--compact` | 32px | 16px | Toolbar ou grupo denso de desktop |
| Default | `.b-icon-btn` | 40px | 20px | Ação padrão e standalone |
| Touch | `.b-icon-btn--touch` | 44px | 24px | Mobile/coarse ou ação isolada prioritária |
| Perímetro de navegação | `.sidebar-collapse-toggle` | 36 × 36px fine; 44 × 44px coarse | 20px Regular | Header do rail 49px com eixo 24px; Sidebar Simple contextual, logo sem fundo 32px ou fallback Fill 24px no repouso |

Valores 28 e 36px não pertencem à API geral. A combinação contextual quadrada 36px/44px só é permitida para o controle que compartilha exatamente o perímetro do item de navegação colapsado; O modificador legado `.b-icon-btn--sm` foi removido.

## Ênfase

| Papel | Classe | Uso |
|---|---|---|
| Ghost | `.b-icon-btn` | Ação neutra recorrente |
| Subtle | `.b-icon-btn--subtle` | Separação leve sobre fundo neutro |
| Outline | `.b-icon-btn--outline` | Maior delimitação sem ação primária |
| Filled | `.b-icon-btn--filled` | Ação icon-only primária, rara e inequívoca |
| Danger | `.b-icon-btn--danger` | Destruição ou perigo; vermelho nunca é genérico |

Ênfase não altera largura, altura, glyph ou curva.

## Comportamento

### Ação momentânea

Executa e retorna ao estado inicial. Não usa `aria-pressed`.

### Toggle

Representa estado persistente e usa `aria-pressed="true|false"`. Fill do glyph pode reforçar seleção, mas nunca substituir o atributo, tooltip ou nome acessível.

`aria-expanded` é permitido para controles que abrem uma superfície associada. Loading e disabled preservam a mesma geometria.

## Shape

| Papel | Classe | Uso |
|---|---|---|
| Squircle | `.b-icon-btn` | Padrão para ações standalone, shell, cards e toolbars |
| Circle | `.b-icon-btn--circle` | `.b-composer__action` dentro de `.b-composer` ou filho direto de `.b-icon-btn-context--radial` |

Circle é uma variante de shape, nunca de ênfase. Não use Circle para “deixar mais importante”, simular floating action button ou corrigir falta de hierarquia.

A referência ClickAgents usa ações circulares no composer: slot de 35px, raio de 48px e envio filled. O Baluarte preserva essa gramática com a escala governada 32/40/44, Phosphor 16/20/24 e linha de ações a 9px das laterais/base do Composer. `data-shape-role` não concede permissão: a classe só produz Circle em `.b-composer__action` dentro de `.b-composer` ou como filho direto do wrapper `.b-icon-btn-context--radial`.

## Controles que não são Icon Button

- célula icon-only de segmented control;
- opção do theme switch;
- paginação;
- ação interna de campo, como limpar ou revelar conteúdo;
- color swatch;
- crop/resize handle;
- avatar action;
- media transport pertencente a um player composto.

Esses elementos podem compartilhar tokens, mas seguem anatomia, seleção e geometria do componente pai.

## Contextos oficiais

| Contexto | Classificação |
|---|---|
| Shell menu/drawer | Default 40/20; promove integralmente para Touch 44/24 em pointer coarse |
| Shell collapse | Perímetro 36×36/20 Regular ou 44×44/20 Regular coarse, Squircle 16px e `--text`; logo sem fundo 32px ou fallback Fill 24px no repouso; Sidebar Simple aparece no hover/foco do controle; inset aberto fine 9px/9px |
| App header | Default |
| Dense toolbar/button group | Compact |
| Workspace toolbar | Compact |
| Conversational composer | Default + Circle; send pode ser Filled |
| Floating toolbelt | Compact; toggle por `aria-pressed` |
| Card trailing action | Compact em desktop; Touch quando isolado em mobile |
| Theme switch/segmented | Não é Icon Button |
| Picker e File Tile icon-only | Representações compostas com API própria; não são Icon Button |

## Anatomia e acessibilidade

- elemento semântico `button` com `type="button"`;
- `aria-label` obrigatório quando não há nome por outro mecanismo;
- um único `.b-icon`, sempre `aria-hidden="true"`; o collapse pode acrescentar uma marca visual não `.b-icon`, também `aria-hidden`, alternada sem mudar a caixa;
- tooltip para descoberta, sem substituir o nome acessível;
- foco visível azul;
- alvo, glyph e shape permanecem estáveis em hover, focus, active, selected, loading e disabled;
- Circle deve manter largura e altura idênticas e `border-radius: 50%`;
- não usar offsets para centralizar glyph.

## API

```html
<button class="b-icon-btn b-icon-btn--compact" aria-label="Desfazer" type="button">
  <span class="b-icon ph ph-arrow-counter-clockwise" data-icon="undo" aria-hidden="true"></span>
</button>

<span class="b-icon-btn-context--radial">
  <button class="b-icon-btn b-icon-btn--circle" aria-label="Adicionar" type="button">
    <span class="b-icon ph ph-plus" data-icon="add" aria-hidden="true"></span>
  </button>
</span>
```

A ordem recomendada é contexto → base → densidade → shape → ênfase → hook contextual.

## Critério de aprovação

A auditoria deve rejeitar:

- tamanho fora de 32/40/44px, exceto o contexto governado quadrado 36px/44px do collapse do shell;
- glyph fora de 16/20/24px para sua densidade, com caret de 16px e marca de 20px obrigatórios no perímetro de navegação;
- botão sem nome acessível;
- `.b-icon-btn--sm` ou classe paralela `icon-button`;
- Circle sem `.b-icon-btn--circle`, fora da action oficial do composer/wrapper radial ou com largura e altura diferentes;
- atributo `data-shape-role` como autoautorização;
- alteração de geometria entre estados;
- controle composto contabilizado como Icon Button standalone.
