Typography

arXiv sets all text in the IBM Plex family with STIX Two Math for notation, self-hosted — no external font services.

The stack

The type family is IBM Plex, plus STIX Two Math for notation. Each face has a job.

IBM Plex Sans

Body text — paragraphs, author names, abstracts, UI.

Gauge-independent approach to inflation in quadratic gravity
We explore inflation driven by the Starobinsky-like R + R² term using a manifestly gauge-independent approach to cosmological perturbation theory.
Regular 400Medium 500Semibold 600
Relevant code
font-family: var(--ds-font-sans);
--ds-font-sans
The default: where no other face applies, this is the answer. Weights 400 / 500 / 600.

IBM Plex Sans Condensed

Labels & captions — metadata labels, table headers, uppercase section labels.

SUBJECTS · DOI · LICENSE · ANCILLARY FILES
ArXiv identifierJournal DOIWho cites this paper
Relevant code
font-family: var(--ds-font-condensed);
--ds-font-condensed
Labels, captions, table headers and metadata, usually small and uppercase. Weights 500 / 600.
.ds-panel-label
The ready-made label in this face; see Panel label below.

IBM Plex Mono

Code & identifiers — arXiv IDs, DOIs, BibTeX, code blocks.

arXiv:2604.22725 [gr-qc]
@article{palomares2026gauge, doi={10.48550/arXiv.2604.22725}}
Relevant code
font-family: var(--ds-font-mono);
--ds-font-mono
Identifiers and code. Weights 400 / 500. Inline <code> and <pre> already use it; see Code blocks below.

IBM Plex Serif italic

Annotation voice — footnote text and figure alt-text in the reader margins. “The editor speaking quietly next to the body text.”

Starobinsky's 1980 model adds only the R² term; the resulting scalaron drives inflation while leaving the gravitational sector otherwise unmodified.
Relevant code
<p class="ds-annotation">Figure 2: the scalaron potential.</p>
.ds-annotation
The annotation voice: --ds-font-serif, italic, 400, 0.8125rem, --ds-text-muted. It is a voice, not a layout role; where it sits is the consumer's decision.
--ds-font-serif
The serif stack. On the public site and in internal tools it is used only through .ds-annotation.

IBM Plex Serif (blog only)

Headlines and pull quotes on the arXiv blog. The upright serif weights appear in no other context.

Updates on all things arXiv
I am excited and honored to join arXiv at such a significant time for the organization.
Relevant code
font-family: var(--ds-font-serif);
--ds-font-serif
Upright, weights 400 and 600. Outreach properties only; see outreach sites.

STIX Two Math

Mathematical notation in HTML papers, rendered from MathML.

𝑑𝑠² = −𝑑𝑡² + 𝑎²(𝑡) δ𝑖𝑗 𝑑𝑥𝑖𝑑𝑥𝑗
Relevant code
font-family: "STIX Two Math", "Cambria Math", math;
<math>
No font token exists for math; use the stack directly on the notation. Loads with font-display: auto per DESIGN-POLICIES.

The type scale

The text sizes design-system.css sets, in rem, so every one of them moves with the reader's base size. Headings have their own scale below.

1rem
Body text: paragraphs, abstracts, interface copy, on a 1.5 line-height.
0.875rem
Small: secondary text, captions, and the code block.
0.8125rem
Annotation: a margin footnote, figure alt text.
0.75rem
Panel label
0.9em
inline code tracks whatever it sits inside, a heading included.
Relevant code
<p>Body text.</p>
<small>Secondary text.</small>
<p class="ds-annotation">A margin footnote.</p>
<p class="ds-panel-label">Paper information</p>
<p>An identifier: <code>arXiv:2604.22725</code></p>
<p>
1rem, the reader's base size. Nothing sets it; the browser does.
<small>
0.875rem in --ds-text-muted.
<pre>
0.875rem, line-height 1.6, on the dark chrome ground.
.ds-annotation
0.8125rem, serif italic, line-height 1.45.
.ds-panel-label
0.75rem, condensed, uppercase.
<code>
0.9em, so it follows the size of its parent.

The heading scale

