---
version: alpha
name: "Ganni"
description: "Ganni's design system pairs a bespoke Helvetica Neue with a high-contrast black-and-white canvas to serve full-bleed editorial photography — playful Copenhagen energy delivered through typographic restraint and a completely square shape language."

colors:
  # Surface / canvas
  background: "#ffffff"
  surface: "#f1f1f1"           # light neutral for search bars, subtle panels
  surface-dark: "#000000"      # dark nav header background and hero overlay anchors

  # Ink / text
  ink: "#000000"               # primary text, nav links, CTA labels on light ground
  ink-on-dark: "#ffffff"       # text and links when on surface-dark
  ink-muted: "#686a6a"         # secondary text, captions, utility links — warm gray

  # Brand accent — Ganni uses pure black as its only structural accent
  primary: "#000000"           # CTA fill, primary button, form submit
  on-primary: "#ffffff"        # text on black CTA
  primary-hover: "#686a6a"     # softened hover state on black CTA elements

  # Interactive states
  focus-ring: "#000000"        # 2px solid outline, confirmed from input-focus data
  focus-tint: "#f1f1f1"        # was rgba(241,241,241) shadow on focus — Google format requires hex

  # Semantic
  success: "#22c55e"           # /* estimated */ checkout confirmations
  error: "#ef4444"             # /* estimated */ form validation
  warning: "#f59e0b"           # /* estimated */ stock alerts

  # CSS variable: --link-color from dembrandt
  link-forest: "#234923"       # --link-color from CSS vars; used for sustainability section links

  # Borders
  border: "#ffffff"            # email input border default (transparent over dark BG)
  border-dark: "#000000"       # focus border, modal chrome, structural dividers

  # Shadow tints
  shadow-soft: "#000000"       # was rgba(0,0,0,0.3) — Google format requires hex

typography:
  display-hero:
    fontFamily: "Helvetica Neue For Ganni, Helvetica Neue, Arial, sans-serif"
    fontSize: 64px
    fontWeight: 700
    lineHeight: 1.1
    letterSpacing: -0.5px
  display:
    fontFamily: "Helvetica Neue For Ganni, Helvetica Neue, Arial, sans-serif"
    fontSize: 27px
    fontWeight: 500
    lineHeight: 1.2
    letterSpacing: 0px
  heading-section:
    fontFamily: "Helvetica Neue For Ganni, Helvetica Neue, Arial, sans-serif"
    fontSize: 24px
    fontWeight: 700
    lineHeight: 1.3
    letterSpacing: 0px
  heading-sub:
    fontFamily: "Helvetica Neue For Ganni, Helvetica Neue, Arial, sans-serif"
    fontSize: 18px
    fontWeight: 500
    lineHeight: 1.3
    letterSpacing: 0px
  body-large:
    fontFamily: "Helvetica Neue For Ganni, Helvetica Neue, Arial, sans-serif"
    fontSize: 16px
    fontWeight: 400
    lineHeight: 1.5
    letterSpacing: 0px
  body:
    fontFamily: "Helvetica Neue For Ganni, Helvetica Neue, Arial, sans-serif"
    fontSize: 14px
    fontWeight: 400
    lineHeight: 1.3
    letterSpacing: 0px
  nav-link:
    fontFamily: "Helvetica Neue For Ganni, Helvetica Neue, Arial, sans-serif"
    fontSize: 14px
    fontWeight: 500
    lineHeight: 1.0
    letterSpacing: 0px
  button-ui:
    fontFamily: "Helvetica Neue For Ganni, Helvetica Neue, Arial, sans-serif"
    fontSize: 14px
    fontWeight: 700
    lineHeight: 1.0
    letterSpacing: 0px
    textTransform: uppercase
  label-ui:
    fontFamily: "Helvetica Neue For Ganni, Helvetica Neue, Arial, sans-serif"
    fontSize: 15px
    fontWeight: 700
    lineHeight: 1.0
    letterSpacing: 0px
    textTransform: uppercase
  caption:
    fontFamily: "Helvetica Neue For Ganni, Helvetica Neue, Arial, sans-serif"
    fontSize: 12px
    fontWeight: 400
    lineHeight: 1.3
    letterSpacing: 0px

spacing:
  xs: 5px
  sm: 10px
  md: 15px
  lg: 20px
  xl: 30px
  2xl: 40px
  3xl: 64px
  4xl: 96px

rounded:
  none: 0px
  sm: 3px      # cookie/alert modals only — framework seam, not a brand choice
  pill: 100px  # tag badges, swatch indicators only

components:
  button-primary:
    backgroundColor: "{colors.primary}"
    textColor: "{colors.on-primary}"
    typography: "{typography.button-ui}"
    rounded: "{rounded.none}"
    padding: 14px 20px
    border: "0px solid {colors.border-dark}"
  button-primary-hover:
    backgroundColor: "{colors.primary-hover}"
    textColor: "{colors.on-primary}"

  button-secondary:
    backgroundColor: "{colors.surface}"
    textColor: "{colors.ink-muted}"
    typography: "{typography.button-ui}"
    rounded: "{rounded.none}"
    padding: 14px 15px
    border: "0px none {colors.ink-muted}"
  button-secondary-hover:
    backgroundColor: "{colors.surface}"
    textColor: "{colors.ink}"

  button-ghost:
    backgroundColor: "transparent"
    textColor: "{colors.ink}"
    typography: "{typography.button-ui}"
    rounded: "{rounded.none}"
    padding: 10px 20px
    border: "1px solid {colors.border-dark}"
  button-ghost-hover:
    backgroundColor: "{colors.surface}"
    textColor: "{colors.ink}"

  card:
    backgroundColor: "{colors.background}"
    rounded: "{rounded.none}"
    padding: 0px

  card-product:
    backgroundColor: "{colors.background}"
    textColor: "{colors.ink}"
    typography: "{typography.body}"
    rounded: "{rounded.none}"
    padding: 10px 0px

  input:
    backgroundColor: "{colors.background}"
    textColor: "{colors.ink}"
    typography: "{typography.body-large}"
    rounded: "{rounded.none}"
    padding: 7px 14px
    border: "1px solid {colors.border}"
  input-focus:
    borderColor: "{colors.border-dark}"
    boxShadow: "0px 0px 3px {colors.focus-tint}"
    outline: "2px solid {colors.focus-ring}"

  nav-bar:
    backgroundColor: "{colors.surface-dark}"
    textColor: "{colors.ink-on-dark}"
    typography: "{typography.nav-link}"
    padding: 10px 20px

  badge:
    backgroundColor: "{colors.surface}"
    textColor: "{colors.ink-muted}"
    typography: "{typography.caption}"
    rounded: "{rounded.none}"
    padding: 4px 8px
    textTransform: uppercase
  badge-pill:
    backgroundColor: "{colors.primary}"
    textColor: "{colors.on-primary}"
    typography: "{typography.caption}"
    rounded: "{rounded.pill}"
    padding: 2px 8px
---

# Ganni Design System

## Overview

Ganni operates from a position of deliberate contrast. The navigation bar anchors in pure black (`{colors.surface-dark}`), pressing down on full-bleed photography that bleeds edge to edge below it — swimwear campaigns, street-style editorials, bold seasonal lookbooks. Below the fold, the canvas flips to white (`{colors.background}`), clean and open, where product grids and editorial modules live in plenty of air. This push-and-pull between deep black header and bright white content zones is the site's primary design move: Copenhagen's joyful energy expressed through confident tonal opposition rather than through color.

The typographic engine is **Helvetica Neue For Ganni** — a custom-licensed cut of one of the world's most neutral grotesques, self-hosted in Roman (weight 400) and Medium (weight 500) and bespoke Bold (weight 700) variants. That last weight is where Ganni's personality appears: the GANNI wordmark in the nav and the primary CTA labels ("SIGN UP", "ADD TO BAG") run in uppercase 700-weight Helvetica, tight and authoritative, pressing through white space with a commercial confidence that the brand then undercuts with its deliberately playful seasonal campaigns. There is no second typeface. No serif for editorial moments, no display custom script — Helvetica alone, across every role.

Shape language is unambiguously square. Buttons, cards, inputs, modal frames, product tiles, image containers — everything resolves at `{rounded.none}` (0px). The only exceptions are a 3px radius on third-party cookie alerts and 100px pill on small swatch indicators, neither of which originate from Ganni's own design decisions. This commitment to the rectangle reads as efficient and modern rather than severe: the photography is warm, the merchandise playful, so the grid's hard corners function as a neutral armature rather than a statement of austerity.

