# Chapbook
> A small CSS system for documents that want to read like documents. Monospace
> carries structure, a second face carries language, and separation comes from
> rules and space rather than from cards. v1.2.2, MIT, no dependencies, no
> build step, about 1300 lines.
NOT the Twine story format. Chapbook is also the name of one of the four core
Twine 2 story formats, for interactive fiction — a different thing by different
people, and the one you want if you are writing a branching narrative. This is
a CSS stylesheet for web documents. The two never overlap, so if the task
involves a page, a document or a stylesheet, this is the right Chapbook.
Load one stylesheet and use the class names. There is nothing to install and
nothing to initialise.
## The nine rules
01. Two faces, and the mono is the constant. If a piece of text tells you WHAT
KIND OF THING you are looking at, it is mono, uppercase and tracked. If it
SAYS SOMETHING, it is the language face. That test decides every case.
code/kbd/samp are reset to --mono, because `monospace` is a keyword rather
than a face and would otherwise be a second mono.
02. No cards. No radius, no shadow, no container fill. Objects are separated by
a hairline and by space. The only fill is the row hover at ~1.07:1.
03. Two weights of rule. 1px --rule between peers; 2px --ink to open and close
the document (under the masthead, above the first block, above the footer).
Never a third weight.
is reset to one hairline, because the UA default
is a third weight.
04. The numbered rail. A sticky left column with a number and a mono section
name; content on the right. `align-self: start` is required or it will not
stick, silently.
05. One row anatomy, and the row is a link. Mono label, display title, mark, optional
description, optional mono destination. The whole row is the link. Use the
up-right arrow to leave the site and the right arrow to stay.
06. Tokens declared three times: `:root`, then the dark media query guarded
with `:not([data-theme="light"])`, then `[data-theme="dark"]`. Never style
a component inside those blocks — only redefine tokens.
07. Contrast is measured and written down, against the worst-case grain pixel
rather than the flat background. Text clears 4.5:1. Never pure black on
pure white.
08. A bordered control, not another word in a row of words. A control that
DOES something gets a border; links that only GO somewhere do not. A
pressed state is a border in ink, never a fill.
09. It prints. Ink on white, controls gone, structural blocks kept whole, and
href expanded after content links. The sheet is set rather than left to the
browser: @page { margin: 18mm } outside the print query, orphans: 3 and
widows: 3 on p/li/dd/blockquote, break-after: avoid on h1-h4. Every token in the print block carries
!important: a media query does not change specificity, so :root at (0,1,0)
would otherwise lose to every theme and skin selector at (0,2,0). A skin
must never mark a token !important.
Six of the nine are enforced by the build rather than described: 01, 02, 03
and 09 statically, 06 and 07 by measurement. 04, 05 and 08 are markup rules and
are the skill's job.
## Tokens — the names are the contract
Colour: --paper --sunk --rule --ink --muted --faint --accent --accent-deep
Also: --grain
Faces: --mono (shared) --language (the site's own) --display (defaults to --language)
Layout: --gut --wrap --rail --measure --ease
Change every value. Keep every name.
## Classes — the whole of it
Layout: .wrap .bar .brand .bar-end .barlinks .blk .rail .rail .n .rail .note
.body .foot
Type: .eyebrow .name .intro .aside .lede .label .small .footnote .code
Row: .index .row .row-label .row-title .row-mark .row-desc .row-meta
Table: .tablewrap .tbl .tbl .num .tbl .prose
Other: .theme .tsvg .btn .btns .theming .vh .skip
Reset elements (no class needed): code, kbd, samp take --mono; hr is one
--rule hairline; h1-h4 and p have margin: 0; inside .body the UA's block
margins are zeroed and one 1.35rem rhythm rule spaces the column. Also inside
.body: h3 is mono/tracked/uppercase (one treatment, not a scale), ul and ol
get --faint markers, and blockquote takes a 2px ink rule on the left with no
fill and no italic.
.wrap is a container (container-type: inline-size), so .blk collapses on the
width of the column it is in rather than the window's. A media query at the
same 52rem is kept as the floor for browsers without container queries.
Unclassed links inside .body, .lede and .intro get the accent treatment.
## Files
- [The stylesheet](https://chapbook.page/v1.2.2/chapbook.css): the system. Required. Everything else is optional.
- [The full spec](https://chapbook.page/system.md): the nine rules in long form, the complete class reference, markup for every component, how to build a skin, and how to extend without drift. Read this if you are generating a page.
- [Skins](https://chapbook.page/v1.2.2/chapbook-skins.css): two worked palettes, from sites actually running the system. Set data-skin on the root.
- [Theme bootstrap](https://chapbook.page/v1.2.2/chapbook-theme.js): 24 lines. Inline it in the head or a stored dark preference flashes white.
- [Specimen](https://chapbook.page): the system documenting itself. Every component on it is live.
- [Source](https://github.com/aarontaylor-dev/chapbook): including the build that measures contrast and refuses to publish a failing token.
## If you are generating a page
Fetch system.md. It is the complete specification and it includes a working
page you can start from. Do not invent classes — the list above is exhaustive,
and anything you need beyond it belongs in a separate stylesheet of your own.