/** * The landing hero artwork. * * This is the supplied illustration, not a drawing of one — see * assets/hero-source.png and scripts/build-hero-images.js, which produces * everything under public/brand/hero-*. Regenerate rather than hand-editing. * * Server-safe by construction: no 'use client', no hooks, no handlers, so it * renders in the RSC pass and never reaches the client bundle. * * TWO CROPS, ONE * ------------------------ * The slot is two different shapes. On desktop the artwork sits behind the * whole panel at roughly 2.1:1 → 2.7:1, with the headline over the empty cream * area the illustration reserves on its left. Below the one-column breakpoint * it becomes a band between 2.6:1 and 4.9:1, under the search rather than * behind it. * * A single file under `object-fit: cover` centre-crops, and at the band's * extreme that slices a strip through the middle of the scene and loses the * schoolhouse — exactly how the previous SVG hero failed on phones. So the * switches crop, not just resolution: `band` is pre-cropped * around the school and is already near 2.6:1, so the narrow band barely * crops it further. * * `object-position` is set in CSS per breakpoint and is load-bearing — see * .heroArt in HomeView.module.css. * * The artwork is decorative: the proposition beside it carries the meaning, so * alt is empty and it is hidden from assistive tech rather than described. */ /* * The panel is not the viewport. `.main` is capped at 1400px with 1.5rem of * padding (1rem under 768px), so the artwork's box is that minus the padding — * describing it as 100vw over-requests by ~48px worth of candidate at every * width, which on a slow connection is a larger file than needed for the LCP * element. */ const SIZES = '(min-width: 1400px) 1352px, (min-width: 769px) calc(100vw - 3rem), calc(100vw - 2rem)'; /** Intrinsic size of the wide crop — the aspect hint that prevents reflow. */ const WIDE_W = 2000; const WIDE_H = 1125; export function HeroIllustration() { return ( {/* Band crop first: is first-match-wins, so the narrow-viewport rules have to precede the unconstrained desktop ones. */} {/* The band's JPEG, and the reason it exists. cannot vary by viewport, so it is always the wide crop. A browser that takes neither AVIF nor WebP would therefore fall through to the desktop frame on a phone and lose the schoolhouse — the exact failure this whole component is arranged to prevent, surviving in the one path nobody looks at. No `type` here, so it matches anywhere the media query does, and it sits after the modern formats so they still win where supported. */} {/* The hero is the largest thing above the fold, so it is almost certainly the LCP element: fetchPriority high, and never lazy. eslint's no-img-element wants next/image, which cannot art-direct between two different crops — that is the whole point of the above. */} {/* eslint-disable-next-line @next/next/no-img-element */} ); }