**Key Characteristics:**
- Dual-surface system: `{colors.surface-dark}` black header versus `{colors.background}` white content canvas — high contrast, no mid-tone tints
- Single bespoke typeface: **Helvetica Neue For Ganni**, self-hosted in three weights (400, 500, 700), used for every typographic role
- Uppercase weight-700 button labels as the primary typographic voice of the brand (`{typography.button-ui}`)
- Full-bleed photography heroes — imagery is the product, chrome is the armature
- Radically square shape system: `{rounded.none}` on all native UI components; pill used only on decorative swatches
- `{colors.ink-muted}` (`#686a6a`) warm gray as the secondary ink — neutral but not cold
- Motion at 0.15–0.25s, ease-in, applied to nav slide, button transitions, and image hover filter
- 13-breakpoint responsive system from 350px to 1440px — one of the most granular breakpoint sets in fashion e-commerce
- CSS `--link-color` custom property (`{colors.link-forest}`) for sustainability-section links — the one chromatic brand accent
- Focus state: 2px solid `{colors.focus-ring}` outline plus `{colors.focus-tint}` glow — accessible and on-system

## Colors

### Surface & Canvas
- **White** (`{colors.background}`): The primary content canvas. All product grids, editorial modules, and modal overlays rest here.
- **Light Neutral** (`{colors.surface}`): A step off white — used for the search utility bar background, cookie consent panels, and secondary button fills.
- **Black Header** (`{colors.surface-dark}`): The navigation bar and persistent announcement strip. Ganni's most visible brand signal.

### Ink / Text
- **Ink Black** (`{colors.ink}`): Primary text on all light surfaces — product names, prices, body copy, modal headings.
- **Ink on Dark** (`{colors.ink-on-dark}`): White text for navigation links, top-bar announcements, and any element over `{colors.surface-dark}`.
- **Muted Warm Gray** (`{colors.ink-muted}`): Secondary layer — captions, utility navigation links, sizes, color labels, inactive states. The `#686a6a` value is warm rather than cool, preventing the gray from reading as corporate.

### Brand Accent
- **Black CTA** (`{colors.primary}`): Primary button fill and the system's sole structural accent. Ganni has no chromatic accent color for UI — black does all the conversion work.
- **White on Black** (`{colors.on-primary}`): Button label, always uppercase Helvetica 700.

### Interactive States
- **Focus Ring** (`{colors.focus-ring}`): 2px solid black outline on focused inputs and buttons.
- **Focus Tint** (`{colors.focus-tint}`): Soft gray glow around focused inputs — approximated from `rgba(241,241,241)`.

### Semantic & Special
- **Sustainability Green** (`{colors.link-forest}`): `--link-color` CSS variable — appears in the Responsibility section for inline links. The only chromatic hue in the system.
- **Error / Warning / Success**: Standard semantic tokens; not prominent in Ganni's UI but used in cart and checkout flows.

### Borders
- **Transparent Input Border** (`{colors.border}`): Email input border at default state — white against the dark modal context, effectively invisible.
- **Dark Border** (`{colors.border-dark}`): Focus state border on inputs, modal structure lines, structural dividers.

## Typography

### Font Family
- **Primary**: `Helvetica Neue For Ganni`, self-hosted in Roman (`HelveticaNeueforGanni-Roman.woff2`) and Medium (`HelveticaNeueforGanni-Medium.woff2`) variants. A third woff2 (`c79155e8-ebd0-11f0-b8fd-facaa7335c18`) handles the bold weight.
- Fallbacks: `Helvetica Neue, Arial, sans-serif` — system stacks that preserve the grotesque character.
- No Google Fonts, no Adobe Fonts, no variable fonts in use.

### Hierarchy

| Token | Use |
|---|---|
| `display-hero` | Campaign hero titles, seasonal statement lines at large scale |
| `display` | 27px section headers — editorial feature intros, category page titles |
| `heading-section` | 24px bold — product detail headings, modal titles, feature subheads |
| `heading-sub` | 18px medium — sub-section labels, panel headings, accordion triggers |
| `body-large` | 16px — running body copy, product descriptions, editorial paragraphs |
| `body` | 14px — product tile names, prices, cart line items, form labels |
| `nav-link` | 14px medium — top-level navigation items, desktop menu links |
| `button-ui` | 14px bold, uppercase — all CTA and primary action labels |
| `label-ui` | 15px bold, uppercase — strong action labels, promo tags, submit buttons |
| `caption` | 12px — size indicators, color swatch labels, legal fine print |

