---
meta:
  name: "Linear"
  version: "1.0.0"
  updated: "2026-04-19"
  description: "Linear.app aesthetic — dark-first, typographic-led, dense content, single indigo accent. Feels closer to a tool than to a landing page."
  inspiration: "linear.app"

tokens:
  colors:
    bg: "#08090A"
    surface: "#0F1011"
    accent: "#5E6AD2"
    text: "#F7F8F8"
    border: "#1C1D1F"
    status:
      success: "#4CB782"
      warning: "#F2994A"
      danger: "#EB5757"
      info: "#5E6AD2"

  typography:
    families:
      primary: "Inter Variable, Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif"
      display: "Tiempos Headline, Inter Variable, Inter, ui-serif, Georgia, serif"
      mono: "Berkeley Mono, ui-monospace, 'SF Mono', Menlo, monospace"
    scale:
      - "11px"
      - "13px"
      - "14px"
      - "15px"
      - "17px"
      - "22px"
      - "28px"
      - "40px"
      - "56px"
    weights: [400, 500, 600, 700]
    lineHeight:
      tight: "1.1"
      snug: "1.3"
      normal: "1.5"

  spacing:
    - "4px"
    - "8px"
    - "12px"
    - "16px"
    - "24px"
    - "32px"
    - "48px"
    - "64px"
    - "96px"

  radius:
    none: "0px"
    sm: "4px"
    md: "6px"
    lg: "8px"
    xl: "12px"
    full: "9999px"

  shadow:
    sm: "0 1px 2px rgba(0,0,0,0.40)"
    md: "0 4px 12px rgba(0,0,0,0.50)"
    lg: "0 16px 40px rgba(0,0,0,0.55)"

  motion:
    duration:
      fast: "100ms"
      base: "180ms"
      slow: "260ms"
    easing:
      standard: "cubic-bezier(0.2, 0, 0, 1)"
      emphatic: "cubic-bezier(0.3, 0, 0, 1.2)"

components:
  button:
    radius: md
    paddingX: "12px"
    paddingY: "6px"
    fontWeight: 500
  card:
    radius: lg
    padding: "24px"
    shadow: sm
  input:
    radius: md
    paddingX: "12px"
    paddingY: "6px"
    borderWidth: "1px"

