One header, footer and breadcrumb style on every page

The home page's header and footer now come from the same styles as every other page, the error page has the full header and footer, Privacy and Terms sit beside the copyright line, and every breadcrumb looks the same and clears the header on phones.

A survey of the header, footer and page tops on every route at 1440, 1024, 768 and 390 pixels wide found five layout problems. All five are fixed here.

The header and footer markup was already defined once, in src/lib/site-chrome.ts, but it was styled twice: by site-v18.css for every inner page and by its own copy in site-home-v19.css for the home page. The two copies had drifted until the home page’s header and footer looked like another site. Its navigation was uppercase and edge to edge, its Discord button was square, and its menu collapsed at a different width.

  • site-v18.css is now the only source. tools/derive-chrome-css.mjs takes every header and footer rule from it and produces site-chrome.min.css, which the home page loads after its own stylesheet. npm run minify:assets writes that file alongside the other bundles.
  • The copied header and footer rules were removed from site-home-v19.css.
  • The derived rules keep their original specificity, so earlier, less specific rules cannot win. They also keep the size tokens they read pinned to their inner-page values, because the home stylesheet defines some of the same names differently.
  • The phone menu now opens below 58rem on every page; the script used a different breakpoint on the home page.

The 404 page had no header, no skip link and a reduced footer, so a visitor who followed a dead link lost the site navigation exactly when they needed it. It now has the skip link, the full header with a working phone menu, and the same footer as every other page. The reduced footer variant no longer exists.

The error page’s structured data also gave Sammy’s contact address as contact@akasammythepup.me. It now gives contact@akasammythepuppy.me, like every other page. The release audit checked the address only on canonical pages, so it now also requires every mail link on every built page to use the site’s own domain.

Privacy and Terms moved out of the footer navigation and onto the copyright line, where policy links are looked for. Each page marks its own link as the current page. The copyright wording is unchanged.

The footer navigation also wraps evenly now. Its thirteen links used to leave one or two stranded on a line of their own at most widths, Mello Zone alone on desktop and tablet. They now split seven and six at every width from 642 to 1440 pixels. Phones keep the two-column list.

One breadcrumb style

Breadcrumbs had four different looks. The press, privacy and terms pages used their own press-breadcrumb style, and the media kit and project pages overrode the size, colour and spacing. Article breadcrumbs took the article’s body link colour, and the press page’s link underline showed through.

  • Every breadcrumb now uses the shared inner-page style.
  • The page-specific stylesheets keep only their own spacing below it.
  • Every breadcrumb marks its last item as the current page, which only the press and project pages did before.

Blog and changelog articles started 4rem from the top of the page, which is shorter than the 4.15rem phone header, so their breadcrumbs sat underneath it. Article pages now always start at least the header’s height plus 1.75rem from the top, and desktop spacing is unchanged.

On phones, the Live page moved its portrait above everything else. The breadcrumb, the “Is Sammy live?” heading and its answer started 557 pixels below the header, after a 48vh image. Below 761 pixels the portrait now follows the buttons, in the same order as the page’s markup. The breadcrumb sits 31 pixels below the header, and the heading and the current live status are on the first screen. Tablet and desktop keep the side-by-side layout.

Verification

  • tools/test-site-chrome.mjs no longer exempts the error page:

    • every page, the 404 included, must render the shared header and footer;
    • a new check requires the Privacy and Terms links on the copyright line, with the copyright wording unchanged;
    • another requires every breadcrumb to use the shared class and mark the current page. It fails when the privacy page is given back its old class.
  • tools/test-generated-assets.mjs checks the derived header and footer sheet:

    • it fails if site-chrome.min.css is stale;
    • it fails if a derived rule would no longer reach the home page, or a size token is not pinned.
  • Against npm run preview in headless Chrome, the home page’s header and footer showed no computed-style differences from /about/ across 17 elements at 1440, 1024, 768 and 390 pixels.

  • The same check measured these pages at 1440, 768 and 390 pixels wide:

    • the 404 page;
    • About, Work, Live, Press, Privacy, Terms, Media kit, Projects and a project page;
    • Blog, Changelog and a blog article.

    Every breadcrumb had identical computed styles, and the article breadcrumb sat 27 pixels below the phone header. There was no horizontal overflow. The 404 page’s phone menu opened. The only console messages on the 404 page were its own intended 404 status and an intermittent reset of a third-party analytics sync request.

  • Release checks:

    • npm run test:delivery 198 of 198 and npm run test:worker 85 of 85;
    • npm run test:built 384 of 384, after tools/indexing-surface.json was rewritten deliberately for this entry’s route;
    • the release audit across 45 canonical pages, and npm run check:feeds.
  • npm run test:browser reported 0 failures across 45 routes, and npm run test:a11y 0 failures across 100 checks.