Skin / Advanced pack
Linear
Linear-inspired skin: indigo brand on a cool neutral ramp, a flat 13px chrome band, 4px radius, hairline borders instead of elevation, and pill-shaped filled actions.
One command installs the pack's theme.css, skin.css and skin.config.tsx over the refined library — tokens, skin.css and slot classes together, plus any runtime the pack mounts. Reinstalling refined resets the theme and skin targets back to the baseline look.
npx shadcn@latest add http://127.0.0.1:3000/r/linear/skin.jsonPack source
The 3 files this pack ships, read straight from the registry. Each is yours to own and edit after install.
theme.css — token block scoped to [data-skin]; a theme skin's entire brand
src/registry/skin-packs/linear/theme.css
/* * ADVANCED skin (tokens + skin.css material + skin.config slots) — a reading of Linear's product UI: * indigo brand on a near-neutral cool ramp, 13px chrome, 4px radius knob, hairline borders instead of * elevation, and floating surfaces that are the ONLY things allowed a real shadow. * Scoped [data-skin="linear"] only, never :root, so skins co-compile; a standalone install adds its own * `@custom-variant dark`. Raw token re-values only — @theme belongs to the baseline. */[data-skin="linear"] { /* Inter, self-hosted by the app shell (next/font fills --font-inter); host without it falls to the system stack. */ --font-sans: var(--font-inter, "Inter"), "Inter Variable", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif; --font-mono: "Berkeley Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace; /* Type scale: Linear runs one flat 13px band for ALL chrome (nav rows, controls, body) and reserves the larger rungs for content headings. Label == body on purpose. */ --text-micro: 0.625rem; /* 10px */ --text-caption: 0.6875rem; /* 11px */ --text-label: 0.8125rem; /* 13px — sm controls, nav rows, tooltips */ --text-body: 0.8125rem; /* 13px — THE workhorse */ --text-body-lg: 0.9375rem; /* 15px */ --text-meta: 0.6875rem; /* 11px — label pills */ /* Headings stay tight and semibold; no 700 anywhere (Linear tops out at semibold). */ --text-heading-4: 0.875rem; --text-heading-4--line-height: 1.4; --text-heading-4--font-weight: 600; --text-heading-3: 1rem; --text-heading-3--line-height: 1.4; --text-heading-3--font-weight: 600; --text-heading-2: 1.1875rem; --text-heading-2--line-height: 1.3; --text-heading-2--font-weight: 600; --text-heading-1: 1.5rem; /* 24px — the issue-title rung */ --text-heading-1--line-height: 1.25; --text-heading-1--font-weight: 600; --text-heading-1--letter-spacing: -0.014em; --text-display: 2rem; --text-display--line-height: 1.15; --text-display--font-weight: 600; --text-display--letter-spacing: -0.022em; --text-title-sm: 0.875rem; --text-title-sm--line-height: 1.4; --text-title-sm--font-weight: 600; --text-title-md: 1rem; --text-title-md--line-height: 1.4; --text-title-md--font-weight: 600; --text-title-lg: 1.1875rem; --text-title-lg--line-height: 1.3; --text-title-lg--font-weight: 600; /* Light: pure-white surfaces on a cool gray paper. card == background so the shell's content frame reads as the one white sheet Linear floats its whole app on. */ --background: oklch(1 0 0); --foreground: oklch(0.2228 0.0079 274.573); /* #1a1b1f */ --card: oklch(1 0 0); --card-foreground: oklch(0.2228 0.0079 274.573); --popover: oklch(1 0 0); --popover-foreground: oklch(0.2228 0.0079 274.573); --primary: oklch(0.5674 0.1585 275.206); /* #5e6ad2 — THE Linear indigo */ --primary-foreground: oklch(1 0 0); --muted: oklch(0.9614 0.0013 286.375); /* #f2f2f3 */ --muted-foreground: oklch(0.5401 0.0124 280.281); /* #6d6e76 */ --secondary: oklch(0.9614 0.0013 286.375); --secondary-foreground: oklch(0.2228 0.0079 274.573); --accent: oklch(0.9434 0.0013 286.374); /* #ececed — hover / selection fill */ --accent-foreground: oklch(0.2228 0.0079 274.573); --destructive: oklch(0.6534 0.1835 23.679); /* #eb5757 */ --destructive-foreground: oklch(1 0 0); --ring-opacity: 1; --border: oklch(0.9255 0.0027 286.347 / var(--ring-opacity)); /* #e6e6e8 hairline */ --input: oklch(0.9042 0.0027 286.346); /* #dfdfe1 — fields carry a touch more edge */ --ring: oklch(0.5674 0.1585 275.206); /* focus == brand */ --canvas: oklch(0.9734 0.0013 286.375); /* #f6f6f7 — the paper the white sheet sits on */ /* Popup rows: a whisper of ink, no brand tint (Linear highlights rows, it doesn't color them). Derived from --foreground so the dark block inherits the same recipe with no restatement. */ --popup-item-foreground: var(--foreground); --popup-item-highlight-background: oklch(from var(--foreground) l c h / 0.05); --popup-item-disabled-opacity: 0.4; /* Surfaces are opaque: no glass anywhere. The modal scrim is the only dim. */ --popover-opacity: 1; --backdrop-blur-popover: 0px; --overlay-opacity: 0.3; --backdrop-blur-overlay: 0px; --scroll-fade-size: 1.5rem; /* Elevation is EARNED here: controls and panels are held by hairlines, only floating surfaces lift. Hence a near-zero control tier, a 1x panel tier, and popover/modal tiers pushed way up. */ --shadow-color: oklch(0.2217 0.0084 264.39); --shadow-highlight: oklch(1 0 0 / 0.08); /* matte: a whisper of top light, not a lit-paper rim */ --shadow-size: 1; --shadow-opacity: 0.75; --shadow-y: 1; --shadow-control-multiplier: 0.6; --shadow-panel-multiplier: 1; --shadow-popover-multiplier: 5; --shadow-modal-multiplier: 8; --shadow-ambient-multiplier: 8; /* THE radius knob: 4px. Controls ride 1.5x (6px), panels 3x (12px) — small, never pill-shaped by token (the button pill is a deliberate slot choice, not a radius side effect). */ --radius: 0.25rem; --radius-control: calc(var(--radius) * 1.5); --radius-field: calc(var(--radius) * 2); /* 8px — composer shell, user bubble */ --radius-panel: calc(var(--radius) * 3); /* 12px — dialogs, code, the content sheet */ --radius-scene: calc(var(--radius) * 3.5); /* 14px */ --corner-shape: round; --corner-shape-control: var(--corner-shape); --corner-shape-popover: var(--corner-shape); --corner-shape-panel: var(--corner-shape); /* Concentric floating-list geometry. Re-declared (not inherited): the baseline formulas live on :root and would bake the REFINED --radius-control into this pack's popups. */ --popover-padding: 0.25rem; /* Rows carry the SAME 6px corner as controls (Linear has one row corner everywhere: menus, nav, tree, and the sliding selection pill, which the library shapes from this token). */ --radius-popup-item: var(--radius-control); --nest-safe: 1px; --nest-corner-ratio: 3.41421356; --radius-popup-item-fit: min(var(--radius-popup-item), calc(var(--control-h-xs) / 2)); --radius-popover: calc(var(--radius-popup-item-fit) + clamp(0px, var(--radius-popup-item-fit) * 1000, var(--popover-padding) - 1px)); --padding-x: 0.75rem; --padding-y: 0.5rem; /* Control ramp: 32px base, so `sm` lands on Linear's 28px button. Re-derived for the same reason the popup radii are: the ramp formulas on :root would bake the baseline's 36px base. */ --control-h: 2rem; --control-h-xs: round(var(--control-h) * 0.78, 1px); --control-h-sm: round(var(--control-h) * 0.89, 1px); --control-h-md: var(--control-h); --control-h-lg: round(var(--control-h) * 1.11, 1px); /* Motion is a snap, not a glide — Linear's whole feel rests on this. */ --ease-standard: cubic-bezier(0.4, 0, 0.2, 1); --ease-emphasized: cubic-bezier(0.16, 1, 0.3, 1); --duration-fast: 90ms; --duration-base: 130ms; --duration-slow: 200ms;}/* Dark tokens: the real Linear night — near-black canvas, panel one step up, popups two. Every surface color is RESTATED (the light block above out-specifies the baseline's :where(.dark)). */:where(.dark) [data-skin="linear"],.dark[data-skin="linear"] { --background: oklch(0.1739 0.0041 285.967); /* #101012 */ --foreground: oklch(0.9784 0.0011 197.139); /* #f7f8f8 */ --card: oklch(0.1739 0.0041 285.967); --card-foreground: oklch(0.9784 0.0011 197.139); --popover: oklch(0.2277 0.0057 285.935); /* #1c1c1f — menus sit above the sheet */ --popover-foreground: oklch(0.9784 0.0011 197.139); --primary: oklch(0.5674 0.1585 275.206); --primary-foreground: oklch(1 0 0); --muted: oklch(0.2277 0.0057 285.935); --muted-foreground: oklch(0.6488 0.0146 262.359); /* #8a8f98 */ --secondary: oklch(0.2277 0.0057 285.935); --secondary-foreground: oklch(0.9784 0.0011 197.139); --accent: oklch(0.2494 0.0075 285.844); /* #212125 */ --accent-foreground: oklch(0.9784 0.0011 197.139); --destructive: oklch(0.6534 0.1835 23.679); --destructive-foreground: oklch(1 0 0); --ring-opacity: 1; --border: oklch(0.2618 0.0113 278.089 / var(--ring-opacity)); /* #23242a */ --input: oklch(0.2986 0.0109 278.197); --ring: oklch(0.6102 0.1404 276.317); /* the indigo lifts a rung to stay legible on ink */ --canvas: oklch(0.139 0.0029 246.256); /* #08090a */ --popup-item-highlight-background: oklch(from var(--foreground) l c h / 0.07); --shadow-color: oklch(0 0 0); --shadow-highlight: oklch(1 0 0 / 0.05); --shadow-opacity: 1;}/* prefers-reduced-motion: token-driven, so every derived tempo flattens together. */@media (prefers-reduced-motion: reduce) { [data-skin="linear"] { --duration-fast: 0ms; --duration-base: 0ms; --duration-slow: 0ms; }}