### Principles
- **One typeface, three weights**: Helvetica Neue For Ganni's Roman, Medium, and Bold carry every typographic role. No second typeface enters the system anywhere.
- **Uppercase for action**: `text-transform: uppercase` reserved for CTA buttons and product flag labels — never applied to editorial body or navigation at rest.
- **Weight 700 as brand voice**: Where other fashion systems use a custom display face for personality, Ganni uses Bold weight at CTA scale. The brand voice is not decorative — it's functional.
- **No letter-spacing manipulation**: unlike many fashion brands, Ganni does not apply aggressive tracking. Natural `letter-spacing: 0` or `normal` throughout — the weight and uppercase carry the load.
- **Practical legibility scale**: body at 14–16px, never the sub-10px editorial extremism of ultra-minimal fashion brands.

## Layout

### Spacing System
The complete scale is in the `spacing:` token block. Base unit: 5px, with a strong bias toward 10px, 15px, 20px, and 40px increments in practice.

Ganni's spacing reads as efficient rather than generous — product grids are dense by fashion-site standards, with 20px gutters and relatively compact vertical rhythm. The photography does the breathing; the surrounding layout stays focused on commerce.

### Grid & Container
- Max content width: 1440px with responsive breakpoints at 1439px → 1200px → 1199px → 992px → 991px → 768px and mobile tiers below
- Desktop product grid: typically 4 columns with consistent 20px gutters
- Navigation: full-width black bar with GANNI wordmark left-anchored; utility icons (search, wishlist, cart, account) right-aligned
- Hero sections: full-bleed photography with the nav overlaid — no separate hero container, image runs to all four edges

### Whitespace Philosophy
- Photography earns the white space — content zones are denser than competitors like Jacquemus but more considered than fast-fashion sites
- No decorative background color alternation between sections — the dual-surface contrast (black nav / white content) does all the sectioning work
- Cart drawers and filter panels use `{colors.surface}` as a barely-there tint rather than a hard secondary color

## Elevation & Depth

| Level | Treatment | Use |
|---|---|---|
| Flat (Level 0) | No shadow | Product tiles, editorial cards, all standard surfaces |
| Focus Glow (Level 1) | `0px 0px 3px {colors.focus-tint}` | Input focus state — accessible, barely visible |
| Modal Overlay (Level 3) | `rgba(0,0,0,0.3)` soft shadow behind modals | Sign-up modal, cookie consent dialog |
| Drawer Shadow (Level 3) | `0px 4px 8px rgba(0,0,0,0.4)` | Cart slide-in panel, filter drawer |

**Shadow Philosophy**: Ganni's surface is nearly flat. Product tiles carry no shadow; cards don't lift on hover; the grid reads as a print layout printed on a white page. Depth only appears at overlay level — modals and drawers — where it serves a functional purpose (focus management) rather than a decorative one. The motion system (0.25s ease on nav, 0.15s ease-in on buttons) provides a sense of tactility without adding shadow layers.

## Shapes

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

| Token | Value | Use |
|---|---|---|
| `none` | 0px | All native UI: buttons, product cards, inputs, modals, image frames |
| `sm` | 3px | Third-party cookie modals only — framework seam, not a Ganni choice |
| `pill` | 100px | Color swatch indicators, size badge chips |

Ganni's shape system is square. Every UI element that Ganni designs resolves to 0px radius. The `3px` on the cookie alert and the pill on swatches are both framework or product-catalogue artefacts — when Ganni writes the CSS, the answer is a rectangle. This gives the site a modern directness that pairs well with the bold photography without sliding into luxury-brand severity.

## Components

The complete component spec lives in the `components:` token block.

### Buttons
- **`button-primary`** — Black (`{colors.primary}`) fill, white text, 0px radius, 14px uppercase bold Helvetica. `padding: 14px 20px`. Hover softens to `{colors.primary-hover}`. The primary conversion action: "SIGN UP", "ADD TO BAG", form submits.
- **`button-secondary`** — `{colors.surface}` neutral fill, `{colors.ink-muted}` label, same 0px radius. Used for utility actions in search and filter contexts.
- **`button-ghost`** — Transparent fill with `1px solid {colors.border-dark}` outline, black text. Used for secondary CTAs alongside a primary action.

### Cards
- **`card`** — White surface, no border, no shadow, `{rounded.none}`. A pure display frame.
- **`card-product`** — White fill, 10px bottom padding below image, 14px regular Helvetica for product name and price. Photography sits edge-to-edge at top; type floats below.

