## Library content externalised — loaded at runtime via sg.*, no longer inlined

- **`library.html` is now a thin renderer, not a 2 MB blob.** The library content —
  `assets/library/library.json` plus one webp per article — lives as vault data and is loaded at
  runtime through the SG bridge (`sg.vfs.readText` / `sg.vfs.read`), which is available both in the
  vault app iframe and on riskmandate.ai, with a relative-path fallback for any other context. The
  built page dropped from ~2.1 MB to ~50 KB.
- **Images lazy-load.** Article data is fetched on load; each infographic is fetched only as its
  card scrolls into view (IntersectionObserver, 300px margin) and turned into a blob URL, cached by
  path. The reading overlay loads the full figure on open. No `data:` URIs anywhere in the output —
  the contract scan and a new smoke assertion both enforce it.
- **Content is now decoupled from the page.** Adding or editing articles means editing
  `assets/library/` — no page rebuild. `build.js` still validates the content as a gate (referential
  integrity of `related`/`theme` + every referenced image present), so bad content fails the build.
- Net vault size is ~2 MB smaller (removed the inlined output and the duplicate `src` assets; the
  webps now live once under `assets/library/`).
