---
version: alpha
name: "&Walsh"
description: "Radical restraint meets maximalist output — a near-monochrome UI shell that steps aside entirely so the studio's bold, chromatic portfolio work can carry every visual conversation"

colors:
  background: "#f3f3f3"
  surface: "#ffffff"
  ink: "#060509"
  on-background: "#060509"
  on-surface: "#060509"
  primary: "#060509"
  on-primary: "#f3f3f3"
  primary-container: "#000000"
  ink-muted: "#5a5a5a" # estimated — mid-grey for captions
  border: "#000000"
  focus-ring: "#060509"
  text-hover: "#000000"
  shadow-soft: "#d9d9d9"
  overlay-fade: "#f3f3f3" # gradient fade — was linear-gradient(#f3f3f3, rgba(255,255,255,0))

typography:
  display-hero:
    fontFamily: "Maison Neue, Aktiv Grotesk, Helvetica Neue, Arial, sans-serif"
    fontSize: 50px
    fontWeight: 400
    lineHeight: 0.71
    letterSpacing: 0px
    fontFeature: "\"ss05\""
  display:
    fontFamily: "Maison Neue, Aktiv Grotesk, Helvetica Neue, Arial, sans-serif"
    fontSize: 50px
    fontWeight: 500
    lineHeight: 1.5
    letterSpacing: 0px
    fontFeature: "\"ss05\""
  heading-section:
    fontFamily: "Maison Neue, Aktiv Grotesk, Helvetica Neue, Arial, sans-serif"
    fontSize: 36px
    fontWeight: 400
    lineHeight: 1.0
    letterSpacing: 0px
    fontFeature: "\"ss05\""
  heading-sub:
    fontFamily: "Maison Neue, Aktiv Grotesk, Helvetica Neue, Arial, sans-serif"
    fontSize: 36px
    fontWeight: 500
    lineHeight: 1.0
    letterSpacing: 0px
    fontFeature: "\"ss05\""
  body-large:
    fontFamily: "Maison Neue, Aktiv Grotesk, Helvetica Neue, Arial, sans-serif"
    fontSize: 21px
    fontWeight: 500
    lineHeight: 1.75
    letterSpacing: 0px
    fontFeature: "\"ss05\""
  body:
    fontFamily: "Maison Neue, Aktiv Grotesk, Helvetica Neue, Arial, sans-serif"
    fontSize: 21px
    fontWeight: 400
    lineHeight: 1.75
    letterSpacing: 0px
    fontFeature: "\"ss05\""
  nav-link:
    fontFamily: "Maison Neue, Aktiv Grotesk, Helvetica Neue, Arial, sans-serif"
    fontSize: 21px
    fontWeight: 500
    lineHeight: 1.0
    letterSpacing: 0px
    fontFeature: "\"ss05\""
  button-ui:
    fontFamily: "Maison Neue, Aktiv Grotesk, Helvetica Neue, Arial, sans-serif"
    fontSize: 21px
    fontWeight: 500
    lineHeight: 1.0
    letterSpacing: 0px
    fontFeature: "\"ss05\""
  caption:
    fontFamily: "Maison Neue, Aktiv Grotesk, Helvetica Neue, Arial, sans-serif"
    fontSize: 13px
    fontWeight: 400
    lineHeight: 1.4
    letterSpacing: 0px
    fontFeature: "\"ss05\""

spacing:
  xs: 8px
  sm: 13px
  md: 26px
  lg: 47px
  xl: 75px
  2xl: 92px

rounded:
  none: 0px

