Documentation
Design tokens
DataLeaf’s visual language is defined by CSS custom properties in the theme’s assets/css/tokens.css. Components use only these tokens, so a site can adjust the design by overriding them in custom CSS without touching component selectors. The regression tests keep this page in sync with the stylesheet and check that the default colors meet WCAG 2.2 AA in both color schemes.
The design is editorial rather than app-like: reading text and titles are set in a serif, the interface and metadata in a sans, and structure comes from thin rules, alignment, and whitespace instead of cards and shadows. Color is restrained: one accent for links and focus, a muted second color for annotations, and semantic tints for callouts.
Typography
#Typeface families
#Each stack names the bundled face first, then installed fonts of similar proportions, so the design holds when the bundle is disabled. With the bundle, a metric-matched fallback follows each text face: Arial or a metric-compatible clone for IBM Plex Sans, and Georgia, or Times New Roman and its clones where Georgia is missing, scaled to the width of Source Serif 4. Text is set in it while the bundled fonts load, so lines keep their breaks and the page does not shift when the fonts arrive. IBM Plex Sans, the interface face, is preloaded and loaded with font-display: optional: it is used from the first render when it arrives promptly, and otherwise from the next page, so a late font never rewraps the navigation.
| Token | Default | Role |
|---|---|---|
--dl-font-serif | "Source Serif 4", "Source Serif 4 Fallback", "Source Serif 4 Times Fallback", "Source Serif Pro", "Iowan Old Style", "Charter", "Bitstream Charter", "Sitka Text", Cambria, Georgia, serif | Editorial serif for reading text and titles |
--dl-font-sans | "IBM Plex Sans", "IBM Plex Sans Fallback", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif | Sans-serif for navigation, metadata, captions, and labels |
--dl-font-mono | "IBM Plex Mono", ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, "Liberation Mono", monospace | Monospace for code |
--dl-font-math | "STIX Two Math", "Cambria Math", "Latin Modern Math", "Libertinus Math", "TeX Gyre Pagella Math", "DejaVu Math TeX Gyre", "Noto Sans Math", math | MathML fonts with OpenType MATH tables |
Typeface roles
#Components choose a role, not a family. To set reading text in the sans, override --dl-font-body with var(--dl-font-sans).
| Token | Default | Role |
|---|---|---|
--dl-font-display | var(--dl-font-serif) | Titles, headings, and entry titles in lists |
--dl-font-body | var(--dl-font-serif) | Prose, ledes, and summaries |
--dl-font-ui | var(--dl-font-sans) | Interface text, metadata, captions, and labels |
--dl-font-code | var(--dl-font-mono) | Code blocks, inline code, and code labels |
Font strategy
#The theme bundles Source Serif 4, IBM Plex Sans, IBM Plex Mono, and STIX Two Math under the SIL Open Font License 1.1 and serves them from your own site: no font service, CDN, or tracking request is involved. Browsers download a file only when a page renders characters in that face and its unicode-range; a typical English page needs about 140 KB, and STIX Two Math (about 400 KB) loads only on pages with formulas when it is not installed.
To rely on installed fonts instead, disable the bundle:
[params.fonts]
bundled = falseThe theme then publishes no font files and no @font-face rules. The family stacks above fall back to installed fonts: Iowan Old Style, Charter, Sitka Text, Cambria, or Georgia for the serif; the system interface font for the sans; and the system monospace. A locally installed copy of a bundled family is still used when present. To use other web fonts, keep the bundle disabled, declare your own @font-face rules in custom CSS, and override the family tokens.
Type scale
#Interface sizes are fixed; reading text and titles grow slightly with the viewport.
| Token | Default | Role |
|---|---|---|
--dl-text-xs | 0.8125rem | Kickers, labels, archive dates, and code labels |
--dl-text-sm | 0.875rem | Metadata, captions, tags, site tools, and status messages |
--dl-text-ui | 0.9375rem | Table-of-contents links |
--dl-text-md | 1.0625rem | Primary navigation, summaries, search excerpts, and list entry titles |
--dl-text-prose | clamp(1.0625rem, 1rem + 0.25vw, 1.1875rem) | Body text of articles and pages |
--dl-text-lg | 1.25rem | Ledes, fourth-level headings, and adjacent-article titles |
--dl-text-xl | clamp(1.375rem, 1.25rem + 0.5vw, 1.5rem) | Third-level headings and entry titles |
--dl-text-2xl | clamp(1.625rem, 1.4rem + 0.9vw, 2rem) | Second-level headings, section titles, and the masthead site title |
--dl-text-3xl | clamp(1.875rem, 1.5rem + 1.2vw, 2.5rem) | Article titles |
--dl-text-display | clamp(2.25rem, 1.75rem + 1.6vw, 3rem) | The home page title |
Line height, tracking, and weight
#| Token | Default | Role |
|---|---|---|
--dl-leading-tight | 1.1 | Display, article, and masthead titles |
--dl-leading-heading | 1.25 | Headings and entry titles |
--dl-leading-ui | 1.5 | Interface text and ledes |
--dl-leading-code | 1.55 | Code blocks |
--dl-leading-prose | 1.65 | Body text |
--dl-tracking-display | -0.02em | The home page title |
--dl-tracking-title | -0.015em | Article titles and the masthead site title |
--dl-tracking-caps | 0.08em | Uppercase kickers and labels |
--dl-weight-regular | 400 | Body and interface text |
--dl-weight-strong | 600 | Headings and bold text; the bundled faces have no heavier weight |
Rhythm
#Paragraph spacing is relative to the text it separates, so it follows the body size.
| Token | Default | Role |
|---|---|---|
--dl-flow-space | 1em | Space between paragraphs, lists, and display equations |
--dl-block-space | var(--dl-space-6) | Space around code, tables, figures, callouts, and statements |
--dl-heading-space | clamp(var(--dl-space-6), 5vw, var(--dl-space-7)) | Space before article headings and thematic breaks |
Layout
#| Token | Default | Role |
|---|---|---|
--dl-wide | 1180px | Page shell: header, main content, and footer |
--dl-gutter | var(--dl-space-4) | Minimum space between the shell and the viewport edge |
--dl-reading | 42rem | Manuscript column: the reading measure of articles and pages, and the minimum width of wide technical content |
--dl-reading-narrow | 37rem | Ledes and list summaries |
--dl-rail | 16rem | Article side rail with the metadata and table of contents, from 72rem |
--dl-wide-content | 60rem | Maximum width of wide technical content: tables, display equations, code, and figures marked wide |
--dl-meta-width | 6rem | Narrow metadata columns, such as archive years and dates |
--dl-control-height | 2.5rem | Minimum height of navigation links, site tools, and controls |
Breakpoints
#Media queries cannot read custom properties, so the layout changes at four fixed widths rather than at tokens. Visual checks cover 320, 375, 768, 1024, 1280, 1440, and 1920px around them.
| Name | Width | What changes |
|---|---|---|
| compact | below 32rem (512px) | List entries, archive rows, and pagination stack in one column |
| medium | 40rem (640px) | Site tools are separated by hairlines, the footer sits on one line, and previous and next articles sit side by side |
| large | 64rem (1024px) | The front page sets its introduction and latest writing in two columns |
| wide | 72rem (1152px) | Articles and discovery pages gain the side rail, with metadata and a sticky table of contents |
Spacing
#Components use these steps rather than one-off values.
| Token | Default | Role |
|---|---|---|
--dl-space-1 | 0.25rem | Hairline gaps: list items, label offsets |
--dl-space-2 | 0.5rem | Tight gaps: metadata, captions, small controls |
--dl-space-3 | 0.75rem | Control padding and compact rows |
--dl-space-4 | 1rem | Default gap and block padding |
--dl-space-5 | 1.5rem | List entries and section padding |
--dl-space-6 | 2rem | Separation between blocks |
--dl-space-7 | 3rem | Separation between page regions |
--dl-space-8 | 4rem | Large page padding |
--dl-space-9 | 6rem | Section separation on wide screens |
Surfaces and shape
#| Token | Default | Role |
|---|---|---|
--dl-radius | 0 | Corner radius of content blocks; square by default |
--dl-radius-control | 0.25rem | Corner radius of form controls and buttons |
Color
#Dark mode is a separate palette for reading on a dark ground, not an inversion: a warm charcoal page rather than black or navy, warm off-white text, a lighter and less saturated accent, strong rules softened to grey so tables and lists do not glare, and its own code surface and syntax colors. Figures keep a light backdrop. Both the automatic and the explicit scheme use it, and the browser interface color (theme-color) follows --dl-bg in each. Tokens without a dark value keep their light value; role tokens such as --dl-link follow the color they reference.
Surfaces and text
#| Token | Light | Dark | Role |
|---|---|---|---|
--dl-bg | #fbfaf7 | #171614 | Page background |
--dl-surface | #ffffff | #201f1c | Raised surfaces: inputs, tables, the table of contents |
--dl-figure-bg | #ffffff | #f3f1ec | Backdrop behind figure images; light in both schemes for transparent plots |
--dl-text | #1c1b18 | #e9e5dc | Body text |
--dl-text-soft | #5c5850 | #a9a397 | Metadata, captions, and secondary text |
--dl-border | #dedad1 | #35332e | Hairline rules and borders |
--dl-rule | #1c1b18 | #8f897d | Strong rules: tables, list openings, archive years, pagination, and the search field; keep at 3:1 or more against the background |
--dl-control-border | #857f74 | #857f72 | Form-control boundaries; keep at 3:1 or more against the background |
--dl-accent-bg | #f1eee7 | #26241f | Subtle background changes, such as table headers |
--dl-header-bg | var(--dl-bg) | same | Header background |
--dl-selection-bg | #d3e0f1 | #2e4566 | Selected text |
Roles
#| Token | Light | Dark | Role |
|---|---|---|---|
--dl-primary | #1f4e8c | #9fbde6 | Accent color |
--dl-primary-strong | #163a68 | #c3d6f1 | Stronger accent for hover and pressed states |
--dl-secondary | #8c3a26 | #e3a690 | Muted second color |
--dl-link | var(--dl-primary) | same | Links |
--dl-link-hover | var(--dl-primary-strong) | same | Hovered links |
--dl-annotation | var(--dl-secondary) | same | Annotations: kickers, footnote markers, and highlighted code lines |
--dl-focus | #1f4e8c | #9fbde6 | Focus indicators |
--dl-mark-bg | #f2e3b3 | #3d3418 | Technical emphasis: highlighted text marked with mark |
--dl-inline-code-bg | #ece8df | #2b2925 | Inline code |
Callouts and statements
#Callouts keep a restrained tint and a rule in their semantic color. Mathematical statements have no tint: a thin rule in the colors below and a small label identify them.
| Token | Light | Dark | Role |
|---|---|---|---|
--dl-callout-bg | #f1f4f8 | #1d2129 | Note callout background |
--dl-tip-bg | #f1f6f1 | #1b231d | Tip callout background |
--dl-warning-bg | #fbf6e9 | #26221a | Warning callout background |
--dl-important-bg | #fbf0ed | #281d1a | Important callout background |
--dl-tip-rule | #3b7650 | #7fb491 | Tip callout rule |
--dl-warning-rule | #94660f | #d2a75a | Warning callout rule |
--dl-important-rule | #a33d2c | #e0907f | Important callout rule |
--dl-definition-rule | #2c6b67 | #7cbbb5 | Definition rule |
--dl-remark-rule | #7a756a | #a9a397 | Remark rule |
--dl-example-rule | #6a4a86 | #b89fd0 | Example rule |
Code
#Code sits on a quiet tint of the page between hairlines, with a restrained syntax palette in each scheme.
| Token | Light | Dark | Role |
|---|---|---|---|
--dl-code-bg | #f3f0e8 | #1f1e1b | Code block background |
--dl-code-text | #1c1b18 | #ebe8e1 | Code text |
--dl-code-border | #dedad1 | #35332e | Hairlines above and below code, and the line-number rule |
--dl-code-muted | #625e55 | #a39d90 | Line numbers and language labels |
--dl-code-highlight | #e9e3d3 | #2e2c27 | Highlighted lines |
--dl-code-comment | #625e55 | #a39d90 | Comments |
--dl-code-keyword | #6b2f7a | #cdb0ea | Keywords |
--dl-code-string | #2d6a3e | #a5d4a5 | Strings |
--dl-code-function | #8a4a0c | #e8bc84 | Function, class, and attribute names |
--dl-code-number | #a23a28 | #f0a491 | Numbers |
--dl-skip-bg | #1c1b18 | #e9e5dc | Skip-link background |
--dl-skip-text | #fbfaf7 | #171614 | Skip-link text |