Skip to content

feat(design): editorial 'Letter' layout adapted from Claude Design#47

Closed
ditvor wants to merge 1 commit into
developfrom
feat/editorial-redesign
Closed

feat(design): editorial 'Letter' layout adapted from Claude Design#47
ditvor wants to merge 1 commit into
developfrom
feat/editorial-redesign

Conversation

@ditvor
Copy link
Copy Markdown
Owner

@ditvor ditvor commented May 1, 2026

Summary

Adopts the Trailpath / Claude Design "Letter" layout for the editorial style. Black ink on cream paper, system serif + system mono, drop cap, single-rule pull quote, asymmetric inline photos, marginalia sidebar with sparkline. Magazine vocabulary, not dashboard vocabulary.

log and encyclopedia styles are intentionally untouched in this PR — they get their own design pass later.

Critique of the Claude Design source (UI/UX evangelist read)

What's exceptional:

  • OKLCH paper/ink palette (oklch(0.972 0.008 80) / oklch(0.18 0.01 80)). Warm in a way no hex/rgb pairing achieves. Magazine warmth, not iOS blue.
  • Eyebrow / mono / serif type system. Mono uppercase tracking eyebrow signals "this is editorial" the moment your eye hits it. Cereal/Monocle move.
  • Marginalia stats column. Quiet but present, in the gutter — National Geographic, not Strava.
  • Drop cap + single-rule italic pull quote. The two cheapest signals of editorial that exist; both costs zero and both pay off.
  • Asymmetric photo placement with saturate(0.92) contrast(1.02) filter. A uniform grid would have killed this; the asymmetry is the taste.
  • Sparkline elevation with no axis labels. Refuses the dashboard reflex.

What didn't fit (and what I did instead):

  • Google Fonts via CDN violates our offline-readability constraint (ADR-001 — base64 photos, single-file). Newsreader at view-time falls back to Times when the recipient is offline. Used a system stack (Charter / Iowan Old Style / Apple Garamond / Hoefler) instead — Charter ships on every Apple device, which is where most recipients will read. Embedding a subset Newsreader as base64 woff2 is a follow-up. Created a tracking note below.
  • The design uses 6 chapters with per-chapter title / time / place / body / photo. Our NarrativeOutput has flat paragraphs (3-5) + photo indices (6-8). Adopting the chapter shape exactly would have meant a schema change and a prompt-tuning ceremony. Adapted instead: paragraphs render as prose with the same editorial typography, photos placed asymmetrically by paragraph index.
  • Track SVG (the ink line of the GPX path). Beautiful, but our GpxStats only carries a normalised elevation profile, not waypoint coordinates. Sparkline kept; track-line dropped pending a model extension.
  • Three layouts (Letter / Postcards / Trail). Adopted only the Letter aesthetic into the editorial style. Postcards inspired the existing Instagram carousel; Trail is novel enough to deserve its own future style or a dedicated route.
  • EN/RU only in the prototype. Extended to EN/RU/DE since ADR-005 makes that the contract — labels, dek, byline, facts dt/dd, and share buttons all carry all three.
  • Marginalia sidebar at 240px is desktop-only. Collapses on < 900px to a single column with marginalia sitting after the prose as a closing reference. Mobile-first survives.

What changed

  • templates/styles/editorial.html.j2 — full rewrite: design tokens, masthead, drop cap, pull quote, hero photo, two-column body grid, marginalia sidebar with facts + sparkline, asymmetric scrapbook, restyled share row. Three EN/RU/DE pills replace the cycling button.
  • tests/test_styles.py::test_editorial_style_keeps_existing_visual_identity — refreshed identity markers for the new design (eyebrow, drop cap, pull-class, marginalia, three pills) so future refactors can't silently drift it.
  • tests/golden/test-render-editorial.html — refreshed (one style only; log + encyclopedia goldens untouched).
  • CHANGELOG.md — entry under ### Changed.

