ease-servico
cubic-bezier(0.2, 0.7, 0.2, 1): começa rápido e termina devagar. Classe ease-servico.
Passe o mouse aqui para ver a curva.
Design system
Tokens em src/app/globals.css. Componentes em src/components/ds e src/components/sections.
O sistema em resumo
Fraunces
Albert Sans
01 · Princípios
O verde cheio aparece uma vez por tela. Os outros caminhos vão em contorno ou em link de texto.
Botão verde (ou com o ícone do WhatsApp) leva a uma conversa com a Samara. Tinto, ou contorno com ícone de download, leva a um material gratuito.
Blocos se separam com linhas de 1 px, como num cardápio impresso. A única sombra, shadow-papel, fica para o que flutua: cartão em destaque e menu aberto.
Cantos de 2 a 6 px em botões, campos e cartões. Formas redondas ficam para o prato, as fotos e o botão flutuante do WhatsApp.
02 · Tokens
@theme de src/app/globals.css. Cada token vira classe do Tailwind: --color-verde gera bg-verde, text-verde, border-verde e assim por diante.| Token | Classes | HEX | Uso |
|---|---|---|---|
| verde | bg-verdetext-verde | #12392D | Cor principal: nome, títulos, botões |
| noite | bg-noitetext-noite | #0B241C | Fundos escuros, rodapé |
| linho | bg-linhotext-linho | #F4EEE3 | Fundo principal |
| papel | bg-papeltext-papel | #FBF8F2 | Cartões e superfícies |
| tinto | bg-tintotext-tinto | #7B2335 | O &, ênfases, detalhes de destaque |
| latao | bg-lataotext-latao | #A8834A | Filetes, ícones e ornamentos sobre claro |
| latao-claro | bg-latao-clarotext-latao-claro | #C9A66B | O & e detalhes sobre fundo escuro |
| salvia | bg-salviatext-salvia | #DDE3D6 | Superfícies secundárias |
| tinta | bg-tintatext-tinta | #1C2420 | Texto principal |
| grafite | bg-grafitetext-grafite | #535C57 | Texto secundário |
| verde-claro | bg-verde-clarotext-verde-claro | #1D4B3C | Hover do botão primário |
| tinto-escuro | bg-tinto-escurotext-tinto-escuro | #5F1828 | Hover do botão destaque |
| tinto-claro | bg-tinto-clarotext-tinto-claro | #E3B7BF | Tinto suave. Ainda sem uso nos componentes. |
| linha | bg-linhatext-linha | #D8CFBE | Bordas, divisores e campos |
| erro | bg-errotext-erro | #9B2C2C | Mensagem e borda de campo com erro |
| sucesso | bg-sucessotext-sucesso | #2F6B4F | Confirmações. Ainda sem uso nos componentes. |
bg-whatsapptext-whatsapp | #1FA855 | Botão flutuante do WhatsApp |
verde
bg-verdetext-verdenoite
bg-noitetext-noitelinho
bg-linhotext-linhopapel
bg-papeltext-papeltinto
bg-tintotext-tintolatao
bg-lataotext-lataolatao-claro
bg-latao-clarotext-latao-clarosalvia
bg-salviatext-salviatinta
bg-tintatext-tintagrafite
bg-grafitetext-grafiteverde-claro
bg-verde-clarotext-verde-clarotinto-escuro
bg-tinto-escurotext-tinto-escurotinto-claro
bg-tinto-clarotext-tinto-clarolinha
bg-linhatext-linhaerro
bg-errotext-errosucesso
bg-sucessotext-sucessobg-whatsapptext-whatsappUsados pelos componentes de interface em src/components/ui (shadcn). Nas páginas, prefira os nomes da marca.
backgroundforegroundcardcard-foregroundpopoverpopover-foregroundprimaryprimary-foregroundsecondarysecondary-foregroundmutedmuted-foregroundaccentaccent-foregrounddestructivedestructive-foregroundborderinputringt-displayFraunces 400 · clamp(2.6rem, 1.55rem + 4.1vw, 4.6rem) · entrelinha 1.04Taçat-h1Fraunces 400 · clamp(2.3rem, 1.6rem + 2.6vw, 3.5rem) · 1.08Salãot-h2Fraunces 400 · clamp(1.85rem, 1.4rem + 1.6vw, 2.55rem) · 1.14Turnot-h3Fraunces 400 · clamp(1.35rem, 1.2rem + 0.55vw, 1.65rem) · 1.25Mise en placet-leadAlbert Sans · clamp(1.125rem, 1.05rem + 0.3vw, 1.25rem) · 1.6Couvert e cartat-smallAlbert Sans · 0.875rem · 1.55Conversa inicial gratuitat-eyebrowAlbert Sans 600 · 0.75rem · espaçamento 0.18em · caixa altaCarta de serviçosfont-display · font-sansleaderprosa<em> em títulos14 px28 px312 px416 px520 px624 px832 px1040 px1248 px1456 px1664 px2080 px2496 pxProp spacing do Section. Há também none, para faixas que cuidam do próprio respiro, como o PageHero.
compact56 px / 80 pxpy-14 md:py-20default80 px / 112 pxpy-20 md:py-28large96 px / 144 pxpy-24 md:py-36celular desktop
Largura máxima de 1200 px (default), 820 px (narrow) ou 1320 px (wide), com margem lateral de 20 px no celular e 32 px a partir de 640 px.
rounded-sm2 px: Botões, campos, cartões
rounded-md3 px
rounded-lg4 px
rounded-xl6 px
rounded-fullcírculo: Prato, fotos, botão do WhatsApp
Filete
border border-linha: o padrão para separar e emoldurar.
Sombra papel
shadow-papel: cartão em destaque e menu aberto.
cubic-bezier(0.2, 0.7, 0.2, 1): começa rápido e termina devagar. Classe ease-servico.
Passe o mouse aqui para ver a curva.
Opacidade e 10 px de subida em 0,6 s, com ease-servico. Usada na abertura da home.
Do primeiro olá à última taça.
Com prefers-reduced-motion, animações e transições caem para 0,01 ms e a rolagem suave é desligada.
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}03 · Componentes
ButtonLink é um link com cara de botão. Endereço externo (WhatsApp, Instagram) abre em nova aba, e com download vira um link de download. Button é o botão de formulário. buttonClasses devolve só as classes.
Um primário por tela, e o texto do botão sempre começa por um verbo.
import { Button, ButtonLink, buttonClasses } from "@/components/ds/button";variantsizeiconctadownloadestadosSobre claro: primario, destaque, contorno, texto
Sobre escuro: claro, contorno-claro, texto
Tamanhos: md e lg
Desativado (Button)
Rótulo curto acima do título, com um filete à esquerda. Tinto no claro e latão claro no escuro, sem configurar nada: a cor muda sozinha dentro de seção verde ou noite.
import { Eyebrow } from "@/components/ds/layout";childrenasCarta de serviços
Carta de serviços
Cabeçalho padrão de seção: rótulo, título e abertura. Marque com <em> a palavra que carrega a frase. Passe id e use o mesmo valor no labelledBy da seção.
import { SectionHeader } from "@/components/ds/layout";eyebrowtitleintroalignlevelComo o trabalho acontece
Alinhado ao centro
Faixa de fundo inteiro com respiro padrão. Nos tons verde e noite a seção ganha a classe on-dark, e os componentes dentro dela trocam de cor sozinhos. Dentro da seção, use Container para a largura.
import { Container, Section } from "@/components/ds/layout";tonespacingid · labelledByCada momento tem dono
Fundo principal das páginas
Cada momento tem dono
Faixas de destaque, com filete em cima e embaixo
Cada momento tem dono
Bloco secundário, como o do Raio-X
Cada momento tem dono
Método e chamada final
Cada momento tem dono
Rodapé e fundos mais escuros
Lista em forma de cardápio: nome, filete pontilhado e detalhe. No celular o detalhe desce para baixo do nome. Use em listas curtas.
import { Carta, type CartaItem } from "@/components/ds/content";itemsclassNamePresencial · 4 horas
Presencial · 2 a 3 horas
Uma visita · relatório em PDF
Um ciclo completo de serviço · no local
4 a 6 meses · presença na operação
Pela Mar de Vinhos
PDF gratuito
Com descrição: checklist para observar um turno da casa com olhos de cliente.
Presencial · 4 horas
Presencial · 2 a 3 horas
Uma visita · relatório em PDF
Um ciclo completo de serviço · no local
4 a 6 meses · presença na operação
Pela Mar de Vinhos
Sequência numerada com filete em cima. Use para método e jornada do cliente; os números (01, 02...) saem sozinhos.
import { Moments, type Moment } from "@/components/ds/content";itemscolumnsQuem chega é cumprimentado em segundos, mesmo que a mesa ainda não esteja pronta.
A equipe sabe quem pediu o quê. Ninguém chega à mesa perguntando de quem é o filé.
Pedir a conta e pagar recebem o mesmo cuidado que pedir o prato.
O cliente sai com um agradecimento olho no olho e um motivo para voltar.
Citação de cliente. Só fala literal, copiada das transcrições em src/content/depoimentos.ts. Nada de reescrever ou resumir o que a cliente disse.
import { Quote } from "@/components/ds/content";childrenname · rolesizesize="md"
Existe uma jornada do cliente aqui dentro que é muito bem pontuada, para que ele não se sinta perdido.
size="lg", sobre verde
Ela nos ensinou a fazer um processo. Então hoje o nosso cliente é orientado desde o momento que ele entra na nossa porta até o momento que nós nos despedimos dele.
Perguntas com details e summary. Nas páginas, os mesmos itens alimentam os dados estruturados (faqSchema), então o texto visível e o do schema nunca divergem.
import { Faq, type FaqItem } from "@/components/ds/content";itemsPorque abre e fecha sem JavaScript, funciona com teclado e o texto continua no HTML, onde os buscadores leem.
Dá. Cada pergunta é independente, e o sinal de mais gira para virar um x quando ela está aberta.
Selo pequeno de informação, ao lado de um título ou botão. Não é botão e não leva link.
import { Tag } from "@/components/ds/content";childrenRótulo sempre visível. Campo opcional ganha “(opcional)” sozinho; obrigatório, um asterisco tinto. Ajuda e erro ficam ligados ao campo por aria-describedby, e o erro marca aria-invalid.
Esta demonstração não envia nada. As mensagens de erro são as mesmas do formulário real.
import { CheckboxField, SelectField, TextAreaField, TextField } from "@/components/ds/fields";id · labelhinterrorrequiredoptionsConfira o e-mail.
Com DDD.
Onde fica a casa.
Escolha o tipo de negócio.
Conte um pouco mais (pelo menos uma frase).
Marque a autorização para continuar.
Trilha visível e BreadcrumbList nos dados estruturados, no mesmo componente. O “Início” entra sozinho. O PageHero já inclui a trilha: a versão sobre claro está no topo desta página.
import { Breadcrumbs } from "@/components/sections/shared";trailLogo em SVG dentro do HTML, com as cores dos tokens. Para o tamanho, defina a largura e deixe a altura automática (w-[240px] h-auto). Ao lado do nome escrito, passe title="" para o leitor de tela não ler duas vezes.
import { BrandSymbol, Signature, Wordmark } from "@/components/brand/Logo";tonevarianttitleBorda de prato: o anel duplo do símbolo, sem o &. Emoldura fotos redondas, selos e números. A cor vem de uma classe text-*; o anel é decorativo e fica fora da leitura de tela.
import { PlateRing } from "@/components/ds/layout";className
Filete com o prato no meio, como a dobra de um cardápio. Separa blocos de texto longos; não use entre todas as seções.
import { Ornament } from "@/components/ds/layout";classNameFechamento de página: WhatsApp como caminho curto, formulário como alternativa. Escolha o contexto do WhatsApp pela página (prop wa); o nome do clique segue o contexto.
import { CtaFinal } from "@/components/sections/shared";title · textwaformHrefeyebrow · tonePróximo passo
Conversa inicial gratuita e sem compromisso. Resposta em até 24 horas úteis.
Bloco do material gratuito, com a capa do Raio-X, a lista do que vem no checklist e o formulário de cadastro embutido. Não aparece aqui para não criar um segundo formulário de verdade nesta página.
import { LeadMagnetSection } from "@/components/sections/shared";idtonetitle · introVeja o componente em uso na home, nas páginas de serviço e nos guias. A página do material mostra o formulário completo.
Ver o Raio-X do Atendimento04 · Padrões de CTA
Leva ao formulário de contato ou ao WhatsApp com a mensagem pronta. Botão verde (primario); sobre fundo escuro, claro com o ícone do WhatsApp.
Leva ao Raio-X do Atendimento ou a um guia. Tinto (destaque) quando o material é a ação principal da tela; contorno com ícone de download quando divide espaço com uma conversa.
Lado a lado com uma conversa, como na abertura da home: o verde fica com a conversa e o material vai de contorno.
waMessages (src/lib/whatsapp.ts), waLinkFor(contexto) monta o link e o botão flutuante escolhe o contexto pela rota, com waContextForPath.| Contexto | Mensagem | Botão flutuante em |
|---|---|---|
padrao | “Olá, Samara! Vim pelo site da Servir & Encantar e quero conversar sobre o atendimento da minha casa.” | //samara-telles/privacidade |
conversa | “Olá, Samara! Quero marcar a reunião inicial sobre o atendimento da minha casa.” | /contato |
treinamento | “Olá, Samara! Quero saber sobre o Treinamento Garçom 0 a 100 para a minha equipe.” | /treinamento-de-equipe |
vinhos | “Olá, Samara! Quero saber sobre o Treinamento Vinhos Finos para a minha equipe.” | Só em botões com o contexto explícito |
temporada | “Olá, Samara! Quero preparar minha equipe para a temporada. Podemos conversar?” | /guias/equipe-temporaria-para-a-temporada |
clienteOculto | “Olá, Samara! Quero saber como funciona o Cliente Oculto para a minha casa.” | Só em botões com o contexto explícito |
diagnostico | “Olá, Samara! Quero saber sobre o Diagnóstico Operacional 360º para a minha casa.” | Só em botões com o contexto explícito |
consultoria | “Olá, Samara! Quero conversar sobre a Consultoria Servir & Encantar para a minha casa.” | /consultoria-de-atendimento |
sommelier | “Olá, Samara! Quero conversar sobre a carta de vinhos da minha casa.” | /sommelier |
cases | “Olá, Samara! Vi os depoimentos no site da Servir & Encantar e quero conversar sobre a minha casa.” | /cases |
raioX | “Olá, Samara! Fiz o Raio-X do Atendimento e quero conversar sobre o resultado.” | /raio-x-do-atendimento |
guia | “Olá, Samara! Li um guia no site da Servir & Encantar e quero tirar uma dúvida sobre a minha casa.” | /guias/guias/como-montar-carta-de-vinhos/guias/reclamacao-de-cliente-no-restaurante |
padrao
//samara-telles/privacidadeconversa
/contatotreinamento
/treinamento-de-equipevinhos
temporada
/guias/equipe-temporaria-para-a-temporadaclienteOculto
diagnostico
consultoria
/consultoria-de-atendimentosommelier
/sommeliercases
/casesraioX
/raio-x-do-atendimentoguia
/guias/guias/como-montar-carta-de-vinhos/guias/reclamacao-de-cliente-no-restaurantedata-cta, usado para ler os cliques por botão. No ButtonLink, passe a prop cta; em links soltos, escreva o atributo direto.<ButtonLink href="/contato" cta="hero-conversa">
Agendar uma conversa
</ButtonLink>
// vira
<a href="/contato" data-cta="hero-conversa">...</a>hero-conversa, header-raio-x.consultoria-hero-whatsapp, guia-{slug}-whatsapp.final-whatsapp-conversa.hero-conversahero-raio-xheader-conversaheader-raio-xmenu-conversamenu-raio-xfaixa-temporadawhatsapp-flutuantefooter-whatsappfinal-whatsapp-{contexto}final-formulariovideo-{id}05 · Acessibilidade
Todo elemento focável ganha contorno de 2 px em tinto, afastado 3 px (:focus-visible, no globals.css). Dentro de seção escura, o contorno passa para latão claro. Aperte Tab nesta página para ver o anel de verdade.
Simulação do foco, sobre claro e sobre verde.
Texto principal em tinta (13,8:1 sobre linho) e secundário em grafite (6,0:1). Títulos em verde (11,0:1) e ênfases em tinto (8,5:1). No escuro, rótulos e o & em latão claro (7,1:1 sobre noite).
Latão sobre linho fica em 3,0:1. Serve para filete, ícone e ornamento, nunca para texto pequeno. Rótulo sobre claro é sempre tinto.
Primeiro link do cabeçalho, escondido até receber foco. Leva a #conteudo, o main de todas as páginas.
Como ele aparece ao receber foco, no canto da tela.
Abre e fecha com Enter ou espaço, sem JavaScript. A pergunta é um h3 dentro do summary, o que mantém a ordem dos títulos. O sinal de mais é decorativo.
<details>
<summary>
<h3>Pergunta</h3>
<Plus aria-hidden />
</summary>
<p>Resposta</p>
</details>Com prefers-reduced-motion, animações e transições caem para 0,01 ms e a rolagem suave é desligada. Nenhuma informação pode depender de animação.
Regra global em src/app/globals.css, dentro de @layer base. Componente novo não precisa repetir.
Todo campo tem rótulo visível; ajuda e erro são ligados por aria-describedby, e o erro sai com role="alert". Ícone decorativo leva aria-hidden. A página declara lang="pt-BR".
Logo ao lado do nome escrito recebe title="", para não ser lido duas vezes. Sozinho, o logo leva o nome da marca como texto alternativo.