antiPatterns:
  - id: no-side-stripe-borders
    category: layout
    pattern: "border-left:\\s*(?:[3-9]|\\d{2,})px"
    why: "Side-stripe callouts (>= 3px left borders) are an AI tell — they read as generic CMS snippets, not designed surfaces."
    rewrite: "Use a subtle background tint, a top-aligned icon, or a semantic text color instead of a left stripe."
  - id: no-nested-cards
    category: layout
    pattern: "class=\"[^\"]*rounded-(?:xl|2xl|3xl)[^\"]*shadow[^\"]*\"[^>]*>\\s*<[^>]*class=\"[^\"]*rounded-(?:xl|2xl|3xl)[^\"]*shadow"
    why: "A rounded-shadowed card containing another rounded-shadowed card reads as 'I didn't know how to group these'. Flatten."
    rewrite: "Use section-level whitespace and a single card, or swap the outer card for a plain div."
  - id: no-gradient-text
    category: typography
    pattern: "background-clip:\\s*text"
    why: "Gradient text (background-clip: text) is the single strongest AI aesthetic. It reads as try-hard landing-page filler."
    rewrite: "Use a solid color from tokens.colors.text or tokens.colors.accent. Reserve gradients for non-type surfaces."
  - id: no-inter-only
    category: typography
    pattern: "font-family:\\s*['\"]?Inter['\"]?\\s*[,;]?\\s*$"
    why: "Inter as the sole declared font is the AI-default and signals zero type choice was made."
    rewrite: "Declare a primary family with intentional fallbacks (see tokens.typography.families.primary) or pick a distinctive display face."
  - id: no-all-bold-headings
    category: typography
    pattern: "<h[1-3][^>]*class=\"[^\"]*font-black\\b"
    why: "`font-black` on every heading collapses type hierarchy into shouting. Weight differentiates; shouting doesn't."
    rewrite: "Reserve font-black for one hero moment per page; use semibold/bold for most headings."
  - id: no-uppercase-body
    category: typography
    pattern: "<p[^>]*class=\"[^\"]*uppercase\\b"
    why: "ALL-CAPS body text kills readability. Uppercase belongs on labels and eyebrow text only."
    rewrite: "Use tracking-widest or small-caps on short labels; keep body at normal case."
  - id: no-purple-saas-gradient-hero
    category: color
    pattern: "linear-gradient\\([^)]*#[68][0-9a-f]{2}[a-f0-9]f[a-f0-9]"
    why: "Purple→pink hero gradients are the generic SaaS tell."
    rewrite: "Use a single tokens.colors.accent flood or a neutral photograph."
  - id: no-cyan-on-dark
    category: color
    pattern: "color:\\s*#(?:0[0-9a-f]f[0-9a-f]ff|00ffff|22d3ee|06b6d4|0891b2)\\b"
    why: "Bright cyan/electric-teal text on dark backgrounds is the 2015 futuristic-dashboard trope — high chroma, low information density."
    rewrite: "Use a desaturated accent from tokens.colors.accent or a neutral color at reduced alpha."
  - id: no-rainbow-accents
    category: color
    pattern: "(?:text|bg|border)-(?:red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-500[^\"]*\"[^>]*(?:text|bg|border)-(?:red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-500"
    why: "Multiple saturated Tailwind 500-series accents on the same surface reads as 'I couldn't decide'. Commit to one accent."
    rewrite: "Use tokens.colors.accent for primary actions; reserve status colors for semantic contexts only."
  - id: no-bounce-easing
    category: motion
    pattern: "cubic-bezier\\(0\\.68,\\s*-0\\.55"
    why: "Overshoot/bounce easings feel juvenile on UI surfaces."
    rewrite: "Use tokens.motion.easing.standard for UI, emphatic only for hero-level moments."
  - id: no-slow-default
    category: motion
    pattern: "transition(?:-[a-z]+)?:\\s*(?:all|[a-z-]+)\\s+(?:[5-9]\\d{2}|\\d{4,})ms"
    why: "Transitions >= 500ms on UI interactions feel sluggish; users interpret them as jank."
    rewrite: "Keep UI transitions under 280ms (tokens.motion.duration.slow). Reserve 500ms+ for hero entrances only."
  - id: no-permanent-spinner
    category: motion
    pattern: "animation:\\s*spin\\s+\\d+(?:\\.\\d+)?s\\s+linear\\s+infinite"
    why: "A perpetual spinner (`animation: spin … infinite`) left in a mockup for 'loading state' always ships to prod."
    rewrite: "Use discrete loading/empty/error variants side-by-side, or replace with a skeleton."
  - id: no-missing-focus
    category: interaction
    pattern: "<button[^>]*class=\"[^\"]*(?:focus:outline-none|outline-none)[^\"]*\"(?![^>]*focus-visible:)"
    why: "Removing the focus outline without replacing it breaks keyboard accessibility. This is the AI's laziest shortcut."
    rewrite: "Either keep the default outline or replace with `focus-visible:outline-2 focus-visible:outline-offset-2`."
  - id: no-placeholder-names
    category: content
    pattern: "\\b(John|Jane)\\s+Doe\\b"
    why: "John/Jane Doe placeholder strings leak into shipped UI when the AI skips real sample data."
    rewrite: "Use sample data that reflects the actual product (real-looking names, real tasks, real copy)."
  - id: no-lorem-ipsum
    category: content
    pattern: "\\bLorem\\s+ipsum\\s+dolor\\s+sit\\s+amet\\b"
    why: "Lorem ipsum in a shipped mockup means no one thought about what the copy should actually say."
    rewrite: "Write real copy that reflects the feature. If the feature is too early for copy, render a single-word label instead."

inspiration:
  - linear
---

# Linear — design contract

> **Contract:** Linear.app aesthetic — dark-first, typographic-led, minimal chrome. Focus on content density with a single indigo accent for action. The frontmatter above is the source of truth for machine-readable tokens; the sections below explain the why and give agents copy-paste prompts for component generation.

## 1. Visual Theme

Dark-first and content-dense. The product feels like a keyboard-first power tool — backgrounds are near-black (`bg: #08090A`), surfaces barely lift (`surface: #0F1011`), borders are quiet (`border: #1C1D1F`). One indigo (`accent: #5E6AD2`) carries every primary action. Type is Inter Variable at tight leading for the working surface, Tiempos serif for marketing headlines. Rounded corners are small (`md: 6px`) — no chunky cards. Motion is short (100–260ms) and always eased.

## 2. Color Palette

See `tokens.colors` in the frontmatter. Narrative rules:

- **Background** `#08090A` is near-black with a hair of green. Pure `#000` is too harsh; `#0A0A0A` reads as just-black. The green undertone is the house signature.
- **Surface** `#0F1011` lifts elevated cards, dropdowns, and the command palette. Do NOT use it for the main working surface.
- **Accent** `#5E6AD2` is Linear indigo. It carries the primary CTA, active tab underlines, focused inputs, and key data points. If `accent` appears more than three times on a screen, reduce.
- **Status colours** (`success #4CB782`, `warning #F2994A`, `danger #EB5757`, `info #5E6AD2`) are semantic only.
- **Text** `#F7F8F8` is the default. Secondary text uses the same hue at 65% alpha; tertiary at 45%.

