Files
portifolio-evandrodevbr/app/components/WorkModalities.tsx
Evandro Fonseca JuniorandClaude Sonnet 5.5 2ffe718fac feat(typography): texto corrido em sans 16px; mono so em rotulos, tags e metadados
- --font-body (Space Grotesk) aplicado a p/li/dd de main e footer com :where() (especificidade zero)
- rotulos (.ds-eyebrow, .ds-kicker, .ds-tag, .ds-metric, .quality-*) seguem em Geist Mono
- .ds-copy 16px/1.6, descricoes e listas 15px/1.7 (celular deixa de usar 13px)
- cards de servicos (WorkModalities) em sans

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-04 23:44:00 -03:00

305 lines
10 KiB
TypeScript

"use client";
import { motion, type Variants } from "motion/react";
import Link from "next/link";
import { useReducedMotion } from "@/app/hooks/useReducedMotion";
import { serviceHubLinks } from "@/lib/site-content";
import { DrawLine } from "./animations/DrawLine";
import MagneticButton from "./cinematic/MagneticButton";
import { Section } from "./Section";
interface Tier {
id: string;
badge: string;
title: string;
tagline: string;
description: string;
deliverables: string[];
pricing: string;
pricingNote: string;
featured?: boolean;
ctaLabel: string;
ctaHref: string;
}
const TIERS: Tier[] = [
{
id: "build",
badge: "Do zero à produção",
title: "Um sistema para a sua operação",
tagline: "Quando as ferramentas prontas já não atendem.",
description:
"Transforme regras de negócio, planilhas e processos dispersos em um sistema próprio, com os fluxos e as integrações que a empresa precisa.",
deliverables: [
"Definição de escopo e arquitetura",
"Interface, backend e banco de dados",
"Integrações e permissões de acesso",
"Validação, publicação e documentação",
],
pricing: "Proposta por projeto",
pricingNote: "Escopo, etapas e investimento definidos antes da execução.",
featured: true,
ctaLabel: "Conversar sobre meu sistema",
ctaHref: "/#contact",
},
{
id: "discovery",
badge: "Antes de investir",
title: "Diagnóstico de um sistema existente",
tagline: "Entenda o que aproveitar e o que precisa mudar.",
description:
"Seu sistema ficou lento, frágil ou difícil de manter? Avalio o código e a operação para orientar a próxima decisão, inclusive em projetos iniciados com IA.",
deliverables: [
"Levantamento de riscos e dependências",
"Revisão de acesso aos dados",
"Análise dos gargalos da aplicação",
"Plano de correção por prioridade",
],
pricing: "Escopo de análise definido",
pricingNote: "Profundidade e prazo combinados conforme o sistema.",
ctaLabel: "Avaliar meu projeto",
ctaHref: "/#contact",
},
{
id: "evolution",
badge: "Continuidade",
title: "Integração e evolução",
tagline: "Faça o que já existe trabalhar melhor.",
description:
"Conecte ferramentas, reduza tarefas manuais e acrescente funcionalidades ao sistema atual, com atenção às dependências e ao impacto de cada mudança.",
deliverables: [
"Integração entre sistemas e equipamentos",
"Novos fluxos e automações",
"Testes das partes afetadas",
"Planejamento de manutenção e operação",
],
pricing: "Etapas acordadas",
pricingNote:
"Prioridades, suporte e responsabilidades definidos em contrato.",
ctaLabel: "Planejar a próxima etapa",
ctaHref: "/#contact",
},
];
const PROCESS = [
{
title: "Entender a operação",
description:
"Quem usa, qual problema precisa resolver e quais dados e ferramentas já existem.",
},
{
title: "Definir a entrega",
description:
"Escopo, arquitetura, riscos, investimento e critérios de aceite antes de desenvolver.",
},
{
title: "Construir e validar",
description:
"Entregas por etapa, demonstrações e testes dos fluxos, das permissões e das integrações.",
},
{
title: "Publicar e dar continuidade",
description:
"Implantação, documentação e condições de manutenção combinadas para a operação.",
},
];
function TierCard({ tier }: Readonly<{ tier: Tier }>) {
const shouldReduceMotion = useReducedMotion();
return (
<motion.article
className={`ds-card relative flex h-full min-w-0 flex-col overflow-hidden outline-none max-md:w-full max-md:max-w-none max-md:px-sp-5 max-md:py-sp-5 ${
tier.featured ? "border-[var(--slash)] shadow-sm" : ""
}`}
style={{
borderWidth: tier.featured ? "2px" : "1px",
}}
whileHover={
shouldReduceMotion
? undefined
: {
y: -4,
boxShadow: "0 24px 50px rgba(0, 0, 0, 0.08)",
}
}
whileTap={shouldReduceMotion ? undefined : { scale: 0.99 }}
transition={{ type: "spring", stiffness: 180, damping: 18 }}
>
<div className="flex min-w-0 items-start justify-between gap-sp-4">
<span className="ds-kicker max-md:text-[10px] max-md:leading-[1.6]">
{tier.badge}
</span>
</div>
<DrawLine delay={0.04} />
<div className="mt-sp-4 min-w-0">
<h3 className="ds-card-title !mt-0 text-balance !text-[clamp(19px,5vw,28px)] !leading-[1.02] !tracking-[-0.035em] [overflow-wrap:break-word] [word-break:normal]">
{tier.title}
</h3>
<p className="mt-sp-2 text-[12px] leading-[1.7] text-[var(--meta)] md:text-[11px]">
{tier.tagline}
</p>
</div>
<p
className="ds-copy !mt-sp-4 !text-[13px] !leading-[1.75] [overflow-wrap:break-word] [word-break:normal] md:!text-[12px]"
data-reel="right"
>
{tier.description}
</p>
<ul
className="ds-list !mt-sp-5 !pl-[1.15rem] !text-[13px] !leading-[1.75] [overflow-wrap:break-word] [word-break:normal] md:!text-[12px]"
data-reel-stagger="fade"
>
{tier.deliverables.map((deliverable) => (
<li key={deliverable} className="pl-sp-1">
{deliverable}
</li>
))}
</ul>
<div className="mt-sp-6 space-y-sp-2 border-t border-[var(--border)] pt-sp-5">
<div className="font-display text-[clamp(17px,4.6vw,18px)] font-extrabold leading-none tracking-tight">
{tier.pricing}
</div>
<div className="font-display text-[12px] leading-[1.7] text-[var(--meta)]">
{tier.pricingNote}
</div>
</div>
<MagneticButton
as="a"
href={tier.ctaHref}
className={`ds-link mt-sp-6 min-h-[50px] w-full justify-center px-sp-4 py-sp-3 text-center text-[11px] leading-none ${
tier.featured ? "ds-link-accent" : "ds-link-muted"
}`}
strength={0.25}
>
{tier.ctaLabel}
</MagneticButton>
</motion.article>
);
}
export function WorkModalities() {
const shouldReduceMotion = useReducedMotion();
const containerVariants: Variants = {
hidden: {},
visible: {
transition: {
delayChildren: 0.08,
staggerChildren: 0.08,
},
},
};
const itemVariants: Variants = {
hidden: shouldReduceMotion
? { opacity: 0 }
: { opacity: 0, y: 20, clipPath: "inset(100% 0 0 0)" },
visible: {
opacity: 1,
y: 0,
clipPath: "inset(0% 0 0 0)",
transition: shouldReduceMotion
? { duration: 0.25 }
: { duration: 0.75, ease: [0.16, 1, 0.3, 1] },
},
};
return (
<Section
id="modalities"
eyebrow="Soluções"
title="Software feito a partir do seu negócio."
description="Para empresas que precisam de um sistema próprio, de ferramentas conectadas ou de uma avaliação técnica antes de dar o próximo passo."
disableChildrenAnimation
>
<div className="mb-sp-8 ds-card bg-[rgba(10,10,10,0.02)]">
<div className="flex flex-col gap-sp-4 lg:flex-row lg:items-end lg:justify-between">
<div className="max-w-[760px]">
<div className="ds-kicker">Reconhece algum destes cenários?</div>
<h3 className="ds-card-title !mt-sp-3" data-reel="left">
Planilhas demais. Sistemas isolados. Trabalho repetido.
</h3>
<p className="ds-copy !mt-sp-3 max-w-[62ch]" data-reel="right">
A operação cresceu, mas as ferramentas não acompanharam. Ou a
ideia precisa sair do protótipo para atender clientes. O projeto
começa pelo problema, sem exigir que você já saiba qual tecnologia
usar.
</p>
</div>
<MagneticButton
as="a"
href="/servicos"
className="ds-link ds-link-accent"
strength={0.2}
>
Conhecer todos os serviços
</MagneticButton>
</div>
<div
className="mt-sp-6 grid gap-sp-3 md:grid-cols-2 xl:grid-cols-3"
data-reel-stagger="left"
>
{serviceHubLinks.map((service) => (
<Link
key={service.href}
href={service.href}
className="min-w-0 rounded-[8px] border border-[var(--border)] bg-white/70 px-sp-4 py-sp-4 transition-colors duration-200 hover:border-[var(--slash)] hover:bg-white"
>
<div className="font-display text-base font-semibold leading-snug text-[var(--ink)]">
{service.label}
</div>
<div className="mt-sp-2 font-display text-sm leading-6 text-[var(--ink-80)]">
{service.description}
</div>
</Link>
))}
</div>
</div>
<motion.div
className="grid grid-cols-1 gap-sp-4 md:grid-cols-2 md:gap-sp-5 lg:grid-cols-3 lg:gap-sp-6"
initial="hidden"
whileInView="visible"
viewport={{ once: true, amount: 0.2 }}
variants={containerVariants}
>
{TIERS.map((tier) => (
<motion.div key={tier.id} variants={itemVariants} className="min-w-0">
<TierCard tier={tier} />
</motion.div>
))}
</motion.div>
<div id="process" className="mt-sp-12 scroll-mt-24">
<h3 className="ds-card-title">Como o projeto acontece</h3>
<p className="ds-copy max-w-[65ch]">
Você acompanha as decisões e valida cada etapa. Prazo e investimento
dependem do escopo, das integrações e dos riscos identificados.
</p>
<ol className="mt-sp-6 grid gap-sp-6 sm:grid-cols-2 xl:grid-cols-4">
{PROCESS.map((step, index) => (
<li
key={step.title}
className="border-t border-[var(--border)] pt-sp-4"
>
<span className="ds-kicker">
{String(index + 1).padStart(2, "0")}
</span>
<h4 className="mt-sp-3 text-base font-semibold">{step.title}</h4>
<p className="ds-copy">{step.description}</p>
</li>
))}
</ol>
</div>
</Section>
);
}