Folk
MIT
A modern, minimal design system with playful brand accents and pill-shaped buttons, built for SaaS and content-driven products that value clarity and personality
Layout StudioImport this kit into a Studio project and start editing.
CLI installRun it in any project. No account needed.
npx @layoutdesign/context install folkUI themeReskin shadcn or Layout UI components to match Folk.
npx shadcn add https://layout.design/r/folk/theme.json# layout.md — folk.app Design System
---
## 0. Quick Reference
> Inject this block into `CLAUDE.md` or `.cursorrules` for immediate AI context.
> **Stack:** Webflow-generated HTML/CSS · Token source: extracted CSS vars (high confidence, 48 properties)
> **How to apply:** Use as `var(--token-name)` in CSS, `style={{ prop: 'var(--token-name)' }}` in JSX, or `bg-[var(--token-name)]` in Tailwind.
```css
/* ── Core Tokens ── */
--black: #030200e3; /* Primary text & border colour */
--white: white; /* Inverse text, card backgrounds */
--grey1: #fcfcfc; /* App background */
--folk-purple: #c1aaf9; /* Brand accent cool */
--folk-green: #bdee63; /* Success / brand accent */
--folk-orange: #ffc53d; /* Warning / brand accent */
--highlight-color: #fab9fb; /* Decorative highlight pink */
--folk-radius-sm: 12px; /* Cards */
--folk-radius-md: 20px; /* Badges, tab pills */
--folk-radius-full: 1000px; /* Primary pill buttons — ALWAYS pill-shaped */
--folk-space-xs: 4px;
--folk-space-sm: 10px;
--folk-space-md: 12px;
--folk-space-lg: 16px;
--folk-space-xl: 24px;
--folk-space-2xl: 32px;
--folk-space-3xl: 48px;
--folk-duration-base: 0.2s;
--folk-ease-default: ease;
```
```tsx
/* Primary Button — pill-shaped, black fill, Inter/Rubik font */
<button
className="primary-button"
style={{
background: 'var(--black)',
color: 'var(--white)',
borderRadius: 'var(--folk-radius-full)',
padding: '0.375rem 1.1rem',
fontFamily: 'Rubik, sans-serif',
fontWeight: 700,
fontSize: '14px',
border: '1px solid var(--black)',
transition: 'background var(--folk-duration-base) var(--folk-ease-default)',
}}
onMouseOver={e => {
e.currentTarget.style.background = 'transparent';
e.currentTarget.style.color = 'var(--black)';
}}
>
Get started free
</button>
```
**NEVER rules:**
- **NEVER** use rounded corners other than `--folk-radius-sm` (12px), `--folk-radius-md` (20px), `--folk-radius-lg` (180px), or `--folk-radius-full` (1000px).
- **NEVER** render primary CTA buttons without `border-radius: var(--folk-radius-full)` — folk uses pill buttons everywhere.
- **NEVER** use Inter for headings — headings use `Uxumgrotesque, sans-serif`.
- **NEVER** use spacing values not in the `--folk-space-*` scale (xs=4px, sm=10px, md=12px, lg=16px, xl=24px, 2xl=32px, 3xl=48px).
- **NEVER** hardcode hex colours — always reference a `--*` CSS custom property.
- **NEVER** use `font-weight: 700` (semibold) on headings — headings are `font-weight: 500`.
- **NEVER** use generic sans-serif fallbacks without the brand font stack (`Uxumgrotesque` → `Inter, Arial, sans-serif`).
> Full design system → see `layout.md`
---
## 1. Design Direction & Philosophy
### Character & Mood
Folk is a **modern, friendly CRM** positioned against corporate enterprise software. The aesthetic is:
- **Warm and approachable** — soft pastel brand surfaces (lavender, sage, warm yellow, sky blue) paired with near-black text on an off-white canvas.
- **Confident but not aggressive** — black pill buttons with clean white type; hover states invert to transparent/outline, never change shape.
- **Playful without being juvenile** — custom brand colours (folk-purple, folk-green, folk-orange, highlight-color pink) used as decorative accents on cards and feature tiles, not as primary UI chrome.
- **Editorial and typographic** — `Uxumgrotesque` for headings gives a distinctive grotesque character; `Instrument Serif` (italic) appears as a contrast serif accent; `Foundersgrotesk` for body/link type.
### What This Design Explicitly Rejects
- **No rounded corners in the 2–8px "standard" range** — folk's minimum card radius is 12px; buttons are full pill (1000px).
- **No warm gradients or bright gradient fills** — backgrounds use flat pastels, never gradient overlays.
- **No heavy drop shadows as decoration** — shadows are functional (cards lift off the page); not used for decorative depth.
- **No system UI fonts** — never fall back to system-ui, -apple-system, or Helvetica Neue as intended faces.
- **No uppercase text transforms** — all type is `text-transform: none`.
- **No heavy colour palettes** — the primary UI is monochrome (black/white/grey) with selective brand colour pops.
---
## 2. Colour System
### Tier 1 — Primitive Values
```css
/* ── Primitive Colour Tokens (extracted CSS vars — names preserved exactly) ── */
/* Neutrals */
--black: #030200e3; /* Near-black, primary text & UI chrome */
--grey11: #050500a1; /* Deep muted dark, secondary icon/text */
--white: white; /* Pure white */
--grey1: #fcfcfc; /* App canvas background */
--grey2: #12120008; /* Almost transparent tint, hover bg */
--grey3: #0f08000f; /* Subtle tint, pricing hover bg */
--grey4: #0f0a001a; /* Light overlay */
--grey5: #e4e4e4; /* Border / divider */
--grey6: #0d0a0029; /* Medium overlay, active tab bg */
--grey7: #d4d4d4; /* Light border */
--grey8: #bbb; /* Muted border */
--grey9: #8d8d8d; /* Placeholder / muted text */
--grey10: grey; /* Generic mid-grey */
/* Black scale */
--black--100<deleted|variable-3f5d0b1a>: #f4f5f5; /* Lightest tint */
--black--200<deleted|variable-33acd7b1>: #ebebec; /* Hover bg for nav links, dropdowns */
--black--300<deleted|variable-35e7fffd>: #d6d7d7; /* Subtle border */
--black--500<deleted|variable-25419047>: #989a9c; /* Disabled / muted text */
--black--700<deleted|variable-0a0534d5>: #464a4d; /* Dark secondary text */
--black--800<deleted|variable-a5ec4446>: #313539; /* Secondary text, near-black */
--grey--600<deleted|variable-289adc91>: #6f7275; /* Mid-grey text */
/* Brand Accents */
--folk-blue: #94c4ff; /* Brand blue pastel */
--folk-purple: #c1aaf9; /* Brand purple / cool accent */
--folk-orange: #ffc53d; /* Brand orange / warning */
--folk-green: #bdee63; /* Brand green / success */
--highlight-color: #fab9fb; /* Highlight pink, decorative */
--bg-color: #bee0ef; /* Sky blue background accent */
/* Brand Surfaces (mined from computed styles) */
--brand-surface-1: rgb(246, 223, 246); /* Lavender surface — testimonial card */
--brand-surface-2: rgb(227, 239, 220); /* Sage green surface — testimonial card */
--brand-surface-3: rgb(255, 240, 189); /* Warm yellow surface — feature section */
--brand-surface-4: rgb(190, 217, 239); /* Sky blue surface — feature section */
/* Deleted-variable originals (preserved for reference) */
--blue<deleted|variable-83e67b71>: #f6f8fe; /* Blue-tinted surface */
--pink<deleted|variable-4cc9684e>: #fff7f6; /* Blush pink surface */
--orange-plain<deleted|variable-73e30f5b>: #f56741; /* Warm orange plain */
--yellow<deleted|variable-a9798688>: #fffcf2; /* Pale yellow, hover accent */
--blue-plain<deleted|variable-475b994a>: #5079e4; /* Blue for info/links */
/* Accessible overrides */
--accessible-components--dark-grey: #9b9b9b; /* AA-compliant dark grey */
--accessible-components--dodger-blue: #1378d1; /* AA-compliant blue for links */
```
### Tier 2 — Semantic Aliases
```css
/* ── Semantic Colour Tokens (curated folk-* namespace) ── */
--folk-bg-app: var(--grey1); /* #fcfcfc — Main app canvas background */
--folk-bg-surface: var(--brand-surface-1); /* rgb(246,223,246) — Elevated surface / feature bg */
--folk-bg-hover: var(--button--hover-bg); /* transparent — Button hover background */
--folk-accent: var(--brand-surface-3); /* rgb(255,240,189) — Warm yellow accent surface */
--folk-accent-warm: var(--orange-plain<deleted|variable-73e30f5b>); /* #f56741 — Warm orange CTA accent */
--folk-accent-cool: var(--folk-purple); /* #c1aaf9 — Cool purple accent */
--folk-accent-hover: var(--yellow<deleted|variable-a9798688>); /* #fffcf2 — Pale yellow hover tint */
--folk-text-primary: var(--black); /* #030200e3 — Body / primary text */
--folk-text-secondary: var(--black--800<deleted|variable-a5ec4446>); /* #313539 — Secondary text */
--folk-text-muted: var(--grey--600<deleted|variable-289adc91>); /* #6f7275 — Muted / caption text */
--folk-text-disabled: var(--black--500<deleted|variable-25419047>); /* #989a9c — Disabled state text */
--folk-success: var(--folk-green); /* #bdee63 — Success indicator */
--folk-warning: var(--folk-orange); /* #ffc53d — Warning indicator */
--folk-info: var(--blue-plain<deleted|variable-475b994a>); /* #5079e4 — Info / link blue */
--folk-error: var(--grey3); /* #0f08000f — Error tint (low confidence — verify) */
--folk-border-default: var(--black); /* #030200e3 — Default component border */
--folk-border-subtle: var(--grey5); /* #e4e4e4 — Subtle dividers */
--folk-border-muted: var(--grey8); /* #bbb — Muted borders */
```
### Tier 3 — Component Tokens
```css
/* ── Component-Level Colour Tokens (extracted button vars) ── */
--button--bg: var(--black); /* Default button fill */
--button--text: var(--white); /* Default button label colour */
--button--border: var(--black); /* Default button border */
--button--hover-bg: transparent; /* Hover fill — reveals background */
--button--hover-text: var(--black); /* Hover label colour */
--button--hover-border: var(--black); /* Hover border — maintains outline */
```
### Brand Surface Palette (decorative tile backgrounds)
| Token | Value | Usage |
|---|---|---|
| `--brand-surface-1` | `rgb(246, 223, 246)` | Lavender — testimonial / feature card bg |
| `--brand-surface-2` | `rgb(227, 239, 220)` | Sage green — testimonial card bg |
| `--brand-surface-3` | `rgb(255, 240, 189)` | Warm yellow — CTA / feature section bg |
| `--brand-surface-4` | `rgb(190, 217, 239)` | Sky blue — feature section bg |
| `--highlight-color` | `#fab9fb` | Pink highlight — decorative illustration accent |
| `--accessible-components--dodger-blue` | `#1378d1` | AA-compliant interactive blue |
---
## 3. Typography System
### Font Families
```css
/* ── Font Stacks ── */
/* Heading: Uxumgrotesque — custom grotesque, weight 500 only */
font-family: Uxumgrotesque, sans-serif;
/* Body / Nav / Links: Foundersgrotesk — elegant grotesque */
font-family: Foundersgrotesk, sans-serif;
/* UI / Body copy: Inter — system-grade readable sans */
font-family: Inter, Arial, sans-serif;
/* Buttons / Labels / Form elements: Rubik — rounded humanist */
font-family: Rubik, sans-serif;
/* Accent italic: Instrumentserif — editorial serif contrast */
font-family: Instrumentserif, serif; /* italic style only */
```
### Composite Typography Groups
```css
/* ── Composite Typography Tokens — always use the full group, never individual props ── */
/* H1 — Hero headline */
--folk-type-h1: {
font-family: Uxumgrotesque, sans-serif;
font-size: 64px;
font-weight: 500;
line-height: 64px; /* 1:1 tight leading */
letter-spacing: normal;
text-align: center; /* H1 is always centred on folk.app */
}
/* H2 — Section headline */
--folk-type-h2: {
font-family: Uxumgrotesque, sans-serif;
font-size: 48px; /* maps to --folk-font-size-3xl */
font-weight: 500;
line-height: 52.8px; /* 1.1 leading */
letter-spacing: normal;
text-align: start;
}
/* H3 — Subsection / feature headline */
--folk-type-h3: {
font-family: Uxumgrotesque, sans-serif;
font-size: 40px; /* maps to --folk-font-size-2xl */
font-weight: 500;
line-height: 44px; /* 1.1 leading */
letter-spacing: normal;
text-align: start;
}
/* Feature stat (large numbers, e.g. 4.9) */
--folk-type-stat: {
font-family: Uxumgrotesque, sans-serif;
font-size: 28px; /* maps to --folk-font-size-xl */
font-weight: 500;
line-height: normal;
letter-spacing: normal;
}
/* Body — primary content */
--folk-type-body: {
font-family: Inter, Arial, sans-serif;
font-size: 16px;
font-weight: 400;
line-height: 24px; /* 1.5 reading comfort */
letter-spacing: normal;
}
/* Body SM — nav, feature subtext */
--folk-type-body-sm: {
font-family: Foundersgrotesk, sans-serif;
font-size: 14.4px; /* maps to --folk-font-size-md */
font-weight: 400;
line-height: 23.04px; /* maps to --folk-line-height-loose */
letter-spacing: normal;
}
/* Caption / label — metadata, social proof */
--folk-type-caption: {
font-family: Inter, Arial, sans-serif;
font-size: 13px; /* maps to --folk-font-size-xs */
font-weight: 400;
line-height: 21px; /* maps to --folk-line-height-tight */
letter-spacing: normal;
}
/* Button label */
--folk-type-button: {
font-family: Rubik, sans-serif;
font-size: 14px; /* maps to --folk-font-size-sm */
font-weight: 700;
line-height: 17.5px;
letter-spacing: normal;
}
/* Form label */
--folk-type-label: {
font-family: Rubik, sans-serif;
font-size: 14.4px; /* maps to --folk-font-size-md */
font-weight: 700;
line-height: 21.6px;
letter-spacing: normal;
}
/* Badge / pill text */
--folk-type-badge: {
font-family: Inter, Arial, sans-serif;
font-size: 11px;
font-weight: 400;
line-height: 11px; /* 1:1 for compact badges */
letter-spacing: normal;
}
/* Link / nav item */
--folk-type-link: {
font-family: Foundersgrotesk, sans-serif;
font-size: 14.4px;
font-weight: 400;
line-height: 23.04px;
text-decoration: underline;
letter-spacing: normal;
}
```
### Size Scale Reference
| Token | Value | Element |
|---|---|---|
| `--folk-font-size-xs` | `13px` | Captions, social proof labels |
| `--folk-font-size-sm` | `14px` | Nav items, button text |
| `--folk-font-size-md` | `14.4px` | Body copy, links, labels |
| `--folk-font-size-lg` | `15px` | Feature subheadings |
| `--folk-font-size-xl` | `28px` | Stat numbers |
| `--folk-font-size-2xl` | `40px` | H3 feature sections |
| `--folk-font-size-3xl` | `48px` | H2 section headlines |
| *(extracted)* | `64px` | H1 hero — **no token; use literal 64px** |
### Font Pairing Rules
- **Headings** → `Uxumgrotesque` only, weight `500` only.
- **Italic accent / editorial pull quotes** → `Instrumentserif` italic, never upright.
- **Nav, links, card body** → `Foundersgrotesk` regular.
- **Buttons, form labels, checkboxes** → `Rubik` bold (700).
- **Body paragraphs, inputs, badges** → `Inter, Arial, sans-serif`.
---
## 4. Spacing & Layout
```css
/* ── Spacing Scale (4px base grid) ── */
--folk-space-xs: 4px; /* Tight internal gaps, icon margins */
--folk-space-sm: 10px; /* Note: 10px is off 4px grid — use only for vertical button padding (extracted) */
--folk-space-md: 12px; /* Card internal gap (extracted: card gap = 12px) */
--folk-space-lg: 16px; /* Standard component padding */
--folk-space-xl: 24px; /* Section internal spacing */
--folk-space-2xl: 32px; /* Between components */
--folk-space-3xl: 48px; /* Between major sections */
/* ── Button Padding (extracted) ── */
--button--vertical-padding: 0.375rem; /* 6px — button top/bottom */
--button--horizontal-padding: 1.1rem; /* 17.6px — button left/right */
--button--line-height: 1.25rem; /* 20px */
/* ── Layout: Margin / Bottom ── */
--margin-bottom: 7rem; /* 112px — section bottom margin (extracted) */
/* ── Radius Scale ── */
--folk-radius-sm: 12px; /* Cards, feature tiles */
--folk-radius-md: 20px; /* Badges, new-badge pill, spark tabs */
--folk-radius-lg: 180px; /* Play / demo buttons (video CTA) */
--folk-radius-full: 1000px; /* ALL primary/secondary/responsive buttons */
```
### Grid & Breakpoints
```css
/* ── Responsive Breakpoints ── */
--breakpoint-xs: 450px; /* Small mobile */
--breakpoint-sm: 479px; /* Webflow mobile landscape */
--breakpoint-md-low: 767px; /* Webflow tablet portrait (max-width) */
--breakpoint-md: 768px; /* Tablet portrait (min-width) */
--breakpoint-lg: 991px; /* Webflow desktop (max-width) */
--breakpoint-xl: 1440px; /* Large desktop */
--breakpoint-2xl: 1920px; /* Ultra-wide / TV */
```
### Layout Conventions
- **Navigation:** `display: flex; flex-direction: row; align-items: center;` — horizontal bar, no padding on the nav element itself.
- **Cards:** `display: flex; flex-direction: column; justify-content: flex-start; align-items: center; gap: 12px;` — vertical stack, centred content.
- **Button groups:** `display: flex; flex-direction: row; justify-content: center;` — inline centred.
- **Flex vs Grid:** Use flex for nav and button rows; use grid/multi-column flex for card grids (inferred — no explicit grid tokens extracted).
- **Container width:** `--h1-width-crmfor: 120ch; --subtitle-width-crmfor: 90ch;` — hero text max-widths are character-width constrained, not pixel-fixed.
---
## 5. Page Structure & Layout Patterns
### 5.1 Section Map
| # | Section | Layout Type | Approx Height | Key Elements | Source |
|---|---|---|---|---|---|
| 1 | Navigation / Header | `flex row`, sticky | ~64px | Logo, nav links (dropdown), CTA buttons (pill) | extracted |
| 2 | Hero | Block, centred | ~480–640px | H1 (64px, centred, max-width 120ch), subtitle (max-width 90ch), pill CTA buttons, social proof badges | extracted (h1-width-crmfor, subtitle-width-crmfor) |
| 3 | Social proof / ratings | `flex row`, centred | ~80px | Rating badges (G2, Product Hunt, Chrome), `font-size-xs` captions, star marks | extracted (badge, caption) |
| 4 | Feature card grid | `flex column` cards in row grid | ~500–800px | Feature tiles with brand surface bg colours (lavender, sage, yellow, sky), H3 40px, body copy | extracted (card, brand-surface-*) |
| 5 | CRM feature section (lavender) | Block, `--brand-surface-1` bg | ~400px | H2 48px, body text, pill CTA, feature illustration | extracted (brand-surface-1) |
| 6 | Feature section (warm yellow) | Block, `--brand-surface-3` bg | ~400px | H2 or H3, "A future-proof CRM" copy, illustration | extracted (brand-surface-3) |
| 7 | Testimonials / Social proof | `flex row` cards, coloured bg | ~360px | Testimonial cards (lavender `--brand-surface-1`, sage `--brand-surface-2`), quotes, avatar | extracted (brand-surface-1/2) |
| 8 | Integrations | `flex row` wrap | ~280px | Integration icon pills, hover: `--grey2` bg + `#8d8d8d` border | extracted (integrations-wrap hover) |
| 9 | Pricing section | Block | ~600px | Pricing plan cards, `pricing-plans_link` hover: `--grey3` | extracted (hover states) |
| 10 | Use cases / Filters | `flex row` filter bar + results | ~480px | Checkbox filter pills (hover: black fill), results collection items | extracted (usecases-filter hover) |
| 11 | CTA / Banner | Block, full-width | ~240px | H2, pill CTA button, coloured bg | inferred |
| 12 | Footer | `flex row`, multi-column | ~300px | Nav link groups, legal links (Foundersgrotesk), language selector, dark mode links | extracted (nav-link hover states) |
### 5.2 Layout Patterns
**Navigation:**
```
display: flex | flex-direction: row | align-items: center
Dropdown toggle: hover → background rgba(0,0,0,0.1) | border-radius: --folk-radius-md (20px inferred)
Nav links: hover → background --black--200 (#ebebec) | text-decoration: none
CTA buttons: pill shape (--folk-radius-full), black fill
```
**Hero:**
```
Centred block layout
H1: max-width 120ch | text-align: center | font 64px/64px Uxumgrotesque 500
Subtitle: max-width 90ch | Inter 16px/24px
Buttons: flex row, justify-content: center, gap: --folk-space-md (12px)
Section bottom margin: --margin-bottom (7rem / 112px)
```
**Card Grid (Feature tiles):**
```
Cards: display:flex | flex-direction:column | align-items:center | gap:12px | border-radius:12px
Card border: 10px solid white (extracted — thick white border creates inset appearance)
Box shadow: --folk-shadow-sm (multi-layer, soft long-range)
Transition: transform 0.3s ease
Background: brand-surface-* pastel colours per tile
```
**Testimonial cards:**
- Two-tone: `--brand-surface-1` (lavender) and `--brand-surface-2` (sage)
- Same card anatomy as feature tiles
**Filter / Use-cases:**
- Pill checkbox filters: hover `background-color: var(--black); color: var(--white)` — inverted pill
- Results: `collection-item:hover` → underline text decoration
### 5.3 Visual Hierarchy
1. **H1 (64px Uxumgrotesque 500)** — dominates hero, full attention
2. **H2 (48px Uxumgrotesque 500)** — section anchors, always `text-align: start`
3. **H3 (40px Uxumgrotesque 500)** — feature card headlines
4. **Stat numbers (28px)** — rating numbers in social proof row
5. **Body (16px Inter)** — supporting copy
6. **Badges (11px Inter, border-radius 20px)** — social proof labels, status tags
**CTA Placement:** Primary pill buttons (`--folk-radius-full`, `background: var(--black)`) appear in hero and section CTAs. Hover state inverts to transparent with black outline — shape never changes.
**Whitespace rhythm:** `--folk-space-3xl` (48px) between section components; `--margin-bottom: 7rem` (112px) for full section separation.
### 5.4 Content Patterns
**Feature tile pattern (repeating):**
```
[Brand-coloured card bg]
[Icon or illustration — top]
[H3 feature name — 40px Uxumgrotesque]
[Body copy — 15–16px Inter]
[Optional: pill CTA "Learn more"]
```
**Testimonial card pattern:**
```
[Coloured bg card — lavender or sage]
[Quote text — Foundersgrotesk 14.4px]
[Attribution — name, role, company]
[Avatar]
```
**Social proof badge pattern:**
```
[White badge, border-radius 20px, 1px black border]
[Rating number — 28px stat]
[Platform name — 13px caption]
[Star row]
```
---
## 6. Component Patterns
### 6.1 Primary Button
**Anatomy:** `[border-radius:full pill] [label:Rubik 700 14px] [border:1px solid black]`
**States:**
| State | Background | Text | Border | Other |
|---|---|---|---|---|
| Default | `var(--black)` | `var(--white)` | `var(--black)` | — |
| Hover | `transparent` | `var(--black)` | `var(--black)` | — |
| Focus | `transparent` | `var(--black)` | `var(--black)` + `outline: 1px solid black` | See `.primary_button_responsive:hover` |
| Active | `rgba(0,0,0,0.84)` | `var(--white)` | `var(--black)` | template variant |
| Disabled | — | `var(--black--500)` `#989a9c` | `var(--grey5)` | opacity 0.5, pointer-events: none |
| Loading | — | — | — | `@keyframes spin` on icon |
```tsx
// Primary Button — production-ready with all states
interface PrimaryButtonProps {
children: React.ReactNode;
disabled?: boolean;
loading?: boolean;
onClick?: () => void;
variant?: 'primary' | 'secondary';
}
export function PrimaryButton({
children,
disabled = false,
loading = false,
onClick,
variant = 'primary',
}: PrimaryButtonProps) {
const isPrimary = variant === 'primary';
return (
<button
onClick={onClick}
disabled={disabled || loading}
style={{
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
gap: 'var(--folk-space-xs)',
padding: 'var(--button--vertical-padding) var(--button--horizontal-padding)',
background: isPrimary ? 'var(--black)' : 'transparent',
color: isPrimary ? 'var(--white)' : 'var(--black)',
border: '1px solid var(--button--border)',
borderRadius: 'var(--folk-radius-full)',
fontFamily: 'Rubik, sans-serif',
fontSize: 'var(--folk-font-size-sm)',
fontWeight: 700,
lineHeight: 'var(--button--line-height)',
cursor: disabled || loading ? 'not-allowed' : 'pointer',
opacity: disabled ? 0.5 : 1,
transition: `background var(--folk-duration-base) var(--folk-ease-default),
color var(--folk-duration-base) var(--folk-ease-default)`,
textDecoration: 'none',
whiteSpace: 'nowrap',
}}
onMouseEnter={e => {
if (!disabled && !loading) {
const el = e.currentTarget;
el.style.background = 'transparent';
el.style.color = 'var(--black)';
}
}}
onMouseLeave={e => {
if (!disabled && !loading) {
const el = e.currentTarget;
el.style.background = isPrimary ? 'var(--black)' : 'transparent';
el.style.color = isPrimary ? 'var(--white)' : 'var(--black)';
}
}}
aria-busy={loading}
aria-disabled={disabled || loading}
>
{loading && (
<span
aria-hidden="true"
style={{
display: 'inline-block',
width: '14px',
height: '14px',
border: '2px solid currentColor',
borderTopColor: 'transparent',
borderRadius: '50%',
animation: 'spin 0.6s linear infinite',
}}
/>
)}
{children}
</button>
);
}
```
---
### 6.2 Card
**Anatomy:** `[coloured-bg container] [top: icon/illustration] [H3 title] [body text] [optional CTA]`
**States:**
| State | Transform | Shadow | Border |
|---|---|---|---|
| Default | none | `var(--folk-shadow-sm)` | `10px solid white` |
| Hover | `translateY(-2px)` (inferred from `transition: transform 0.3s`) | `var(--folk-shadow-sm)` | `10px solid white` |
| Focus | — | `var(--folk-shadow-md)` | `10px solid white` |
| Disabled | `opacity: 0.5` | none | — |
```tsx
interface CardProps {
title: string;
body: string;
accentBg?: string; // CSS colour value — use brand-surface-* vars
children?: React.ReactNode;
}
export function Card({ title, body, accentBg = 'var(--white)', children }: CardProps) {
return (
<div
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'flex-start',
gap: 'var(--folk-space-md)',
backgroundColor: accentBg,
borderRadius: 'var(--folk-radius-sm)',
border: '10px solid var(--white)',
boxShadow: 'var(--folk-shadow-sm)',
transition: `transform var(--folk-duration-slow) var(--folk-ease-default)`,
cursor: 'default',
}}
onMouseEnter={e => {
(e.currentTarget as HTMLElement).style.transform = 'translateY(-2px)';
}}
onMouseLeave={e => {
(e.currentTarget as HTMLElement).style.transform = 'none';
}}
>
{children}
<h3
style={{
fontFamily: 'Uxumgrotesque, sans-serif',
fontSize: 'var(--folk-font-size-2xl)',
fontWeight: 500,
lineHeight: '44px',
color: 'var(--black)',
margin: 0,
}}
>
{title}
</h3>
<p
style={{
fontFamily: 'Inter, Arial, sans-serif',
fontSize: '16px',
fontWeight: 400,
lineHeight: '24px',
color: 'var(--black)',
margin: 0,
}}
>
{body}
</p>
</div>
);
}
```
---
### 6.3 Input
**Anatomy:** `[white bg container] [Inter 14px text] [1px black border] [focus ring: 2px black shadow]`
**States:**
| State | Background | Border | Shadow |
|---|---|---|---|
| Default | `rgba(255,255,255,0.9)` | `1px solid var(--black)` | none |
| Hover | `rgba(255,255,255,0.9)` | `1px solid var(--black)` | none |
| Focus | `rgb(255,255,255)` | `1px solid rgb(0,0,0)` | `rgba(0,0,0,0.12) 0px 0px 0px 2px` |
| Dark Focus | `rgb(255,255,255)` | `1px solid rgba(255,255,255,0.64)` | `rgba(255,255,255,0.12) 0px 0px 0px 2px` |
| Disabled | `var(--black--100)` `#f4f5f5` | `1px solid var(--grey5)` | none |
| Error | `var(--white)` | `1px solid var(--folk-accent-warm)` `#f56741` | none |
```tsx
interface FormInputProps extends React.InputHTMLAttributes<HTMLInputElement> {
label?: string;
error?: string;
isDark?: boolean;
}
export function FormInput({ label, error, isDark = false, ...props }: FormInputProps) {
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--folk-space-xs)' }}>
{label && (
<label
style={{
fontFamily: 'Rubik, sans-serif',
fontSize: 'var(--folk-font-size-md)',
fontWeight: 700,
lineHeight: '21.6px',
color: 'var(--black)',
marginBottom: '5px',
}}
>
{label}
</label>
)}
<input
{...props}
style={{
fontFamily: 'Inter, Arial, sans-serif',
fontSize: 'var(--folk-font-size-sm)',
fontWeight: 400,
lineHeight: '22.4px',
color: 'var(--black)',
backgroundColor: 'rgba(255, 255, 255, 0.9)',
border: error ? '1px solid #f56741' : '1px solid var(--black)',
borderRadius: 0,
padding: '6.4px 8px',
outline: 'none',
transition: `border-color var(--folk-duration-base) var(--folk-ease-default),
box-shadow var(--folk-duration-base) var(--folk-ease-default)`,
width: '100%',
...props.style,
}}
onFocus={e => {
const el = e.currentTarget;
el.style.backgroundColor = 'rgb(255, 255, 255)';
el.style.borderColor = isDark ? 'rgba(255,255,255,0.64)' : 'rgb(0,0,0)';
el.style.boxShadow = isDark
? 'rgba(255,255,255,0.12) 0px 0px 0px 2px'
: 'rgba(0,0,0,0.12) 0px 0px 0px 2px';
}}
onBlur={e => {
const el = e.currentTarget;
el.style.backgroundColor = 'rgba(255, 255, 255, 0.9)';
el.style.borderColor = error ? '#f56741' : 'var(--black)';
el.style.boxShadow = 'none';
}}
aria-invalid={!!error}
/>
{error && (
<span
role="alert"
style={{
fontFamily: 'Inter, Arial, sans-serif',
fontSize: 'var(--folk-font-size-xs)',
color: '#f56741',
}}
>
{error}
</span>
)}
</div>
);
}
```
---
### 6.4 Badge
**Anatomy:** `[white bg] [1px black border] [border-radius:20px pill] [Inter 11px/11px text]`
**States:**
| State | Background | Border |
|---|---|---|
| Default | `var(--white)` | `1px solid var(--black)` |
| Coloured variant | brand-surface colour | `1px solid var(--black)` (inferred) |
| Hover | — (static) | — |
```tsx
interface BadgeProps {
children: React.ReactNode;
bg?: string;
}
export function Badge({ children, bg = 'var(--white)' }: BadgeProps) {
return (
<span
style={{
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
padding: '2px 4.8px',
backgroundColor: bg,
border: '1px solid var(--black)',
borderRadius: 'var(--folk-radius-md)', /* 20px */
fontFamily: 'Inter, Arial, sans-serif',
fontSize: '11px',
fontWeight: 400,
lineHeight: '11px',
color: 'var(--black)',
marginBottom: '2px',
}}
>
{children}
</span>
);
}
```
---
### 6.5 Nav Item
**Anatomy:** `[Foundersgrotesk 14.4px link] [flex row, align:center] [hover bg: --black--200]`
**States:**
| State | Background | Text | Decoration |
|---|---|---|---|
| Default | transparent | `var(--black)` | none |
| Hover | `var(--black--200)` `#ebebec` | `var(--black)` | none |
| Dropdown hover | `rgba(0,0,0,0.1)` | `var(--black)` | none |
| Footer dark hover | `transparent` | `var(--white)` | underline |
| Active / current | `var(--grey6)` `#0d0a0029` | `var(--black)` | none |
| Focus | outline removed (Webflow default) | `var(--black)` | — |
```tsx
interface NavItemProps {
label: string;
href: string;
isActive?: boolean;
isDark?: boolean;
}
export function NavItem({ label, href, isActive = false, isDark = false }: NavItemProps) {
return (
<a
href={href}
style={{
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
fontFamily: 'Foundersgrotesk, sans-serif',
fontSize: 'var(--folk-font-size-md)',
fontWeight: 400,
lineHeight: 'var(--folk-line-height-loose)',
color: isDark ? 'var(--white)' : 'var(--black)',
backgroundColor: isActive ? 'var(--grey6)' : 'transparent',
borderRadius: 'var(--folk-radius-md)',
padding: `var(--folk-space-xs) var(--folk-space-md)`,
textDecoration: 'none',
transition: `background-color var(--folk-duration-base) var(--folk-ease-default)`,
outline: 'none',
}}
onMouseEnter={e => {
const el = e.currentTarget;
el.style.backgroundColor = isDark ? 'transparent' : 'var(--black--200\<deleted|variable-33acd7b1\>)';
if (isDark) {
el.style.textDecoration = 'underline';
el.style.color = 'var(--white)';
}
}}
onMouseLeave={e => {
const el = e.currentTarget;
el.style.backgroundColor = isActive ? 'var(--grey6)' : 'transparent';
el.style.textDecoration = 'none';
el.style.color = isDark ? 'var(--white)' : 'var(--black)';
}}
aria-current={isActive ? 'page' : undefined}
>
{label}
</a>
);
}
```
---
## 7. Elevation & Depth
```css
/* ── Shadow Tokens ── */
/* Card / panel lift — multi-layer soft diffuse shadow */
--folk-shadow-sm: rgba(0, 0, 0, 0.08) 0px 5px 12px 0px,
rgba(0, 0, 0, 0.07) 0px 21px 21px 0px,
rgba(0, 0, 0, 0.04) 0px 48px 29px 0px,
rgba(0, 0, 0, 0.01) 0px 86px 34px 0px;
/* Usage: cards, feature tiles. Creates deep, realistic lift without hard edges. */
/* Surface + border-combined shadow — subtle elevation with outline */
--folk-shadow-md: rgba(17, 24, 39, 0.03) 0px 16px 16px 0px,
rgba(17, 24, 39, 0.03) 0px 8px 8px 0px,
rgba(17, 24, 39, 0.03) 0px 4px 4px 0px,
rgba(17, 24, 39, 0.03) 0px 2px 2px -2px,
rgba(17, 24, 39, 0.12) 0px 0px 0px 1px;
/* Usage: input focus ring emulation, modal surfaces, form elements.
The last layer (0 0 0 1px rgba 0.12) creates a subtle border effect. */
/* Focus ring (extracted from .form-input:focus) */
--folk-focus-ring-light: rgba(0, 0, 0, 0.12) 0px 0px 0px 2px;
--folk-focus-ring-dark: rgba(255, 255, 255, 0.12) 0px 0px 0px 2px;
/* Slider dot focus (Webflow component) */
--folk-slider-focus: rgb(255, 255, 255) 0px 0px 0px 2px;
/* ── Border Tokens ── */
--folk-border-ui: 1px solid var(--black); /* Standard UI border */
--folk-border-card-inset: 10px solid var(--white); /* Card white inset border (creates padding-like effect) */
--folk-border-input: 1px solid var(--black); /* Form input default */
--folk-border-input-focus: 1px solid rgb(0, 0, 0); /* Form input focus */
--folk-border-subtle: 1px solid var(--grey5); /* Dividers, light borders */
--folk-border-muted: 1px solid var(--grey8); /* Muted / inactive borders */
--folk-border-integration-hover: 1px solid var(--grey9); /* Integration tile hover border */
```
### Z-Index Scale
```css
/* ── Z-Index (inferred — no explicit tokens extracted) ── */
/* reconstructed: moderate confidence, inferred from component types */
--z-base: 0; /* Page content */
--z-card: 1; /* Lifted cards */
--z-dropdown: 100; /* Dropdown menus */
--z-nav: 200; /* Sticky navigation */
--z-modal: 400; /* Modal overlay */
--z-toast: 500; /* Toast notifications */
```
### Layering Principles
- Cards use `--folk-shadow-sm` — long diffuse shadow for realistic physical depth.
- Form focus uses a `box-shadow` ring (`2px spread`) rather than `outline` — consistent cross-browser.
- Modal overlays use `display: block` (not flex) — full screen takeover.
- Never use `!important` to override shadow — compose shadow tokens at the component level.
---
## 8. Motion
```css
/* ── Duration Tokens ── */
--folk-duration-fast: 0.1s; /* Micro-interactions: image swap, icon flip */
--folk-duration-base: 0.2s; /* Standard: button hover, nav link, input focus */
--folk-duration-slow: 0.3s; /* Elevated: card lift (transform), panel open */
/* ── Easing Tokens ── */
--folk-ease-default: ease; /* Applied to 226 elements — universal default */
/* ── Named Transitions (extracted from computed styles) ── */
--folk-transition-button: transform var(--folk-duration-base) var(--folk-ease-default);
/* Button: only transform animates (not bg/color — those are instant) */
--folk-transition-card: transform var(--folk-duration-slow) var(--folk-ease-default);
/* Card lift on hover: 0.3s ease */
--folk-transition-breadcrumb: opacity 0.25s var(--folk-ease-default),
transform 0.25s var(--folk-ease-default);
/* Breadcrumb fade/slide — starts display:none, transitions in */
--folk-transition-all: all var(--folk-duration-base) var(--folk-ease-default);
/* Fallback for unspecified transitions — many elements use 'transition: all' */
```
### Named Keyframes
```css
/* Spin — loading indicator */
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Slide in from left — hero element entrance */
@keyframes czrsUQ {
0% { opacity: 0; transform: translate3d(-200px, 0px, 0px); }
100% { opacity: 1; transform: translate3d(0px, 0px, 0px); }
}
```
### Motion Usage Rules
- **Animate only** `transform` and `opacity` for performance — never `width`, `height`, or `padding`.
- **Button background colour change** on hover is instantaneous (no transition on `background-color`) — only `transform` has a duration.
- **Card hover** lifts with `transform: translateY(...)` at `0.3s ease` — no shadow change.
- **Respect `prefers-reduced-motion`** — wrap entrance animations in `@media (prefers-reduced-motion: no-preference)`.
- **Never animate** page-level layout properties (`display`, `position`, `grid-template`).
---
## 9. Anti-Patterns & Constraints
1. **NEVER use rectangular buttons (border-radius: 4–8px) → Why it fails: folk's entire CTA system uses `--folk-radius-full` (1000px) pill buttons. An agent defaulting to `rounded-md` (8px) or `rounded` (4px) produces buttons that look like a different product entirely, breaking brand recognition on the most prominent interactive element. → Do instead:** Always apply `border-radius: var(--folk-radius-full)` to primary and secondary buttons. Reserve `--folk-radius-sm` (12px) exclusively for cards and tile containers.
2. **NEVER use Uxumgrotesque at `font-weight: 700` → Why it fails: The font only ships in `weight: 500` (Medium). Requesting bold causes the browser to synthesise a faux-bold, creating distorted letterforms inconsistent with the brand's editorial intent. → Do instead:** All `Uxumgrotesque` text must be `font-weight: 500`. If emphasis is needed within a heading, switch to a semantic inline element styled with `Rubik` bold.
3. **NEVER hardcode hex values in component code → Why it fails: With 36+ near-duplicate colour pairs in the extraction, an agent guessing `#313539` vs `#030200e3` will choose the wrong one for the context. CSS var references are also required for any future theme changes. → Do instead:** Always reference `var(--black)`, `var(--black--800<deleted|variable-a5ec4446>)`, etc. Use the semantic `--folk-*` aliases where available.
4. **NEVER use spacing values outside the extracted scale → Why it fails: `10px` (--folk-space-sm) is the one off-grid value in the system. Agents defaulting to "8px or 12px" grids will use 8px where folk uses 10px for button padding, creating slightly cramped or oversized buttons. → Do instead:** Use only `--folk-space-xs` (4px), `--folk-space-sm` (10px), `--folk-space-md` (12px), `--folk-space-lg` (16px), `--folk-space-xl` (24px), `--folk-space-2xl` (32px), `--folk-space-3xl` (48px). For button vertical padding specifically, use `--button--vertical-padding: 0.375rem`.
5. **NEVER use Inter or Foundersgrotesk for headings → Why it fails: AI agents default to Inter (the most common sans-serif) for all text. On folk.app, headings exclusively use `Uxumgrotesque` — using Inter produces a genericised look that erases the brand's typographic signature. → Do instead:** Map heading levels to fonts explicitly: `h1–h3 → Uxumgrotesque`, `nav/links/body → Foundersgrotesk`, `UI/body → Inter`, `buttons/labels → Rubik`.
6. **NEVER construct Tailwind classes dynamically (e.g. `` `bg-${colour}` ``) → Why it fails: Tailwind's JIT purges classes not present as complete strings at build time. Dynamic construction means the class is never generated, producing invisible/unstyled elements at runtime. → Do instead:** Write complete class names: `bg-[var(--black)]`, `rounded-[var(--folk-radius-full)]`. Or use inline `style` with CSS var references.
7. **NEVER omit hover state inversion on buttons → Why it fails: Folk's button interaction model is distinctive — the button goes from filled-black to transparent-with-black-outline on hover. An agent that only implements `opacity: 0.8` or `background: darkened-black` on hover produces an interaction that feels foreign to the folk design language. → Do instead:** Implement `background: transparent; color: var(--black); border: 1px solid var(--black)` for all primary button hover states.
8. **NEVER apply `text-transform: uppercase` to any text element → Why it fails: All extracted elements have `text-transform: none`. Agents trained on SaaS UI patterns often uppercase labels, nav items, or badges by default. folk's voice is conversational and sentence-case throughout. → Do instead:** Explicitly set `text-transform: none` on all text elements, especially buttons and badges.
9. **NEVER use the card `border-radius: 12px` alone without the `10px solid white border` → Why it fails: The card's visual weight and the apparent inner radius depend on the combination of `border-radius: 12px` and `border: 10px solid white`. Omitting the border makes cards look flat and borderless instead of having the distinctive inset appearance. → Do instead:** Always pair `border-radius: var(--folk-radius-sm)` with `border: 10px solid var(--white)` on card containers.
10. **NEVER place absolute-positioned elements to achieve layout structure → Why it fails: The extracted layout signals show `flex` for navigation, `flex column` for cards, and `block` for modals — no structural absolute positioning. Using `position: absolute` to lay out columns or stack sections breaks responsive reflow at folk's 7 breakpoints (450px → 1920px). → Do instead:** Use `display: flex` with `flex-direction: column` for card stacks, `flex-direction: row` for navigation and button groups, following the extracted layout signals.
11. **NEVER merge the `--folk-error` token (`#0f08000f`) as a red error colour → Why it fails: The curated token maps `--folk-error` to `--grey3` (`#0f08000f`), an almost-transparent warm dark tint — it is NOT a red/danger colour. Using it as a red error state produces invisible error indicators. → Do instead:** For error states, use `--folk-accent-warm` (`#f56741`) as the error border/text colour. The `--folk-error` token should be reviewed and potentially remapped manually.
---
## Appendix A: Complete Token Reference
Every token extracted from the source. §0 CORE TOKENS is the primary AI signal; this appendix is reference material an AI can cross-check against when a curated role is missing.
```css
/* Colours (59) */
--black: #030200e3;
--grey11: #050500a1;
--white: white;
--blue<deleted|variable-83e67b71>: #f6f8fe;
--pink<deleted|variable-4cc9684e>: #fff7f6;
--orange-plain<deleted|variable-73e30f5b>: #f56741;
--yellow<deleted|variable-a9798688>: #fffcf2;
--black--300<deleted|variable-35e7fffd>: #d6d7d7;
--black--200<deleted|variable-33acd7b1>: #ebebec;
--grey5: #e4e4e4;
--grey2: #12120008;
--black--500<deleted|variable-25419047>: #989a9c;
--black--100<deleted|variable-3f5d0b1a>: #f4f5f5;
--grey8: #bbb;
--black--800<deleted|variable-a5ec4446>: #313539;
--black--700<deleted|variable-0a0534d5>: #464a4d;
--blue-plain<deleted|variable-475b994a>: #5079e4;
--grey4: #0f0a001a;
--grey3: #0f08000f;
--grey6: #0d0a0029;
--grey7: #d4d4d4;
--grey1: #fcfcfc;
--grey--600<deleted|variable-289adc91>: #6f7275;
--folk-blue: #94c4ff;
--folk-purple: #c1aaf9;
--folk-orange: #ffc53d;
--folk-green: #bdee63;
--grey9: #8d8d8d;
--accessible-components--dark-grey: #9b9b9b;
--accessible-components--dodger-blue: #1378d1;
--button--bg: var(--black);
--button--hover-bg: transparent;
--grey10: grey;
--highlight-color: #fab9fb;
--bg-color: #bee0ef;
--brand-surface-1: rgb(246, 223, 246); /* Brand surface, dominant on 1 element — e.g. "simplify our whole sales flow." /* mined from computed styles */ */
--brand-surface-2: rgb(227, 239, 220); /* Brand surface, dominant on 1 element — e.g. "helps us capture all of this." /* mined from computed styles */ */
--brand-surface-3: rgb(255, 240, 189); /* Brand surface, dominant on 1 element — e.g. "A future-proof CRM" /* mined from computed styles */ */
--brand-surface-4: rgb(190, 217, 239); /* Brand surface, dominant on 1 element — e.g. "simple and flexible" /* mined from computed styles */ */
--brand-surface-1: rgb(246, 223, 246);
--brand-surface-2: rgb(227, 239, 220);
--brand-surface-3: rgb(255, 240, 189);
--brand-surface-4: rgb(190, 217, 239);
--folk-bg-app: --grey1;
--folk-bg-surface: --brand-surface-1;
--folk-bg-hover: --button--hover-bg;
--folk-border-default: var(--black);
--folk-border-subtle: 1px solid var(--grey5);
--folk-border-muted: 1px solid var(--grey8);
--button--border: var(--black);
--button--hover-border: var(--black);
--folk-focus-ring-light: rgba(0, 0, 0, 0.12) 0px 0px 0px 2px;
--folk-focus-ring-dark: rgba(255, 255, 255, 0.12) 0px 0px 0px 2px;
--folk-slider-focus: rgb(255, 255, 255) 0px 0px 0px 2px;
--folk-border-ui: 1px solid var(--black);
--folk-border-card-inset: 10px solid var(--white);
--folk-border-input: 1px solid var(--black);
--folk-border-input-focus: 1px solid rgb(0, 0, 0);
--folk-border-integration-hover: 1px solid var(--grey9);
/* Typography (36) */
--button--text: var(--white);
--button--text-size: 0.9375rem;
--button--hover-text: var(--black);
--button--font: Inter,Arial,sans-serif;
--button--line-height: 1.25rem;
--font-size-xs: 13px; /* 8 elements — e.g. p "Product hunt", p "Chrome store", p "G2 review" /* mined from computed styles */ */
--font-size-sm: 14px; /* 6 elements — e.g. div "Products", div "Solutions", div "Resources" /* mined from computed styles */ */
--font-size-md: 14.4px; /* 18 elements — e.g. a "Pricing", a "Get a demo", a "Login" /* mined from computed styles */ */
--font-size-lg: 15px; /* 22 elements — e.g. h3 "Get a single source ", h3 "Shape the exact data", h3 "Chat with your CRM o" /* mined from computed styles */ */
--font-size-xl: 28px; /* 3 elements — e.g. p "4,9", p "4,8", p "4,5" /* mined from computed styles */ */
--font-size-2xl: 40px; /* 5 elements — e.g. h3 "Capture contacts fas", h3 "Sales research, done", h3 "Personal outreach, a" /* mined from computed styles */ */
--font-size-3xl: 48px; /* 4 elements — e.g. h2 "folk CRM captures mu", h2 "Finally, a CRM conne", h2 "Loved by closers" /* mined from computed styles */ */
--font-weight-regular: 400; /* 52 elements — e.g. h3 "Get a single source ", h3 "Shape the exact data", h3 "Chat with your CRM o" /* mined from computed styles */ */
--font-weight-medium: 500; /* 18 elements — e.g. h1 "The CRM that works f", h2 "folk CRM captures mu", h2 "Finally, a CRM conne" /* mined from computed styles */ */
--font-weight-semibold: 700; /* 1 element — e.g. div "folk CRM captures mu" /* mined from computed styles */ */
--line-height-tight: 21px; /* 6 elements — e.g. div "Learn more", div "Explore folkX extens", div "Explore 1-click Enri" /* mined from computed styles */ */
--line-height-normal: 22.4px; /* 6 elements — e.g. div "Products", div "Solutions", div "Resources" /* mined from computed styles */ */
--line-height-loose: 23.04px; /* 18 elements — e.g. a "Pricing", a "Get a demo", a "Login" /* mined from computed styles */ */
--folk-text-primary: --black;
--folk-text-secondary: --black--800;
--folk-text-muted: var(--grey--600<deleted|variable-289adc91>);
--folk-text-disabled: var(--black--500<deleted|variable-25419047>);
--folk-font-size-xs: 13px;
--folk-font-size-sm: 14px;
--folk-font-size-md: 14.4px;
--folk-font-size-lg: 15px;
--folk-font-size-xl: 28px;
--folk-font-size-2xl: 40px;
--folk-font-size-3xl: 48px;
--folk-font-weight-regular: 400;
--folk-font-weight-medium: 500;
--folk-font-weight-semibold: 700;
--folk-font-sans: Inter,Arial,sans-serif;
--folk-line-height-tight: 21px;
--folk-line-height-normal: 22.4px;
--folk-line-height-loose: 23.04px;
/* Spacing (27) */
--button--vertical-padding: 0.375rem;
--button--horizontal-padding: 1.1rem;
--margin-bottom: 7rem;
--h1-width-crmfor: 120ch;
--subtitle-width-crmfor: 90ch;
--button--hover-border: var(--black);
--space-xs: 4px; /* 20 elements — e.g. div .nav-wrapper-link, div .nav-wrapper-link, div .nav-wrapper-link /* mined from computed styles */ */
--space-sm: 10px; /* 9 elements — e.g. div .rating-grid-wrapper, div .rating-grid-wrapper, div .rating-grid-wrapper /* mined from computed styles */ */
--space-md: 12px; /* 10 elements — e.g. div .w-layout-grid, div .w-layout-grid, div .card-component-2 /* mined from computed styles */ */
--space-lg: 16px; /* 36 elements — e.g. footer .footer5_component, div .ttitle-container, div .ttitle-container /* mined from computed styles */ */
--space-xl: 24px; /* 27 elements — e.g. div .product-section-container, div .product-section-container, div .product-section-container /* mined from computed styles */ */
--space-2xl: 32px; /* 18 elements — e.g. footer .footer5_component, div .nav-items-wrapper, div .nav-items-wrapper /* mined from computed styles */ */
--space-3xl: 48px; /* 9 elements — e.g. div .nav-items-container, div .nav-items-container, div .nav-items-container /* mined from computed styles */ */
--folk-space-xs: 4px;
--folk-space-sm: 10px;
--folk-space-md: 12px;
--folk-space-lg: 16px;
--folk-space-xl: 24px;
--folk-space-2xl: 32px;
--folk-space-3xl: 48px;
--breakpoint-xs: 450px;
--breakpoint-sm: 479px;
--breakpoint-md-low: 767px;
--breakpoint-md: 768px;
--breakpoint-lg: 991px;
--breakpoint-xl: 1440px;
--breakpoint-2xl: 1920px;
/* Radius (8) */
--radius-sm: 12px; /* 4 elements — e.g. div .card-component-2 "Follow-up AssistantS", div .card-component-2 "Recap AssistantAutom", div .card-component-2 "Research AssistantAu" /* mined from computed styles */ */
--radius-md: 20px; /* 2 elements — e.g. div .new-badge "New", div .new-badge "New" /* mined from computed styles */ */
--radius-lg: 180px; /* 1 element — e.g. div .play-button "Watch Demo" /* mined from computed styles */ */
--radius-full: 1000px; /* 4 elements — e.g. div .btn_wrapper "Learn more", div .btn_wrapper "Learn more", div .btn_wrapper "Learn more" /* mined from computed styles */ */
--folk-radius-sm: 12px;
--folk-radius-md: 20px;
--folk-radius-full: 1000px;
--folk-radius-lg: 180px;
/* Effects (5) */
--separator: var(--black);
--shadow-sm: rgba(0, 0, 0, 0.08) 0px 5px 12px 0px, rgba(0, 0, 0, 0.07) 0px 21px 21px 0px, rgba(0, 0, 0, 0.04) 0px 48px 29px 0px, rgba(0, 0, 0, 0.01) 0px 86px 34px 0px; /* 4 elements — e.g. div .card-component-2, div .card-component-2, div .card-component-2 /* mined from computed styles */ */
--shadow-md: rgba(17, 24, 39, 0.03) 0px 16px 16px 0px, rgba(17, 24, 39, 0.03) 0px 8px 8px 0px… <0.2KB elided>; /* 1 element — e.g. div .logo-context-menu /* mined from computed styles */ */
--folk-shadow-sm: Multi-layer diffuse (see Section 7);
--folk-shadow-md: Multi-layer subtle + 1px border (see Section 7);
/* Motion (6) */
----motion-spin: @keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}; /* @keyframes spin */
----motion-czrsUQ: @keyframes czrsUQ {
0% { opacity: 0; transform: translate3d(-200px, 0px, 0px); }
100% { opacity: 1; transform: translate3d(0px, 0px, 0px); }
}; /* @keyframes czrsUQ */
--duration-fast: 0.1s; /* 1 element — e.g. img /* mined from computed styles */ */
--duration-base: 0.2s; /* 6 elements — e.g. button, button, div /* mined from computed styles */ */
--duration-slow: 0.3s; /* 1 element — e.g. div /* mined from computed styles */ */
--ease-default: ease; /* 226 elements — e.g. button, button, a /* mined from computed styles */ */
```
## Appendix B: Token Source Metadata
```
tokenSource: extracted-css-vars
confidence: high
cssVarsFound: 48
curatedTokens: 44
```
**Extraction method:** CSS custom properties extracted directly from folk.app's live stylesheet. All `--folk-*` and `--black`, `--grey*`, `--white` tokens are first-party CSS variables — high fidelity to the site's actual design system.
**Deleted variables:** Several tokens carry a `<deleted|variable-XXXXXXXX>` suffix in their CSS variable names. These are Webflow variable slots that were removed from the Webflow design system but whose values remain referenced in the compiled CSS. They are preserved verbatim in this document. Treat them as valid runtime values but be aware they may be cleaned up in future deploys.
**Computed style reconstruction:** Typography scale (`--folk-font-size-*`), line heights (`--folk-line-height-*`), and font weights (`--folk-font-weight-*`) were confirmed by cross-referencing the extracted CSS vars against computed styles for `h1`, `h2`, `h3`, `body`, `button_primary`, `input`, and `badge` elements. **Confidence: high.**
**Brand surfaces:** `--brand-surface-1` through `--brand-surface-4` were mined from computed background colours on testimonial and feature section elements — not found as explicit CSS vars. **Confidence: medium** (values confirmed from 1 element each; verify across viewport sizes).
**Error token note:** `--folk-error` maps to `--grey3` (`#0f08000f`) — this is an extremely transparent near-invisible tint. The semantic mapping is **low confidence** — this token should be manually verified or replaced with `--orange-plain<deleted|variable-73e30f5b>` (`#f56741`) for actual error states.
**Font loading:** Uxumgrotesque (weight 500), Instrumentserif (italic 400), Inter (400, 500), Rubik (400), Foundersgrotesk (400) are loaded from Webflow's CDN. Ensure these font files are available in any non-Webflow implementation; they are not Google Fonts.
**Libraries detected:** Tailwind + Bootstrap classes may coexist with Webflow's native CSS in the compiled output. Prefer `var(--token)` references over utility classes to avoid library conflicts.More from the gallery
Browse all kits →You may also like

atlassian.com
MITEnterprise design system for Atlassian's marketing site, featuring bold brand colours, custom typography, and structured spacing tokens built for large-scale SaaS platforms
06
boldsaaslanding-pagelight

github.com
MITGitHub's production design system with 568 CSS custom properties, featuring clean typography, accessible colour tokens, and motion primitives built for developer platforms and collaborative workflows
04
darkdeveloper-toolsaas

Customer.io
MITDark SaaS design system with mint-green accents and clean typography, built for product dashboards and developer-focused platforms
011
darksaasdeveloper-tooldashboard