# F3.I1.T1 — Tailwind 4 + daisyUI 5 + Lucide vendorizados (zero CDN)

| Campo | Valor |
|---|---|
| **Fase** | F3 — Layout & UX |
| **Issue** | F3.I1 — Design system (plano 09) |
| **kd task** | `task_01qocc32` (`closed`) |
| **Âncora** | `wiki/implementation/03-layout-ux.md` |
| **Status da revisão** | 🔧 com correções |

## O que foi implementado

- Tailwind 4 + daisyUI 5 como base de estilo; **Lucide** (e marcas do Simple Icons) vendorizados em SVG, renderizados por `<x-ui::icon>` (`Layout\Design\IconSet`).
- Gate `tools/vendor-check.sh` (allowlist fechada de origens externas) e `tools/assets-licenses-check.php` (npm + assets + binários).
- Sem CDN de fonte/ícone/JS.

## Arquivos para revisar

### Configuração/build
- `package.json`, `package-lock.json`
- `vite.config.js`
- `eslint.config.js`

### Layout / ícones
- `src/layout/Design/IconSet.php`
- `src/layout/Components/ui/icon.blade.php`
- `src/layout/Assets/icons/**` (lucide/*.svg, brand/*.svg)
- `src/layout/Assets/css/icons.css`
- `src/layout/Assets/icons/README.md`

### Gates
- `tools/vendor-check.sh`
- `tools/assets-licenses-check.php`
- `tests/Feature/IconTest.php`

## Pontos de revisão

### PHP 8.4
- [ ] `declare(strict_types=1)`; tipos nativos (union/enum/`readonly`); sem `mixed` desnecessário.
- [ ] Dependências **injetadas** (nenhum `new`/`app()`/`resolve()` no corpo); sem traits/abstract/generics.
- [ ] `match` em vez de cadeias de `if`; `?->`/`??`; sem código morto; PHPStan `max` limpo.

### Laravel 12
- [ ] Nativo primeiro (Eloquent casts/scopes, `FormRequest`, `Gate`, scheduler, events) — sem reimplementar.
- [ ] Sem closure em rota; resources/rotas nomeadas; `config()` só lê, `env()` só em `config/`.
- [ ] Migração **idempotente**; `down()` → `backup_*` (nunca `DROP`); sem `orderBy` cru quando `latest/oldest` serve.

### HTML semântico + a11y (eMAG/WCAG 2.2 AA)
- [ ] Um `<main>`, headings em nível correto, landmarks; só ARIA quando necessário.
- [ ] Alvos ≥ 24 px (≥ 44 px em ponteiro grosso); foco visível; rótulos em todos os campos; contraste (axe).
- [ ] Funciona **sem JS**; `sniffCSS` sem `fail`/`warn` fora do ledger.

### CSS moderno
- [ ] `oklch`, `clamp`, `rem`/`fr`/`dvh`/`%`; `@layer` (a11y por último); `@property`; subgrid com fallback.
- [ ] Sem `!important`, sem `style="…"` inline, sem hex/rgb (exceto justificado); sem CDN.

### Decisões do projeto (ADRs)
- [ ] Respeita a ADR do escopo (ver cabeçalho) e não escapa das demais (001, 002, 004, 013, 015…).
- [ ] Determinismo: relógio/id injetados, ordem explícita, dados idempotentes (ADR-001).

### i18n (ADR-012)
- [ ] Nenhuma string visível fixa; 4 locales com paridade de chaves; `route()`/`localized_url()` (nunca path literal).

### Observabilidade/segurança/testes
- [ ] Span + `log_event('{module}.{action}')` com atributos `scalar|null`, **sem PII** (ADR-024).
- [ ] Teste que falha sem a mudança (vermelho→verde) + evidência no `kd`; `make quality` 2×.

### Específicos desta task

- [ ] `IconSet` resolve `name="home"` e `name="lucide-home"`; nome desconhecido **não** gera request.
- [ ] Todo ícone de manifesto e do layout tem SVG vendorizado (`IconTest`).
- [ ] Nenhuma dependência GPL/AGPL; `THIRD_PARTY_LICENSES_ASSETS` atualizado.

## Comandos úteis

```bash
make quality            # lint + PHPStan max + gates + testes
make e2e                # Playwright + axe (se a task toca UI)
make check-boundaries   # fronteiras core/services/layout/modules
```

---

> Revisar contra `AGENTS.md`, `wiki/adr/` e o plano citado. Registrar achados no `kd` (`kd write --anchor`) e, se houver correção, teste de regressão.

## Notas da revisão

| Data | Revisor | Resultado | Observações |
|---|---|---|---|
| 2026-10-19 | agente | 🔧 | **A** (alto, D7/D13) **6 ícones** usados em views de módulo/serviço não tinham SVG vendorizado e renderizavam **nada** (`pencil`/`archive`/`eye-off`/`send`/`building-2` em Notícias/DadosAbertos/Lgpd + `minus` na toolbar do RichText); o `IconTest` só varria `src/layout` (e não a prop `icon=`) — ponto cego do gate. Corrigido: SVGs copiados de `node_modules/lucide-static` (cabeçalho ISC), `THIRD_PARTY_LICENSES_ASSETS` 71→77, gate ampliado para todo `src` + prop da toolbar; vermelho→verde (`pencil`, depois `minus`) (`error_01w8n8et`). **B** (observação) `{!! $icon['inner'] !!}` confia no SVG vendorizado (verificado: sem `<script>`/`on*`/`javascript:`; só `xmlns` e URLs de licença) (`risk_00flr3qt`). Verificado OK: allowlist fechada do `vendor-check` (única menção externa são namespaces/URLs de licença nos SVG), licenças permissivas (Lucide ISC, Simple Icons CC0, MPL só `lightningcss` build-only), `lucide-static` pinado no lock, tema daisyUI via tokens, `eslint` ES2025 e `precompress` determinístico (coberto na F5.I1.T3). Evidência: `make check E2E=1` verde 2× (20 OK · 0 FAIL · 1 SKIP), `IconTest` 8 testes/84 asserções. |

> Resultado: `✅ revisado` · `🔧 com correções` · `⏭️ delegado` (com justificativa).
