Stoichos: typography that respects the screen
A demo of stoichos primitives inside Quarto
Premise
Markdown won. Plain-text first, diffable, AI-native, every editor and chat client and static site generator emits and renders it natively. The network effect is enormous and represents real value. Any tool that asks authors to abandon Markdown is fighting a war it cannot win.
But typography on Markdown is bad. The browsers have shipped semantic typography primitives for years — hanging-punctuation, text-wrap: pretty, font-feature-settings, true small caps via smcp and c2sc, variable-font optical-size axes, anchor positioning, container queries — and almost no Markdown-based pipeline exposes any of them.
Stoichos is a Quarto extension that activates them by default and adds a small directive vocabulary for the typographic moments.
What’s in this document
Three shortcodes ({{<· smallcaps ·>}}, {{<· stat ·>}}, {{<· chem ·>}}), one filter (::: aside), and a typography theme that does most of the heavy lifting silently. Each is demonstrated below in context.
This sidebar is a stoichos ::: aside block. On wide viewports it flows in the right margin via Quarto’s column-margin; on narrow it collapses inline. The typography is styled by .nyx-aside.
Inline directives
smallcaps
True OpenType small caps via font-feature-settings: "smcp", "c2sc". Replaces Quarto’s default fake-smallcaps (text-transform: lowercase + font-size: 0.8em), which is typographically incorrect.
The OpenType feature smcp maps lowercase letters to designed small-cap glyphs; c2sc additionally maps uppercase letters so that
NASAbecomes a small-capnasainstead of a same-size sequence. Both ship in stoichos by default.
stat
Typed inline values with format and color tier. Tabular figures + lining nums via font-variant-numeric; color tier maps to one of danger | warning | info | success.
In a recent benchmark, schema-constrained extraction failed at 90% hallucination rates for models below 32B parameters. Models above 70B held the failure rate to 7%, with an average inference cost of $12.4 per million tokens.
chem
Auto-subscripts trailing digits in chemical formulas. Pure regex; no MathJax round-trip required.
Photosynthesis: 6 CO2 + 6 H2O → C6H12O6 + 6 O2.
Sulfuric acid: H2SO4. Calcium hydroxide: Ca(OH)2.
large-letter
Inline oversized letter via the float-left technique. Works in every browser. Use anywhere in prose; this is not a dropcap (the paragraph-level ::: dropcap filter further down does that).
Typography exists to honor content. The large initial above is just a span — <span class="nyx-large-letter">T</span> — floated and sized via CSS. For a true paragraph-level dropcap with initial-letter baseline alignment, see the dropcap filter below.
Block directives
aside (filter)
Already demonstrated above. Marginalia in the right column on wide screens, inline collapse on narrow. Authors write ::: aside; the filter adds column-margin (Quarto layout) and nyx-aside (stoichos styling).
pullquote (direct class)
Pullquotes use the SCSS class directly — no shortcode needed for v0.1, since fenced-div syntax handles it cleanly:
Typography exists to honor content. — Robert Bringhurst
epigraph (direct class)
Same pattern:
The traditional way is to put off all annoying decisions until the last possible moment.
diff (filter)
The diff filter walks fenced code blocks with class diff and emits per-line spans with nyx-diff-line--add / --del / --hunk classifications. The CSS handles the green/red/blue tinting + monospace + Catppuccin-friendly palette.
@@ -1,4 +1,5 @@- function format_stat(value, format)- return string.format("%g", value)+ function format_stat(value, format, color)+ local display = format_number(value, format)+ return wrap_class(display, color) end
A second example with a language hint ({.diff lang=ts} would set data-lang="ts" for future per-line syntax highlighting; v0.2):
@@ -10,3 +10,3 @@- const measure: string = "65ch";+ const measure: string = "66ch";
Modern CSS, activated
The theme silently activates several browser-shipped primitives most Markdown pipelines don’t reach for:
hanging-punctuation: first last— quotes hang into the margin (best in Chromium/Safari; Firefox partial)text-wrap: pretty— body prose wrapping uses Knuth-Plass-adjacent line breaking (Chromium 114+)text-wrap: balance— headings and pullquotes get balanced line lengths (Chromium 114+, Safari 17+)font-feature-settings: "kern", "liga", "calt", "onum"— kerning, ligatures, contextual alternates, oldstyle figures by default in body prosefont-variant-numeric: oldstyle-nums proportional-nums— narrative numbers don’t shout- Variable-font optical-size axes via Fraunces (
opsz 9–144) and Source Serif 4 (opsz 8–60) — type adjusts metrics at scale
None of these require user opt-in. Drop the theme into _quarto.yml and the typography appears.
Compatibility
| Feature | Chromium / Edge | Safari 17+ | Firefox |
|---|---|---|---|
hanging-punctuation: first |
✓ | ✓ | partial |
hanging-punctuation: last |
✓ | ✓ | ✗ (falls back gracefully) |
text-wrap: pretty |
✓ (114+) | partial | ✗ (falls back to normal) |
text-wrap: balance |
✓ (114+) | ✓ (17+) | ✓ (121+) |
font-feature-settings: smcp, c2sc |
✓ | ✓ | partial (smcp ✓, c2sc varies) |
font-variant-caps: all-small-caps |
✓ | ✓ | ✓ |
font-variant-numeric |
✓ | ✓ | ✓ |
| Variable-font optical sizing | ✓ | ✓ | ✓ |
System-font fallbacks apply when Fraunces / Source Serif 4 / JetBrains Mono fail to load.