Pular para o conteúdo
Forma & elevação

Fundações

Forma & elevação

Regra de bolso: toca = pílula · contém = canto 16. Duas formas no vocabulário, mais o canto interno derivado — é isso que faz qualquer tela ser reconhecível de longe. Elevação vem de borda 1px e um fio de sombra; sombra pesada só no que FLUTUA.
--radius: 0.75rem3 formas + 2 exceções4 níveis de elevação

O vocabulário de forma

Três formas. A pergunta que decide não é o tamanho do elemento — é o que ele FAZ.

Pílula

rounded-full

Tudo que você TOCA ou lê como estado: botão, campo de uma linha, filtro, badge, avatar, item de nav, tooltip, barra de ações.

Canto 16

rounded-xl · 16px

Tudo que CONTÉM coisas: card, modal, tabela, menu aberto, painel, aviso, textarea, bloco de código.

Interno

rounded-md · 10px

Só DENTRO de um contêiner (canto externo − padding): item de menu, linha de escolha, tapete de edição, bolha de chat, código inline.

A conta dos raios

Tudo deriva de um token só. Mexer nele muda o app inteiro de forma coerente — e é por isso que ele nunca é mexido por capricho.
globals.css
--radius: 0.75rem; /* 12px — a base do remap */

--radius-sm: calc(var(--radius) - 4px); /* 8px */
--radius-md: calc(var(--radius) - 2px); /* 10px ← o canto interno */
--radius-lg: var(--radius); /* 12px */
--radius-xl: calc(var(--radius) + 4px); /* 16px ← o "contém" */
--radius-2xl: calc(var(--radius) + 8px); /* 20px */

--radius-evt: 6px; /* 6px ← NÃO deriva do remap */

Armadilha já pagaO 2xl precisa ser declarado

Sem a última linha, rounded-2xl fica no default do Tailwind v4 (16px) — igual ao xl remapeado — e quem pede um canto MAIOR recebe o mesmo canto, sem nenhum erro na tela.
ClasseValorUso canônico
rounded-full9999pxToca ou é estado
rounded-2xl20pxPeça flutuante grande: a barra de ações em massa e o cartão de agendamento da agenda
rounded-xl16pxContém — e é o raio do toast (o Sonner recebe calc(--radius + 4) = 16px)
rounded-lg12pxRaro — a base crua, quase nunca usada direta
rounded-md10pxItem interno
rounded-sm8pxAlvo de foco em texto — o focus-ring de link e de célula
rounded-evt6pxExceção medida: o cartão de compromisso da agenda
rounded-[3px]3pxExceção medida: checkbox e marca-texto da busca

As exceções — e só elas

ElementoFormaPor quê
Checkboxrounded-[3px]Redondo pareceria radio (opção única). Um dos dois valores fora da escala no app inteiro, compartilhado com a marca-texto da busca. O canto duro afasta a caixinha da bolinha de cor que vive ao lado dela na agenda.
Cartão de compromisso (agenda)rounded-evt · 6pxO outro valor fora da escala. A grade da agenda copia o Google ao pé da letra, e o raio dele é 6px — medido em 28/08 ajustando um arco de círculo ao canto de um print (rms de 0,089px, escala aferida por duas âncoras). Em rounded-sm o cartão da Semana, que tem a altura exata do deles, saía 33% mais redondo. É token, e não valor literal, porque seis lugares precisam do mesmo canto: cartão, fantasma do arrasto e bloco em criação, nas duas visões.
Textarearounded-xlMulti-linha não funciona como pílula: a curva cortaria a primeira linha.
Recorte de visão (segmented control)trilho rounded-full bg-ink-100 p-1O botão ativo vira uma pílula de superfície com shadow-xs dentro do trilho. É o que o app usa na Agenda e na janela de Filtros de Cadastros — ver Navegação.
Slot de OTProunded só nas pontasfirst:rounded-l-md last:rounded-r-md — o conjunto lê como um campo só.
CTAnunca retângulo de canto médioPílula ou nada. Botão rounded-md no meio de uma tela de pílulas parece de outro sistema.

Sim

Buscar paciente…FiltroAtivos 12

Mesma linha, mesma forma, mesma altura (h-8): busca, filtro e estado falam a mesma língua.

Não

Buscar paciente…FiltroAtivos 12

Três formas e três alturas na mesma fileira: o olho lê dois ou três sistemas diferentes na mesma tela.

Bordas

Uma espessura, um token, e uma regra global que quase ninguém precisa saber que existe.
globals.css — a borda padrão de TODO elemento
@layer base {
  * { @apply border-border outline-ring/50 }
}

/* Efeito: escrever `border` (sem cor) já pinta a cor certa do tema.
   `border-input` existe pro campo: é alias de --border, mas nomeia o papel. */
