# Page Tune Up

> Auditoria tecnica e otimizacao de paginas HTML/landing pages focando em performance (Core Web Vitals), SEO, acessibilidade basica, mobile e boas praticas — PRESERVANDO o design visual existente. Nao altera layout, cores, fontes, tipografia ou estrutura. Identifica problemas, prioriza por impacto/ esforco e aplica quick wins seguros automaticamente. Use quando o usuario pedir otimizar pagina, melhorar performance, auditar SEO, tunar pagina, lighthouse, Core Web Vitals, PageSpeed, accessibility audit, mobile audit, page speed, web vitals, ou aplicar boas praticas sem mexer no design. Triggers: "otimizar pagina", "tunar pagina", "page tune-up", "performance", "lighthouse", "core web vitals", "web vitals", "page speed", "auditar pagina", "SEO audit", "audit pagina", "boas praticas web", "a11y", "accessibility", "lcp", "cls", "inp".

- Skill: `clfigueiredo/page-tune-up` (Agent Skill)
- Install (CLI): `npx skillmds@latest add clfigueiredo/page-tune-up`
- Raw SKILL.md: https://api.skillmd.com/api/skills/clfigueiredo/page-tune-up/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Marketing & Growth
- Author: clfigueiredo (https://skillmd.com/u/clfigueiredo)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/clfigueiredo/page-tune-up

---


# page-tune-up

Audita uma pagina HTML/landing page e aplica otimizacoes tecnicas
(performance, SEO, a11y, boas praticas) **preservando o design visual**.
Sem alterar layout, cores, fontes, tipografia ou estrutura — so o que faz
a pagina rodar melhor, ser melhor indexada e ser mais acessivel.

## Princípio fundamental

**O design fica intocado.** A skill identifica problemas TECNICOS e propoe
fixes que melhoram performance/SEO/a11y sem alterar:

- Layout (grid, flex, posicionamento)
- Paleta de cores
- Tipografia (familia, peso, escala)
- Componentes visuais
- Conteudo textual original

Se um fix exige mudanca visual significativa, **reporta mas nao aplica
sem permissao explicita**.

## Processo

### 1. Inventário da página

Ler o(s) HTML alvo e identificar:

- Tipo de pagina (landing, blog, dashboard, e-commerce, formulario)
- Frameworks/libs externas carregadas
- Imagens (formato, dimensoes, atributos, peso)
- Fontes (Google Fonts, locais, custom, quantos pesos/estilos)
- Scripts (sincronos, async, defer, externos, inline)
- Meta tags existentes (title, description, OG, Twitter, viewport)
- Structured data (JSON-LD)
- Atributos de a11y (alt, aria-*, role, label)
- CSS (inline, external, render-blocking, criticos)
- Forms (campos, labels, inputmode, validacao)

### 2. Auditoria (8 áreas)

Avaliar a pagina nestas areas, gerando lista de problemas priorizada
por **impacto vs esforco**:

#### A. Performance / Core Web Vitals

**LCP (Largest Contentful Paint) — alvo <2.5s**
- [ ] Imagem hero/LCP element tem `loading="eager"` + `fetchpriority="high"`
- [ ] Imagem hero tem `<link rel="preload" as="image">` no head
- [ ] Imagem hero esta em formato moderno (WebP/AVIF)
- [ ] Imagem hero tem `width` e `height` definidos (evita CLS)
- [ ] Hero nao depende de fonte web critica nao-preloaded
- [ ] CSS critico inline no head

**INP (Interaction to Next Paint) — alvo <200ms**
- [ ] Sem scripts pesados rodando no main thread no load
- [ ] Trackers (GA, Pixel, Hotjar) carregam via `requestIdleCallback` ou async
- [ ] Sem libs gigantes (jQuery, lodash, moment.js) — preferir vanilla
- [ ] Event handlers leves no main thread
- [ ] Listeners passivos em scroll/touch (`{passive: true}`)

**CLS (Cumulative Layout Shift) — alvo <0.1**
- [ ] Todas as imagens tem atributos `width` e `height`
- [ ] Iframes tem `width`/`height`
- [ ] Fontes web usam `font-display: swap` (e size-adjust se possivel)
- [ ] Anuncios/embeds com altura reservada (aspect-ratio)
- [ ] Sem injection de conteudo acima do fold via JS apos load

**Outras métricas**
- [ ] Page weight total <2MB
- [ ] DOM nodes <1500
- [ ] CSS/JS minificados em producao
- [ ] Gzip/Brotli compressao ativada
- [ ] HTTP/2 ou HTTP/3 ativado

#### B. SEO técnico

**Meta tags essenciais**
- [ ] `<title>` 50-60 chars, unico, com keyword principal
- [ ] `<meta name="description">` 150-160 chars
- [ ] `<meta name="viewport" content="width=device-width, initial-scale=1">`
- [ ] `<link rel="canonical">` apontando pra URL canonica
- [ ] `<html lang="pt-BR">` (ou idioma da pagina)
- [ ] `<meta charset="UTF-8">`

**Open Graph + Twitter Cards**
- [ ] `og:title`, `og:description`, `og:image` (1200x630), `og:url`, `og:type`
- [ ] `twitter:card` (summary_large_image), `twitter:title`, `twitter:description`
- [ ] Imagem OG existe, tem dimensoes corretas e abre publicamente

**Structured data (JSON-LD)**
- [ ] Schema apropriado pro tipo de pagina (Article, Product, Event,
      Organization, LocalBusiness, FAQPage)
- [ ] Marcado dentro de `<script type="application/ld+json">`
- [ ] Validavel em https://search.google.com/test/rich-results

**Hierarquia de heading**
- [ ] Exatamente 1 `<h1>` na pagina
- [ ] H2/H3 em ordem logica (nao pular niveis)
- [ ] Headings descritivos, com keywords naturais

**URLs e indexacao**
- [ ] URL canonica curta, com keywords, sem ID/timestamps
- [ ] HTTPS obrigatorio
- [ ] Pagina nao tem `noindex` indevido (a menos que intencional)
- [ ] robots.txt acessivel
- [ ] sitemap.xml referenciado em robots.txt

#### C. Imagens

- [ ] Formato moderno (WebP/AVIF) com fallback se necessario
- [ ] Comprimidas (~80% qualidade pra fotos; lossless pra logos/icones)
- [ ] Dimensoes adequadas (nao servir 2000px pra container de 600px)
- [ ] `loading="lazy"` em tudo abaixo do fold
- [ ] `loading="eager"` + `fetchpriority="high"` so na hero/LCP
- [ ] `alt=""` em decorativas, `alt="descricao real"` em informativas
- [ ] `width` e `height` explicitos (evita CLS)
- [ ] `decoding="async"` em nao-criticas
- [ ] `srcset` + `sizes` em imagens responsivas
- [ ] Logos SVG quando possivel

#### D. Fontes

- [ ] Preconnect pro provedor de fontes:
      `<link rel="preconnect" href="https://fonts.googleapis.com">`
      `<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>`
- [ ] `font-display: swap` em todas as fontes web
- [ ] Apenas pesos/estilos realmente usados (cada peso extra = +20-50KB)
- [ ] Preload da fonte critica do hero (se aplicavel):
      `<link rel="preload" as="font" type="font/woff2" crossorigin>`
- [ ] Fontes locais via `@font-face` com `font-display: swap` e woff2
- [ ] Maximo 2-3 familias na pagina (pra nao explodir o budget)

#### E. Scripts

- [ ] Trackers/analytics carregados via `requestIdleCallback` ou no fim do body
- [ ] Scripts externos com `async` ou `defer`
- [ ] Sem `document.write()`
- [ ] Sem libs pesadas pra tarefas simples (querySelector resolve sem jQuery)
- [ ] Listeners passivos em scroll/touch
- [ ] Sem console.log/error em producao
- [ ] Sem comentarios HTML revelando stack/segredos

#### F. Acessibilidade básica

- [ ] Imagens informativas com `alt` descritivo
- [ ] Botoes com texto OU `aria-label`
- [ ] Links com texto descritivo (nao "clique aqui")
- [ ] Forms com `<label for="...">` associado a `<input id="...">`
- [ ] Contraste de cor ≥4.5:1 pra texto normal, ≥3:1 pra texto grande/UI
- [ ] Foco visivel em elementos interativos (`:focus-visible`)
- [ ] Ordem de tab logica (sem `tabindex` artificial)
- [ ] Sem texto so como imagem
- [ ] `<html lang>` definido
- [ ] Skip-to-content link em paginas longas
- [ ] Sem `outline: none` sem substituto visivel

#### G. Mobile

- [ ] Tap targets ≥48x48px (botoes, links, inputs)
- [ ] Espacamento entre touch targets ≥8px
- [ ] Font size base ≥16px (sem zoom forcado no iOS)
- [ ] Sem horizontal scroll em qualquer breakpoint
- [ ] Forms com `inputmode` correto (`email`, `tel`, `numeric`, `decimal`)
- [ ] Telefones em `<a href="tel:...">`
- [ ] Emails em `<a href="mailto:...">`
- [ ] Imagens responsivas (srcset ou max-width: 100%)
- [ ] Sticky bars nao cobrem CTA principal
- [ ] Sem `user-scalable=no` na viewport (a11y)
- [ ] Usa `min-h-[100dvh]` em vez de `100vh` em heros full-height

#### H. Boas práticas técnicas

- [ ] HTTPS forcado (com redirect 301 do http)
- [ ] Headers de seguranca:
      `X-Content-Type-Options: nosniff`
      `Referrer-Policy: strict-origin-when-cross-origin`
      `X-Frame-Options: SAMEORIGIN` (ou CSP frame-ancestors)
- [ ] Cookies com `Secure`, `HttpOnly`, `SameSite=Lax`
- [ ] `.htaccess` (Apache) ou config Nginx com cache de assets estaticos
- [ ] Compressao Gzip/Brotli ativada
- [ ] favicon presente (preferencialmente SVG + .ico fallback)
- [ ] 404 page customizada
- [ ] Sem mixed content (HTTP em pagina HTTPS)

### 3. Reportar e priorizar

Apresenta o report assim:

```markdown
## Auditoria: <pagina-url>

**Health Score**: XX/100 (estimado)
**Page weight atual**: X.X MB
**LCP estimado**: X.Xs

### CRITICOS (impacto alto, esforco baixo)
1. [PERF] Hero image sem preload — LCP -0.8s estimado
2. [SEO] Falta <meta description>
3. [A11Y] 3 imagens sem alt
4. [MOBILE] Tap targets do menu <48px

### QUICK WINS (aplicar agora?)
- Adicionar `loading="lazy"` em N imagens abaixo do fold
- Adicionar `font-display: swap` em N fontes
- Mover script do GA pra requestIdleCallback
- Adicionar `width`/`height` em N imagens
- Adicionar `alt` em N imagens decorativas

### IMPORTANTES (revisar)
- Bundle JS de XYZ KB pode ser reduzido (sugestao: remover libX)
- 3 scripts third-party bloqueando render
- Imagens em PNG que poderiam ser WebP (-XX% peso)

### COSMETICOS (nice-to-have)
- Adicionar JSON-LD Organization
- Adicionar canonical em N paginas
- Reservar altura em embeds com aspect-ratio

### O QUE FICOU INTOCADO
- Layout, cores, fontes (preservado por principio)
- Estrutura HTML
- Conteudo textual
```

### 4. Aplicar fixes seguros (com confirmação)

Aplicar AUTOMATICAMENTE os quick wins que NAO mudam design:

**Sempre seguros (aplicar direto, reportar no diff):**
- Adicionar atributos a tags: `loading`, `decoding`, `fetchpriority`,
  `width`, `height`, `srcset`, `sizes`
- Adicionar/atualizar meta tags (title, description, OG, Twitter, canonical)
- Adicionar `lang` no `<html>`
- Adicionar `<meta charset>` e `<meta viewport>` se faltam
- Adicionar `preconnect`/`preload`
- Adicionar `alt` descritivo (gerar texto a partir do contexto/contents)
- Adicionar `aria-label` em botoes sem texto visivel
- Mover scripts pra fim do body OU envolver em requestIdleCallback
- Adicionar `async`/`defer` em scripts externos
- Adicionar `font-display: swap` em @font-face
- Adicionar `<link rel="canonical">`
- Adicionar OG/Twitter tags faltando
- Adicionar `tel:` em telefones e `mailto:` em emails
- Adicionar `inputmode` em inputs de form
- Adicionar headers de seguranca em .htaccess/nginx
- Adicionar regras de cache em .htaccess/nginx

**Confirmar antes (risco baixo, pode afetar comportamento):**
- Trocar formato de imagens (PNG → WebP)
- Mover CSS pra inline (above-fold critico)
- Adicionar JSON-LD
- Adicionar lazy loading em imagens dentro de slider/carrossel
- Remover pesos/estilos de fonte nao usados
- Minificar CSS/JS inline

**NUNCA aplicar sem permissao explicita:**
- Mudar fontes (familia, peso, estilo)
- Mudar cores
- Mudar grid/layout/spacing
- Mudar componentes visuais
- Remover libs externas que tem dependencia
- Reescrever JS existente
- Mudar wording de copy/headlines

## Snippets de implementação

### Preconnect + preload pra hero
```html
<!-- no <head>, antes do CSS -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="dns-prefetch" href="https://www.google-analytics.com">
<link rel="preload" as="image" href="hero.webp" media="(min-width: 901px)">
<link rel="preload" as="image" href="hero-mobile.webp" media="(max-width: 900px)">
```

### Meta tags SEO completas
```html
<title>Titulo da pagina — 50-60 chars com keyword</title>
<meta name="description" content="Descricao concisa 150-160 chars que faz o usuario clicar no resultado.">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="canonical" href="https://example.com/pagina">
<link rel="icon" href="/favicon.ico">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">

<!-- OG -->
<meta property="og:type" content="website">
<meta property="og:title" content="Titulo">
<meta property="og:description" content="Descricao">
<meta property="og:image" content="https://example.com/og-image.jpg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:url" content="https://example.com/pagina">
<meta property="og:site_name" content="Nome do Site">
<meta property="og:locale" content="pt_BR">

<!-- Twitter -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Titulo">
<meta name="twitter:description" content="Descricao">
<meta name="twitter:image" content="https://example.com/og-image.jpg">
```

### JSON-LD Organization
```html
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Organization",
  "name": "Nome",
  "url": "https://example.com",
  "logo": "https://example.com/logo.png",
  "sameAs": [
    "https://instagram.com/...",
    "https://youtube.com/@..."
  ],
  "contactPoint": {
    "@type": "ContactPoint",
    "telephone": "+55-11-9999-9999",
    "contactType": "Customer Service",
    "areaServed": "BR"
  }
}
</script>
```

### JSON-LD Event (pra landing de evento)
```html
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Event",
  "name": "Nome do evento",
  "startDate": "2026-05-23T14:00-03:00",
  "eventAttendanceMode": "https://schema.org/OnlineEventAttendanceMode",
  "eventStatus": "https://schema.org/EventScheduled",
  "location": {
    "@type": "VirtualLocation",
    "url": "https://zoom.us/..."
  },
  "organizer": {
    "@type": "Person",
    "name": "Cristiano Figueiredo"
  },
  "offers": {
    "@type": "Offer",
    "price": "39.90",
    "priceCurrency": "BRL",
    "url": "https://pay.hotmart.com/..."
  }
}
</script>
```

### Tracker via requestIdleCallback
```html
<script>
(function() {
  function loadTracker() {
    var s = document.createElement('script');
    s.src = 'https://example.com/tracker.js';
    s.async = true;
    document.head.appendChild(s);
  }
  if ('requestIdleCallback' in window) {
    requestIdleCallback(loadTracker, { timeout: 3000 });
  } else {
    setTimeout(loadTracker, 1500);
  }
})();
</script>
```

### Image responsiva moderna
```html
<picture>
  <source type="image/avif" srcset="img.avif" />
  <source type="image/webp" srcset="img.webp" />
  <img src="img.jpg"
       alt="descricao real e informativa"
       width="800" height="600"
       loading="lazy"
       decoding="async" />
</picture>
```

### Hero image (LCP element)
```html
<img src="hero.webp"
     alt="descricao do hero"
     width="1200" height="800"
     loading="eager"
     fetchpriority="high"
     decoding="sync" />
```

### .htaccess otimizado (Apache)
```apache
# Forca UTF-8
AddDefaultCharset UTF-8

# Index
DirectoryIndex index.html index.php

# Cache de assets estaticos
<IfModule mod_expires.c>
  ExpiresActive On
  ExpiresByType text/css "access plus 7 days"
  ExpiresByType application/javascript "access plus 7 days"
  ExpiresByType image/png "access plus 30 days"
  ExpiresByType image/jpeg "access plus 30 days"
  ExpiresByType image/webp "access plus 30 days"
  ExpiresByType image/avif "access plus 30 days"
  ExpiresByType image/svg+xml "access plus 30 days"
  ExpiresByType font/woff2 "access plus 1 year"
</IfModule>

# Compressao Gzip
<IfModule mod_deflate.c>
  AddOutputFilterByType DEFLATE text/html text/css application/javascript application/json image/svg+xml
</IfModule>

# Headers de seguranca
<IfModule mod_headers.c>
  Header set X-Content-Type-Options "nosniff"
  Header set Referrer-Policy "strict-origin-when-cross-origin"
  Header set X-Frame-Options "SAMEORIGIN"
  Header set Permissions-Policy "geolocation=(), microphone=(), camera=()"
</IfModule>

# Forca HTTPS
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
```

### Skip-to-content (a11y em paginas longas)
```html
<a href="#main" class="skip-link">Pular pro conteudo</a>
<style>
.skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  background: #000;
  color: #fff;
  padding: 8px;
  z-index: 100;
}
.skip-link:focus { top: 0; }
</style>
```

### Tap targets (a11y mobile)
```css
button, a, input[type="checkbox"], input[type="radio"] {
  min-height: 48px;
  min-width: 48px;
}
nav a + a { margin-left: 8px; }
```

### Performance — animacoes corretas
```css
/* CORRETO: anima transform e opacity (GPU) */
.btn:hover { transform: translate(-2px, -2px); opacity: 0.9; }
.btn { transition: transform 0.2s ease-out, opacity 0.2s; }

/* ERRADO: anima top/left/width/height (forca layout/paint) */
/* .btn:hover { top: -2px; width: 200px; } */
```

### Font loading otimizado
```html
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap"
      rel="stylesheet">
```

```css
/* fonte local */
@font-face {
  font-family: 'CustomFont';
  src: url('/fonts/custom.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
```

## Como medir antes/depois

### Antes de tocar na pagina
1. Rodar **Lighthouse** no DevTools (Mobile + Desktop). Anotar:
   - Performance score
   - LCP, FID/INP, CLS, FCP, TTI, TBT
   - Acessibilidade score
   - SEO score
   - Best Practices score
2. Rodar **PageSpeed Insights**: https://pagespeed.web.dev/
3. Rodar **Mobile-Friendly Test**: https://search.google.com/test/mobile-friendly
4. Rodar **Rich Results Test**: https://search.google.com/test/rich-results

### Depois das mudancas
- Repetir os mesmos testes
- Reportar diff: "LCP 3.2s → 1.9s | Score 64 → 89"
- Se algo regrediu, rollback

## Princípios duros

### NUNCA fazer
- Mudar cores, fontes, layout ou tipografia sem permissao explicita
- Adicionar dependencias JS pesadas pra "otimizar" (ironico)
- Remover funcionalidade que ja funciona
- Aplicar mudancas que quebram o JS existente
- Otimizar sem medir antes/depois
- Adicionar Tailwind/framework em pagina vanilla
- Usar emojis em codigo HTML (alt text, comentarios)
- Inflar a pagina com structured data demais

### SEMPRE fazer
- Medir antes (Lighthouse/PageSpeed) e depois
- Reportar metricas concretas: "LCP era 3.2s, ficou 1.9s"
- Priorizar por impacto/esforco (ROI)
- Preservar funcionalidade JS existente
- Manter o design intacto a menos que liberado
- Aplicar so mudancas que cabem no que ja existe na pagina
- Conferir mobile + desktop separadamente
- Documentar o que NAO foi tocado no report

## Checklist de saída

Antes de fechar a auditoria, ter rodado:
- [ ] Inventario completo
- [ ] Auditoria nas 8 areas (A-H)
- [ ] Report priorizado entregue ao usuario
- [ ] Quick wins aplicados (com confirmacao do usuario)
- [ ] Diff resumido das mudancas
- [ ] Sugestoes de medicao pra validar (PageSpeed + Lighthouse)
- [ ] Lista do que NAO foi tocado e por que
- [ ] Backup ou git commit antes (pra rollback se necessario)

## Casos avancados — quando o quick win nao basta

Quando o report do PageSpeed/Lighthouse mostra que o gargalo principal é
**Google Fonts bloqueando render** ou o **LCP tá em fonte web critica**, os
quick wins não resolvem. Aqui vai o playbook avançado, em ordem de impacto.

### A. Self-hosting de fontes Google (impacto: -1500 a -2000ms LCP)

**Quando aplicar**: Lighthouse diz "Renderizar solicitacoes de bloqueio" e
aponta `fonts.googleapis.com/css2`.

**Por que funciona**: a cadeia critica externa some. Browser nao precisa
resolver DNS de `fonts.googleapis.com`, baixar CSS de la, depois resolver
DNS de `fonts.gstatic.com`, depois baixar woff2. Tudo vem do mesmo
servidor que entregou o HTML.

**Como fazer:**

1. Baixar os woff2 do Google Fonts CDN com User-Agent Chrome moderno
   (garante woff2 ao inves de woff/eot)

```python
import urllib.request, re
from pathlib import Path

UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '\
     '(KHTML, like Gecko) Chrome/120 Safari/537.36'
CSS_URL = 'https://fonts.googleapis.com/css2?family=Bowlby+One:wght@400&display=swap'

req = urllib.request.Request(CSS_URL, headers={'User-Agent': UA})
css = urllib.request.urlopen(req).read().decode('utf-8')

# Extrair URLs woff2
for match in re.finditer(r"url\((https://[^)]+\.woff2)\)", css):
    woff_url = match.group(1)
    # Baixar e salvar local
    data = urllib.request.urlopen(
        urllib.request.Request(woff_url, headers={'User-Agent': UA})
    ).read()
    Path('fonts/' + woff_url.split('/')[-1]).write_bytes(data)
```

2. Subset Latin: o Google Fonts entrega 1 woff2 por bloco unicode-range
   (latin, latin-ext, vietnamese, cyrillic, etc). Para portugues-BR voce
   so precisa do **Latin basico (U+0000-00FF)** — cobre todos os acentos
   (ã, õ, ç, á, é, í, ó, ú, ê, ô, ü). Pode jogar fora os outros subsets.

   **Economia**: 30-40% do peso total das fontes.

3. Substituir o `<link>` do Google Fonts por `<style>` inline com
   `@font-face` apontando pros arquivos locais:

```html
<style>
@font-face{font-family:'Bowlby One';font-style:normal;font-weight:400;font-display:swap;src:url('fonts/bowlby-one-400-normal.woff2') format('woff2')}
@font-face{font-family:'DM Sans';font-style:normal;font-weight:400;font-display:swap;src:url('fonts/dm-sans-400-normal.woff2') format('woff2')}
</style>
```

4. Preload das fontes criticas (a do LCP element + a do body):

```html
<link rel="preload" href="fonts/bowlby-one-400-normal.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="fonts/dm-sans-400-normal.woff2" as="font" type="font/woff2" crossorigin>
```

   **Importante**: o `crossorigin` é obrigatorio mesmo same-origin, senao
   o browser baixa a fonte duas vezes (uma pelo preload, outra pelo CSS).

5. Cache `immutable` no `.htaccess` pra fontes:

```apache
<IfModule mod_headers.c>
  <FilesMatch "\.woff2$">
    Header set Cache-Control "public, max-age=31536000, immutable"
  </FilesMatch>
</IfModule>
```

### B. Cortar pesos de fonte raramente usados

**Quando aplicar**: voce tem 6+ pesos da mesma familia mas so 2-3 sao
realmente visiveis above-the-fold.

**Como diagnosticar**:

```bash
grep -n "font-weight:" pagina.html
```

Conte ocorrencias de cada peso. Pesos 100, 200, 300 (light/thin) e 900
(black) sao frequentemente decorativos.

**Como substituir**: troca peso 900 por 800, ou 200 por 300 no CSS.
Diferença visual quase imperceptivel, economia de 30-40KB por peso
removido.

### C. Eliminar uma familia de fonte inteira

**Quando aplicar**: uma familia (ex: Caveat handwritten) e usada em apenas
1-3 lugares da pagina.

**Como substituir sem perder o efeito visual**:

| Familia original | Substituto sem custo |
|---|---|
| Caveat (handwritten) | DM Sans italic 600 |
| Playfair Display | Anton, Bowlby One, ou outra serif ja carregada |
| Quicksand (round) | DM Sans 500/600 |
| Pacifico (script) | DM Sans italic 600 |

Economia: 50-80KB por familia removida (incluindo todos os pesos dela).

### D. Truque "media=print onload" (alternativa sem self-host)

**Quando aplicar**: voce nao quer/pode hospedar as fontes localmente
(ex: deploy em GitHub Pages sem build step).

**Como**: carregar o CSS do Google Fonts como `media="print"` (nao
bloqueia render) e trocar pra `media="all"` no onload.

```html
<link rel="preload" as="style" href="https://fonts.googleapis.com/css2?...">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?..."
      media="print" onload="this.media='all'">
<noscript>
  <link rel="stylesheet" href="https://fonts.googleapis.com/css2?...">
</noscript>
```

**Ganho**: -500 a -1000ms render-blocking. Menos efetivo que self-host
mas zero infra adicional.

### E. Otimizar imagens servidas em tamanhos maiores que o display

**Quando aplicar**: Lighthouse diz "Melhorar a entrega de imagens" e
mostra que voce serve 1200px pra container de 600px.

**Como** (sem ferramenta de build):

```python
from PIL import Image
from pathlib import Path

TARGET_W = 800  # 2x retina pra container de ~400px

for f in Path('img').glob('*.webp'):
    img = Image.open(f)
    if img.size[0] > TARGET_W:
        ratio = TARGET_W / img.size[0]
        new_h = int(img.size[1] * ratio)
        img.resize((TARGET_W, new_h), Image.LANCZOS).save(
            f, format='WEBP', quality=82, method=6
        )
```

**Sempre fazer backup do original antes** (`img/_original/`).

**Lembrar**: depois de redimensionar, atualizar o `width=` e `height=`
no HTML pra refletir as novas dimensoes (mantem o aspect ratio correto
e evita CLS).

### F. Mover trackers pra requestIdleCallback

**Quando aplicar**: Lighthouse mostra `fbevents.js`, Google Analytics,
Hotjar, ou outro script third-party no caminho critico.

**Padrao seguro pro Meta Pixel** (mantem PageView event sem perder dados):

```html
<!-- HEAD: stub que captura PageView em queue -->
<script>
!function(f,b,e,v,n,t,s){
  if(f.fbq)return;
  n=f.fbq=function(){n.callMethod?n.callMethod.apply(n,arguments):n.queue.push(arguments)};
  if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];
}(window,document,'script','https://connect.facebook.net/en_US/fbevents.js');
fbq('init','SEU_PIXEL_ID');
fbq('track','PageView');
</script>
```

```html
<!-- FIM DO BODY: carrega o script real via idle callback -->
<script>
(function(){
  function loadPixel(){
    var t=document.createElement('script');
    t.async=true;
    t.src='https://connect.facebook.net/en_US/fbevents.js';
    document.head.appendChild(t);
  }
  if('requestIdleCallback' in window){
    requestIdleCallback(loadPixel,{timeout:3000});
  } else {
    setTimeout(loadPixel,1500);
  }
})();
</script>
```

**Resultado**: TBT cai ~50-100ms. Eventos do Pixel ficam em queue até o
script real carregar e processar.

### G. Limites duros que voce nao consegue passar

Quando todos os truques acima foram aplicados e o score ainda nao chegou
em 90+, normalmente é porque:

- **Conteudo demais**: 10+ sections na pagina inicial. Mesmo com
  `content-visibility:auto`, o DOM pesa. Solucao real: reduzir sections.
- **Fontes display pesadas**: Bowlby One, Anton, Pacifico — fontes
  display sao naturalmente maiores que sans-serif normais. Trade-off
  entre identidade visual e velocidade.
- **Third-party fora do controle**: Meta Pixel, Google Analytics,
  Hotjar, ipapi — você não consegue otimizar. Único caminho real:
  remover ou trocar por CAPI server-side (Pixel).

**Reporte isso ao usuario com transparencia**. Score 70-80 pode ser
o teto razoavel pra uma landing comic/colorida com analytics third-party.

## Quando usar OUTRAS skills no lugar

Esta skill NAO faz:
- Redesign visual (use `comic-page-redesign`, `redesign-existing` ou
  `impeccable-frontend`)
- Reescrita de copy (use `copywriting`)
- A/B test design (use `ads-test`)
- Geracao de imagens (use `ads-generate` ou `comic-page-redesign`)
- Auditoria de campanhas de anuncios (use `ads-audit`)

Esta skill faz: **otimizacao tecnica preservando o que ja existe**.