components:
  button-primary:
    backgroundColor: "{colors.primary}"
    textColor: "{colors.on-primary}"
    typography: "{typography.button-ui}"
    rounded: "{rounded.none}"
    padding: 13px 26px
  button-primary-hover:
    backgroundColor: "{colors.primary-container}"
    textColor: "{colors.surface}"
    typography: "{typography.button-ui}"
    rounded: "{rounded.none}"
    padding: 13px 26px
  button-ghost:
    backgroundColor: "transparent"
    textColor: "{colors.ink}"
    typography: "{typography.button-ui}"
    rounded: "{rounded.none}"
    padding: 8px 0px
  button-ghost-hover:
    backgroundColor: "transparent"
    textColor: "{colors.ink}"
    typography: "{typography.button-ui}"
    rounded: "{rounded.none}"
    padding: 8px 0px
    textDecoration: "underline"
  card:
    backgroundColor: "{colors.surface}"
    textColor: "{colors.ink}"
    rounded: "{rounded.none}"
    padding: 13px 0px
  card-hover:
    backgroundColor: "{colors.surface}"
    textColor: "{colors.ink}"
    rounded: "{rounded.none}"
    padding: 13px 0px
    opacity: "0.85"
  nav:
    backgroundColor: "{colors.background}"
    textColor: "{colors.ink}"
    typography: "{typography.nav-link}"
    rounded: "{rounded.none}"
    padding: 13px 26px
  nav-link-hover:
    backgroundColor: "transparent"
    textColor: "{colors.ink}"
    typography: "{typography.nav-link}"
    rounded: "{rounded.none}"
    padding: 0px
    textDecoration: "underline"
  input:
    backgroundColor: "transparent"
    textColor: "{colors.ink}"
    typography: "{typography.body}"
    rounded: "{rounded.none}"
    padding: 1px 2px
  input-focus:
    backgroundColor: "transparent"
    textColor: "{colors.ink}"
    borderColor: "{colors.border}"
    typography: "{typography.body}"
    rounded: "{rounded.none}"
    padding: 1px 2px
  badge:
    backgroundColor: "{colors.ink}"
    textColor: "{colors.on-primary}"
    typography: "{typography.caption}"
    rounded: "{rounded.none}"
    padding: 4px 8px
---

# &Walsh Design System

## Overview

&Walsh's website is a masterclass in self-erasure. Jessica Walsh's studio — known globally for its bold, maximalist, chromatic work — presents itself on the web through the most restrained UI imaginable: a flat `{colors.background}` canvas, a near-black `{colors.ink}` type treatment (not quite black, a barely perceptible chromatic whisper), and zero decorative chrome. The navigation is a handful of words. The footer is two lines. Every pixel of UI investment has been redirected toward one purpose: framing the portfolio imagery so nothing competes with it. This is restraint deployed with total conviction, not timidity.

The typeface is Maison Neue — a contemporary grotesk with stylistic set `ss05` applied throughout, which activates alternate letterforms for a subtly warmer, more character-rich sans than the default. At the largest sizes (50px), it runs at a compressed line-height of 0.71, stacking headlines so tightly that the letters nearly interlock — a display mode that creates maximum typographic weight from minimum space. At body sizes, line-height relaxes to 1.75, flipping from dense editorial to generous reading comfort. The type system does not shout. It steps back. The work does the shouting.

What makes &Walsh genuinely distinctive as a system is not what it adds but what it withholds. There are no shadows. There is no border-radius. The `{colors.border}` is a pure hard black stroke. Hover states collapse to a simple opacity shift on images and underlines on links — the most legible, non-theatrical interaction language possible. The gradient appearing in the CSS — a fade from `{colors.background}` to transparent — is a content-fade device, not decoration. The entire palette is three colors. The emotional range comes entirely from the photography, the illustration, and the brand work on display, not from the container holding it. An agent working in this system should treat the UI as a picture frame: invisible, flat, and perfectly neutral.

