Fundação

Elevação & superfície

Cor e tipografia resolvem o plano. Este capítulo resolve a terceira dimensão: o que fica apoiado, o que fica flutuando, e quanto de sombra separa um do outro. São quatro sombras, seis raios e uma escada de camadas — e nada disso é decorativo. Sombra é a resposta visual para uma pergunta de hierarquia: isto está no papel ou está acima dele?

A regra que resume o capítulo: elevação é informação, não enfeite — só eleva o que pode ser tocado ou o que está por cima de outra coisa.

As quatro sombras

Vivem no :root de app/globals.css e chegam ao Tailwind como shadow-card, shadow-card-blue, shadow-fab e shadow-modal. Todas são COLORIDAS — nunca cinza puro nem preto duro. Os espécimes abaixo estão renderizados ao vivo, sobre o --bg real do produto.

card

.shadow-card

--shadow-card

O degrau de sempre. Quase imperceptível, e é isso mesmo.

Use em: Todo card, tabela, input e painel apoiado no fundo --bg. É a sombra padrão: na dúvida, é esta.

Cor de origem: --ink 15 23 42 a 4% · em uso em 37 arquivos

card-blue

.shadow-card-blue

--shadow-card-blue

A sombra que tem cor. Azul da marca vazando por baixo.

Use em: Só o que é AZUL e é ação: botão primário (variante primary de components/ui/button.tsx), card azul de destaque, hover de item selecionável.

Cor de origem: --blue 17 55 162 a 45% · em uso em 20 arquivos

fab

.shadow-fab

--shadow-fab

Amarelo derramado. A mais forte das quatro.

Use em: Só o botão flutuante e a variante accent do botão. Um por tela — dois FABs brilhando é briga, não hierarquia.

Cor de origem: --yellow 245 200 0 a 55% · em uso em 6 arquivos

modal

.shadow-modal

--shadow-modal

Descolou do plano. Grande, difusa, escura.

Use em: Tudo que flutua POR CIMA da página: dialog, bottom sheet, drawer, menu flutuante, popover. Sempre acompanhada de overlay.

Cor de origem: --ink 15 23 42 a 20% · em uso em 64 arquivos

TokenValor exatoQuando
--shadow-card0 4px 16px rgba(15, 23, 42, 0.04)Todo card, tabela, input e painel apoiado no fundo --bg. É a sombra padrão: na dúvida, é esta.
--shadow-card-blue0 14px 30px -10px rgba(17, 55, 162, 0.45)Só o que é AZUL e é ação: botão primário (variante primary de components/ui/button.tsx), card azul de destaque, hover de item selecionável.
--shadow-fab0 12px 28px -6px rgba(245, 200, 0, 0.55)Só o botão flutuante e a variante accent do botão. Um por tela — dois FABs brilhando é briga, não hierarquia.
--shadow-modal0 20px 50px -15px rgba(15, 23, 42, 0.2)Tudo que flutua POR CIMA da página: dialog, bottom sheet, drawer, menu flutuante, popover. Sempre acompanhada de overlay.

Não existe uma quinta sombra. Se a peça pede um degrau que não está aqui, o problema é de hierarquia, não de sombra — provavelmente há elevação demais na tela. Utilitários genéricos do Tailwind (shadow-lg, shadow-2xl) e sombras escritas na mão em shadow-[...] não pertencem ao produto: são cinza neutro e brigam com a paleta.

No tema escuro a sombra troca de matéria

O admin tem um tema escuro por atributo — [data-tema="apol"] em app/globals.css. Sombra clara desaparece em fundo escuro, então dois dos quatro tokens são redefinidos lá.

TokenClaro (:root)Escuro ([data-tema="apol"])
--shadow-card0 4px 16px rgba(15, 23, 42, 0.04)0 6px 18px rgba(0, 0, 0, 0.35) — preto real, porque relevo no escuro só vem de preto
--shadow-card-blue0 14px 30px -10px rgba(17, 55, 162, 0.45)0 14px 30px -10px rgba(245, 200, 0, 0.28) — vira glow amarelo; o azul sumia no fundo
--shadow-fab / --shadow-modalComo acimaNão são redefinidos — herdam o valor do claro.

Consequência prática: use sempre a classe (shadow-card), nunca o valor copiado. Quem escreve shadow-[0_4px_16px_rgba(15,23,42,0.04)] à mão ganha um card sem relevo nenhum no tema escuro — e o bug só aparece em quem usa o tema.

Escala de raio