Constraints respected

  • ADR-001 — every photo still embeds as a data:image/jpeg;base64 URI. No external network at view time. No CDN fonts. Photo-count contract preserved: each selected photo renders exactly once (hero, inline, or scrapbook — never both).
  • ADR-005 — tri-lingual via class swap (body.lang-en / .lang-ru / .lang-de). No prompt changes.
  • Mobile-first — 375 px works (single column, full-width photos, marginalia at the bottom).
  • prefers-color-scheme: dark palette swap and prefers-reduced-motion: reduce both honored.

Test plan

  • make ci passes locally — 301 tests, 95.30% coverage. The new pull-quote, drop-cap, marginalia, and three-pill markers are now contract-checked.
  • make test-render STYLE=editorial produces a clean render against fixture data; opened in a browser at 375 / 768 / 1440 widths and dark mode.
  • log and encyclopedia goldens unchanged — the redesign is scoped strictly to editorial.
  • Real-device pass on iPhone Safari + Android Chrome (do this after merge against the deployed staging URL).
  • WhatsApp / Telegram preview card screenshot (post-deploy).

Follow-ups (not in this PR)

  1. Embed Newsreader as a subset base64 woff2 so the design fidelity matches what Charter approximates. ~80–100 KB; subset for EN+RU+DE+digits+punctuation via pyftsubset.
  2. Extend GpxStats with waypoint coordinates (or a normalised track shape), then render the ink-on-paper Track SVG from the design as an additional marginalia element.
  3. Postcard / Trail layouts as new style values — Postcards is a natural fit for the existing Instagram carousel preview; Trail is the most novel and deserves a dedicated user choice.
  4. Per-photo micro-captions as a new LocalizedParagraphs field on NarrativeOutput. Captions-as-micro-stories was Phase 3.5 of the prior design plan; needs the full prompt-tuning ceremony from CLAUDE.md.

🤖 Generated with Claude Code

Adapts the Trailpath / Claude Design exploration into the editorial
style. Black ink on cream paper (OKLCH tokens for paper / ink /
rule / hairline, dark-mode swap via prefers-color-scheme). System
serif stack (Charter / Iowan Old Style / Apple Garamond / Hoefler
fallbacks) and system mono — deliberately no Google Fonts CDN so
the page stays readable offline (ADR-001). The Newsreader serif
the design used will land later as a base64-embedded subset; the
system stack is the right interim because Charter ships on every
Apple device, where the bulk of recipients will read.

Markup changes:
- Masthead: mono-uppercase eyebrow (uses narrative.milestone), large
  editorial title, balanced dek (uses narrative.subtitle), delicate
  byline-and-date meta line.
- First paragraph carries a serif drop cap; siblings in inactive
  languages are display:none, so ::first-letter automatically
  selects the active language's first character — no per-language
  dropcap variants needed.
- Pull quote uses a single left-rule italic treatment, not a
  tinted box. Hero photo crops 16:9 mobile / 2.35:1 desktop with a
  saturate(0.92) contrast(1.02) print-magazine filter.
- Photos 2 and 3 float as inline asymmetric figures (right then
  left) inside the prose at desktop widths; on mobile they fall
  into the flow at full bleed. Any photo not claimed by hero or
  inline placement falls through to an asymmetric scrapbook grid.
  Photo-count contract unchanged: every selected photo embeds
  exactly once.
- Sticky marginalia sidebar on >= 900px holds a mono-uppercase
  facts table (Where/When/Distance/Ascent/Time/Summit) and the
  elevation sparkline. On mobile the marginalia collapses to a
  closing reference under the prose.
- Three discrete EN / RU / DE pills replace the cycling single
  button. Each is click-targetable, aria-pressed reflects state,
  and the class-swap mechanism (ADR-005) is unchanged.

The pull-quote class, drop-cap class, and marginalia sidebar are
new contract markers — codified in test_styles.py so future
refactors can't silently drift the polished default.

log and encyclopedia styles are intentionally untouched.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@ditvor
Copy link
Copy Markdown
Owner Author

ditvor commented May 1, 2026

Closing per request — jumped straight to implementation when the right move was to stop at the critique and align on what to keep/adapt/drop first.

@ditvor ditvor closed this May 1, 2026
@ditvor ditvor deleted the feat/editorial-redesign branch May 1, 2026 07:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant