Conditions

The stylesheet holds every visual choice. This page covers how those choices vary: by environment and by what the surface is for. There is no view-selection engine — no scoring, no extends, no “pick one profile” step. Variation is exactly what the CSS cascade already does: rules guarded by conditions, resolved by layers, specificity, and source order.

Environment conditions — real @media

Anything the rendering environment can answer is a native media query, so a bare file adapts in any browser with zero tooling:

Axis Spelling
medium @media screen, @media print
viewport width / height (min-width: …), (max-width: …)
orientation (orientation: portrait | landscape)
color capability (monochrome), (color) — e-ink targets
pointer / hover (pointer: coarse | fine), (hover: hover | none)
pixel density (min-resolution: …)
color scheme light-dark() values + color-scheme (see Theming)

The engine evaluates the same enumerated feature set in JS wherever a live browser cascade isn’t available — the paginator, print materialization, EPUB encoding, and preview emulation: the app can enumerate every condition a sheet mentions and render it under a forced environment (a monochrome e-reader, a narrow phone, the printed page), using the same transform the EPUB encoder uses — so preview-on-device is what the export gets.

App conditions — data-spub-* guards

What the environment can’t answer — what the surface is for, which device profile is targeted, which export is running — is applied by the app (or the export pipeline) as attribute tokens on the document root, and tested by ordinary attribute selectors:

html[data-spub-intent~="edit"] main { --spub-editor-current-line: highlight; }
html[data-spub-device~="ereader"] main { font-family: serif; }
html[data-spub-package~="epub"] main { max-width: none; }
Axis Attribute Tokens
intent data-spub-intent write · edit · read · skim · annotate · proof · cover · snippet
device data-spub-device the class vocabulary phone · tablet · desktop · ereader and open device-profile ids (kindle-paperwhite) in one list — either matches
export syntax data-spub-syntax syntax ids, during an export render pass
package data-spub-package package ids (epub), during package encoding
scheme data-spub-scheme light | dark — the app’s explicit override

The attributes are runtime state, never serialized into a file. In a bare browser they are absent, every guard is inert, and the unguarded rules apply — so a bare file is the read-on-screen posture, by construction. A guard adds attribute specificity, so a rule stating more conditions beats one stating fewer — the browser enforces what the old scoring engine used to compute.

The reader’s own layer

The app composes two more layers around every document (spec §Layers): the user’s Default Style (sp-user) fills in under the document’s sheet — the document’s stated choices win, the user’s cover the gaps — and flipping “always use my style” moves it above (sp-tweaks), together with any per-surface runtime tweaks. The app may hold several Default Styles scoped by surface (a reading default, an editing default), all composing into this layer. Both are app state; a serialized document never carries them.

What replaced the old model

config.views, use clauses, extends/abstract, the selection scorer, and the layout patch cascade are gone (pre-release — no back-compat). Their successors: guards + media queries (conditions), @layer order (inheritance), and --spub-* settings (the non-CSS knobs). The old theme group dissolved too: light/dark is light-dark() + color-scheme (see Styling — Theming). Named alternative stylings (“Looks”) were also part of this rework but have been removed — alternative tastes belong to the reader’s own layer above, not the document.