/* bloo.app — Product detail: AI Code Review Skill Pack.
   Registers window.Pages['ai-code-review']; routed via app.jsx like every
   other page. Linked from the Products grid card. */
(function () {
const { Button, Badge, Card, Tag, Tabs, Alert } = window.BlooAppDesignSystem_ab7292;
const { LINKS, Icons, Icon, S } = window.Site;
const { useT } = window.I18n;
const { IconCode, IconLayers, IconUsers, IconTarget, IconCheck, IconPackage, IconSpark, IconTrendUp, IconArrow } = Icons;

const PackS = {
  backLink: { display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: 13.5, fontWeight: 500, color: 'var(--text-muted)', textDecoration: 'none', marginBottom: 18 },
  hero: { background: 'linear-gradient(180deg, var(--blue-50) 0%, var(--surface-card) 100%)', paddingTop: 72, paddingBottom: 88 },
  heroInner: { display: 'flex', flexDirection: 'column', gap: 18, alignItems: 'flex-start', maxWidth: 760 },
  h1: { fontFamily: 'var(--font-display)', fontWeight: 500, fontSize: 56, lineHeight: 1.06, letterSpacing: '-.03em', color: 'var(--text-strong)', margin: 0, textWrap: 'balance' },
  lede: { fontSize: 19, lineHeight: 1.55, color: 'var(--text-body)', maxWidth: 620, margin: 0 },
  copy: { fontSize: 16.5, lineHeight: 1.65, color: 'var(--text-muted)', maxWidth: 620, margin: 0 },
  trustRow: { display: 'flex', gap: 16, alignItems: 'center', marginTop: 8, flexWrap: 'wrap' },
  trustLabel: { fontFamily: 'var(--font-mono)', fontSize: 11, letterSpacing: '.1em', color: 'var(--text-subtle)', whiteSpace: 'nowrap' },

  band: { background: 'var(--surface-sunken)', borderTop: '1px solid var(--border-subtle)', borderBottom: '1px solid var(--border-subtle)' },

  grid3: { display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 20 },
  grid2: { display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 20 },

  fileLabel: { fontFamily: 'var(--font-mono)', fontSize: 12.5, color: 'var(--text-muted)' },

  reviewPanel: { maxWidth: 900, margin: '0 auto', overflow: 'hidden' },
  reviewHeader: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 16, flexWrap: 'wrap', padding: '16px 24px', borderBottom: '1px solid var(--border-subtle)' },
  reviewHeaderLeft: { display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' },
  reviewFileBadge: { display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: 20, height: 20, borderRadius: 'var(--radius-xs)', background: 'var(--amber-50)', color: 'var(--amber-600)', fontFamily: 'var(--font-mono)', fontSize: 9, fontWeight: 700, flex: 'none' },
  reviewFile: { fontFamily: 'var(--font-mono)', fontSize: 13.5, fontWeight: 600, color: 'var(--text-strong)' },
  reviewMeta: { fontSize: 12.5, color: 'var(--text-muted)' },

  findingRow: { padding: '22px 24px', display: 'flex', flexDirection: 'column', gap: 12 },
  findingHead: { display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' },
  findingTitle: { fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 16.5, letterSpacing: '-.01em', color: 'var(--text-strong)', margin: 0 },

  diffPanel: { background: 'var(--surface-inverse)', fontFamily: 'var(--font-mono)', fontSize: 12.5, lineHeight: 1.7, borderRadius: 'var(--radius-md)', margin: 0, padding: '10px 0', overflowX: 'auto' },
  diffLine: { display: 'flex', gap: 10, padding: '0 16px', whiteSpace: 'pre' },
  diffLineDel: { background: 'color-mix(in oklch, var(--red-500) 20%, transparent)' },
  diffLineAdd: { background: 'color-mix(in oklch, var(--green-500) 20%, transparent)' },
  diffMarker: { flex: 'none', width: 12, color: 'rgba(255,255,255,.3)' },
  diffMarkerDel: { color: 'color-mix(in oklch, var(--red-500) 60%, white)' },
  diffMarkerAdd: { color: 'color-mix(in oklch, var(--green-500) 60%, white)' },
  diffCode: { flex: 1, color: 'rgba(255,255,255,.82)' },

  includedCount: { fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 26, letterSpacing: '-.02em', color: 'var(--brand)' },

  faqRow: { borderBottom: '1px solid var(--border-subtle)' },
  faqBtn: { display: 'flex', width: '100%', alignItems: 'center', justifyContent: 'space-between', gap: 16, padding: 'var(--space-5) 0', background: 'none', border: 'none', cursor: 'pointer', textAlign: 'left', font: 'inherit', color: 'var(--text-strong)' },
  faqQ: { fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 16.5, letterSpacing: '-.01em' },
  faqChevron: { flex: 'none', display: 'flex', color: 'var(--text-muted)', transition: 'transform var(--duration-normal, 200ms) var(--ease-standard, ease)' },
  faqA: { fontSize: 15, lineHeight: 1.6, color: 'var(--text-body)', margin: '0 0 var(--space-6)', maxWidth: 720 },

  priceCard: { display: 'flex', flexDirection: 'column', gap: 16, textAlign: 'left' },
  planBadgeRow: { display: 'flex', gap: 8, flexWrap: 'wrap', alignItems: 'center' },
  priceRow: { display: 'flex', alignItems: 'baseline', gap: 8 },
  priceNum: { fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 44, letterSpacing: '-.02em', color: 'var(--text-strong)' },
  priceUnit: { fontSize: 14, color: 'var(--text-muted)' },
  fine: { fontSize: 12.5, color: 'var(--text-subtle)', margin: 0, lineHeight: 1.5 },
  includedWrap: { maxWidth: 640, margin: 'var(--space-12) auto 0', display: 'flex', flexDirection: 'column', gap: 14, alignItems: 'center' },
  includedLabel: { fontFamily: 'var(--font-mono)', fontSize: 11, letterSpacing: '.1em', color: 'var(--text-subtle)' },
  includedList: { listStyle: 'none', padding: 0, margin: 0, display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: '12px 28px', width: '100%' },

  finalCta: { background: 'var(--surface-inverse)', padding: 'var(--space-21) 0' },
  finalCtaInner: { textAlign: 'center', display: 'flex', flexDirection: 'column', gap: 18, alignItems: 'center' },
};

function mailtoHref(t, cycle) {
  const base = t('Interested in: AI code review skill pack', 'Interesse em: Pacote de skills de revisão de código com IA');
  const suffix = cycle === 'monthly' ? t(' (monthly billing)', ' (cobrança mensal)')
    : cycle === 'annual' ? t(' (annual billing)', ' (cobrança anual)')
    : '';
  return `mailto:${LINKS.companyEmail}?subject=${encodeURIComponent(base + suffix)}`;
}

function CheckoutSuccessBanner() {
  const { t } = useT();
  const [visible, setVisible] = React.useState(false);
  React.useEffect(() => {
    const params = new URLSearchParams(window.location.search);
    if (params.get('checkout') === 'success') setVisible(true);
  }, []);
  if (!visible) return null;
  return (
    <section style={{ ...S.section, paddingTop: 24, paddingBottom: 0 }}>
      <div style={S.container} className="site-container">
        <Alert tone="success" title={t('Subscription confirmed', 'Assinatura confirmada')}>
          {t(
            'Check your email for the GitHub org invite, accept it, then install the pack from the private repo. Need help? Email us at contato@bloo.app.',
            'Confira seu e-mail pelo convite da org no GitHub, aceite-o e instale o pacote a partir do repositório privado. Precisa de ajuda? Escreva para contato@bloo.app.'
          )}
          {' '}
          <a href="product-ai-code-review-inside.html" style={{ color: 'inherit', fontWeight: 600 }}>
            {t('See what\u2019s inside', 'Ver o que vem no pacote')}
          </a>
        </Alert>
      </div>
    </section>
  );
}

function SubscribeButton({ plan, variant, size, block, trailingIcon, children }) {
  const { t, locale } = useT();
  const [loading, setLoading] = React.useState(false);
  const [error, setError] = React.useState(null);

  React.useEffect(() => {
    function onPageShow() {
      setLoading(false);
    }
    window.addEventListener('pageshow', onPageShow);
    return () => window.removeEventListener('pageshow', onPageShow);
  }, []);

  async function handleClick() {
    setLoading(true);
    setError(null);
    try {
      const res = await fetch(LINKS.checkoutApi, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ plan, locale }),
      });
      const data = await res.json().catch(() => ({}));
      if (!res.ok || !data.url) {
        throw new Error(data.error || t('Checkout unavailable', 'Checkout indisponível'));
      }
      window.location.href = data.url;
    } catch (err) {
      setLoading(false);
      setError(err.message || t('Checkout failed', 'Falha no checkout'));
    }
  }

  return (
    <>
      <Button
        as="button"
        type="button"
        variant={variant}
        size={size}
        block={block}
        trailingIcon={trailingIcon}
        disabled={loading}
        onClick={handleClick}
      >
        {loading ? t('Redirecting\u2026', 'Redirecionando\u2026') : children}
      </Button>
      {error && (
        <p style={{ ...PackS.fine, color: 'var(--red-600)', marginTop: 8 }}>
          {error}.{' '}
          <a href={mailtoHref(t, plan)} style={{ color: 'inherit' }}>
            {t('Contact us instead', 'Fale conosco')}
          </a>
        </p>
      )}
    </>
  );
}

