Commit Graph

48 Commits

Author SHA1 Message Date
Levi Neuwirth caa113e036 Frontend: search races, lightbox a11y, popup edge cases
- semantic-search.js: generation token prevents stale results from
  rendering over newer queries; in-flight dedup on the index fetch;
  index/meta size consistency check fails loudly instead of NaN
  ranking (AUDIT §5.5)
- lightbox.js: triggers keyboard-activatable (role=button, tabindex,
  Enter/Space); Tab trapped inside the aria-modal overlay, modeled on
  gallery.js (§5.6)
- nav.js: portal toggle persists via guarded safeStorage so
  storage-blocked contexts can't kill the toggle (§5.7)
- popups.js: provider url() throws (malformed percent-encoding) are
  treated as no-popup; future dates render nothing instead of
  "N days ago" (§5.7)
- search.js: missing PagefindUI degrades to a console warning instead
  of aborting the whole handler (§5.7)
- citations.js: deleted — dead code superseded by popups.js (§5.7)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 09:43:25 -04:00
Levi Neuwirth c64f3d63c0 Fix audit frontend MEDs
- score-reader template: load utils.js before theme.js — without
  lnUtils.safeStorage the saved theme/text-size never restored on
  score pages (AUDIT §5.1)
- search-filters: expand trailing-slash pathnames to .../index.html
  before the epistemicMeta lookup; clean-URL pages were silently
  bypassing every active filter (AUDIT §5.2)
- viz: treat cappuccino as a dark theme so charts stop rendering
  near-black marks on a dark brown background (AUDIT §5.3)
- collapse: namespace section-collapsed keys by pathname (Pandoc
  auto-slugs recur across essays) and go through safeStorage like the
  rest of the site (AUDIT §5.4)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 09:21:47 -04:00
Levi Neuwirth 37665f67db Branding: traced logo mark, regenerated favicons, og-image
New inline logo-mark.svg partial in the nav (two-tone cutout via
--logo-ink/--logo-bg), regenerated favicon set + web-app manifest icons
from the new mark, 1200x630 og-image wired into head.html.

Known follow-ups (AUDIT-2026-06-09.md §9): the traced SVG is ~33 KB
inlined per page, favicon.ico carries 128/256px entries, and the
webmanifest dropped its maskable purpose.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 18:57:34 -04:00
Levi Neuwirth af27479c6e Add now.js: recompute "Last updated" relative phrase client-side
build/Now.hs renders the .now-stamp-relative phrase ("3 days ago") at
build time against the build machine's clock; a page served days later
from cache or a CDN would then read stale. now.js recomputes the
phrase in the browser from the <time datetime> attribute (an
unambiguous YYYY-MM-DD) against the visitor's clock, with bucket
thresholds that mirror Now.hs:relativeTime exactly so the no-JS
fallback and the recomputed value agree.

* static/js/now.js — the recomputation script.
* templates/default.html includes it via $if(now)$ so it only loads
  on the Current page.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 12:06:49 -04:00
Levi Neuwirth 70dda56625 Popups: render the source page's monogram in internal previews
Internal-page hover popups now show the source's monogram alongside
the title / abstract / metadata when one exists. Two-column grid is
gated on .has-monogram so popups for pieces without an authored mark
keep their default single-column body. The serialised SVG comes from
the rendered page's own .frontmatter-mark--monogram figure, excluded
when it is the symmetric-layout placeholder roundel so empty-slot
pieces do not get a fake mark in the preview.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 12:06:35 -04:00
Levi Neuwirth a3b3457803 print.css: refresh page rules and prose treatments
Tightens what gets printed and how. Reading-mode warm tints are
disabled so pages do not repaint cream; the mobile TOC bar's
screen-only body padding is reset; sidenote / footnote treatments
are reworked so the prose flows continuously instead of breaking
into a separate footnotes section; decorative link-icon glyphs
are suppressed while external links keep their underline so a
reader can follow them in the printed copy.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 12:06:20 -04:00
Levi Neuwirth 802fc75968 Layout: page-shell wrapper for iOS sticky, scrollable TOC
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>
2026-05-23 12:06:02 -04:00
Levi Neuwirth 154b47a4cb Marks II: broader monogram coverage + audit-marks tool
Extends the Phase-1 monogram mark system to every long-form content
type (essays, blog posts, poems, fiction, music) and introduces a
coverage audit so gaps are visible.