**Key Characteristics:**
- Maison Neue with `font-feature-settings: "ss05"` applied at all sizes — a quiet typographic refinement that separates it from generic grotesks
- 50px display type at line-height 0.71 — compressed to near-touching; a bold graphic statement from a simple numeric choice
- Three-color palette: `{colors.background}` near-white, `{colors.ink}` near-black, `{colors.surface}` white — the entire UI in three hexes
- `{rounded.none}` across every element — no border-radius anywhere, hard rectangular shapes throughout
- Zero box shadows — no elevation system; depth is entirely spatial, provided by layout and imagery
- Links hover to underline at 0.2s ease; images fade opacity at 0.2s ease — two interaction rules, nothing more
- Navigation fades in at 0.4s ease — slightly slower than links, giving the nav a composed, unhurried quality
- A 50px font-weight 400 at line-height 0.71 and the same 50px at weight 500 at line-height 1.5 are treated as distinct display modes, not a scale
- Spacing values derive from a base near 13px (likely a 1/16th-rem grid fragment from a fractional scale) with multiples at 26px, 47px, 75px, 92px
- Typography filter — Work, Info, Contact, Search — is rendered at body weight 500, a small bump that signals interactivity without visual emphasis
- The portfolio grid is the layout; the UI is the absence of layout decisions

## Colors

### Primary
- **Near-Black** (`{colors.ink}`): The dominant ink — used for all type, navigation, borders, and primary interactive states. Not pure black; the RGB value `rgb(6, 5, 9)` carries a faint violet undertone. Count of 440 in extraction — it is the entire palette for UI text.
- **Canvas Grey** (`{colors.background}`): The page background — a warm near-white at `rgb(243, 243, 243)`. Present in three instances in the extraction, and in the site's gradient fade. Not pure white; the warmth matches Maison Neue's humanist character.

### Brand Accent
- **Pure Black** (`{colors.primary}`): Used when maximum contrast is required — the deepest form of the near-black ink, reserved for borders and the darkest interactive moments. Also the primary button background in the token system.

### Surfaces
- **White** (`{colors.surface}`): Clean white for card surfaces that need to lift fractionally against the warm canvas.
- **Overlay Fade** (`{colors.overlay-fade}`): The stop color in the single linear gradient in the system — a `{colors.background}`-to-transparent fade used for scrollable content masking, not decoration.

### Text States
- **Muted Ink** (`{colors.ink-muted}`): Estimated mid-grey for captions and secondary metadata. Not extracted directly — inferred from visual hierarchy of the live site.
- **Text Hover** (`{colors.text-hover}`): Pure black — the hover state for links, which shifts from `{colors.ink}` to `{colors.primary-container}` (pure `#000000`) via underline decoration, not color shift.

### Borders
- **Hard Border** (`{colors.border}`): Pure black — used for any ruled line or input border. The zero-radius, hard-black border reinforces the system's rejection of softness.

### Shadows
- No shadows are used. None were extracted. The system is fully flat.

## Typography

### Font Family
- **Primary**: `Maison Neue`, with fallbacks: `Aktiv Grotesk`, `Helvetica Neue`, `Arial`, `sans-serif`
- **Monospace**: None — Maison Neue handles all typographic registers
- **OpenType Features**: `font-feature-settings: "ss05"` applied universally — activates Maison Neue's alternate glyph set, providing subtly humanized letterforms across all sizes

*Note: Maison Neue is a proprietary typeface by Milieu Grotesque. The closest freely available substitute is Aktiv Grotesk or, at smaller sizes, Inter. The `ss05` alternates add warmth to the lowercase `a`, `g`, and similar characters — Inter with `ss01` enabled approximates this.*

### Hierarchy

| Token | Use |
|---|---|
| `display-hero` | 50px / 400 / lh 0.71 — compressed stacked display; project hero statements, editorial header text |
| `display` | 50px / 500 / lh 1.5 — the same size relaxed; flowing display for intro copy and section openers |
| `heading-section` | 36px / 400 / lh 1.0 — regular-weight section anchors; project titles in the grid |
| `heading-sub` | 36px / 500 / lh 1.0 — medium-weight version for emphasis within a section |
| `body-large` | 21px / 500 / lh 1.75 — medium-weight readable body; used for introductory paragraphs |
| `body` | 21px / 400 / lh 1.75 — standard reading text; ample leading for comfortable long-form |
| `nav-link` | 21px / 500 / lh 1.0 — navigation items; weight 500 distinguishes from body |
| `button-ui` | 21px / 500 / lh 1.0 — UI action labels; identical metrics to nav-link |
| `caption` | 13px / 400 / lh 1.4 — metadata, project captions, secondary labels |