tailwind.config.ts sobrescreve a escala do Tailwind: os números daqui não são os que você tem na memória. Cada amostra abaixo está desenhada no valor real.

  • 10px

    .rounded-sm

    Chip, tag, badge, pastilha de status. O menor raio que a marca usa.

    Padrão do Tailwind: 2px

  • 16px

    .rounded-md

    O raio de trabalho: card, input, botão, linha de tabela, item de menu. É o mais usado do sistema.

    Padrão do Tailwind: 6px

  • 20px

    .rounded-lg

    Contêiner que agrupa outros cards, painel, bottom sheet, menu flutuante.

    Padrão do Tailwind: 8px

  • 26px

    .rounded-xl

    Bloco de destaque grande — card de meta, hero interno, tile do Brand Hub.

    Padrão do Tailwind: 12px

  • 36px

    .rounded-2xl

    Superfície de página inteira e cards do site. O maior raio antes do redondo.

    Padrão do Tailwind: 16px

  • 999px

    .rounded-full

    Avatar, FAB, pill de navegação, botão de ícone. Nunca em card retangular.

    Padrão do Tailwind: 9999px (não sobrescrito)

A pegadinha que já mordeu: o bloco extend.borderRadius sobrescreve só sm · md · lg · xl · 2xl. O que ele não toca continua sendo Tailwind puro — e aí rounded-3xl (24px) fica menor que rounded-2xl (36px), e rounded sozinho é 4px, quase reto. Regra: use só as cinco sobrescritas mais rounded-full. rounded-3xl e rounded não fazem parte da escala da marca.

O que éRaioPor quê
Chip, tag, badgerounded-sm · 10pxObjeto pequeno com raio grande vira comprimido.
Card, input, botão, linha de tabelarounded-md · 16pxO raio de trabalho — o mais usado do sistema.
Painel, sheet, menu flutuanterounded-lg · 20pxContêiner que guarda cards de 16px: o de fora tem que ser maior.
Bloco de destaque, tilerounded-xl · 26pxO mesmo 26px que o site escreve como rounded-[26px].
Card do site, superfície de páginarounded-2xl · 36pxO maior raio antes do redondo — respiro grande de peça institucional.
Avatar, FAB, pill, botão de íconerounded-fullRedondo é redondo: nunca aproxime com 2xl.
Raio aninhadode fora sempre maiorCard de 16px dentro de painel de 20px. Igualar os dois faz o de dentro parecer torto.

Os raios do site

O site do Alemão usa a mesma escala do produto (é o mesmo tailwind.config.ts), mas escreve dois raios fora dela em arbitrary value. Vale saber o que cada um é antes de copiar.

Como está escrito no siteValorSituação
rounded-2xl36px✓ Na escala. Card de conteúdo, form de orçamento, bloco de serviço.
rounded-full9999px✓ Na escala. É o raio mais frequente do site — pill de navegação, selo, botão.
rounded-[26px]26px✓ Mesmo valor de rounded-xl — prefira a classe da escala.
rounded-3xl24px⚠️ Fora da escala (é o default do Tailwind). Balão de fala do hero — trocar por rounded-xl ao encostar no arquivo.
rounded-[22px] / rounded-[4px]22px / 4px⚠️ Fora da escala. Sem par na escada — a confirmar qual degrau assumem.

O site não tem sombra nomeada. Um levantamento em components/site-alemao/ encontra dez sombras diferentes escritas à mão — de shadow-[0_10px_30px_rgba(16,32,63,0.06)] a shadow-2xl — contra os quatro tokens do produto. Pela lei do sistema unificado, quem manda é o produto: peça nova do site usa shadow-card e shadow-modal. A migração das dez existentes é a confirmar — está registrada em Pendências, não decidida aqui.

Hierarquia de superfície — a árvore de decisão

A pergunta que o time faz toda hora: fundo chapado, card sólido, vidro ou só sombra? Responda de cima pra baixo e pare na primeira que der Sim.

  1. 1. Isto flutua por cima da página?

    Sim — dialog, sheet, drawer, menu, popovershadow-modal + overlay + z-[80]/[81]

    Superfície bg-superficie, raio rounded-lg (ou rounded-t-lg em bottom sheet), overlay bg-ink/50 backdrop-blur-sm. Sem borda: a sombra grande e o overlay já separam do fundo — borda em cima disso vira contorno duro.

  2. 2. O fundo atrás dele é rico? (azul, gradiente, foto ou padrão)

    Sim — e o conteúdo é curtomaterial .vidro-* (sem sombra e sem borda)

    O vidro já traz a própria borda de luz. Escolha do material e cor de texto em Materiais de vidro. Texto corrido longo continua pedindo .vidro-fosco ou card sólido.

  3. 3. O fundo é claro? (branco ou --bg / --gelo)

    Simcard sólido: bg-white + border border-line + shadow-card

    Esta é a resposta padrão do sistema e a combinação mais repetida do produto — os três juntos, sempre. Sobre fundo claro, vidro está proibido: o blur não tem o que borrar.

  4. 4. Isto é a ação principal da tela?

    Sim, e é azulshadow-card-blue

    Vem de graça na variante primary de components/ui/button.tsx — não reescreva. Se for amarelo (FAB ou variante accent), a sombra é shadow-fab.

  5. 5. Sobrou algo?

    É seção da página, não objetofundo chapado, zero sombra

    Faixa de seção, bloco de agrupamento, sticky header: bg-bg, bg-blue-soft ou bg-blue, separados por border-line. Sombra em coisa que não é objeto elevado só suja a tela.

Teste de bolso: se você não consegue dizer em uma frase por que aquele retângulo está acima do plano, ele não está — tire a sombra. Uma tela em que tudo flutua é uma tela sem hierarquia, e é assim que a sombra deixa de comunicar.

A regra do vidro, aplicada à superfície

Vidro é um material de superfície como qualquer outro — e o que decide se ele pode entrar é o que está ATRÁS dele, nunca o gosto de quem desenha.

Fundo rico

Vidro autorizado. Sem sombra e sem borda: o material já traz as duas.

✓ Sobre azul, gradiente, foto ou padrão → material .vidro-*

Fundo claro

Card sólido. bg-white + border-line + shadow-card, os três juntos.

✓ Sobre branco ou --bg → card sólido

Vidro só sobre fundo rico. Sobre claro, card sólido — sem exceção, porque o blur precisa de algo pra borrar e sem isso o texto perde contraste (WCAG AA). A demonstração lado a lado do que acontece quando se ignora isso, mais os cinco materiais e a cor de texto de cada um, estão em Materiais de vidro.

SuperfícieSombraBordaRaio
Card sólido sobre fundo claroshadow-cardborder border-linerounded-md
Card azul de açãoshadow-card-bluenenhuma — a sombra colorida já separarounded-md
Material .vidro-* sobre fundo riconenhumanenhuma — o material tem borda de luzrounded-md ou rounded-lg
Dialog, sheet, drawer, menushadow-modalnenhuma — overlay + sombra bastamrounded-lg
Faixa / seção de páginanenhumaborder-line pra dividir0 — seção não tem raio
FABshadow-fabborder-4 border-white (o anel que o solta do fundo)rounded-full

Camadas — a escada real do sistema

Levantada com grep de z-index em app/ e components/. Isto é o que EXISTE hoje, não um ideal: a tabela serve pra você escolher um número que não colida, e pra ver onde o sistema já se contradiz.

CamadaQuem ocupaOnde vive
z-0Decoração de fundoblobs do admin — components/admin/admin-layout-client.tsx
z-[1]Régua dentro de gráficolinha de meta — components/admin/shared/grafico-barras.tsx
z-10Conteúdo acima da decoraçãowrapper do admin; cabeçalho sticky de lista
z-20Sticky dentro de um container que rolathead do Caixa; faixa de aviso do admin
z-30Bottom nav do admin (mobile)components/admin/admin-bottom-nav.tsx
z-40Header sticky do site · bottom nav do funcionário · WhatsApp flutuantecomponents/site-alemao/header.tsx · components/ponto/bottom-nav.tsx · components/site-alemao/whatsapp-flutuante.tsx
z-50FAB · menu mobile do site · takeover de celebração · dropdown do admincomponents/ponto/fab.tsx · components/ponto/meta-batida-celebracao.tsx
z-[60] / z-[61]Overlay / conteúdo — sheets de navegação e perfil · toast do Kanban · skip link do sitecomponents/admin/menu-modulos-mobile.tsx · components/admin/shared/dialog-meu-perfil.tsx
z-[70]Pilha de toastscomponents/central/portal.tsx
z-[80] / z-[81]Overlay / conteúdo — a escada de dialog mais usada (14 arquivos: OS, Caixa, Orçamentos, Tarefas, Compras)components/admin/os/ficha-os-sheet.tsx e irmãos
z-[90] / z-[91]Overlay / conteúdo — menu flutuante (abre POR CIMA de dialog) e dialogs de segundo nívelcomponents/admin/shared/menu-flutuante.tsx · components/admin/os/receber-os-dialog.tsx
z-[95]Confete de comemoraçãocomponents/caixa/confetti-festa.tsx
z-[100]Abertura em tela cheiacomponents/intro/intro-variants.tsx
z-[200]Barra de progresso de rota — tem que vencer tudocomponents/admin/route-top-loader.tsx

O padrão N / N+1 é a convenção que funciona: overlay em z-[80], conteúdo em z-[81]. Os dois têm que ser vizinhos — deixar o conteúdo em z-50 e o overlay em z-[80] é como o overlay engole o próprio dialog.

