Pular para o conteúdo
Cor

Fundações

Cor

Cinco temas, um vocabulário. Os tokens nomeiam PAPÉIS, não matizes: --brand é a ação, --ia é o agente, --positive é o sucesso. Nenhum componente sabe qual tema está no ar — ele pede bg-surface e recebe a superfície do tema vestido. Troque o tema no topo desta página e todas as amostras abaixo mudam, porque elas leem o valor real no navegador.
src/app/globals.css5 temascontraste.test.tstokens.test.ts

Papéis, não matizes

A regra que sobrevive à troca de tema não é “verde e roxo” — é “a ação e a IA ficam longe uma da outra”.

A distância é o canon

No Claro, marca e IA ficam a 120° de matiz (verde e violeta). Com a marca em azul, o violeta cairia pra 41° e os dois fundos suaves (#dbeafe e #ede9fe) virariam a mesma cor no olho. Por isso o tema Azul clínico leva a IA pro fúcsia, que devolve 72° e continua lendo como “roxo de IA”.

O troco, assumido

Branco sobre o fúcsia dá 4,71 contra 5,70 do violeta: passa o AA com menos folga. Vale, porque cor de IA que não se distingue da ação não cumpre função nenhuma, por melhor que seja o contraste dela.

O que NÃO anda com a marcaPor quê
--positiveSucesso é verde em qualquer tema. É o desfecho que fecha a conta — “compareceu” não pode virar azul num app azul.
--tick-readO ✓✓ de lida é convenção do WhatsApp, não roupa da clínica. Se andasse com o tema, um app verde diria “lida” em verde e o sinal perderia o significado.
O verde do logotipo (#16a34a)Constante congelada no SVG. Logotipo que troca de cor com o tema deixa de ser logotipo.
O verde do WhatsApp (#25D366)Marca de terceiro: vive no glifo do canal e na textura do chat.

Os cinco temas

A pessoa escolhe em Ajustes ◊ Aparência e a escolha fica na conta dela. Cada tema é um bloco [data-theme=…] em globals.css que redefine SÓ valores — nenhum componente muda.

NuncaAs peles são do APP. A identidade é o verde.

Os três temas escuros existem para o modo escuro do aplicativo, e para mais nada. Landing page, apresentação, proposta, e-mail, post, anúncio, impresso, papelaria, slide, vídeo, ícone de loja — qualquer material da Hiperclini que não seja a tela do produto usa o tema Claro, que é a identidade da marca: o verde sobre superfície branca.

A mesma trava vale pro Azul clínico: ele é uma preferência que a CLÍNICA escolhe dentro do produto, não uma variante da marca Hiperclini. Peça de marketing em azul (ou em grafite, verde profundo, ardósia) está falando a língua de um cliente específico, ou de nenhuma — não a nossa.

O seletor no topo desta página é ferramenta de conferência: ele existe pra você ver como um componente se comporta vestido de cada pele. Escolher um escuro aqui não autoriza usá-lo fora do app.

SlugNome na UIO que a pessoa ganhaAparência
data-theme="light"ClaroO padrão da casa, para sala clara.light
data-theme="azure"Azul clínicoClaro, com o azul que muita clínica prefere.light
data-theme="graphite"GrafiteEscuro neutro, contraste alto.dark
data-theme="forest"Verde profundoEscuro com um fundo esverdeado.dark
data-theme="slate"ArdósiaEscuro suave, sem preto — cansa menos de dia.dark

Comparação lado a lado

Cada bloco abaixo é uma ILHA de tema: o mesmo HTML, vestido por outro data-theme. É o mesmo truque do seletor de Aparência do app — e a razão de cada tema declarar tudo em vez de herdar.

Claro · data-theme="light"

Ocupação

esta semana

ConfirmarIA84%3 faltas

Azul clínico · data-theme="azure"

Ocupação

esta semana

ConfirmarIA84%3 faltas

Grafite · data-theme="graphite"

Ocupação

esta semana

ConfirmarIA84%3 faltas

Verde profundo · data-theme="forest"

Ocupação

esta semana

ConfirmarIA84%3 faltas

Ardósia · data-theme="slate"

Ocupação

esta semana

ConfirmarIA84%3 faltas

Armadilha já pagaTema aninhado precisa se bastar

Um tema declarado DENTRO de outro (é o caso das ilhas acima e do preview do seletor) não pode herdar nada do tema de fora — por isso cada bloco escuro em globals.css declara até o que repete o valor do claro, como --accent-dark e --ia-accent-dark. A variante dark: do Tailwind tem o mesmo cuidado embutido (um :not() que desarma a variante dentro de uma ilha clara).

Marca ◊ a cor da ação

Um verde só na UI inteira (azul no tema clínico). Ação direta, dado, item ativo.

IA ◊ a cor do agente

Reservado ao agente recepcionista. Se não veio do agente, não é roxo.

Sim

✦ Sugestão do agente

O que o agente escreveu, sugeriu ou classificou vem em roxo, com Sparkles.

Não

✦ Paciente cadastrado

Um dado que a recepção digitou não é território de IA. Roxo aqui mente sobre a origem do dado.

Neutros ◊ a escala “ink”

Do fundo da página ao texto extremo. No Claro é a escala zinc; cada tema escuro tem a sua, e o Verde profundo carrega uma gota de verde no cinza.

Armadilha já pagaA ilha ink-950 é escura nos CINCO temas

bg-ink-950 é a superfície de contraste máximo — dock, tooltip, bloco de código, painel do split de acesso. Dentro dela, texto relativo (text-ink-100) some: no tema escuro o ink-100 já é quase preto. Use tinta fixa (branco) ou --accent-dark. E note que no escuro a ilha SOBE um degrau (#26262c, não quase-preto): preto sobre preto não é ilha, é buraco.

Semânticas ◊ base · strong · soft

Quatro famílias, três papéis cada: a base pinta dot, fundo cheio e borda; o -strong é sempre o TEXTO; o -soft é o fundo suave.

A regra do -strong, medida ao vivo

As razões abaixo são calculadas no navegador, no tema que você está vendo. Troque o tema no topo e os números mudam.
text-warning-strong:1< 4.5
text-warning · o tom base:1< 4.5
text-negative-strong:1< 4.5
text-info-strong:1< 4.5
Texto secundário:1< 4.5
Caption e placeholder:1< 4.5

O -strong é o tom 700 no claro e o 300 no escuro: a direção inverte, a regra não. E a segunda amostra é o teste: no tema Claro o tom BASE sobre o -soft desaba pra ~2,2:1 e reprova — nos temas escuros ele passa, porque lá a base já é um tom claro. É por isso que a regra é “texto usa -strong”, e não “use o que parecer legível no tema em que eu estou desenhando”.

A gramática do escuro

Tema escuro não é o claro invertido. Quatro coisas mudam de sentido, e as quatro estão presas em globals.css.

Elevação vira tom, não sombra

Sombra preta não desenha sobre fundo escuro: o que sobe fica mais claro (--surface-2) com um fio de luz na borda (0 0 0 1px rgb(255 255 255 / 0.04)).

O tom -strong clareia

No claro ele é o 700 (escurece); no escuro é o 300. A regra do canon continua: texto SEMPRE no -strong.

Botão colorido inverte a tinta

O fundo clareia pro tom 400 e o texto vira o 950 da família (--brand-fg, --ia-fg, --warning-fg). Nunca text-white num botão.

Véu de tinta não escurece o escuro

--scrim no claro é preto a 40%; no escuro sobe pra 65% e o --veu da película deixa de ser a superfície e passa a ser o fundo — recuar no escuro é afundar no preto, não clarear.

Tokens de propósito único

Cores que existem porque um significado específico não cabia em nenhuma família. Nenhuma delas é decoração.
TokenO que éPor que não usa a família
--tick-readO ✓✓ azul de mensagem lida.É recibo do WhatsApp. No Azul clínico ele fica AINDA mais fundo (blue-800), pra não sumir na bolha azul-clara nem virar a tinta da marca.
--agora / --agora-soft / --agora-strongO fio do horário corrente na grade da agenda, e a etiqueta da hora.Rosa, não vermelho: nos temas escuros --negative e --agora seriam o mesmo vermelho e o fio sumiria dentro do cartão de “faltou”. E “agora” não é erro — é posição do relógio.
--hatchO triplet RGB da hachura de fora-do-expediente (o alpha fica no consumidor).Risco preto não desenha sobre fundo escuro: nos temas escuros vira 255 255 255.
--scrim / --scrim-suave / --scrim-tenueOs três véus: diálogo e gaveta · busca com desfoque · captura de clique de fora.Carregam a própria transparência porque no escuro não basta trocar a cor — é o preto puro que passa a fazer o trabalho.
--veuA cor de “para onde a tela recua” no foco em camadas.No claro é a superfície (o conteúdo se dissolve no branco); no escuro é o fundo.
--surface-hoje / --surface-hoje-hoverA coluna de HOJE na agenda.É color-mix de --brand-muted com --surface, resolvido no uso. Opaca de propósito: cabeçalho e faixa “dia todo” ficam grudados no topo, e tinta transparente deixaria os compromissos passarem por baixo.
--evt-fundo-l/c · --evt-texto-l/c · --evt-borda-l/cA receita OKLCH da cor de um compromisso.O banco guarda o NOME da cor; a tinta é conta do tema. OKLCH porque amarelo e azul no mesmo lightness pesam igual na tela — em HSL o amarelo salta.
globals.css — a cor do compromisso é montada no tema, não no componente
.evt {
  background: oklch(var(--evt-fundo-l) calc(var(--evt-fundo-c) * var(--evt-k, 1)) var(--evt-h));
  color:      oklch(var(--evt-texto-l) calc(var(--evt-texto-c) * var(--evt-k, 1)) var(--evt-h));
  border-color: oklch(var(--evt-borda-l) calc(var(--evt-borda-c) * var(--evt-k, 1)) var(--evt-h));
}

/* A FORMA é o ESTADO e sobrevive à cor escolhida:
   .evt-listrado  agendado — tinta pela metade, ainda é promessa
   .evt-vazado    faltou   — o buraco na agenda precisa se ver vazado
   .evt-check     compareceu — o carimbo cabe num cartão de 15 min porque é um caractere */

Status da jornada

Os estados do paciente não ganham cor nova: reusam a semântica. O significado (rótulo, cor, ordem) mora no domínio — cor nova aqui é erro.
Agendado· consulta futura marcadaConfirmado· o paciente confirmou presençaCompareceu· esteve na clínica — o único selo CHEIOFaltou· no-show, vira recuperávelFantasma· sem resposta: inatividade, nunca “perdido”Recuperável· oportunidade viva
selo leve: dot + rótulo, cada cor vinda de um token semântico — zero matiz novo

Armadilha já pagaO tema Azul revelou uma inversão de dois anos

No tema Claro, --brand e --positive são o MESMO verde — e isso escondia que a agenda pintava “Compareceu” com a MARCA e “Confirmado” com o SUCESSO, invertido em relação ao que o canon sempre disse. O Azul clínico separou os dois e o erro apareceu. Corrigido: compareceu é verde em qualquer tema (é o desfecho que vale dinheiro) e confirmado veste a marca.

Como o tema chega na tela

Sem flash, sem useEffect, sem next-themes: o primeiro HTML já vem vestido.
src/app/layout.tsx
const tema = await temaDoEspelho();   // cookie hc-tema (espelho de user_settings)

<html data-theme={tema === TEMA_PADRAO ? undefined : tema}>
PeçaOndeNota
A verdadeuser_settings.themeÉ da conta: entrar noutro computador já traz o tema junto.
O espelhocookie hc-tema (__Host- em produção)O servidor precisa da resposta antes de qualquer query. O prefixo __Host- impede um subdomínio irmão de plantar um espelho falso.
A pinturaatributo data-theme no <html>O tema padrão NÃO carimba o atributo — :root já é o claro.
Os nativoscolor-scheme: light | darkSelect, campo de data e barra de rolagem seguem a UI em vez do SO. Era o que pintava controles escuros por cima do app claro.
A moldura do celularTEMA_BG (meta theme-color)Meta tag não lê CSS var — é o único espelho manual do --bg, e há teste comparando os dois.

Regras de cor

O que a máquina cobra e o que a revisão cobra.

Nunca hex solto no componente

Sempre a classe utilitária (bg-brand, text-fg-muted, border-border). O teste tokens.test.ts varre src/ e reprova cor literal fora das exceções declaradas.

Cor nova é decisão de design system

Não do componente. Cor nova entra por globals.css, nos CINCO temas, e aparece aqui.

Texto semântico usa o -strong

text-warning-strong, text-negative-strong… O tom base fica pra dot, fundo e borda.

Tinta sobre botão colorido vem do -fg

text-brand-fg, text-ia-fg. Nunca text-white: no escuro o botão clareia e o branco deixa de ler.

A variante dark: é exceção, não ferramenta

Quase tudo troca pelo token. dark: existe pro caso pontual que INVERTE (uma pílula escura no claro tem que ficar clara no escuro).

Sombra colorida é token próprio

As sombras utilitárias têm tinta por tema, e a var é opaca: compor cor na utility (shadow-sm shadow-brand/20) deixa de funcionar em silêncio. Ver --shadow-glow-ia.

NotaDébitos congelados

Cinco pares do design CLARO já reprovavam AA antes dos temas existirem, e corrigi-los é decisão de cor do founder. Eles não foram dispensados do teste: ficam congelados no valor de hoje — piorar reprova, e melhorar obriga a baixar a constante. O débito só anda numa direção.