* build/Marks.hs gains hasMonogram (predicate), monogramSvgFieldFor +
  hasMonogramFieldFor (for explicit-path callers like the /build/ and
  /stats/ pages). Contexts.hs exports hasMonogramField as a siteCtx
  boolean so templates can conditionally render the slot without
  emitting an empty <div>.
* essay.html, blog-post.html, reading.html: hoist the frontmatter
  block out of <main id="markdownBody"> so the monogram + epistemic
  marks render as wrapper chrome rather than indexable prose; left
  + right mark slots are now unconditional (CSS handles the empty
  state) so the layout is grid-stable across pieces.
* templates/partials/item-card.html: optional monogram chip on cards
  (item-card--has-monogram modifier), gated on $has-monogram$ so
  monogram-less pieces stay flush.
* build/Stats.hs grows a "Marks coverage" telemetry section: per-type
  pieces / monogram / epistemic-figure counts + a coverage rollup,
  rendered between epistemic and output on /build/.
* tools/audit-marks.py: coverage report (ASCII table) walking
  content/**/*.md, plus a pre-commit hook at
  tools/hooks/pre-commit-marks.sh that runs the same scan against
  newly-staged .md files. New `make audit-marks` runs the report
  manually; the hook gates commits.
* static/css/marks.css: layout for the new frontmatter slots and the
  item-card monogram chip.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 12:05:08 -04:00
Levi Neuwirth 77e31efdae Add link archive system: snapshots, backlinks, link-rot
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>
2026-05-23 10:06:33 -04:00
Levi Neuwirth 7f7c029601 Marks I 2026-05-07 23:51:14 -04:00
Levi Neuwirth 1274b36d42 Internal audit 2026-05-07 17:20:27 -04:00
Levi Neuwirth 9a343f16b0 Branch preprint 2026-05-06 12:21:59 -04:00
Levi Neuwirth 977c1cecbb yum cappuccino yay! 2026-05-03 21:16:58 -04:00
Levi Neuwirth 6286c82389 more prominent related pages 2026-05-03 14:01:14 -04:00
Levi Neuwirth f41311a3eb Inline code reference previews 2026-05-02 10:40:43 -04:00
Levi Neuwirth cd94227acb Spec dilemma 2026-05-01 21:22:01 -04:00
Levi Neuwirth 42ba2bf972 Current rework 2026-04-26 19:42:47 -04:00
Levi Neuwirth 6585573dae States/Context/Embeddings fixes 2026-04-26 11:22:57 -04:00
Levi Neuwirth 3a95a05284 Fix broken PDF hyperlinks 2026-04-22 12:10:31 -04:00
Levi Neuwirth 40ba09209c Professional content refactor 2 2026-04-22 11:56:25 -04:00
Levi Neuwirth 913a374fb2 Professional content refactor 2026-04-22 11:46:57 -04:00
Levi Neuwirth daa0ea4c3c library: fine-press typography + muted-warm palette
Scoped warm accent tokens (--library-accent and friends) defined at
:root inside library.css — page-scoped since the file only loads on
/library.html and /search.html. Section headings become Spectral
small-caps chapter markers at 1.2rem in the accent color, so the
ornament span inherits it via currentColor. Divider and "more on
this shelf" link pick up the muted variant. The leading blockquote
gets an epigraph treatment: narrower measure, italic, warm intro
ink, with the attribution line dropping to the accent-muted tone.
Card-level refinements (oldstyle figures on dates, small-caps on
item-kind) scoped via .library-section so /new.html and tag pages
retain their lining-figure UI treatment.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 21:21:47 -04:00
Levi Neuwirth 0221603766 library: portal ornaments + inter-shelf divider
Each shelf gets a dingbat keyed by portal slug: laurel (research),
quill (nonfiction), open book (fiction), lyre (poetry), plus the
existing clef / ai / tech / trefoil glyphs for the remaining four.
Rendered via mask-image with currentColor so a single SVG per
portal inherits whatever color its heading carries. Between rendered
shelves, a centered fleuron flanked by thin rules (library-divider.svg)
sits via CSS adjacent-sibling so hidden sections leave no orphan
dividers. The template swaps its Unicode placeholder for a
data-ornament span, wires a '\$library-intro\$' slot above the shelves,
and renders a "More on this shelf →" link when has-more gates fire.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 21:20:35 -04:00
Levi Neuwirth 908136b646 Navigation refactor 2026-04-19 14:35:41 -04:00
Levi Neuwirth 237380c4be date data 2026-04-17 15:15:04 -04:00
Levi Neuwirth 1a532f881b major visual changes - dingbats, footer, etc 2026-04-17 12:48:22 -04:00
Levi Neuwirth acb3ae7066 visual enhancements 2026-04-15 22:25:38 -04:00
Levi Neuwirth 03babfb02a new mobile fix 2026-04-13 11:05:01 -04:00
Levi Neuwirth e005380362 subdomain svg correction 2026-04-13 10:26:25 -04:00
Levi Neuwirth c3fa26f60e mobile fixes 2026-04-12 15:29:35 -04:00
Levi Neuwirth 41bbbd799b favicon, logo, internal popups 2026-04-12 14:57:01 -04:00
Levi Neuwirth e25a311dd9 filters + epistemic popups 2026-04-12 10:40:58 -04:00
Levi Neuwirth d113671e96 epistemic redo 2026-04-11 19:40:58 -04:00
Levi Neuwirth e5ed6a3bb4 library sorting 2026-04-11 15:10:48 -04:00
Levi Neuwirth dd61fc0cc4 audit: frontend a11y, JS shared utils, CSS variable definitions 2026-04-10 17:41:21 -04:00
Levi Neuwirth 02b7694bfe forgejo links 2026-04-05 11:32:50 -04:00
Levi Neuwirth 9a01c602bc auto: 2026-04-05T01:18:45Z 2026-04-04 21:18:45 -04:00
Levi Neuwirth aee326bfec New page 2026-03-30 20:45:03 -04:00
Levi Neuwirth b06b1e741c popup improvements, citation fix 2026-03-29 08:02:04 -04:00
Levi Neuwirth 1be6292757 ToC fix 2026-03-27 16:19:52 -04:00
Levi Neuwirth b38e9359d5 annotation system 2026-03-26 13:29:37 -04:00
Levi Neuwirth 1210314cc8 build footer hyperlink 2026-03-26 11:12:28 -04:00
Levi Neuwirth a5495035be epistemic v2 2026-03-26 09:10:35 -04:00
Levi Neuwirth 728afd4c68 affiliation, cabal helper script 2026-03-26 08:14:50 -04:00
Levi Neuwirth 5cfbfbc0ef GPG signing, embedding pipeline, visualization filter, search timing, sig popups
- GPG page signing: dedicated signing subkey in ~/.gnupg-signing, sign-site.sh
  walks _site/**/*.html producing .sig files, preset-signing-passphrase.sh caches
  passphrase via gpg-preset-passphrase; make sign target; make deploy chains it
