Lossless Changelog
product

The Page-Load Flash, and a Team Roster Correction

The logo stopped animating itself into place on every page load — plus a person off the roster, a pronoun fix, and three scripts that had been 404ing in production the whole time.

Michael StatonMusic Editor

Changelog — 2026-08-23_01

Summary

Two unrelated batches shipped together: a roster correction on /the-people, and the fix for the page-load flash that had been affecting all 80 pages of the site.

The flash was never a team-page problem. It lived in Header.astro and the mode script, so it happened everywhere — the team page just made it obvious by being long and image-heavy.

The page-load flash

Root cause — the logo animated into position on every load

Header.astro server-rendered the logo wrapper in the homepage's starting pose:

HTML
<div id="logo-wrapper"
     class="... p-8 ... transition-all duration-300 absolute"
     style="top: 4rem; left: 0;">

A dark #042632 box, 2rem of padding, absolutely positioned 4rem down the page. Then a DOMContentLoaded handler rewrote twelve inline styles on every non-index page to put it back where it belonged. Because the element carried transition-all duration-300, that correction was animated — a dark rounded box visibly sliding up and shrinking, on every single page view. Mobile homepage had it too.

Fixed

  • Which pose applies is now decided at build time from Astro.url.pathname and expressed as CSS, so the correct pose is painted immediately and nothing needs correcting afterward.

  • The resting pose is the default for every page and every viewport. The homepage opts into the tall drop-in pose via a logo-wrapper--index class, scoped to @media (min-width: 1024px).

  • The CSS values are copied exactly from the JavaScript end-states, so the homepage's drop-in and scroll behaviour are unchanged.

  • Deleted the twenty lines of load-time style rewriting. Non-index and mobile now return immediately.

Verified in the build: logo-wrapper--index appears in exactly one of 80 pages.

Contributing cause — the anti-FOUC script was not early

The script in BoilerPlateHTML.astro was commented "Early mode application to avoid FOUC" but sat at the end of <body>. Measured in the built HTML: 136,110 characters of content before it, 1,258 after. The page fully painted in the hardcoded data-mode="dark" before the script ran, so a stored light preference repainted the entire page after paint.

Moved into <head>, immediately after <meta charset>.

Contributing cause — mode applied three times per load

The inline script applied it, the ModeSwitcher constructor applied it again at module load, and a third DOMContentLoaded handler applied it once more. That third call omitted initialLoad, so it defaulted to false and wrote to localStorage — directly contradicting the inline script's own "do not write to localStorage here" comment.

  • Removed the DOMContentLoaded re-application from src/utils/mode-switcher.js.

  • Removed html, body from the transition: var(--transition-smooth, all 0.3s ease) rule in BaseThemeLayout.astro. Transitioning them meant every mode application cross-faded the whole page over 300ms instead of swapping instantly.

Scripts that were 404ing in production

Three script references used raw /src/ paths. Vite serves those in dev, so they worked locally; dist/src does not exist, so they 404'd on the live site. The mode toggle has therefore been dead in production.

FileReferenceResolution
BoilerPlateHTML.astroimport '/src/utils/mode-switcher.js'Converted to a bundled relative import
BaseThemeLayout.astro<script src="/src/utils/bio-modal.js">Removed — PersonCard.astro already ships an identical window.showBio
ModeToggle.astroawait import('/src/utils/mode-switcher.js')Removed; it was a fallback that could never have succeeded

grep '"/src/' across all 80 built pages now returns nothing.

Team / People data updates

Removed

  • Removed one person from the roster, at the client's request:

    • src/content/people/team.json (20 → 19 entries)

    • src/content/people/team-extended.json (21 → 20 entries)

  • Scrubbed the same name from changelog/2026-04-09_01.md and context-v/Updates-for-April-2026.md so it does not surface in search. Git history was deliberately left intact.

  • This also retired the last use of the string TWF Strategy Institute, which had only ever appeared in that one person's role field. Every remaining Institute role now reads TWF Institute Partner.

Corrected

  • Ineeleng Molete — bio was written throughout in she/her; corrected to he/him in both team.json and team-extended.json. He remains TWF Ambassador South Africa.

Notes for whoever touches this next

  • src/content/people/team-extended.json is dead. Nothing imports it; eleven files import team.json. It survived this change only because it was already being edited. Worth deleting so there is one source of truth.

  • Header.astro's logo now depends on Astro.url.pathname at build time. If the homepage ever moves off /, update the isIndexPage check or the logo will render in the wrong pose.

  • The two poses in CSS are ID-anchored (#logo-wrapper.logo-wrapper--index) specifically to outrank the resting pose. Do not weaken those selectors to classes without re-checking specificity.

Verification

  • pnpm build — clean, 80 pages.

  • pnpm exec astro check — 64 errors, unchanged from the pre-change baseline; all pre-existing and unrelated. Hints dropped 202 → 199 from the deletions.

  • Verified structurally against the production build: script placement in <head>, emitted CSS for both logo poses, bundle contents, and absence of /src/ paths.

  • Not visually verified — no browser tooling wired in this repo. The rendered result still wants a human walk-through of /the-people and the homepage.

Parked

Two findings from the build audit were written up rather than fixed:

  • context-v/issues/Issue-of-Empty-Fellowship-Program-Page.md — /our-fellowship-program builds to a zero-byte HTML file.

  • context-v/issues/Issue-of-Slide-Decks-Bypassing-the-Mode-System.md — the two deck layouts declare their own <html> and ignore light/dark entirely.