Design System — Orquestro

Este documento é a fonte única de verdade do visual do Orquestro. Toda tela nova deve seguir estas diretrizes. Qualquer mudança de design começa aqui — não direto no código.


1. Princípios

PrincípioDescrição
Denso, não poluídoInformação comercial é densa. Priorize espaço útil sem sacrificar respiração.
Hierarquia claraO usuário deve saber, em 2 segundos, o que é mais importante em cada tela.
Ações visíveisBotões e ações primárias nunca ficam escondidos. Ações destrutivas têm confirmação.
IA sugere, humano decideConteúdo gerado por IA tem marcação visual própria — nunca parece um fato.

2. Cores

O sistema usa uma paleta Material Design 3 adaptada, com primário em navy escuro. Os tokens estão em src/app/globals.css.

Paleta principal

Token CSSValor hexUso
--primary#011323Sidebar, botões primários, links de ação
--background#f8fafbFundo geral da aplicação
--foreground#191c1dTexto principal

Superfícies (do mais claro ao mais escuro)

Token CSSValor hexUso típico
--v-surface-container-lowest#ffffffCards, modais, tabelas
--v-surface-container-low#f2f4f5Hover de linha, fundo de input
--v-surface-container#eceeefDivisórias, muted
--v-surface-container-high#e6e8e9Bordas de card, header de tabela
--v-surface-container-highest#e1e3e4Badges neutros

Textos sobre superfície

Token CSSValor hexUso
--v-on-surface#191c1dTexto de maior peso (títulos, dados)
--v-on-surface-variant#43474cTexto secundário (labels, metadados)
--v-outline#74777dTextos desabilitados, placeholders
--v-outline-variant#c4c6cdBordas de input, divisórias
Token CSSUso
--sidebar#011323Fundo da sidebar
--sidebar-foreground#ffffffTexto e ícones
--sidebar-accentrgba(255,255,255,0.07)Item de nav ativo/hover
--sidebar-borderrgba(255,255,255,0.08)Divisórias internas

Semânticas

TokenValorUso
--v-success-container#004536Textos de sucesso, status “ganho”
--v-on-success-container#54b89bÍcones e labels de sucesso
--destructive#ba1a1aErros, ações destrutivas
--v-secondary#456366Ícones neutros, elementos de apoio

Como usar em código

// Tailwind usa o prefixo do token mapeado em @theme
<div className="bg-surface-container-lowest border border-outline-variant text-on-surface">
<span className="text-on-surface-variant">
<button className="bg-primary text-on-primary">

3. Tipografia

Fonte: Lato (400, 700, 900) — carregada via Google Fonts no layout.tsx.

Escala

Classe TailwindTamanhoPesoUso
text-display-lg32px / lh 40px700Títulos de página (Bem-vinda, Ana!)
text-headline-md24px / lh 32px600Seções principais
text-headline-sm18px / lh 24px600Títulos de card, sub-seções
text-stats-number28px / lh 34px700Números de KPI
text-body-lg16px / lh 24px400Subtítulo de página, parágrafos
text-body-md14px / lh 20px400Texto corrente de tabelas e formulários
text-label-md12px / lh 16px500Labels de campo, badges, tabs de filtro

Exemplos

<h2 className="text-display-lg font-bold text-on-surface">Bem-vinda, Ana!</h2>
<p className="text-body-lg text-on-surface-variant">Subtítulo da página</p>
<h3 className="text-headline-sm text-on-surface">Título de card</h3>
<span className="text-label-md text-on-surface-variant">Label de campo</span>
<div className="text-stats-number font-bold text-on-surface">42</div>

4. Ícones

Biblioteca: Material Symbols Outlined — variável (filled 0, weight 400, optical size 20–48).

Carregada via <link> no layout.tsx. Uso via <span>:

<span className="material-symbols-outlined text-[20px]">dashboard</span>
<span className="material-symbols-outlined text-xl text-primary">trending_up</span>

Tamanhos padrão

ContextoClasse de tamanho
Ícone na sidebartext-[20px]
Ícone em botãotext-[18px]
Ícone em topbartext-[24px] (padrão)
Ícone decorativo grandetext-4xl
Ícone em badge / inlinetext-sm

Ícones canônicos do Orquestro

