Build notes · journal family · build #1 of 2
How the SAVE THE FROGS! Blog template was made
This is the build guide for the journal blog archive and its demonstration post — the third layout family in this series after cinematic and broadsheet, and the first that is not a landing page of any kind. It is a reading surface: a page whose entire design budget goes into measure, rhythm, hierarchy, and a margin apparatus, because its job is to hold a reader through 2,000 words, often on a phone, often arriving from a search result.
What it is for: these two page types are the planned future home of savethefrogs.com/blog once it migrates off WordPress. That framing decided almost everything below — the block library had to survive contact with a real WordPress post, not one written to fit the design.
The migration rehearsal
The demonstration post is The Portland Frog: A Symbol Of Resistance And Hope, published October 10, 2025 — chosen by survey of the 30 most recent live posts because it was the only one whose body exercises the full block range: 2,030 words, 11 H2 sections, 5 H3s, 8 lists, 2 blockquotes, 8 YouTube embeds, a call-to-action button, and 18 photographs (every one already carrying real alt text — credit to the source site). The body was taken verbatim; the template adapts around the content, never the reverse. The canonical URL of the reproduction points at the original post, so the demo can never compete with the real article in search.
Two publishing details worth recording: the post carries two published titles — the display title above and the shorter SEO headline in its <title>/JSON-LD (The Portland Frog: A Symbol Of Resistance And Hope). The demo uses the SEO headline as its H1 because the hero spec caps the slab at two lines, and 78 characters of display title runs three. And the byline is STF! Webmaster — the post's actual author account, not a re-attribution; that account's own public bio ("Dr. Kerry Kriger is the SAVE THE FROGS! Webmaster and has been building this website since 2008") became the author card.
Type: what the brand guide says, and what the web can license
The SAVE THE FROGS! Brand Guide 2025 specifies Rockwell Std. Extra Bold for the logo and URL, Berlin Sans FB Demi Bold for primary headings (with the guide's own note that Berlin's lowercase "k" is defective), and Urbane — Light, Bold, Light Italic, with 600 for website text and headers. None of the three can be self-hosted: Rockwell and Urbane are Adobe Fonts (which would put a third-party font CDN request on every page load of a reading surface), and Berlin Sans FB has no straightforward webfont license. The live site, measured 2026-08-05, actually serves Nunito Sans from Google Fonts for both body and headings — no Adobe Fonts request anywhere.
So the template ships three free faces, self-hosted as subset variable WOFF2 with zero font-CDN requests:
- Rokkitt (display — H1, H2, pull quotes, prev/next): an explicitly Rockwell-derived geometric slab1 — the same genus as the SAVE THE FROGS! wordmark, so headlines read as the organization without inventing anything the brand guide doesn't already contain. Sanity-checked at 76px in the first harness pass before committing.
- Nunito Sans (body): continuity with what savethefrogs.com already serves — a migrated post renders as the same organization. Tuned for length: 21px / 1.75 line-height, weight 400, −0.005em tracking, measure pulled in to 66ch because its large x-height tires eyes on long lines.
- IBM Plex Mono 400/500 (the rail voice): dates, categories, captions, table of contents, footers.
The grid: rail + measure
The signature move is an asymmetric two-track grid — a fixed 13.5rem rail on the left, a 3.25rem gutter, and a 66ch measure — with three spans available to any block: text (the measure), wide (rail + gutters + measure), and full (edge to edge). Everything that is not prose lives in the rail: the collapsed table of contents, section ordinals with their orange marker squares, figure captions, the margin note, blockquote attributions. The prose column runs uninterrupted from first word to last. Below 1100px the rail contents relocate rather than disappear — meta moves above the title, the TOC becomes a sticky collapsed bar, captions move under their figures, the margin note becomes an inline <details>.
The block library: 13 of 16 rehearsed on real content
The post demonstrates paragraphs, H2 + rail marker, H3, lists (unordered and ordered), blockquotes (including one with attribution), pull quotes (two protest-sign slogans that stand alone in the source — extracted lines, duplicating no prose), figures in all three spans, a figure pair with the source's own shared caption, a margin note (the post's parenthetical Pepe aside, anchored beside the figure it follows), a callout panel (the post's 501(c)(3) disclaimer), an inline CTA (the post's own Million Frog March button), eight facade-loaded video embeds, and a divider (the source's own <hr>).
Three blocks had no source content to carry them — the honesty rule ("never invent copy to demonstrate a block") routes them here as labeled specimens:
Specimen · Block 11 — code block (real code: the TOC gate from the verifier)
// The criteria agreed 2026-08-02 — a build-time gate, not a switch.
const tocGate = (isReadingSurface, qualifyingHeadings, words) =>
isReadingSurface && qualifyingHeadings >= 4 && words > 1500;
tocGate(true, 11, 2030) // the demo post → TOC renders
tocGate(true, 3, 800) // a short post → zero TOC markup, zero TOC JS
tocGate(false, 11, 2030) // a landing page → zero TOC markup, zero TOC JS
Specimen · Block 12 — data table (real data: this build's type scale)
| Role | Size / leading | Face |
|---|---|---|
| H1 | clamp(40–76px) / 1.03 | Rokkitt 700, −0.02em |
| Deck | clamp(21.6–25.6px) / 1.5 | Nunito Sans 400, muted |
| H2 | clamp(30.4–41.6px) / 1.12 | Rokkitt 700, −0.015em |
| Body ¶ | 21px / 1.75 | Nunito Sans 400, −0.005em |
| Pull quote | clamp(28–34.4px) / 1.25 | Rokkitt 500 |
| Caption | 17px / 1.45 | IBM Plex Mono 400 |
| Rail meta | 16px / 1.4 — the floor | IBM Plex Mono 500 |
Specimen · Block 16 — footnote (a real note, see the superscript in the type section above)
Footnotes render as superscript links in the prose; on the post surface the note also surfaces in the rail on hover/focus, and a numbered list with back-links closes the article either way. The demo post's source contains no footnotes, so the pattern ships here.
The reading apparatus
The table of contents renders only when all three gate criteria hold (code above). It ships collapsed by default as a native <details> sticky in the rail; active-section tracking is an IntersectionObserver (never a scroll handler) that sets aria-current="location" and fills the entry's orange tick — the TOC is the progress indicator, with a 2px top hairline as the secondary cue. Back-to-top appears only after ~1.5 viewports of downward scroll, hides while the footer is visible so it never covers the prev/next band, and has an always-present text-link twin at the article's end for keyboard and screen-reader users.
The motion budget is spent before reading starts: a one-time hero entrance (title → deck → byline → image, 60ms stagger), a one-time 8px rise on figures, 180–220ms link and tick transitions, and the archive's cursor-following image card — the one expressive flourish, deliberately on the index rather than the reading page. Prose never animates, and the verifier fails the build if any rule ever pairs a body-paragraph selector with opacity or transform. prefers-reduced-motion turns all of it off, including smooth scrolling.
The archive
An index, not a card grid: full-width hairline-separated rows — date and category in the rail column, Rokkitt title, one-line deck — with year dividers as ghosted numerals. On pointer devices the row's featured image trails the cursor as a 360px card (GSAP quickTo, slight velocity rotation); on touch, narrow screens, and reduced-motion, every row shows a 96px thumbnail instead — images are never unavailable. An Index ⇄ Grid toggle (persisted, defaulting to Index) offers a genuinely designed 3-up editorial grid: full-bleed images, no shadows, no rounded corners, no boxes. Category filters are real links to real pages (/journal/category/campaigns/ and five siblings) that also filter client-side; "load more" sits on top of a real page 2; the search has a designed empty state; the feed is real RSS.
Verification: the gates that fail the build
Every journal page passes scripts/verify-journal.mjs (254 assertions, wired into npm run build): every image must carry alt text and explicit dimensions; no font-size may resolve below 16px (a clamp is judged by its minimum; any sub-1em size fails); every text tier must clear WCAG AA on every ground it can land on, in both themes — including the regression pin on the one contrast bug this build actually shipped (de-emphasizing text with opacity composites below AA even when its token passes; Lighthouse caught .toc-count at 4.1:1); the TOC gate is asserted in both directions; and prose-never-animates is a build failure, not a convention. All three headline gates were canary-tested — deliberately broken, confirmed to fail the build, restored.
⚠ For Kerry's review — sentences written for this demo
Everything in the demo post's body is verbatim from the original. The following were written for the demo because WordPress posts carry no standfirsts and two source images had no captions — each is derived from the post's own content, and each is flagged <!-- DRAFT — Kerry to review --> in the markup:
- The figure-pair caption: "The Portland Frog going viral — as shared across social media, October 2025." (the two screenshots are uncaptioned in the source)
- The Pepe margin-note caption: "'Be nice, man.' — Pepe by his creator, Matt Furie." (image uncaptioned in the source)
- The archive decks — 15 one-line standfirsts, one per post row, each derived from that post's own opening paragraph (the demo post's deck is verbatim: the post's own meta description). Review them on the archive.
- The archive masthead description — assembled from the organization's mission statement.
- Editorial selections (real content, presentation choice only): the SEO headline as H1; the disclaimer paragraph rendered as a callout; the Pepe aside rendered as a margin note; the two protest slogans rendered as pull quotes; the supporter-quote paragraphs rendered as blockquotes.
Decisions this build banks for build #2
Build #2 is zero2webmaster.com/blog — the other real migration target — and per the parameterize-after-two rule, only after it ships does the family get factored into a config-driven layout. Sixteen axes are pre-declared in the brief (ground, body face, rail side, hero mode, accent role, archive mode, TOC policy…) so #2 can be steered to the opposite end of each: true dark, a reading serif or grotesk, no rail, an overlay hero, code-heavy technical posts. What the two builds agree on — the block library, the rhythm unit, the contrast and imagery gates, the TOC criteria, prose-never-animates — becomes the hard-coded core.
- Rokkitt (by Vernon Adams, updated by Sorkin Type) is an open-source geometric slab serif designed after the Rockwell model — the same "geometric slab" genus as the wordmark's Rockwell Std. Extra Bold. ↩
The demonstration post · The archive · Built 2026-08-05/06 in a Claude Fable 5 session from briefs/journal-blog-fable-brief.md · Part of the Zero2Webmaster showcase series