# DESIGN.md — fonte única visual

> **Status:** Vigente (F3.I1) · **Dono:** Layout/UX · **Evolui em:** F3 (planos 09–11)
> **Decisões:** ADR-009 (UI nativa, sem Livewire/Filament), ADR-010 (web moderna),
> ADR-011 (tipografia), ADR-016 (tema como dado), ADR-025 (a11y/UX como gate).
>
> Este arquivo é a **referência visual canônica**. O token nasce aqui **e só então** entra em
> `src/layout/Assets/css/tokens.css`. Vale para o **portal** e para o **CMS** (mesmos tokens).

---

## 1. Princípios

1. **Semântica primeiro** — HTML significativo antes de qualquer estilo.
2. **Simples e previsível** — sem "magia", sem sobreposição de frameworks (ADR-001/009).
3. **Acessível por construção** — WCAG 2.2 AA + eMAG; a11y é requisito, não polimento (ADR-025).
4. **Tema é dado** — cor/marca/precedência vêm de configuração (`jsonb`), não de código (ADR-016).
5. **Conteúdo legível** — a leitura é o produto; a UI serve ao conteúdo.

---

## 2. Cadeia de estilos e camadas

- **Tailwind 4** (utilitários + `@theme`) + **daisyUI 5** (componentes) + **Lucide/marcas**
  (SVG vendorizados). **Sem** Bootstrap/jQuery/CDN/reactive-UI (ADR-009/010).
- **Build único** via Vite (feito pelo `make check`/deploy); nenhum sub-recurso externo (gate `tools/vendor-check`).
- **Ordem determinística das camadas** (`tokens.css`), com a **a11y por último**:

```css
@layer theme, base, components, utilities, overrides, a11y;
```

- **daisyUI é tematizado pelos nossos tokens**: o bridge em `tokens.css` (`:root, [data-theme='concordia']`)
  mapeia `--color-primary → var(--tenant-primary)`, `--radius-* → var(--tenant-radius)`,
  `--border → 0.0625rem` etc. Componentes daisyUI (CMS e, onde viável, portal) ficam **on-brand**.
- Overrides de tema/tenant e a11y vão em **`overrides`/`a11y`** (vencem por **camada**, não por força).
- **`!important` é proibido** no CSS do design system (o gate `DesignTokensTest` verifica).

---

## 3. Tipografia

- **Conteúdo (leitura):** **Atkinson Hyperlegible Next**, **vendorizada** (WOFF2 variable em
  `src/layout/Assets/fonts/`), exposta como **`--font-content`** e **ajustável pelo usuário** (ADR-011).
  `font-display: swap`, subset latin/latin-ext, fallback métrico com `size-adjust`.
- **Modo dislexia:** **OpenDyslexic** (WOFF2 vendorizada, OFL-1.1) como primeira família de
  `--font-content`, com o fallback métrico do Atkinson e alternativas de sistema. Só é baixada com a
  preferência ativa; o default de leitura continua Atkinson.
- **Interface:** pilha de sistema (`system-ui`) — zero download no CMS.
- **Escala fluida** com `clamp()` (**mín/máx sempre em `rem`**), `line-height` 1.6–1.75, medida
  de leitura **60–75ch**.

```css
:root {
  --font-content: 'Atkinson Hyperlegible Next', 'Atkinson Fallback', system-ui, sans-serif;
  --text-body: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
  --text-h1: clamp(1.75rem, 3vw, 2.25rem);
  --text-h2: clamp(1.375rem, 2.5vw, 1.875rem);
}
```

---

## 4. Cor

- **`oklch()` é o PADRÃO** (espaço perceptualmente uniforme, gamut P3). `hex`/`rgb` só como
  **exceção justificada** (ex.: `manifest.webmanifest`, onde o `hex` é o formato interoperável);
  o gate `DesignTokensTest` falha se aparecer `hex` no CSS do design system.
- Contraste mínimo **4.5:1** (texto normal) e **3:1** (texto grande/ícones); informação nunca só por cor.
- Dois conjuntos:
  - **Tenant** (marca, ajustável pelo CMS via `GET /theme.css`): `--tenant-primary`, `--tenant-accent`,
    `--tenant-link`, `--tenant-radius` — com `@property` (tipados).
  - **Civic Precision** (paleta institucional fixa): `--civic-ink`, `--civic-navy`,
    `--civic-yellow`, `--civic-surface`, `--civic-border`, `--civic-link`, `--civic-error`, …
  - **Pares "texto sobre fundo fixo"**: `--civic-on-ink`, `--civic-on-navy`, `--civic-on-navy-soft`,
    `--civic-on-yellow`. O fundo institucional **não** acompanha o tema; o par de texto também não —
    é o token que garante o contraste 4.5:1 em selos/badges (o `@layer a11y` ainda pode sobrescrever).
- **Estados semânticos** com prefixo `--status-` (`--status-success|warning|danger|info`) — o prefixo
  evita colisão com as variáveis de mesmo nome do daisyUI (que são preenchidas a partir destes).

---

## 5. Espaçamento, forma e elevação

- Espaço base em múltiplos de **0.25rem** via utilitários Tailwind; **fluidos** com `clamp` em rem:
  `--space-container`, `--space-section`.
- Raios: `--tenant-radius` (tenant) + utilitários; sombras discretas, nunca como única hierarquia.
- **z-index por allowlist** (evita "guerra de camadas"):