## 3. Typography

See `tokens.typography` in the frontmatter.

- **Display** (`Tiempos Headline`) is for marketing hero moments only. Everything in-app uses `primary`.
- **Primary** (`Inter Variable`) ships with variable axis — use weight 500 for labels and UI controls, 400 for body, 600 for section headings.
- **Mono** (`Berkeley Mono`) is for identifiers (issue IDs like `ENG-1234`), keyboard shortcuts (`⌘K`), and file paths — never for prose.
- Scale is 11/13/14/15/17/22/28/40/56 — the 13/14/15 trio reflects Linear's dense inline density at the workspace surface.

## 4. Component Stylings

Token overrides live under `components` in the frontmatter. Narrative rules:

- **Button.** `md` (6px) radius, `12px` horizontal padding, `6px` vertical — compact. Primary uses `accent` on `bg`. Secondary uses `surface` with 1px `border` outline. Tertiary is `accent`-labelled text.
- **Card.** `lg` (8px) radius, `24px` padding, `sm` shadow. Cards are rare in Linear — prefer sectioned surfaces over rounded containers.
- **Input.** `md` (6px) radius, 1px `border` outline, `12px` / `6px` padding. Focus state: border replaced with `accent` 2px ring, zero offset.

## 5. Layout

- 12-column grid at ≥ 1024px; workspace is typically 3-pane (nav / content / inspector) with a fixed 260px left nav and a collapsible 360px right inspector.
- Max content width **1280px** for dense tools; marketing pages cap at **1080px**.
- Section padding uses the spacing scale — prefer `spacing[5]` (32px) between cards and `spacing[7]` (64px) between page sections.
- Hero is never centred — Linear leans on left-aligned asymmetric layouts for scanability.

## 6. Depth

- `shadow.sm` (`0 1px 2px rgba(0,0,0,0.40)`) is the only shadow on the working surface — used sparingly for floating menus.
- `shadow.md` for command palette, tooltips.
- `shadow.lg` only for modals.
- Do not stack shadows. Dark surfaces do not need multi-layer elevation.

## 7. Do's and Don'ts

**Do**
- Keep chrome minimal — favour whitespace and type weight for hierarchy over rules and dividers.
- Use `mono` for every identifier the user can copy (`ENG-1234`, commit hashes, file paths).
- Write sample data that reflects an engineering workflow (real issue titles, real cycle names, real PR links).
- Ship every interactive element with a visible focus state — keyboard is the primary input.

**Don't**
- Use any of the `antiPatterns` in the frontmatter. `apt-tools design-lint` will catch them.
- Introduce a secondary accent colour. Linear's palette is one indigo by design.
- Use Inter as the sole declared primary font string (without fallbacks and without Variable axis — the `no-inter-only` rule catches this).
- Use the brand indigo on text at body sizes — contrast is insufficient against `bg`.

## 8. Responsive

- **Narrow** (<640px): single column, the inspector and nav collapse into command-palette-only interactions.
- **Medium** (640–1023px): 8-column grid, inspector docks to a bottom sheet.
- **Wide** (≥1024px): 12-column grid, tri-pane workspace layout.
- Touch targets are **36×36px** minimum — Linear's power users are on pointer devices, but the minimum still respects accessibility.

## 9. Agent Prompt Guide

Copy-paste starters for `apt:mockup` and ad-hoc generation.

### Build a button

> Render a primary button using `tokens.colors.accent` on `tokens.colors.bg`. Radius from `components.button.radius`. Padding from `components.button.paddingX/paddingY`. Font from `tokens.typography.families.primary`, weight 500, at scale[2] (14px). Focus: 2px outline in `tokens.colors.accent`, 0 offset, no shadow.

### Build a card

> Render a card on `tokens.colors.surface`, 1px `tokens.colors.border` outline, `components.card.radius` corners, `components.card.padding` inner padding, `tokens.shadow.sm` shadow. Headline in `primary` weight 600 at scale[5] (22px). Meta row in `mono` at scale[0] (11px), `text` colour at 65% alpha.

### Build a data table

> Render a dense data table: `tokens.typography.scale[2]` (14px) body size, `tokens.spacing[2]` (12px) row padding, `tokens.colors.border` horizontal row separators only, `tokens.colors.surface` hover state. ID column uses `mono` left-aligned; numeric columns right-aligned; text columns left-aligned. Selected row: 1px `accent` left indicator and `surface` background.

### Reject criteria

Before handing off to `apt:plan`, every generated mockup must pass:

- `apt-tools design-validate DESIGN.md` → exit 0
- `apt-tools design-lint mockups/*.html` → zero violations against `antiPatterns`
- Visual read-through against §7 Do's and Don'ts (dark-first, single indigo, Inter Variable, short motion)
