import Image from "next/image"; import { getShowcaseAssets } from "@/lib/project-showcase"; import { generalFirstStep, type ServiceOffer, serviceOffers, } from "@/lib/site-content"; import { primaryButton, textLink } from "./button-styles"; import ContactOfferLink from "./ContactOfferLink"; import "./conversion.css"; import HoverPrefetchLink from "./HoverPrefetchLink"; import { Reveal } from "./Reveal"; import { Section } from "./Section"; /** O que só a home diz de cada oferta; o nome e "O que você recebe" vêm de `serviceOffers`, a fonte única que /servicos também usa. */ interface OfferExtras { description: string; ctaLabel: string; /** Case cujo pôster ilustra a oferta; sem ele, o cartão traz uma ilustração própria (ver OfferArt). */ poster?: { id: string; title: string }; moreLabel: string; moreHref: string; } /** * Os textos da home para as três ofertas, na ordem de `serviceOffers` (a do H1). Cada texto só diz o que o case ou a * página de /ia citados já sustentam; sem prazo nem preço. Só o site tem foto: a Lavação 047 é um site de catálogo e * tabela de preços, o que o texto descreve. O sistema e a revisão não têm um case que mostre o que descrevem (a vitrine * da SEV é uma loja, não um painel), então cada um traz uma ilustração feita em HTML e SVG, do tamanho da foto. */ const OFFER_EXTRAS: Record = { site: { description: "O cliente vê o que você oferece e vai para a conversa no WhatsApp, como na Lavação 047.", ctaLabel: "Começar pelo site", poster: { id: "lavacao-047", title: "Lavação 047" }, moreLabel: "Ver case Lavação 047", moreHref: "/cases/lavacao-047", }, sistema: { description: "Pedidos, estoque e rotinas que hoje vivem em planilhas e mensagens passam para um painel próprio, feito para a sua equipe. Um exemplo é a SEV Moda Íntima, com cadastro de peças, pedidos e estoque por tamanho.", ctaLabel: "Começar pelo sistema", moreLabel: "Ver case SEV Moda Íntima", moreHref: "/cases/sev-modaintima", }, revisao: { description: "Para quem já tem um sistema, como um app feito no Lovable, no Bolt ou no Replit, e quer saber se ele está pronto para receber clientes.", ctaLabel: "Começar pela revisão", moreLabel: "Ver como funciona a revisão", moreHref: "/ia", }, }; 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.", }, ]; /** Colunas e linhas da planilha do esquema do sistema (a primeira linha é o cabeçalho) e a largura de cada traço de dado. */ const SHEET_COLUMNS = [0, 1, 2]; const SHEET_DATA_ROWS = [0, 1, 2, 3, 4]; const SHEET_DASH_WIDTHS = [18, 12, 15]; /** Alturas das cinco barras do painel do esquema. */ const PANEL_BARS = [14, 26, 20, 34, 28]; /** * Ilustração do sistema: as linhas de uma planilha, uma seta e um painel com três indicadores e um gráfico de barras, * sem números nem nomes de cliente. É um SVG com `viewBox` (cresce com o cartão) do mesmo tamanho da foto do site, só * em traços claros sobre o fundo escuro, e não tem texto: o nome do cartão e a lista dizem o que é. */ function SystemArt() { return ( {SHEET_DATA_ROWS.flatMap((row) => SHEET_COLUMNS.map((column) => ( )), )} {[147, 175, 203].map((x) => ( ))} {PANEL_BARS.map((height, index) => ( ))} ); } /** * Três achados do "Modelo do relatório" de /ia (#ia-modelo), em versão curta para caber no cartão: a falha, em poucas * palavras, e a gravidade. Como lá, são exemplos ilustrativos: não são de nenhum cliente nem de um app real. */ const REPORT_EXCERPT = [ { finding: "Dados expostos", severity: "Alta" }, { finding: "Chave exposta", severity: "Alta" }, { finding: "Sem backup", severity: "Média" }, ] as const; /** O mesmo tamanho nos dois selos: a gravidade fica no texto, não só na cor ou no enchimento. */ const SEVERITY_BADGE = "inline-flex min-w-12 shrink-0 items-center justify-center border border-[var(--ink)] px-1.5 font-display text-[15px] leading-5"; /** * Ilustração da revisão: um recorte do "Modelo do relatório" de /ia, com três linhas de achado, cada uma com o selo * da gravidade, e a legenda "Exemplo ilustrativo". O texto tem 15 px também aqui; os achados são curtos para caberem * numa linha só no cartão mais estreito (três colunas em 1024 px). */ function ReviewArt() { return (
); } /** Foto do case, quando há um; senão a ilustração própria da oferta. Sempre dentro da mesma caixa do mesmo tamanho. */ function OfferArt({ offer, extras, }: Readonly<{ offer: ServiceOffer; extras: OfferExtras }>) { const poster = extras.poster ? getShowcaseAssets(extras.poster.id, "desktop") : null; if (poster && extras.poster) { return ( {`Site ); } return offer.id === "sistema" ? : ; } /** Um único estilo de cartão para as três ofertas: foto ou ilustração, título com altura mínima, texto, o que você recebe, botão e link do case. */ function OfferCard({ offer, extras, }: Readonly<{ offer: ServiceOffer; extras: OfferExtras }>) { return (
{/* min-h de 3 linhas no desktop: os títulos de 2 e 3 linhas terminam na mesma altura e os textos se alinham */}

{offer.name}

{extras.description}

O que você recebe

    {offer.deliverables.map((item) => (
  • {item}
  • ))}
{/* mt-auto: com cartões de alturas diferentes, o botão e o link descem juntos até o pé do cartão */} {extras.ctaLabel} {extras.moreLabel}
); } export function WorkModalities() { return (
{serviceOffers.map((offer, index) => ( ))}
{/* Uma vez só, depois dos três cartões: o primeiro passo é o mesmo para qualquer oferta (uma conversa e, depois dela, escopo e proposta por escrito, sem prazo nem preço); a página de cada oferta diz o que se entende na conversa. */}

Primeiro passo

{generalFirstStep}

Ver todos os serviços {/* Lista compacta: o título e a descrição de cada etapa numa linha só, sem a grade de quatro cartões. */}

Como eu trabalho

Você acompanha as decisões e valida cada etapa. Prazo e investimento dependem do escopo, das integrações e dos riscos identificados.

    {PROCESS.map((step, index) => (
  1. {String(index + 1).padStart(2, "0")}

    {step.title}. {" "} {step.description}

  2. ))}
); }