feat: control room hero, SEO/AEO optimization and design system fixes
Hero: replace particle field with cobe globe (Capricorn view, multi-axis drag, reduced-motion safe), telemetry HUD with pointer parallax, particle text build effect, Space Grotesk display font. SEO: short titles with template, PT-BR accents, twitter cards on dynamic cases, escaped JSON-LD via lib/jsonld.ts, CSP report-only, 25 service FAQs answer-first. Design: fix TW4 layered reset killing spacing utilities, literal @theme tokens, mobile hero overflow, header overlap, empty case cards. Remove framer-motion (unified on motion/react), header version badge, phone number from hero CTA. Production build verified (24 static pages).
This commit is contained in:
1 parent
0920370f30
commit
b791b7de9e
94 files changed
+2621
-2889
No files matched your search
+137
-90
@@ -1,11 +1,15 @@
|
||||
"use client";
|
||||
"use client";
|
||||
|
||||
import { motion, type Variants } from "framer-motion";
|
||||
import { motion, type Variants } from "motion/react";
|
||||
import dynamic from "next/dynamic";
|
||||
import { useEffect, useState } from "react";
|
||||
import { shouldLoadHeroScene } from "@/app/lib/should-load-hero-scene";
|
||||
import { buildWhatsAppUrl, getWhatsAppDisplayNumber } from "@/lib/whatsapp";
|
||||
import { CV_URL } from "@/lib/site-navigation";
|
||||
import { buildWhatsAppUrl } from "@/lib/whatsapp";
|
||||
import { ControlRoomGlobe } from "./cinematic/ControlRoomGlobe";
|
||||
import MagneticButton from "./cinematic/MagneticButton";
|
||||
import { ParticleBuildText } from "./cinematic/ParticleBuildText";
|
||||
import { TelemetryStrip } from "./cinematic/TelemetryStrip";
|
||||
|
||||
const HeroScene = dynamic(() => import("./cinematic/HeroScene"), {
|
||||
ssr: false,
|
||||
@@ -94,16 +98,16 @@ const HERO_VARIANTS: HeroVariant[] = [
|
||||
],
|
||||
proof: [
|
||||
{
|
||||
label: "Operacao",
|
||||
value: "Fluxo pensado para discovery, build, deploy e sustentacao.",
|
||||
label: "Operação",
|
||||
value: "Fluxo pensado para discovery, build, deploy e sustentação.",
|
||||
},
|
||||
{
|
||||
label: "Clareza",
|
||||
value: "Menos ruído entre produto, engenharia e decisao tecnica.",
|
||||
value: "Menos ruído entre produto, engenharia e decisão técnica.",
|
||||
},
|
||||
{
|
||||
label: "Resultado",
|
||||
value: "Base pronta para operar, evoluir e receber proximo ciclo.",
|
||||
value: "Base pronta para operar, evoluir e receber próximo ciclo.",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -114,27 +118,27 @@ const HERO_VARIANTS: HeroVariant[] = [
|
||||
layout: "visual-first",
|
||||
status: "Launch sequence ready",
|
||||
chip: "Discovery → build → deploy",
|
||||
eyebrow: "MVP, produto e entrega em producao",
|
||||
eyebrow: "MVP, produto e entrega em produção",
|
||||
headline:
|
||||
"Tire seu MVP do plano e coloque em producao com base tecnica real.",
|
||||
"Tire seu MVP do plano e coloque em produção com base técnica real.",
|
||||
subtitle:
|
||||
"Transformo escopo solto em sequencia de lancamento: o que validar, o que construir primeiro e como publicar sem criar uma divida tecnica logo no inicio.",
|
||||
cta: "Lancar meu MVP",
|
||||
"Transformo escopo solto em sequência de lançamento: o que validar, o que construir primeiro e como publicar sem criar uma dívida técnica logo no início.",
|
||||
cta: "Lançar meu MVP",
|
||||
whatsappMessage:
|
||||
"Ola! Quero lancar um MVP com uma base tecnica segura. Podemos conversar?",
|
||||
sideLabel: "Sequencia de lancamento",
|
||||
"Olá! Quero lançar um MVP com uma base técnica segura. Podemos conversar?",
|
||||
sideLabel: "Sequência de lançamento",
|
||||
sideTitle: "Do primeiro corte ao deploy.",
|
||||
sideText:
|
||||
"A conversa define prioridade, risco e o menor caminho confiavel para colocar a primeira versao no ar.",
|
||||
"A conversa define prioridade, risco e o menor caminho confiável para colocar a primeira versão no ar.",
|
||||
points: [
|
||||
"Recorte de MVP sem inflar escopo.",
|
||||
"Entrega incremental com criterio de producao.",
|
||||
"Deploy e continuidade pensados desde o inicio.",
|
||||
"Entrega incremental com critério de produção.",
|
||||
"Deploy e continuidade pensados desde o início.",
|
||||
],
|
||||
proof: [
|
||||
{ label: "01", value: "Diagnostico do objetivo e gargalo principal." },
|
||||
{ label: "02", value: "Plano de construcao com risco visivel." },
|
||||
{ label: "03", value: "Publicacao e proximo ciclo sem perder contexto." },
|
||||
{ label: "01", value: "Diagnóstico do objetivo e gargalo principal." },
|
||||
{ label: "02", value: "Plano de construção com risco visível." },
|
||||
{ label: "03", value: "Publicação e próximo ciclo sem perder contexto." },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -144,22 +148,22 @@ const HERO_VARIANTS: HeroVariant[] = [
|
||||
layout: "split",
|
||||
status: "Rescue mode available",
|
||||
chip: "Legado, instabilidade e projeto travado",
|
||||
eyebrow: "Rescue tecnico para sistemas que precisam voltar a andar",
|
||||
eyebrow: "Rescue técnico para sistemas que precisam voltar a andar",
|
||||
headline:
|
||||
"Codigo confuso, entrega travada ou sistema instavel? Vamos organizar.",
|
||||
"Código confuso, entrega travada ou sistema instável? Vamos organizar.",
|
||||
subtitle:
|
||||
"Entro no ponto onde o projeto parou: leio o fluxo real, separo sintoma de causa e transformo caos tecnico em plano executavel.",
|
||||
"Entro no ponto onde o projeto parou: leio o fluxo real, separo sintoma de causa e transformo caos técnico em plano executável.",
|
||||
cta: "Destravar meu projeto",
|
||||
whatsappMessage:
|
||||
"Ola! Tenho um projeto travado ou instavel e quero destravar. Podemos conversar?",
|
||||
sideLabel: "Antes / depois tecnico",
|
||||
"Olá! Tenho um projeto travado ou instável e quero destravar. Podemos conversar?",
|
||||
sideLabel: "Antes / depois técnico",
|
||||
sideTitle: "Do caos operacional para uma rota clara.",
|
||||
sideText:
|
||||
"O primeiro objetivo nao e reescrever tudo. E encontrar o menor corte seguro que devolve controle e previsibilidade.",
|
||||
"O primeiro objetivo não é reescrever tudo. É encontrar o menor corte seguro que devolve controle e previsibilidade.",
|
||||
points: [
|
||||
"Leitura rapida de fluxo, risco e acoplamento.",
|
||||
"Priorizacao do que destrava sem reescrever tudo.",
|
||||
"Correcoes com criterio para nao trocar um bug por outro.",
|
||||
"Leitura rápida de fluxo, risco e acoplamento.",
|
||||
"Priorização do que destrava sem reescrever tudo.",
|
||||
"Correções com critério para não trocar um bug por outro.",
|
||||
],
|
||||
proof: [
|
||||
{
|
||||
@@ -167,8 +171,8 @@ const HERO_VARIANTS: HeroVariant[] = [
|
||||
value: "Backlog confuso, bugs recorrentes e pouca previsibilidade.",
|
||||
},
|
||||
{
|
||||
label: "Intervencao",
|
||||
value: "Mapa de risco, cortes pequenos e decisao tecnica clara.",
|
||||
label: "Intervenção",
|
||||
value: "Mapa de risco, cortes pequenos e decisão técnica clara.",
|
||||
},
|
||||
{ label: "Depois", value: "Entrega volta a andar com menos improviso." },
|
||||
],
|
||||
@@ -179,23 +183,23 @@ const HERO_VARIANTS: HeroVariant[] = [
|
||||
scene: "signal",
|
||||
layout: "default",
|
||||
status: "Signal map active",
|
||||
chip: "Hardware + software + operacao",
|
||||
eyebrow: "Produtos conectados, telemetria e integracoes criticas",
|
||||
chip: "Hardware + software + operação",
|
||||
eyebrow: "Produtos conectados, telemetria e integrações críticas",
|
||||
headline:
|
||||
"Conecte dispositivo, backend e interface em uma operacao confiavel.",
|
||||
"Conecte dispositivo, backend e interface em uma operação confiável.",
|
||||
subtitle:
|
||||
"Atuo na fronteira que costuma quebrar primeiro: sinal fisico, API, painel, dados e rotina operacional funcionando como um unico produto.",
|
||||
"Atuo na fronteira que costuma quebrar primeiro: sinal físico, API, painel, dados e rotina operacional funcionando como um único produto.",
|
||||
cta: "Conectar meu produto",
|
||||
whatsappMessage:
|
||||
"Ola! Quero conectar hardware, software e operacao em um produto confiavel. Podemos conversar?",
|
||||
"Olá! Quero conectar hardware, software e operação em um produto confiável. Podemos conversar?",
|
||||
sideLabel: "Mapa de sinais",
|
||||
sideTitle: "Dados, comandos e painel no mesmo fluxo.",
|
||||
sideText:
|
||||
"A conversa identifica fontes de dados, contratos, pontos de falha e o caminho para transformar integracao em produto.",
|
||||
"A conversa identifica fontes de dados, contratos, pontos de falha e o caminho para transformar integração em produto.",
|
||||
points: [
|
||||
"Contratos claros entre dispositivo, API e interface.",
|
||||
"Telemetria e dashboards com contexto operacional.",
|
||||
"Base pronta para automacao, IA ou analytics.",
|
||||
"Base pronta para automação, IA ou analytics.",
|
||||
],
|
||||
proof: [
|
||||
{
|
||||
@@ -207,8 +211,8 @@ const HERO_VARIANTS: HeroVariant[] = [
|
||||
value: "APIs, WebSockets, filas, banco e observabilidade.",
|
||||
},
|
||||
{
|
||||
label: "Saida",
|
||||
value: "Painel, operacao, alerta e decisao de produto.",
|
||||
label: "Saída",
|
||||
value: "Painel, operação, alerta e decisão de produto.",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -218,22 +222,22 @@ const HERO_VARIANTS: HeroVariant[] = [
|
||||
scene: "diagnostic",
|
||||
layout: "report",
|
||||
status: "Diagnostic report open",
|
||||
chip: "Arquitetura antes de mais codigo",
|
||||
eyebrow: "Diagnostico tecnico para decidir melhor",
|
||||
headline: "Antes de escrever mais codigo, descubra o proximo passo certo.",
|
||||
chip: "Arquitetura antes de mais código",
|
||||
eyebrow: "Diagnóstico técnico para decidir melhor",
|
||||
headline: "Antes de escrever mais código, descubra o próximo passo certo.",
|
||||
subtitle:
|
||||
"Quando a base cresce sem clareza, mais features podem piorar o problema. Eu ajudo a mapear risco, arquitetura e prioridades antes da proxima decisao cara.",
|
||||
cta: "Agendar diagnostico",
|
||||
"Quando a base cresce sem clareza, mais features podem piorar o problema. Eu ajudo a mapear risco, arquitetura e prioridades antes da próxima decisão cara.",
|
||||
cta: "Agendar diagnóstico",
|
||||
whatsappMessage:
|
||||
"Ola! Quero um diagnostico tecnico para decidir o proximo passo do meu sistema. Podemos conversar?",
|
||||
sideLabel: "Relatorio tecnico",
|
||||
sideTitle: "Risco, arquitetura e rota de acao.",
|
||||
"Olá! Quero um diagnóstico técnico para decidir o próximo passo do meu sistema. Podemos conversar?",
|
||||
sideLabel: "Relatório técnico",
|
||||
sideTitle: "Risco, arquitetura e rota de ação.",
|
||||
sideText:
|
||||
"Ideal para produto que precisa escalar, migrar, estabilizar ou parar de acumular retrabalho tecnico.",
|
||||
"Ideal para produto que precisa escalar, migrar, estabilizar ou parar de acumular retrabalho técnico.",
|
||||
points: [
|
||||
"Mapa claro dos gargalos e dependencias.",
|
||||
"Trade-offs traduzidos para decisao de negocio.",
|
||||
"Plano de transicao sem promessa magica.",
|
||||
"Mapa claro dos gargalos e dependências.",
|
||||
"Trade-offs traduzidos para decisão de negócio.",
|
||||
"Plano de transição sem promessa mágica.",
|
||||
],
|
||||
proof: [
|
||||
{ label: "Risco", value: "O que pode quebrar, atrasar ou custar caro." },
|
||||
@@ -241,7 +245,7 @@ const HERO_VARIANTS: HeroVariant[] = [
|
||||
label: "Arquitetura",
|
||||
value: "Onde simplificar, separar ou estabilizar primeiro.",
|
||||
},
|
||||
{ label: "Acao", value: "Proximo corte de implementacao com criterio." },
|
||||
{ label: "Ação", value: "Próximo corte de implementação com critério." },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -251,34 +255,34 @@ const HERO_VARIANTS: HeroVariant[] = [
|
||||
layout: "portrait",
|
||||
status: "Direct technical partner",
|
||||
chip: "Conversa direta com quem implementa",
|
||||
eyebrow: "Engenharia senior, ownership e execucao",
|
||||
headline: "Um parceiro tecnico para transformar complexidade em entrega.",
|
||||
eyebrow: "Engenharia sênior, ownership e execução",
|
||||
headline: "Um parceiro técnico para transformar complexidade em entrega.",
|
||||
subtitle:
|
||||
"Voce nao precisa apenas de tela bonita ou codigo isolado. Precisa de alguem que entenda contexto, escolha o corte certo e acompanhe ate o sistema operar.",
|
||||
"Você não precisa apenas de tela bonita ou código isolado. Precisa de alguém que entenda contexto, escolha o corte certo e acompanhe até o sistema operar.",
|
||||
cta: "Falar com Evandro",
|
||||
whatsappMessage:
|
||||
"Ola Evandro! Quero conversar sobre um projeto e entender como podemos colocar esse sistema no ar.",
|
||||
"Olá Evandro! Quero conversar sobre um projeto e entender como podemos colocar esse sistema no ar.",
|
||||
sideLabel: "Founder-led engineering",
|
||||
sideTitle: "Menos repasse, mais ownership.",
|
||||
sideText:
|
||||
"A conversa e comigo: contexto tecnico, prioridade, risco e caminho de entrega sem perder informacao entre camadas.",
|
||||
"A conversa é comigo: contexto técnico, prioridade, risco e caminho de entrega sem perder informação entre camadas.",
|
||||
points: [
|
||||
"Atendimento consultivo com leitura tecnica real.",
|
||||
"Atendimento consultivo com leitura técnica real.",
|
||||
"Do produto ao backend sem perder contexto.",
|
||||
"Execucao com criterio, nao so codigo por demanda.",
|
||||
"Execução com critério, não só código por demanda.",
|
||||
],
|
||||
proof: [
|
||||
{
|
||||
label: "Perfil",
|
||||
value: "Engenharia full-stack com base em sistemas e integracoes.",
|
||||
value: "Engenharia full-stack com base em sistemas e integrações.",
|
||||
},
|
||||
{
|
||||
label: "Postura",
|
||||
value: "Clareza, autonomia e decisao tecnica pragmatica.",
|
||||
value: "Clareza, autonomia e decisão técnica pragmática.",
|
||||
},
|
||||
{
|
||||
label: "Acesso",
|
||||
value: "WhatsApp direto para conversa tecnica inicial.",
|
||||
value: "WhatsApp direto para conversa técnica inicial.",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -286,14 +290,15 @@ const HERO_VARIANTS: HeroVariant[] = [
|
||||
|
||||
const LAYOUT_CLASSES: Record<HeroVariant["layout"], string> = {
|
||||
default:
|
||||
"grid items-start gap-sp-8 lg:grid-cols-[minmax(0,1.1fr)_minmax(340px,0.9fr)] lg:gap-sp-10",
|
||||
"grid grid-cols-[minmax(0,1fr)] items-start gap-sp-8 lg:grid-cols-[minmax(0,1.1fr)_minmax(340px,0.9fr)] lg:gap-sp-10",
|
||||
"visual-first":
|
||||
"grid items-start gap-sp-8 lg:grid-cols-[minmax(340px,0.9fr)_minmax(0,1.1fr)] lg:gap-sp-10",
|
||||
split: "grid items-stretch gap-sp-8 lg:grid-cols-2 lg:gap-sp-10",
|
||||
"grid grid-cols-[minmax(0,1fr)] items-start gap-sp-8 lg:grid-cols-[minmax(340px,0.9fr)_minmax(0,1.1fr)] lg:gap-sp-10",
|
||||
split:
|
||||
"grid grid-cols-[minmax(0,1fr)] items-stretch gap-sp-8 lg:grid-cols-2 lg:gap-sp-10",
|
||||
report:
|
||||
"grid items-start gap-sp-8 lg:grid-cols-[minmax(360px,0.85fr)_minmax(0,1.15fr)] lg:gap-sp-10",
|
||||
"grid grid-cols-[minmax(0,1fr)] items-start gap-sp-8 lg:grid-cols-[minmax(360px,0.85fr)_minmax(0,1.15fr)] lg:gap-sp-10",
|
||||
portrait:
|
||||
"grid items-center gap-sp-8 lg:grid-cols-[minmax(0,1fr)_minmax(320px,0.72fr)] lg:gap-sp-10",
|
||||
"grid grid-cols-[minmax(0,1fr)] items-center gap-sp-8 lg:grid-cols-[minmax(0,1fr)_minmax(320px,0.72fr)] lg:gap-sp-10",
|
||||
};
|
||||
|
||||
function getGreeting(message: string) {
|
||||
@@ -303,7 +308,25 @@ function getGreeting(message: string) {
|
||||
return message;
|
||||
}
|
||||
|
||||
function SideVisual({ variant }: { variant: HeroVariant }) {
|
||||
function SideVisual({
|
||||
variant,
|
||||
shouldReduceMotion,
|
||||
}: {
|
||||
variant: HeroVariant;
|
||||
shouldReduceMotion: boolean;
|
||||
}) {
|
||||
if (variant.scene === "command") {
|
||||
return (
|
||||
<div className="mb-sp-6 space-y-sp-4">
|
||||
{/* Partículas decorativas atrás da cena: o h1 real permanece o conteúdo acessível */}
|
||||
<ParticleBuildText text={variant.headline} />
|
||||
{/* autoRotate off em reduced-motion: globo vira âncora estática */}
|
||||
<ControlRoomGlobe autoRotate={!shouldReduceMotion} />
|
||||
<TelemetryStrip reducedMotion={shouldReduceMotion} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (variant.scene === "launch") {
|
||||
return (
|
||||
<div className="mb-sp-6 grid gap-sp-3">
|
||||
@@ -355,7 +378,11 @@ function SideVisual({ variant }: { variant: HeroVariant }) {
|
||||
if (variant.scene === "signal") {
|
||||
return (
|
||||
<div className="relative mb-sp-6 h-40 overflow-hidden border border-[rgba(255,255,255,.08)] bg-[rgba(255,255,255,.03)]">
|
||||
<svg className="absolute inset-0 h-full w-full" viewBox="0 0 420 160">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="absolute inset-0 h-full w-full"
|
||||
viewBox="0 0 420 160"
|
||||
>
|
||||
<path
|
||||
d="M28 116 C108 18 190 142 284 56 S380 36 400 28"
|
||||
fill="none"
|
||||
@@ -430,7 +457,6 @@ export default function Hero() {
|
||||
const variant = HERO_VARIANTS[0];
|
||||
const [shouldReduceMotion, setShouldReduceMotion] = useState(false);
|
||||
const [shouldRenderHeroScene, setShouldRenderHeroScene] = useState(false);
|
||||
const [whatsAppDisplay, setWhatsAppDisplay] = useState("WhatsApp");
|
||||
|
||||
useEffect(() => {
|
||||
const reducedMotion = window.matchMedia(
|
||||
@@ -438,7 +464,6 @@ export default function Hero() {
|
||||
).matches;
|
||||
const coarsePointer = window.matchMedia("(pointer: coarse)").matches;
|
||||
setShouldReduceMotion(reducedMotion);
|
||||
setWhatsAppDisplay(getWhatsAppDisplayNumber());
|
||||
|
||||
if (
|
||||
!shouldLoadHeroScene({
|
||||
@@ -524,7 +549,8 @@ export default function Hero() {
|
||||
/>
|
||||
<div className="pointer-events-none absolute inset-0 z-[2] bg-[radial-gradient(circle_at_50%_50%,transparent_40%,rgba(10,10,10,0.6)_100%)]" />
|
||||
|
||||
<div className="relative z-10 mx-auto flex w-full max-w-[1240px] flex-col px-sp-6 py-sp-16 lg:px-sp-16 lg:py-sp-12">
|
||||
{/* pt >= altura do header fixo (52px): conteúdo do hero nunca nasce sob a barra */}
|
||||
<div className="relative z-10 mx-auto flex w-full max-w-[1240px] flex-col px-sp-6 pt-sp-16 pb-sp-16 lg:max-h-none lg:px-sp-16 lg:pt-sp-14 lg:pb-sp-12">
|
||||
<motion.div
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
@@ -578,7 +604,7 @@ export default function Hero() {
|
||||
</motion.p>
|
||||
|
||||
<motion.h1
|
||||
className="max-w-[940px] text-balance font-display text-[clamp(3rem,7vw,6.2rem)] font-extrabold leading-[0.9] tracking-[-0.055em]"
|
||||
className="max-w-[940px] font-display text-[clamp(1.9rem,5.2vw,4.75rem)] font-extrabold leading-[0.95] tracking-[-0.055em] lg:leading-[0.9] lg:text-balance"
|
||||
variants={heroItemSlow}
|
||||
>
|
||||
{variant.headline}
|
||||
@@ -644,7 +670,7 @@ export default function Hero() {
|
||||
|
||||
<MagneticButton
|
||||
as="a"
|
||||
href="/assets/Evandro_Fonseca_Junior_CV.pdf"
|
||||
href={CV_URL}
|
||||
download
|
||||
className="inline-flex min-h-12 items-center justify-center px-sp-2 text-[12px] font-medium text-[rgba(244,242,237,.76)] no-underline transition-colors duration-300 hover:text-[var(--slash)]"
|
||||
strength={0.2}
|
||||
@@ -719,7 +745,10 @@ export default function Hero() {
|
||||
transition={{ duration: 1.5, delay: 1, ease: [0.16, 1, 0.3, 1] }}
|
||||
/>
|
||||
|
||||
<SideVisual variant={variant} />
|
||||
<SideVisual
|
||||
variant={variant}
|
||||
shouldReduceMotion={shouldReduceMotion}
|
||||
/>
|
||||
|
||||
<div className="border-b border-[rgba(255,255,255,0.08)] pb-sp-5">
|
||||
<div className="font-mono text-[10px] uppercase tracking-[0.14em] text-[var(--slash)]">
|
||||
@@ -736,7 +765,16 @@ export default function Hero() {
|
||||
onClick={handleWhatsAppClick}
|
||||
className="mt-sp-5 inline-flex w-full items-center justify-center bg-[var(--slash)] px-sp-5 py-sp-4 font-mono text-[11px] font-bold uppercase tracking-[0.1em] text-[var(--ink)] transition hover:bg-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--slash)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--ink)]"
|
||||
>
|
||||
Agendar no WhatsApp: {whatsAppDisplay}
|
||||
{/* Ícone WhatsApp inline: lucide não tem brand icons */}
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
className="h-4 w-4"
|
||||
>
|
||||
<path d="M12.04 2a9.88 9.88 0 0 0-8.41 4.7A9.88 9.88 0 0 0 2.1 12.6a9.8 9.8 0 0 0 1.34 5.02L2 22l4.53-1.38a9.86 9.86 0 0 0 5.51 1.66h.01a9.87 9.87 0 0 0 7.02-2.9 9.79 9.79 0 0 0 2.89-6.98 9.73 9.73 0 0 0-.29-2.35A9.88 9.88 0 0 0 12.04 2Zm5.77 13.94c-.24.68-1.42 1.3-1.96 1.35-.5.05-1.13.24-3.8-.98-3.18-1.44-5.15-4.72-5.31-4.93-.15-.22-1.25-1.75-1.16-3.29.09-1.54.92-2.28 1.23-2.59.31-.31.66-.37.88-.36h.63c.2 0 .47-.03.71.58.26.65.88 2.25.96 2.41.08.17.13.36.02.57-.11.22-.17.35-.33.54-.17.19-.35.43-.5.58-.16.16-.33.34-.15.66.18.32.81 1.42 1.75 2.3 1.2 1.14 2.21 1.49 2.52 1.66.31.17.5.14.68-.09.18-.22.78-.99.99-1.33.21-.34.42-.27.7-.16.29.11 1.82.95 2.13 1.12.31.17.52.26.6.4.07.15.07.83-.17 1.51Z" />
|
||||
</svg>
|
||||
Agendar no WhatsApp
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -776,20 +814,29 @@ export default function Hero() {
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 2, duration: 1 }}
|
||||
>
|
||||
<motion.div
|
||||
className="flex flex-col items-center gap-2"
|
||||
animate={{ y: [0, 8, 0] }}
|
||||
transition={{
|
||||
duration: 2,
|
||||
repeat: Number.POSITIVE_INFINITY,
|
||||
ease: "easeInOut",
|
||||
}}
|
||||
>
|
||||
<span className="font-mono text-[8px] uppercase tracking-[0.2em] text-[rgba(244,242,237,.4)]">
|
||||
Scroll
|
||||
</span>
|
||||
<div className="h-8 w-px bg-gradient-to-b from-[var(--slash)] to-transparent opacity-50" />
|
||||
</motion.div>
|
||||
{shouldReduceMotion ? (
|
||||
<div className="flex flex-col items-center gap-2" aria-hidden="true">
|
||||
<span className="font-mono text-[8px] uppercase tracking-[0.2em] text-[rgba(244,242,237,.4)]">
|
||||
Scroll
|
||||
</span>
|
||||
<div className="h-8 w-px bg-gradient-to-b from-[var(--slash)] to-transparent opacity-50" />
|
||||
</div>
|
||||
) : (
|
||||
<motion.div
|
||||
className="flex flex-col items-center gap-2"
|
||||
animate={{ y: [0, 8, 0] }}
|
||||
transition={{
|
||||
duration: 2,
|
||||
repeat: Number.POSITIVE_INFINITY,
|
||||
ease: "easeInOut",
|
||||
}}
|
||||
>
|
||||
<span className="font-mono text-[8px] uppercase tracking-[0.2em] text-[rgba(244,242,237,.4)]">
|
||||
Scroll
|
||||
</span>
|
||||
<div className="h-8 w-px bg-gradient-to-b from-[var(--slash)] to-transparent opacity-50" />
|
||||
</motion.div>
|
||||
)}
|
||||
</motion.div>
|
||||
</section>
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user