Four levels, one ratio: each level is a quarter larger than the one below it, which puts h1 at exactly twice body size. Sizes are rem; the px equivalents assume a 16px root and move with the reader's setting. Every level is --ds-font-sans in --ds-text — rank is carried by size and weight alone, never by a colour change or a different face.

h1 · 2rem · 700
Gauge-independent approach to inflation
h2 · 1.5rem · 600
Submission history
h3 · 1.25rem · 600
Gauge-invariant perturbations
h4 · 1rem · 600
Boundary conditions
Relevant code
<h1>Gauge-independent approach to inflation</h1>
  <h2>Submission history</h2>
    <h3>Gauge-invariant perturbations</h3>
      <h4>Boundary conditions</h4>
<h1>
The page's one subject: what the page is about, stated once — a paper title, a form name, a console view. A page that seems to need two h1s is two pages. 2rem (32px) · 700 · line-height 1.25 · space above 0, below --ds-space-4.
<h2>
A major section: a top-level division of that subject — Abstract, Submission history, References, each step of a submission form. 1.5rem (24px) · 600 · line-height 1.25 · space above --ds-space-8, below --ds-space-3.
<h3>
A division inside one section: a subsection of a paper, or a card heading inside a panel. It only exists where an h2 already does. 1.25rem (20px) · 600 · line-height 1.25 · space above --ds-space-6, below --ds-space-2.
<h4>
The smallest named step: a named paragraph in a paper, a field group in a form. This is the last level the scale defines; needing an h5 is a sign the content wants restructuring, not a fifth size. 1rem (16px) · 600 · line-height 1.25 · space above --ds-space-4, below --ds-space-2.

Links are typography with a job, so they live here. Color carries the state; the underline carries the meaning — and inline links in body text are always underlined (color alone fails WCAG 1.4.1 at our contrast levels). Standalone navigation links (headers, footers, button-like rows) may drop the underline.

Full state-by-state references (rest / hover / visited / focus / disabled, light and dark): Links. Link color tokens with ratios: Colors.

Reading text with an inline link in its resting state — Link Blue, underlined, offset so the descenders stay readable. Hover darkens it; a visited link turns Visited Purple; keyboard focus draws the standard 3px ring.
Relevant code
Reading text with <a href="/abs/2604.22725">an inline link</a> in it.
.ds-link
The inline text link. Both surfaces use .ds-link and the --ds-link-* tokens: the same grammar, the same names and the same values. Inside a .ds-page a bare <a> gets the same treatment without the class.
--ds-link, --ds-link-hover, --ds-link-visited
Rest, hover and visited colours. The underline does not change between states.
--ds-focus-ring
The 3px keyboard focus ring, drawn on :focus-visible only.

Code blocks, and the copy button

A code block is Plex Mono on the dark chrome ground, and it always carries a copy button — the familiar two-sheets icon, top right. Someone reading a pattern page is there to take the markup away with them, and asking them to select four lines of it by hand without missing the last character is asking them to make a mistake.

<button class="ds-btn ds-btn-primary" type="button">Save</button>
Relevant code
<!-- Write the block the way you already do -->
<pre><code>&lt;button class="ds-btn"&gt;Save&lt;/button&gt;</code></pre>

<!-- And include the script once, at the foot of the page -->
<script src="copy-code.js" defer></script>
<pre><code>
The block. Escape <, > and & inside it. No wrapper and no button of your own.
<script src="copy-code.js" defer>
Once per page, at the foot. It finds every <pre> on the page and adds the control.
.ds-code, .ds-code-copy
The wrapper and the button. The script writes both; never hand-build them.
[data-no-copy]
On a <pre>, opts that block out — for a block that is an illustration of output rather than something to take away.

Panel label

The small uppercase Condensed label that names a panel, a column or a group. It is not a heading level and stays out of the document outline — if a reader needs to navigate to it, it is an h3 or an h4 at the sizes above.

Note

Do not reach for it as a heading substitute. A label that a reader needs to navigate to is a heading, and belongs in the outline.

Paper information

The label sits closer to what it introduces than to what precedes it, so it bonds downward. That relationship is intrinsic to the thing, not something its context supplies — which matters because half the instances in these pages are paragraphs rather than headings.

