Fecha a meta de LCP ≤ 2,5 s da SPEC §6.6 em todas as páginas, nos dois presets.
Continuação direta do commit anterior: com fontes e marca resolvidas, o elemento
de LCP de toda página no mobile passou a ser a imagem do hero, e o Load Delay de
1,88 s era contenção de banda pura.
## Variantes webp
`ResponsiveImage::generate()` escreve uma variante `.webp` ao lado de cada
variante no formato original, e `x-media.image` a oferece num
`<source type="image/webp">`. O `<img>` continua apontando para o formato
original: o `<source>` é preferência, não substituição, então nada quebra em
quem não decodifica webp, e mídia antiga sem irmãos webp renderiza `<img>` puro
como antes.
O `<picture>` recebe `display: contents` porque os chamadores estilizam o `<img>`
com classes como `h-full w-full object-cover` que resolvem contra o pai grid ou
flex — um wrapper inline quebraria isso.
O nome do arquivo acrescenta a extensão em vez de trocá-la
(`photo-720.jpg.webp`): uploads usam UUID, então colisão já era improvável, mas
`photo-720.webp` colidiria com a variante webp de um `photo.png`.
## sizes que descreve a realidade
Nenhuma imagem do site ocupa a viewport inteira — todas ficam dentro de
`container-amare`, que reserva 1,5rem de padding de cada lado. Declarar `100vw`
fazia uma viewport de 412 px em DPR 1,75 pedir 721 px e pular para a variante de
960 para desenhar uma caixa de 637 px. Errar por um pixel custava um terço a mais
de bytes em toda página.
Com `calc(100vw - 3rem)` a home passa a usar a variante de 720: 74 KiB, contra
143 KiB no início da investigação. Foi também por isso que 720 entrou em
`ResponsiveImage::WIDTHS` — sem ela o salto de 480 para 960 é grande demais para
a viewport mobile mais comum.
## Efeito medido
Mobile, mediana de 3 execuções: home 3,39 → 2,49 s; portfolio-detalhe
3,01 → 2,18 s; servicos 2,63 → 2,03 s; portfolio 1,58 s; sobre 1,58 s;
contato 1,50 s. Desktop no máximo 0,65 s. Peso total da home 798 → 347 KiB.
Contra o início da investigação (`2e43fde`): home 4,58 → 2,49 s com score de
performance 83 → 98.
A home passa **em cima da linha** — a pior das três execuções deu 2,57 s. Está
documentado como aprovada por margem, não com folga, e os levers restantes estão
listados em docs/evidence/lighthouse/README.md em ordem de custo.
Os 16 baselines visuais não mudaram: nenhum seeder gera variantes e
`media:generate-variants` não roda no runner visual, então naquele ambiente
`availableVariants()` volta vazio e o componente renderiza `<img>` puro. A
cobertura do caminho com variantes fica em MediaImageComponentTest e
ResponsiveImageTest, não nos baselines — anotado como lacuna conhecida.
Co-Authored-By: Claude noreply@anthropic.com
AI-Assisted: yes
AI-Tool: claude-code
Replace tiny JPEG stubs with per-slot Unsplash editorial placeholders,
align public type scale to DESIGN.md display/headline tokens, add
final-cta on all subpages, about_image_path on site settings, and harden
visual regression with solid-color VisualContentSeeder fixtures.
* fix: prevent long strings from overflowing public layout
* fix: fall back to default hero copy and tighten hero line-height
* fix: skip blank testimonials and guard empty portfolio metadata
* feat: add branded 419, 429 and 503 error pages
* fix: reset submit state on bfcache restore, swap label while sending, trap mobile menu focus
* chore: track hardening task status
* fix: restore contact submit state after bfcache
* fix: allow contact links to wrap long unbroken strings
* feat: add Dossiê vivo motion to the public site
Introduce a focal Home opening, chapter index, and restrained continuity
reveals while keeping reduced-motion and visual baselines intact.
Co-authored-by: Cursor <cursoragent@cursor.com>
* test: refresh visual baselines from CI Ubuntu screenshots
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
* feat: recreate public frontend with Heritage Editorial identity
Replace placeholder visual system with EB Garamond/olive tokens, brand assets, editorial home narrative, São Paulo settings, real testimonials, and regenerated visual baselines.
Co-authored-by: Cursor <cursoragent@cursor.com>
* docs: archive recreate-public-frontend and sync Heritage Editorial specs
Merge delta requirements into main OpenSpec capabilities and move the completed change into the dated archive.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
* feat: ship public site with SEO and visuals
Publish CMS content on public routes with responsive media,
accessibility checks, and deterministic visual baselines.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix: make browser visual CI deterministic for media
Mount host public storage into FrankenPHP so seeded fixtures are served,
and replace PNG-as-JPG fixtures with real JPEGs so Chromium can render them.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix: serve public media on same-origin storage paths
Pest Browser hosts on 127.0.0.1:port while Storage::url used
http://localhost, so screenshots captured broken images. Use relative
/storage URLs for media and absolutize only OG tags via url().
Co-authored-by: Cursor <cursoragent@cursor.com>
* test: refresh visual baselines from CI Ubuntu screenshots
Media now loads on same-origin /storage paths, so baselines must
capture the rendered fixtures. Use full-page snapshots from the CI
runner to keep Pest's exact snapshot match stable across environments.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>