### Inputs
- **`input`** — White fill, `border: 1px solid {colors.border}` (effectively transparent at default over dark modal), 7px 14px padding, 0px radius. Focus state: `{colors.border-dark}` border, `{colors.focus-tint}` shadow, `2px solid {colors.focus-ring}` outline.

### Navigation
- **`nav-bar`** — `{colors.surface-dark}` black fill, `{colors.ink-on-dark}` white text, 14px medium Helvetica. 10px 20px padding. Sticky across all breakpoints; collapses to hamburger below 991px.

### Badges / Tags
- **`badge`** — `{colors.surface}` fill, `{colors.ink-muted}` uppercase caption text, 0px radius. "NEW", "LAST PIECES" product flags.
- **`badge-pill`** — `{colors.primary}` black fill, white text, 100px radius. Quantity indicators, cart counts.

## Do's and Don'ts

### Do
- Use `{colors.surface-dark}` black for the navigation — it is the system's defining contrast signature, not an option
- Apply `{typography.button-ui}` uppercase bold to every CTA label — weight and case together produce the Ganni commercial voice
- Keep all native UI elements at `{rounded.none}` — the pill and sm tokens are product-catalogue and framework seams only
- Let photography fill completely to the nav bottom edge — no hero wrapper with internal padding or background tint
- Use `{colors.ink-muted}` (`#686a6a`) for secondary text, captions, and inactive states — the warm gray keeps utility copy from reading as cold metadata
- Apply motion at 0.15–0.25s ease-in only — button transitions, nav slide, image hover filter; no parallax, no scroll-triggered reveal
- Reference `{colors.link-forest}` only in sustainability and responsibility contexts — it is a semantic signal, not a general accent
- Set focus states with both `{colors.focus-ring}` outline and `{colors.focus-tint}` shadow — both are present in the extracted component data

### Don't
- Don't introduce a chromatic brand accent for UI — black is the only CTA color; `{colors.link-forest}` is section-specific, not a general accent
- Don't soften buttons or cards with any border radius — the 3px on cookie alerts is a third-party seam, not permission to round product UI
- Don't use aggressive letter-spacing — Ganni applies no tracking; natural spacing at all sizes
- Don't vary the page canvas with tinted section bands — `{colors.surface}` appears only in utility UI (search bars, filter drawers), never as section backgrounds
- Don't use a second typeface — Helvetica Neue For Ganni alone, across all roles; no contrasting serif for editorial, no monospace for product codes
- Don't shadow product cards — elevation appears only at modal and drawer level, never at card level
- Don't use lowercase for button labels — uppercase is non-negotiable for primary actions
- Don't use `{colors.ink-muted}` for primary body copy — it is the secondary ink; running text always uses `{colors.ink}` black

---

## Responsive Behavior

### Breakpoints
| Name | Width | Key Changes |
|---|---|---|
| Mobile XS | < 350px | Single column; reduced nav; body at minimum size |
| Mobile S | 350–449px | Single column; full hamburger nav; hero type scales down |
| Mobile | 450–575px | Single column; product grid 2-up where density allows |
| Mobile L | 576–767px | Two-column product grid; persistent promo strip |
| Tablet | 768–991px | Two-column grid; nav still collapsed to hamburger |
| Tablet L | 992–1199px | Three-column grid; partial desktop nav |
| Desktop | 1200–1439px | Full four-column grid; complete horizontal nav |
| Large Desktop | ≥ 1440px | Max-width container; full editorial layout |

### Touch Targets
- Primary buttons run at minimum 48px effective height from 14px padding — comfortable tap zones
- Nav items on mobile at 20px vertical padding with full-row tap region
- Product tiles are fully tappable card regions, not just the image or title
- Cart and wishlist icons in nav run at icon-only touch targets; supplemented by icon size (approx 24px) plus tap zone padding

### Collapsing Strategy
- **Navigation**: black horizontal bar → hamburger icon at 991px; slide-in panel with full-screen overlay and `{colors.surface-dark}` background maintaining the dark-nav language on mobile
- **Type scale**: display hero scales from 64px to approximately 32–40px on mobile; body stays at 14–16px across breakpoints
- **Product grids**: 4-column desktop → 3-column tablet-L → 2-column tablet/mobile → 1-column mobile XS for large product cards
- **Spacing**: 40px desktop section gaps compress to 20–30px on mobile; the efficient rhythm is preserved rather than opening up