| Token | Valor | Uso |
|---|---|---|
| `--z-base` | 0 | fluxo normal |
| `--z-sticky` | 10 | cabeçalho fixo |
| `--z-dropdown` | 20 | menus |
| `--z-overlay` | 30 | `<dialog>`/popover nativos |
| `--z-toast` | 40 | avisos |

---

## 6. Foco, estados e movimento

- **Foco sempre visível** (`:focus-visible`, `base.css`): anel de 0.1875rem (`--tenant-accent`) + offset.
- Estados (`hover`/`active`/`disabled`/`invalid`) previsíveis e operáveis por teclado.
- **Alvos de toque ≥ 44×44px** (casa ≥ 24px).
- Movimento respeita `prefers-reduced-motion` **em `@layer a11y`** (sem `!important`).

---

## 7. Layout e responsividade

- Mobile-first; **container queries** com fallback `@supports`; **subgrid** onde simplificar.
- Breakpoints nomeados coerentes entre portal e CMS; **nada de `!important` nem estilo inline**.
- Grades e slots do portal seguem o **layout engine** (plano 10): slots ordenados (ADR-016);
  o `src/layout` é **só estrutura** — o módulo fornece o **fragmento** do espaço.

---

## 8. Componentes e ícones

- Componentes Blade **semânticos** com namespace: `<x-cms::button>`, `<x-cms::card>`,
  `<x-service-media::picture>`, `<x-service-seo::tags>`, `<x-ui::icon name="…" />`.
- **Ícones:** vendorizados em `src/layout/Assets/icons/{lucide,brand}`; `<x-ui::icon>` emite `<svg>`
  com `aria-hidden="true"` (decorativo) ou `role="img"` + `aria-label` (com significado).
- Vanilla JS **mínimo** e progressivo (`<dialog>`, `<details>`, popover) — conteúdo público
  funciona **sem JS** (ADR-010).

---

## 9. Acessibilidade e UX — checklist de aceite

Base: WCAG 2.2 AA + eMAG (ADR-025). Detalhe em `.agents/skills/web-accessibility/`.

- [ ] Contraste de texto/ícones conforme §4; informação nunca só por cor.
- [ ] Navegação completa por teclado, ordem de foco lógica, foco sempre visível.
- [ ] Estrutura semântica (landmarks, hierarquia de títulos, `<label>`).
- [ ] Alvos ≥ 24px sempre (≥ 44px em ponteiro grosso); formulários com rótulo, ajuda e erro associados.
- [ ] Imagens com `alt` (via Media, ADR-026); mídia com legendas quando aplicável.
- [ ] `prefers-reduced-motion` e `forced-colors` respeitados.
- [ ] Conteúdo público utilizável com **JS desabilitado**.

---

## 10. Tema como dado (ADR-016)

- Precedência: **default → global → preset → URL → instância**; a11y aplicada **por último**.
- Presets/marca definidos em `jsonb` (cores, tipografia, densidade) — **nunca** HTML/CSS solto no
  banco (ADR-017). O schema de override do tenant cobre **cor, raio e tipografia de conteúdo**
  (`--font-content`); **borda, densidade e espaçamento** pertencem ao `PresetSchema`/presets
  (ADR-016). O tenant só sobrepõe **tokens semânticos**, nunca CSS.
- **Overrides limitados por schema** (`config/design.php`): só tokens semânticos em **enums/escalas**
  ou **cor CSS validada** (`color`); valor fora do schema é **ignorado** (a camada anterior vence).
  O painel de suporte não escreve CSS — não há como “quebrar” o layout.
- **Entrega**: `GET /theme.css` (same-origin, `ETag`/`304`, `Cache-Control: public`), publicando
  `:root{--tenant-*}`; **sem `<style>` inline** (ADR-022). Sem overrides, a página **não** faz
  nenhuma requisição extra (os defaults vivem em `tokens.css`).
- **Painel (CMS)**: a identidade do CMS é dado (ADR-036) — `--cms-primary`/`--cms-accent` entram **na
  frente** da do tenant na ponte (`--color-primary: var(--cms-primary, var(--tenant-primary))`) e são
  publicadas em `GET /cms-theme.css` (same-origin, `ETag`); sem override, nenhuma requisição extra.
  Regiões (`header`/`footer`/`sidebar`) e a posição da navegação (`left|right|orbital`) também são dado;
  a largura da coluna vem de **escala fechada** (`16|18|20|22rem`) e a posição é resolvida em **CSS**
  (propriedades lógicas, sem JS de medição → CLS 0).

---

## 11. Anti-padrões (proibido)

- Bootstrap, jQuery, Livewire, Filament, Alpine/reactive-UI, CDN ou sub-recurso remoto.
- Estilo inline arbitrário, `!important`, cor literal no meio do componente.
- HTML/CSS/flag de UI persistido no banco.
- Animação sem respeitar `prefers-reduced-motion`.

---

## 12. Referências

- `wiki/adr/ADR-009-ui-cms-proprio-tailwind-daisyui.md` · `ADR-010` · `ADR-011` · `ADR-016` · `ADR-025`
- `wiki/plan/09-design-system-daisyui.md` · `wiki/plan/10-layout-engine-slots.md` · `wiki/plan/11-acessibilidade-ux-gate.md`
- `src/layout/Assets/css/{tokens,base,fonts,icons}.css` · `wiki/specs/04-acessibilidade-ux.md`
- `.agents/skills/{daisyui,css-moderno,html-moderno,javascript-moderno,web-accessibility}/`
