# Portswigger Design System

> High-contrast technical utility anchored by a signature safety orange and deep naval foundations.

**Source:** https://portswigger.net | **Captured:** 2026-06-06 | **Pages analyzed:** 3
**Brand layer:** parent | **Related brands:** None

## TL;DR
Portswigger employs a high-contrast, information-dense aesthetic that balances professional cybersecurity authority with approachable "builder" energy. The system is anchored by a primary orange `#ff6733` used for critical actions and brand accents, set against a foundation of deep navy `#001350` and neutral grays. Typography is strictly sans-serif, utilizing Arial for high-scale display and Droid Sans for functional body text. Layouts favor a structured grid of cards with soft radii (4px to 6px) and significant elevation depth provided by multi-layered shadows.

## Signature DNA
1. **The Action Orange** (`#ff6733`): Used exclusively for primary CTAs and brand-critical iconography (chevrons, lightning bolts). It provides a 2.9:1 contrast ratio on white, prioritizing brand recognition over strict AA compliance for decorative elements.
2. **Deep Navy Foundations** (`#001350`): This color acts as the "professional" weight, used for section headers, primary text in high-importance areas, and as a solid background for hero sections to establish authority.
3. **Elevated Card Grids**: Content is almost universally contained in white cards with subtle 4px-6px corner radii and heavy, multi-stop shadows (`rgba(50, 50, 93, 0.25)...`) to create a sense of modularity and depth.

## Colors
### Foundation
| Token | Hex | Role | Occurrences | Confidence | Source |
|-------|-----|------|-------------|------------|--------|
| `--dl-color-core-white` | `#ffffff` | Page background, card surface, button text | 119 | 1 | Computed Style |
| `--dl-color-core-grey-1` | `#333332` | Primary body text, secondary headers | 198 | 1 | `--dl-color-core-grey-1` |
| `--dl-color-text-body-grey` | `#5c5c5b` | Secondary body text, UI labels | 129 | 1 | `--dl-color-text-body-grey` |
| `--dl-color-backgrounds-black` | `#000000` | Footer text, high-contrast accents | 41 | 1 | Computed Style |

### Accent
| Token | Hex | Role | Occurrences | Confidence | Source |
|-------|-----|------|-------------|------------|--------|
| `--dl-color-core-orange-1` | `#ff6733` | Primary CTA background, brand icons | 106 | 1 | `--dl-color-core-orange-1` |
| `--dl-color-core-navy-1` | `#001350` | Section headers, primary brand color | 62 | 1 | `--dl-color-core-navy-1` |
| `--dl-color-text-header-navy` | `#060738` | Display headings | 17 | 1 | `--dl-color-text-header-navy` |
| `--dl-color-twitter-1` | `#00acee` | Social icons (decorative_only) | 3 | 1 | Computed Style |

### Semantic
Not captured in source.

## Typography
### Fonts
| Family | Weights observed | Role | Open-source substitute | License |
|--------|------------------|------|------------------------|---------|
| Arial | 400, 700, 900 | Heading, Display, UI | Arimo | System |
| Droid sans | 400, 700 | Body, Links | Open Sans | Apache 2.0 |
| ps-icons | 400 | Iconography | N/A | Proprietary |

### Scale
| Token | Size | Line height | Letter spacing | Weight | Use | Evidence selector |
|-------|------|-------------|----------------|--------|-----|-------------------|
| `{text.display-xl}` | 64px | 73.6px | normal | 700 | Stats values | `span.stats-section-thq-stat1-value-elm` |
| `{text.display-lg}` | 60px | 70px | -2.4px | 700 | Main Hero H1 | `h1.heading-1` |
| `{text.display-md}` | 40px | 500px | -1.6px | 700 | Section Headers | `h2.banner-two-columns-text1` |
| `{text.heading-md}` | 32px | 42px | normal | 700 | Sub-section titles | `h2#our-history` |
| `{text.heading-sm}` | 22px | 32px | -0.88px | 700 | Card titles | `h3.blog-post-card-text1` |
| `{text.body-lg}` | 18px | 30px | normal | 400 | Intro paragraphs | `p:nth-of-type(1)` |
| `{text.body-md}` | 16px | 26px | normal | 400 | Default body text | `span.mega-nav-text` |
| `{text.body-sm}` | 14px | 24px | normal | 400 | Button labels, small text | `button.button-primary` |

### Principles
1. **Tight Display Tracking**: Large display sizes (40px+) use negative letter spacing (-1.6px to -2.4px) to maintain visual tension.
2. **Weight for Emphasis**: Bold weights (700) are strictly reserved for headings and interactive labels; body text never exceeds 400.
3. **Iconic Punctuation**: The `ps-icons` font is used at 16px-30px to provide directional cues (chevrons) and brand motifs.

## Spacing
**Base unit:** 5px (derived from common multiples)
| Token | Value | Occurrences |
|-------|-------|-------------|
| `{space.xs}` | 8px | 28 |
| `{space.sm}` | 10px | 40 |
| `{space.md}` | 15px | 63 |
| `{space.lg}` | 20px | 62 |
| `{space.xl}` | 40px | 25 |