### Principles
- **Two sizes, many moods**: The system uses 50px and 36px as its primary display registers, varying weight and line-height to create mode shifts rather than adding sizes. This compresses the type scale to essentials.
- **Line-height as expression**: 0.71 vs 1.5 at the same 50px is not a hierarchy — it is a register switch. Tight for editorial statements; relaxed for prose. The decision to use 0.71 at display is a deliberate graphic choice, not a readability trade-off.
- **`ss05` as quiet brand differentiation**: Without it, Maison Neue reads as a capable but generic grotesk. With `ss05`, the lowercase alternates warm the typeface to match the studio's humanist design philosophy. An invisible detail that designers notice.
- **Weight 500 as the only emphasis tool**: There is no bold (700), no italic, no uppercase transform. Medium weight (500) is the maximum typographic emphasis in this system.
- **Single family, total coverage**: Maison Neue handles display, body, UI, and caption roles without a secondary typeface. The self-sufficiency mirrors the UI's restraint.

## Layout

### Spacing System
The complete spacing scale is in the `spacing:` token block above. The base unit is approximately 13px — a fractional value suggesting the spacing derives from a fluid/viewport-based calculation rather than a fixed grid. Multiples cascade at 26px (2×), 47px (~3.6×), 75px, and 92px.

The spacing personality is sparse at the micro level and generous at the macro. Small gaps between elements are tight (8–13px); section breathing room reaches 75–92px. This creates a system where elements cluster into tight groups and groups themselves breathe widely apart — the gallery-hanging principle.

### Grid & Container
- Max content width: approximately 1750px at the large breakpoint (1550px+)
- The work grid dominates: fluid multi-column thumbnail layout at standard widths, collapsing to narrower columns on tablet
- Navigation: minimal horizontal strip — wordmark left, Work / Info / Contact + search icon right
- Content areas align to implicit columns; no evidence of a formal grid variable in the CSS

### Whitespace Philosophy
- The UI is structurally sparse so imagery does not need to fight for space — whitespace is not decorative, it is a ceding of territory to the work
- Section transitions are abrupt; there are no ornamental dividers, no transition elements, no decorative rules
- The overlay-fade gradient (background-to-transparent) is the only soft whitespace device in the system

## Elevation & Depth

| Level | Treatment | Use |
|---|---|---|
| Flat (Level 0) | No shadow | Everything — nav, cards, buttons, inputs |
| Opacity Shift | `opacity: 0.85` on hover | Portfolio image cards — the single depth cue |
| Gradient Mask | `linear-gradient({colors.background}, transparent)` | Content fade at scroll edges |
| Focus Ring | `outline: {colors.focus-ring} none 3px` | Keyboard focus — declared, not visually styled |

**Shadow Philosophy**: &Walsh uses no shadows. The extraction confirmed zero shadow values across the entire page. Depth is implied by photography — the studio's work is shot, composed, and color-graded such that the images themselves carry depth, light, and dimension. The container around them is, by design, perfectly flat.

## Shapes

The complete radius scale is in the `rounded:` token block above.

| Token | Value | Use |
|---|---|---|
| `none` | 0px | Every element — cards, buttons, inputs, nav, images |

The shape philosophy is binary and absolute: everything is a hard rectangle. There is no pill, no sm, no lg. The choice is not neutral — it is a statement. &Walsh's work is often visually explosive, layered, and chromatic. The container holding it is a sharp-edged frame. The tension between the irregular, bold work and the rigid rectangular grid that displays it is precisely the point.

## Components

The complete component spec lives in the `components:` token block above. Reference component tokens directly (`{components.button-primary}`, `{components.card}`) rather than reconstructing them.

### Button variants

- **`button-primary`** — `{colors.primary}` background with `{colors.on-primary}` text; padding `13px 26px`; hard rectangle at `{rounded.none}`. Used for primary CTAs and form submissions.
- **`button-primary-hover`** — Shifts to pure `{colors.primary-container}` black; identical shape and padding.
- **`button-ghost`** — Transparent background, `{colors.ink}` text, no border, no padding on sides; acts as a plain text link but semantically a button. Hover adds underline decoration.