Três escadas concorrentes pra dialog. Hoje convivem 60/61 (sheets de navegação e perfil), 80/81 (a maioria — 14 arquivos entre OS, Caixa, Orçamentos, Tarefas e Compras) e 90/91 (menu flutuante e dialog de segundo nível). Os números não são arbitrários — o menu flutuante precisa abrir por cima de um dialog aberto, e o bottom nav em z-30 precisa ficar por baixo de todos eles. Mas a escada não está normalizada: a confirmar se 80/81 vira o padrão único de dialog e 90/91 fica só pro que abre por cima de dialog.

Precisa de camada nova?Use
Sticky dentro de um container que rolaz-20 — e nada acima disso
Barra de navegação fixa (mobile)z-30 (admin) / z-40 (funcionário e site)
Botão flutuante que fica na telaz-50
Dialog, bottom sheet, drawerz-[80] overlay + z-[81] conteúdo
Menu ou popover que abre por cima de um dialogz-[90] + z-[91]
Toastz-[70] — abaixo dos dialogs (80/81), de propósito: toast não deve tapar o que a pessoa está confirmando
Qualquer outra coisaNada. Reveja o empilhamento antes de inventar um número — número novo é dívida permanente.

Superfície e o espaço que as camadas fixas reservam

Barra fixa não flutua sobre o conteúdo por acidente: o admin reserva a altura dela em CSS var. Quem escreve altura na mão reintroduz o bug.

TokenMobileDesktop (md+)Por quê
--admin-topocalc(3.5rem + env(safe-area-inset-top, 0px))2.5rem56px é exatamente o espaço do sino de notificações flutuante (top-4 + size-10). Reduzir faz o conteúdo começar embaixo do sino.
--admin-rodapecalc(3.75rem + env(safe-area-inset-bottom, 0px))2.5rem60px de bottom nav + o home indicator do iPhone. No desktop não há nav — só a respiração.
--altura-tarefasauto — no celular a página rolacalc(100dvh - --admin-topo - --admin-rodape)Um lugar só. O valor já foi repetido à mão como calc(100dvh-104px) e mexer num sem o outro quebrava a altura do Kanban.

Nunca use position:fixed pro CTA principal de uma tela que rola. Numa página que rola no nível do body, a barra fixa cobre ~110px do fim da viewport o tempo todo — inclusive na primeira visão. O padrão do sistema é h-dvh flex-col com a barra em shrink-0: o flexbox calcula o espaço, sem sobrepor nada.

Overlay — a camada que ninguém desenha e todo mundo vê

Toda superfície com shadow-modal vem acompanhada de um overlay. Ele não é fundo escuro genérico: é --ink com opacidade, mais um blur leve.

ReceitaOnde é usadaQuando
bg-ink/50 backdrop-blur-sm21 ocorrências — a mais comumDialog e sheet que exigem decisão: mais escuro, corta a distração.
bg-ink/40 backdrop-blur-sm17 ocorrênciasSheet de navegação e ficha lateral: a pessoa ainda precisa se localizar no que está atrás.
bg-ink/56 ocorrênciasNão é overlay — é hover/fundo sutil de linha. Não confunda os dois usos.
bg-black/301 ocorrência (Exportar orçamento)⚠️ Fora do padrão: preto puro em vez de --ink. Corrigir ao encostar no arquivo.

Escolha entre /40 e /50 pela tarefa, não pelo gosto: se fechar aquela camada sem decidir é aceitável, use /40; se a pessoa precisa decidir ali, use /50. E o overlay é sempre --ink — preto chapado não existe na marca.

Fica de olho

O que mantém a marca inteira — e o que a quebra.

Sempre

  • Uma das quatro sombras: shadow-card, shadow-card-blue, shadow-fab, shadow-modal
  • Card sólido = bg-white + border border-line + shadow-card, os três juntos
  • Vidro só sobre fundo rico; sobre branco ou --bg, card sólido
  • Raio de fora sempre maior que o de dentro (card 16px dentro de painel 20px)
  • Overlay em --ink com backdrop-blur-sm, nunca preto puro
  • Overlay e conteúdo em camadas vizinhas — z-[80] e z-[81]
  • Reservar a altura de barra fixa em --admin-topo / --admin-rodape
  • shadow-fab só no FAB, um por tela

Nunca

  • shadow-lg, shadow-2xl ou shadow-[...] à mão — cinza neutro, briga com a paleta
  • Copiar o valor da sombra em vez da classe (quebra o tema escuro em silêncio)
  • rounded-3xl (24px) achando que é maior que rounded-2xl (36px)
  • rounded sozinho (4px) — não faz parte da escala da marca
  • Sombra em faixa, seção ou fundo chapado: aquilo não é objeto elevado
  • Sombra e borda de vidro juntas — o material .vidro-* já traz as duas
  • Inventar um z-index novo antes de conferir a escada deste capítulo
  • position:fixed no CTA principal de uma tela que rola

Continua em

Elevação encosta em três capítulos. Nenhum deles repete o que está aqui.