- Footer sig link: $url$.sig with hover popup showing ASCII armor (popups.js
  sigContent provider; .footer-sig-link bound explicitly to bypass footer exclusion)
- Public key at static/gpg/pubkey.asc
- Embedding pipeline: tools/embed.py encodes _site pages with nomic-embed-text-v1.5
  + FAISS IndexFlatIP, writes data/similar-links.json; staleness check skips when
  JSON is newer than all HTML; make build invokes via uv, skips gracefully if .venv absent
- SimilarLinks.hs: similarLinksField loads similar-links.json with Hakyll dependency
  tracking; renders Related section in page-footer.html
- uv environment: pyproject.toml + uv.lock (CPU-only torch via pytorch-cpu index)
- Visualization filter: Filters/Viz.hs runs Python scripts for .figure (SVG) and
  .visualization (Vega-Lite JSON) fenced divs; viz.js renders with monochrome config
  and MutationObserver dark-mode re-render; viz.css layout
- Search timing: #search-timing element shows elapsed ms via MutationObserver
- Build telemetry timestamps removed from git tracking (now in .gitignore)
- spec.md updated to v9; WRITING.md updated with viz, related, signing, build docs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 20:14:49 -04:00
Levi Neuwirth 26c067147a Build telemetry 2026-03-19 15:27:12 -04:00
Levi Neuwirth 9c47811372 Administrativa. 2026-03-17 22:31:24 -04:00
Levi Neuwirth 714824a0b5 initial deploy! whoop 2026-03-17 21:56:14 -04:00