Tokens
Variáveis OKLCH, sua classe Tailwind, e o sistema de tema duplo usado pelo dashboard.
Todos os tokens vivem em apps/client/app/globals.css. O sistema suporta dois temas via classe em <html>: .light e .dark. Cada nome de token resolve para um valor diferente por tema; a mesma utility do Tailwind (bg-card, text-foreground, border-border, etc.) faz a coisa certa nos dois contextos.
A escala base vem de uma engenharia reversa do Geist design system do vercel.com (research em docs/design-research/vercel/STYLE-GUIDE.md). O body é 15px (definido em html); as primitivas shadcn, text-sm (~13px), e text-base (15px) derivam daí.
Sempre referencie a classe semântica. Nunca hardcode o literal OKLCH em um componente.
Superfícies (elevadas sobre o bg da página)
| Token | Classe | Light | Dark |
|---|---|---|---|
--background | bg-background | oklch(0.985 0 0) (~#FAFAFA) | oklch(0 0 0) (#000) |
--foreground | text-foreground | oklch(0.21 0 0) (~#171717) | oklch(0.94 0 0) (~#EDEDED) |
--card | bg-card | oklch(1 0 0) (#FFF) | oklch(0.087 0 0) (~#0A0A0A) |
--popover | bg-popover | oklch(1 0 0) | oklch(0.087 0 0) |
--muted | bg-muted | oklch(0.95 0 0) | oklch(0.21 0 0) |
--muted-foreground | text-muted-foreground | oklch(0.45 0 0) | oklch(0.62 0 0) |
O bg da página (--background) é a cor mais plana; cards, popovers e outras superfícies elevadas usam --card, que fica um passo de luminosidade na direção do inverso. Isso evita problemas de stacking de alpha quando um card está sobre outro.
CTA — paper-white sobre preto, preto sobre branco
| Token | Classe | Light | Dark |
|---|---|---|---|
--primary | bg-primary | oklch(0.21 0 0) (quase-preto) | oklch(0.94 0 0) (paper-white) |
--primary-foreground | text-primary-foreground | oklch(0.98 0 0) | oklch(0 0 0) |
--accent | bg-accent | oklch(0 0 0 / 0.06) | oklch(1 0 0 / 0.06) |
--accent-foreground | text-accent-foreground | oklch(0.21 0 0) | oklch(0.94 0 0) |
--primary é o fill inverso ao bg — a CTA canônica. --accent não é uma cor de marca; é o overlay de hover (transparente) que as primitivas shadcn usam para indicar estado ativo/hover. Para cor de marca use --brand.
Marca & info — Vercel blue
| Token | Classe | Ambos os temas |
|---|---|---|
--brand | bg-brand, text-brand | oklch(0.591 0.227 256) (~hsla(212, 100%, 48%, 1)) |
--brand-foreground | text-brand-foreground | oklch(0.98 0 0) |
--info | bg-info, text-info | alias de --brand |
--ring | ring-ring | --brand (focus rings usam a cor de marca) |
Use --brand para links, badges informativos, highlights inline, e focus rings. Não use como bg de botão — os botões ficam paper-white/black via --primary. Isso reflete a separação do Vercel: o azul é "acento informativo", o contraste é "ação primária".
Cores de status
| Token | Classe | Light | Dark |
|---|---|---|---|
--success | bg-success, text-success | oklch(0.55 0.13 152) | oklch(0.62 0.135 152) |
--warning | bg-warning, text-warning | oklch(0.74 0.16 70) (âmbar) | igual |
--destructive | bg-destructive, text-destructive | oklch(0.59 0.21 22) (vermelho) | igual |
Use a primitiva <StatusBadge> (components/dashboard/status-badge.tsx) para renderizá-los consistentemente. Combine sempre cor + ícone/ponto + texto — nunca use só cor (regra de a11y do Vercel, ver STYLE-GUIDE §3.5).
Cores de stage (ambientes)
Reservadas para indicadores de ambiente quando expusermos stages de deploy. Nada usa ainda, mas documentadas para não as repintar inconsistentemente.
| Token | Classe | Hex | Uso |
|---|---|---|---|
--develop | text-develop | #0a72ef | Ambiente de desenvolvimento |
--preview | text-preview | #de1d8d | Deployments de preview |
--ship | text-ship | #ff5b4f | Produção |
Bordas — box-shadow, não 1px solid
O padrão do Vercel: bordas de card são shadows, não border: 1px solid. Evita a matemática de box-sizing (a borda não consome espaço de layout) e compõe bem com drop shadows.
--border-hairline: 0 0 0 1px <alpha hairline>;
--border-hairline-inset: inset 0 0 0 1px <alpha mais sutil>;
--border-hairline-large: hairline + drop shadows para cards elevados;Três utilities expostas em @layer utilities:
border-hairline— borda hairline outer, o defaultborder-hairline-inset— linha inner sutil (para headers de tabela, scroll containers)border-hairline-lg— borda + drop shadow composto para cards flutuantes / popovers
Os componentes existentes que usam border-border (a versão 1px solid) continuam funcionando. Migre-os gradualmente quando forem reescritos — não reescreva primitivas shadcn intactas.
Charts
--chart-1 a --chart-5 são monocromos (foreground puro descendo até muted), com --chart-5 fazendo alias para --brand para ênfase quando uma série precisa se destacar.
Sidebar
Uma sub-escala pequena (--sidebar, --sidebar-foreground, --sidebar-border, --sidebar-accent, …) move alguns passos de luminosidade para que o rail de nav do dashboard se leia como uma superfície distinta sem quebrar o monocromático.
Utilities custom
Definidas em globals.css @layer utilities:
.label-mono— label mono pequeno em uppercase com letter-spacing 0.18em, foreground a 55% alpha. Envolva em<MonoLabel>(ver primitives)..border-hairline,.border-hairline-inset,.border-hairline-lg— box-shadow-as-border (ver acima)..shadow-soft/.shadow-soft-lg— drop shadows ajustadas para a base escura..card-premium/.card-lift/.card-glow— efeitos só de landing (UseDeploy hero cards). Não use no dashboard.
Escala de radius
--radius: 0.5rem (8px effective em base 15px)
--radius-sm: calc(var(--radius) - 2px)
--radius-md: var(--radius)
--radius-lg: calc(var(--radius) + 2px)
--radius-xl: calc(var(--radius) + 6px)Use rounded-md para a maioria dos cards, rounded-sm para chips, rounded-lg para overlays flutuantes.
Tipografia
Geist Sans + Geist Mono são carregadas em app/layout.tsx. Use font-sans (default) ou font-mono. O body tem font-feature-settings: "cv11", "ss01" ativado para os stylistic alternates do Geist — não override globalmente.
O font-size do body é 15px em <html> — entre os 14 do Vercel (mais denso) e os 16 default (mais acessível). Todas as utilities text-* derivam dessa base.