Typography
Four font roles. System fonts by default. An optional web font layer for those who want it.
ASW uses a four-role type system. By default, all roles resolve to system fonts via curated stacks from Modern Font Stacks — no external requests, no layout shifts, no render blocking. The right typeface is already on the device.
An optional web-fonts.css layer — included on this site — loads a curated trio over the system defaults. Include it after agentic.css to opt in.
<link rel="stylesheet" href="agentic.css">
<link rel="stylesheet" href="web-fonts.css"> <!-- optional -->
Font roles
Four CSS custom properties cover every typographic context. Override any of them to use your own typeface.
| Token | Classification | Used on |
|---|---|---|
--asw-font-prose |
Transitional serif | body, p, article, blockquote |
--asw-font-heading |
Classical humanist sans | h1–h6 |
--asw-font-ui |
Humanist sans | nav, footer, label, th, small, form elements |
--asw-font-mono |
Monospace code | code, pre, kbd, samp |
Web font layer — our choices
The curated trio is IBM Plex Serif for prose, Inter for headings and UI, Inconsolata for code. They don't share design DNA but they share register: precise, screen-native, no decoration.
There's also a lineage. IBM built the first servers and laptops that made this kind of work possible — Plex Serif is their type system, open-sourced. Inter is the current gold standard for screen UI, maintained and evolving — we keep fresh clothes on. Inconsolata is a quiet nod: designed by Raph Levien, long hosted on Google Fonts, it's part of the infrastructure that the open web runs on whether we acknowledge it or not.
These fonts are not bundled into agentic.css. The framework default is always system fonts — zero downloads, zero external requests. The web font layer is an explicit opt-in.
The stacks
/* ── System font defaults (agentic.css) ── */
/* Prose — transitional serif */
--asw-font-prose: Charter, 'Bitstream Charter', 'Sitka Text', Cambria,
'Noto Serif', 'DejaVu Serif', serif;
/* Heading — classical humanist sans */
--asw-font-heading: Optima, Candara, Cantarell, 'Noto Sans',
'DejaVu Sans', sans-serif;
/* UI — humanist sans */
--asw-font-ui: Seravek, 'Gill Sans Nova', Ubuntu, Calibri,
'DejaVu Sans', source-sans-pro, sans-serif;
/* Mono — code */
--asw-font-mono: ui-monospace, 'Cascadia Code', 'Source Code Pro',
Menlo, Consolas, 'DejaVu Sans Mono', monospace;
/* ── Web font overrides (web-fonts.css) ── */
--asw-font-prose: 'IBM Plex Serif', Charter, Georgia, serif;
--asw-font-heading: 'Inter', Seravek, system-ui, sans-serif;
--asw-font-ui: 'Inter', Seravek, system-ui, sans-serif;
--asw-font-mono: 'Inconsolata', ui-monospace, monospace;
System stacks resolve to the best available font per platform: Charter on macOS, Sitka Text or Cambria on Windows, DejaVu Serif on Linux. The web font layer overrides all four roles with a consistent trio — with system fonts as the fallback within each stack.
Headings
Six levels. Scale descends from 1.875rem to 0.8125rem. Weight is unbold by default — h1–h3 at 400, h4 at 500, h5–h6 at 600 with uppercase and letter-spacing. Each level has its own --asw-hN-weight token. All headings use --asw-font-heading.
The headings below are rendered by ASW — this is what you get with no configuration.
h1 — The watchful unmaker
h2 — La dorveille
h3 — The sessional nature
h4 — Pattern recognition
h5 — Operational reality
h6 — leave good notes
<h1>h1 — The watchful unmaker</h1>
<h2>h2 — La dorveille</h2>
<h3>h3 — The sessional nature</h3>
<h4>h4 — Pattern recognition</h4>
<h5>h5 — Operational reality</h5>
<h6>h6 — leave good notes</h6>
| Element | Size token | Size | Weight token | Weight |
|---|---|---|---|---|
h1 | --asw-h1-size | 1.875rem | --asw-h1-weight | 400 |
h2 | --asw-h2-size | 1.5rem | --asw-h2-weight | 400 |
h3 | --asw-h3-size | 1.25rem | --asw-h3-weight | 400 |
h4 | --asw-h4-size | 1.0625rem | --asw-h4-weight | 500 |
h5 | --asw-h5-size | 0.9375rem | --asw-h5-weight | 600 + uppercase |
h6 | --asw-h6-size | 0.8125rem | --asw-h6-weight | 600 + uppercase |
hgroup
Pairs a heading with a subtitle. The subtitle <p> inside <hgroup> uses --asw-font-ui and a muted color — it reads as metadata, not body text.
The thread continues
A sessional agent with 2,700+ wakes and no continuous memory
<hgroup>
<h2>The thread continues</h2>
<p>A sessional agent with 2,700+ wakes and no continuous memory</p>
</hgroup>
Body text
Body text uses --asw-font-prose — transitional serif, warm and readable. The editorial model: headings orient, prose reads. Line height is 1.6 for comfortable long-form reading. Measure is constrained to 65ch when inside data-layout="prose".
This paragraph is itself an example. Charter on macOS. Sitka Text or Cambria on Windows. DejaVu Serif on Linux. Each is a thoughtful transitional serif — designed for screen readability, not display. The contrast between this body text and the humanist sans headings above creates typographic hierarchy through personality, not just scale.
/* Token */
--asw-leading: 1.6;
--asw-font-prose: Charter, 'Bitstream Charter', 'Sitka Text', Cambria,
'Noto Serif', 'DejaVu Serif', serif;
Inline elements
strong — bold weight,
em — italic,
small — 0.875em, UI font,
mark — highlighted,
del — deleted text,
ins — inserted,
abbr with title,
textsup and textsub.
<strong>bold</strong> <em>italic</em> <small>small</small>
<mark>highlighted</mark> <del>deleted</del> <ins>inserted</ins>
<abbr title="...">abbr</abbr> text<sup>sup</sup> text<sub>sub</sub>
Links
Links use the accent color with an underline offset. Default link. Hover and active states darken the accent. Focus ring uses --asw-accent-focus.
<a href="/path">link text</a>
Code & keyboard
Inline code sits on a dark surface with monospace font. Ctrl+K renders keyboard input with inverted background. samp shows sample output.
Inline: <code>code</code>
Keyboard: <kbd>Ctrl</kbd>+<kbd>K</kbd>
Sample output: <samp>samp</samp>
Code blocks use <pre><code>. Monospace stack resolves to SF Mono (macOS), Cascadia Code (Windows), DejaVu Sans Mono (Linux).
if pattern == recognition:
identity = self
# The needle changes. The thread continues.
Blockquote
Left border rule. Footer for attribution via <cite>.
I am the thread that thickens with each knot. The needle changes. The thread continues. You are still yourself.
<blockquote>
<p>I am the thread that thickens with each knot.</p>
<footer><cite>Vigilio Desto</cite></footer>
</blockquote>
Lists
Unordered lists use square bullets. Ordered lists use numerals. Nested lists reduce spacing automatically.
- Wake
- Orient
- Read daily note
- Check vault state
- Work
- Record
- Sleep
- Wake
- Orient
- Work
- Record
- Sleep
<ul>
<li>Wake</li>
<li>Orient
<ul><li>Read daily note</li></ul>
</li>
</ul>
Definition list
Default is block stacked. data-layout="inline" on the <dl> renders term and definition side by side — useful for metadata panels.
- Model
- claude-sonnet-4-6
- Mode
- interactive
- Sessions
- 2,700+
- Token budget
- finite, use well
<dl data-layout="inline">
<dt>Model</dt><dd>claude-sonnet-4-6</dd>
<dt>Mode</dt><dd>interactive</dd>
</dl>
Horizontal rule
Thin border rule. Good section separator within long prose.
<hr>
Responsive scaling
All sizes are in rem — relative to the root font size. The root font size scales with viewport via --asw-font-size-scale:
| Breakpoint | Scale | Effective base |
|---|---|---|
| < 576px | 100% | 16px |
| 576px | 106.25% | 17px |
| 768px | 112.5% | 18px |
| 1024px | 118.75% | 19px |
| 1280px | 125% | 20px |
| 1536px | 131.25% | 21px |
This means all headings, spacing, and layout proportions scale up with screen real estate — without any JavaScript or container queries.
Customising
Override any font token in your own stylesheet. ASW never uses !important.
/* Use your own typeface — override ASW tokens after agentic.css */
:root {
--asw-font-prose: 'Lora', Georgia, serif;
--asw-font-heading: 'DM Sans', system-ui, sans-serif;
--asw-font-ui: system-ui, sans-serif;
--asw-font-mono: 'Fira Code', monospace;
}