/* ---- Hero ---- */
function Hero() {
  const { t } = useT();
  return (
    <section style={PackS.hero}>
      <div style={{ ...S.container, ...PackS.heroInner }} className="site-container">
        <a href="products.html" style={PackS.backLink}>
          <span style={{ display: 'inline-flex', transform: 'rotate(180deg)' }}><IconArrow size={14} /></span>
          {t('Products', 'Produtos')}
        </a>
        <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
          <Badge tone="brand" dot>{t('40+ files · Claude, Cursor, Copilot', '40+ arquivos · Claude, Cursor, Copilot')}</Badge>
          <Badge dot>{t('Updated regularly', 'Atualizado regularmente')}</Badge>
        </div>
        <h1 style={PackS.h1} className="site-h1-hero">{t('AI code review skill pack', 'Pacote de skills de revisão de código com IA')}</h1>
        <p style={PackS.lede}>{t('A practical code review system for Claude, Cursor, and GitHub Copilot. Better pull requests, clearer feedback, fewer missed issues — without adding heavy process.', 'Um sistema de revisão de código prático para Claude, Cursor e GitHub Copilot. Pull requests melhores, feedback mais claro, menos problemas passando despercebidos — sem burocracia extra.')}</p>
        <p style={PackS.copy}>{t('Your AI tools can already review code. This pack makes them do it well: specialized reviews that find real issues instead of nitpicks, native skills and rules that keep every review consistent, and slash commands that update the pack and tune the standard as your repo evolves. Paste one install prompt — a git commit shares it with your whole team, and they never need the pack repo.', 'Suas ferramentas de IA já conseguem revisar código. Este pacote faz com que façam isso bem: revisões especializadas que encontram problemas reais em vez de implicâncias de estilo, skills e regras nativas que mantêm cada revisão consistente, e comandos slash que atualizam o pacote e ajustam o padrão conforme seu repositório evolui. Cole um único prompt de instalação — um git commit compartilha com todo o seu time, que nunca precisa acessar o repositório do pacote.')}</p>
        <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', marginTop: 6 }}>
          <Button as="a" href="#pricing" size="lg" trailingIcon={<IconArrow />}>{t('Get the pack', 'Quero o pacote')}</Button>
          <Button as="a" href="#sample" size="lg" variant="secondary">{t('See a sample review', 'Ver um exemplo de revisão')}</Button>
        </div>
        <a href="product-ai-code-review-inside.html" style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: 14, fontWeight: 500, color: 'var(--text-link)', textDecoration: 'none' }}>
          {t('Or read every file before you install \u2192', 'Ou leia cada arquivo antes de instalar \u2192')}
        </a>
        <div style={PackS.trustRow}>
          <span style={PackS.trustLabel}>{t('WORKS WITH', 'FUNCIONA COM')}</span>
          <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
            <Tag>Claude</Tag><Tag>Cursor</Tag><Tag>GitHub Copilot</Tag>
          </div>
        </div>
      </div>
    </section>
  );
}

