Netflix
MIT
Dark, bold streaming platform design system with signature red accent and cinematic motion, built for large-scale video content discovery and subscription flows
Colour (96)
color.colorgrey30rgba(128, 128, 128, 0.4)
color.colorgrey50rgba(128, 128, 128, 0.7)
color.colorred500rgb(229, 9, 20)
color.colorred600rgb(193, 17, 25)
color.colorred700rgb(153, 22, 29)
color.colordark500rgb(65, 65, 65)
color.colordark600rgb(45, 45, 45)
color.colordark700rgb(35, 35, 35)
color.colordark800rgb(22, 22, 22)
color.colordark900rgb(0, 0, 0)
color.colorwhite40rgba(255, 255, 255, 0.4)
color.colorwhite70rgba(255, 255, 255, 0.7)
color.netflixbgapprgb(0, 0, 0)
color.netflixerrorrgb(235, 57, 66)
color.colorgreen400rgb(43, 184, 113)
color.colorrederrorrgb(235, 57, 66)
color.colorwhite100rgb(255, 255, 255)
color.netflixaccentrgb(229, 9, 20)
color.netflixborderrgba(128, 128, 128, 0.7)
color.colorgreyfocus#a9a9a9
color.coloryellow400rgb(216, 157, 49)
color.netflixsuccessrgb(43, 184, 113)
color.netflixwarningrgb(216, 157, 49)
color.brandprimaryctargb(229, 9, 20)
color.netflixbgsurfacergba(22, 22, 22, 0.7)
color.netflixtextmutedrgba(255, 255, 255, 0.7)
color.netflixtextwhitergb(255, 255, 255)
color.netflixaccentwarmrgb(193, 17, 25)
color.wctfocusringcolorrgb(255, 255, 255)
color.netflixborderfocusrgb(255, 255, 255)
color.netflixtextpressedrgba(255, 255, 255, 0.7)
color.netflixtextdisabledrgba(255, 255, 255, 0.4)
color.netflixaccentpressedrgb(153, 22, 29)
color.typeinputlabelfilled{
font-family: "Netflix Sans", "Helvetica Neue", "Segoe UI", Roboto, Ubuntu, sans-serif
color.netflixaccentdisabledrgba(229, 9, 20, 0.4)
color.netflixbgskeletonbasergb(35, 35, 35)
color.netflixborderdisabledrgba(128, 128, 128, 0.4)
color.netflixaccordionsurfacergb(45, 45, 45)
color.wctlayoutcontainerwidthinherit
color.netflixbgskeletonshimmerrgb(65, 65, 65)
color.netflixbgsurfacedisabledrgba(22, 22, 22, 0.2)
color.netflixbordertransparentrgba(0, 0, 0, 0)
color.wctfocusringcolordefault#a9a9a9
color.wctlocaldesigninputborderrgba(128, 128, 128, 0.7)
color.netflixaccordionforegroundrgb(255, 255, 255)
color.wctlocaldesignbuttonborderrgba(0, 0, 0, 0)
color.wctlocaldesigninputsurfacergba(22, 22, 22, 0.7)
color.wctlocaldesignselectborderrgba(128, 128, 128, 0.7)
Spacing (51)
spacing.wctlayoutitempaddinginitial
spacing.wctlocaldesignaccordionpanelspace0rem var(--wct--local-design--Accordion-PanelSpaceExpanded)
spacing.wctlocaldesignselectspacevertical0rem
spacing.wctlocaldesignaccordionheadlinespaceexpandedvar(--wct--local-design--Accordion-HeadlineSpace)
spacing.netflixspacexs0.0625rem
spacing.wctlocaldesignbuttonborderwidth0.0625rem
spacing.wctlocaldesignaccordionspacebetweenheadlinepanel0.0625rem
spacing.netflixspacesm0.125rem
spacing.focusringoffset0.125rem
spacing.wctfocusringwidth0.125rem
spacing.wctfocusringoffset0.125rem
spacing.netflixspacemd0.25rem
spacing.wctlocaldesigninputspacevertical0.25rem
spacing.wctlocaldesignbuttonspacevertical0.25rem
spacing.wctlocaldesignselectmessagespacebetweeniconcontent0.25rem
spacing.netflixspacelg0.375rem
spacing.wctlocaldesignselectspaceverticalempty0.375rem
spacing.wctlocaldesigninputspacebetweenfieldmessage0.375rem
spacing.wctlocaldesignselectspacebetweenfieldmessage0.375rem
spacing.wctlocaldesigninputspacebetweenfielddescription0.375rem
spacing.wctlocaldesignselectspacebetweenfielddescription0.375rem
spacing.netflixspacexl0.5rem
spacing.wctlocaldesignaccordionspacebetween0.5rem
spacing.wctlocaldesignbuttonspacebetweenicontext0.5rem
spacing.wctlocaldesigninputspacebetweeniconcontent0.5rem
spacing.wctlocaldesignselectspacebetweeniconcontent0.5rem
spacing.netflixspace2xl0.625rem
spacing.wctlocaldesignselectspacehorizontal0.625rem
spacing.netflixspace3xl0.75rem
spacing.wctlocaldesigninputspaceverticalempty0.75rem
spacing.wctlocaldesignaccordionheadlinespacebetweenicontext0.75rem
spacing.wctlocaldesignbuttoniconwidth1rem
spacing.wctlocaldesignbuttoniconheight1rem
spacing.wctlocaldesigninputspacehorizontal1rem
spacing.wctlocaldesignbuttonspacehorizontal1rem
spacing.wctlocaldesignaccordionheadlinespace1.5rem
spacing.wctlocaldesignaccordionpanelspaceexpanded1.5rem
spacing.wctlocaldesignbuttonheight2rem
spacing.spaceheroheadingbottom16px
spacing.spacebodybottom32px
spacing.otfooterspace160px
spacing.bpmobilesm400px
spacing.bpmobile530px
spacing.bptabletsm640px
spacing.bptablet768px
spacing.bptabletlg960px
spacing.bpdesktop1024px
spacing.bpdesktoplg1280px
spacing.bpdesktopxl1600px
spacing.bphd1920px
spacing.bp4k2560px
Radius (15)
wctlocaldesignaccordionpanelborderradius0rem
wctlocaldesignaccordionheadlineborderradius0rem
wctlocaldesignaccordionpanelborderradiusexpanded0rem 0rem var(--wct--local-design--Accordion-PanelBorderRadius) var(--wct--local-design--Accordion-PanelBorderRadius)
wctlocaldesignaccordionheadlineborderradiusexpandedvar(--wct--local-design--Accordion-HeadlineBorderRadius) var(--wct--local-design--Accordion-HeadlineBorderRadius) 0rem 0rem
wctlocaldesigninputborderradius0.25rem
wctlocaldesignbuttonborderradius0.25rem
wctlocaldesignselectborderradius0.25rem
radiussm2px
netflixradiussm2px
radiusmd4px
netflixradiusmd4px
radiuslg8px
netflixradiuslg8px
radiusfull50px
netflixradiusfull50px
Shadow (12)
effect.shadownonenone
effect.shadowbadgergb(128, 128, 128) 0px 0px 5px 0px
effect.wctfocusringstylesolid
effect.wctaccordioniconrotation-45deg
effect.wctlocaldesignbuttonwidthauto
effect.wctlocaldesignbuttonduration250ms
effect.wctlayoutcontainerflexdirectionxsinitial
effect.wctlocaldesignbuttoneasingdisabledvar(--wct--local-design--Button-Easing)
effect.wctlocaldesignbuttondurationpressed0
effect.wctlocaldesignbuttondurationdisabledvar(--wct--local-design--Button-Duration)
effect.wctlocaldesignbuttonforegroundhoveredvar(--wct--local-design--Button-Foreground)
effect.wctlocaldesignaccordionheadlinedurationhoveredvar(--wct--local-design--Accordion-HeadlineDuration)
# layout.md — Netflix Design System
---
## 0. Quick Reference
**Stack:** React/CSS-in-JS (Emotion), custom CSS properties, Bootstrap utility layer. Token source: `extracted-css-vars` (262 properties, high confidence). Use as `var(--token-name)` in CSS, `style={{ prop: 'var(--token-name)' }}` in JSX, or `bg-[var(--token-name)]` in Tailwind.
```css
:root {
/* Brand */
--netflix-accent: rgb(229, 9, 20); /* Primary CTA background — "Get Started", "Sign In" buttons */
--netflix-accent-warm: rgb(193, 17, 25); /* Button hover state surface */
--netflix-accent-pressed: rgb(153, 22, 29); /* Button active/pressed surface */
--netflix-accent-disabled: rgba(229, 9, 20, 0.4); /* Button disabled surface */
/* Surfaces */
--netflix-bg-surface: rgba(22, 22, 22, 0.7); /* Form inputs, select, overlaid containers */
--netflix-accordion-surface: rgb(45, 45, 45); /* Accordion headline background */
--netflix-accordion-surface-hover: rgb(65, 65, 65); /* Accordion headline hover */
/* Text */
--netflix-text-white: rgb(255, 255, 255); /* Primary text on dark surfaces */
--netflix-text-muted: rgba(255, 255, 255, 0.7); /* Labels, descriptions */
--netflix-text-disabled: rgba(255, 255, 255, 0.4);/* Disabled state text */
/* Status */
--netflix-success: rgb(43, 184, 113);
--netflix-warning: rgb(216, 157, 49);
--netflix-error: rgb(235, 57, 66);
/* Border */
--netflix-border: rgba(128, 128, 128, 0.7);
--netflix-border-focus: rgb(255, 255, 255);
/* Radius */
--netflix-radius-sm: 2px; /* badge, tile corners */
--netflix-radius-md: 4px; /* buttons, inputs */
--netflix-radius-lg: 8px; /* content cards */
/* Motion */
--netflix-duration-base: 0.25s;
--netflix-ease-out: cubic-bezier(0.32, 0.94, 0.6, 1);
--netflix-ease-in: cubic-bezier(0.4, 0, 0.68, 0.06);
}
```
```tsx
// Primary CTA button — production-ready
<button
style={{
backgroundColor: 'var(--netflix-accent)',
color: 'var(--netflix-text-white)',
borderRadius: 'var(--netflix-radius-md)',
padding: '12px 24px',
fontSize: '24px',
fontWeight: 500,
fontFamily: '"Netflix Sans", "Helvetica Neue", "Segoe UI", Roboto, Ubuntu, sans-serif',
transition: `background-color var(--netflix-duration-base) var(--netflix-ease-in)`,
border: 'none',
cursor: 'pointer',
}}
onMouseOver={e => e.currentTarget.style.backgroundColor = 'var(--netflix-accent-warm)'}
onMouseOut={e => e.currentTarget.style.backgroundColor = 'var(--netflix-accent)'}
>
Get Started
</button>
```
**NEVER rules:**
- NEVER use `Inter`, `Roboto`, or `Arial` as the primary font — use `"Netflix Sans"` with its full fallback stack
- NEVER hardcode `#e50914` — use `var(--netflix-accent)`
- NEVER use `border-radius > 8px` on primary buttons — Netflix buttons use `4px` (`--netflix-radius-md`)
- NEVER omit hover and active states on buttons — surface color must change on hover (`rgb(193,17,25)`) and active (`rgb(153,22,29)`)
- NEVER use warm or light backgrounds — the entire UI is dark (`rgb(0,0,0)` to `rgb(45,45,45)` range)
- NEVER skip focus ring — all interactive elements must show `outline: 0.125rem solid rgb(255,255,255)` on `:focus-visible`
**Full design system → see layout.md**
---
<!-- Quick Reference truncated to fit the 75-line cap. See later sections for the full design system. -->
## 1. Design Direction & Philosophy
### Character & Mood
Netflix's design is **cinematic, authoritative, and immersive**. The visual language prioritises content (show artwork, thumbnails) above all else. The UI is a dark stage that recedes to let media take center focus. The red accent (`rgb(229,9,20)`) signals action and brand identity — it appears only on CTAs, never as decoration.
### Aesthetic Intent
- **Dark-first**: Every surface is dark. Background ranges from pure black to `rgba(22,22,22,0.7)`. There is no light mode.
- **High contrast**: White text (`rgb(255,255,255)`) on near-black backgrounds achieves maximum legibility for TV/monitor viewing distances.
- **Typographic scale is dramatic**: `h1` at `56px / 900` weight is deliberately billboard-scale. The jump from body (`20px`) to hero heading (`56px`) is intentional and must not be compressed.
- **Minimal chrome**: Borders are semi-transparent (`rgba(128,128,128,0.7)`), not solid. Shadows are used sparingly. The UI does not compete with content.
- **Sharp-ish geometry**: Buttons are `4px` radius — not pill, not square. Cards are `8px`. Accordions are `0px`. Each shape is deliberate.
### What This Design Explicitly Rejects
- **Light backgrounds**: NEVER use white or light-grey surfaces for content sections.
- **Decorative colour**: Red is reserved for primary actions only. It is NEVER used for text, dividers, or decorative elements.
- **Rounded pill buttons**: Despite having a `--netflix-radius-full: 50px` token (used on one `input` element), primary CTA buttons are `4px` radius.
- **Font substitution**: The proprietary `Netflix Sans` font is critical to brand identity. System font fallbacks exist but should never be used as a deliberate choice.
- **Generic spacing**: Netflix uses precise, non-standard spacing values (e.g. `0.375rem` for field gaps). Do not substitute an 8px grid system.
---
## 2. Colour System
### Tier 1 — Primitive Values
```css
/* Raw colour values — reference only, use semantic tokens in components */
:root {
/* Red scale */
--color-red-500: rgb(229, 9, 20); /* #e50914 — brand primary */
--color-red-600: rgb(193, 17, 25); /* #c11119 — hover */
--color-red-700: rgb(153, 22, 29); /* #99161d — pressed */
/* Dark scale */
--color-dark-900: rgb(0, 0, 0); /* Pure black — page background */
--color-dark-800: rgb(22, 22, 22); /* #161616 — form surfaces */
--color-dark-700: rgb(35, 35, 35); /* #232323 — loading skeleton base */
--color-dark-600: rgb(45, 45, 45); /* #2d2d2d — accordion surface */
--color-dark-500: rgb(65, 65, 65); /* #414141 — accordion hover, skeleton shimmer */
/* White scale */
--color-white-100: rgb(255, 255, 255); /* Full white */
--color-white-70: rgba(255, 255, 255, 0.7); /* Muted text */
--color-white-40: rgba(255, 255, 255, 0.4); /* Disabled text */
/* Grey scale */
--color-grey-50: rgba(128, 128, 128, 0.7); /* Border default */
--color-grey-30: rgba(128, 128, 128, 0.4); /* Border disabled */
--color-grey-focus: #a9a9a9; /* Focus ring default (non-keyboard) */
/* Status */
--color-green-400: rgb(43, 184, 113); /* success */
--color-yellow-400: rgb(216, 157, 49); /* warning */
--color-red-error: rgb(235, 57, 66); /* error — distinct from brand red */
}
```
### Tier 2 — Semantic Aliases (Primary Reference Layer)
```css
:root {
/* Action / Brand */
--netflix-accent: rgb(229, 9, 20); /* extracted: high confidence — primary CTA bg */
--netflix-accent-warm: rgb(193, 17, 25); /* extracted: high confidence — button hover */
--netflix-accent-pressed: rgb(153, 22, 29); /* extracted: high confidence — button active */
--netflix-accent-disabled: rgba(229, 9, 20, 0.4); /* extracted: high confidence — button disabled */
/* Surfaces */
--netflix-bg-app: rgb(0, 0, 0); /* reconstructed: high confidence — page background */
--netflix-bg-surface: rgba(22, 22, 22, 0.7); /* extracted: high confidence — form surface */
--netflix-bg-surface-disabled: rgba(22, 22, 22, 0.2); /* extracted: high confidence */
--netflix-bg-skeleton-base: rgb(35, 35, 35); /* extracted: high confidence — loading animation base */
--netflix-bg-skeleton-shimmer: rgb(65, 65, 65); /* extracted: high confidence — loading animation peak */
/* Text */
--netflix-text-white: rgb(255, 255, 255); /* extracted: high confidence — primary foreground */
--netflix-text-muted: rgba(255, 255, 255, 0.7); /* extracted: high confidence — labels, helper text */
--netflix-text-disabled: rgba(255, 255, 255, 0.4);/* extracted: high confidence — disabled state */
--netflix-text-pressed: rgba(255, 255, 255, 0.7); /* extracted: high confidence — button text when active */
/* Borders */
--netflix-border: rgba(128, 128, 128, 0.7); /* extracted: high confidence — default border */
--netflix-border-disabled: rgba(128, 128, 128, 0.4); /* extracted: high confidence */
--netflix-border-focus: rgb(255, 255, 255); /* extracted: high confidence — keyboard focus ring */
--netflix-border-transparent: rgba(0, 0, 0, 0); /* extracted: high confidence — button border (no border) */
/* Status */
--netflix-success: rgb(43, 184, 113); /* extracted: high confidence */
--netflix-warning: rgb(216, 157, 49); /* extracted: high confidence */
--netflix-error: rgb(235, 57, 66); /* extracted: high confidence */
/* Accordion */
--netflix-accordion-surface: rgb(45, 45, 45); /* extracted: high confidence */
--netflix-accordion-surface-hover: rgb(65, 65, 65); /* extracted: high confidence */
--netflix-accordion-foreground: rgb(255, 255, 255); /* extracted: high confidence */
}
```
### Tier 3 — Component Tokens (Original CSS Variable Names)
```css
/* Button component tokens — PRESERVE these original names exactly */
:root {
--wct--local-design--Button-Surface: rgb(229, 9, 20); /* button bg: default */
--wct--local-design--Button-SurfaceHovered: rgb(193, 17, 25); /* button bg: hover */
--wct--local-design--Button-SurfaceDisabled: rgba(229, 9, 20, 0.4);/* button bg: disabled */
--wct--local-design--Button-SurfacePressed: rgb(153, 22, 29); /* button bg: active/pressed */
--wct--local-design--Button-Foreground: rgb(255, 255, 255); /* button text: default */
--wct--local-design--Button-ForegroundDisabled: rgba(255, 255, 255, 0.4); /* button text: disabled */
--wct--local-design--Button-ForegroundHovered: var(--wct--local-design--Button-Foreground);
--wct--local-design--Button-ForegroundPressed: rgba(255, 255, 255, 0.7); /* button text: active */
--wct--local-design--Button-Border: rgba(0, 0, 0, 0); /* button border: transparent */
--wct--local-design--Button-BorderDisabled: rgba(0, 0, 0, 0);
--wct--local-design--Button-BorderHovered: rgba(0, 0, 0, 0);
--wct--local-design--Button-BorderPressed: rgba(0, 0, 0, 0);
--wct--local-design--Button-BorderRadius: 0.25rem; /* 4px */
--wct--local-design--Button-BorderWidth: 0.0625rem; /* 1px */
/* Input / Select component tokens */
--wct--local-design--Select-Surface: rgba(22, 22, 22, 0.7);
--wct--local-design--Select-SurfaceDisabled: rgba(22, 22, 22, 0.02);
--wct--local-design--Select-Foreground: rgb(255, 255, 255);
--wct--local-design--Select-ForegroundDisabled: rgba(255, 255, 255, 0.4);
--wct--local-design--Select-LabelForeground: rgba(255, 255, 255, 0.7);
--wct--local-design--Select-LabelForegroundDisabled: rgba(255, 255, 255, 0.4);
--wct--local-design--Select-DescriptionForeground: rgba(255, 255, 255, 0.7);
--wct--local-design--Select-Border: rgba(128, 128, 128, 0.7);
--wct--local-design--Select-BorderDisabled: rgba(128, 128, 128, 0.4);
--wct--local-design--Select-BorderError: rgb(235, 57, 66);
--wct--local-design--Select-BorderSuccess: rgb(43, 184, 113);
--wct--local-design--Select-BorderWarning: rgb(216, 157, 49);
--wct--local-design--Select-BorderRadius: 0.25rem;
--wct--local-design--Select-BorderWidth: 0.0625rem;
--wct--local-design--Select-MessageForegroundError: rgb(235, 57, 66);
--wct--local-design--Select-MessageForegroundSuccess: rgb(43, 184, 113);
--wct--local-design--Select-MessageForegroundWarning: rgb(216, 157, 49);
/* Input tokens */
--wct--local-design--Input-Surface: rgba(22, 22, 22, 0.7);
--wct--local-design--Input-SurfaceDisabled: rgba(22, 22, 22, 0.2);
--wct--local-design--Input-Foreground: rgb(255, 255, 255);
--wct--local-design--Input-ForegroundDisabled: rgba(255, 255, 255, 0.4);
--wct--local-design--Input-LabelForeground: rgba(255, 255, 255, 0.7);
--wct--local-design--Input-LabelForegroundDisabled: rgba(255, 255, 255, 0.4);
--wct--local-design--Input-DescriptionForeground: rgba(255, 255, 255, 0.7);
--wct--local-design--Input-Border: rgba(128, 128, 128, 0.7);
--wct--local-design--Input-BorderDisabled: rgba(128, 128, 128, 0.4);
--wct--local-design--Input-BorderError: rgb(235, 57, 66);
--wct--local-design--Input-BorderSuccess: rgb(43, 184, 113);
--wct--local-design--Input-BorderWarning: rgb(216, 157, 49);
--wct--local-design--Input-BorderRadius: 0.25rem;
--wct--local-design--Input-BorderWidth: 0.0625rem;
--wct--local-design--Input-MessageForegroundError: rgb(235, 57, 66);
--wct--local-design--Input-MessageForegroundSuccess: rgb(43, 184, 113);
--wct--local-design--Input-MessageForegroundWarning: rgb(216, 157, 49);
/* Focus ring */
--wct--focus-ring--color: rgb(255, 255, 255);
--wct--focus-ring--color-default: #a9a9a9;
--wct--focus-ring--width: 0.125rem; /* 2px */
--wct--focus-ring--style: solid;
--wct--focus-ring--offset: 0.125rem; /* 2px */
}
```
### Accent / Brand Subgroup (additional detected)
```css
:root {
/* Decorative brand colours — tile backgrounds, illustration accents */
--wct--local-design--Button-SurfacePressed: rgb(153, 22, 29); /* deep red pressed state */
--brand-primary-cta: rgb(229, 9, 20); /* extracted: high confidence — maps to --netflix-accent */
}
```
---
## 3. Typography System
### Font Stack
```css
:root {
/* Primary typeface — Netflix proprietary variable font */
--font-family-primary: "Netflix Sans", "Helvetica Neue", "Segoe UI", Roboto, Ubuntu, sans-serif;
/* extracted: high confidence — used on h1, h2, h3, body, button, input, dropdown */
/* Script-specific overrides (do not use for Latin UI) */
--font-family-arabic: "NKufi", "Netflix Sans", sans-serif;
--font-family-thai: "GraphikTH", "Netflix Sans", sans-serif;
--font-family-ja: "Netflix Sans JA", "Netflix Sans", sans-serif;
}
```
### Composite Typography Tokens
```css
/* Each composite bundles family + size + weight + line-height + letter-spacing */
/* Hero Heading */
--type-hero: {
font-family: "Netflix Sans", "Helvetica Neue", "Segoe UI", Roboto, Ubuntu, sans-serif;
font-size: 56px; /* --netflix-font-size-2xl */
font-weight: 900; /* --netflix-font-weight-semibold (Netflix's "Black" cut) */
line-height: 70px; /* --netflix-line-height-loose */
letter-spacing: normal;
color: rgb(255, 255, 255);
text-align: center;
}
/* Usage: h1 on hero/landing section only */
/* Section Heading */
--type-section-heading: {
font-family: "Netflix Sans", "Helvetica Neue", "Segoe UI", Roboto, Ubuntu, sans-serif;
font-size: 24px; /* --netflix-font-size-xl */
font-weight: 500;
line-height: normal;
letter-spacing: normal;
color: rgb(255, 255, 255);
text-align: start;
}
/* Usage: h2 — "Trending Now", "More Reasons to Join", "Frequently Asked Questions" */
/* Body / Subheading */
--type-body-large: {
font-family: "Netflix Sans", "Helvetica Neue", "Segoe UI", Roboto, Ubuntu, sans-serif;
font-size: 20px; /* --netflix-font-size-lg */
font-weight: 500;
line-height: normal;
letter-spacing: normal;
color: rgb(255, 255, 255);
text-align: center;
}
/* Usage: body — hero sub-copy, section intro text. margin-bottom: 32px */
/* Content Heading / UI Label Large */
--type-ui-heading: {
font-family: "Netflix Sans", "Helvetica Neue", "Segoe UI", Roboto, Ubuntu, sans-serif;
font-size: 16px; /* --netflix-font-size-md */
font-weight: 400;
line-height: 24px;
letter-spacing: normal;
color: rgb(255, 255, 255);
}
/* Usage: h3 — form field labels, feature sub-labels */
/* Button Text (large CTA) */
--type-button-large: {
font-family: "Netflix Sans", "Helvetica Neue", "Segoe UI", Roboto, Ubuntu, sans-serif;
font-size: 24px; /* extracted from button_primary computed style */
font-weight: 500;
line-height: 24px;
letter-spacing: normal;
color: rgb(255, 255, 255);
}
/* Usage: primary hero CTA — "Get Started" */
/* Button Text (small/nav) */
--type-button-small: {
font-family: "Netflix Sans", "Helvetica Neue", "Segoe UI", Roboto, Ubuntu, sans-serif;
font-size: 14px; /* --netflix-font-size-sm */
font-weight: 500;
line-height: 14px; /* extracted from link computed style */
letter-spacing: normal;
color: rgb(255, 255, 255);
}
/* Usage: nav "Sign In" button, secondary CTAs, footer links */
/* Accordion Headline */
--type-accordion-headline: {
font-family: "Netflix Sans", "Helvetica Neue", "Segoe UI", Roboto, Ubuntu, sans-serif;
font-size: 24px; /* --wct--local-design--Accordion-HeadlineTextFontSize: 1.5rem */
font-weight: 400;
line-height: normal;
letter-spacing: normal;
color: rgb(255, 255, 255);
}
/* Usage: FAQ accordion question headers */
/* Accordion Panel / Body */
--type-accordion-panel: {
font-family: "Netflix Sans", "Helvetica Neue", "Segoe UI", Roboto, Ubuntu, sans-serif;
font-size: 24px; /* --wct--local-design--Accordion-PanelTextFontSize: 1.5rem */
font-weight: 400;
line-height: normal;
letter-spacing: normal;
color: rgb(255, 255, 255);
}
/* Usage: FAQ accordion answer body text */
/* Input / Form Text */
--type-input-value: {
font-family: "Netflix Sans", "Helvetica Neue", "Segoe UI", Roboto, Ubuntu, sans-serif;
font-size: 16px; /* --wct--local-design--Input-TextFontSize: 1rem */
font-weight: 400;
line-height: 24px; /* 1.5 relative → 24px computed */
letter-spacing: normal;
color: rgb(255, 255, 255);
}
/* Input Label (filled state) */
--type-input-label-filled: {
font-family: "Netflix Sans", "Helvetica Neue", "Segoe UI", Roboto, Ubuntu, sans-serif;
font-size: 12px; /* --wct--local-design--Input-LabelTextFontSize: 0.75rem */
font-weight: 400;
line-height: 18px; /* 1.5 relative */
letter-spacing: normal;
color: rgba(255, 255, 255, 0.7);
}
/* Input Label (empty/placeholder state) */
--type-input-label-empty: {
font-family: "Netflix Sans", "Helvetica Neue", "Segoe UI", Roboto, Ubuntu, sans-serif;
font-size: 16px; /* --wct--local-design--Input-LabelTextEmptyFontSize: 1rem */
font-weight: 400;
line-height: 24px; /* 1.5 relative */
letter-spacing: normal;
color: rgba(255, 255, 255, 0.7);
}
/* Helper / Description / Message */
--type-field-helper: {
font-family: "Netflix Sans", "Helvetica Neue", "Segoe UI", Roboto, Ubuntu, sans-serif;
font-size: 13px; /* --wct--local-design--Input-DescriptionFontSize: 0.8125rem */
font-weight: 400;
line-height: normal;
letter-spacing: normal;
color: rgba(255, 255, 255, 0.7);
}
/* Dropdown / Select */
--type-dropdown: {
font-family: "Netflix Sans", "Helvetica Neue", "Segoe UI", Roboto, Ubuntu, sans-serif;
font-size: 16px;
font-weight: 400;
line-height: 20px;
letter-spacing: normal;
color: rgb(255, 255, 255);
}
/* Footer / Nav small */
--type-footer: {
font-family: "Netflix Sans", "Helvetica Neue", "Segoe UI", Roboto, Ubuntu, sans-serif;
font-size: 14px; /* --netflix-font-size-sm — 44 elements in footer */
font-weight: 500;
line-height: 21px; /* --netflix-line-height-tight */
letter-spacing: normal;
color: rgb(255, 255, 255);
}
/* Large Numeric Display (category numbers, episode counts) */
--type-display-numeral: {
font-family: "Netflix Sans", "Helvetica Neue", "Segoe UI", Roboto, Ubuntu, sans-serif;
font-size: 100px; /* --netflix-font-size-3xl — 20 elements, span numerals */
font-weight: 900;
line-height: normal;
letter-spacing: normal;
color: rgb(255, 255, 255);
}
/* Usage: ranking numbers overlaid on content tiles (Top 10 rows) */
```
### Weight Scale
| Weight | Token value | Netflix Sans Cut | Usage |
|--------|-------------|-----------------|-------|
| 100 | `font-weight: 100` | Thin | Decorative only |
| 300 | `font-weight: 300` | Light | Secondary copy |
| 400 | `font-weight: 400` | Regular | Body, labels, accordion |
| 500 | `font-weight: 500` | Medium | **Buttons, nav, section heads** |
| 700 | `font-weight: 700` | Bold | Emphasis |
| **900** | `font-weight: 900` | Black | **Hero h1 — single use** |
---
## 4. Spacing & Layout
### Base Unit & Scale
```css
:root {
/* Component micro-spacing (from extracted CSS vars) */
--wct--local-design--Button-BorderWidth: 0.0625rem; /* 1px — border widths */
--wct--focus-ring--width: 0.125rem; /* 2px — focus ring, also offset */
--wct--focus-ring--offset: 0.125rem; /* 2px */
--wct--local-design--Select-SpaceVerticalEmpty: 0.375rem; /* 6px — field top gap when empty */
--wct--local-design--Select-SpaceBetweenFieldDescription: 0.375rem; /* 6px */
--wct--local-design--Select-SpaceBetweenFieldMessage: 0.375rem; /* 6px */
--wct--local-design--Select-MessageSpaceBetweenIconContent: 0.25rem;/* 4px */
--wct--local-design--Select-SpaceBetweenIconContent: 0.5rem; /* 8px */
--wct--local-design--Select-SpaceHorizontal: 0.625rem; /* 10px — field horizontal padding */
--wct--local-design--Button-SpaceVertical: 0.25rem; /* 4px */
--wct--local-design--Button-SpaceHorizontal: 1rem; /* 16px */
--wct--local-design--Button-SpaceBetweenIconText: 0.5rem;/* 8px */
--wct--local-design--Button-Height: 2rem; /* 32px — default button height */
--wct--local-design--Button-IconHeight: 1rem; /* 16px */
--wct--local-design--Button-IconWidth: 1rem; /* 16px */
--wct--local-design--Input-SpaceHorizontal: 1rem; /* 16px */
--wct--local-design--Input-SpaceVertical: 0.25rem; /* 4px */
--wct--local-design--Input-SpaceVerticalEmpty: 0.75rem; /* 12px */
--wct--local-design--Input-SpaceBetweenIconContent: 0.5rem; /* 8px */
--wct--local-design--Input-SpaceBetweenFieldDescription: 0.375rem; /* 6px */
--wct--local-design--Input-SpaceBetweenFieldMessage: 0.375rem; /* 6px */
--wct--local-design--Accordion-HeadlineSpace: 1.5rem; /* 24px — accordion header padding */
--wct--local-design--Accordion-HeadlineSpaceExpanded: var(--wct--local-design--Accordion-HeadlineSpace);
--wct--local-design--Accordion-PanelSpaceExpanded: 1.5rem; /* 24px — accordion body padding */
--wct--local-design--Accordion-SpaceBetween: 0.5rem; /* 8px — gap between accordion items */
--wct--local-design--Accordion-SpaceBetweenHeadlinePanel: 0.0625rem; /* 1px — separator */
--wct--local-design--Accordion-HeadlineSpaceBetweenIconText: 0.75rem; /* 12px */
/* Page-level spacing (computed from element styles) */
--space-hero-heading-bottom: 16px; /* reconstructed: high confidence — h1 margin-bottom */
--space-body-bottom: 32px; /* reconstructed: high confidence — body margin-bottom */
--ot-footer-space: 160px; /* extracted: high confidence — footer top spacing */
/* Semantic spacing aliases */
--netflix-space-xs: 0.0625rem; /* 1px — borders */
--netflix-space-sm: 0.125rem; /* 2px — focus ring */
--netflix-space-md: 0.25rem; /* 4px — tight padding */
--netflix-space-lg: 0.375rem; /* 6px — field spacing */
--netflix-space-xl: 0.5rem; /* 8px — icon-text gap */
--netflix-space-2xl: 0.625rem; /* 10px — horizontal field padding */
--netflix-space-3xl: 0.75rem; /* 12px — icon-text in accordion */
}
```
### Radius Scale
```css
:root {
--netflix-radius-sm: 2px; /* 28 elements — badges, small tiles, decorative */
--netflix-radius-md: 4px; /* 4 elements — PRIMARY BUTTONS, form inputs */
--netflix-radius-lg: 8px; /* 11 elements — content cards, thumbnail containers */
--netflix-radius-full: 50px; /* 1 element — specific input field only, NOT buttons */
/* Component-specific */
--wct--local-design--Button-BorderRadius: 0.25rem; /* 4px */
--wct--local-design--Input-BorderRadius: 0.25rem; /* 4px */
--wct--local-design--Select-BorderRadius: 0.25rem; /* 4px */
--wct--local-design--Accordion-HeadlineBorderRadius: 0rem; /* 0px — sharp */
--wct--local-design--Accordion-PanelBorderRadius: 0rem; /* 0px — sharp */
}
```
### Grid & Breakpoints
```css
/* Responsive breakpoints (from media query extraction) */
/* Key tiers for layout decisions: */
:root {
--bp-mobile-sm: 400px; /* small phones */
--bp-mobile: 530px; /* standard mobile */
--bp-tablet-sm: 640px; /* small tablet */
--bp-tablet: 768px; /* standard tablet */
--bp-tablet-lg: 960px; /* large tablet / small desktop */
--bp-desktop: 1024px; /* desktop */
--bp-desktop-lg: 1280px; /* large desktop */
--bp-desktop-xl: 1600px; /* XL desktop */
--bp-hd: 1920px; /* HD / full screen */
--bp-4k: 2560px; /* 4K displays */
}
/* Layout container pattern (layout-container vars are intentionally `initial` — */
/* populated per-breakpoint by the component system) */
--wct--layout-container--width: inherit;
/* Column spacing, row spacing, padding, maxWidth: set via --wct--layout-container--{prop}-{breakpoint} */
```
### Button Layout (computed)
```css
/* Primary hero button */
.btn-primary-hero {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
padding: 12px 24px; /* extracted from button_primary computed style */
height: auto; /* not fixed — grows with content */
gap: normal;
}
/* Small / nav button */
.btn-small {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
padding: 4px 16px; /* extracted from link computed style */
}
```
---
## 5. Page Structure & Layout Patterns
> **Note:** No screenshots provided. All section ordering and layout details are inferred from the LAYOUT DIGEST, component inventory, computed styles, and CTA census. Rows marked **(inferred)** are not visually confirmed.
### 5.1 Section Map
| # | Section | Layout Type | Approx. Height | Key Elements |
|---|---------|-------------|----------------|--------------|
| 1 | **Navigation / Header** | Flex row, space-between | ~70px | Netflix logo (left), language dropdown (right), Sign In button — red CTA `rgb(229,9,20)` |
| 2 | **Hero / Landing Banner** | Flex column, centered | ~600px | Full-bleed background gradient, h1 (56px/900), body subtext (20px/500), email input + CTA row |
| 3 | **Trending Now / Content Row** (inferred) | Horizontal scroll flex | ~300–400px | h2 section heading, thumbnail tiles (radius-lg: 8px), Top 10 numerals (100px/900) |
| 4 | **Feature Highlights** (inferred) | Alternating 2-column | ~300px each | h2 left/right, media image opposite, body copy at 20px |
| 5 | **More Reasons to Join** (inferred) | 2–4 column grid | ~300px | h2 heading, feature cards with icon + text |
| 6 | **FAQ / Accordion** | Single column, full-width | ~400px+ | h2 "Frequently Asked Questions", accordion items (0px radius, 1px separator) |
| 7 | **Footer CTA** (inferred) | Flex column, centered | ~150px | Repeated email input + "Get Started" button, disclaimer text (13px) |
| 8 | **Footer** | Multi-column grid | ~400px (`--ot-footer-space: 160px` + links) | 4-column link grid, language selector dropdown, legal text (14px) |
### 5.2 Layout Patterns
**Hero section:**
- `display: flex; flex-direction: column; align-items: center; text-align: center`
- h1 has `margin-bottom: 16px`; body paragraph has `margin-bottom: 32px`
- Email input + button inline: `display: flex; flex-direction: row; gap: 8px`
- Button: `display: flex; justify-content: center; align-items: center; padding: 12px 24px`
**Content tile rows (inferred from computed badge/thumbnail styles):**
- Horizontal scroll: `display: flex; flex-direction: row; overflow-x: auto`
- Tiles: `border-radius: 8px` (`--netflix-radius-lg`)
- Top 10 numerals: `font-size: 100px` overlapping left edge of tile
**FAQ Accordion:**
- Single column, full-width
- Headline: `background: rgb(45,45,45)`; hover: `rgb(65,65,65)`
- No border-radius on accordion items (`0rem`)
- `1px` gap between headline and panel: `--wct--local-design--Accordion-SpaceBetweenHeadlinePanel: 0.0625rem`
- `8px` gap between accordion items: `--wct--local-design--Accordion-SpaceBetween: 0.5rem`
- Internal padding: `24px` on all sides when expanded
**Footer:**
- Grid: 4 columns on desktop, stacks on mobile
- Footer top spacing: `160px` (`--ot-footer-space`)
- Link text: `14px / 500 / line-height: 21px`
### 5.3 Visual Hierarchy
- **Primary CTA** colour is **always** `rgb(229,9,20)` — confirmed by button census (3 "Get Started" buttons extracted)
- **Hero heading** (56px/900) is the dominant typographic element — nothing else approaches this scale on the landing page
- **Top 10 numerals** at 100px are a visual signature but appear on content rows, not the hero
- **Accordion** on FAQ section uses dark grey surfaces (`rgb(45,45,45)`) slightly lighter than page black — creates subtle separation
- CTA button appears at minimum twice: hero section + pre-footer repeat (confirmed by 3 button instances in computed styles)
- Images/thumbnails are right or left of text in alternating feature rows — Netflix's classic zig-zag pattern (inferred)
- Whitespace between sections is generous — `32px` body margin and `160px` footer space signal deliberate breathing room
### 5.4 Content Patterns
**Pattern A — Hero email-capture row:**
```
[h1: large headline centered]
[p: subtext centered, mb: 32px]
[input: email field] [button: Get Started — red]
```
**Pattern B — Feature zig-zag (inferred):**
```
[image/video — 50%] [text block — 50%] ← alternates left/right per row
h2: feature name (24px/500)
p: description (20px/500)
```
**Pattern C — Accordion FAQ:**
```
[h2: "Frequently Asked Questions" — 24px/500]
[Accordion item — dark grey bg]
[header: question — 24px/400, padding: 24px]
[panel: answer — 24px/400, padding: 24px]
[Accordion item]
...
```
**Pattern D — Content tile row:**
```
[h2: row title — 24px/500]
[scrollable row of tiles: border-radius: 8px]
Tile: thumbnail + optional Top 10 numeral (100px, overlapping)
```
---
## 6. Component Patterns
### 6.1 Primary Button
**Anatomy:** `<button>` → `[optional icon]` + `[label text]`
**Token-to-property mappings:**
| State | Background | Text color | Border | Transition |
|-------|-----------|-----------|--------|-----------|
| Default | `rgb(229,9,20)` | `rgb(255,255,255)` | none | — |
| Hover | `rgb(193,17,25)` | `rgb(255,255,255)` | none | `0.25s cubic-bezier(0.32,0.94,0.6,1)` |
| Focus | `rgb(229,9,20)` | `rgb(255,255,255)` | outline: `2px solid rgb(255,255,255)`, offset `2px` | — |
| Active/Pressed | `rgb(153,22,29)` | `rgba(255,255,255,0.7)` | none | `0s` (instant) |
| Disabled | `rgba(229,9,20,0.4)` | `rgba(255,255,255,0.4)` | none | `0.25s` |
```tsx
// Production-ready Netflix Primary Button
import { ButtonHTMLAttributes, FC } from 'react';
interface NetflixButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
size?: 'large' | 'small';
isLoading?: boolean;
}
const NetflixButton: FC<NetflixButtonProps> = ({
children,
size = 'large',
isLoading = false,
disabled,
style,
...props
}) => {
const isDisabled = disabled || isLoading;
const baseStyles: React.CSSProperties = {
// Layout
display: 'flex',
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
gap: 'var(--wct--local-design--Button-SpaceBetweenIconText)', // 8px
// Sizing
padding: size === 'large' ? '12px 24px' : '4px 16px',
height: 'auto',
width: 'var(--wct--local-design--Button-Width)', // auto
// Typography
fontFamily: '"Netflix Sans", "Helvetica Neue", "Segoe UI", Roboto, Ubuntu, sans-serif',
fontSize: size === 'large' ? '24px' : '14px',
fontWeight: 500,
lineHeight: size === 'large' ? '24px' : '14px',
letterSpacing: 'normal',
textDecoration: 'none',
whiteSpace: 'nowrap',
// Appearance
backgroundColor: isDisabled
? 'var(--wct--local-design--Button-SurfaceDisabled)'
: 'var(--wct--local-design--Button-Surface)',
color: isDisabled
? 'var(--wct--local-design--Button-ForegroundDisabled)'
: 'var(--wct--local-design--Button-Foreground)',
border: `var(--wct--local-design--Button-BorderWidth) solid var(--wct--local-design--Button-Border)`,
borderRadius: 'var(--wct--local-design--Button-BorderRadius)', // 4px
cursor: isDisabled ? 'not-allowed' : 'pointer',
opacity: 1,
// Motion
transition: `
background-color var(--wct--local-design--Button-Duration) var(--wct--local-design--Button-Easing),
border-color var(--wct--local-design--Button-Duration) var(--wct--local-design--Button-Easing),
color var(--wct--local-design--Button-Duration) var(--wct--local-design--Button-Easing)
`,
...style,
};
return (
<button
{...props}
disabled={isDisabled}
aria-disabled={isDisabled}
style={baseStyles}
onMouseEnter={(e) => {
if (!isDisabled) {
e.currentTarget.style.backgroundColor =
'var(--wct--local-design--Button-SurfaceHovered)';
e.currentTarget.style.transitionTimingFunction =
'var(--wct--local-design--Button-EasingHovered)';
}
props.onMouseEnter?.(e);
}}
onMouseLeave={(e) => {
if (!isDisabled) {
e.currentTarget.style.backgroundColor =
'var(--wct--local-design--Button-Surface)';
e.currentTarget.style.transitionTimingFunction =
'var(--wct--local-design--Button-Easing)';
}
props.onMouseLeave?.(e);
}}
onMouseDown={(e) => {
if (!isDisabled) {
e.currentTarget.style.backgroundColor =
'var(--wct--local-design--Button-SurfacePressed)';
e.currentTarget.style.color =
'var(--wct--local-design--Button-ForegroundPressed)';
e.currentTarget.style.transitionDuration = '0s';
}
props.onMouseDown?.(e);
}}
onMouseUp={(e) => {
if (!isDisabled) {
e.currentTarget.style.backgroundColor =
'var(--wct--local-design--Button-SurfaceHovered)';
e.currentTarget.style.color =
'var(--wct--local-design--Button-Foreground)';
e.currentTarget.style.transitionDuration =
'var(--wct--local-design--Button-Duration)';
}
props.onMouseUp?.(e);
}}
>
{isLoading ? (
<span aria-label="Loading" style={{ opacity: 0.7 }}>
{/* Replace with spinner SVG */}
···
</span>
) : (
children
)}
</button>
);
};
export default NetflixButton;
```
---
### 6.2 Form Input (Floating Label)
**Anatomy:** `<div wrapper>` → `<input>` + `<label>` (floating) + `[border chrome]` + `[helper/error message]`
**Token-to-property mappings:**
| State | Border color | Label | Background |
|-------|-------------|-------|-----------|
| Default/Empty | `rgba(128,128,128,0.7)` | `16px rgba(255,255,255,0.7)` | `rgba(22,22,22,0.7)` |
| Focused | outline `2px solid rgb(255,255,255)` | `12px rgba(255,255,255,0.7)` (floated) | `rgba(22,22,22,0.7)` |
| Filled | `rgba(128,128,128,0.7)` | `12px rgba(255,255,255,0.7)` (floated) | `rgba(22,22,22,0.7)` |
| Disabled | `rgba(128,128,128,0.4)` | `rgba(255,255,255,0.4)` | `rgba(22,22,22,0.2)` |
| Error | `rgb(235,57,66)` | `rgba(255,255,255,0.7)` | `rgba(22,22,22,0.7)` |
| Success | `rgb(43,184,113)` | `rgba(255,255,255,0.7)` | `rgba(22,22,22,0.7)` |
| Warning | `rgb(216,157,49)` | `rgba(255,255,255,0.7)` | `rgba(22,22,22,0.7)` |
```tsx
// Netflix floating-label input
interface NetflixInputProps {
id: string;
label: string;
value: string;
onChange: (v: string) => void;
type?: string;
disabled?: boolean;
error?: string;
success?: string;
helperText?: string;
}
const NetflixInput: FC<NetflixInputProps> = ({
id, label, value, onChange, type = 'text',
disabled = false, error, success, helperText,
}) => {
const hasValue = value.length > 0;
const validationState = error ? 'error' : success ? 'success' : 'default';
const borderColor =
validationState === 'error' ? 'var(--wct--local-design--Input-BorderError)' :
validationState === 'success' ? 'var(--wct--local-design--Input-BorderSuccess)' :
disabled ? 'var(--wct--local-design--Input-BorderDisabled)' :
'var(--wct--local-design--Input-Border)';
const messageColor =
validationState === 'error' ? 'var(--wct--local-design--Input-MessageForegroundError)' :
validationState === 'success' ? 'var(--wct--local-design--Input-MessageForegroundSuccess)' :
'var(--wct--local-design--Input-DescriptionForeground)';
return (
<div style={{ position: 'relative', width: '100%' }}>
{/* Chrome / border layer */}
<div
data-wct-form-control-chrome
style={{
position: 'absolute',
inset: 0,
borderRadius: 'var(--wct--local-design--Input-BorderRadius)',
border: `var(--wct--local-design--Input-BorderWidth) solid ${borderColor}`,
backgroundColor: disabled
? 'var(--wct--local-design--Input-SurfaceDisabled)'
: 'var(--wct--local-design--Input-Surface)',
pointerEvents: 'none',
}}
/>
{/* Floating label */}
<label
htmlFor={id}
style={{
position: 'absolute',
left: 'var(--wct--local-design--Input-SpaceHorizontal)',
top: hasValue ? '8px' : '50%',
transform: hasValue ? 'none' : 'translateY(-50%)',
fontFamily: '"Netflix Sans", "Helvetica Neue", "Segoe UI", Roboto, Ubuntu, sans-serif',
fontSize: hasValue
? 'var(--wct--local-design--Input-LabelTextFontSize)' /* 0.75rem / 12px */
: 'var(--wct--local-design--Input-LabelTextEmptyFontSize)', /* 1rem / 16px */
fontWeight: 'var(--wct--local-design--Input-LabelTextFontWeight)',
color: disabled
? 'var(--wct--local-design--Input-LabelForegroundDisabled)'
: 'var(--wct--local-design--Input-LabelForeground)',
transition: 'all var(--netflix-duration-base) var(--netflix-ease-in)',
pointerEvents: 'none',
zIndex: 1,
}}
>
{label}
</label>
{/* Actual input */}
<input
id={id}
type={type}
value={value}
disabled={disabled}
onChange={(e) => onChange(e.target.value)}
style={{
position: 'relative',
zIndex: 1,
display: 'block',
width: '100%',
padding: `24px var(--wct--local-design--Input-SpaceHorizontal) 8px`,
fontFamily: '"Netflix Sans", "Helvetica Neue", "Segoe UI", Roboto, Ubuntu, sans-serif',
fontSize: 'var(--wct--local-design--Input-TextFontSize)',
fontWeight: 'var(--wct--local-design--Input-TextFontWeight)',
lineHeight: 'var(--wct--local-design--Input-TextLineHeight)',
color: disabled
? 'var(--wct--local-design--Input-ForegroundDisabled)'
: 'var(--wct--local-design--Input-Foreground)',
background: 'transparent',
border: 'none',
outline: 'none',
borderRadius: 'var(--wct--local-design--Input-BorderRadius)',
boxSizing: 'border-box',
}}
/>
{/* Validation / helper message */}
{(error || success || helperText) && (
<p
data-wct-form-control-validation
style={{
marginTop: 'var(--wct--local-design--Input-SpaceBetweenFieldMessage)',
fontFamily: '"Netflix Sans", "Helvetica Neue", "Segoe UI", Roboto, Ubuntu, sans-serif',
fontSize: 'var(--wct--local-design--Input-MessageFontSize)',
fontWeight: 'var(--wct--local-design--Input-MessageFontWeight)',
color: messageColor,
lineHeight: 'normal',
margin: 0,
paddingTop: 'var(--wct--local-design--Input-SpaceBetweenFieldMessage)',
}}
>
{error || success || helperText}
</p>
)}
</div>
);
};
```
---
### 6.3 Accordion (FAQ)
**Anatomy:** `<div container>` → `[accordion item: header button + panel]`
**Token-to-property mappings:**
| State | Headline bg | Headline text | Transition |
|-------|------------|--------------|-----------|
| Collapsed | `rgb(45,45,45)` | `rgb(255,255,255)` | — |
| Hover | `rgb(65,65,65)` | `rgb(255,255,255)` | `250ms cubic-bezier(0.32,0.94,0.6,1)` |
| Expanded | `rgb(45,45,45)` | `rgb(255,255,255)` | `250ms cubic-bezier(0.4,0,0.68,0.06)` |
| Focus | outline `2px solid rgb(255,255,255)`, offset `2px` | — | — |
```tsx
// Netflix FAQ Accordion item
import { useState, FC } from 'react';
interface AccordionItemProps {
question: string;
answer: string;
}
const NetflixAccordionItem: FC<AccordionItemProps> = ({ question, answer }) => {
const [isOpen, setIsOpen] = useState(false);
return (
<div
style={{
marginBottom: 'var(--wct--local-design--Accordion-SpaceBetween)', /* 8px */
}}
>
{/* Headline / trigger */}
<button
onClick={() => setIsOpen(!isOpen)}
aria-expanded={isOpen}
style={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
width: '100%',
padding: 'var(--wct--local-design--Accordion-HeadlineSpace)', /* 24px */
gap: 'var(--wct--local-design--Accordion-HeadlineSpaceBetweenIconText)', /* 12px */
backgroundColor: 'var(--wct--local-design--Accordion-HeadlineSurface)', /* rgb(45,45,45) */
color: 'var(--wct--local-design--Accordion-HeadlineForeground)',
border: 'none',
borderRadius: isOpen
? 'var(--wct--local-design--Accordion-HeadlineBorderRadiusExpanded)' /* top corners only: 0 */
: 'var(--wct--local-design--Accordion-HeadlineBorderRadius)', /* 0 */
cursor: 'pointer',
fontFamily: '"Netflix Sans", "Helvetica Neue", "Segoe UI", Roboto, Ubuntu, sans-serif',
fontSize: 'var(--wct--local-design--Accordion-HeadlineTextFontSize)', /* 1.5rem */
fontWeight: 'var(--wct--local-design--Accordion-HeadlineTextFontWeight)', /* 400 */
textAlign: 'left',
transition: `background-color var(--wct--local-design--Accordion-HeadlineDuration) var(--wct--local-design--Accordion-HeadlineEasing)`,
}}
onMouseEnter={(e) => {
(e.currentTarget as HTMLElement).style.backgroundColor =
'var(--wct--local-design--Accordion-HeadlineSurfaceHovered)';
(e.currentTarget as HTMLElement).style.transitionTimingFunction =
'var(--wct--local-design--Accordion-HeadlineEasingHovered)';
}}
onMouseLeave={(e) => {
(e.currentTarget as HTMLElement).style.backgroundColor =
'var(--wct--local-design--Accordion-HeadlineSurface)';
(e.currentTarget as HTMLElement).style.transitionTimingFunction =
'var(--wct--local-design--Accordion-HeadlineEasing)';
}}
>
<span>{question}</span>
{/* Icon rotates -45deg when closed → 0deg when open */}
<span
style={{
display: 'inline-block',
transform: isOpen ? 'rotate(0deg)' : 'rotate(-45deg)',
transition: `transform var(--wct--local-design--Accordion-HeadlineIconDuration) var(--wct--local-design--Accordion-HeadlineIconEasing)`,
fontSize: '2rem',
lineHeight: 1,
}}
aria-hidden
>
✕
</span>
</button>
{/* Panel */}
{isOpen && (
<div
style={{
backgroundColor: 'var(--wct--local-design--Accordion-PanelSurface)', /* rgb(45,45,45) */
color: 'var(--wct--local-design--Accordion-PanelForeground)',
padding: `var(--wct--local-design--Accordion-PanelSpaceExpanded)`, /* 24px */
borderRadius: 'var(--wct--local-design--Accordion-PanelBorderRadiusExpanded)',
fontFamily: '"Netflix Sans", "Helvetica Neue", "Segoe UI", Roboto, Ubuntu, sans-serif',
fontSize: 'var(--wct--local-design--Accordion-PanelTextFontSize)', /* 1.5rem */
fontWeight: 'var(--wct--local-design--Accordion-PanelTextFontWeight)', /* 400 */
borderTop: `var(--wct--local-design--Accordion-SpaceBetweenHeadlinePanel) solid rgba(128,128,128,0.3)`,
}}
>
{answer}
</div>
)}
</div>
);
};
```
---
### 6.4 Badge / Content Label
**Anatomy:** `<span>` with `box-shadow` for subtle elevation
**Token-to-property mappings:**
| State | Background | Shadow | Radius |
|-------|-----------|--------|--------|
| Default | contextual (tile bg) | `rgb(128,128,128) 0px 0px 5px 0px` | `2px` |
| Hover | — | unchanged | unchanged |
```tsx
const NetflixBadge: FC<{ children: React.ReactNode }> = ({ children }) => (
<span
style={{
display: 'inline-block',
borderRadius: 'var(--netflix-radius-sm)', /* 2px */
boxShadow: 'rgb(128, 128, 128) 0px 0px 5px 0px',
fontFamily: '"Netflix Sans", "Helvetica Neue", "Segoe UI", Roboto, Ubuntu, sans-serif',
fontSize: '13px',
fontWeight: 400,
color: 'var(--netflix-text-white)',
padding: '2px 6px',
}}
>
{children}
</span>
);
```
---
### 6.5 Language Dropdown (Select)
**Anatomy:** `<div wrapper>` → `<select>` + `[chrome border]` + `[label]`
| State | Border | Surface | Text |
|-------|--------|---------|------|
| Default | `rgba(128,128,128,0.7)` | `rgba(22,22,22,0.7)` | `rgb(255,255,255)` |
| Focus | outline `2px solid rgb(255,255,255)` on chrome | same | same |
| Disabled | `rgba(128,128,128,0.4)` | `rgba(22,22,22,0.02)` | `rgba(255,255,255,0.4)` |
| Error | `rgb(235,57,66)` | same | same |
```tsx
const NetflixSelect: FC<{ options: string[]; disabled?: boolean; error?: string }> = ({
options,
disabled = false,
error,
}) => (
<div
data-wct-form-control-chrome
style={{
position: 'relative',
display: 'inline-block',
border: `var(--wct--local-design--Select-BorderWidth) solid ${
error ? 'var(--wct--local-design--Select-BorderError)' :
disabled ? 'var(--wct--local-design--Select-BorderDisabled)' :
'var(--wct--local-design--Select-Border)'
}`,
borderRadius: 'var(--wct--local-design--Select-BorderRadius)',
backgroundColor: disabled
? 'var(--wct--local-design--Select-SurfaceDisabled)'
: 'var(--wct--local-design--Select-Surface)',
}}
>
<select
disabled={disabled}
style={{
appearance: 'none',
background: 'transparent',
border: 'none',
outline: 'none',
padding: `var(--wct--local-design--Select-SpaceVerticalEmpty) var(--wct--local-design--Select-SpaceHorizontal)`,
fontFamily: '"Netflix Sans", "Helvetica Neue", "Segoe UI", Roboto, Ubuntu, sans-serif',
fontSize: 'var(--wct--local-design--Select-TextFontSize)',
fontWeight: 'var(--wct--local-design--Select-TextFontWeight)',
lineHeight: 'var(--wct--local-design--Select-TextLineHeight)',
color: disabled
? 'var(--wct--local-design--Select-ForegroundDisabled)'
: 'var(--wct--local-design--Select-Foreground)',
paddingRight: '2rem', /* space for dropdown arrow */
width: 'var(--wct--local-design--Select-Width)',
cursor: disabled ? 'not-allowed' : 'pointer',
}}
>
{options.map((o) => <option key={o} value={o}>{o}</option>)}
</select>
</div>
);
```
---
## 7. Elevation & Depth
```css
:root {
/* Shadows — extracted from computed styles */
--shadow-badge: rgb(128, 128, 128) 0px 0px 5px 0px;
/* Usage: badge/label overlays on content tiles */
--shadow-none: none;
/* Usage: buttons, inputs, accordion panels — no shadow on interactive form elements */
/* Focus ring (elevation via outline, not shadow) */
--focus-ring: 0.125rem solid rgb(255, 255, 255);
/* equivalent to: outline: var(--wct--focus-ring--width) var(--wct--focus-ring--style) var(--wct--focus-ring--color) */
--focus-ring-offset: 0.125rem;
/* Usage: ALL keyboard-focusable elements */
/* Z-index scale (inferred from page structure) */
--z-content: 0; /* default page content */
--z-badge: 1; /* top-10 numerals and tile overlays */
--z-dropdown: 10; /* language selector open state */
--z-nav: 100; /* sticky navigation bar */
--z-modal: 1000; /* dialogs and overlays */
--z-toast: 2000; /* notification toasts */
}
```
**Layering principles:**
- Netflix UI is primarily **flat** — depth is achieved through colour contrast (dark bg → darker surface), not drop shadows
- Shadows appear **only** on tile badges and overlaid labels
- **No box-shadow** on buttons, inputs, or accordion — these use background colour to signal state
- Focus rings use `outline` (not `box-shadow`) to ensure they are visible over any background
---
## 8. Motion
```css
:root {
/* Duration tokens */
--netflix-duration-fast: 0.2s; /* extracted: high confidence — button hover micro-interactions */
--netflix-duration-base: 0.25s; /* extracted: high confidence — standard UI transitions (buttons, accordion) */
--netflix-duration-slow: 0.4s; /* extracted: high confidence — larger layout transitions */
/* Easing tokens */
--netflix-ease-default: ease; /* extracted: high confidence — 78 elements */
--netflix-ease-in: cubic-bezier(0.4, 0, 0.68, 0.06);
/* Usage: element leaving screen, button default state transition */
/* Corresponds to: --wct--local-design--Button-Easing, --wct--local-design--Accordion-HeadlineEasing */
--netflix-ease-out: cubic-bezier(0.32, 0.94, 0.6, 1);
/* Usage: element entering screen, hover state transition (fast in, satisfying deceleration) */
/* Corresponds to: --wct--local-design--Button-EasingHovered, --wct--local-design--Accordion-HeadlineIconEasing */
/* Component-specific motion */
--wct--local-design--Button-Duration: 250ms;
--wct--local-design--Button-DurationPressed: 0; /* INSTANT on press — intentional */
--wct--local-design--Button-Easing: cubic-bezier(0.4, 0, 0.68, 0.06);
--wct--local-design--Button-EasingHovered: cubic-bezier(0.32, 0.94, 0.6, 1);
--wct--local-design--Button-EasingPressed: cubic-bezier(0.4, 0, 0.68, 0.06);
--wct--local-design--Accordion-HeadlineDuration: 250ms;
--wct--local-design--Accordion-HeadlineEasing: cubic-bezier(0.4, 0, 0.68, 0.06);
--wct--local-design--Accordion-HeadlineIconDuration: 250ms;
--wct--local-design--Accordion-HeadlineIconEasing: cubic-bezier(0.32, 0.94, 0.6, 1);
--wct--local-design--Accordion-HeadlineDurationHovered: var(--wct--local-design--Accordion-HeadlineDuration);
--wct--local-design--Accordion-HeadlineEasingHovered: cubic-bezier(0.32, 0.94, 0.6, 1);
--wct--local-design--Accordion-PanelDuration: 250ms;
--wct--local-design--Accordion-PanelEasing: cubic-bezier(0.32, 0.94, 0.6, 1);
/* Loading skeleton animation */
/* @keyframes loading: 0% rgb(35,35,35) → 70% rgb(65,65,65) → 90% rgb(35,35,35) */
/* Applied to: skeleton/placeholder content tiles while data loads */
}
```
**When to animate:**
- Button background on hover/focus: `0.25s` with `ease-out` (`cubic-bezier(0.32,0.94,0.6,1)`)
- Button background on press/active: **instant** (`0s` transition-duration) — feels physically snappy
- Accordion headline background: `250ms ease-in`
- Accordion icon rotation: `250ms ease-out`
- Accordion panel expand: `250ms ease-out`
- Loading skeleton shimmer: continuous loop — `0% → 70% → 90%` background colour pulse
**When NOT to animate:**
- Do NOT animate layout shifts or width/height changes unless panel expand/collapse
- Do NOT add entrance animations to static text content
- Do NOT animate colour changes on disabled states — `transition-duration` set to `var(--netflix-duration-base)` but visually irrelevant since no interaction occurs
---
## 9. Anti-Patterns & Constraints
1. **NEVER use a generic font stack without Netflix Sans first → Why it fails → What to do instead.**
AI agents default to `Inter`, `system-ui`, or `Arial` when no font is specified. Netflix's typographic identity depends entirely on the proprietary `Netflix Sans` variable font. Without it, headings lose weight range (100–900), and the distinctive kerning vanishes. **Do this instead:** Always declare `fontFamily: '"Netflix Sans", "Helvetica Neue", "Segoe UI", Roboto, Ubuntu, sans-serif'` — the full stack with proper fallbacks.
2. **NEVER hardcode red hex values as `#e50914` or `#E50914` directly in component styles → Why it fails → What to do instead.**
Hardcoded values break when Netflix A/B tests button colours or adjusts brand colour globally. Additionally, hardcoded hex bypasses the three-state red system (default/hover/pressed). An AI agent seeing "red button" will pick one hex and stop there, missing the `rgb(193,17,25)` hover and `rgb(153,22,29)` pressed states. **Do this instead:** Use `var(--wct--local-design--Button-Surface)` for default, `var(--wct--local-design--Button-SurfaceHovered)` for hover, `var(--wct--local-design--Button-SurfacePressed)` for active.
3. **NEVER use `border-radius` values larger than `8px` on primary buttons → Why it fails → What to do instead.**
AI agents trained on generic design systems often produce pill buttons (`border-radius: 50px` or `9999px`) because they're visually common. Netflix buttons are strictly `4px` radius (`--wct--local-design--Button-BorderRadius: 0.25rem`). Pill-shaped buttons break the geometric language and look alien on the Netflix homepage. **Do this instead:** Use `var(--wct--local-design--Button-BorderRadius)` for every button. Reserve `--netflix-radius-full: 50px` for the one specific input field that uses it.
4. **NEVER omit the active/pressed state with `transition-duration: 0` → Why it fails → What to do instead.**
AI agents model hover and focus states but routinely skip the "pressed" (`:active`) state. Netflix's design system explicitly sets `--wct--local-design--Button-DurationPressed: 0` — the background colour change to `rgb(153,22,29)` is instantaneous. Omitting this makes buttons feel sluggish and wrong. **Do this instead:** Apply `onMouseDown` handler that sets `backgroundColor` to `var(--wct--local-design--Button-SurfacePressed)` and `transitionDuration` to `0s`.
5. **NEVER use a light or white background for any content section → Why it fails → What to do instead.**
AI agents filling in "blank" sections default to white or off-white backgrounds. Netflix is a pure dark-mode product — `rgb(0,0,0)` page background, `rgba(22,22,22,0.7)` form surfaces, `rgb(45,45,45)` accordion surfaces. Any light surface would destroy the cinematic immersive experience. **Do this instead:** Default every new section to `background-color: rgb(0,0,0)` unless a specific token (`--netflix-bg-surface`, `--netflix-accordion-surface`) is more appropriate.
6. **NEVER use `rgb(229,9,20)` for decorative elements, text colour, or dividers → Why it fails → What to do instead.**
Red in the Netflix system is exclusively reserved for primary call-to-action button backgrounds. AI agents, seeing the dominant brand colour, will apply it to borders, link text, hover underlines, or section dividers. This dilutes the CTA signal — red means "click this" and nothing else. **Do this instead:** Use `rgb(255,255,255)` for text, `rgba(128,128,128,0.7)` for borders, and `rgb(45,45,45)` for surface dividers.
7. **NEVER use arbitrary spacing values or substitute a standard 8px grid → Why it fails → What to do instead.**
Netflix uses precise, non-8px-aligned spacing values: `0.375rem` (6px) for field gaps, `0.625rem` (10px) for horizontal field padding, `0.0625rem` (1px) for the accordion separator. An AI agent normalising these to the nearest 8px multiple (`8px`, `8px`, `0px`) destroys the tight micro-spacing that makes form components feel refined. **Do this instead:** Always reference the exact extracted token. Never round to a "cleaner" value.
8. **NEVER remove or simplify the focus ring → Why it fails → What to do instead.**
AI agents often drop focus styles when they "look bad" or clash with the dark design. Netflix's focus ring is `2px solid rgb(255,255,255)` with `2px offset` — white on black, maximum visibility. The system uses `:focus-visible` to suppress it for mouse users and show it for keyboard users via `var(--wct--focus-ring--override-on/off)`. Removing this violates WCAG 2.4.11 and breaks keyboard navigation. **Do this instead:** Use `outline: var(--wct--focus-ring--width) var(--wct--focus-ring--style) var(--wct--focus-ring--color); outline-offset: var(--wct--focus-ring--offset)` on all interactive elements.
9. **NEVER construct dynamic Tailwind class names with string interpolation → Why it fails → What to do instead.**
Patterns like `` `bg-[${color}]` `` or `` `text-${size}` `` cause Tailwind's JIT scanner to miss the class, resulting in unstyled elements in production. **Do this instead:** For dynamic values, use inline CSS custom property references (`style={{ backgroundColor: 'var(--netflix-accent)' }}`) or use complete, static class names that can be statically analysed.
10. **NEVER use `!important` to override Netflix's component token cascade → Why it fails → What to do instead.**
The `--wct--local-design--*` token system uses CSS custom property inheritance for component-level overrides. Adding `!important` breaks the cascade in ways that are difficult to debug and will cause previously functional states (disabled, hover) to stop updating. **Do this instead:** Override tokens at the appropriate scope — set `--wct--local-design--Button-Surface: your-value` on the parent container to scope changes correctly.
11. **NEVER use `position: absolute` to achieve column layouts or section stacking → Why it fails → What to do instead.**
AI agents sometimes use absolute positioning for complex multi-column layouts. Netflix's layout system uses `display: flex` with `flexDirection: row/column` and responsive `--wct--layout-container` tokens. Absolute positioning breaks the responsive reflow at the numerous breakpoints (98px through 2560px). **Do this instead:** Use `display: flex` or `display: grid` with gap values from the spacing scale, and respond to breakpoints via media queries.
---
## 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 (95) */
--wct--layout-container--width: inherit;
--wct--local-design--Select-Border: rgba(128, 128, 128, 0.7);
--wct--local-design--Select-BorderDisabled: rgba(128, 128, 128, 0.4);
--wct--local-design--Select-BorderError: rgb(235, 57, 66);
--wct--local-design--Select-BorderSuccess: rgb(43, 184, 113);
--wct--local-design--Select-BorderWarning: rgb(216, 157, 49);
--wct--local-design--Button-ForegroundPressed: rgba(255, 255, 255, 0.7);
--wct--focus-ring--color: rgb(255, 255, 255);
--wct--local-design--Button-ForegroundDisabled: rgba(255, 255, 255, 0.4);
--wct--local-design--Select-Surface: rgba(22, 22, 22, 0.7);
--wct--local-design--Select-SurfaceDisabled: rgba(22, 22, 22, 0.02);
--wct--focus-ring--color-default: #a9a9a9;
--wct--local-design--Button-BorderDisabled: rgba(0, 0, 0, 0);
--wct--local-design--Button-Surface: rgb(229, 9, 20);
--wct--local-design--Button-SurfaceDisabled: rgba(229, 9, 20, 0.4);
--wct--local-design--Button-SurfaceHovered: rgb(193, 17, 25);
--wct--local-design--Button-SurfacePressed: rgb(153, 22, 29);
--wct--local-design--Input-SurfaceDisabled: rgba(22, 22, 22, 0.2);
--wct--local-design--Accordion-HeadlineSurface: rgb(45,45,45);
--wct--local-design--Accordion-HeadlineSurfaceHovered: rgb(65,65,65);
--brand-primary-cta: rgb(229, 9, 20); /* Primary CTA background, dominant on 3 buttons — e.g. "Get Started" /* mined from computed styles */ */
--netflix-accent: rgb(229, 9, 20);
--netflix-accent-warm: rgb(193, 17, 25);
--netflix-accent-pressed: rgb(153, 22, 29);
--netflix-accent-disabled: rgba(229, 9, 20, 0.4);
--netflix-bg-surface: rgba(22, 22, 22, 0.7);
--netflix-accordion-surface: rgb(45, 45, 45);
--netflix-accordion-surface-hover: rgb(65, 65, 65);
--netflix-text-white: rgb(255, 255, 255);
--netflix-text-muted: rgba(255, 255, 255, 0.7);
--netflix-text-disabled: rgba(255, 255, 255, 0.4);
--netflix-success: rgb(43, 184, 113);
--netflix-warning: rgb(216, 157, 49);
--netflix-error: rgb(235, 57, 66);
--netflix-border: rgba(128, 128, 128, 0.7);
--netflix-border-focus: rgb(255, 255, 255);
--color-red-500: rgb(229, 9, 20);
--color-red-600: rgb(193, 17, 25);
--color-red-700: rgb(153, 22, 29);
--color-dark-900: rgb(0, 0, 0);
--color-dark-800: rgb(22, 22, 22);
--color-dark-700: rgb(35, 35, 35);
--color-dark-600: rgb(45, 45, 45);
--color-dark-500: rgb(65, 65, 65);
--color-white-100: rgb(255, 255, 255);
--color-white-70: rgba(255, 255, 255, 0.7);
--color-white-40: rgba(255, 255, 255, 0.4);
--color-grey-50: rgba(128, 128, 128, 0.7);
--color-grey-30: rgba(128, 128, 128, 0.4);
--color-grey-focus: #a9a9a9;
--color-green-400: rgb(43, 184, 113);
--color-yellow-400: rgb(216, 157, 49);
--color-red-error: rgb(235, 57, 66);
--netflix-bg-app: rgb(0, 0, 0);
--netflix-bg-surface-disabled: rgba(22, 22, 22, 0.2);
--netflix-bg-skeleton-base: rgb(35, 35, 35);
--netflix-bg-skeleton-shimmer: rgb(65, 65, 65);
--netflix-text-pressed: rgba(255, 255, 255, 0.7);
--netflix-border-disabled: rgba(128, 128, 128, 0.4);
--netflix-border-transparent: rgba(0, 0, 0, 0);
--netflix-accordion-foreground: rgb(255, 255, 255);
--wct--local-design--Button-Foreground: rgb(255, 255, 255);
--wct--local-design--Button-Border: rgba(0, 0, 0, 0);
--wct--local-design--Button-BorderHovered: rgba(0, 0, 0, 0);
--wct--local-design--Button-BorderPressed: rgba(0, 0, 0, 0);
--wct--local-design--Button-BorderWidth: 0.0625rem;
--wct--local-design--Select-Foreground: rgb(255, 255, 255);
--wct--local-design--Select-ForegroundDisabled: rgba(255, 255, 255, 0.4);
--wct--local-design--Select-LabelForeground: rgba(255, 255, 255, 0.7);
--wct--local-design--Select-LabelForegroundDisabled: rgba(255, 255, 255, 0.4);
--wct--local-design--Select-DescriptionForeground: rgba(255, 255, 255, 0.7);
--wct--local-design--Select-BorderWidth: 0.0625rem;
--wct--local-design--Select-MessageForegroundError: rgb(235, 57, 66);
--wct--local-design--Select-MessageForegroundSuccess: rgb(43, 184, 113);
--wct--local-design--Select-MessageForegroundWarning: rgb(216, 157, 49);
--wct--local-design--Input-Surface: rgba(22, 22, 22, 0.7);
--wct--local-design--Input-Foreground: rgb(255, 255, 255);
--wct--local-design--Input-ForegroundDisabled: rgba(255, 255, 255, 0.4);
--wct--local-design--Input-LabelForeground: rgba(255, 255, 255, 0.7);
--wct--local-design--Input-LabelForegroundDisabled: rgba(255, 255, 255, 0.4);
--wct--local-design--Input-DescriptionForeground: rgba(255, 255, 255, 0.7);
--wct--local-design--Input-Border: rgba(128, 128, 128, 0.7);
--wct--local-design--Input-BorderDisabled: rgba(128, 128, 128, 0.4);
--wct--local-design--Input-BorderError: rgb(235, 57, 66);
--wct--local-design--Input-BorderSuccess: rgb(43, 184, 113);
--wct--local-design--Input-BorderWarning: rgb(216, 157, 49);
--wct--local-design--Input-BorderWidth: 0.0625rem;
--wct--local-design--Input-MessageForegroundError: rgb(235, 57, 66);
--wct--local-design--Input-MessageForegroundSuccess: rgb(43, 184, 113);
--wct--local-design--Input-MessageForegroundWarning: rgb(216, 157, 49);
--brand-primary-cta: rgb(229, 9, 20);
--type-input-label-filled: {
font-family: "Netflix Sans", "Helvetica Neue", "Segoe UI", Roboto, Ubuntu, sans-serif;
--wct--local-design--Accordion-PanelSurface: rgb(45, 45, 45);
--wct--local-design--Accordion-HeadlineForeground: rgb(255, 255, 255);
--wct--local-design--Accordion-PanelForeground: rgb(255, 255, 255);
/* Typography (42) */
--wct--local-design--Button-TextFontFamily: unset;
--wct--local-design--Select-DescriptionFontSize: 0.8125rem;
--wct--local-design--Accordion-HeadlineTextFontWeight: 400;
--wct--local-design--Select-LabelTextFontSize: 0.75rem;
--wct--local-design--Button-TextFontSize: 0.875rem;
--wct--local-design--Input-TextFontSize: 1rem */
font-weight: 400;
--wct--local-design--Accordion-HeadlineTextFontSize: 1.5rem */
font-weight: 400;
--wct--local-design--Select-TextLineHeight: 1.25rem;
--wct--local-design--Button-TextFontWeight: 500;
--wct--local-design--Button-Easing: cubic-bezier(0.4,0,0.68,0.06);
--wct--local-design--Button-EasingHovered: cubic-bezier(0.32,0.94,0.6,1);
--wct--local-design--Input-LabelTextLineHeight: 1.5;
--wct--input--date-text: var(--wct--local-design--Input-Foreground);
--wct--input--date-calendar-icon: url("data:image/svg+xml; <0.4KB elided>");
--font-size-xs: 13px; /* 1 element — e.g. p "This page is protect" /* mined from computed styles */ */
--font-size-sm: 14px; /* 44 elements — e.g. p "Netflix Germany", a "Sign In", a "FAQ" /* mined from computed styles */ */
--font-size-md: 16px; /* 40 elements — e.g. h3 "Ready to watch? Ente", h3 "Ready to watch? Ente", p "Get our most afforda" /* mined from computed styles */ */
--font-size-lg: 20px; /* 2 elements — e.g. h3 "The Netflix you love", p "Starts at €4.99. Can" /* mined from computed styles */ */
--font-size-xl: 24px; /* 28 elements — e.g. h2 "Trending Now", h2 "More Reasons to Join", h2 "Frequently Asked Que" /* mined from computed styles */ */
--font-size-2xl: 56px; /* 1 element — e.g. h1 "Unlimited movies, TV" /* mined from computed styles */ */
--font-size-3xl: 100px; /* 20 elements — e.g. span "11", span "11", span "22" /* mined from computed styles */ */
--font-weight-semibold: 900; /* 1 element — e.g. h1 "Unlimited movies, TV" /* mined from computed styles */ */
--line-height-tight: 21px; /* 42 elements — e.g. a "FAQ", a "Cancel Membership", a "Help Center" /* mined from computed styles */ */
--line-height-loose: 70px; /* 1 element — e.g. h1 "Unlimited movies, TV" /* mined from computed styles */ */
--font-family-primary: "Netflix Sans", "Helvetica Neue", "Segoe UI", Roboto, Ubuntu, sans-serif;
--font-family-arabic: "NKufi", "Netflix Sans", sans-serif;
--font-family-thai: "GraphikTH", "Netflix Sans", sans-serif;
--font-family-ja: "Netflix Sans JA", "Netflix Sans", sans-serif;
--wct--local-design--Accordion-PanelTextFontSize: 1.5rem */
font-weight: 400;
--wct--local-design--Input-LabelTextFontSize: 0.75rem */
font-weight: 400;
--wct--local-design--Input-LabelTextEmptyFontSize: 1rem */
font-weight: 400;
--wct--local-design--Input-DescriptionFontSize: 0.8125rem */
font-weight: 400;
--netflix-font-size-xs: 13px;
--netflix-font-size-sm: 14px;
--netflix-font-size-md: 16px;
--netflix-font-size-lg: 20px;
--netflix-font-size-xl: 24px;
--netflix-font-size-2xl: 56px;
--netflix-font-size-3xl: 100px;
--netflix-font-weight-semibold: 900;
--netflix-line-height-tight: 21px;
--netflix-line-height-loose: 70px;
/* Spacing (51) */
--wct--layout-item--padding: initial;
--wct--local-design--Button-BorderWidth: 0.0625rem;
--wct--local-design--Button-SpaceVertical: 0.25rem;
--wct--local-design--Button-SpaceBetweenIconText: 0.5rem;
--wct--local-design--Select-SpaceVerticalEmpty: 0.375rem;
--wct--local-design--Select-SpaceHorizontal: 0.625rem;
--wct--local-design--Select-SpaceVertical: 0rem;
--wct--focus-ring--width: 0.125rem;
--wct--local-design--Button-Height: 2rem;
--wct--local-design--Button-IconHeight: 1rem;
--wct--local-design--Accordion-HeadlineSpaceBetweenIconText: 0.75rem;
--wct--local-design--Accordion-HeadlineSpace: 1.5rem;
--wct--local-design--Accordion-HeadlineSpaceExpanded: var(--wct--local-design--Accordion-HeadlineSpace);
--wct--local-design--Accordion-PanelSpace: 0rem var(--wct--local-design--Accordion-PanelSpaceExpanded);
--ot-footer-space: 160px;
--wct--focus-ring--offset: 0.125rem;
--wct--local-design--Select-SpaceBetweenFieldDescription: 0.375rem;
--wct--local-design--Select-SpaceBetweenFieldMessage: 0.375rem;
--wct--local-design--Select-MessageSpaceBetweenIconContent: 0.25rem;
--wct--local-design--Select-SpaceBetweenIconContent: 0.5rem;
--wct--local-design--Button-SpaceHorizontal: 1rem;
--wct--local-design--Button-IconWidth: 1rem;
--wct--local-design--Input-SpaceHorizontal: 1rem;
--wct--local-design--Input-SpaceVertical: 0.25rem;
--wct--local-design--Input-SpaceVerticalEmpty: 0.75rem;
--wct--local-design--Input-SpaceBetweenIconContent: 0.5rem;
--wct--local-design--Input-SpaceBetweenFieldDescription: 0.375rem;
--wct--local-design--Input-SpaceBetweenFieldMessage: 0.375rem;
--wct--local-design--Accordion-PanelSpaceExpanded: 1.5rem;
--wct--local-design--Accordion-SpaceBetween: 0.5rem;
--wct--local-design--Accordion-SpaceBetweenHeadlinePanel: 0.0625rem;
--space-hero-heading-bottom: 16px;
--space-body-bottom: 32px;
--netflix-space-xs: 0.0625rem;
--netflix-space-sm: 0.125rem;
--netflix-space-md: 0.25rem;
--netflix-space-lg: 0.375rem;
--netflix-space-xl: 0.5rem;
--netflix-space-2xl: 0.625rem;
--netflix-space-3xl: 0.75rem;
--bp-mobile-sm: 400px;
--bp-mobile: 530px;
--bp-tablet-sm: 640px;
--bp-tablet: 768px;
--bp-tablet-lg: 960px;
--bp-desktop: 1024px;
--bp-desktop-lg: 1280px;
--bp-desktop-xl: 1600px;
--bp-hd: 1920px;
--bp-4k: 2560px;
--focus-ring-offset: 0.125rem;
/* Radius (15) */
--wct--local-design--Button-BorderRadius: 0.25rem;
--wct--local-design--Accordion-HeadlineBorderRadius: 0rem;
--wct--local-design--Accordion-HeadlineBorderRadiusExpanded: var(--wct--local-design--Accordion-HeadlineBorderRadius) var(--wct--local-design--Accordion-HeadlineBorderRadius) 0rem 0rem;
--wct--local-design--Accordion-PanelBorderRadiusExpanded: 0rem 0rem var(--wct--local-design--Accordion-PanelBorderRadius) var(--wct--local-design--Accordion-PanelBorderRadius);
--radius-sm: 2px; /* 28 elements — e.g. a "Check out some of ou", a "Questions? Contact u", a .default-ltr-iqcdef-cache-348dfw "FAQ" /* mined from computed styles */ */
--radius-md: 4px; /* 4 elements — e.g. button .e136yimv2 "Get Started", button .e136yimv2 "Learn More", button .e136yimv2 "Get Started" /* mined from computed styles */ */
--radius-lg: 8px; /* 11 elements — e.g. button .default-ltr-iqcdef-cache-1it3med "Berlin and the Lady ", button .default-ltr-iqcdef-cache-1it3med "Apex22", button .default-ltr-iqcdef-cache-1it3med "ONE PIECE33" /* mined from computed styles */ */
--radius-full: 50px; /* 1 element — e.g. input /* mined from computed styles */ */
--netflix-radius-sm: 2px;
--netflix-radius-md: 4px;
--netflix-radius-lg: 8px;
--wct--local-design--Select-BorderRadius: 0.25rem;
--wct--local-design--Input-BorderRadius: 0.25rem;
--netflix-radius-full: 50px;
--wct--local-design--Accordion-PanelBorderRadius: 0rem;
/* Effects (12) */
--wct--layout-container--flexDirection-xs: initial;
--wct--local-design--Button-Width: auto;
--wct--focus-ring--style: solid;
--wct--local-design--Button-ForegroundHovered: var(--wct--local-design--Button-Foreground);
--wct--local-design--Button-Duration: 250ms;
--wct--local-design--Button-DurationDisabled: var(--wct--local-design--Button-Duration);
--wct--local-design--Button-DurationPressed: 0;
--wct--local-design--Button-EasingDisabled: var(--wct--local-design--Button-Easing);
--wct--local-design--Accordion-HeadlineDurationHovered: var(--wct--local-design--Accordion-HeadlineDuration);
--wct--accordion--icon-rotation: -45deg;
--shadow-badge: rgb(128, 128, 128) 0px 0px 5px 0px;
--shadow-none: none;
/* Motion (7) */
----motion-animation-1o3pzgb-autofillStart: @keyframes animation-1o3pzgb-autofillStart {
}; /* @keyframes animation-1o3pzgb-autofillStart */
----motion-animation-und0r9-autofillEnd: @keyframes animation-und0r9-autofillEnd {
}; /* @keyframes animation-und0r9-autofillEnd */
----motion-loading: @keyframes loading {
0% { background-color: rgb(35, 35, 35); }
40% { backgr… <0.2KB elided>; /* @keyframes loading */
--duration-fast: 0.2s; /* 10 elements — e.g. button, button, button /* mined from computed styles */ */
--duration-base: 0.25s; /* 4 elements — e.g. button, button, button /* mined from computed styles */ */
--duration-slow: 0.4s; /* 2 elements — e.g. button, div /* mined from computed styles */ */
--ease-default: ease; /* 78 elements — e.g. button, button, button /* mined from computed styles */ */
```
## Appendix B: Token Source Metadata
```
tokenSource: extracted-css-vars
site: netflix.com
extractionDate: [see extraction run metadata]
confidence: high
totalCSSCustomProperties: 262
curatedTokensMapped: 38
fontSource: extracted-font-declarations
- Netflix Sans Variable (woff2, 100–900 variable axis) — PRIMARY
- Netflix Sans (woff2/woff, 6 weights: 100/300/400/500/700/900) — fallback static
- Netflix Sans JA (Japanese ellipsis override)
- NKufi (Arabic, weights 400/500)
- GraphikTH (Thai, weights 400/500)
- Netflix Sans Debug (development only)
originalVariableConvention: --wct--local-design--{Component}-{Property}
Prefix: wct (Web Component Toolkit — Netflix's internal design system)
Components documented: Button, Input, Select, Accordion, Text
Additional: --wct--focus-ring--*, --wct--layout-container--*, --wct--layout-item--*
syntheticTokensCreated:
- --netflix-accent, --netflix-accent-warm, --netflix-accent-pressed (clustered from 3 red values)
- --netflix-bg-app (inferred from page dark background, not directly extracted)
- --netflix-bg-skeleton-base / shimmer (from @keyframes loading animation)
- --space-hero-heading-bottom / --space-body-bottom (from h1/body computed margin)
- --font-family-primary (from computed fontFamily on h1/h2/button)
All synthetic tokens annotated with confidence level inline.
nearDuplicateWarning:
11 pairs of near-identical colours detected.
Resolution: canonical value selected per role, duplicates merged.
Example: --wct--local-design--Select-Border and --wct--local-design--Input-Border
both equal rgba(128,128,128,0.7) → merged to --netflix-border
layoutContainerTokens:
--wct--layout-container--{columnSpacing|rowSpacing|maxWidth|padding|width}-{breakpoint}: initial
These are intentionally `initial` at the :root level — the component system
populates them per-breakpoint. Do not override these with fixed values.
breakpointCount: 23 distinct media query values detected (98px–2560px)
Key layout breakpoints: 768px (tablet), 1024px (desktop), 1280px (large desktop)
libraryDetected: Bootstrap (utility layer only — Netflix's primary styling is bespoke CSS-in-JS via Emotion)
tokenAuthority: reverse-engineered from live production site CSS
These are NOT Figma-authoritative tokens. They represent the production implementation.
Treat as high-fidelity but not design-source-of-truth.
```More from the gallery
Browse all kits →You may also like

Cash App
MITBold, high-contrast fintech design system built on Cash App's signature neon green and black palette, optimised for mobile payment interfaces and developer implementation
00
fintechmobilebolddark

Klarna
MITClean, modern fintech interface with Klarna's signature pink accents and dark eggplant typography, designed for seamless payment and shopping experiences
00
lightboldfintechecomm

Monzo
MITDark, modern fintech design system with navy foundations, coral accents, and fluid typography—built for fast-moving financial products and developer teams
00
darkfintechdeveloper-toolsaas