Guia para LLMs
Regras que agentes de código (Claude, Cursor, Copilot, Windsurf) seguem ao escrever código em projectos Request. Copia o ficheiro para a raiz do teu projecto ou aponta o agente para a URL pública.
Como usar
- Opção 1 — copiar para o projecto.
Commita. O Claude Code e Cursor lêem automaticamente ficheiros na raiz.curl -o DESIGN.md https://design.request.pt/llms.txt - Opção 2 — referenciar no CLAUDE.md / .cursorrules:
# Design system Segue sempre as regras em https://design.request.pt/llms.txt - Opção 3 — MCP / rule import. Ferramentas com suporte a fetch de regras remotas podem indexar directamente
https://design.request.pt/llms.txt.
DESIGN.md
# Request Design System — Guia para LLMs
Regras vinculativas para qualquer agente (Claude, Cursor, Copilot, etc.) que escreva código em projectos Request. Copia este ficheiro para a raiz do teu projecto, ou referencia via URL: https://design.request.pt/llms.txt
## Princípios
1. **Light mode only.** Fundos slate-50/white, texto slate-700/800/900. Nunca dark mode.
2. **Rose é acção, nunca decoração.** Só usa `rose-*` em botões primários, links, estados activos. Nunca para fundos de página ou secções inteiras.
3. **Slate para tudo o resto.** Neutros slate-50/100/200/600/700/800/900. Sem violet, amber, cyan, pink, sky, indigo.
4. **Nunca hardcode valores.** Tudo passa pelos tokens do `@request-labs/tokens`. Zero `bg-[#...]`, zero `px-[15px]`, zero `style="color: #..."`.
5. **Hanken Grotesk em h1-h6. Inter em tudo o resto.** `font-display` para títulos, `font-sans` (default) para corpo.
## Setup obrigatório
Qualquer projecto Request novo instala e configura:
```bash
pnpm add @request-labs/tokens @request-labs/brand
```
**tailwind.config.js:**
```js
const tokens = require('@request-labs/tokens/tailwind');
module.exports = {
content: ['./src/**/*.{html,js,ts,jsx,tsx,vue,blade.php,astro}'],
theme: {
extend: {
colors: tokens.colors,
spacing: tokens.spacing,
fontFamily: tokens.fontFamily,
fontSize: tokens.fontSize,
fontWeight: tokens.fontWeight,
lineHeight: tokens.lineHeight,
borderRadius: tokens.borderRadius,
boxShadow: tokens.boxShadow,
transitionDuration: tokens.transitionDuration,
transitionTimingFunction: tokens.transitionTimingFunction,
zIndex: tokens.zIndex,
},
},
};
```
**CSS global (uma vez):**
```css
@import "@request-labs/brand/fonts.css"; /* Hanken Grotesk self-hosted */
@import "@request-labs/tokens/css"; /* custom properties */
body { font-family: theme('fontFamily.sans'); }
h1, h2, h3, h4, h5, h6 { font-family: theme('fontFamily.display'); }
```
**Head (favicons do brand):**
```html
<link rel="icon" href="/favicon.ico" sizes="any" />
<link rel="icon" type="image/png" href="/favicon-32.png" sizes="32x32" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
<link rel="manifest" href="/manifest.json" />
<meta name="theme-color" content="#1d1d1b" />
```
## Cores — o que usar quando
| Papel | Classe | Quando |
|---|---|---|
| Fundo de página | `bg-slate-50` | Sempre |
| Fundo de card / painel | `bg-white` + `border-slate-200` | Sempre |
| Header / footer de marca | `bg-brand-dark` (#1d1d1b) + `text-white` | Só a shell da app |
| Acção primária | `bg-rose-600 hover:bg-rose-700 text-white` | Botões submit, CTAs, links principais |
| Acção secundária | `border-slate-300 bg-white hover:bg-slate-50 text-slate-700` | Cancel, voltar |
| Acção destructiva | `bg-red-600 hover:bg-red-700 text-white` | Delete, logout |
| Texto principal | `text-slate-800` ou `text-slate-900` | Default |
| Texto secundário | `text-slate-600` | Descrições, meta |
| Texto terciário / placeholder | `text-slate-400` ou `text-slate-500` | Hints, empty states |
| Sucesso | `bg-emerald-50 text-emerald-800 border-emerald-200` | Alerts, badges de status "ready/done" |
| Erro | `bg-red-50 text-red-800 border-red-200` | Alerts, validation |
| Aviso | `bg-amber-50 text-amber-800 border-amber-200` | Apenas em alerts. Não noutros sítios. |
| Info | `bg-sky-50 text-sky-800 border-sky-200` | Apenas em alerts. Não noutros sítios. |
**NÃO FAZER:**
- `bg-gradient-to-r from-violet-500 to-pink-500` — nunca gradientes coloridos.
- `bg-blue-500` para primária — a primária é **rose**.
- Mais do que 2 cores não-neutras no mesmo ecrã.
## Tipografia
```html
<h1 class="text-4xl font-bold text-slate-900">...</h1> <!-- Hanken Grotesk -->
<h2 class="text-2xl font-semibold text-slate-900">...</h2>
<p class="text-base text-slate-700">...</p> <!-- Inter -->
<small class="text-sm text-slate-600">...</small>
```
- **Tamanho mínimo de input:** `text-base` (16px). Nunca `text-sm` em inputs (mobile zoom).
- **Line-height:** default `leading-normal` (1.5). Títulos podem ir `leading-tight`.
- **Pesos:** 400 (regular), 500 (medium), 600 (semibold), 700 (bold). Nada de 300 ou 900.
## Spacing (escala 4px)
Sempre da escala. `1` = 4px, `2` = 8px, `3` = 12px, `4` = 16px, `6` = 24px, `8` = 32px, `12` = 48px, `16` = 64px.
Nunca `p-[13px]`, nunca `gap-[7px]`. Se precisares de algo que não existe, usa o valor mais próximo ou adiciona aos tokens.
## Border radius
- `rounded` (4px) ou `rounded-md` (6px) — default para inputs, cards pequenos
- `rounded-lg` (8px) — cards, painéis
- `rounded-xl` (12px) — hero blocks
- `rounded-full` — avatars, badges circulares
- **Sem `rounded-none` e sem `rounded-3xl`+**
## Shadows
- `shadow-sm` — cards neutros
- `shadow-md` — hover state, dropdowns
- `shadow-lg` — modals, popovers
- Sem sombras coloridas, sem sombras dramáticas.
## Motion
| Token | Quando |
|---|---|
| `duration-instant` (75ms) | Hover states, focus rings |
| `duration-fast` (150ms) | Micro-interacções, botões, toggles |
| `duration-base` (250ms) | Default. Dropdowns, modais a abrir |
| `duration-slow` (400ms) | Transições de página, grandes layouts |
Easing default: `ease-out` para entrada, `ease-in` para saída, `ease-in-out` quando ambos.
```html
<button class="transition-colors duration-fast ease-out ...">
```
## Z-index
Usa sempre os tokens, nunca números arbitrários:
```
z-dropdown (1000) — menus, autocompletes
z-sticky (1100) — headers sticky
z-overlay (1200) — backdrop de modais
z-modal (1300) — modais
z-popover (1400) — popovers
z-toast (1500) — notifications
z-tooltip (1600) — sempre no topo
```
## Ícones
Sempre **Lucide** (`lucide-react`, `lucide-vue-next`, `lucide-static`, `blade-lucide-icons`).
- Tamanhos: `w-4 h-4` (small), `w-5 h-5` (default), `w-6 h-6` (large)
- Stroke 2 (default do Lucide). Não mudar.
- `aria-hidden="true"` quando decorativo ao lado de texto; `aria-label="..."` quando sozinho num botão.
- Cor via `text-*` (o SVG é `currentColor`).
Nunca misturar bibliotecas (Lucide + Heroicons + FontAwesome no mesmo projecto).
## Componentes
Shadcn-style: **copy/paste**, não lib. Vai a https://design.request.pt/components, copia o código, adapta à tua stack. Cada projecto é dono do próprio código.
**Forma canónica de um botão (referência):**
```html
<button class="inline-flex items-center gap-2 px-4 py-2 bg-rose-600 text-white font-medium rounded-md hover:bg-rose-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-rose-500 focus-visible:ring-offset-2 transition-colors duration-fast disabled:opacity-50 disabled:cursor-not-allowed">
Label
</button>
```
**Forma canónica de um input:**
```html
<input class="w-full px-3 py-2 text-base border border-slate-300 rounded-md focus:outline-none focus:ring-2 focus:ring-rose-500 focus:border-rose-500 disabled:bg-slate-50 disabled:cursor-not-allowed" />
```
## Acessibilidade (não negociável)
- **Contraste AA** mínimo em todo o texto. `text-slate-400` só em fundos brancos.
- **Focus visível** em tudo que é interactivo (`focus-visible:ring-2 focus-visible:ring-rose-500 focus-visible:ring-offset-2`).
- **Touch target** mínimo 44x44px em mobile. Ícones sozinhos precisam de padding.
- **Labels em inputs** via `<label>` ou `aria-label`. Placeholder não substitui label.
- **Skip link** em layouts com muita nav.
- **Idioma** declarado no `<html lang="pt-PT">`.
## Content / Copy (PT-PT)
- Tratamento: **tu** (informal, chill). Nunca "você".
- Botões: verbo no imperativo (Guardar, Cancelar, Enviar). Nunca "Click aqui".
- Erros: explicar o que correu mal + o que fazer (não "Ocorreu um erro").
- Datas: `18 de Abril de 2026` (longo) ou `18/04/2026` (curto). ISO só em APIs.
- Números: separador milhares `.`, decimal `,`. `€1.234,56`.
## Checklist antes de commitar
- [ ] Zero classes com valores arbitrários (`[...]`)
- [ ] Zero `style="..."` inline para cores/spacing
- [ ] Nenhuma cor fora do palette (rose, slate, emerald/red/amber/sky para semantic)
- [ ] Títulos em `font-display`, corpo em default (`font-sans`)
- [ ] Focus visible em tudo interactivo
- [ ] Inputs com `text-base`
- [ ] Ícones da Lucide, com `aria-*` correcto
- [ ] Touch targets >= 44x44 em mobile
- [ ] `lang="pt-PT"` no HTML
## Recursos
- Docs completas: https://design.request.pt
- Tokens: https://design.request.pt/tokens
- Componentes (copy/paste): https://design.request.pt/components
- Brand (logos, fontes): https://design.request.pt/brand
- Ícones: https://design.request.pt/icons
- npm: `@request-labs/tokens`, `@request-labs/brand`