Brio in plain HTML
A small CSS library is mostly an opinionated stylesheet over semantic markup. The
.prose class is the part that handles long-form content, the kind of
writing where you'd otherwise reach for a CMS theme or a typography reset.
Why prose
Most pages in a docs site or knowledge base aren't single components. They're
paragraphs, headings, code blocks, lists, occasional images, the rare blockquote.
Each could be wired up with its own class, but the volume makes that tedious. Bare
HTML inside a single .prose wrapper is faster to write, faster to read,
and survives copy-paste from external sources.
Lists
Unordered
- Sets typography for headings, paragraphs, links, lists, blockquotes.
- Styles tables and definition lists when they aren't classed.
-
Adds visual chrome to
<details>,<kbd>,<abbr>,<mark>, and friends. -
Survives nesting:
- Indents naturally.
- Uses muted markers.
-
And nests further:
- Three levels deep stays readable.
- Each level inherits the rhythm.
Ordered
- Author the markup.
- Wrap in
.prose. - Ship.
Task lists
- Port v0.1 components to brio.
- Add the v0.2 extras layer.
- Write a real consumer site.
- Retire the transfer manifest.
Blockquotes
The best way to predict the future is to invent it. Hype-driven front-end churn invents it for us, in the worst possible direction.
A small library you fully understand beats a large one you rent.
— Brio, internal philosophy notes
Inline elements
Inline code is set in
--font-mono with a quiet --color-fill-subtle background,
so references like --prose-margin-block or
document.querySelector() read distinctly without yelling.
Press Cmd + K to open the command palette. The Esc key dismisses it.
Abbreviations get a dotted underline and a help-cursor: CSS handles the visual layer, HTML carries the structure, and JS only enters where the platform falls short.
Use highlighted text sparingly -- it's loud enough that one or two phrases per article register; more, and the eye stops noticing.
Strikethrough text comes in two flavors:
deleted content for editorial removal and obsolete syntax for
things the language used to accept.
Tables
Bare tables get a quiet treatment -- no outer border, just header underline and row
dividers. Use a classed
<table class="table"> for the full component (with hover,
striping, density, etc.).
| Token | Default | Purpose |
|---|---|---|
--prose-margin-block |
--space-sm-md |
Block-axis margin between direct children. |
--prose-max-width |
65ch |
Readable line length for long-form content. |
--prose-blockquote-border-color |
--color-border-strong |
Inline-start accent on blockquotes. |
--prose-blockquote-border-width |
3px |
Width of the blockquote accent. |
Definition lists
- Atom
-
A small, self-contained component.
.button,.input,.badge. - Composition primitive
-
Layout helper that arranges children.
.cluster,.stack,.media. - Slotted container
-
A root with named child slots.
.tabs,.timeline,.stat.
Disclosure
What's inside a bare <details>?
Prose adds a quiet border, padding, and a custom rotating chevron via
::before on the summary. The expand-collapse animation comes from
brio's global details.css (which applies to every
<details>); prose only adds the visual chrome.
Reach for <details class="details">
when you want brio's full component (richer chrome, token-driven theming, hover
states).
Images and figures
Footnotes and rules
Inline references can point to numbered footnotes
1 at the end of the article. Goldmark and other
GFM-flavor markdown processors emit a .footnotes section automatically.
Horizontal rules make natural breakpoints in long articles -- shifting topics, separating an aside from the main flow, marking the end of the body before footnotes. Prose gives them a quiet 1px line and generous block-margins.
-
Footnotes use
.footnotesas the section wrapper. Prose drops the font size a step so the metadata sits below the body without competing. ↩