Typography
Every text element is styled out of the box. Block elements have no top margin and a bottom margin of --jf-flow, so vertical rhythm is consistent.
The scale is rem. Reading sizes (xs, sm, base) are fixed; md and up — every heading — are fluid, built by the fluid($min, $max) function into a single clamp() that scales with the viewport between 320px and 1240px, no breakpoints. Each fluid step also gets a paired line-height automatically — type($step) (the mixin every heading uses) looks the step up in $type-leading and sets both font-size and line-height together, so a bigger heading and its tighter leading can't drift apart. Use type($step) in your own rules for the same pairing; call fluid() directly only if you need a one-off size outside the scale.
.callout-heading {
@include type(lg);
// font-size: clamp(1.125rem, 0.45vw + 1.05rem, 1.25rem);
// line-height: 1.35; // "snug" — looked up from $type-leading, not set by hand
}
The scale
Eleven steps, emitted as --jf-font-size-*. Reference one with @include type($step) (size and leading) or token(font-size-lg) (size only). The Line-height column is what $type-leading pairs with that step; see the leading scale for the values behind those keys.
| Step | Size | Line-height | Used by |
|---|---|---|---|
| xs | 12px | base (1.5) | — |
| sm | 14px | base (1.5) | <small>, .font-size-small, .chip, tables |
| base | 16px | base (1.5) | Body copy, form labels, buttons |
| md | 16 → 18px | snug (1.35) | <h6>, .button.large, accordion headings |
| lg | 18 → 20px | snug (1.35) | <h5>, .standfirst |
| xl | 20 → 24px | tight (1.2) | <h4> |
| 2xl | 24 → 30px | tight (1.2) | <h3> |
| 3xl | 30 → 36px | tight (1.2) | <h2> |
| 4xl | 36 → 48px | tight (1.2) | <h1> |
| 5xl | 48 → 60px | tight (1.2) | — |
| 6xl | 60 → 72px | tight (1.2) | — |
A single value is fixed; a → b is a clamp() sliding between those two sizes as the viewport goes from $fluid-min-vw (320px) to $fluid-max-vw (1240px). Which step each heading level takes is $heading-scale; merge $type-scale to retune a size or add a step.
Headings
Semantic <h1>–<h6> are sized by the scale. The matching .h1–.h6 classes apply the same size + line-height to any element without the semantics (they use !important). In Sass, @include h3(); does the same in your own rule.
Heading 1
Heading 2
Heading 3
Heading 4
Heading 5
Heading 6
.h1
.h2
.h3
.h4
.h5
.h6
text-wrap: balance is applied to h1–h3 (even multi-line headings), and text-wrap: pretty to p / li / dd / figcaption (no orphans). Unsupported browsers ignore both.
Lists
Ordered
- First
- Nested a
- Nested b
- Second
- Third
Unordered
- First
- Nested a
- Nested b
- Second
- Third
Definition
- Term
- Its definition.
- Another
- Its definition.
List markers are on by element. To strip them (nav lists, card grids) add role="list" — which also keeps VoiceOver announcing it as a list.
Blockquote & preformatted
A journey of a thousand miles begins with a single step.
Lao Tzu
console.log("Jellyfish is awesome");
Inline elements
| Element | Example |
|---|---|
<strong> / .bold | important · bold, no semantics |
<em> / .italic | emphasis · italic, no semantics |
<a> | a link, with a hover transition on --jf-transition |
<small> / .font-size-small | fine print — carries its own line-height |
<mark> | highlighted — its own surface, so it reads on any background. Fill is $mark-background-color / --jf-mark-background; the text colour is contrast-picked at build (Variables). |
<code> / <samp> / <var> / <kbd> | code · samp · var · kbd |
<sup> / <sub> | E = mc2 · H2O |
<ins> / <del> / <s> / <u> / <abbr> | inserted · |
Utilities
| Class | Example |
|---|---|
| .standfirst | A lead paragraph, one step up the scale (lg, fluid), medium weight. |
| .h1 … .h6 | The heading size + line-height on any element (!important) — see Headings above for all six live. |
| .font-size-small | The <small> size on any element (named so it doesn't clash with .button.small / .chip.small). |
| .weight-hairline … .weight-black | hairline · thin · light · normal · medium · semibold · bold · xbold · black — whichever the typeface actually has. |
| .bold / .italic | bold · italic — no semantics, see Inline elements above. |
| .nowrap |
A long brand name that stays on one line
|
Reading measure
Set $measure (or --jf-measure at runtime) to a value like 66ch to cap line length on p / li / dd / blockquote / small (WCAG 1.4.8). Default is none.
Overriding
- Fonts — $font-primary / -secondary / -monospace (also --jf-font-primary …). Body uses $font-primary, headings $font-secondary.
- Scale — $type-scale (merge to change / add sizes), $heading-scale (which step each h* uses), $type-leading (size → line-height), $fluid-min-vw / -max-vw. Or the type($step) mixin.
- Root — --jf-root-font-size on <html> rescales the whole rem scale at once.
Variables
Sass variables
| Name | Default | Notes |
|---|---|---|
| $font-primary | system sans stack | → --jf-font-primary. The project typeface. |
| $font-secondary | token(font-primary) | → --jf-font-secondary. Defaults to the primary stack — set it for a separate display face. |
| $font-monospace | system mono stack | → --jf-font-monospace. Used by code / pre / samp / var / kbd. |
| $font-body | token(font-primary) | The stack <body> uses. Point it at $font-secondary to swap body and headings without touching either stack. |
| $font-headings | token(font-secondary) | The stack h1–h6 use. |
| $type-scale | 11 steps, xs – 6xl | The size map → --jf-font-size-*. md and up are fluid($min, $max) clamps. All values are tabled above. Merge to retune a step or add one. |
| $heading-scale | h1: "4xl" … h6: "md" | Which $type-scale step each heading level takes. Merge one entry to resize a level. |
| $type-leading | step → leading key | The line-height paired with each size step. Read by type(), so size and leading can't drift apart. |
| $leading-scale | flush tight snug base loose | The unitless leading values those keys point at → --jf-leading-*. Values on Variables. |
| $fluid-min-vw | 320px | Viewport width at which every fluid size sits at its floor. |
| $fluid-max-vw | 1240px | Viewport width at which every fluid size reaches its ceiling. Independent of the layout breakpoints. |
| $heading-weight | get-weight(medium) | Font weight for h1–h6. |
| $font-weight-scale | hairline: 100 … black: 900 | The nine named weights → --jf-font-weight-*, behind get-weight() and the .weight-* utilities. |
| $root-font-size | token(font-size-base) (1rem) | Applied to <html> → --jf-root-font-size. The whole scale is rem, so overriding this one property rescales everything — that's how the font-size control works. |
| $root-line-height | token(leading-base) (1.5), | Applied to <body> → --jf-root-line-height. Holds a var(), so it can't be passed to Sass maths — use the token. |
| $font-size-adjust | none | → --jf-font-size-adjust on <html>. Normalises apparent size across faces by x-height when a swapped-in typeface reads small or large. Progressive — unsupported browsers skip it. |
| $measure | none | → --jf-measure, a max-inline-size on p / li / dd / blockquote / small (WCAG 1.4.8). Set a ch value like 66ch. |