Relevant code
<p class="ds-panel-label">Paper information</p>
.ds-panel-label
One class for the whole system: 0.75rem · 600 · Condensed · uppercase · 0.04em · --ds-text-muted. Use it wherever this treatment appears — panel headings, column labels, the label above a group of controls — on whichever element is semantically right. A component that owns its internal spacing takes the margin back.
<dt>
A definition term inside .ds-acc-body is this label, and carries no class.

Accessibility essentials

  • Keep the heading order. One <h1> per page, then <h2>, <h3> and <h4> in order, without skipping a level. Choose the level from the outline, not from the size you want; the scale gives each level its size. A screen reader user moves through the page by these levels.
  • Write sizes in rem, never in px. A reader who raises the browser font size must see every piece of text grow. Give a control its padding and minimum width in em, so the box grows with its label.
  • Let text reflow at 200% zoom. Do not give a box that holds text a fixed height, and do not cut text off with overflow: hidden unless there is another way to read all of it. At 400% page zoom a 1280px screen is a 320px screen, and the page must not scroll sideways there.
  • Put text in text, not in images. An image of words cannot be resized, translated, searched or read aloud. If an image must carry words, the same words go in its alt text or next to it.
  • Uppercase comes from CSS, never from the keyboard. The panel label is uppercase because .ds-panel-label makes it so. Type it in sentence case, so copy-and-paste, search and screen readers get the real words.

Rules

Which faces where — the three contexts

One family, three contexts. Internal tools and the public site share the working set; outreach properties add the upright serif and the heaviest sans. A face without a mark is not used in that context.

Face · weightsInternal toolsPublic siteOutreach
IBM Plex Sans · 400 / 500 / 600✓ all text✓ all text✓ all text
IBM Plex Sans · 700 + 700 italic✓ h1 only✓ h1 only✓ the one heading that must not read as an article
IBM Plex Sans Condensed · 500 / 600✓ labels, table headers✓ labels✓ labels
IBM Plex Mono · 400 / 500✓ IDs, code✓ arXiv IDs, code✓ code, plus a display register (wordmark, standfirst)
IBM Plex Serif · 400 italicannotation voice only (.ds-annotation)annotation voice only (.ds-annotation)✓ emphasis, bylines, prev/next
IBM Plex Serif · 400 / 600 upright——✓ headlines to display size, pull quotes, drop caps
STIX Two Math · 400—✓ math in HTML papers—

Headings

Space is given as spacing tokens, not pixels, because that is what design-system.css implements — --ds-space-8 is 2rem, --ds-space-6 is 1.5rem, and so on down the scale.

The copy button

Sizes are rem, and a box that holds text scales with its text

A browser font-size setting has to reach arXiv content (accessibility-priorities.md, cognitive/dyslexia track), so every type size is rem. But a label that grows inside a box that does not is no better than a label that never grew: set a control's padding and minimum width in em, against its own label, and the whole control follows the reader. Absolute floors stay absolute — min-height: 24px is a WCAG target size, not a type size.

Self-hosted, with honest fallbacks

No Google Fonts, no Typekit, no CDN fonts (DESIGN-POLICIES.md). Every font-family declaration carries system fallbacks; text fonts load with font-display: swap (readability first), STIX Two Math with font-display: auto (math must render in the correct face).

Do not fight the reader

No fixed line-heights, no pinned letter-spacing, no !important on font-family in content areas. User stylesheets, reader-mode extensions, and OS settings win — "HTML gives you freedom: you can use software to change colors or typefaces" (research, dyslexia track).

Fluid where titles meet phones

Paper titles use clamp() between rem bounds (22px–32px equivalent) so a seven-word title does not wrap to five lines at 320px. Body text never scales fluidly — it tracks the user's base size exactly.

Spec

Everything above is the design. This is what an implementer needs: the tokens, the files, the @font-face rules and the fallbacks. Placed last because it is reference, not reading.

Why IBM Plex

Open source under the SIL Open Font License, so there is no licensing cost and no vendor dependency; self-hostable as woff2 from arXiv's own assets; one designer's family covering Sans, Condensed, Mono and Serif so nothing is mixed; broad language coverage including Latin Extended, Cyrillic, Greek, Arabic, Hebrew, Devanagari and Thai; and it pairs with STIX Two Math, which is built for the same technical context. The family was re-evaluated in June 2026 against Atkinson Hyperlegible Next, Source Sans 3, Inter and Public Sans, and kept — that comparison lives in planning/proposals, not here.

