Overview
Linear's marketing site is a dark product surface, not a dark marketing page. The canvas is {colors.bg-primary} (#08090a) — very close to black but never black — and hero sections go one step darker still on {colors.bg-marketing} (#010102). Everything above the canvas is separated not by a drop shadow but by an inset white hairline at three to five percent: the raised card, the panel, the input all read as lifted because a single pixel of light traces their edge.
The type system is unusually precise. Inter Variable runs on non-integer weights — 510 for medium and 590 for semibold rather than the conventional 500 and 600 — with cv01 and ss03 enabled and the optical-size axis left on auto. Nine title steps and six text steps are published as tokens, and negative tracking tightens from −0.012em on the small titles to −0.022em from 32px upward. Body copy sits in {colors.text-tertiary} (#8a8f98), not in the primary near-white; on this site white is reserved for headlines and the things you can act on.
Colour is disciplined to the point of austerity. One indigo, {colors.brand} (#5e6ad2), carries the brand; {colors.accent} (#7170ff) and {colors.link} (#828fff) are its two lighter siblings for interactive text. The primary call to action is not brand-coloured at all — it is a near-white pill, {colors.action-bg} (#e5e5e6), which on this canvas is the loudest thing available. Editorial surfaces such as /method break the system in exactly one deliberate place: the display face swaps from Inter to a serif, {typography.title-editorial}.
Key Characteristics:
- Dark-only. There is no light theme;
color-scheme: darkis set on the root and no light token set is published. - Elevation is drawn with light:
inset 0 0 0 1px rgba(255,255,255,.03)rather than a cast shadow. - Non-integer weights — 300 / 400 / 510 / 590 / 680 — exploiting the Inter Variable axis.
- Body copy is
{colors.text-tertiary}; primary near-white is reserved for headlines and actions. - The primary action is a near-white pill, not the brand indigo.
{rounded.rounded}dominates: 14 of 18 rounded elements on the pricing surface are full pills.- Four background levels plus three border levels give depth without a single gradient.
- One easing everywhere:
cubic-bezier(.25, .46, .45, .94)at 0.1s and 0.16s. - The serif display face appears only on editorial pages — the one sanctioned exception.
Colors
Source pages analyzed: homepage, pricing, and the /method editorial surface, plus the header and footer chrome shared across all three.
Brand & Accent
- Brand Indigo (
{colors.brand}— #5e6ad2): The brand mark and brand-filled surfaces. Notably not the primary CTA colour. - Accent (
{colors.accent}— #7170ff): A lighter indigo for interactive accents and highlights. - Link (
{colors.link}— #828fff): Inline links, lighter again so it holds contrast as small text on the dark canvas. Pressed goes to{colors.link-hover}(pure white). - Accent Tint (
{colors.accent-tint}— #18182f): The faintest indigo wash, for selected or highlighted rows. - Action (
{colors.action-bg}— #e5e5e6): The primary button. A near-white pill is the highest-contrast object available on this canvas, so Linear spends its loudest value on the action rather than on the brand.
Surface
Four descending levels plus a marketing floor, all within a nine-value range of near-black:
- Marketing (
{colors.bg-marketing}— #010102): Hero sections. One step below the app canvas. - Primary (
{colors.bg-primary}— #08090a): The page. Never pure black. - Level 1 (
{colors.bg-level-1}— #0f1011): Panels and raised cards. - Level 2 (
{colors.bg-level-2}— #141516) / Level 3 ({colors.bg-level-3}— #191a1b): Nested surfaces. - Secondary (
{colors.bg-secondary}— #1c1c1f) through Quaternary ({colors.bg-quaternary}— #28282c): Controls, chips, inputs. - Translucent (
{colors.bg-translucent}— rgba(255,255,255,.05)): The pressed state of a ghost control — light added, never a darker fill. - Header (
{colors.header-bg}— #0b0b0bcc): 80% opaque over a 20px backdrop blur.
Text
- Primary (
{colors.text-primary}— #f7f8f8): Headlines and interactive labels. An off-white, never #fff. - Secondary (
{colors.text-secondary}— #d0d6e0): Sub-headings and emphasised body. Faintly blue. - Tertiary (
{colors.text-tertiary}— #8a8f98): Default body copy, and the resting colour of nav items. - Quaternary (
{colors.text-quaternary}— #62666d): Disabled and the quietest metadata.
Hairlines & Borders
Two parallel ramps serve different jobs. border- are opaque and used on controls; line- are darker and used as structural rules between regions.
- Border (
{colors.border-primary}— #23252a,{colors.border-secondary}— #34343a,{colors.border-tertiary}— #3e3e44) - Translucent (
{colors.border-translucent}— rgba(255,255,255,.05),{colors.border-translucent-strong}— rgba(255,255,255,.08)): The preferred edge, because it holds its relationship to whatever sits behind it. - Line (
{colors.line-primary}— #37393a down to{colors.line-tertiary}— #18191a): Dividers.
Semantic
{colors.red} #eb5757 · {colors.green} #27a644 · {colors.yellow} #f0bf00 · {colors.orange} #fc7840 · {colors.teal} #00b8cc. Status only; they never appear as chrome.
Brand Gradient
No gradient tokens. Depth comes from the four background levels and the inset hairline. What reads as a glow in hero imagery is artwork, not CSS.
Typography
Font Family
- Inter Variable — the interface and display face, loaded with
font-feature-settings: "cv01", "ss03"andfont-variation-settings: "opsz" auto.cv01gives the single-storey lowercase g;ss03adjusts the curved-r pairs. Both are on everywhere and are part of the site's fingerprint. - Tiempos Headline — serif, display only, and only on editorial surfaces (
/method). See{typography.title-editorial}. - Berkeley Mono — code and technical labels.
Weights
300 light · 400 normal · 510 medium · 590 semibold · 680 bold.
The 510 and 590 are the tell. A variable axis makes any value available, and Linear uses that to sit slightly below the conventional 500/600 stops — enough to read as lighter and more precise at display sizes without losing structure.
Hierarchy
| Token | Size | Weight | Line Height | Letter Spacing | Use |
|---|---|---|---|---|---|
{typography.title-9} | 72px | 590 | 1 | -0.022em | Largest display step |
{typography.title-8} | 64px | 590 | 1.06 | -0.022em | Display |
{typography.title-7} | 56px | 510 | 1.1 | -0.022em | Homepage hero — note the lighter 510 |
{typography.title-6} | 48px | 590 | 1 | -0.022em | Section display |
{typography.title-editorial} | 48px | 400 | 1 | 0 | Serif. Editorial page headline only |
{typography.title-5} | 40px | 590 | 1.1 | -0.022em | Section headline |
{typography.title-4} | 32px | 510 | 1.125 | -0.022em | Sub-section headline, usually in {colors.text-tertiary} |
{typography.title-3} | 24px | 590 | 1.33 | -0.012em | Card headline |
{typography.title-2} | 20px | 590 | 1.33 | -0.012em | Feature heading |
{typography.title-1} | 17px | 590 | 1.4 | -0.012em | Smallest title step |
{typography.text-large} | 17px | 400 | 1.6 | 0 | Editorial body |
{typography.text-regular} | 15px | 400 | 1.6 | -0.011em | Default body |
{typography.text-small} | 14px | 400 | 1.5 | -0.013em | Secondary copy |
{typography.text-mini} | 13px | 400 | 1.5 | -0.01em | Nav items, button labels |
{typography.text-micro} | 12px | 400 | 1.4 | 0 | Metadata |
{typography.text-tiny} | 10px | 400 | 1.5 | -0.015em | Badges |
Principles
- Tracking tightens with size, in two bands. Titles up to 24px carry −0.012em; from 32px upward it jumps to −0.022em and stays there. Text steps run −0.011em to −0.015em, with 12px and 17px at zero.
- Line-height inverts with size. 1 to 1.125 across the display range, 1.5 to 1.6 for text.
- The hero is lighter than the ladder suggests.
{typography.title-7}is published at 590 but the homepage h1 renders at 510 — the largest type gets the lightest treatment. - Section headings are often tertiary grey, not white. Hierarchy comes from size and colour together.
- Editorial pages swap the face, not the system. Only the display step changes; body, spacing and colour stay identical.
Note on Font Substitutes
Inter is free (Google Fonts, variable) — use the real thing and keep the feature settings:
font-family: "Inter Variable", "Inter", system-ui, sans-serif;
font-feature-settings: "cv01", "ss03";
font-variation-settings: "opsz" auto;
Without cv01/ss03 the face is recognisably not Linear. Tiempos Headline is licensed from Klim; the closest free substitutes are Newsreader or Source Serif 4 at weight 400 — both need roughly −0.01em tracking added to match Tiempos' tighter fit. Berkeley Mono is commercial; JetBrains Mono is the nearest free equivalent.
Layout
Spacing System
- Base unit: 4px, working scale 4 · 8 · 12 · 16 · 24 · 28 · 32 · 48 · 64.
- Tokens:
{spacing.xs}4px ·{spacing.sm}8px ·{spacing.md}12px ·{spacing.lg}16px ·{spacing.xl}24px ·{spacing.outer}28px ·{spacing.inset}32px ·{spacing.page-block}48px ·{spacing.section}64px. - Button padding is
0 {spacing.md}on a fixed 32px height — controls are sized by height, not by vertical padding.
Grid & Container
| Context | Max width | Inset |
|---|---|---|
| Marketing pages | 1400px (calc(1344px + 28px * 2)) | 28px |
| Documentation / app pages | 1024px | 24px |
| Prose column | 624px published; 410px measured on /method | — |
The grid is 8 columns, not 12 — narrower than the usual marketing grid and part of why the layout reads as a product rather than a brochure.
Whitespace Philosophy
Whitespace here is tight by marketing standards and generous by product standards, which is exactly the impression intended. Sections do not use large fixed vertical padding; they are separated by a change of background level or a line-* rule. The prose column is unusually narrow — around 410px on the editorial pages — which forces short measure and gives long-form pages the density of documentation rather than of a blog.
Elevation & Depth
| Level | Treatment | Use |
|---|---|---|
| Flat | Background level change only | Sections, page regions |
| Hairline | inset 0 0 0 1px rgba(255,255,255,.03) | The default raised surface — 6 of 11 shadowed elements on the pricing page |
| Border | 1px rgba(255,255,255,.05) | Controls, cards, inputs |
| Low | 0 2px 4px rgba(0,0,0,.1) | Slightly lifted controls |
| Medium | 0 4px 24px rgba(0,0,0,.2) | Popovers, menus |
| High | 0 7px 32px rgba(0,0,0,.35) | Dialogs, command menu |
Shadow philosophy. On a near-black canvas a cast shadow is invisible, so Linear inverts the technique: elevation is drawn with light. A raised surface gets one pixel of white at 3% inset along its edge; a stronger one gets 5%. Dark shadows exist in the token set and appear only under genuinely floating layers — popovers, dialogs — where they separate a surface from the content scrolling beneath it. Never reach for a dark shadow to raise a card.
Decorative Depth
- Background levels (
{colors.bg-primary}→{colors.bg-level-3}) do most of the work. - Backdrop blur appears once, on the header: 20px behind an 80%-opaque fill.
- No gradients.
Shapes
Border Radius Scale
| Token | Value | Use |
|---|---|---|
{rounded.none} | 0px | Full-bleed sections |
{rounded.xs} | 4px | Badges, the smallest chips |
{rounded.sm} | 6px | Inline code, editor blocks |
{rounded.md} | 8px | Compact controls, inline card imagery |
{rounded.lg} | 12px | Cards and panels |
{rounded.xl} – {rounded.xxxl} | 16 / 24 / 32px | Large containers and media frames |
{rounded.rounded} | 9999px | All buttons, nav items and chips |
{rounded.circle} | 50% | Avatars, icon buttons |
The grammar is two-tier: pills mean interactive, 12px means container. On the pricing surface 14 of 18 rounded elements are pills, which is why the page reads as a control panel.
Media Geometry
Product screenshots sit on {component.surface-raised} at {rounded.lg} with the inset hairline, so the artwork appears inset into the page rather than laid on top of it.
Components
Top Navigation
header — 72px, sticky, {colors.header-bg} (#0b0b0b at 80%) over a 20px backdrop blur. Nav items are {component.button-ghost}: pill, 32px tall, {typography.text-mini} at {colors.text-tertiary}, transitioning colour and background over 0.1s. The right cluster pairs a ghost "Log in" with the near-white {component.button-action} "Sign up".
Buttons
All buttons are {rounded.rounded} and 32px tall, sized by height with 0 {spacing.md} inline padding.
button-action — The primary. {colors.action-bg} (#e5e5e6) fill, {colors.action-text} (#08090a) label, 1px border in the same value, {typography.text-mini} at weight 510. Pressed brightens the fill to {colors.action-bg-hover} (#ffffff). Transition: border 0.16s, background-color 0.16s on cubic-bezier(.25,.46,.45,.94).
button-ghost — Transparent with {colors.text-tertiary} label. Pressed adds {colors.bg-translucent} — light is added, never a darker fill. Transition 0.1s.
button-brand — {colors.brand} fill with white label, for brand moments rather than for the main conversion path.
Cards & Containers
surface-raised — {colors.bg-level-1}, {rounded.lg}, edge drawn with inset 0 0 0 1px rgba(255,255,255,.03). The default card.
surface-overlay — {colors.bg-secondary} with the stronger {colors.border-translucent-strong} edge and {colors.overlay} behind it, for menus and dialogs. This is where the dark medium/high shadows are permitted.
Inputs & Forms
Inputs follow {component.surface-overlay}: a {colors.bg-secondary} fill, a translucent white border and {rounded.md}. Validation and error states were not surfaced on the analyzed pages — see ## Known Gaps.
Footer
footer — {colors.bg-primary}, links in {typography.text-small} at {colors.text-primary} weight 400. Column headings use {colors.text-tertiary}. No background change from the page; a line-* rule separates it.
Do's and Don'ts
Do
- Build on
{colors.bg-primary}and lift surfaces withinset 0 0 0 1px rgba(255,255,255,.03). - Set body copy in
{colors.text-tertiary}and reserve{colors.text-primary}for headlines and actions. - Use the non-integer weights: 510 for medium, 590 for semibold.
- Keep
font-feature-settings: "cv01", "ss03"on Inter — without them the face is not Linear. - Give every button
{rounded.rounded}and a fixed 32px height. - Make the primary action the near-white pill, not the brand indigo.
- Animate with
cubic-bezier(.25, .46, .45, .94)at 0.1s for colour and 0.16s for anything structural. - Switch to
{typography.title-editorial}only on long-form editorial pages.
Don't
- Don't add a light theme; this system publishes no light token set.
- Don't raise a card with a dark drop shadow — dark shadows belong to floating layers only.
- Don't use pure black or pure white as a surface or as body text.
- Don't make the brand indigo the primary CTA; it is a brand colour, not an action colour.
- Don't round a container to a pill or a button to 12px — the two-tier grammar is the signal.
- Don't widen the prose column past ~624px; the narrow measure is part of the voice.
- Don't use the semantic colours as chrome — they carry status only.
Responsive Behavior
Breakpoints
The system is fluid rather than step-based: containers are min()-capped and the grid holds at 8 columns. The published constants are the marketing cap (1400px), the app cap (1024px), the prose cap (624px) and the page inline padding (24px, opening to 28–32px on wide viewports).
Touch Targets
--min-tap-size: 44px is published, but controls render at 32px on desktop — the token governs touch contexts, where the hit area is expanded around the same visual pill.
Collapsing Strategy
- Header: the nav collapses behind a trigger at mobile; the 72px height and the action pill persist.
- Type: the title ladder steps down through its published sizes rather than by media query per element.
- Prose: the narrow column is already mobile-width, so long-form pages barely reflow.
Image Behavior
Product artwork keeps its {rounded.lg} frame and inset hairline at every width.
Iteration Guide
- Work on one component at a time, addressed by its YAML key (
{component.surface-raised},{component.button-action}). - Variants live as their own
components:entries with an-activesuffix. - Use
{token.refs}everywhere; never inline a hex once a token exists. - Document default and active/pressed states only — never hover.
- The two rules that define this language: elevation is drawn with light, not shadow, and body copy is tertiary grey. Break either and it stops being Linear.
- Before adding chrome for emphasis, change the background level instead.
- Weights are 510 and 590, not 500 and 600. The difference is visible at display sizes.
Known Gaps
- No light theme exists to document. The root sets
color-scheme: darkand publishes no light token set; this is a single-theme system. - Form validation and error states were not surfaced. The analyzed pages contained no form with visible validation; input styling is inferred from the overlay surface tokens.
- The in-app product UI was not analyzed. These findings come from the marketing surfaces; the application itself may extend the system.
- 54 of 77 stylesheets are cross-origin and could not be read as rules. Values here were resolved off the live root element instead, which yields computed values but not the authoring conditions behind them.
- Spacing is derived. Linear publishes layout constants (page insets, container caps) but no numbered spacing scale; the scale here is the dominant measured set.
- The full easing set is published but only one is used. Twenty-two Penner curves exist as tokens; only
ease-out-quadwas observed in effect on the analyzed pages.