One wrapper styles everything a rich-text editor can emit: headings, lists, quotes, rules, tables, code — and every Ghost Koenig card. Templates never style editor output themselves; they wrap it and walk away.
A heading in the display face
Body copy sets at the reading measure with generous leading. Links underline on a hairline, strong goes semibold, and marked text takes the accent wash.
- Lists get quiet markers
- and breathing room between items
The quote takes an accent rule, never a box.Frame & Signal
const frame = (life) => life.filter(m => m.signal > m.noise);
.content — headings · body · lists · quote · code, all inherited
Editor cards
| Card | Treatment |
.kg-width-wide / -full | break out of the prose column without the template knowing |
.kg-bookmark-card | title, description, metadata, thumbnail — stacks on phones |
.kg-callout-card (+ -accent) | emoji + text on a sunken panel |
.kg-toggle-card | native disclosure inside content |
.kg-button-card / .kg-btn | a pill button in the accent |
.kg-header-card · .kg-signup-card | in-content bands; signup rides the inverse surface |
.kg-gallery-card · .kg-embed-card | rows that keep their ratio; embeds default to 16:9 |
.kg-audio-card · .kg-file-card · .kg-product-card | bordered surface cards |
Why not .prose?
Because @tailwindcss/typography owns that class name, and it loads after most imports — its --tw-prose-* colours silently win, and headings go dark in dark mode. A system that ships as a package must never fight a plugin half its users already have installed, so the component is .content.