## Border radius
| Token | Value | Use | Evidence |
|-------|-------|-----|----------|
| `{radius.none}` | 0px | Default containers | 547 occurrences |
| `{radius.sm}` | 4px | Form inputs, small cards | Pricing page cards |
| `{radius.md}` | 6px | Feature cards | Homepage benefit cards |
| `{radius.pill}` | 100px | Primary buttons | CTA buttons |

## Elevation
| Level | Value | Use | Evidence |
|-------|-------|-----|----------|
| `{shadow.deep}` | `rgba(50, 50, 93, 0.25) 0px 13px 27px -5px...` | Feature cards | Homepage benefit grid |
| `{shadow.soft}` | `rgba(0, 0, 35, 0.2) 0px 0px 20px 0px` | Pricing cards | Pricing tier cards |
| `{shadow.subtle}`| `rgba(0, 0, 0, 0.16) 0px 4px 6px 0px` | Surface panels | About page sections |

## Components
### Tier 1: Foundational
#### Rounded Button
**Role:** Primary site-wide CTA
**Pages observed:** https://portswigger.net, https://portswigger.net/pricing
**Spec:** Background: `#ff6733` | Text: `#ffffff` | Border: 2px solid `#ff6733` | Radius: `100px` | Padding: `10px 20px` | Typography: `14px/700`
**States observed:** Default | Hover: captured | Focus: not captured | Active: captured | Disabled: not captured

### Tier 2: Patterns
#### Feature Card
**Role:** Highlighting product benefits or news items
**Pages observed:** https://portswigger.net, https://portswigger.net/pricing
**Spec:** Background: `#ffffff` | Text: `#333332` | Radius: `6px` | Padding: `20px` | Shadow: `{shadow.deep}`
**States observed:** Default | Hover: captured | Focus: not captured | Active: not captured | Disabled: not captured

#### Navigation Link
**Role:** Top-level site navigation
**Pages observed:** All
**Spec:** Text: `#333332` | Typography: `16px/400` | Padding: `0px 15px` | Height: `50px`
**States observed:** Default | Hover: captured | Focus: not captured | Active: not captured | Disabled: not captured

### Tier 3: Surface-specific
#### Pricing Card
**Role:** Displaying purchase options
**Pages observed:** https://portswigger.net/pricing
**Spec:** Background: `#ffffff` | Radius: `4px` | Padding: `40px` | Shadow: `{shadow.soft}`
**States observed:** Default | Hover: not captured

#### Icon Badge
**Role:** Categorizing content (e.g., "Test", "Train")
**Pages observed:** https://portswigger.net
**Spec:** Background: `#0594ff` (Enterprise) or `#ff6733` (General) | Text: `#ffffff` | Radius: `0px` | Padding: `5px 10px`
**States observed:** Default

## Layout
| Property | Value |
|----------|-------|
| Max Content Width | 1200px |
| Section Vertical Gap | 60px - 100px |
| Grid Gutter | 20px |

## Responsive
| Breakpoint | Width | Key changes |
|------------|-------|-------------|
| Mobile | < 768px | Navigation collapses to hamburger; 3-up card grids stack to 1-up. |
| Desktop | 1440px | Full mega-nav visibility; horizontal card layouts. |

## Do's
- Use `#ff6733` for all primary user actions.
- Apply negative letter spacing to Arial headings above 32px.
- Use `{shadow.deep}` for cards that contain interactive content.
- Ensure all body text uses Droid Sans for legibility.
- Maintain a minimum of 60px vertical padding between major page sections.

## Don'ts
- **Wrong:** Using `#0094ff` for a primary Portswigger CTA. **Right:** Use `#ff6733`. **Reason:** Blue is reserved for sub-brand/product-specific accents (Enterprise), not global actions.
- Do not use border radii larger than 6px for square containers; 100px is reserved for buttons.
- Do not use Arial for long-form body copy; reserve it for headings and UI labels.
- Do not place orange text on navy backgrounds (contrast failure).

## Quick start

```css
:root {
  --ps-orange: #ff6733;
  --ps-navy: #001350;
  --ps-grey-dark: #333332;
  --ps-grey-body: #5c5c5b;
  --ps-white: #ffffff;
  
  --ps-shadow-deep: 0px 13px 27px -5px rgba(50, 50, 93, 0.25), 0px 8px 16px -8px rgba(0, 0, 0, 0.3);
  --ps-radius-card: 6px;
  --ps-radius-button: 100px;
}
```

## Known gaps
- Semantic success/error states were not observed in the primary marketing flow.
- Focus states for keyboard navigation were not explicitly captured in the visual evidence.
- Mobile-specific spacing tokens were not fully delineated from desktop values.

## Provenance
| Page sampled | URL | Viewport | Capture time |
|--------------|-----|----------|--------------|
| Homepage | https://portswigger.net | 1440px | 2026-06-06 |
| Pricing | https://portswigger.net/pricing | 1440px | 2026-06-06 |
| About | https://portswigger.net/about | 1440px | 2026-06-06 |
