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:

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)

RoleSize / leadingFace
H1clamp(40–76px) / 1.03Rokkitt 700, −0.02em
Deckclamp(21.6–25.6px) / 1.5Nunito Sans 400, muted
H2clamp(30.4–41.6px) / 1.12Rokkitt 700, −0.015em
Body ¶21px / 1.75Nunito Sans 400, −0.005em
Pull quoteclamp(28–34.4px) / 1.25Rokkitt 500
Caption17px / 1.45IBM Plex Mono 400
Rail meta16px / 1.4 — the floorIBM 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:

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.

  1. 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