iOS WebKit silently degrades position: sticky to static on direct
flex/grid children of <body>, so the sticky nav was breaking on
mobile. Wrapping everything below the nav in a .page-shell flex
column keeps the sticky-footer math out of body { } and restores
sticky behaviour across browsers. The essay-frontmatter hoisted in
the Marks II commit becomes a body-level sibling of .page-shell so
its monogram and epistemic-figure columns can span viewport width.
* templates/default.html wraps $body$ + footer in .page-shell.
* static/css/layout.css moves the flex-column + min-height math from
body to .page-shell; the body > header rule now excludes
.essay-frontmatter so the essay header does not inherit nav chrome
(sticky, nav-bg, border-bottom).
* static/css/base.css drops the html/body overflow-x: clip — the
page-shell wrapper handles horizontal containment and clipping at
the viewport level was interfering with position: sticky.
* static/css/reading.css updates its #markdownBody centering selector
to match .page-shell > #markdownBody.
* static/css/components.css makes the TOC outline scrollable when
it overflows: bounded max-height tied to the sticky budget plus a
thin themed scrollbar, with overflow: hidden preserved for the
collapse transition.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Preserve external works the site cites against link rot, host them at
permanent /archive/<slug>/ URLs in site chrome, and treat them as
first-class citizens of the backlinks and similar-pages indexes.
Curated, not crawled: the author adds one line to archive/manifest.yaml
and the build fetches, hashes, snapshots, and indexes the work.
* archive/manifest.yaml + tools/archive.py (fetch / refresh / wayback /
check / gc) — PDFs downloaded directly, HTML pages snapshotted with a
vendored monolith (tools/bin/monolith @ 2.10.1) into a single
self-contained file with the archive CSP and a noarchive robots meta
injected. Per-entry PROVENANCE.json committed; gitignored .txt
sidecars regenerated from the artifact's SHA-256.
* build/Archive.hs + build/ArchiveIndex.hs + build/Filters/Archive.hs
— Hakyll rules for /archive/ and /archive/<slug>/, a body Pandoc
filter that appends an archive affordance to live citations and
flips dead ones to the local copy on archive.py check's asymmetric
hysteresis (rotted needs 3 fails over >= 14 days; one ok recovers).
* build/Backlinks.hs — keeps archived external URLs through pass 1 and
canonicalises them to /archive/<slug>/ in pass 2, producing a
"Referenced by" section grouped by the fragment each citation
targets. build/Stats.hs gains a "Link archive" telemetry block on
/build/ (count, total size, median age, by-status / by-quality /
by-visibility, orphans).
* Integrity: archive.py fetch and build/Archive.hs (via sha256sum)
both re-hash every committed artifact, so a tampered file halts the
build even with cabal invoked directly or no .venv present. refresh
refuses to replace an uncommitted prior snapshot and rolls back
atomically on any exit path. removed.yaml is honoured by fetch,
wayback, and check using canonical-form (tracking-stripped,
arXiv-canonicalised) comparison.
* visibility: private keeps an entry in-repo but undeployed.
nginx/archive.conf emits X-Robots-Tag: noindex, noarchive for raw
artifacts that cannot carry meta directives.
The full design, phase plan (1-5), and three refinement passes live
in ARCHIVE.md.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>