### Cards

**Portfolio Work Card**: `{colors.surface}` background, `{rounded.none}`, no shadow, no border. Full-width thumbnail image above project title in `{typography.heading-section}`. Hover triggers an opacity transition (`0.2s ease`) on the image. The card itself has no chrome — the image is the card. Padding is `{spacing.sm}` top only, no side padding (images run to the column edge).

### Inputs

**Search / Text Input**: Transparent background, no border at rest, `{colors.border}` on focus. Padding `1px 2px` — flush, anti-styled. Font `{typography.body}`. The PrimeReact framework underpins the component layer but the visual treatment overrides its defaults to near-zero chrome.

### Badges

Tags and category labels render in `{typography.caption}` on `{colors.ink}` background with `{colors.on-primary}` text, `{rounded.none}`. Used for work filter labels (Branding / Advertising / Motion / Print).

### Navigation

Top horizontal nav: `{colors.background}` strip, wordmark SVG left, text links right. Links in `{typography.nav-link}`, `{colors.ink}`, no underline at rest — underline appears on hover at `0.4s ease`. Sticky behavior; no backdrop blur; no border separator between nav and content. Simple, transparent, and present only enough to navigate.

## Do's and Don'ts

### Do
- Use `font-feature-settings: "ss05"` on all Maison Neue usage — without it, the humanist alternates are lost and the face reads generic
- Apply line-height 0.71 only at 50px display contexts where you want compressed graphic density; switch to 1.5 for display text in prose-adjacent contexts
- Keep the palette to three values — `{colors.background}`, `{colors.ink}`, `{colors.surface}` — UI chrome never introduces a new color
- Use `{rounded.none}` everywhere without exception; even form inputs and buttons are hard rectangles
- Let hover states be simple: underline on links, opacity shift on images — nothing theatrical
- Use `{spacing.md}` (26px) as the primary internal element gap; jump to `{spacing.lg}` or `{spacing.xl}` for section-level breathing room
- Build navigation as a minimal horizontal strip with generous left/right padding; the nav should feel like a caption, not a header
- Trust the portfolio imagery to carry all visual energy; the UI's job is to stay out of the way

### Don't
- Don't add border-radius to any element — not 2px, not 4px, not a pill on tags; the system is 0px by design, and any rounding introduces a softness that conflicts with the hard editorial stance
- Don't introduce drop shadows or elevation — the system is flat; depth comes from photography, not CSS
- Don't add brand accent colors to the UI chrome; the work provides all color
- Don't use font-weight above 500 anywhere in the hierarchy; there is no bold in this system
- Don't use letter-spacing on any text — Maison Neue's natural spacing, adjusted by `ss05`, is the tracking; manual intervention overwrites the typeface's design intent
- Don't tighten line-height on body text below 1.5 — the 1.75 body leading is what makes dense project lists readable
- Don't add decorative dividers, rules, or ornaments between sections; abrupt adjacency is the section-break strategy
- Don't override the opacity hover on image cards with a color overlay or border highlight — the fade is the entire hover system

---

## Responsive Behavior

### Breakpoints
| Name | Width | Key Changes |
|---|---|---|
| Mobile Small | <374px | Single column, display text reduces, nav collapses |
| Mobile | 374–767px | Single column portfolio grid, tight side padding |
| Tablet | 768–1549px | Two-column grid begins, nav expands to full links |
| Desktop | 1550px+ | Multi-column grid, hero at full scale, max-width container |

### Touch Targets
- Navigation links: 21px text with sufficient surrounding padding; estimated 44px tap height at standard nav padding
- Portfolio cards: large tap regions (full image + title); no minimum size concern
- Filter tags: compact but usable; consider 40px minimum touch height on mobile implementations