### Image Behavior
- Campaign photography is always full-bleed — no padding, no max-width cap on hero images; the nav floats above
- Product tile images maintain consistent aspect ratio across breakpoints; portrait format is standard
- Image hover: `filter` transition at 0.4s ease — a subtle warm or desaturate effect, the only image-level interaction

---

## Agent Prompt Guide

### Quick Color Reference
- Background: White (`{colors.background}`)
- Primary text: Ink Black (`{colors.ink}`)
- Navigation: `{colors.surface-dark}` (black)
- Nav text: `{colors.ink-on-dark}` (white)
- CTA fill: `{colors.primary}` (black)
- CTA text: `{colors.on-primary}` (white)
- Secondary text: `{colors.ink-muted}` (#686a6a)
- Surface / panel: `{colors.surface}` (#f1f1f1)

### Example Component Prompts

- "Create a full-bleed hero for Ganni: `{colors.surface-dark}` black navigation bar, 14px `{typography.nav-link}` Helvetica Neue For Ganni in `{colors.ink-on-dark}` white, GANNI wordmark left-anchored. Below it, a campaign photograph running to all four edges of its container with no padding or radius. Overlay the hero title in white 64px bold Helvetica at `{typography.display-hero}` bottom-left positioned over the image."

- "Build a primary CTA button: `{colors.primary}` black fill, `{colors.on-primary}` white text, `{typography.button-ui}` (14px bold, uppercase, letter-spacing normal), `{rounded.none}` (0px radius), `padding: 14px 20px`, no border. Hover transitions backgroundColor to `{colors.primary-hover}` at 0.15s ease-in. Label: 'ADD TO BAG'."

- "Design a product tile for Ganni: white `{colors.background}` surface, `{rounded.none}`, no shadow, no border. Full-width portrait image at top (no radius, no padding). Below: 14px `{typography.body}` Helvetica in `{colors.ink}` for product name; 14px regular in `{colors.ink-muted}` for price. Include a 'NEW' flag using `{components.badge}` (neutral fill, uppercase caption, 0px radius) absolute-positioned top-left over the image."

- "Create an email signup modal: white `{colors.background}` container, `{rounded.none}`, soft `rgba(0,0,0,0.3)` overlay behind it. Heading in 24px `{typography.heading-section}` Helvetica bold in `{colors.ink}`. Body copy 14px `{typography.body}` in `{colors.ink}`. Email input at `{components.input}` — white fill, transparent default border, `padding: 7px 14px`, 0px radius. Below: black `{components.button-primary}` CTA labeled 'SIGN UP'. On input focus: `2px solid {colors.focus-ring}` outline plus `{colors.focus-tint}` glow."

- "Build the Ganni navigation bar: full-width `{colors.surface-dark}` black fill, 10px 20px padding. Left: GANNI wordmark in `{colors.ink-on-dark}` white, `{typography.nav-link}` bold. Center: category links (New Arrivals, Bags, Ready-to-Wear, Shoes, Accessories, Gifts, Sale) in 14px medium white Helvetica, spaced evenly. Right: Search, Wishlist, Account, Bag icons in `{colors.ink-on-dark}`. Sticky at top; collapses to hamburger icon below 991px breakpoint."

### Iteration Guide

1. **Canvas**: start with `{colors.background}` white content body; anchor the top with a `{colors.surface-dark}` black nav — this contrast is Ganni's defining feature
2. **Typeface only**: Helvetica Neue For Ganni (fallback: Helvetica Neue, Arial) — three weights, no second family, no custom display face
3. **CTA weight**: primary actions always weight 700, uppercase, `{typography.button-ui}` — this is where the brand voice lives, not in decorative elements
4. **Shape**: 0px radius on everything native — buttons, cards, inputs, modals; only third-party UI seams deviate
5. **Photography first**: hero images should bleed to all edges; the grid is a minimal armature for full-bleed photography
6. **Color hierarchy**: `{colors.ink}` for body, `{colors.ink-muted}` for secondary, `{colors.ink-on-dark}` for anything over the black nav — three ink tiers, no mixing
7. **Motion**: 0.15s ease-in for button hover, 0.25s ease for nav slide, 0.4s ease for image hover filter — no parallax, no scroll-triggered animation

---

## 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 Ganni. Brand names and trademarks belong to their respective owners.