Tokens

--ds-font-sans:      "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
--ds-font-condensed: "IBM Plex Sans Condensed", "IBM Plex Sans", sans-serif;
--ds-font-mono:      "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, monospace;
--ds-font-serif:     "IBM Plex Serif", Georgia, "STIX Two Text", "Times New Roman", serif;

Every stack carries system fallbacks so text stays readable if the web fonts fail: sans falls to the OS system font, mono to the platform monospace. There is no math token — STIX Two Math is applied by the paper renderer on HTML paper pages, not by the design system, so the stylesheet does not declare one.

Available weights, and sanctioned ones

Every weight and style IBM Plex ships is self-hosted — Thin 100, ExtraLight 200, Light 300, Regular 400, Text 450, Medium 500, SemiBold 600 and Bold 700, each with an italic, across Sans, Sans Condensed, Mono and Serif. That is 64 files and about 4 MB in the repository, and it costs a reader nothing: a @font-face rule downloads only when a page uses that face.

Available is not the same as approved. Only the faces the design system uses are declared in fonts.css; the rest are present but commented out, so you can see what exists without going to look for it. Uncommenting one is how you turn it on — and it is a decision, not a formality.

WeightUse it for
400 RegularBody copy, and anything that is read rather than scanned.
500 MediumNavigation, table headers, the quieter emphasis.
600 SemiBoldHeadings, button labels, and the label half of a label/value pair.
700 BoldThe h1, and nothing else — see the heading scale.
100, 200, 300, 450Present, unused, and commented out.

Light weights are an accessibility problem that contrast ratios do not catch

Thin, ExtraLight and Light are now reachable. At interface sizes their strokes are too fine for many readers to resolve even when the colour passes AA — the ratio measures the hue, not whether the letterform survives. Body and interface text use 400 or heavier. Anything lighter belongs at display sizes, if anywhere, and is worth testing before it ships.

The files

Self-hosted woff2, from arXiv's static assets. No external font service — see DESIGN-POLICIES for why that one is a hard constraint.

/static/fonts/
  IBMPlexSans-*.woff2            8 weights x roman/italic  = 16 files
  IBMPlexSansCondensed-*.woff2   8 weights x roman/italic  = 16 files
  IBMPlexMono-*.woff2            8 weights x roman/italic  = 16 files
  IBMPlexSerif-*.woff2           8 weights x roman/italic  = 16 files
  STIXTwoMath-Regular.woff2      ← HTML paper pages only

This repo's pattern pages serve the same files from docs/fonts/, declared in fonts.css, which every page links ahead of the stylesheet. The @font-face rules live in that separate file rather than in the design system itself, because consumers bundle the design system with their own font paths. Files come from IBM/plex (OFL).

@font-face

@font-face {
  font-family: "IBM Plex Sans";
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  src: url("/static/fonts/IBMPlexSans-Regular.woff2") format("woff2");
}
/* …one per weight and style… */

@font-face {
  font-family: "STIX Two Math";
  font-weight: 400;
  font-display: auto;
  src: local("STIX Two Math"),
       url("/static/fonts/STIXTwoMath-Regular.woff2") format("woff2");
}

Which faces each surface uses

SurfaceBodyLabelsCodeMath
Abstract pagesPlex SansPlex Sans CondensedPlex Mono—
HTML paper pagesPlex SansPlex Sans CondensedPlex MonoSTIX Two Math
Internal toolsPlex SansPlex Sans CondensedPlex Mono—
Homepage, listings, searchPlex SansPlex Sans CondensedPlex Mono—

Sizes in use

Not yet a formal scale — these are the sizes used consistently across the mockups, recorded so the scale can be settled from what exists rather than invented.

UseSizeWeightFace
Paper title (abstract page)24px600Plex Sans
Section heading15–16px600Plex Sans
Body text15px400Plex Sans
Metadata labels, table headers11px uppercase600Plex Sans Condensed
Secondary text, captions13px400–500Plex Sans
Annotation (margin footnote, alt text)13px italic400Plex Serif
Code, identifiers12–13px400Plex Mono
Nav links13px500Plex Sans