Kontra: GOTH app (Go+templ+htmx+Tailwind tokens), markdown content, Decap admin, media shortcodes. Phase 3 build complete + verified locally.

This commit is contained in:
sam
2026-09-08 17:11:21 +10:00
commit 31e9a708cc
46 changed files with 4178 additions and 0 deletions

175
DESIGN.md Normal file
View File

@@ -0,0 +1,175 @@
---
type: design-system
name: Kontra — Broadsheet Editorial
version: 1.0.0
status: approved 2026-09-08
source:
stitch-panel: "The Gazette — Tides of the Outer Reach"
stitch-export-html: "Image 2.html"
stitch-export-design-md: "Image 3.markdown"
audience: desktop + mobile news-opinion site (Kontra)
---
# Kontra — DESIGN.md (Broadsheet Editorial)
> Adopted 2026-09-08 from Google Stitch "Broadsheet Editorial" panel.
> **Finalized 2026-09-08:** brand is **Kontra** (not "Kontra Day"); centered masthead;
> "Topics" heading; responsive (≥1024 / 641–1023 / ≤640) with dropdown topic nav
> + mobile sections drawer. Clickable prototype: `prototype/index.html`,
> `prototype/article.html`, tokens in `prototype/assets/kontra.css`.
> Palette + typography reconciled to the *rendered* Stitch export (Image 2.html) —
> the DESIGN.md export used slightly different hexes (e.g. `#F8F6F0` vs `#fbf9f3`);
> the rendered HTML is what you actually saw, so it wins. Differences noted inline.
## Identity
A tactile, deliberate reading environment inspired by physical print journalism
and high-grade editorial typography. Intellectual, trustworthy, measured, authorial.
Ultra-clean editorial minimalism: structure from hairline rules, typographic scale,
and whitespace — **not** shadows, rounded containers, or neon accents.
Rejects app-clutter (FABs, heavy shadows, dense cards).
**Kontra adaptation:** from a mobile-first Stitch panel, we built a **desktop-first**
site: front page with lead stack + Topics grid + Latest feed, subject indexes,
wider measures. Tokens carry over; the desktop layout is finalized in §Layout.
## Palette
Base is **warm newsprint**, ink is **soft charcoal**, accent is **editorial vermilion**.
No pure black-on-white (optical glare).
| Token | Value (rendered) | Role |
|---|---|---|
| `--canvas` | `#fbf9f3` | Base page background (newsprint) |
| `--canvas-bright` | `#ffffff` | Cards/forms on dark wells; bright surfaces |
| `--surface` | `#f0eee8` | Secondary canvas: section wells, meta blocks |
| `--surface-hi` | `#eae8e2` | Tertiary wells, footer sections |
| `--surface-highest` | `#e4e2dd` | Hairline borders, dividers (also `#e4e2dd`) |
| `--ink` | `#1b1c18` | Primary text (soft charcoal, not black) |
| `--ink-muted` | `#444748` | Byline, captions, secondary metadata |
| `--ink-faint` | `#747878` | Timestamps, reading time, tertiary |
| `--accent` | `#ad3222` | **Editorial vermilion**: breaking tags, section headers, links, active states, numerals |
| `--accent-deep` | `#8b190d` | Accent hover/pressed states (from secondary-fixed-variant) |
| `--accent-soft` | `#ffdad4` | Accent tint wells, selection bg |
| `--on-accent-soft` | `#400100` | Text on accent-soft (selection) |
| `--ink-inverse` | `#1c1b1b` | Dark solid: primary buttons, masthead icon well |
| `--on-ink-inverse` | `#ffffff` | Text/icon on ink-inverse |
| `--outline` | `#c4c7c7` | Subtle separators, placeholder |
| `--hairline` | `#e4e2dd` | 1px rules (same as surface-highest) |
| `--scrim` | `rgba(26,26,26,0.4)` | Warm charcoal scrim for modals/drawers |
### Notes
- Default button: `--ink-inverse` bg, `--on-ink-inverse` text; hover → `--accent`.
- Focus: hairline transitions `--hairline` → `--ink`, **no glow/shadow**.
- Selection: `bg #ffdad4`, text `#400100`.
## Typography
| Token | Family | Size | Weight | Line | Track |
|---|---|---|---|---|---|
| `--font-display` | **Newsreader** (serif) | — | — | — | — |
| `--font-body` | **Literata** (serif, print) | — | — | — | — |
| `--font-ui` | **Work Sans** (sans) | — | — | — | — |
| `masthead` | Newsreader | 38px (mob 30px) | 700 | 1.16 (44px) | -3% |
| `headline-xl` | Newsreader | 32px (mob 28px) | 600 | 1.19 (38px) | -2% |
| `headline-lg` | Newsreader | 24px | 600 | 1.25 | -1% |
| `headline-md` | Newsreader | 20px | 500 | 1.3 | 0 |
| `headline-sm` | Newsreader | 18px | 600 | 1.33 | 0 |
| `body-lead` | Literata | 19px | 400 | 1.58 (30px) | -0.5% |
| `body-md` | Literata | 17px | 400 | 1.65 (28px) | 0 |
| `body-sm` | Literata | 14px | 400 | 1.57 (22px) | 0 |
| `quote` | Newsreader *italic* | 21–22px | 400 | 1.45 | -1% |
| `label-caps` | Work Sans | 11px | 600 | 16px | +12% (uppercase) |
| `label-meta` | Work Sans | 12px | 500 | 18px | +2% |
| `label-ui` | Work Sans | 14px | 500 | 20px | +1% |
### Rules
- **Body measure ≤ 68ch** (`max-width: 65ch`); content column `42rem` max.
- **Italic serif reserved**: book titles, direct quotes, editorial side notes only.
- Section lead-ins: `label-caps` in `--accent` above headline.
- Headlines: Newsreader, tight tracking, no hyphenation; keep 2-line constraint on feeds.
- **Hierarchy (approved tweak)**: sub-headings in feeds/subject boxes render **one step smaller** than the box's primary headline, and decks one step smaller again — so the leading story reads clearly above the secondary tiers.
- Fonts self-hosted (woff2) — not Google CDN at runtime (page 3 of plan).
## Spacing / Grid
- Baseline: **8px** grid. Vertical rhythm via `--space-md` (16px) / `--space-lg` (24px) / `--space-xl` (32px).
- Gutter: mobile `20px` (1.25rem); tablet/desktop scales to `24–32px`.
- **Content column**: centered `max-width: 42rem` (672px) for article body.
- Front page: two/three-tier column grid (12-col on ≥1024px) — see Desktop Extension.
- Line length hard cap: `65ch` body.
## Shape / Elevation
- **0px radius everywhere** (buttons, cards, inputs, chips, image frames). Sharp right angles only.
- Circular allowed **only** for: author avatars, audio scrubbers.
- **No drop shadows, no blur-layered elevation.** Depth is planar + hairlines.
- Modals/drawers: solid sheet, 1px `--ink` border, `--scrim` backup. Sticky masthead: hairline bottom border only.
## Components
### Masthead (sticky top)
- Meta line: date • edition (label-caps, `--ink-muted`), edition flag (label-caps, `--accent`).
- Brand row: masthead title (Newsreader, `--ink`) + search icon + avatar circle (`--ink-inverse`).
- Section ribbon: horizontal scroll, label-caps `--ink-muted`; active = `--ink` + 2px bottom rule; accent section (`--accent`).
- Border-bottom hairline; `bg --canvas/95` + `backdrop-blur-md` (only blur allowed).
### Bottom nav (mobile)
- Fixed bar, 4 items (Edition / Sections / Reader Mode / Saved), icon + 11px label, hairline top border. (Desktop: replaced by persistent top nav.)
### Article header
- Section tag chip (`--accent` label-caps + 4px dot) → `headline-xl` → byline (`--ink` label-meta) → desk • dateline • read time (`--ink-faint`). Hairline under meta.
### Hero plate / figure
- Full-bleed image, max-h 72vh; **grayscale + slightly boosted contrast** (Stitch used `contrast-108`, true B&W look).
- Figcaption: `Fig. N` label-caps `--ink` + plate/credit `--ink-faint`; 1-2 line description `body-sm` `--ink-muted`. Hairline frame.
### Pull quote
- `--surface` well, `4px` left rule `--accent`, giant serif opening quote (`--accent`, 38px, opacity-80), Newsreader italic `quote` text, cite in `--accent` label-caps with hairline above. Sharp corners.
### Photo strip / field notes
- Section header: `label-caps` `--ink` + small icon; "X of Y" `--ink-faint`.
- Grid (1-col mobile, 2-col tablet+). Figures: `--surface` well, 1px hairline frame, 3:2 image, `--accent` label-caps fig caption + body-sm description.
### Feed list (related / subject index)
- Stacked rows divided by hairlines. Each: section tag (`--accent` label-caps), **primary headline (`headline-sm`, 17–18px)**, **sub-headline one step smaller (`headline-sm` 16px)**, deck `body-sm` 13px `--ink-muted`, byline+read time `label-meta` `--ink-faint`. Thumb 3:2 or 16:9 with hairline frame. Hover: row/hairline shifts `--ink-faint`; headline → `--accent`.
- Rows are touch-friendly (min 44px).
### Subject grid boxes (front page)
- Approved: lower boxes titled **World / Politics / Culture / Tech etc.** (subject names). Each box: subject title (`label-caps` `--accent`), latest story **headline 17px** (`headline-sm`), sub-headline 16px, deck 13px, byline. Subject titles stay full strength; story sub-headings step down in size to differentiate tiers.
### Buttons
- Primary: solid `--ink-inverse`, `label-ui` `--on-ink-inverse`, 0px, min-h 42–44px, hover → `--accent`. Include uppercase `label-caps` style for action labels.
- Secondary: 1px `--ink` border, `--ink` label; press = 10% `--ink` tint.
- Text links: 1px underline 3px below baseline, `--accent` or `--ink-faint`.
### Forms
- Underline or 1px bordered box (`--hairline`); focus border → `--ink` (no glow). Placeholder `--ink-faint` in Literata. Sharp corners.
### Newsletter / save modules
- `--surface` or white card, hairline border, `label-caps` `--accent` title, icon, body-sm copy, inline form (input + primary button). HTMX `hx-post` swap-outerHTML.
## Layout (finalized 2026-09-08)
Brand: **Kontra** (centered masthead). Home section heading: **Topics** (not "By Subject").
1. **Front page** (home template):
- **Lead stack**: featured article (hero plate + headline-xl + deck) 2fr + right rail of `headline-md` secondary stories 1fr.
- **Topics grid**: 4 subject boxes (World / Politics / Culture / Tech) — kicker `--accent` label-caps, 17px s-head, 16px s-sub, byline, "More X →". 4-col desktop → 2-col tablet → 1-col mobile. **Approved.**
- **Latest feed**: 2-col article rows (kicker + headline + sub + meta) → 1-col mobile.
2. **Subject index page**: section masthead (`--accent` label-caps + Newsreader title) + lead featured + feed.
3. **Article**: centered 42rem column; hero plate full-bleed to column edge; pull quotes and photo strips within measure; sticky masthead.
4. **Nav**: desktop/tablet persistent top ribbon with **hover dropdowns** per topic (2–3 active stories + "All X →"); mobile ≤640 fixed bottom nav (Edition / Sections / Reader / Saved) where Sections opens a **full-screen drawer** (`<details>`-based, no JS).
5. **Responsive breakpoints**: **≥1024px** 12-col grid / lead+rail; **641–1023px** single-column, 42rem, ribbon scrolls, topics 2-col; **≤640px** single column, topics 1-col, bottom nav replaces ribbon.
Reference implementation: `prototype/` (index.html, article.html, assets/kontra.css).
## Token wiring (for the theme)
- Implement as CSS custom properties on `:root` (the design-token layer).
- Subject accent overrides: each subject sets `--accent`-derived token(s) via a data attribute /
config (per plan: `subjects/<x>/_subject.yaml` → design tokens, admin-editable values, not code).
---
*Source: Stitch panel "The Gazette — Tides of the Outer Reach" (design.png), export Image 2.html, Image 3.markdown.*