Tela / AçãoÍcone
Logo / identidadetoken
Dashboarddashboard
Leads / Pipelinetrending_up
Usuáriosmanage_accounts
Configuraçõessettings
Auditoriasecurity
Sugestão de IAauto_awesome
Gate / Decisão humanagavel
Arquivo / uploadupload_file
Origem da informaçãoinfo
Sucesso / validadocheck_circle
Erro / rejeitadocancel
Pendenteschedule
Notificaçõesnotifications
Ajudahelp_outline
Sairlogout

5. Espaçamento e layout

Variáveis de espaçamento

TokenValorUso
--spacing-sidebar-width260pxLargura fixa da sidebar
--spacing-card-padding24pxPadding interno de todos os cards
--spacing-container-margin32pxPadding da área de conteúdo principal
--spacing-gutter-md16pxEspaço entre elementos dentro de um card
--spacing-gutter-lg24pxEspaço entre seções / cards

Uso em Tailwind

// padding de card
<div className="p-card-padding">
 
// padding da área de conteúdo
<div style={{ padding: 'var(--spacing-container-margin)' }}>
 
// gap entre cards
<div className="grid gap-4">   // gutter-md
<div className="space-y-6">   // gutter-lg aprox.

Estrutura de tela

┌──────────────┬──────────────────────────────────────────┐
│              │ Topbar (h-16, borda inferior)             │
│   Sidebar    ├──────────────────────────────────────────┤
│  (260px)     │                                          │
│  bg-primary  │  Conteúdo (padding 32px)                 │
│              │                                          │
│              │                                          │
└──────────────┴──────────────────────────────────────────┘

6. Componentes

Card padrão

<div className="bg-surface-container-lowest rounded-xl border border-surface-container-high shadow-[0_4px_20px_rgba(0,0,0,0.04)] p-card-padding">
  ...
</div>

Card clicável (hover state)

<Link className="group bg-surface-container-lowest p-card-padding rounded-xl shadow-[0_4px_20px_rgba(0,0,0,0.04)] border border-surface-container-high hover:border-primary hover:shadow-md transition-all block">
  <span className="group-hover:text-primary transition-colors">Texto</span>
</Link>

Card de KPI

<div className="bg-surface-container-lowest p-card-padding rounded-xl shadow-[0_4px_20px_rgba(0,0,0,0.04)] border border-surface-container-high">
  <div className="flex justify-between items-start mb-4">
    <span className="text-body-md text-on-surface-variant">Label</span>
    <span className="material-symbols-outlined text-xl text-primary">icon_name</span>
  </div>
  <div className="text-stats-number font-bold text-on-surface">42</div>
  <div className="text-label-md text-on-surface-variant mt-1">Sub-label</div>
</div>

Tabela

<div className="bg-surface-container-lowest rounded-xl border border-outline-variant shadow-[0_4px_20px_rgba(0,0,0,0.04)] overflow-hidden">
  <table className="w-full text-left">
    <thead>
      <tr className="bg-surface-container-low border-b border-outline-variant">
        <th className="py-3.5 px-4 text-label-md text-on-surface-variant font-semibold">Coluna</th>
      </tr>
    </thead>
    <tbody className="divide-y divide-outline-variant/50">
      <tr className="hover:bg-surface-container-low/50 transition-colors">
        <td className="py-4 px-4 text-body-md text-on-surface">Dado</td>
      </tr>
    </tbody>
  </table>
</div>

Botão primário

<button className="px-4 py-2 bg-primary text-on-primary rounded-lg font-bold text-label-md hover:opacity-90 transition-opacity flex items-center gap-2">
  <span className="material-symbols-outlined text-[18px]">add</span>
  Criar lead
</button>

Botão secundário (outline)

<button className="px-4 py-2 border border-outline-variant rounded-lg bg-surface-container-lowest text-on-surface text-label-md font-bold hover:bg-surface-container-low transition-colors flex items-center gap-2">
  <span className="material-symbols-outlined text-[18px]">filter_alt</span>
  Filtrar
</button>

Badge de status

// Ativo / em andamento
<span className="inline-flex items-center px-2.5 py-1 rounded-md text-[11px] font-bold bg-teal-100 text-teal-800 border border-teal-200">
  Em andamento
</span>
 
// Ganho
<span className="... bg-green-100 text-green-800">Ganho</span>
 
// Pendente (humano precisa agir)
<span className="... bg-amber-100 text-amber-900 border border-amber-300">Pendente</span>
 
