Build the scale.
lh 0.898 / tracking -0.056em01 / 04
Columns and rows combine into repeatable modules.
Columns and rows combine into repeatable modules.
catalogues, indexes, dashboards, posters
Native CSS Grid
Dense modules can become noisy if every guide is shown at once.
24px / 16px root
1.5rem * 16px root
clamp(1rem, 0.7143rem + 1.4286vw, 2rem)Viewport interpolation from 16px to 32px across 320px and 1440px.
Fluid values combine rem endpoints with a modest vi component rather than pure viewport units.
Spacing is derived from base size and body line-height, so rhythm changes with the type system.
Heading semantics remain independent from visual tokens; the default h1-h6 mapping is editable in production.
Large type receives tighter leading and tracking, while smaller supporting text keeps more line separation.
Rich-text spacing uses contextual selectors so headings, lists, media, captions, and prose do not share one generic margin.
Export workspace
The export UI now keeps the format picker separate from the code so long token files do not collapse into a cramped sidebar card.
Raw custom properties and prose tokens for direct use in apps or prototypes.
:root {
--font-body: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
--font-heading: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
--body-weight: 400;
--heading-weight: 600;
--type-display: clamp(2.986rem, calc(2.0358rem + 4.7508vi), 6.3115rem);
--type-heading-xl: clamp(2.4883rem, calc(1.8465rem + 3.2093vi), 4.7348rem);
--type-heading-l: clamp(2.0736rem, calc(1.6512rem + 2.112vi), 3.552rem);
--type-heading-m: clamp(1.728rem, calc(1.4604rem + 1.3381vi), 2.6647rem);
--type-heading-s: clamp(1.44rem, calc(1.2803rem + 0.7986vi), 1.999rem);
--type-body-l: clamp(1.2rem, calc(1.1144rem + 0.428vi), 1.4996rem);
--type-body: clamp(1rem, calc(0.9643rem + 0.1786vi), 1.125rem);
--type-body-s: clamp(0.8333rem, calc(0.8303rem + 0.0152vi), 0.844rem);
--type-caption: clamp(0.6944rem, calc(0.712rem - 0.0876vi), 0.6331rem);
--leading-display: 0.898;
--leading-heading-xl: 0.898;
--leading-heading-l: 1.012;
--leading-heading-m: 1.06;
--leading-heading-s: 1.096;
--leading-body-l: 1.58;
--leading-body: 1.58;
--leading-body-s: 1.64;
--leading-caption: 1.64;
--tracking-display: -0.056em;
--tracking-heading-xl: -0.056em;
--tracking-heading-l: -0.03em;
--tracking-heading-m: -0.0282em;
--tracking-heading-s: -0.0256em;
--tracking-body-l: 0em;
--tracking-body: 0em;
--tracking-body-s: 0.006em;
--tracking-caption: 0.006em;
--space-3xs: clamp(0.3865rem, calc(0.3664rem + 0.1005vi), 0.4568rem);
--space-2xs: clamp(0.5797rem, calc(0.5496rem + 0.1507vi), 0.6852rem);
--space-xs: clamp(0.7729rem, calc(0.7327rem + 0.201vi), 0.9136rem);
--space-s: clamp(1.1594rem, calc(1.0991rem + 0.3015vi), 1.3705rem);
--space-m: clamp(1.5459rem, calc(1.4655rem + 0.402vi), 1.8273rem);
--space-l: clamp(2.3188rem, calc(2.1982rem + 0.603vi), 2.7409rem);
--space-xl: clamp(3.0917rem, calc(2.9309rem + 0.804vi), 3.6545rem);
--space-2xl: clamp(4.6376rem, calc(4.3964rem + 1.206vi), 5.4818rem);
--space-3xl: clamp(6.9564rem, calc(6.5946rem + 1.809vi), 8.2227rem);
--space-inline: clamp(1.1802rem, calc(1.1188rem + 0.3072vi), 1.3953rem);
--space-stack: clamp(1.5734rem, calc(1.4915rem + 0.4099vi), 1.8604rem);
--space-paragraph: clamp(1.0699rem, calc(1.0142rem + 0.2788vi), 1.2651rem);
--space-heading-before: clamp(3.6511rem, calc(3.4613rem + 0.9489vi), 4.3154rem);
--space-heading-after: clamp(0.9678rem, calc(0.9174rem + 0.2519vi), 1.1441rem);
--space-list: clamp(1.4161rem, calc(1.3423rem + 0.3689vi), 1.6744rem);
--space-media: clamp(3.3049rem, calc(3.1331rem + 0.8589vi), 3.9062rem);
--space-component: clamp(2.3605rem, calc(2.2378rem + 0.6135vi), 2.79rem);
--space-section-s: clamp(3.3049rem, calc(3.1331rem + 0.8589vi), 3.9062rem);
--space-section-m: clamp(5.0987rem, calc(4.8334rem + 1.3262vi), 6.027rem);
--space-section-l: clamp(7.3647rem, calc(6.9817rem + 1.9151vi), 8.7053rem);
--measure-narrow: 50ch;
--measure-reading: 66ch;
--measure-wide: 76ch;
--prose-measure: 66ch;
--prose-body-leading: 1.651;
--prose-body-tracking: 0em;
--prose-flow: clamp(1.5851rem, calc(1.5025rem + 0.4128vi), 1.874rem);
--prose-paragraph-gap: clamp(1.1376rem, calc(1.0784rem + 0.2962vi), 1.3449rem);
--prose-heading-1-scale: 1.146;
--prose-heading-2-scale: 1.095;
--prose-heading-3-scale: 1.067;
--prose-heading-1-before: clamp(6.043rem, calc(5.7287rem + 1.5714vi), 7.1431rem);
--prose-heading-1-after: clamp(1.0145rem, calc(0.9615rem + 0.265vi), 1.2rem);
--prose-heading-2-before: clamp(4.2515rem, calc(4.0305rem + 1.1051vi), 5.0251rem);
--prose-heading-2-after: clamp(1.0165rem, calc(0.9634rem + 0.2655vi), 1.2023rem);
--prose-list-gap: clamp(1.3879rem, calc(1.3157rem + 0.3614vi), 1.6409rem);
--prose-list-item-gap: 0.52em;
--prose-list-indent: 1.25em;
--prose-heading-measure: 24ch;
--prose-heading-leading-scale: 1;
--prose-lead-scale: 1;
--prose-quote-gap: clamp(4.0792rem, calc(3.8671rem + 1.0603vi), 4.8214rem);
--prose-quote-padding: 1.44rem;
--prose-quote-border: 0.25rem;
--prose-quote-scale: 1.118;
--prose-pullquote-measure: 20ch;
--prose-media-gap: clamp(3.5284rem, calc(3.345rem + 0.917vi), 4.1703rem);
--prose-caption-gap: clamp(0.3792rem, calc(0.3595rem + 0.0987vi), 0.4483rem);
--prose-section-gap: clamp(5.8452rem, calc(5.5412rem + 1.52vi), 6.9092rem);
--prose-code-leading: 1.398;
--prose-code-padding: 1rem;
--prose-inline-code-pad-y: 0.07em;
--prose-inline-code-pad-x: 0.32em;
--prose-code-font-size: 0.907em;
--prose-table-cell-pad: 0.63em;
}
/* Progressive enhancements: balance headings, pretty-wrap paragraphs, use tabular numbers for tables and metadata. */
.hype-prose {
--flow-space: var(--prose-flow);
max-inline-size: var(--prose-measure);
color: var(--ink);
font-family: var(--font-body);
font-size: var(--type-body);
font-weight: var(--body-weight);
line-height: var(--prose-body-leading);
letter-spacing: var(--prose-body-tracking);
font-optical-sizing: auto;
hyphens: auto;
text-wrap: pretty;
}
.hype-prose > * {
margin-block: 0;
}
.hype-prose > * + * {
margin-block-start: var(--flow-space);
}
.hype-prose :where(h1, h2, h3, h4) {
font-family: var(--font-heading);
font-weight: var(--heading-weight);
text-wrap: balance;
}
.hype-prose h1 {
font-size: clamp(2.8514rem, calc(2.1157rem + 3.6785vi), 5.4263rem);
line-height: 0.898;
letter-spacing: var(--tracking-heading-xl);
margin-block-start: var(--prose-heading-1-before);
max-inline-size: calc(var(--prose-heading-measure) * 0.86);
}
.hype-prose h2 {
font-size: clamp(2.2708rem, calc(1.8083rem + 2.3122vi), 3.8893rem);
line-height: 1.012;
letter-spacing: var(--tracking-heading-l);
margin-block-start: var(--prose-heading-2-before);
max-inline-size: var(--prose-heading-measure);
}
.hype-prose h3 {
font-size: clamp(1.8439rem, calc(1.5585rem + 1.4271vi), 2.8429rem);
line-height: 1.06;
letter-spacing: var(--tracking-heading-m);
margin-block-start: calc(var(--prose-heading-2-before) * 0.78);
}
.hype-prose h4 {
font-size: var(--type-heading-s);
line-height: 1.096;
letter-spacing: var(--tracking-heading-s);
margin-block-start: calc(var(--prose-heading-2-before) * 0.64);
}
.hype-prose h1 + :where(p, ul, ol, figure, blockquote, pre, table) {
margin-block-start: var(--prose-heading-1-after);
}
.hype-prose :where(h2, h3, h4) + :where(p, ul, ol, figure, blockquote, pre, table) {
margin-block-start: var(--prose-heading-2-after);
}
.hype-prose > :where(h2, h3):has(+ :where(h3, h4)) {
margin-block-end: calc(var(--prose-heading-2-after) * 0.45);
}
.hype-prose p + p {
margin-block-start: var(--prose-paragraph-gap);
}
.hype-prose p + :where(ul, ol),
.hype-prose :where(ul, ol) + p {
margin-block-start: var(--prose-list-gap);
}
.hype-prose :where(ul, ol) + :where(ul, ol) {
margin-block-start: var(--prose-list-gap);
}
.hype-prose p,
.hype-prose li {
max-inline-size: var(--prose-measure);
}
.hype-prose .lead {
font-size: clamp(1.2rem, calc(1.1145rem + 0.4277vi), 1.4994rem);
line-height: 1.585;
letter-spacing: var(--tracking-body-l);
max-inline-size: calc(var(--prose-measure) * 0.92);
}
.hype-prose a {
color: inherit;
text-decoration-thickness: 0.08em;
text-underline-offset: 0.18em;
}
.hype-prose :where(strong, b) { font-weight: 720; }
.hype-prose :where(em, i) { font-style: italic; }
.hype-prose mark { background: var(--spot-soft); color: inherit; padding-inline: 0.15em; }
.hype-prose small { font-size: var(--type-caption); line-height: var(--leading-caption); }
.hype-prose sup, .hype-prose sub { font-size: 0.68em; line-height: 0; }
.hype-prose :where(ul, ol) {
padding-inline-start: var(--prose-list-indent);
}
.hype-prose li + li {
margin-block-start: var(--prose-list-item-gap);
}
.hype-prose :where(ul, ol) :where(ul, ol) {
margin-block-start: var(--prose-list-item-gap);
padding-inline-start: 1.05em;
}
.hype-prose blockquote,
.hype-prose .pullquote {
border-inline-start: var(--prose-quote-border) solid var(--ink);
font-size: clamp(1.3416rem, calc(1.246rem + 0.4781vi), 1.6763rem);
line-height: 1.618;
padding-inline-start: var(--prose-quote-padding);
margin-block-start: var(--prose-quote-gap);
}
.hype-prose blockquote {
color: var(--ink-soft);
}
.hype-prose .pullquote {
max-inline-size: var(--prose-pullquote-measure);
font-size: clamp(1.8923rem, calc(1.5994rem + 1.4646vi), 2.9175rem);
line-height: var(--leading-heading-m);
letter-spacing: var(--tracking-heading-m);
}
.hype-prose figure,
.hype-prose pre,
.hype-prose table {
margin-block-start: var(--prose-media-gap);
}
.hype-prose figure + :where(p, h2, h3) {
margin-block-start: var(--prose-section-gap);
}
.hype-prose :where(blockquote, pre, table, hr) + :where(p, h2, h3, h4, ul, ol) {
margin-block-start: var(--prose-section-gap);
}
.hype-prose img,
.hype-prose video {
display: block;
inline-size: 100%;
block-size: auto;
border: 1px solid var(--rule);
}
.hype-prose figcaption {
margin-block-start: var(--prose-caption-gap);
font-size: var(--type-caption);
line-height: var(--leading-caption);
letter-spacing: var(--tracking-caption);
}
.hype-prose hr {
border: 0;
border-block-start: 1px solid var(--rule-strong);
margin-block-start: var(--prose-section-gap);
}
.hype-prose table {
border-collapse: collapse;
inline-size: 100%;
font-size: var(--type-body-s);
font-variant-numeric: tabular-nums;
}
.hype-prose th,
.hype-prose td {
border-block: 1px solid var(--rule);
padding: var(--prose-table-cell-pad) 0.65em;
text-align: start;
}
.hype-prose pre {
overflow: auto;
padding: var(--prose-code-padding);
border: 1px solid var(--rule);
background: var(--paper-muted);
font-size: var(--prose-code-font-size);
line-height: var(--prose-code-leading);
}
.hype-prose :where(code, kbd) {
font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace;
font-size: var(--prose-code-font-size);
}
.hype-prose :not(pre) > code,
.hype-prose kbd {
background: var(--paper-muted);
border: 1px solid var(--rule);
padding: var(--prose-inline-code-pad-y) var(--prose-inline-code-pad-x);
}
.hype-prose details {
border-block: 1px solid var(--rule);
padding-block: var(--space-s);
}
.hype-prose summary {
cursor: pointer;
font-weight: 700;
}
.hype-prose .footnotes {
font-size: var(--type-body-s);
line-height: var(--leading-body-s);
border-block-start: 1px solid var(--rule-strong);
padding-block-start: var(--space-s);
}
/* Optional CMS compatibility */
.hype-prose :where(.wp-block-image, .wp-block-table, .wp-caption) {
margin-block-start: var(--prose-media-gap);
}
.hype-prose :where(.wp-block-quote) {
border-inline-start: 0.18rem solid currentColor;
padding-inline-start: var(--space-s);
}
.hype-prose .alignwide {
max-inline-size: var(--measure-wide);
}
.hype-prose .alignfull {
max-inline-size: none;
}