/* ---- How it works (3 pillars) ---- */
function HowItWorks() {
  const { t } = useT();
  const PILLARS = [
    { icon: <IconCode />, title: t('Specialized review prompts', 'Prompts de revisão especializados'), body: t('10 passes — general, PR, large-PR chunking, security, performance, accessibility, architecture, Flutter, React, and API — each built around one rule: every finding names the concrete scenario where the code breaks. Findings are severity-ranked — blocker, should-fix, suggestion — with a specific fix, not a vague note.', '10 passes — geral, PR, PR grande em blocos, segurança, performance, acessibilidade, arquitetura, Flutter, React e API — cada um construído em torno de uma regra: todo achado nomeia o cenário concreto em que o código quebra. Os achados vêm classificados por severidade — bloqueante, deveria corrigir, sugestão — com uma correção específica, não uma observação vaga.') },
    { icon: <IconLayers />, title: t('One-paste install, native integrations', 'Instalação com um copy-paste, integrações nativas'), body: t('INSTALL.md has your AI agent install and configure a Claude Code skill, Cursor rules, and Copilot instructions by inspecting your codebase — about 2 minutes. Commit it and your whole team gets the same standard.', 'O INSTALL.md faz seu agente de IA instalar e configurar uma skill do Claude Code, regras do Cursor e instruções do Copilot inspecionando seu código — cerca de 2 minutos. Faça o commit e todo o seu time recebe o mesmo padrão.') },
    { icon: <IconCheck />, title: t('Slash commands keep it current', 'Comandos slash mantêm tudo atualizado'), body: t('/update-bloo-pack pulls in the latest prompts and checklists. /refresh-conventions re-infers your stack and risk areas as the repo changes. /customize-review layers in team-specific rules without losing them on the next update. /review-the-review scores a review against the evaluation rubric so you can calibrate the setup.', '/update-bloo-pack traz os prompts e checklists mais recentes. /refresh-conventions redescobre sua stack e áreas de risco conforme o repositório muda. /customize-review adiciona regras específicas do time, sem perdê-las na próxima atualização. /review-the-review pontua uma revisão contra a rubrica de avaliação para calibrar a configuração.') },
  ];
  return (
    <section style={S.section}>
      <div style={S.container} className="site-container">
        <div style={S.sectionHead}>
          <span style={S.eyebrow}>{t('HOW IT WORKS', 'COMO FUNCIONA')}</span>
          <h2 style={S.h2}>{t('One review standard, three parts.', 'Um único padrão de revisão, três partes.')}</h2>
          <p style={S.sectionSub}>{t('Most AI code reviews are shallow — vague summaries, style nitpicks, missed security holes. The tools are capable; the prompts and process are what\u2019s missing.', 'A maioria das revisões de código com IA é superficial — resumos vagos, implicâncias de estilo, falhas de segurança que passam batido. As ferramentas são capazes; o que falta são os prompts e o processo.')}</p>
        </div>
        <div style={PackS.grid3} className="site-grid-3">
          {PILLARS.map((p) => (
            <Card key={p.title} padding="lg" style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
              <span style={S.serviceIcon}>{p.icon}</span>
              <h3 style={S.h3}>{p.title}</h3>
              <p style={S.cardBody}>{p.body}</p>
            </Card>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ---- Sample finding ---- */
function DiffBlock({ lines }) {
  return (
    <pre style={PackS.diffPanel}><code>
      {lines.map((l, i) => (
        <div key={i} style={{ ...PackS.diffLine, ...(l.k === 'del' ? PackS.diffLineDel : l.k === 'add' ? PackS.diffLineAdd : null) }}>
          <span style={{ ...PackS.diffMarker, ...(l.k === 'del' ? PackS.diffMarkerDel : l.k === 'add' ? PackS.diffMarkerAdd : null) }}>
            {l.k === 'del' ? '-' : l.k === 'add' ? '+' : ''}
          </span>
          <span style={PackS.diffCode}>{l.c}</span>
        </div>
      ))}
    </code></pre>
  );
}

/* Same PR, read through four specialized passes. Each finding is deliberately
   a subtle, expensive issue a competent engineer ships under deadline — not a
   textbook bug — to show the range and judgment a generic review can't. */
const sampleS = {
  tabsWrap: { display: 'flex', justifyContent: 'center', marginBottom: 20 },
  passLine: { fontSize: 13.5, color: 'var(--text-muted)', textAlign: 'center', maxWidth: 620, margin: '0 auto 26px', lineHeight: 1.5 },
  panel: { maxWidth: 860, margin: '0 auto', overflow: 'hidden' },
  scWrap: { display: 'flex', flexDirection: 'column', gap: 12, marginTop: 4 },
  scRow: { display: 'grid', gridTemplateColumns: '132px 1fr', gap: 16, alignItems: 'baseline' },
  scLabel: { fontFamily: 'var(--font-mono)', fontSize: 10.5, letterSpacing: '.09em', color: 'var(--text-subtle)', paddingTop: 2 },
  scText: { fontSize: 14.5, lineHeight: 1.55, color: 'var(--text-body)', margin: 0 },
  catalogWrap: { maxWidth: 900, margin: '46px auto 0' },
  catalogHead: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap', marginBottom: 16 },
  catalogLabel: { fontFamily: 'var(--font-mono)', fontSize: 11, letterSpacing: '.1em', color: 'var(--text-subtle)' },
  catalogLegend: { display: 'inline-flex', alignItems: 'center', gap: 7, fontSize: 12, color: 'var(--text-subtle)' },
  catalogGrid: { display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 12 },
  catalogItem: { display: 'flex', flexDirection: 'column', gap: 5, padding: '15px 17px', border: '1px solid var(--border-subtle)', borderRadius: 'var(--radius-lg)', background: 'var(--surface-card)' },
  catalogName: { display: 'flex', alignItems: 'center', gap: 9, fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 15.5, letterSpacing: '-.01em', color: 'var(--text-strong)' },
  catalogDesc: { fontSize: 13, lineHeight: 1.45, color: 'var(--text-muted)', margin: 0, paddingLeft: 16 },
  catalogDot: { flex: 'none', width: 7, height: 7, borderRadius: '50%' },
  catalogDotDemo: { background: 'var(--brand)' },
  catalogDotPlain: { background: 'transparent', border: '1.5px solid var(--border-default)' },
};

function PassPanel({ pass, t }) {
  return (
    <Card variant="raised" padding="none" style={sampleS.panel}>
      <div style={PackS.reviewHeader}>
        <div style={PackS.reviewHeaderLeft}>
          <span style={{ ...PackS.reviewFileBadge, background: pass.badgeBg, color: pass.badgeFg }}>{pass.ext}</span>
          <span style={PackS.reviewFile}>{pass.file}</span>
          <span style={PackS.reviewMeta}>{pass.reviewedWith}</span>
        </div>
        <Badge tone={pass.tone}>{pass.severity}</Badge>
      </div>
      <div style={PackS.findingRow}>
        <p style={PackS.findingTitle}>{pass.title}</p>
        <DiffBlock lines={pass.lines} />
        <div style={sampleS.scWrap}>
          <div style={sampleS.scRow} className="pack-sc-row">
            <span style={sampleS.scLabel}>{t('THE SCENARIO', 'O CENÁRIO')}</span>
            <p style={sampleS.scText}>{pass.scenario}</p>
          </div>
          <div style={sampleS.scRow} className="pack-sc-row">
            <span style={sampleS.scLabel}>{pass.secondLabel}</span>
            <p style={sampleS.scText}>{pass.note}</p>
          </div>
        </div>
      </div>
    </Card>
  );
}

function SampleFinding() {
  const { t } = useT();
  const JS = { ext: 'JS', badgeBg: 'var(--amber-50)', badgeFg: 'var(--amber-600)' };
  const TS = { ext: 'TS', badgeBg: 'var(--blue-50)', badgeFg: 'var(--blue-600)' };
  const PASSES = [
    {
      id: 'security', tab: t('Security', 'Segurança'), ...JS,
      tone: 'danger', severity: t('Blocker', 'Bloqueante'),
      file: 'routes/users.js:32',
      reviewedWith: t('reviewed with the security pass', 'revisado com o passe de segurança'),
      title: t('Mass assignment lets any user make themselves an admin', 'Mass assignment deixa qualquer usuário se tornar admin'),
      lines: [
        { k: 'ctx', c: "router.patch('/users/:id', auth, async (req, res) => {" },
        { k: 'del', c: '  const user = await User.update(req.params.id, req.body);' },
        { k: 'add', c: '  const { name, email, avatarUrl } = req.body;' },
        { k: 'add', c: '  const user = await User.update(' },
        { k: 'add', c: '    req.params.id, { name, email, avatarUrl });' },
        { k: 'ctx', c: '  res.json(user);' },
        { k: 'ctx', c: '});' },
      ],
      scenario: t('A routine profile save POSTs {"role":"admin"} in the JSON body. update() writes every field straight through — the next request is authenticated as an administrator.', 'Um salvamento de perfil comum envia {"role":"admin"} no corpo JSON. O update() grava todos os campos direto — a próxima requisição já está autenticada como administrador.'),
      secondLabel: t('WHY IT SURVIVES', 'POR QUE PASSA'),
      note: t('The code is short, generic, and reads as clean — exactly what a human skim approves. An explicit allowlist of writable fields is the fix.', 'O código é curto, genérico e parece limpo — exatamente o que uma revisão apressada aprova. A correção é uma allowlist explícita dos campos graváveis.'),
    },
    {
      id: 'perf', tab: t('Performance', 'Performance'), ...JS,
      tone: 'warning', severity: t('Should-fix', 'Deveria corrigir'),
      file: 'services/report.js:48',
      reviewedWith: t('reviewed with the performance pass', 'revisado com o passe de performance'),
      title: t('A .find() inside .map() turns this report into an O(n·m) scan', 'Um .find() dentro de .map() torna o relatório uma varredura O(n·m)'),
      lines: [
        { k: 'del', c: '  const rows = orders.map(o => ({' },
        { k: 'del', c: '    ...o,' },
        { k: 'del', c: '    customer: users.find(u => u.id === o.userId),' },
        { k: 'del', c: '  }));' },
        { k: 'add', c: '  const byId = new Map(users.map(u => [u.id, u]));' },
        { k: 'add', c: '  const rows = orders.map(o => ({' },
        { k: 'add', c: '    ...o,' },
        { k: 'add', c: '    customer: byId.get(o.userId),' },
        { k: 'add', c: '  }));' },
      ],
      scenario: t('5,000 orders matched against 2,000 users is 10 million comparisons on every report load — instant on seed data, a multi-second stall in production.', '5.000 pedidos cruzados com 2.000 usuários são 10 milhões de comparações a cada carregamento — instantâneo com dados de teste, uma trava de vários segundos em produção.'),
      secondLabel: t('COST AT SCALE', 'CUSTO EM ESCALA'),
      note: t('A Map built once makes the lookup O(n+m) — the same result with roughly a thousandth of the work at this size.', 'Um Map construído uma vez torna a busca O(n+m) — o mesmo resultado com cerca de um milésimo do trabalho nesse tamanho.'),
    },
    {
      id: 'arch', tab: t('Architecture', 'Arquitetura'), ...TS,
      tone: 'warning', severity: t('Should-fix', 'Deveria corrigir'),
      file: 'ui/InvoiceCard.tsx:1',
      reviewedWith: t('reviewed with the architecture pass', 'revisado com o passe de arquitetura'),
      title: t('A view component queries the database directly', 'Um componente de view consulta o banco diretamente'),
      lines: [
        { k: 'del', c: "import { db } from '../../db';" },
        { k: 'ctx', c: 'export function InvoiceCard({ id }: Props) {' },
        { k: 'del', c: '  const invoice = db.query(' },
        { k: 'del', c: "    'SELECT * FROM invoices WHERE id = $1', [id]);" },
        { k: 'add', c: "  // fetched through the app's data layer, not the view" },
        { k: 'add', c: '  const invoice = useInvoice(id);' },
        { k: 'ctx', c: '  return <InvoiceView invoice={invoice} />;' },
        { k: 'ctx', c: '}' },
      ],
      scenario: t('The widget imports the db client and runs SQL in render. The view layer now depends on the schema, can\u2019t render without a database, and can\u2019t be unit-tested in isolation.', 'O widget importa o cliente do banco e roda SQL no render. A camada de view passa a depender do schema, não renderiza sem um banco e não dá para testar isoladamente.'),
      secondLabel: t('FLAGGED AGAINST', 'EM DESACORDO COM'),
      note: t('The layered architecture your team named in conventions — architecture is never a blocker on its own. Route it through the data layer the rest of the app already uses.', 'A arquitetura em camadas que seu time nomeou nas convenções — arquitetura nunca é bloqueante por si só. Encaminhe pela camada de dados que o resto do app já usa.'),
    },
    {
      id: 'react', tab: 'React', ...TS,
      tone: 'warning', severity: t('Should-fix', 'Deveria corrigir'),
      file: 'hooks/useProfile.ts:9',
      reviewedWith: t('reviewed with the React pass', 'revisado com o passe de React'),
      title: t("A re-fetch race can show one profile under another's name", 'Uma condição de corrida no re-fetch pode mostrar um perfil com o nome de outro'),
      lines: [
        { k: 'ctx', c: 'useEffect(() => {' },
        { k: 'del', c: '  fetchProfile(id).then(setProfile);' },
        { k: 'add', c: '  let active = true;' },
        { k: 'add', c: '  fetchProfile(id).then(p => {' },
        { k: 'add', c: '    if (active) setProfile(p);' },
        { k: 'add', c: '  });' },
        { k: 'add', c: '  return () => { active = false; };' },
        { k: 'ctx', c: '}, [id]);' },
      ],
      scenario: t('Open profile 482, then quickly 917. If 482\u2019s response resolves last, the page shows 917\u2019s header with 482\u2019s data. No error, no crash — just wrong.', 'Abra o perfil 482 e, logo em seguida, o 917. Se a resposta do 482 chegar por último, a tela mostra o cabeçalho do 917 com os dados do 482. Sem erro, sem crash — só errado.'),
      secondLabel: t("WHY IT'S MISSED", 'POR QUE ESCAPA'),
      note: t('It only shows under fast navigation or a slow network, so it passes every calm local test. A cleanup flag discards stale responses.', 'Só aparece com navegação rápida ou rede lenta, então passa em todo teste local tranquilo. Uma flag de cleanup descarta respostas obsoletas.'),
    },
  ];
  const [active, setActive] = React.useState('security');
  const pass = PASSES.find((p) => p.id === active) || PASSES[0];
  const items = PASSES.map((p) => ({ value: p.id, label: p.tab }));
  const CATALOG = [
    { name: t('General', 'Geral'), desc: t('Correctness, edge cases, and error handling on any diff.', 'Corretude, casos extremos e tratamento de erros em qualquer diff.') },
    { name: t('PR summary', 'Resumo de PR'), desc: t('Risk, blast radius, and what to test before you merge.', 'Risco, área de impacto e o que testar antes do merge.') },
    { name: t('Large PRs', 'PRs grandes'), desc: t('Chunks oversized diffs so nothing gets skimmed.', 'Divide diffs grandes em blocos para nada passar batido.') },
    { name: t('Security', 'Segurança'), desc: t('Injection, authorization, secrets, and unsafe input.', 'Injeção, autorização, segredos e entrada não validada.'), demo: true },
    { name: t('Performance', 'Performance'), desc: t('N+1 queries, needless work, and hot-path cost at scale.', 'Consultas N+1, trabalho desnecessário e custo em escala.'), demo: true },
    { name: t('Accessibility', 'Acessibilidade'), desc: t('Semantics, focus order, labels, and color contrast.', 'Semântica, ordem de foco, rótulos e contraste de cor.') },
    { name: t('Architecture', 'Arquitetura'), desc: t('Layering and boundary violations against your conventions.', 'Violações de camadas e limites contra as suas convenções.'), demo: true },
    { name: 'Flutter', desc: t('Rebuilds, state handling, and platform pitfalls.', 'Rebuilds, gestão de estado e armadilhas de plataforma.') },
    { name: 'React', desc: t('Hooks, effects, and re-render or data-fetch races.', 'Hooks, efeitos e corridas de re-render ou de fetch.'), demo: true },
    { name: 'API', desc: t('Contract, versioning, status codes, and error shapes.', 'Contrato, versionamento, códigos de status e formato de erro.') },
  ];
  return (
    <section id="sample" style={{ ...S.section, ...PackS.band, scrollMarginTop: 80 }}>
      <div style={S.container} className="site-container">
        <div style={S.sectionHead}>
          <span style={S.eyebrow}>{t('SEE IT WORK', 'VEJA FUNCIONANDO')}</span>
          <h2 style={S.h2}>{t('One pull request. Ten specialized passes.', 'Um pull request. Dez passes especializados.')}</h2>
          <p style={S.sectionSub}>{t('A generic review sees one file and a few obvious bugs. Each specialized pass reads the same diff through its own lens — and catches the subtle, expensive issue a good engineer ships under deadline.', 'Uma revisão genérica vê um arquivo e alguns bugs óbvios. Cada passe especializado lê o mesmo diff pela sua própria lente — e pega o problema sutil e caro que um bom engenheiro entrega sob prazo.')}</p>
        </div>
        <div style={sampleS.tabsWrap}>
          <Tabs variant="pill" value={active} onChange={setActive} items={items} />
        </div>
        <p style={sampleS.passLine}>{t('Four of the ten passes, in depth — switch tabs to see what each one is built to catch. The full set is below.', 'Quatro dos dez passes, em detalhe — troque as abas para ver o que cada um foi feito para pegar. O conjunto completo está abaixo.')}</p>
        <PassPanel pass={pass} t={t} />
        <div style={sampleS.catalogWrap}>
          <div style={sampleS.catalogHead}>
            <span style={sampleS.catalogLabel}>{t('ALL TEN PASSES', 'AS DEZ PASSAGENS')}</span>
            <span style={sampleS.catalogLegend}>
              <span style={{ ...sampleS.catalogDot, ...sampleS.catalogDotDemo }} />
              {t('shown in the demo above', 'mostradas na demo acima')}
            </span>
          </div>
          <div style={sampleS.catalogGrid} className="site-grid-2">
            {CATALOG.map((c) => (
              <div key={c.name} style={sampleS.catalogItem}>
                <div style={sampleS.catalogName}>
                  <span style={{ ...sampleS.catalogDot, ...(c.demo ? sampleS.catalogDotDemo : sampleS.catalogDotPlain) }} />
                  {c.name}
                </div>
                <p style={sampleS.catalogDesc}>{c.desc}</p>
              </div>
            ))}
          </div>
        </div>
      </div>
    </section>
  );
}

/* ---- Review economics: what the pack saves, in the buyer's own numbers ----
   Inputs are the team's reality; the single savings assumption (minutes saved
   per PR) is exposed as a slider with a conservative default, and the math is
   plain arithmetic the buyer can verify. Deliberately counts only reviewer
   time handed back — not prevented production incidents, which cost far more. */
const econS = {
  grid: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 24, maxWidth: 940, margin: '0 auto', alignItems: 'stretch' },
  controls: { display: 'flex', flexDirection: 'column', gap: 22, justifyContent: 'center' },
  row: { display: 'flex', flexDirection: 'column', gap: 9 },
  rowTop: { display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 12 },
  label: { fontSize: 14.5, color: 'var(--text-body)', fontWeight: 500 },
  val: { fontFamily: 'var(--font-mono)', fontSize: 14, fontWeight: 600, color: 'var(--brand)', whiteSpace: 'nowrap' },
  hint: { fontSize: 12, color: 'var(--text-subtle)', lineHeight: 1.4 },
  range: { width: '100%', accentColor: 'var(--blue-500)', height: 4, cursor: 'pointer', margin: 0 },
  result: { background: 'var(--surface-inverse)', borderRadius: 'var(--radius-xl)', padding: 'var(--space-10)', display: 'flex', flexDirection: 'column', justifyContent: 'center' },
  resultLabel: { fontFamily: 'var(--font-mono)', fontSize: 11, letterSpacing: '.1em', color: 'rgba(255,255,255,.55)', marginBottom: 10 },
  resultNumRow: { display: 'flex', alignItems: 'baseline', gap: 8, flexWrap: 'wrap' },
  resultNum: { fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 52, letterSpacing: '-.03em', color: '#fff', lineHeight: 1 },
  resultUnit: { fontSize: 15, color: 'rgba(255,255,255,.6)' },
  resultSub: { fontSize: 14.5, color: 'rgba(255,255,255,.8)', lineHeight: 1.5, margin: '10px 0 0' },
  chipRow: { display: 'flex', gap: 8, flexWrap: 'wrap', marginTop: 16 },
  chip: { fontFamily: 'var(--font-mono)', fontSize: 12, color: 'rgba(255,255,255,.9)', background: 'rgba(255,255,255,.08)', border: '1px solid rgba(255,255,255,.16)', borderRadius: 'var(--radius-full)', padding: '5px 12px', whiteSpace: 'nowrap' },
  fine: { fontSize: 12, color: 'rgba(255,255,255,.5)', lineHeight: 1.5, margin: '16px 0 0', borderTop: '1px solid rgba(255,255,255,.12)', paddingTop: 14 },
};

function SliderRow({ label, display, min, max, step, value, onChange, hint }) {
  return (
    <div style={econS.row}>
      <div style={econS.rowTop}>
        <span style={econS.label}>{label}</span>
        <span style={econS.val}>{display}</span>
      </div>
      <input type="range" min={min} max={max} step={step} value={value}
        onChange={(e) => onChange(Number(e.target.value))} style={econS.range}
        aria-label={label} />
      {hint && <span style={econS.hint}>{hint}</span>}
    </div>
  );
}

function ReviewEconomics() {
  const { t } = useT();
  const [devs, setDevs] = React.useState(5);
  const [prsPerDev, setPrsPerDev] = React.useState(4);
  const [rate, setRate] = React.useState(90);
  const [mins, setMins] = React.useState(12);

  const prsWeek = devs * prsPerDev;
  const hoursMonth = (prsWeek * 4.33 * mins) / 60;
  const moneyMonth = hoursMonth * rate;
  const annual = moneyMonth * 12;
  const price = 49;
  const multiple = moneyMonth / price;

  // Minimum minutes-saved-per-PR at which monthly savings still cover the plan
  // for this exact team (size × PR volume × rate). Below it the estimate would
  // dip under what the pack costs — we surface it and flag it rather than
  // quietly showing a "not worth it" number.
  const breakeven = (price * 60) / (prsWeek * 4.33 * rate);
  const beCeil = Math.ceil(breakeven);
  const belowBreakeven = mins < breakeven;

  const cur = (n) => '$' + Math.round(n).toLocaleString('en-US');
  const hrs = Math.round(hoursMonth);
  const multDisplay = multiple >= 10 ? Math.round(multiple) : Math.max(1, multiple).toFixed(1);
  const beLabel = breakeven < 1
    ? t('under 1 min/PR', 'menos de 1 min/PR')
    : t(`~${beCeil} min/PR`, `~${beCeil} min/PR`);

  return (
    <section style={{ ...S.section, ...PackS.band }}>
      <div style={S.container} className="site-container">
        <div style={S.sectionHead}>
          <span style={S.eyebrow}>{t('THE ECONOMICS', 'A CONTA')}</span>
          <h2 style={S.h2}>{t('What it saves, in your numbers.', 'O que economiza, nos seus números.')}</h2>
          <p style={S.sectionSub}>{t('The specialized passes catch mechanical, security, and performance issues before a human reviews — hours your team gets back every week. Set your own numbers; the math is yours to check.', 'Os passes especializados pegam problemas mecânicos, de segurança e de performance antes da revisão humana — horas que seu time recupera toda semana. Defina os seus números; a conta é sua para conferir.')}</p>
        </div>
        <div style={econS.grid} className="site-grid-2">
          <Card variant="outline" padding="lg" style={econS.controls}>
            <SliderRow label={t('Developers on the team', 'Desenvolvedores no time')} display={String(devs)}
              min={1} max={40} step={1} value={devs} onChange={setDevs} />
            <SliderRow label={t('Pull requests per dev, per week', 'PRs por dev, por semana')} display={String(prsPerDev)}
              min={1} max={15} step={1} value={prsPerDev} onChange={setPrsPerDev} />
            <SliderRow label={t('Blended cost per hour', 'Custo total por hora')} display={cur(rate)}
              min={40} max={250} step={5} value={rate} onChange={setRate}
              hint={t('Fully-loaded engineering cost.', 'Custo completo de engenharia (salário + encargos).')} />
            <SliderRow label={t('Review time saved per PR', 'Tempo de revisão poupado por PR')} display={t(`${mins} min`, `${mins} min`)}
              min={5} max={40} step={1} value={mins} onChange={setMins}
              hint={t(`Break-even for this team: ${beLabel}. Keep it conservative.`, `Ponto de equilíbrio para este time: ${beLabel}. Use uma estimativa conservadora.`)} />
            {belowBreakeven && (
              <Alert tone="warning" title={t('Below break-even for a team this size', 'Abaixo do ponto de equilíbrio para um time deste tamanho')}>
                {t(`At ${mins} min/PR, ${devs} developer${devs === 1 ? '' : 's'} at ${prsPerDev} PR/week save${devs === 1 ? 's' : ''} about ${cur(moneyMonth)}/mo — under the ${cur(price)}/mo plan. Break-even here is about ${beCeil} min/PR; in real client work the security, performance, and mechanical passes hand back 10–15 min on a typical PR.`, `Com ${mins} min/PR, ${devs} desenvolvedor${devs === 1 ? '' : 'es'} a ${prsPerDev} PR/semana economiza${devs === 1 ? '' : 'm'} cerca de ${cur(moneyMonth)}/mês — abaixo do plano de ${cur(price)}/mês. O ponto de equilíbrio aqui é ~${beCeil} min/PR; em projetos reais, os passes de segurança, performance e mecânicos devolvem de 10 a 15 min num PR típico.`)}
              </Alert>
            )}
          </Card>
          <div style={econS.result}>
            <span style={econS.resultLabel}>{t('ESTIMATED SAVINGS', 'ECONOMIA ESTIMADA')}</span>
            <div style={econS.resultNumRow}>
              <span style={econS.resultNum}>{cur(moneyMonth)}</span>
              <span style={econS.resultUnit}>{t('/ month', '/ mês')}</span>
            </div>
            <p style={econS.resultSub}>{t(`About ${hrs} engineering hours handed back every month across ${devs} developer${devs === 1 ? '' : 's'}.`, `Cerca de ${hrs} horas de engenharia recuperadas por mês entre ${devs} desenvolvedor${devs === 1 ? '' : 'es'}.`)}</p>
            <div style={econS.chipRow}>
              <span style={econS.chip}>{prsWeek} {t('PRs / week', 'PRs / semana')}</span>
              {!belowBreakeven && <span style={econS.chip}>{multDisplay}× {t('the', 'o plano de')} {cur(price)}{t('/mo plan', '/mês')}</span>}
              <span style={econS.chip}>{cur(annual)} {t('/ year', '/ ano')}</span>
            </div>
            <p style={econS.fine}>{t('Counts only reviewer time the passes hand back — mechanical, security, and performance issues caught before a human looks. It leaves out prevented production incidents, which cost far more. Every input is yours to adjust.', 'Conta apenas o tempo de revisão que os passes devolvem — problemas mecânicos, de segurança e de performance pegos antes da revisão humana. Não inclui incidentes de produção evitados, que custam muito mais. Todos os valores são ajustáveis.')}</p>
          </div>
        </div>
      </div>
    </section>
  );
}

/* ---- Token efficiency: the AI-cost side of the ledger ---- */
const tokenS = {
  card: { display: 'grid', gridTemplateColumns: 'auto 1fr', gap: 40, alignItems: 'center' },
  statBox: { display: 'flex', flexDirection: 'column', gap: 8, alignItems: 'flex-start' },
  statNum: { fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 60, letterSpacing: '-.03em', color: 'var(--brand)', lineHeight: 1 },
  statCap: { fontSize: 14, color: 'var(--text-muted)', maxWidth: 180, lineHeight: 1.4 },
  list: { listStyle: 'none', padding: 0, margin: 0, display: 'flex', flexDirection: 'column', gap: 14 },
  li: { display: 'flex', gap: 12, alignItems: 'flex-start', fontSize: 15, lineHeight: 1.55, color: 'var(--text-body)' },
  caveat: { maxWidth: 760, margin: '20px auto 0', textAlign: 'center', fontSize: 12.5, color: 'var(--text-subtle)', lineHeight: 1.5 },
};

function TokenCost() {
  const { t } = useT();
  const POINTS = [
    t('One scoped pass replaces the three or four vague follow-ups an unstructured review burns to surface the same issue.', 'Um passe focado substitui os três ou quatro follow-ups vagos que uma revisão sem estrutura gasta para chegar ao mesmo problema.'),
    t('For most pull requests that lands at a few cents of API usage per full review — negligible next to the reviewer hours in the calculator above.', 'Na maioria dos PRs isso fica em alguns centavos de uso de API por revisão completa — irrelevante perto das horas de revisão da calculadora acima.'),
  ];
  return (
    <section style={S.section}>
      <div style={S.container} className="site-container">
        <div style={S.sectionHead}>
          <span style={S.eyebrow}>{t('AI TOKEN EFFICIENCY', 'EFICIÊNCIA DE TOKENS DE IA')}</span>
          <h2 style={S.h2}>{t('Fewer AI tokens to reach the same review.', 'Menos tokens de IA para chegar à mesma revisão.')}</h2>
          <p style={S.sectionSub}>{t('The pack spends AI tokens to run — but because each pass is scoped to one concern, it gets there in far fewer than an ad-hoc review that re-prompts its way to the same findings.', 'O pacote gasta tokens de IA para rodar — mas, como cada passe é focado em uma só preocupação, chega lá com muito menos que uma revisão improvisada que fica re-promptando até achar os mesmos problemas.')}</p>
        </div>
        <Card variant="raised" padding="lg" style={{ maxWidth: 860, margin: '0 auto' }}>
          <div style={tokenS.card} className="site-grid-2">
            <div style={tokenS.statBox}>
              <span style={tokenS.statNum}>2–4×</span>
              <span style={tokenS.statCap}>{t('fewer tokens than ad-hoc re-prompting, to the same findings', 'menos tokens que ficar re-promptando à toa, para os mesmos achados')}</span>
            </div>
            <ul style={tokenS.list}>
              {POINTS.map((p) => (
                <li key={p} style={tokenS.li}><span style={S.checkDot}><Icons.IconCheck size={13} /></span>{p}</li>
              ))}
            </ul>
          </div>
        </Card>
        <p style={tokenS.caveat}>{t('Rough estimates — actual AI token use varies with the model, the size of the pull request, and how much surrounding code your tool pulls in for context.', 'Estimativas aproximadas — o uso real de tokens de IA varia com o modelo, o tamanho do pull request e quanto código de contexto sua ferramenta puxa.')}</p>
      </div>
    </section>
  );
}

/* ---- What's included ---- */
function WhatsIncluded() {
  const { t } = useT();
  const ITEMS = [
    { icon: <IconSpark />, count: '1', title: t('One-paste auto-setup', 'Auto-configuração com um copy-paste'), body: t('INSTALL.md installs and customizes every integration below by inspecting your codebase — nothing to fill in by hand. About 2 minutes.', 'O INSTALL.md instala e personaliza cada integração abaixo inspecionando seu código — nada para preencher manualmente. Cerca de 2 minutos.') },
    { icon: <IconLayers />, count: '3', title: t('Native integrations', 'Integrações nativas'), body: t('A Claude Code skill + CLAUDE.md, 11 Cursor rules, and Copilot repository + file-type instructions — install any combination.', 'Uma skill do Claude Code + CLAUDE.md, 11 regras do Cursor, e instruções de repositório + por tipo de arquivo do Copilot — instale qualquer combinação.') },
    { icon: <IconCode />, count: '10', title: t('Review prompts', 'Prompts de revisão'), tags: t(['General', 'PR', 'Large PRs', 'Security', 'Performance', 'Accessibility', 'Architecture', 'Flutter', 'React', 'API'], ['Geral', 'PR', 'PRs grandes', 'Segurança', 'Performance', 'Acessibilidade', 'Arquitetura', 'Flutter', 'React', 'API']) },
    { icon: <IconCheck />, count: '5', title: t('Checklists', 'Checklists'), tags: t(['PR', 'Security', 'Performance', 'Maintainability', 'Architecture'], ['PR', 'Segurança', 'Performance', 'Manutenibilidade', 'Arquitetura']) },
    { icon: <IconTrendUp />, count: '3', title: t('Before/after examples', 'Exemplos de antes/depois'), body: t('A calibration pair with known issues, plus a sample PR summary — verify your setup catches real bugs before you trust it.', 'Um par de calibração com problemas conhecidos, mais um resumo de PR de exemplo — verifique se sua configuração pega bugs reais antes de confiar nela.') },
    { icon: <IconPackage />, count: '5', title: t('Templates', 'Templates'), tags: t(['PR', 'Review comment', 'Release readiness', 'Customizations', 'Team review policy'], ['PR', 'Comentário de revisão', 'Prontidão para release', 'Customizações', 'Política de revisão em equipe']) },
    { icon: <IconUsers />, count: '6', title: t('Team rollout docs', 'Documentos de adoção em equipe'), tags: t(['Onboarding checklist', 'Team adoption', 'Multi-repo checklist', 'Monorepo guide', 'PR size guidance', 'Evaluation rubric'], ['Checklist de onboarding', 'Adoção em equipe', 'Checklist multi-repo', 'Guia de monorepo', 'Diretrizes de tamanho de PR', 'Rubrica de avaliação']) },
  ];
  return (
    <section style={{ ...S.section, ...PackS.band }}>
      <div style={S.container} className="site-container">
        <div style={S.sectionHead}>
          <span style={S.eyebrow}>{t("WHAT'S INSIDE", 'O QUE TEM DENTRO')}</span>
          <h2 style={S.h2}>{t('40+ files, ready to drop in.', '40+ arquivos, prontos para usar.')}</h2>
          <p style={S.sectionSub}>{t('Everything is plain Markdown. No SaaS, no lock-in, works in any tool that accepts text.', 'Tudo em Markdown puro. Sem SaaS, sem dependência forçada, funciona em qualquer ferramenta que aceite texto.')}</p>
          <a href="product-ai-code-review-inside.html" style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: 14, fontWeight: 500, color: 'var(--text-link)', textDecoration: 'none', marginTop: 4 }}>{t("Browse the full file tree \u2014 see what's inside \u2192", 'Explore a \u00e1rvore completa \u2014 veja o que tem dentro \u2192')}</a>
        </div>
        <div style={PackS.grid3} className="site-grid-3">
          {ITEMS.map((it) => (
            <Card key={it.title} padding="lg" style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
                <span style={S.serviceIcon}>{it.icon}</span>
                <span style={PackS.includedCount}>{it.count}</span>
              </div>
              <h3 style={S.h3}>{it.title}</h3>
              {it.body
                ? <p style={S.cardBody}>{it.body}</p>
                : (
                  <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
                    {it.tags.map((tag) => <Tag key={tag}>{tag}</Tag>)}
                  </div>
                )}
            </Card>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ---- Always improving ---- */
function AlwaysImproving() {
  const { t } = useT();
  const POINTS = [
    { icon: <IconTrendUp />, title: t('Updated as models change', 'Atualizado conforme os modelos mudam'), body: t('When Claude, Cursor, or Copilot change how they read instructions, we revise the pack so it keeps working — not just on day one.', 'Quando Claude, Cursor ou Copilot mudam a forma como leem instruções, revisamos o pacote para que continue funcionando — não só no primeiro dia.') },
    { icon: <IconSpark />, title: t('New prompts, added regularly', 'Novos prompts, adicionados regularmente'), body: t('New review passes ship as we find gaps in real client work — Python and Go are next up — included in your subscription at no extra cost.', 'Novos passes de revisão são lançados conforme encontramos lacunas em projetos reais com clientes — Python e Go são os próximos — incluídos na sua assinatura sem custo extra.') },
    { icon: <IconCheck />, title: t('Every change logged', 'Toda mudança registrada'), body: t('A changelog tracks what changed and why, so you always know what\u2019s new before you pull the latest version.', 'Um changelog registra o que mudou e por quê, para você sempre saber o que há de novo antes de puxar a última versão.') },
  ];
  return (
    <section id="updates" style={{ ...S.section, ...PackS.band, scrollMarginTop: 80 }}>
      <div style={S.container} className="site-container">
        <div style={S.sectionHead}>
          <span style={S.eyebrow}>{t('ALWAYS IMPROVING', 'SEMPRE MELHORANDO')}</span>
          <h2 style={S.h2}>{t('Built to keep getting better.', 'Feito para melhorar continuamente.')}</h2>
          <p style={S.sectionSub}>{t('This is a subscription, not a snapshot — the pack evolves with the tools it supports for as long as you\u2019re on it.', 'É uma assinatura, não uma versão parada no tempo — o pacote evolui junto com as ferramentas que suporta enquanto você estiver assinando.')}</p>
        </div>
        <div style={PackS.grid3} className="site-grid-3">
          {POINTS.map((p) => (
            <Card key={p.title} padding="lg" style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
              <span style={S.serviceIcon}>{p.icon}</span>
              <h3 style={S.h3}>{p.title}</h3>
              <p style={S.cardBody}>{p.body}</p>
            </Card>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ---- Who it's for ---- */
function WhoItsFor() {
  const { t } = useT();
  const AUDIENCE = [
    { icon: <IconCode />, title: t('Solo developers', 'Desenvolvedores solo'), body: t('You ship without a second reviewer — this runs before anyone else sees the diff.', 'Você lança sem um segundo revisor — isso roda antes de qualquer pessoa ver o diff.') },
    { icon: <IconUsers />, title: t('Small teams (2–10 devs)', 'Times pequenos (2 a 10 devs)'), body: t('Informal or inconsistent review becomes one standard, without writing a process doc.', 'Uma revisão informal ou inconsistente vira um único padrão, sem precisar escrever um documento de processo.') },
    { icon: <IconLayers />, title: t('Tech leads', 'Tech leads'), body: t('Standardize review quality across the team without building prompts and rubrics from scratch.', 'Padronize a qualidade de revisão do time sem construir prompts e rubricas do zero.') },
    { icon: <IconTarget />, title: t('Founders', 'Fundadores'), body: t('Auditing contractor or agency code, without reading every line yourself.', 'Auditando código de terceiros ou agências, sem precisar ler linha por linha.') },
  ];
  return (
    <section style={S.section}>
      <div style={S.container} className="site-container">
        <div style={S.sectionHead}>
          <span style={S.eyebrow}>{t("WHO IT'S FOR", 'PARA QUEM É')}</span>
          <h2 style={S.h2}>{t('Built for teams without a dedicated reviewer.', 'Feito para times sem um revisor dedicado.')}</h2>
        </div>
        <div style={PackS.grid2} className="site-grid-2">
          {AUDIENCE.map((a) => (
            <Card key={a.title} padding="lg" style={{ display: 'flex', gap: 16, alignItems: 'flex-start' }}>
              <span style={S.serviceIcon}>{a.icon}</span>
              <div>
                <h3 style={S.h3}>{a.title}</h3>
                <p style={{ ...S.cardBody, marginTop: 6 }}>{a.body}</p>
              </div>
            </Card>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ---- Outcomes + use cases ---- */
function OutcomesUseCases() {
  const { t } = useT();
  const OUTCOMES = [
    t('Catch injection, authz, and error-handling issues before human review', 'Detecte falhas de injeção, autorização e tratamento de erros antes da revisão humana'),
    t('Catch layering and boundary issues before human review, once your team names an app architecture', 'Detecte problemas de camadas e limites antes da revisão humana, quando o time nomeia uma arquitetura de app'),
    t('Human reviewers spend attention on design, not null checks', 'Revisores humanos gastam atenção em design, não em checagens de null'),
    t('One review standard across the team, regardless of tool', 'Um único padrão de revisão em todo o time, independente da ferramenta'),
    t('A verifiable setup — calibrate against known issues, not vibes', 'Uma configuração verificável — calibrada contra problemas conhecidos, não por sensação'),
  ];
  const USE_CASES = t(
    ['Pre-merge self-review', 'Team review standard', 'Security & performance passes', 'Contractor code audits'],
    ['Autorrevisão antes do merge', 'Padrão de revisão em equipe', 'Passes de segurança e performance', 'Auditoria de código de terceiros']
  );
  return (
    <section style={S.section}>
      <div style={{ ...S.container, display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 48, alignItems: 'center' }} className="site-container site-grid-2">
        <div>
          <span style={S.eyebrow}>{t('OUTCOMES', 'RESULTADOS')}</span>
          <h2 style={S.h2}>{t("What changes once it's installed.", 'O que muda depois de instalado.')}</h2>
          <ul style={{ listStyle: 'none', padding: 0, margin: 'var(--space-6) 0 0', display: 'flex', flexDirection: 'column', gap: 14 }}>
            {OUTCOMES.map((o) => (
              <li key={o} style={{ display: 'flex', gap: 12, alignItems: 'flex-start', fontSize: 15, color: 'var(--text-body)', lineHeight: 1.5 }}>
                <span style={S.checkDot}><Icons.IconCheck size={13} /></span>{o}
              </li>
            ))}
          </ul>
        </div>
        <Card variant="raised" padding="lg" style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
          <span style={S.serviceIcon}><IconTarget /></span>
          <div style={{ fontFamily: 'var(--font-mono)', fontSize: 12, letterSpacing: '.06em', color: 'var(--text-muted)' }}>{t('USE CASES', 'CASOS DE USO')}</div>
          <p style={{ fontFamily: 'var(--font-display)', fontSize: 19, lineHeight: 1.4, color: 'var(--text-strong)', letterSpacing: '-.01em', margin: 0 }}>
            {t('From a pre-merge habit to a full audit of code you didn\u2019t write.', 'De um hábito antes do merge a uma auditoria completa de código que você não escreveu.')}
          </p>
          <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
            {USE_CASES.map((u) => <Tag key={u}>{u}</Tag>)}
          </div>
        </Card>
      </div>
    </section>
  );
}

/* ---- FAQ ---- */
function FaqItem({ q, a, open, onToggle }) {
  return (
    <div style={PackS.faqRow}>
      <button type="button" style={PackS.faqBtn} aria-expanded={open} onClick={onToggle}>
        <span style={PackS.faqQ}>{q}</span>
        <span style={{ ...PackS.faqChevron, transform: open ? 'rotate(180deg)' : 'rotate(0deg)' }}>
          <Icon d={<path d="M6 9l6 6 6-6" />} size={18} sw={2} />
        </span>
      </button>
      {open && <p style={PackS.faqA}>{a}</p>}
    </div>
  );
}

function Faq() {
  const { t } = useT();
  const [openIdx, setOpenIdx] = React.useState(0);
  const FAQS = [
    { q: t('Which tools does it work with?', 'Com quais ferramentas funciona?'), a: t('Claude (chat, Projects, Claude Code), Cursor, and GitHub Copilot have dedicated integrations. The prompts are plain text and work in any capable AI coding tool.', 'Claude (chat, Projects, Claude Code), Cursor e GitHub Copilot têm integrações dedicadas. Os prompts são texto puro e funcionam em qualquer ferramenta de coding com IA competente.') },
    { q: t('Where does my code go? Is anything sent to bloo?', 'Para onde vai o meu código? Algo é enviado para a bloo?'), a: t('Nothing is sent to bloo. The pack is plain Markdown — prompts, skills, and rules that run inside your own AI tools. There’s no bloo service, no account, and no telemetry. Your code only ever goes where your AI tool already sends it (Claude, Cursor, or Copilot), under that tool’s own data terms — the pack adds no new destination.', 'Nada é enviado para a bloo. O pacote é Markdown puro — prompts, skills e regras que rodam dentro das suas próprias ferramentas de IA. Não há serviço da bloo, nem conta, nem telemetria. Seu código só vai para onde sua ferramenta de IA já envia (Claude, Cursor ou Copilot), sob os termos de dados dela — o pacote não adiciona nenhum destino novo.') },
    { q: t('Do I need to know prompt engineering?', 'Preciso saber prompt engineering?'), a: t('No. Paste INSTALL.md, answer which tools, commit. Day-to-day, run /code-review.', 'Não. Cole o INSTALL.md, responda quais ferramentas usar, faça o commit. No dia a dia, rode /code-review.') },
    { q: t('Will this replace human code review?', 'Isso substitui a revisão humana de código?'), a: t('No, and it doesn\u2019t try to. It raises the floor — mechanical issues get caught before human review, so humans review the interesting parts. Humans still choose the architecture and own product fit; the architecture pass only raises layering and boundary issues against the pattern your team names in conventions (or soft hints when that field is blank).', 'Não, e não tenta substituir. Ele eleva o nível mínimo — problemas mecânicos são pegos antes da revisão humana, para que humanos revisem as partes interessantes. Humanos continuam escolhendo a arquitetura e responsáveis pelo fit com o produto; o passe de arquitetura só levanta problemas de camadas e limites contra o padrão que o time nomeia nas convenções (ou dicas leves quando esse campo fica em branco).') },
    { q: t('How is this different from free prompts online?', 'Em que isso difere de prompts gratuitos por aí?'), a: t('It\u2019s a system, not a prompt: consistent severity vocabulary across 10 review types, persistent tool integrations, lifecycle skills for updates and convention refreshes, /review-the-review for setup calibration, calibration against a known-issues example, and team rollout docs. And it\u2019s maintained — see the changelog.', 'É um sistema, não um prompt: vocabulário de severidade consistente em 10 tipos de revisão, integrações de ferramenta persistentes, skills de ciclo de vida para atualização e revisão de convenções, /review-the-review para calibração da configuração, calibração contra um exemplo com problemas conhecidos, e documentos de adoção em equipe. E é mantido — veja o changelog.') },
    { q: t("What if my stack isn't Flutter or React?", 'E se minha stack não for Flutter ou React?'), a: t('The general, PR, security, performance, architecture, and API prompts are stack-agnostic — the architecture pass adds Flutter/React appendices only when those file types are present. Run /customize-review to add rules for your framework, or extend the installed skill references, Cursor rules, or Copilot instructions directly.', 'Os prompts de geral, PR, segurança, performance, arquitetura e API são agnósticos de stack — o passe de arquitetura só adiciona apêndices de Flutter/React quando esses tipos de arquivo estão presentes. Rode /customize-review para adicionar regras para o seu framework, ou estenda diretamente as referências da skill instalada, as regras do Cursor ou as instruções do Copilot.') },
    { q: t('Does it cost extra to run? Will it use my AI tokens?', 'Custa mais para rodar? Vai consumir os meus tokens de IA?'), a: t('The subscription is the only fee to bloo. Reviews run on the AI plan you already have — a flat Claude, Cursor, or Copilot plan costs nothing extra, and on usage-based API pricing a full multi-pass review is typically a few cents, since each pass is scoped rather than re-prompting its way to an answer. Exact tokens vary with the model and the size of the PR.', 'A assinatura é a única cobrança da bloo. As revisões rodam no plano de IA que você já tem — um plano fixo de Claude, Cursor ou Copilot não custa nada a mais, e em preço de API por uso uma revisão completa de vários passes fica normalmente em alguns centavos, já que cada passe é focado em vez de ficar re-promptando até chegar a uma resposta. Os tokens exatos variam com o modelo e o tamanho do PR.') },
    { q: t('How do I install it?', 'Como faço para instalar?'), a: t('Paste INSTALL.md into an agent in your project — it installs the tools you pick, fills in your conventions, and offers to add the onboarding checklist for your team.', 'Cole o INSTALL.md em um agente no seu projeto — ele instala as ferramentas escolhidas, preenche suas convenções e oferece para adicionar o checklist de onboarding do seu time.') },
    { q: t('How does the team get it?', 'Como o time recebe o pacote?'), a: t('One person installs and commits the dot-folders. Everyone else pulls your project. Teammates do not need access to the pack GitHub repo.', 'Uma pessoa instala e faz o commit das pastas ocultas. O resto do time só precisa dar pull no projeto. Os colegas não precisam ter acesso ao repositório do pacote no GitHub.') },
    { q: t('What if clone fails?', 'E se o clone falhar?'), a: t('It\u2019s almost always an access problem (invite not accepted), not a wrong URL. The pack URL is fixed for every subscriber: https://github.com/bloo-app/ai-code-review-skill-pack.git.', 'Quase sempre é um problema de acesso (convite não aceito), não uma URL errada. A URL do pacote é fixa para todo assinante: https://github.com/bloo-app/ai-code-review-skill-pack.git.') },
    { q: t('How do I update?', 'Como faço para atualizar?'), a: t('Run /update-bloo-pack in your project, or re-paste INSTALL.md in update mode. Filled conventions in .bloo/conventions.md are preserved; use /refresh-conventions when the repo evolves.', 'Rode /update-bloo-pack no seu projeto, ou cole o INSTALL.md novamente em modo de atualização. As convenções já preenchidas em .bloo/conventions.md são preservadas; use /refresh-conventions quando o repositório evoluir.') },
    { q: t('Can I cancel or switch plans?', 'Posso cancelar ou trocar de plano?'), a: t('Yes — cancel anytime, and you keep access through the end of the period you’ve paid for. You can switch between monthly and annual whenever you like; annual is the same pack at a lower rate, over two months free each year.', 'Sim — cancele quando quiser e você mantém o acesso até o fim do período já pago. Dá para alternar entre mensal e anual quando quiser; o anual é o mesmo pacote por um valor menor, mais de dois meses grátis por ano.') },
    { q: t('License?', 'Licença?'), a: t('For you and your team, for as long as your subscription is active. Don\u2019t redistribute or resell the files.', 'Para você e seu time, enquanto sua assinatura estiver ativa. Não redistribua nem revenda os arquivos.') },
  ];
  return (
    <section style={S.section}>
      <div style={S.container} className="site-container">
        <div style={S.sectionHead}>
          <span style={S.eyebrow}>{t('FAQ', 'PERGUNTAS FREQUENTES')}</span>
          <h2 style={S.h2}>{t('Questions answered.', 'Perguntas respondidas.')}</h2>
        </div>
        <div style={{ maxWidth: 760, margin: '0 auto', borderTop: '1px solid var(--border-subtle)' }}>
          {FAQS.map((f, i) => (
            <FaqItem key={f.q} q={f.q} a={f.a} open={openIdx === i} onToggle={() => setOpenIdx(openIdx === i ? -1 : i)} />
          ))}
        </div>
      </div>
    </section>
  );
}

/* ---- Pricing ---- */
const priceS = {
  grid: { display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 20, maxWidth: 840, margin: '0 auto', alignItems: 'stretch' },
  recWrap: { position: 'relative', display: 'flex' },
  recCard: { width: '100%', borderColor: 'var(--border-brand)', boxShadow: 'var(--shadow-lg)' },
  ribbon: { position: 'absolute', top: 0, left: '50%', transform: 'translate(-50%, -50%)', zIndex: 1 },
  grow: { flex: 1, minHeight: 6 },
  priceWas: { fontFamily: 'var(--font-display)', fontWeight: 500, fontSize: 22, color: 'var(--text-subtle)', textDecoration: 'line-through', textDecorationThickness: '1.5px' },
  includePanel: { maxWidth: 720, margin: 'var(--space-12) auto 0', display: 'flex', flexDirection: 'column', gap: 16, alignItems: 'center', paddingTop: 'var(--space-10)', borderTop: '1px solid var(--border-subtle)' },
};
function Pricing() {
  const { t } = useT();
  const HIGHLIGHTS = t(
    ['Updates included for as long as you subscribe', '40+ files, plain Markdown', '10 specialized review prompts', 'Native integrations for Claude, Cursor & Copilot', 'Checklists + calibration examples'],
    ['Atualizações incluídas enquanto sua assinatura estiver ativa', '40+ arquivos, Markdown puro', '10 prompts de revisão especializados', 'Integrações nativas para Claude, Cursor e Copilot', 'Checklists + exemplos de calibração']
  );
  return (
    <section id="pricing" style={{ ...S.section, ...PackS.band, scrollMarginTop: 80 }}>
      <div style={S.container} className="site-container">
        <div style={S.sectionHead}>
          <span style={S.eyebrow}>{t('PRICING', 'PREÇO')}</span>
          <h2 style={S.h2}>{t('One subscription. No lock-in.', 'Uma assinatura só. Sem dependência forçada.')}</h2>
          <p style={S.sectionSub}>{t('Same pack, same updates on both plans — the annual plan just costs less. Licensed for you and your whole team.', 'O mesmo pacote e as mesmas atualizações nos dois planos — o anual só custa menos. Licenciado para você e todo o seu time.')}</p>
        </div>
        <div style={priceS.grid} className="site-grid-2">
          <Card variant="outline" padding="lg" style={PackS.priceCard}>
            <Badge>{t('STARTER · MONTHLY', 'STARTER · MENSAL')}</Badge>
            <div style={PackS.priceRow}>
              <span style={PackS.priceNum}>$49</span>
              <span style={PackS.priceUnit}>{t('/mo', '/mês')}</span>
            </div>
            <p style={{ ...S.cardBody, flex: 'none' }}>{t('Billed month to month — switch to annual anytime.', 'Cobrado mês a mês — mude para o anual quando quiser.')}</p>
            <div style={priceS.grow} />
            <SubscribeButton plan="monthly" variant="secondary" size="lg" block>{t('Subscribe monthly', 'Assinar mensal')}</SubscribeButton>
            <p style={PackS.fine}>{t('For you and your team. Cancel anytime. Not for redistribution or resale.', 'Para você e seu time. Cancele quando quiser. Não é permitido redistribuir ou revender.')}</p>
          </Card>
          <div style={priceS.recWrap}>
            <div style={priceS.ribbon}><Badge tone="brand">{t('RECOMMENDED', 'RECOMENDADO')}</Badge></div>
            <Card variant="raised" padding="lg" style={{ ...PackS.priceCard, ...priceS.recCard }}>
              <div style={PackS.planBadgeRow}>
                <Badge>{t('STARTER · ANNUAL', 'STARTER · ANUAL')}</Badge>
                <Badge tone="success">{t('Save 20%', 'Economize 20%')}</Badge>
              </div>
              <div style={PackS.priceRow}>
                <span style={priceS.priceWas}>$49</span>
                <span style={PackS.priceNum}>$39</span>
                <span style={PackS.priceUnit}>{t('/mo, billed annually', '/mês, cobrado anualmente')}</span>
              </div>
              <p style={{ ...S.cardBody, flex: 'none' }}>{t('$468 billed once a year — save $120 a year, over two months free vs. paying monthly.', '$468 cobrados uma vez por ano — economize $120 por ano, mais de dois meses grátis vs. o mensal.')}</p>
              <div style={priceS.grow} />
              <SubscribeButton plan="annual" size="lg" block trailingIcon={<IconArrow />}>{t('Subscribe annually', 'Assinar anual')}</SubscribeButton>
              <p style={PackS.fine}>{t('For you and your team. Renews annually — cancel anytime. Not for redistribution or resale.', 'Para você e seu time. Renovação anual — cancele quando quiser. Não é permitido redistribuir ou revender.')}</p>
            </Card>
          </div>
        </div>
        <div style={priceS.includePanel}>
          <span style={PackS.includedLabel}>{t('INCLUDED IN BOTH PLANS', 'INCLUÍDO EM AMBOS OS PLANOS')}</span>
          <ul style={PackS.includedList}>
            {HIGHLIGHTS.map((h) => (
              <li key={h} style={{ display: 'flex', gap: 12, alignItems: 'flex-start', fontSize: 14.5, color: 'var(--text-body)', lineHeight: 1.4 }}>
                <span style={S.checkDot}><Icons.IconCheck size={13} /></span>{h}
              </li>
            ))}
          </ul>
        </div>
      </div>
    </section>
  );
}

/* ---- Final CTA (mailto action, not the site's default "book a call" band) ---- */
function FinalCta() {
  const { t } = useT();
  return (
    <section style={PackS.finalCta}>
      <div style={{ ...S.container, ...PackS.finalCtaInner }} className="site-container">
        <h2 style={{ ...S.h2, color: 'var(--text-onbrand)', maxWidth: 620 }}>{t("Ship cleaner code with the review process you'll actually follow.", 'Entregue código mais limpo com o processo de revisão que você realmente vai seguir.')}</h2>
        <p style={{ fontSize: 17, color: 'rgba(255,255,255,.75)', maxWidth: 520, lineHeight: 1.5, margin: '0 auto' }}>
          {t('Get the AI Code Review Skill Pack — installed and configured in about 2 minutes.', 'Garanta o Pacote de Skills de Revisão de Código com IA — instalado e configurado em cerca de 2 minutos.')}
        </p>
        <div style={{ marginTop: 10 }}>
          <Button as="a" href="#pricing" size="lg" trailingIcon={<IconArrow />}>{t('Get the pack', 'Quero o pacote')}</Button>
        </div>
      </div>
    </section>
  );
}

function ProductAiCodeReviewContent() {
  return (
    <>
      <CheckoutSuccessBanner />
      <Hero />
      <HowItWorks />
      <SampleFinding />
      <WhoItsFor />
      <WhatsIncluded />
      <OutcomesUseCases />
      <ReviewEconomics />
      <TokenCost />
      <AlwaysImproving />
      <Faq />
      <Pricing />
      <FinalCta />
    </>
  );
}

window.Pages = window.Pages || {};
window.Pages['ai-code-review'] = { Content: ProductAiCodeReviewContent, label: 'Product — AI Code Review' };
})();