SituaçãoReceita
Card, painel, tabelaborder border-border
Campo de formulárioborder border-input
Estado vazioborder border-dashed border-border
Separador dentro de cardborder-t border-border (ou divide-y no pai)
Separador de menuh-px bg-border
Fio vertical entre botõesw-px bg-border (com my- pra não colar)
Item selecionado num cartão de resumoborder-brand ring-1 ring-brand

Borda de 2px não existe no vocabulário. Era a exceção da aba sublinhada, que foi recusada em 23/08/2026 — hoje o recorte de visão é segmented control em pílula. Traço mais grosso que 1px, em qualquer lugar, é sinal de que a peça está tentando ser outra coisa.

Elevação

Quatro níveis reais no app, do card quase plano ao modal. Cada degrau tem um motivo funcional: o que sobe é o que FLUTUA sobre o resto.

1 · Plano

Card padrão: border shadow-xs. Um fio de borda e um fio de sombra — o nível mais comum do app inteiro.

2 · Flutuante

Dropdown, tooltip, modal e popover: shadow-md ring-1 ring-foreground/5. A barra de ações em massa tem a mesma sombra, mas é ilha ink-950: o anel claro dela só existe nos temas escuros (dark:ring-white/15).

3 · Alto

Peça fixa que se sobrepõe a uma tela inteira: shadow-xl. Em uso no cartão de agendamento e na barra de confirmar remarcação da agenda.

4 · Bloco na mão

--shadow-lift: o bloco que a mão segura na grade da agenda, e a lista do SelectNative. Era também a sombra do foco em camadas até 18/09, quando o founder recusou pela terceira vez a elevação do bloco em edição — ela desenhava um card dentro do card.

Os tokens de sombra

A escala do Tailwind (xs…2xl) foi roteada por variáveis do tema: os valores são os defaults da v4 no claro, e cada tema escuro reescreve a tinta — sombra preta sobre fundo preto não desenha nada.
TokenValor no ClaroO que veste
--shadow-card0 1px 2px 0 rgb(0 0 0 / .05)Card em repouso (= shadow-xs)
--shadow-lift0 15px 40px -5px rgb(0 0 0 / .15) + fio de bordaBloco erguido na grade da agenda e lista do SelectNative. NÃO é mais o foco em camadas: o bloco em edição sobe só de camada desde 18/09.
--shadow-rise0 -4px 16px -8px rgb(0 0 0 / .12)Sombra que sobe, pra barra colada no rodapé. O consumidor é a barra do Cobrar no pé do painel do serviço (components/ajustes/precificacao/aba-preco.tsx), que fica embaixo enquanto o painel rola. A barra de ações em massa segue no shadow-md, e essa divergência é a próxima decisão: ou ela adota o --shadow-rise, ou os dois jeitos de sombrear barra inferior continuam convivendo.
--shadow-glow-ia0 -8px 40px -12px rgb(124 58 237 / .35)O halo do dock do agente — acompanha o fúcsia no tema Azul
--sh-xs … --sh-2xlescala padrão, tinta por temashadow-xs … shadow-2xl

Armadilha já pagaSombra colorida é sempre um token próprio

As utilities de sombra apontam pra uma var OPACA. Isso significa que compor cor na classe (shadow-sm shadow-brand/20) deixa de funcionar em silêncio — nada quebra, a sombra só sai na cor do tema. Precisa de sombra colorida? Declare um token, como o --shadow-glow-ia.

No escuro, elevação é TOM

Sombra preta não desenha sobre fundo escuro. Nos três temas escuros, o que sobe fica mais claro (--surface-2) e ganha um fio de luz na borda — 0 0 0 1px rgb(255 255 255 / 0.04) no lugar do fio de sombra. E as sombras de overlay ficam MAIS fundas, não menos: no tema Ardósia, que não vai ao preto, elas são as mais fundas de todas, justamente porque o fundo é mais claro.

Anel vs. borda

Duas coisas parecidas com trabalhos diferentes. Confundir as duas é o que produz moldura dentro de moldura.
RecursoPara que serveRegra
borderDesenhar o limite de um objeto: onde ele começa e termina.Ocupa layout. É permanente.
ringMarcar um ESTADO temporário: foco, seleção, o card que está sendo editado.Não ocupa layout (desenha por fora). Aparece e some.
ring-1 ring-foreground/5O fio de definição de superfícies flutuantes.Vai junto do shadow-md em menu, tooltip e modal — é o que separa o painel do fundo quando a sombra é sutil.
border-brand + ring-[3px] ring-brand-mutedO anel de foco do canon.Uma receita só em todo alvo clicável, a mesma do Card. Ver Foco & acessibilidade.

NuncaUm anel por cena

O anel é do CAMPO. O bloco em edição marca o lugar pela ELEVAÇÃO, e o card devolve a borda neutra enquanto se edita. Anel dentro de anel dentro de anel lê como moldura, não como hierarquia — duas versões já foram recusadas por isso.