// Perdido / rejeitado
<span className="... bg-red-100 text-red-800">Rejeitado</span>
 
// Neutro
<span className="... bg-surface-container-high text-on-surface-variant">Rascunho</span>

Sugestão de IA (estado pendente)

<div className="rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 flex items-start gap-3">
  <span className="material-symbols-outlined text-amber-600 mt-0.5 shrink-0">auto_awesome</span>
  <div>
    <p className="text-body-md font-bold text-amber-900">Sugestão da IA</p>
    <p className="text-body-md text-amber-800 mt-0.5">{conteudo}</p>
    <p className="text-label-md text-amber-700 mt-2">Aguardando validação humana</p>
  </div>
</div>

Input de busca

<div className="relative flex-1 max-w-sm">
  <span className="material-symbols-outlined absolute left-3 top-1/2 -translate-y-1/2 text-outline text-lg">
    search
  </span>
  <input
    type="text"
    placeholder="Buscar..."
    className="w-full pl-10 pr-4 py-2 bg-surface text-on-surface border border-outline-variant rounded-lg text-body-md focus:border-primary focus:ring-1 focus:ring-primary"
  />
</div>

Tabs de filtro

{tabs.map((tab) => (
  <button
    key={tab.value}
    className={`px-3 py-1.5 rounded-lg text-label-md font-bold whitespace-nowrap transition-colors border ${
      ativo === tab.value
        ? 'bg-primary text-on-primary border-primary'
        : 'bg-surface-container-lowest text-on-surface-variant border-outline-variant hover:bg-surface-container-low'
    }`}
  >
    {tab.label}
  </button>
))}

7. Marcação de origem da informação (REQ-005)

Todo dado exibido que não é fato verificável deve ter um indicador visual.

Tipo de origemVisual
fatoSem marcação — exibição normal
declaracao_clienteBadge cinza claro: "Cliente declarou"
observacao_vendedorBadge azul claro: "Observação"
percepcao_indicadorBadge roxo claro: "Via indicação"
fonte_publicaBadge slate: "Fonte pública" + link
hipotese_iaBanner âmbar com ícone auto_awesome (ver componente acima)
lacunaBadge vermelho claro: "Informação em falta"
decisao_humanaBadge verde com ícone gavel: "Decisão validada"

8. Padrões de interação

Gates humanos (REQ-007)

Nenhum gate avança automaticamente. Todo avanço de gate usa:

<button className="px-4 py-2 bg-primary text-on-primary rounded-lg font-bold text-label-md flex items-center gap-2">
  <span className="material-symbols-outlined text-[18px]">gavel</span>
  Confirmar Gate 3
</button>

Seguido de modal de confirmação com resumo do que está sendo validado.

Estado vazio

<div className="py-12 text-center text-on-surface-variant">
  <span className="material-symbols-outlined text-4xl text-outline mb-2 block">inbox</span>
  <p className="text-body-md font-bold">Nenhum registro encontrado.</p>
  <p className="text-label-md mt-1">Ajuste os filtros ou crie um novo item.</p>
</div>

Carregando

<div className="flex items-center gap-2 text-on-surface-variant text-body-md">
  <span className="material-symbols-outlined animate-spin text-[20px]">progress_activity</span>
  Carregando…
</div>

Erro de permissão (informação insuficiente)

<div className="rounded-lg border border-outline-variant bg-surface-container px-4 py-3 flex items-center gap-3 text-on-surface-variant">
  <span className="material-symbols-outlined shrink-0">lock</span>
  <p className="text-body-md">Informação insuficiente — você não tem permissão para ver este dado.</p>
</div>

9. Responsividade

O MVP é desktop-first — o público-alvo usa computador durante o processo comercial. Mobile é segunda prioridade.

BreakpointComportamento
lg (1024px+)Layout completo com sidebar fixa
md (768–1023px)Sidebar colapsada (ícones apenas) — a implementar
< mdSidebar vira drawer — a implementar

10. Arquivos relevantes

ArquivoO que contém
src/app/globals.cssTodos os tokens de cor, tipografia e espaçamento
src/components/shell/sidebar.tsxSidebar escura com Material Symbols
src/components/shell/topbar.tsxTopbar branca com usuário e notificações
src/components/ui/Componentes shadcn/ui (botão, input, tabela, etc.)
src/app/(app)/layout.tsxShell geral da aplicação autenticada
src/app/(auth)/layout.tsxShell das telas de autenticação