astro-knots
Mode

← All ship notes

fullstack-vc

Long-Form Reader Chrome — Triptych, Reading Progress, ChapterMeta, and the LFM Pipeline Everywhere

Long-Form Reader Chrome — Triptych, Reading Progress, and the LFM Pipeline Everywhere

Why Care?

For the firm (Mike): the Venture Handbook now has the chrome it needs to feel like a real book on the open web. Drop a chapter .md into src/content/long-form/venture-workflows/ and you get — for free — a banner with overlaid chapter title, a slim meta row (Chapter 03 · 12 min read · 5,420 words · author · updated · source), an "In this chapter" outline derived from the subsection_outline frontmatter, a top triptych showing the previous chapter card · the banner · the next chapter card, an accent rule above every H2, a violet→lime gradient drop-cap on the first paragraph, footnote refs styled as little violet pills, a ✦ ornament on every <hr>, and a bottom prev/next pair of full-fidelity preview cards. All of it tracks --color-primary and adapts across the three modes (light / dark / vibrant) without any per-mode rules.

The reader uses container queries — the reader's own width, not the viewport's — to switch between four layouts: Mobile (chevron-only flanking buttons), Tablet (slim cards, no tags), Half-Screen (~200px slim cards), and Desktop (full 17rem cards beside a wider 1100px outer container). That means the layout responds correctly inside split-screen panels, embedded iframes, and any other constrained context — without a single viewport @media query.

For our end users (the VCs reading): the chapter pages no longer feel like a <Content /> dump on a card. They feel like a Stripe-Press-style ebook chapter — generous typography (~70ch column at 1.7 line-height, 1.0625–1.125rem body), prev/next previews so you can see where you've been and where you're going without scrolling, and a thin scroll-progress stripe at the very top of the viewport so you know how much of this chapter is left.

The webinars detail pages got the same treatment: switched from improvised <Content /> rendering to the canonical Lossless pipeline (parseMarkdown + AstroMarkdown + Sources), and gained the table / hr / footnote-pill styles they were missing. The Agentic VC Dojo launch session's Format breakdown now renders as a proper bordered table with code-font uppercase headers and a subtle hover-row tint, instead of as raw text columns.

What Got Built

BookReaderLayout (new — src/layouts/BookReaderLayout.astro)

Wraps BaseThemeLayout. Receives the chapter entry plus optional prev/next entries. Composes:

  • ReadingProgressBar (3px stripe)

  • Skip-to-content link (a11y)

  • Top triptych: [ContentPreviewNavCard variant="inline"] · [BannerWithOverlay] · [ContentPreviewNavCard variant="inline"] — when a side is missing (chapter 1 or 10), a layout-stable spacer sits in its place

  • ChapterMeta slim row (Chapter NN · X min read · X,XXX words · Author · Updated · Source)

  • Tag chip row (#Train-Case)

  • "In this chapter" outline aside (from frontmatter subsection_outline)

  • The article body slot (where AstroMarkdown + Sources go)

  • Bottom prev/next pair (full-fidelity ContentPreviewNavCard variant="block")

Banner image source resolves through hero_image → og_image → /og-default.png, so chapters with only the OG image populated still get a real banner. The triptych cell stretches the banner to the cards' height (the banner figure's intrinsic 3:1 is overridden in this context); the image inside still uses object-fit: cover so 3:1 generated banners look right and off-aspect fallbacks crop instead of stretching.

Container query modes (width-only, plus a viewport @media fallback for portrait split-screen):

  • Mobile (cw < 768px): chevron-only flanking buttons, single-column bottom nav

  • Tablet (768–1023): medium cards (no tags, 2-line lede)

  • Half-Screen (1024–1279): slim ~200px cards (3-line lede, max 2 tags)

  • Desktop (≥ 1280): full 17rem cards, --reader-outer: 1100px, --reader-prose-size: 1.125rem

Print stylesheet polished: progress bar / triptych / nav suppressed, page-break before each <h2>.

ContentPreviewNavCard (new — src/components/read/)

Direction-aware preview card. variant="inline" adapts to the reader container size (full → slim → chevron-only); variant="block" is always full. Visually echoes AreasOfVentureGrid (same --fx-card-* tokens, same number-in-corner motif, same lede + tags rhythm). The chevron sits in the corner that matches travel direction (‹ top-left for prev, › top-right for next); on hover the chevron slides toward its direction by 2px. Whole card is a single <a>.

ChapterMeta (new — src/components/read/)

Slim code-font row immediately below the banner. Renders Chapter NN · reading time · word count · author · updated date · source organization as a horizontal definition-list. Reading time computed by the caller as ceil(words / 220); word count stripped of code fences and footnote definitions before the count.

ReadingProgressBar (new — src/components/read/)

Fixed 3px top stripe. Tracks scroll position relative to the article body's bounding rect — not the viewport — so the bar reaches 100% when you've scrolled past the last paragraph, not when you hit the bottom of the page including the prev/next cards. requestAnimationFrame-throttled scroll listener; prefers-reduced-motion: reduce kills the width transition.

FormattedDate + format-date.ts (new — src/components/ui/, src/lib/)

Common date formatter usable anywhere. Accepts Date | string | null, returns the date in one of: 'long' (April 26, 2026 — default), 'medium' (Apr 26, 2026), 'short' (Apr. 26, 2026), 'iso' (2026-04-26), 'reverse-medium' (2026, Apr. 26), 'year-only' (2026). UTC-normalized so 2026-04-26 doesn't shift to 2026-04-25 for negative-offset readers — that ambiguity has bitten the site before. The Astro component wraps the output in a semantic <time datetime="YYYY-MM-DD">.

Webinars detail page migrated to the LFM pipeline

src/pages/webinars/[id].astro was using the improvised vanilla-Astro <Content /> rendering. Switched to the canonical pattern: parseMarkdown(entry.body) → <AstroMarkdown node={tree} /> → <Sources citations={citations} />. Added the table / footnote-pill / <hr> styles that the body was missing — the Format table on the launch session now has proper borders, padded cells, code-font uppercase headers, and a subtle hover-row tint. Cleared 3 pre-existing TS-check errors while in the file.

Dojo page brand banner

Dropped a full-width brand banner above the hero on /dojo (Kauffman-logo composite + SVG overlay you spent the time on at /og-default.png). Tasteful card surface treatment via --fx-card-*; 5rem gap below preserves the existing hero / Areas grid rhythm.

Design system catalog updated

Five new catalog entries land in /design-system per the maintenance motion: BookReaderLayout, ReadingProgressBar, ChapterMeta, ContentPreviewNavCard, FormattedDate. ContentPreviewNavCard also gets a live preview section showing both block and inline variants side by side.

Bugs Fixed

  • Duplicate <h2>Sources</h2> on every chapter page. The content port had injected *** + ## Sources as a divider into 8 chapter bodies; LFM's parseMarkdown also populates tree.data.citations.ordered from the numeric [^N]: … defs, and the <Sources /> component renders its own <h2>Sources</h2> from that. Two headings, both legit. Fix: stripped the injected wrapper from all 8 chapters; footnote defs themselves remain (LFM consumes them); <Sources /> is now the sole source of the heading. Verified: chapter 5 now renders exactly 1 <h2>Sources</h2> and 4 source-* anchors.

  • Container-query Desktop layout never firing. @container reader (aspect-ratio >= 13/10) was reading the container's own rendered aspect — which for a long scrolling page is always portrait — so the Desktop rule was a dead branch and full-screen laptops were falling through to Half-Screen. Fix: width-only thresholds in the container queries; one viewport @media (min-width: 1280px) and (max-aspect-ratio: 13/10) clamps wide-but-tall split-screen windows to the slim density (the case the spec actually wanted aspect-ratio for). Both BookReaderLayout and ContentPreviewNavCard rules updated.

  • Banner figure not filling the triptych cell on Desktop. The figure's intrinsic aspect-ratio: 3/1 was making it shorter than the cards beside it. Fix: in the triptych context only, override to aspect-ratio: auto; height: 100%; width: 100%. Image inside still uses object-fit: cover so 3:1 banners look right and off-aspect fallbacks crop gracefully.

Authoring affordances

  • New chapters need only frontmatter + body. The layout handles banner / meta / outline / prev-next from chapter_number sequencing. No manual prev/next wiring.

  • New webinar markdown can use full GFM (tables, footnotes, callouts via the :::callout directive once that lands) — the body now flows through the same renderer as chapters and essays.

  • Date strings in frontmatter render through <FormattedDate> for human-legible output; pass style="reverse-medium" for the year-first variant where desired.

Yak-Shaving Deferred

  • Foreword (00-foreword.md) and appendix (99-perspectives.md) chapters not yet filed.

  • Image directive migration — the chapter bodies still carry backticked ![][image6] markers that need to be unwrapped and resolved to the /read/venture-handbook/images/ PNGs (the 29 images are extracted and in place; the rewrite is one mechanical pass).

  • Mobile collapsing ToC bar (port from lossless-group/site per spec § Mobile ToC).

  • Desktop ToC sidebar (right-margin sticky, IntersectionObserver-driven).

  • Section-share / quote-share buttons + the /share/ SSR endpoint.

  • Save-my-place via localStorage.

  • Per-chapter banner generation pass (currently all chapters fall back to the OG image via the new fallback chain).

Files Touched

See frontmatter files_modified. Chapters listed as a glob since all 10 had the duplicate-Sources fix applied.