Linear Design System
Overview
Linear presents itself as a precision instrument—a product development system that embodies the same rigor it asks of its users. The visual language is unapologetically dark-mode native, built on a canvas so close to pure black ({colors.canvas} — #08090a) that it creates a void-like backdrop against which every interface element must earn its presence. This is not merely inverted light-mode; it's a deliberate chromatic philosophy where luminance is rationed and hierarchy is established through microscopic variations in opacity and warmth rather than crude value shifts.
Brand voltage concentrates in a single signature hue—{colors.primary} (#f79ce0)—a rose-pink that reads as both technical and human, appearing on CTAs, active states, and accent moments throughout the marketing surface and (by extension) the application chrome. This is complemented by a restrained supporting cast of functional tints: indigo for informational states ({colors.accent-indigo}), warm amber for warnings or highlights ({colors.accent-warm}), teal for success-adjacent semantics ({colors.accent-teal}), and buttery yellow for premium callouts ({colors.accent-yellow}). The palette never competes; it orchestrates.
Typography is the system's dominant voice. Every role uses Inter Variable, deployed at non-standard weights (510 for display, 590 for titles) that sit between conventional CSS stops—these are not arbitrary but precisely calibrated to achieve Linear's specific optical density. The {typography.display-xl} at 64px carries negative letter-spacing of -1.408px, tightening the character fit to achieve a headline density that feels architectural rather than typeset. Body text at 15px ({typography.body-md}) sits slightly larger than web convention, acknowledging that developers reading issue descriptions and product managers scanning roadmaps benefit from breathing room. Monospace content—issue IDs, code references, command syntax—defaults to Berkeley Mono at 13px, creating a terminal-aesthetic subsystem that signals "this is machine-readable" while remaining comfortably legible.
Shape language is aggressively restrained. The default corner radius across most containers is {rounded.md} (6px), with inputs and cards sitting in this middle zone. Navigation elements go fully pill-shaped ({rounded.pill} / 9999px), while certain utility surfaces can drop to {rounded.sm} (2px) for near-sharp precision. Avatars are circular ({rounded.circle}). There is no playful rounding, no soft-ui blobbery—every radius serves the geometry it contains.
Two distinct sub-systems operate within this framework: the marketing dialect (hero bands, announcement tickers, CTA rows) which uses maximum whitespace and display typography to create editorial pause; and the application preview dialect (the embedded app mockup visible in the hero) which compresses information density into sidebar-navigation + main-content layouts with tight internal spacing, status badges, assignee avatars, and activity feeds. Both share the same tokens but apply them at different densities—the marketing surface breathes; the application surface operates.
Key Characteristics
- Near-black canvas (
{colors.canvas}#08090a) with layered surfaces distinguished by white-opacity increments ({colors.surface-subtle}, {colors.surface-glass}, {colors.surface-highlight}) - Signature rose-pink primary (
{colors.primary}#f79ce0) used sparingly on CTAs and active states, never as background wash - Inter Variable typeface at precise fractional weights (510 display, 590 titles, 400 body) with aggressive negative tracking on headlines
- Berkeley Mono subsystem (
{typography.mono}) for all machine-readable identifiers, code snippets, and technical metadata - Razor-thin borders (
{colors.hairline}at 8% white opacity) defining container edges without visual weight - Pill-shaped navigation and button radii (
{rounded.pill}) contrasting with moderate 6px rounding on cards and inputs ({rounded.md}) - Micro-shadow elevation system (
{extensions.shadows.hairline},{extensions.shadows.inner-border}) using inset borders and subtle ambient occlusion - Fast transition timing (100-160ms) with custom cubic-bezier easing for all interactive state changes
- Application-preview mockup embedded in marketing surface, demonstrating the product's own design language applied to itself
Colors
Brand & Accent
- Primary (
{colors.primary}— #f79ce0): The signature rose-pink voltage color. Used exclusively for CTAs ({component.button-primary}), active/hover states on interactive elements, and brand-requiring moments. Never deployed as a field or background fill. - Primary Hover (
{colors.primary-hover}— #f588d6): Slightly deepened primary for hover states on buttons and links. - Primary Active (
{colors.primary-active}— #f074cc): Pressed/depressed state for primary buttons, providing tactile feedback through saturation shift. - Accent Indigo (
{colors.accent-indigo}— #6366f1): Functional blue-violet for informational badges, link alternatives, and secondary interactive hints. - Accent Warm (
{colors.accent-warm}— #f7bf8b): Amber-peach tone for warning-adjacent semantics, highlight annotations, and status indicators requiring warmth without alarm. - Accent Yellow (
{colors.accent-yellow}— #ffdf9f): Golden yellow reserved for premium callouts, starred items, and attention-grabbing labels. - Accent Teal (
{colors.accent-teal}— #83dcdc): Cyan-teal for success-adjacent states, completion indicators, and positive feedback signals.
Surface
- Canvas (
{colors.canvas}— #08090a): The root background—extremely dark charcoal, nearly black. Used for page-level backgrounds ({component.hero-band},{component.top-nav}outer shell). - Surface Soft (
{colors.surface-soft}— #000000): Pure black. Used for the application preview container ({component.app-preview-container}) and sidebar ({component.sidebar}) to create maximum contrast against the slightly lighter canvas. - Surface Strong (
{colors.surface-strong}— #0f1011): Slightly lifted dark surface for elevated panels, dropdown backdrops, and modal foundations. - Surface Elevated (
{colors.surface-elevated}— #121214): Mid-tier elevation for floating panels like the Copilot chat bubble ({component.copilot-panel}). - Surface Overlay (
{colors.surface-overlay}— #23252a): Medium-gray dark for disabled surfaces, placeholder fills, and heavy modals. - Surface Subtle (
{colors.surface-subtle}— rgba(255, 255, 255, 0.02)): Barely-perceptible white tint for input backgrounds ({component.text-input}) and hover zones on dark surfaces. - Surface Muted (
{colors.surface-muted}— rgba(255, 255, 255, 0.03)): Slightly stronger white tint for table row alternates, list item hovers, and subtle separators. - Surface Glass (
{colors.surface-glass}— rgba(255, 255, 255, 0.05)): Noticeable glass-like surface for selected sidebar items ({component.sidebar-item-active}), badge backgrounds, and card fills. - Surface Highlight (
{colors.surface-highlight}— rgba(255, 255, 255, 0.08)): Strongest white-tinted surface for inline code blocks ({component.inline-code}), focused input backgrounds, and highlighted regions.
Text
- Ink (
{colors.ink}— #f7f8f8): Near-white primary text color. Used for headlines ({component.hero-headline}), important labels, and any text requiring maximum contrast against dark surfaces. - Body (
{colors.body}— #62666d): Medium-gray for body copy that needs to be readable but de-emphasized relative to headings. - Muted (
{colors.muted}— #a8f898): Softer gray for navigation links ({component.nav-link}), timestamps, metadata, and secondary information. - Muted Soft (
{colors.muted-soft}— #8a8f98): Further-deemphasized gray for issue IDs ({component.issue-id}), section labels ({component.sidebar-section-label}), and tertiary content. - On Dark (
{colors.on-dark}— #e2e4e7): Warm-toned off-white for text sitting on dark-but-not-canvas surfaces, providing slight warmth differentiation from pure ink. - On Surface (
{colors.on-surface}— #d0d6e0): Surface-appropriate text color for form labels, placeholder text, and content within elevated containers. - On Primary (
{colors.on-primary}— #08090a): Text rendered inside primary-colored buttons and badges—dark enough for AA contrast against{colors.primary}.
Hairlines & Borders
- Hairline (
{colors.hairline}— rgba(255, 255, 255, 0.08)): Default border color for input fields ({component.text-input}), card edges, container outlines, and dividers. Extremely subtle—intentionally barely visible. - Hairline Soft (
{colors.hairline-soft}— rgba(255, 255, 255, 0.05)): Even subtler variant for nested borders and decorative separators where minimum visibility suffices. - Border Strong (
{colors.border-strong}— rgba(255, 255, 255, 0.12)): Visible-but-still-restrained border for focus rings, active input states, and emphasized container edges. - Border Inset (
{colors.border-inset}— rgb(35, 37, 42)): Solid dark-gray inset border used for inner shadow simulation and pressed-button effects.
Semantic
- Success Tint (
{colors.success-tint}— rgba(0, 255, 5, 0.1)): Green-tinted background for success-state badges ({component.badge-success}) and positive status indicators. - Link (
{colors.link}— #f7f8f8): Default link color matching ink—links don't use a separate hue in this system; they rely on context and interaction. - Link Active (
{colors.link-active}— #f79ce0): Hover/active link color shifting to primary pink for interactive feedback. - Button Invert BG (
{colors.button-invert-bg}— #e5e5e6): Light gray background for the "Sign up" / secondary button style ({component.button-secondary}). - Button Invert Text (
{colors.button-invert-text}— #08090a): Dark text color paired with invert button background.
Typography
Font Family
Linear's typographic foundation rests entirely on Inter Variable, a variable-font version of Rasmus Andersson's Inter typeface—chosen for its exceptional legibility at small sizes on screens, its extensive weight range enabling the system's fractional-weight usage (510, 590), and its neutral, engineering-first personality that aligns with Linear's product-development audience. The fallback stack includes SF Pro Display for Apple ecosystem fidelity, then system fonts (BlinkMacSystemFont → Segoe UI → Roboto chain) ensuring graceful degradation everywhere.
The monospace subsystem uses Berkeley Mono—a proprietary, highly optimized programming font with excellent readability at small sizes and distinctive character forms that signal "code" or "technical identifier" instantly. It falls back to ui-monospace, SF Mono, Menlo, and finally generic monospace.
Inter Variable plays both display and body roles—there is no second serif or display face. The system achieves hierarchy through size (64px → 48px → 20px → 16px → 15px → 13px), weight modulation (590 titles vs. 400 body), letter-spacing aggression (-1.408px on display-xl, -0.24px on title-md), and color value shifts (ink vs. muted vs. muted-soft).
Hierarchy
| Token | Size | Weight | Line Height | Letter Spacing | Use |
|---|---|---|---|---|---|
| {typography.display-xl} | 64px | 510 | 64px | -1.408px | Hero headline (H1) |
| {typography.display-lg} | 48px | 510 | 48px | -1.056px | Section headline (H2), issue card titles |
| {typography.title-md} | 20px | 590 | 26.6px | -0.24px | Subsection heading (H3), card headers |
| {typography.title-sm} | 16px | 590 | 24px | normal | Minor heading (H4), label groups |
| {typography.body-md} | 15px | 400 | 24px | -0.165px | Body copy, descriptions, paragraphs |
| {typography.body-sm} | 14px | 400 | 22px | -0.154px | Secondary body, captions, metadata |
| {typography.caption} | 13px | 400 | 20px | 0 | Navigation, sidebar items, tiny labels |
| {typography.button} | 13px | 400 | 20px | 0 | Button text (ghost/nav style) |
| {typography.button-bold} | 13px | 510 | 20px | 0 | Button text (primary/CTA style) |
| {typography.label} | 13.33px | 400 | 20px | 0 | Form labels, UI chrome text |
| {typography.mono} | 13px | 400 | 20px | 0 | Code snippets, issue IDs, commands |
Principles
Linear's typography system trusts size over weight for establishing hierarchy. While weights do increase for titles (590 vs. 400), the jumps are modest—this is not a bold-or-nothing system. The display roles (510) are only marginally heavier than body (400), meaning a headline at 64px feels imposing because of its scale, not because it's visually "heavy." This restraint gives the interface a calm, controlled voice appropriate for tools used over long work sessions.
Negative letter-spacing is a signature move. The {typography.display-xl} at -1.408px tracking and {typography.display-lg} at -1.056px create tightly-set headline blocks that feel engineered rather than typeset—like precision-machined text. This tightness contrasts with body text's slight negative tracking (-0.165px), which improves word recognition without feeling compressed.
Color does significant hierarchical work. A headline in {colors.ink} (#f7f8f8) against body text in {colors.muted} (#a8f898) creates roughly a 2.4:1 luminance ratio difference before accounting for size. Tertiary information (issue IDs, timestamps) drops to {colors.muted-soft} (#8a8f98), nearly blending with the surface. This three-tier text-color strategy means the same font at the same size can carry three different information priorities.
There are no italic or uppercase conventions in the extracted interface—all text is sentence-case or lowercase, with capitalization following standard grammatical rules. The system avoids text-transform entirely.
Note on Font Substitutes
Inter Variable is available as a free variable-font download from rsms.me/inter. For Google Fonts integration, substitute "Inter" (the static version)—variable-axis support varies by rendering engine, but the closest Google Fonts match is font-family: 'Inter', sans-serif. Define CSS variables:
:root {
--font-sans: "Inter Variable", "SF Pro Display", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
--font-mono: "Berkeley Mono", ui-monospace, "SF Mono", Menlo, monospace;
}
Berkeley Mono is proprietary. Substitute with JetBrains Mono or Fira Code (both on Google Fonts) for the monospace role—they share similar character widths and developer-friendly design. For a system-monospace fallback that's free and widely available, SF Mono (macOS) or Cascadia Code (Windows) work well.
Layout
Spacing System
- Base unit: 1px (system operates on pixel-exact values with no rem/em abstraction).
- Tokens:
{spacing.xxs}(2px — micro-gap, inset adjustments),{spacing.xs}(3px — icon padding),{spacing.sm}(4px — tight internal gaps),{spacing.md}(5px — icon-text spacing),{spacing.base}(6px — compact element spacing),{spacing.lg}(8px — standard internal gap),{spacing.xl}(12px — component padding),{spacing.xxl}(19px — loose internal gap),{spacing.section-sm}(22px — minor section spacing),{spacing.section-md}(24px — standard vertical rhythm),{spacing.section-lg}(32px — major section break),{spacing.section}(72px — hero/padding-top). - Section padding (vertical):
{spacing.section}(72px) — used on{component.hero-band}top padding and major content band spacing. - Card internal padding:
{spacing.lg}(8px) for dense UI cards,{spacing.xl}(12px) for form inputs ({component.text-input}),{spacing.section-md}(24px) for spacious content cards. - Gutters: Marketing surface uses implicit centering within
{spacing.container}(1440px max-width). Application preview uses fixed sidebar width (240px) with fluid main content area.
Grid & Container
Max content width is 1440px ({spacing.container}), applied to <main>, <section>, <header>, and <nav> containers. This is a wide-format layout designed for desktop-first tool interfaces—content spreads horizontally rather than constraining to blog-width columns.
The marketing surface uses a single-column editorial layout centered within the 1440px constraint, with the hero headline occupying roughly 60% width and the app preview mockup positioned below or adjacent depending on viewport. The application preview itself demonstrates a two-column layout: fixed 240px sidebar ({component.sidebar}) + fluid main content area containing the issue detail view.
At desktop widths, the hero section splits approximately 55/45 between the text column (left) and the announcement/preview column (right). No multi-column marketing grids are visible in this view—Linear favors vertical narrative flow over feature-card mosaics.
Whitespace Philosophy
Whitespace in Linear is functional, not decorative. The marketing surface uses generous vertical padding (72px) to create "breathing room" around the headline, but horizontal space is tightly managed—the headline wraps naturally rather than being artificially constrained. The application preview demonstrates high information density: sidebar items pack closely, issue details stack with minimal padding, and activity feeds use 6px vertical gaps. The system distinguishes between "reading whitespace" (marketing) and "operating whitespace" (app), applying each appropriately.
Header Architecture
┌─────────────────────────────────────────────────────────────────────┐
│ [Logo] Product Resources Customers Pricing [Log in] [Sign up] │
│ Now Contact │
└─────────────────────────────────────────────────────────────────────┘
↑ ↑
(flush-left logo) (flush-right utilities)
Max-width: 1440px (implicit, centered)
Height: 64px ({component.top-nav})
Nav items: pill-shaped ({rounded.pill}), 12px horizontal padding
Sign up: invert-style button ({component.button-secondary})
Navigation items are horizontally spaced with implicit gaps, each rendered as a pill-shaped touch target. The logo anchors left; authentication and signup anchor right. No center-aligned elements exist in this nav configuration.
Hero Section
┌─────────────────────────────────────────────────────────────────────┐
│ │
│ The product development │
│ system for teams and agents │
│ │
│ Purpose-built for planning and building products. Designed for... │
│ │
│ ● Issue tracking is dead linear.app/next → │
│ │
│ ┌─ App Preview Container ({component.app-preview-container}) ───┐ │
│ │ ┌──────┐ ┌──────────────────────────────────────────────┐ │ │
│ │ │Sidebar│ │ Faster app launch ★ ... 02/145 ENG │ │ │
│ │ │ │ │ │ │ │
│ │ │ Inbox│ │ Faster app launch │ │ │
│ │ │ My │ │ Render UI before [vehicle_state] sync... │ │ │
│ │ │ Rev │ │ │ │ │
│ │ │ Pulse│ │ Activity │ │ │
│ │ │ │ │ ... │ │ │
│ │ └──────┘ └──────────────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
Padding-top: 72px ({spacing.section})
Headline: {typography.display-xl}, {colors.ink}
Subhead: {typography.body-md}, {colors.muted}
Announcement: inline badge + link, {typography.body-sm}
The hero pairs a bold editorial statement (two-line 64px headline) with a single-line subheadline, followed by an inline announcement banner ("Issue tracking is dead") that includes a status dot, text, and external link. Below this, the application preview container dominates the lower hero—an accurate render of Linear's own interface showing a sidebar navigation, an issue detail view with title, description, status badges, assignee avatars, and an activity feed, plus a floating Copilot AI panel in the bottom-right corner of the preview.
Application Preview Layout
The embedded app mockup reveals Linear's internal layout patterns:
┌─ Preview Container (border: 1px hairline, rounded: 8px) ──────────┐
│ │
│ ┌─ Sidebar (240px wide, bg: #000000) ─┐ ┌─ Main Content ────────┐ │
│ │ [Linear ▼] │ │ │ │
│ │ 🔍 ⬜ │ │ [Header: issue info] │ │
│ │ │ │ │ │
│ │ 📥 Inbox │ │ Faster app launch │ │
│ │ ✶ My issues │ │ (title: {title-md}) │ │
│ │ ↻ Reviews │ │ │ │
│ │ ⚡ Pulse │ │ Description text... │ │
│ │ │ │ (body: {body-sm}) │ │
│ │ Workspace ▾ │ │ │ │
│ │ ◆ Initiatives │ │ Activity │ │
│ │ ◆ Projects │ │ ───────────── │ │
│ │ ⋯ More │ │ • activity item │ │
│ │ │ │ • activity item │ │
│ │ Favorites ▾ │ │ • activity item │ │
│ │ ⚠ Faster app launch │ │ │ │
│ └─────────────────────────────────────┘ │ [Copilot] ──┐ │
│ └───────────────────────│─┘ │
│ (float)│
└────────────────────────────────────────────────────────────────────┘
The sidebar uses a sectioned navigation pattern: workspace switcher at top, primary navigation (Inbox, My Issues, Reviews, Pulse), expandable sections (Workspace, Favorites), each with section labels in muted-soft color. Active items receive {colors.surface-glass} background. The main content area shows a typical issue detail view with header metadata (starred indicator, issue number, issue ID), title, description with inline code reference, and reverse-chronological activity feed.
The Copilot panel floats bottom-right within the preview, demonstrating an overlay/assistant UI pattern with header, message content, and dismiss control.
Elevation & Depth
| Level | Treatment | Use |
|---|---|---|
| 0 (Flat) | No shadow, no border | Base canvas ({colors.canvas}), flat hero band background |
| 1 (Hairline) | {extensions.shadows.hairline} — 0 1.2px 0 rgba(0,0,0,0.03) | Subtle lift on nav bar bottom edge, card top-edge definition |
| 2 (Border) | 1px {colors.hairline} outline | Input fields ({component.text-input}), app preview container ({component.app-preview-container}), panel edges |
| 3 (Inner Shadow) | {extensions.shadows.md} — inset 0 0 12px rgba(0,0,0,0.2) | Pressed button states, active tab indicators, input focus halos |
| 4 (Inner Border) | {extensions.shadows.inner-border} — inset 0 0 0 1px rgb(35,37,42) | Form container inner edges, modal content boundaries |
| 5 (Float) | {extensions.shadows.sm} — 0 2px 4px rgba(0,0,0,0.4) | Dropdown menus, tooltip surfaces, popover panels |
| 6 (Button) | {extensions.shadows.button} — complex layered shadow | Elevated buttons ({component.button-secondary}), floating action surfaces |
Linear's depth philosophy is layered-flat: surfaces distinguish themselves through subtle opacity differences in white-tinted overlays combined with hairline borders, rather than dramatic drop shadows. Shadows exist but are extremely restrained—never the cartoonish "floating card" aesthetic common in lighter systems. On a near-black canvas, traditional drop shadows (which darken) are invisible, so the system relies instead on inner shadows (for pressed/inset effects) and border brightness (for lifted edges).
The darkest surfaces ({colors.canvas}, {colors.surface-soft}) feel recessed; surfaces with {colors.hairline} borders feel co-planar but defined; surfaces with {colors.surface-glass} backgrounds feel slightly raised. This is a value-based depth system rather than a shadow-based one—lightness equals elevation in dark mode.
No gradient washes, no rainbow decorative treatments, no photographic depth techniques were detected. The system's "decorative depth" comes entirely from the embedded application screenshot—a meta-choice where the product itself becomes the visual texture.
Shapes
Border Radius Scale
| Token | Value | Use |
|---|---|---|
| {rounded.sm} | 2px | Sharp containers, inline code blocks, subtle UI chrome |
| {rounded.DEFAULT} | 4px | Default card rounding, sidebar items, badge containers |
| {rounded.md} | 6px | Primary input fields, standard cards, panel corners |
| {rounded.lg} | 8px | Large containers (app preview, copilot panel), prominent cards |
| {rounded.circle} | 50% | Avatar images, status dots, circular icon buttons |
| {rounded.pill} | 9999px | Navigation links, buttons, tags, fully-rounded elements |
The shape vocabulary is intentionally narrow—six values cover every geometric need. The progression from 2→4→6→8px is linear and predictable. Circular and pill variants serve specific semantic purposes (avatars always round, CTAs always pill). There are no exotic radii (no 12px, no 18px, no asymmetrical squircles).
Photography Geometry
No photography is present in the extracted view. The only imagery is the application preview mockup—a screenshot/render of Linear's own interface contained within a rounded rectangle ({rounded.lg}, 8px corners) with a 1px hairline border. This container maintains a roughly 16:10 aspect ratio and is displayed at substantial scale (occupying ~70% of hero vertical space below the text block).
If user avatars or team photos were present, the system would likely apply {rounded.circle} (based on the assignee avatar component token) with possible subtle border treatment.
Components
No hover states documented. Hover behavior is unreliable to extract from a single screenshot. State variants live as separate entries in the
components:frontmatter (e.g.{component.button-primary-active},{component.text-input-focus}); add hover styling at implementation time per your stack's conventions.
Buttons
{component.button-primary} — The primary call-to-action button with {colors.primary} (#f79ce0) background and {colors.on-primary} (#08090a) dark text. Uses {typography.button-bold} (13px/510 weight), {rounded.pill} radius (fully rounded), and 12px horizontal padding. Height is constrained to 32px. Appears in the top navigation as "Sign up" (though the current implementation uses the secondary/invert style there—primary would appear in conversion-focused contexts). Includes {extensions.shadows.button} layered shadow stack. State variant: {component.button-primary-active} shifts to {colors.primary-active}.
{component.button-primary-active} — Pressed/active state of primary button. Background transitions to deeper {colors.primary-active} (#f074cc), maintaining all other properties. Implement on :active pseudo-class or equivalent press state.
{component.button-secondary} — The "invert" button style used for the actual "Sign up" button in the top navigation. Light gray background ({colors.button-invert-bg} #e5e5e6) with dark text ({colors.button-invert-text} #08090a). Uses {typography.button-bold}, {rounded.pill}, 12px padding, 32px height. Features the full {extensions.shadows.button} shadow stack giving it slight elevation against the dark canvas. This button style bridges the marketing-to-app transition—it looks "native" when placed on the dark surface. State variant: {component.button-secondary-active}.
{component.button-secondary-active} — Pressed state of secondary/invert button. Background shifts to {colors.on-dark} (#e2e4e7) with text flipping to {colors.canvas} (#08090a), creating a pressed-in effect.
{component.button-ghost} — Transparent-background button for navigation links and non-CTA interactions. Text color {colors.muted} (#a8f898), {typography.button} (regular weight), {rounded.pill}, 12px horizontal padding. No shadow, no border—invisible until interacted with. Used for Product, Resources, Customers, Pricing, Now, Contact, Log In in the top nav. State variant: {component.button-ghost-hover} adds {colors.surface-subtle} background and brightens text to {colors.on-dark}.
{component.button-ghost-hover} — Hover state for ghost buttons. Gains subtle {colors.surface-subtle} background (2% white) and text color lifts to {colors.on-dark} (#e2e4e7). Transition uses {extensions.motion.duration-fast} (100ms) with standard easing.
Cards & Containers
{component.app-preview-container} — The large application mockup wrapper dominating the lower hero. Pure black background ({colors.surface-soft} #000000) creating a "window into the app" effect, differentiated from the page's slightly lighter {colors.canvas}. Rounded to {rounded.lg} (8px), bordered with 1px {colors.hairline}. Contains the full sidebar + main-content + copilot layout. No internal padding—the child components manage their own spacing.
{component.issue-card} — An issue detail view within the app preview. Transparent background (inherits parent), text in {colors.ink}, {typography.title-md} (20px/590) for the title. Rounded {rounded.DEFAULT} (4px), padded {spacing.lg} (8px). Contains child components: title ({component.issue-card-title}), description ({component.issue-card-description}), status badges, priority indicators, assignee avatars, and activity feed.
{component.copilot-panel} — Floating AI assistant panel visible bottom-right within the app preview. Background {colors.surface-elevated} (#121214), text {colors.muted}, rounded {rounded.lg} (8px), padded {spacing.lg}, bordered with 1px {colors.hairline}. Demonstrates an overlay/tooltip pattern. Contains header ({component.copilot-header} showing "GitHub Copilot") and message body ({component.copilot-message}).
{component.hero-band} — The full-width hero section container. Background {colors.canvas} (#08090a), text defaults to {colors.ink}, vertically padded {spacing.section} (72px top). Contains the headline, subheadline, announcement ticker, and app preview. Uses {typography.display-xl} as its associated display role.
Inputs & Forms
{component.text-input} — Standard text input field. Background {colors.surface-subtle} (2% white), text {colors.on-surface} (#d0d6e0), {typography.label} (13.33px), rounded {rounded.md} (6px), padded 12px vertical × 14px horizontal. Bordered with 1px {colors.hairline}. Height auto-expands with content (appears as textarea in some contexts). State variant: {component.text-input-focus}.
{component.text-input-focus} — Focused input state. Background remains {colors.surface-subtle}, text color intensifies to {colors.ink} (#f7f8f8) for maximum readability during editing, border thickens visually to {colors.border-strong} (12% white). Focus ring may combine border change with subtle inner glow (extracted CSS shows {extensions.shadows.inner-border} pattern for focus indication).
{component.search-input} — Search/filtered input variant. Fully transparent background (shows parent surface), text {colors.ink} (#f7f8f8), {typography.body-md} (15px/400), no border radius (sharp/0px), heavily padded right (32px) for search icon placement. Appears in the app preview's toolbar area. This is a "chromeless" input that activates on focus.
Navigation
{component.top-nav} — Fixed/sticky top navigation bar spanning full viewport width. Background {colors.canvas} (#08090a), text {colors.muted} (#a8f898), {typography.button} (13px), height 64px. Contains logo (left), navigation links (center-left cluster), auth utilities (right). No visible border-bottom (relies on implicit edge detection against page content).
{component.nav-link} — Individual navigation menu item. Transparent background, {colors.muted} text, {typography.button}, {rounded.pill} (fully rounded), 12px horizontal padding. Used for Product, Resources, Customers, Pricing, Now, Contact. State variants: {component.nav-link-active} (current page, {colors.ink} text), {component.nav-link-hover} (hover, {colors.on-dark} text).
{component.nav-link-active} — Current-page navigation link. Text color upgrades to {colors.ink} (#f7f8f8) indicating the active section. No background change—reliance on color alone for active indication keeps the nav visually quiet.
{component.sidebar} — Left sidebar within the app preview. Background {colors.surface-soft} (#000000), text {colors.muted}, fixed width 240px, {typography.caption} (13px) for all items. Vertically padded {spacing.lg} (8px) top/bottom. Contains workspace switcher, navigation items, collapsible sections, favorites. Demonstrates the app's persistent navigation pattern.
{component.sidebar-header} — Workspace switcher at sidebar top. Transparent background, {colors.ink} white text, {typography.label}, rounded {rounded.DEFAULT} (4px), minimal padding (0×4px). Shows "Linear" with chevron dropdown indicator. Acts as org/context switcher.
{component.sidebar-item} — Standard sidebar navigation entry. Transparent background, {colors.muted} gray text, {typography.caption}, {rounded.DEFAULT} (4px), padded {spacing.sm} (4px) vertical × {spacing.xl} (12px) horizontal. Icon + label pair. Used for Inbox, My Issues, Reviews, Pulse. State variants: {component.sidebar-item-hover} (subtle bg), {component.sidebar-item-active} (glass bg + white text).
{component.sidebar-item-active} — Selected sidebar item. Background becomes {colors.surface-glass} (5% white), text color lifts to {colors.ink} (#f7f8f8). Creates clear selection affordance without heavy highlighting.
{component.sidebar-section-label} — Collapsible section header (Workspace, Favorites). Transparent background, {colors.muted-soft} (#8a8f98) dimmed text, {typography.caption}, padded {spacing.xl} (12px) horizontal with tight vertical spacing. Uppercase or small-cap treatment implied by color demotion alone.
{component.sidebar-favorite-item} — Starred/favorited item under Favorites section. Same structure as {component.sidebar-item} but may include star icon prefix. Shares hover/active state behavior.
Sub-Systems (Application Preview Elements)
{component.issue-card-title} — Issue title text. Inherits card context, {colors.ink} (#f7f8f8), {typography.title-md} (20px/590 weight). The primary identifier within the issue detail view.
{component.issue-card-description} — Issue description body. {colors.muted} (#a8f898), {typography.body-sm} (14px/400), line-height 22px. May contain inline code spans ({component.activity-inline-code}). Wraps naturally within the card.
{component.issue-status-badge} — Status indicator (e.g., "In Progress"). Transparent background, {colors.accent-warm} (#f7bf8b) amber text, {typography.body-sm}, {rounded.DEFAULT} (4px). Often paired with status dot/icon. Color implies semantic state.
{component.issue-priority-badge} — Priority indicator ("High"). Transparent background, {colors.muted} text, {typography.body-sm}. Minimal visual weight—priority is communicated through position and convention.
{component.issue-assignee-avatar} — User avatar circle. Background {colors.surface-highlight} (8% white) with user image or initial, {rounded.circle} (50%), fixed 24px size. Appears next to assignee name in the issue detail metadata area.
{component.issue-id} — Machine-readable issue identifier ("ENG-2703"). {colors.muted-soft} (#8a8f98) very dim text, {typography.mono} (Berkeley Mono, 13px). Positioned in the header metadata row. Signals "copyable/referenceable identifier."
{component.activity-feed} — Chronological event list within the issue detail. Transparent background, {colors.muted} text, {typography.body-sm}. Vertical stack of {component.activity-item} entries separated by 6px gaps.
{component.activity-item} — Single activity event (comment, status change, label addition). {colors.muted} text, {typography.body-sm}, 6px top/bottom padding. Contains actor name (white/bold), action verb (muted), timestamp (dimmed), and optional inline code or entity references.
{component.activity-inline-code} — Inline code span within activity text. Background {colors.surface-highlight} (8% white), text {colors.on-surface} (#d0d6e0), {typography.mono}, {rounded.sm} (2px), padded 1px×4px. Example: [vehicle_state] in the sample issue description.
{component.badge} — Generic tag/pill badge. Background {colors.surface-glass} (5% white), text {colors.muted}, {typography.caption}, {rounded.pill} (fully rounded), padded 2px×8px. Used for labels, tags, and lightweight categorization.
{component.badge-success} — Success-state badge variant. Background {colors.success-tint} (green tint), bright green text (#00ff00), {typography.caption}, {rounded.pill}, 2px×8px padding. High-vibrancy semantic indicator.
{component.inline-code} — Standalone inline code element (not within activity feed). Background {colors.surface-highlight}, text {colors.on-surface}, {typography.mono}, {rounded.sm} (2px), 1px×4px padding. Terminal-aesthetic treatment for technical references anywhere in the UI.
{component.external-link} — External navigation link with arrow indicator. {colors.ink} text, {typography.body-sm}, arrow suffix (→). Used in hero announcement ("linear.app/next →").
{component.hero-headline} — Main H1 headline. Transparent background, {colors.ink} (#f7f8f8), {typography.display-xl} (64px/510/-1.408px tracking). Two-line wrap in current viewport. Maximum visual weight element on the page.
{component.hero-subheadline} — Headline supporting paragraph. Transparent background, {colors.muted} (#a8f898), {typography.body-md} (15px/400/-0.165px tracking). Single-line descriptive text beneath the headline.
{component.hero-cta-row} — Announcement/ticker area. Transparent background, {colors.muted} text, {typography.body-sm}. Contains status dot (colored circle), announcement text, and external link. Horizontal layout, aligned with headline's right edge.
{component.hero-announcement} — Individual announcement item. Part of the CTA row. {colors.ink} text for readability, {typography.body-sm}. The "Issue tracking is dead" text plus link.
{component.label-default} — Generic form/chrome label. Transparent background, {colors.on-surface} text (#d0d6e0), {typography.label} (13.33px). Used for field labels, sidebar item text, and UI chrome descriptions.
{component.copilot-header} — Copilot panel title. Transparent background, {colors.ink} text, {typography.body-sm} (slightly heavier than panel body). Shows provider/name ("GitHub Copilot") with optional dismiss control.
{component.copilot-message} — Copilot panel message content. Transparent background, {colors.muted} text, {typography.body-sm}. Multi-line message from AI assistant. May include inline formatting.
Do's and Don'ts
Do
- Do use
{colors.primary}(#f79ce0) sparingly—reserve for CTAs, active states, and brand moments. Overuse dilutes its voltage. - Do maintain the near-black canvas (
{colors.canvas}#08090a) as your deepest surface. Never introduce lighter blacks that compete with the intentional darkness. - Do apply
{typography.display-xl}with its -1.408px letter-spacing for headlines. The tight tracking is essential to the architectural type voice. - Do use Berkeley Mono (
{typography.mono}) for all machine-readable identifiers (issue IDs, codes, commands). The monospace subsystem signals "technical content." - Do implement the six-value radius scale exactly as defined (
{rounded.sm}through{rounded.pill}). Don't invent new radii. - Do layer surfaces using the opacity-based white-tint system (
{colors.surface-subtle}→{colors.surface-glass}→{colors.surface-highlight}). Value equals elevation in this dark system. - Do keep body text at 15px (
{typography.body-md}) rather than dropping to 14px for general content. The extra pixel aids long-session readability. - Do use the fast transition timing (100-160ms) with
cubic-bezier(0.25, 0.46, 0.45, 0.94)for all state changes. Linear's interactions feel snappy and precise. - Do render the app preview mockup with
{colors.surface-soft}(#000000) as its background, one shade darker than the page canvas. This creates the "window" effect. - Do use
{rounded.pill}for all buttons and navigation items. Linear's touch targets are fully rounded—this is a consistent shape language choice. - Do apply
{colors.muted-soft}(#8a8f98) to tertiary text like issue IDs and timestamps. Let the information hierarchy breathe through color demotion.
Don't
- Don't substitute
{colors.link-active}(pink) for{colors.primary}in non-link contexts. They're semantically different—primary is structural, link-active is behavioral. - Don't bold display headings beyond their specified weight (510). The system achieves impact through scale, not weight. Adding bold would破坏 the refined voice.
- Don't add gradient backdrops or colorful washes to the hero section. The canvas is
{colors.canvas}—pure, dark, undecorated. Let the type and preview do the work. - Don't use shadows darker than
{extensions.shadows.sm}on the dark canvas. Heavy drop shadows are invisible against near-black backgrounds; rely on borders and inner shadows instead. - Don't promote the application-preview density to the marketing surface. The marketing layer breathes (72px padding, 64px type); the app layer operates (240px sidebar, 6px gaps). Respect the dialect boundary.
- Don't mix font families beyond Inter Variable and Berkeley Mono. No serif accents, no display faces, no script elements. The system is deliberately bifont.
- Don't expand the color palette beyond the defined 30+ tokens. If you need a new semantic color, derive it from the existing accent family or surface opacity scale.
- Don't round corners beyond
{rounded.lg}(8px) on containers. Large radii (12px, 16px, 24px) read as "friendly consumer app," not "precision development tool." - Don't use uppercase or italic text transforms. Linear's voice is sentence-case, regular weight, neutral posture. Let the content speak without typographic gymnastics.
- Don't omit hairline borders on input fields and containers. Even though they're barely visible (
{colors.hairline}at 8% opacity), they provide essential edge definition on dark surfaces.
Motion & Animation
Transition Tokens
/* Fast color/background transitions (buttons, links, hover states) */
--transition-fast:
border-color 0.1s cubic-bezier(0.25, 0.46, 0.45, 0.94),
background 0.1s cubic-bezier(0.25, 0.46, 0.45, 0.94);
--transition-fast-color:
color 0.1s cubic-bezier(0.25, 0.46, 0.45, 0.94),
background 0.1s cubic-bezier(0.25, 0.46, 0.45, 0.94);
/* Normal transitions (cards, panels, complex interactions) */
--transition-normal:
border 0.16s cubic-bezier(0.25, 0.46, 0.45, 0.94),
background-color 0.16s cubic-bezier(0.25, 0.46, 0.45, 0.94),
color 0.16s cubic-bezier(0.25, 0.46, 0.45, 0.94),
box-shadow 0.16s cubic-bezier(0.25, 0.46, 0.45, 0.94),
opacity 0.16s cubic-bezier(0.25, 0.46, 0.45, 0.94),
filter 0.16s cubic-bezier(0.25, 0.46, 0.45, 0.94),
transform 0.16s cubic-bezier(0.25, 0.46, 0.45, 0.94);
/* Filter-specific transition */
--transition-filter: filter 0.16s cubic-bezier(0.25, 0.46, 0.45, 0.94);
/* Background-only */
--transition-background: background 0.16s cubic-bezier(0.25, 0.46, 0.45, 0.94);
/* SVG/fill transition */
--transition-fill: fill 0.15s;
/* Fallback */
--transition-color-simple: color;
Keyframe Animations
grid-dot-*series (grid-dot-0-0-agent through grid-dot-3-4-agent): A 5×4 grid of staggered dot animations (20 total keyframes detected). Likely powers the animated agent/grid visualization that appears in other sections of Linear's site (not visible in this viewport but referenced in extracted keyframes). Each dot animates independently with offset delays, creating a coordinated "processing" or "thinking" visualization.
Interaction Patterns
- Button state transitions: All buttons transition background-color and color at 100ms (
{extensions.motion.duration-fast}) with the custom cubic-bezier easing. Ghost buttons gain background on hover; primary buttons deepen in saturation on press. - Input focus transitions: Text inputs transition border-color (from
{colors.hairline}to{colors.border-strong}) and potentially background opacity over 160ms. Text color may also lift from{colors.on-surface}to{colors.ink}. - Navigation link hovers: Nav items transition from
{colors.muted}to{colors.on-dark}text color at 100ms. No background appears on hover for nav links (unlike sidebar items which get{colors.surface-subtle}). - Sidebar item selection: Active sidebar items transition to
{colors.surface-glass}background over 160ms normal duration. Smooth background-fill animation. - Copilot panel appearance: The floating AI panel likely uses opacity + transform transitions (fade-up or fade-in) at 160ms with the normal easing curve.
- Link color shifts: Inline links (like "linear.app/next →") transition from
{colors.ink}to{colors.primary}on hover, using the fast color transition timing. - Badge/status animations: Success badges or status dots may pulse or fade-in using the fill transition (150ms) for SVG-based indicators.
- Scroll-triggered reveals: While not explicitly extractable from CSS alone, the marketing surface likely employs scroll-triggered opacity/transform animations for the headline, subheadline, and app preview entrance—common pattern for Linear's site architecture.
The motion level is subtle ({extensions.motion.level}): transitions exist and are perceptible, but never draw attention to themselves. The 100-160ms duration range ensures interactions feel responsive without feeling animated. The custom easing curve (cubic-bezier(0.25, 0.46, 0.45, 0.94)) has a slightly decelerating quality—fast start, smooth finish—that feels "engineered" rather than "bouncy."
Imagery Style
- The sole imagery in this viewport is the application interface mockup—a high-fidelity render of Linear's own product UI, presented as a "window" within the marketing page. This is meta-imagery: the product demonstrates itself.
- The mockup uses pure black background (#000000) for the app interior, creating strong contrast against the page's #08090a canvas. This 8-value difference is intentional—the app looks "inside" something.
- No photography (team photos, office shots, lifestyle imagery) is present. Linear's marketing relies on type, color, and product visualization rather than human imagery.
- No illustration (custom graphics, icons-as-art, decorative shapes) in this viewport. The visual vocabulary is purely typographic and interface-driven.
- No gradients or abstract textures on backgrounds. The canvas is flat, uniform, confident in its darkness.
- The status dot (colored circle) next to "Issue tracking is dead" functions as a micro-graphic—minimal, symbolic, color-coded.
- Avatar circles (24px,
{rounded.circle}) appear in the issue assignee area—these would be user photos or initials in production. - Icon treatment (see Icon System below) is stroke-based, monochromatic (currentColor), and rendered at 16-20px. Icons support but never dominate.
- Overall imagery philosophy: product-as-image. The interface itself is the visual asset. This aligns with Linear's positioning as a tool for people who make things—the thing being made (or managed) is the visual content.
Icon System
- Library: Custom SVG icons. Linear uses a proprietary icon set (not Lucide, Heroicons, Material, or Bootstrap). Icons are optimized for the system's dark-mode rendering and Inter/Berkeley Mono pairing.
- Specific icons observed in screenshot:
- Logo mark (spiral/linear symbol) — top-left nav
- Chevron down (▼) — workspace switcher, nav dropdowns
- Search/magnifying glass (🔍) — sidebar search trigger
- External link square (⬜ with arrow) — sidebar external link icon
- Inbox/envelope tray (📥) — sidebar Inbox item
- Target/crosshairs (✶) — sidebar My Issues item
- Refresh/reload cycle (↻) — sidebar Reviews item
- Lightning bolt (⚡) — sidebar Pulse item
- Initiative/diamond (◆) — sidebar Initiatives item
- Project/hexagon (⬡) — sidebar Projects item
- Ellipsis/dots (⋯) — sidebar More item
- Warning triangle (⚠) — sidebar favorited item (Faster app launch)
- Star/favorite (★) — issue header starred indicator
- More ellipsis (•••) — issue header overflow menu
- Exclamation circle (!) — issue status "In Progress" indicator
- Signal bars (▎▎▎) — issue priority "High" indicator
- Link/chain (🔗) — issue header link icon
- Copy/document (📄) — issue header duplicate icon
- Branch/git (⌥) — issue header branch icon
- Robot/head (🤖) — GitHub Copilot avatar placeholder
- Close/X (✕) — Copilot panel dismiss
- Arrow right (→) — external link indicator
- Status dot (●) — colored circle (blue in "Issue tracking is dead")
- Treatment: Stroke-based icons (not filled), rendered in
currentColorfor seamless color inheritance. When placed in sidebar items, icons inherit{colors.muted}; when in the active sidebar item, they inherit{colors.ink}. - Size: Consistent 16px–20px rendering within the 13px–15px text context. Icons are optically aligned with text baseline and cap height, maintaining rhythm with adjacent typography.
- Alignment: Icons precede text labels with a small gap (~6-8px). They are vertically centered with text baselines. In navigation items, icon + text form a single interactive unit.
Recommended Frontend Stack
- Framework: Next.js (App Router) — Linear's site shows Next.js patterns (layout containers,
skip-nav, script injection markers)
- Styling: CSS Modules or styled-components (unknown exact preprocessor; Tailwind unlikely
based on class naming conventions)
- Fonts: Inter Variable (self-hosted variable font from rsms.me/inter) + Berkeley Mono
(proprietary, substitute JetBrains Mono or Fira Code)
- Animation: CSS transitions primarily (100-160ms); Framer Motion for scroll-triggered
reveals if needed; GSAP unnecessary given simplicity
- Icons: Custom SVG sprite (Linear's proprietary icon set); build a React/Lightweight
component library wrapping these
- Component lib: Custom components (no Radix/shadcn detected); consider Radix primitives for
accessible dropdowns/popovers if building interactive demo
- Build: Turborepo or Nx if expanding to multi-package; Vite for standalone pages
Responsive Behavior
Breakpoints
| Name | Width | Key Changes | |---|---|---| | Mobile | < 640px | Single-column layout; nav collapses to hamburger; hero headline scales down (~36-40px); app preview hidden or stacked below with reduced complexity | | Tablet | 640px – 1024px | Two-column begins; nav may show abbreviated items; app preview visible but narrower; sidebar may collapse to icons-only | | Desktop | 1024px – 1440px | Full layout as shown; 1440px container max-width; all nav items visible; app preview at full complexity | | Wide | > 1440px | Container centers with equal margins; no content expansion beyond 1440px; additional horizontal whitespace |
Touch Targets
{component.button-primary}: ~32px height × variable width (min ~60px with 12px padding + text). Meets WCAG AAA 44×44px minimum when accounting for padding context; may need height increase to 40-44px for strict compliance.{component.button-secondary}: 32px height × variable width. Same consideration as primary.{component.button-ghost}(nav links): 32px effective height (12px padding + 13px font + implicit spacing). Should expand tap area invisibly to meet 44px minimum.{component.text-input}: Auto-height (min ~44px with 12px+12px padding + 13-15px font). Compliant.{component.sidebar-item}: ~28-32px height (8px + 13px font + 8px padding). May be undersized for mobile touch; recommend increasing to min 44px on touch devices.
Collapsing Strategy
- Top navigation: At tablet/mobile widths, the horizontal nav links (Product, Resources, Customers, etc.) collapse into a hamburger menu or move to a slide-out drawer. The logo and "Sign up" button remain visible. The mobile menu trigger was detected in extracted CSS (
Header_mobileMenuTrigger__ignIg). - Hero headline: Scales from 64px (
{typography.display-xl}) down through intermediate breakpoints (likely 48px → 36px → 28px) using responsive type sizing. Letter-spacing scales proportionally or locks at smaller sizes. - App preview container: At narrow widths, the two-column sidebar+main layout either stacks (sidebar becomes top nav or bottom sheet) or hides entirely (progressive disclosure—"see it in action" CTA replaces live preview).
- Hero column split: The text column + preview column arrangement shifts to single-column vertical stacking. Headline/subheadline/announcement stack above the app preview (if shown).
- Spacing compression:
{spacing.section}(72px) vertical padding reduces to ~40-48px on mobile. Internal component padding ({spacing.lg},{spacing.xl}) may reduce by 25-33%.
Image Behavior
- App preview mockup: At desktop, displays at full complexity (sidebar + main + copilot). At tablet, may crop sidebar or simplify to show only main content area. At mobile, likely replaced with a static thumbnail, simplified diagram, or hidden entirely with a "View demo" CTA.
- Avatars: Maintain
{rounded.circle}at all sizes. Scale from 24px (desktop) to possibly 32-40px on mobile for touch-friendly profile access. - Status dots/icons: Remain proportional to accompanying text. May increase slightly in touch contexts for tappability.
Iteration Guide
- Build a landing page that closely mimics Linear's design system using this DESIGN.md as the single source of truth. Use Next.js with CSS Modules (or your preferred styling solution that supports custom properties).
- Pull every color, font, radius, and spacing value from the YAML frontmatter via the
{section.token}paths. Define these as CSS custom properties or design-token constants in your codebase. Never hard-code a value that has a token—if you need#f79ce0, import/reference{colors.primary}. - Add state variants (
-hover,-disabled,-focus,-active) per your stack's conventions. This spec documents Default and Active/Pressed/Focus explicitly; infer hover states from the active patterns (e.g.,{component.button-primary-active}informs what{component.button-primary-hover}should approximate). - When adding a new component, decide first which sub-system it belongs to: Marketing Dialect (editorial, spacious, display-type dominated) or Application Dialect (dense, sidebar+content, badge-heavy, monospace IDs). Apply the appropriate density and spacing accordingly.
- Variants of an existing component live as separate frontmatter entries (
button-primary-active,text-input-focus)—never nest variants inside a single object. Each variant gets its own YAML key and prose description. - Run
npx @google/design.md lint DESIGN.mdafter any edits—broken-ref,contrast-ratio, andorphaned-tokenswarnings will catch missing or mismatched tokens automatically. - When in doubt about emphasis: bigger type before bolder type (the system uses 64px/weight-510 headlines, not 48px/weight-700), signature surface card (the app preview) before solid accent color washes, and opacity-layered surfaces before drop-shadow elevation.
- Implement the font setup with Inter Variable (variable font, not static) as the primary face. Load the variable-font
.woff2files from rsms.me/inter or use the Google Fonts@font-facedeclaration withfont-weight: 100 900to enable the 510/590 axis positions. For Berkeley Mono, substitute JetBrains Mono if the proprietary font isn't licensed. - Test your implementation in dark mode only initially—this system has no light mode counterpart in the extracted data. Ensure
{colors.canvas}(#08090a) renders as true dark (not gray), and that{colors.hairline}borders remain visible but subtle on real monitors. - Match the motion timing exactly: 100ms for simple color changes (hover, press), 160ms for complex property transitions (panel open, card reveal). Use
cubic-bezier(0.25, 0.46, 0.45, 0.94)for all transitions—this specific curve defines Linear's interaction feel.
Font Setup
/* CSS Variables for Linear Design System */
:root {
/* Font Families */
--font-sans: "Inter Variable", "SF Pro Display", -apple-system, BlinkMacSystemFont,
"Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans",
"Helvetica Neue", sans-serif;
--font-mono: "Berkeley Mono", ui-monospace, "SF Mono", Menlo, monospace;
/* Core Colors (subset — define all tokens from frontmatter) */
--color-canvas: #08090a;
--color-ink: #f7f8f8;
--color-primary: #f79ce0;
--color-body: #62666d;
--color-muted: #a8f8f98;
/* ... extend with all 35+ color tokens ... */
/* Typography Roles */
--font-display-xl: 500 64px/64px var(--font-sans);
--font-display-lg: 500 48px/48px var(--font-sans);
--font-body-md: 400 15px/24px var(--font-sans);
--font-mono: 400 13px/20px var(--font-mono);
/* ... extend with all typography roles ... */
}
/* Google Fonts substitute for Inter (if variable font unavailable) */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap');
/* Note: 510 and 590 weights map to 500 and 600 respectively in static Inter */
Known Gaps
- Hover state styling: Per the no-hover policy, hover appearances for buttons, links, sidebar items, and cards are inferred from active/pressed states but not directly extracted. Implement hover as midpoint between default and active.
- Loading skeletons / pending states: No loading shimmer, skeleton screen, or spinner patterns were detectable in the static CSS. These would need design decisions for async content loading.
- Form validation states beyond focus: Error states, warning borders, success confirmation styling for inputs are not represented in the extracted data. Extend
{component.text-input-focus}with error/warning/success variants using{colors.error}-family tokens (to be defined). - Authenticated-only flows: Login page, onboarding wizard, settings panels, billing dashboard, admin interfaces—not visible in the public marketing surface. These likely introduce new components (password fields, toggle switches, tables, date pickers).
- Sub-brand palettes: Linear offers different tiers (Free, Growth, Enterprise) that may have distinct accent colors or feature badges not shown on the homepage. The
accent-*tokens may expand for these contexts. - Light mode representation: This entire spec describes Linear's dark-mode appearance. The system may have a light-mode counterpart (inverted canvas, adjusted text colors, different surface opacities) that wasn't captured in this extraction.
- Pixel-exact values for translucent surfaces: Colors defined as
rgba(255, 255, 255, 0.02)and similar are derived from computed styles. These represent the author's intent for surface layering but may render differently on varying display profiles (sRGB vs. P3, gamma differences). - Animation keyframe definitions: The
grid-dot-*keyframe names were detected but their actual@keyframesrule bodies (percentage frames, transform values, timing) weren't included in the extracted CSS payload. These would need recreation or source-code reference. - Dropdown/popover components: Navigation menus with dropdown panels, user avatar menus, and context menus aren't visible in this viewport. Their styling (positioning, z-index stacking, arrow indicators) isn't captured here.
- Keyboard focus visible states: Beyond input focus borders, the global
:focus-visiblering style (outline, offset, color) for keyboard navigation isn't explicitly defined in the extracted data. Recommend implementing a consistent 2px{colors.primary}or{colors.border-strong}focus ring with 2px offset.