### Collapsing Strategy
- Navigation collapses at the 374px and 767px breakpoints — exact collapse behavior not extracted, but minimal link count (Work, Info, Contact, Search) means even a full-display mobile strip is feasible
- Display type scales down proportionally; no fluid clamp extracted, but the fractional spacing scale suggests viewport-relative units in the source
- The portfolio grid moves from multi-column to two-column to single-column; no cards redesign, just column count changes
- Section spacing contracts: `{spacing.xl}` (75px) at desktop to `{spacing.md}` (26px) at mobile

### Image Behavior
- Portfolio thumbnails are the dominant content element; they are full-width within their column at all breakpoints
- No art-direction swap detected; same images serve all viewport widths
- Images transition on hover at 0.2s ease (opacity shift); this interaction is suppressed on touch devices in standard practice

---

## Agent Prompt Guide

### Quick Color Reference
- Background: `{colors.background}`
- Text: `{colors.ink}`
- Surface: `{colors.surface}`
- Primary CTA: `{colors.primary}`
- Border: `{colors.border}`
- Focus: `{colors.focus-ring}`

### Example Component Prompts

- "Build a portfolio hero section on an `{colors.background}` canvas. Place a large project image edge-to-edge in its column. Below it, project title in Maison Neue (fallback: Aktiv Grotesk, Helvetica Neue, sans-serif) with `font-feature-settings: 'ss05'` at 36px weight 400 line-height 1.0, color `{colors.ink}`. No card chrome, no border-radius, no shadow. Hover: image fades to 0.85 opacity at 0.2s ease."
- "Create top navigation: sticky white-grey strip (`{colors.background}`), wordmark SVG left-aligned. Right side: 'Work', 'Info', 'Contact' links in Maison Neue 21px weight 500 `{colors.ink}`, no underline at rest. Hover adds underline at 0.4s ease. Search icon far right. No border, no shadow, no backdrop blur. Full-width."
- "Design a work filter row: a horizontal list of category labels (All / Branding / Advertising / Motion / Print). Each label in Maison Neue 13px weight 400 `{colors.ink}`. Active label: `{colors.ink}` background with `{colors.on-primary}` text, padding 4px 8px, border-radius 0px. Inactive: transparent background, same text color, no border."
- "Build a primary CTA button: background `{colors.primary}`, text `{colors.on-primary}`, Maison Neue 21px weight 500, padding 13px 26px, border-radius 0px, no shadow. Hover: background shifts to pure `{colors.primary-container}` black."
- "Create an About / Studio intro text block: `{colors.background}` page, large opening statement in Maison Neue 50px weight 400 line-height 0.71 `font-feature-settings: 'ss05'` color `{colors.ink}` — tight, compressed, graphic. Following body paragraph in Maison Neue 21px weight 400 line-height 1.75 — generous, open, readable. No decorative elements between them."

### Iteration Guide

1. Start with `{colors.background}` as the canvas — the warm near-white sets the entire tonal register; `{colors.surface}` white enters only where card elevation from canvas is needed
2. All type is `{colors.ink}` — the fractional violet undertone of `#060509` against `#f3f3f3` is intentional and should not be substituted with pure `#000000` for body text
3. Apply `font-feature-settings: "ss05"` before adjusting any other type property — it changes the character of the typeface at a foundational level
4. Line-height is the primary expressive lever: 0.71 for compressed graphic display, 1.5–1.75 for readable prose — choose the register before choosing the size
5. Set `border-radius: 0` on every element at the reset level — do not rely on component defaults
6. Hover interactions are two rules: links underline at 0.2s ease; images fade opacity at 0.2s ease; nav fades in at 0.4s ease — nothing else
7. Resist any color that is not `{colors.ink}`, `{colors.background}`, or `{colors.surface}` in UI chrome — if a color appears, it belongs in the portfolio work, not the frame

---

## Attribution

Independent design analysis from [Design Swatches](https://designmd.santiagoalonso.com) by [Santiago Alonso](https://santiagoalonso.com). Based on publicly observable interface patterns. Not affiliated with or endorsed by &Walsh. Brand names and trademarks belong to their respective owners.
