Documents obtained through FOIA requests reveal that enforcement actions against major financial institutions were dropped without explanation in the final weeks of the fiscal year.
Style Guide
Every design token, typographic specimen, component, and interaction pattern for The Umami Post.
Brand
The publication name is always written in full, The Umami Post, capitalised, never abbreviated to "TFT" in reader-facing copy. The icon is a serif "F" on a dark square.
Logotype
Tagline
A community food publication. Tested recipes, technique guides, food journalism, and reviews -- written by cooks, for cooks. Free and open source.
Mascot
The pansy flower, a historical symbol of Food (from the French pensée, meaning "thought"), is the publication's mascot.
Colors
A warm newsprint palette in light mode; deep charcoal in dark mode. Every value is a CSS custom property in tokens.css, change once, retheme everywhere.
Surfaces, light mode
Text
Accents & UI
Section colors
Dark mode surfaces
Typography
Four typefaces do all the work. All served from Bunny Fonts, privacy-friendly, no tracking, with system-font fallbacks.
Families
Hero titles, masthead, page titles, decorative numerals.
Article headlines, section headers, card titles.
Article and page body copy. 16px base, 1.7 line-height.
All UI chrome: nav, buttons, form labels, section badges, reading time.
Dates
Every human-readable date sitewide renders in Month DD, YYYY format — for example, "April 18, 2026". Server-side this is the readableDate and shortDate Eleventy filters (Luxon LLLL d, yyyy); client-side date renderers use toLocaleDateString(undefined, { year: 'numeric', month: 'long', day: 'numeric' }). Abbreviated months ("Apr 18") and ISO ordering ("2026-04-18") are reserved for machine-readable contexts only — the htmlDateString filter and the datetime attribute on <time> elements.
Type scale
Major Third ratio (1.25×). Base size is 16px (1rem). Tokens are defined in tokens.css, never use raw pixel values in templates.
Spacing
A consistent rhythm from 4px to 6rem. Always use spacing tokens, never hardcode values in templates. The scale lives in tokens.css.
Buttons
Square corners (border-radius: 0). All buttons meet the 44×44px minimum touch target. Hover states have explicit color set to override parent link rules.
On dark backgrounds
Support badges
Shields.io-style two-part flat badges used for reader support CTAs. Height is fixed at 20px with vertically centered text. Tippy.js tooltips provide context on hover.
Variants
tip-badge--pub value uses background: #1E3A5F; color: #F4F1EB, deep navy, hardcoded. 10.2:1 contrast. Visually distinct from both light card bg and dark page bg (#141414). Do not change to use accent tokens.
<a class="tip-badge" href="..."> <span class="tip-badge__label">support</span> <span class="tip-badge__value">Author Name</span> </a>
With Tippy tooltip
data-tippy-content="..." data-tippy-theme="badge" data-tippy-placement="top"
Section badges
Small pill-style section labels used in article cards and eyebrows. Background color comes from the section-specific CSS custom property.
<a class="section-badge section-badge--news" href="/news/">News</a>
Breadcrumbs
Used on all sub-pages. Links render in the accent color; the current page is ink-faint. The / separator is injected via CSS ::before.
<nav class="breadcrumbs" aria-label="Breadcrumb">
<ol class="breadcrumbs__list">
<li class="breadcrumbs__item"><a class="breadcrumbs__link" href="/">Home</a></li>
<li class="breadcrumbs__item"><a class="breadcrumbs__link" href="/contributors/">Contributors</a></li>
<li class="breadcrumbs__item breadcrumbs__item--current" aria-current="page">Jon Ajinga</li>
</ol>
</nav>
Article cards
The single canonical card component used across all section feeds, homepage grids, related-posts, author pages, tag pages, and editions. One partial, partials/article-card.njk, four size variants, consistent metadata everywhere.
Metadata, always shown on every card
| Field | Source | Notes |
|---|---|---|
| Section badge | article.data.section | Links to section index |
| Date | article.date | Links to /archives/#date |
| Headline | article.data.title | Size controlled by size variable |
| Description | article.data.description | Suppressed on xs |
| Author | authors[slug].name | Links to /author/slug/; Tippy bio tooltip |
| Reading time | templateContent | readingTime | e.g. "6 min read" |
| Word count | templateContent | wordCount | e.g. "1,847 words" |
| Image | article.data.image | Only when showImage=true |
Large, size="lg"
Homepage lead story, section lead. Used with showImage=true.
priority = true sets fetchpriority="high" and loading="eager" on the image. Use only for the single above-fold hero card to improve LCP.
Medium, size="md"
Standard feed card. Default size.
The collapse of local journalism is not a market failure. It is the predictable outcome of private equity treating public institutions as inventory.
Small, size="sm"
Sidebar, related posts, article lists.
From atheism to secular humanism, the terms we use to describe non-belief carry centuries of argument.
Horizontal, with thumbnail
Used where a compact image + text side-by-side layout is needed. Add class article-card--horizontal.
<article class="article-card article-card--horizontal"> <img class="article-card__image" src="..." ...> <div>...eyebrow, headline, byline...</div> </article>
Usage guide
| Size | Use when | showImage | Description shown |
|---|---|---|---|
lg | Homepage lead, section lead (1 per page) | Yes | Yes |
md | Section feeds, newsletter grids | No | Yes |
sm | Sidebar, related posts, author page list | No | Yes |
xs | Compact lists, "more from" rails | No | No |
| horizontal | Thumbnail + text rows | Yes (fixed) | No |
Author cards
Used on the Contributors page. Centered column layout: avatar on top, body below. The avatar uses a stacked pattern, initials always rendered, photo absolutely positioned on top with onerror fallback.
Avatar stacking pattern
<div class="author-card__avatar">
<div class="author-card__initials" aria-hidden="true">JA</div>
<img src="photo.jpg" class="author-card__photo"
onerror="this.style.opacity=0">
</div>
Initials always render. Photo is position: absolute on top. onerror hides the photo if it fails to load, revealing initials underneath.
Forms
All inputs are minimum 44px tall, set in the UI typeface, and show a distinct focus ring. Forms are handled by embedded third-party providers (Web3Forms, Fillout, Zite), never custom backends.
Tables
Data tables wrap in .table-wrap for horizontal scroll on narrow viewports. Use scope="col" on header cells and scope="row" on row headers.
| Criterion | The Umami Postindependent | Ad-funded outletcommercial |
|---|---|---|
| Revenue model | Reader-funded | Advertisers |
| Editorial control | Full | Partial |
| Paywall | None | Often |
<div class="table-wrap"> <table class="compare-table">…</table> </div>
Icons
Icons are inline SVG, 24×24 viewBox, stroke-width: 2, fill: none, currentColor, they inherit text color automatically in light and dark modes.
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" aria-hidden="true">…</svg>
Accessibility patterns
WCAG 2.2 Level AA minimum across all pages. Most patterns exceed AA and reach AAA.
Skip link
Press Tab on any page. The first focusable element is a "Skip to content" link that jumps past navigation to #main.
Focus ring
Every interactive element shows a 2px vermillion outline with 3px offset on keyboard focus.
Screen-reader-only content
Use .sr-only to hide content visually while keeping it accessible to assistive technology.
<span class="sr-only">Opens in new tab</span>
Reduced motion
All animations and scroll behavior honor prefers-reduced-motion: reduce. Duration drops to near-zero; auto-advance stops.
ARIA landmarks & labels
role="banner"on site header,role="contentinfo"on footeraria-labelon every icon-only button and every navigation regionaria-current="page"on the active nav linkaria-hidden="true"on all decorative SVGs and avatar initials<main id="main">as the skip-link target
Repeated link text
When multiple links share the same visible text but go to different destinations, e.g. "View All →" buttons in section strips, add aria-label to give each a distinct accessible name:
<a href="//" class="btn" aria-label="View all articles"> View All → </a>
This satisfies Lighthouse's "Links do not have descriptive text" audit and WCAG 2.4.6. The visible text stays short; the accessible name is descriptive.
Touch targets
Every interactive element is a minimum of 44×44 CSS pixels, buttons, nav links, form inputs, theme toggle, hamburger, back-to-top, tip badges.
Glossary tooltips
Glossary terms detected in article text receive a dotted underline. Powered by Tippy.js. Keyboard accessible.
Contrast reference
All pairings target WCAG AA: 4.5:1 for normal text, 3:1 for large text and UI. Light mode has two relevant backgrounds, page (#F4F1EB) and card (#E0DBCF). The card bg is the binding constraint and is used below. Dark mode verified independently.
| Pairing | Ratio | AA normal | AA large | AAA |
|---|---|---|---|---|
| Ink on page bg (#F4F1EB) | 15.6 : 1 | Pass | Pass | Pass |
| Ink muted on page bg | 8.2 : 1 | Pass | Pass | Pass |
| Ink faint on card bg (#E0DBCF) | 5.1 : 1 | Pass | Pass | , |
| Ink faint on page bg | 6.3 : 1 | Pass | Pass | Pass |
| Accent on page bg | 5.2 : 1 | Pass | Pass | , |
| Link on page bg | 6.8 : 1 | Pass | Pass | Pass |
| White on Accent (#C0392B) | 5.4 : 1 | Pass | Pass | , |
| Dark mode: Ink faint on card (#252525) | 5.5 : 1 | Pass | Pass | , |
| Dark mode: Ink muted on page (#141414) | 7.4 : 1 | Pass | Pass | Pass |
Note: dark mode accent (#E05545) is for text use only, do not use it as a background with light text (3.8:1 fail). The publication tip-badge uses background: #1E3A5F; color: #F4F1EB, deep navy at 10.2:1, visually distinct from both light card bg and dark page bg (#141414).
Naming conventions
Consistent naming avoids confusion across templates, CSS, and JavaScript. These rules apply to every file in the project.
Publication name
- Always written as The Umami Post, full, capitalised
- Never abbreviated to "TFT" in reader-facing copy
- Short context only: "The Times" is acceptable in conversational UI
CSS class convention
BEM-style: .block__element--modifier. No utility classes except where explicitly defined in utilities.css.
.article-card__byline /* element */ .article-card__headline--lg /* element + modifier */ .section-badge--news /* block + modifier */
JavaScript
- One file per feature, deferred, no bundler
- LocalStorage key prefix:
tft-(e.g.tft-theme,tft-reading-list) - No inline event listeners on elements with custom
displayCSS, tinyHTML can mangle them. Useonclick=""as a fallback alongside deferred listeners.
Design tokens
All tokens live in src/assets/css/tokens.css. Never use raw hex values or pixel sizes in templates or component CSS, always reference a token. Dark mode overrides are declared in the same file under [data-theme="dark"].
Content naming
- The bookshelf project: Recommended Food Reading (compact: Recommended Reading)
- The music feature: Food Music (never "Music Player")
- Layouts directory:
src/_includes/layouts/ - Partials directory:
src/_includes/partials/