# Rhode — Marketing site Design Spec

> Source: rhodeskin.com (live DOM, computed styles), 2026-07-26. Shopify build;
> 0 stylesheets blocked. **§2 is read from the colour census, not from tokens** —
> all 52 `:root` properties belong to third-party widgets (Okendo `--oke-*`,
> `--bdp-*`, `--rc-*`), so the brand palette is hard-coded in the theme. Three
> component vars ARE brand: `--base-color: #67645e`, `--label-color: #fff`,
> `--base-spacing: .3rem 1.9rem .2rem`. **Excluded as dead CSS:** Foundation's
> `.o-button` family (hover `#cf000f` red) — `querySelectorAll('.o-button').length === 0`,
> so that red is framework leftovers, not a Rhode colour. Also excluded: Swiper,
> Shopify checkout, PhotoSwipe and accessibility-widget chrome (`#007aff`,
> `#363638`, `#ebebf0`).
> Reality check: **"glossy minimal cream" holds; "tight serif wordmark" is wrong.**
> The display face is **Rektorat Heavy — a heavy SANS set lowercase** at
> 60.48/72.576 with **-4% tracking**. The site is monochrome-with-one-colour: a
> single warm taupe `#67645e` does text, hairlines, rings and fills. The find
> neither hint mentions: the button hover is a **four-way directional `clip-path`
> wipe** driven by four triangular hit zones, 400 of them live on the homepage.

## 1. Visual Theme &amp; Atmosphere

Quiet, warm and almost entirely monochrome — a photography-led beauty site where one taupe does nearly all the work. The canvas is plain `#ffffff` and the warmth arrives as full-bleed `#f1f0ed` cream bands, not as a tinted body. Every neutral is warm-biased: the workhorse `#67645e` is a greenish-taupe, never a cool grey. Type is disciplined to the point of severity — the UI runs almost entirely **uppercase Swiss at 17px with +2% tracking**, and the only expressive voice is Rektorat Heavy set **lowercase** and very tight. Depth is refused: there are effectively two shadows on the page and both are 1px *inset* rings, so nothing floats. Everything rounded is a 40px pill. Motion is slow and symmetric — `cubic-bezier(.76,0,.24,1)` at 0.7s — and the one moment of real craft is the button, whose fill wipes in from whichever edge the cursor crossed. Feels: warm, minimal, glossy, disciplined, editorial.

## 2. Color Palette &amp; Roles

| Token | Hex / value | Role / usage |
|---|---|---|
| white | #ffffff | body canvas + text on imagery (1552 text / 252 fill uses) |
| cream | #f1f0ed | THE section band — dominant large surface (14 section fills) |
| cream-80 | rgba(241,240,237,.8) | translucent cream overlay |
| taupe (`--base-color`) | #67645e | primary text, hairline, inset ring, fill — 3082 text / 358 fill uses |
| taupe-light | #84827e | secondary text, alt fill, `.Button__gray-backgroung` hover |
| taupe-faint | #acaaa5 | tertiary / muted text |
| warm-grey | #dddedc | alternating-row / subtle hover fill |
| black | #000000 | link hover + text (274 uses) |
| white-90 | rgba(255,255,255,.9) | sticky chrome fill (17 uses) |
| white-70 / white-50 | rgba(255,255,254,.7) / rgba(255,255,255,.5) | scrim / control fills |
| scrim | rgba(0,0,0,.3) / rgba(0,0,0,.75) | image dimmers (3 / 1 uses) |
| hairline-c4 | #c4c4c4 | 1px form border |
| hairline-cc | #cccccc | 1px border, minor |
| grey-a3 | #a3a3a3 | disabled + focused-input border tint |
| off-white-f5 | #f5f5f5 | 2px border, minor |

The whole page is `#ffffff` + `#f1f0ed` + `#67645e`; everything else is a hairline or a scrim. No gradient palette — the page has **exactly one** CSS gradient, `radial-gradient(50% 50%, #f1f0ed, #a3a09b 0.01%, #d3d3d3)`.

## 3. Typography Rules

One brand sans (`Swiss`, licensed) plus one display sans (`Rektorat Heavy`, licensed). No serif anywhere; no mono anywhere. Preview substitutes **Inter** for Swiss and **Archivo Black** for Rektorat Heavy (one webfont link).

| Role | Family | Size / line | Weight | Tracking | Case |
|---|---|---|---|---|---|
| Display | Rektorat Heavy | 60.48 / 72.576 | 400 | **-2.4192px (-4%)** | lowercase |
| Display, micro | Rektorat Heavy | 10 / **7.5** | 400 | -0.4px | lowercase |
| Section head | Swiss | 37.8 / 45.36 | 400 | -0.756px | none |
| UI workhorse | Swiss | 17.024 / 25.536 | **700** | +0.34048px | **uppercase** |
| Button label | Swiss | 17.024 / 25.536 | 400 | +0.34048px | uppercase |
| Nav / link | Swiss | 17.01 / 25.515 | 700 | +0.3402px | none |
| Product name | Swiss | 14 / 16.8 | 700 | +0.28px | uppercase |
| Body | Swiss | 14 / 21 | 400 | +0.28px | none |
| Announcement bar | Swiss | 12 / 14 | 700 | +0.24px | uppercase |

Two things to copy. The **inverted tracking logic** — the display face gets strong NEGATIVE tracking (-4%) while every small UI size gets POSITIVE tracking (+2%), tight where it's big and open where it's small. And the micro Rektorat tag sets **line-height below font size** (10px on 7.5px) so the badge crops to the letterforms.

Caveat, recorded rather than hidden: the `<h1>` computes to **176/211.2 Swiss 400 white** but renders inside a **551×57px** box — an overflow/marquee element, not the display role. Rektorat Heavy at 60.48px is the real display treatment.

## 4. Component Stylings

**Button** (`.Button`, 40px pill) — the system's centrepiece. `background: transparent`, `border-radius: 40px`, `text-transform: uppercase`, `overflow: hidden`, weight 400, `padding: .3rem 1.9rem .2rem` (asymmetric — more top than bottom), fluid `font-size: max(0.875rem + 0.2vw, 0.925vw)`, ~34px tall at 1512px, and **no border**: the outline is `box-shadow: inset 0 0 0 1px var(--base-color)`. Variants all share that construction:

| Variant | Rest | Notes |
|---|---|---|
| `.Button__dark` | taupe label + taupe inset ring | default |
| `.Button__dark.active` | white label | toggled |
| `.Button__transparent` | transparent fill, taupe ring | hover label → #ffffff |
| `.Button__white` | #ffffff fill, taupe ring | hover label → #ffffff |
| `.Button__filled.Button__dark` | #67645e fill, #ffffff label | the solid CTA |
| `.Button__gray-backgroung` | hover content fills #84827e | (sic — typo is theirs) |
| `.Button__dark__whiteOnActive` | fills #ffffff when `.active` | segmented use |
| `.Button__link` / `.Button__text-only` / `.Button__text-only-underline` | no pill | hover/focus → `text-decoration: underline`; wipe disabled (`display:none` on the helpers) |

**The hover mechanic — a four-way directional wipe.** Each pill contains a `.Button-hover-content` (absolute `inset: 0`, `border-radius: 40px`, same inset ring, `opacity: 0`, at rest `clip-path: inset(0 0 100% round 40px)`) plus **four** `.Button-hover-helper` triangular wedges at `z-index: 1` meeting at the centre — `data-index` 1 `polygon(0 0, 100% 0, 50% 50%, 50% 50%)` top, 2 `polygon(100% 0, 100% 100%, 50% 50%)` right, 3 `polygon(0 100%, 100% 100%, 50% 50%)` bottom, 4 `polygon(0 0, 0 100%, 50% 50%)` left. Hovering a wedge (`[data-index="N"]:hover ~ .Button-hover-content`) sets `opacity: 1` and re-clips the content, so the fill slides in from the edge the cursor actually crossed. `transition: clip-path .25s, opacity 0s .25s, visibility 0s .25s` — the clip animates while the opacity flips instantly and only on the way out. Separately `[data-mode="wave"]` carries `transition: color 1.25s`, so the **label recolours five times slower than the fill arrives**. 400 helpers were live (≈100 × 4).

**Inputs** — email 52px, `#ffffff` fill, `border-radius: 12px 0 0 12px` (it butts against a 52px `0 12px 12px 0` SUBSCRIBE button to form one 12px capsule), 16px padding, 17.584px text, `#67645e` placeholder. Also a 59px 10px-radius search field and a 39px 3.5px-radius select. `input:disabled` → `#f1f0ed` fill.

**Focus — anti-pattern, do not copy.** `[type="email"]:focus` sets `outline: none; box-shadow: none;` and only shifts `border-color` to `#a3a3a3` over `.25s ease-in-out`; and `a:hover, a:focus` share one rule (`color: #000000`), so keyboard focus is visually identical to hover. Recommended replacement in the brand's own colour: `box-shadow: 0 0 0 2px #ffffff, 0 0 0 4px #67645e`.

**Cards** — product tiles are borderless, radius 12px (or the compound `20px 20px 12px 12px`), on `#ffffff` or `#f1f0ed`, separated by 2 / 9.6 / 10px gaps rather than by rules.

## 5. Layout Principles

Full-bleed alternating bands — white, then cream `#f1f0ed`, then imagery — each 600–790px tall, no visible container edge. Text columns cap at **1024px** (with 400/480px measure caps inside); everything else runs edge to edge. Gaps are small and deliberate: **10px** and **2px** dominate (60–66 uses each), with 9/9.6px for tile grids and **43px** for section rhythm. `max-width: 100%` is the default, so imagery drives the grid.

## 6. Depth &amp; Elevation

Depth is refused. Radius census: **40px (891 uses — the pill is the system)**, then 12px (71), 10px (69), 8px (60), 50% (47), two compound values — `20px 20px 12px 12px` (17) and `0 12px 12px 0` (10, the subscribe capsule) — plus 4px (4).

Shadows — only two matter, and **both are 1px inset rings**, not drops: `#67645e 0 0 0 1px inset` (536 uses — THE outline for buttons, chips and cards) and `#ffffff 0 0 0 1px inset` (36, the same ring on imagery). Four one-offs exist: `rgba(0,0,0,.24) 0 1px 2px`, `rgba(0,0,0,.2) 0 1px 10px 1px`, `rgba(0,0,0,.25) 0 0 30px` and `rgba(0,0,0,.25) 0 0 100px` (ambient). Borders are hairlines: **0.5px #67645e** (8), 1px #c4c4c4 (6), 1px #67645e (2), 1px #84827e (1).

## 7. Motion

Slow and symmetric. The dominant easing is **`cubic-bezier(.76,0,.24,1)`**
(easeInOutQuart) at **0.7s** on `all` (170 uses) and on `background-color, opacity`
(25 uses) — a long, even in-and-out with no overshoot anywhere. Supporting:
`opacity .3s ease-out` (145), `all .3s ease-in-out` (13), `border-color .25s
ease-in-out` (6), and `cubic-bezier(.075,.82,.165,1)` (easeOutCirc). The button
wipe is `clip-path .25s` (400 uses) against a `color 1.25s` label crossfade.

Brand `@keyframes`: `footer-logo-jello`, `spotwear-fall`, `clockwise`,
`donut-rotate`, `draw`, `erase`. (`swiper-preloader-spin`, `shopify-rotator`,
`shopify-dash`, `oke-spin`, `oke-fade-in`, `animated-checkmark-fill`,
`acceleratedCheckoutLoadingSkeleton` are third-party.) **No JS motion library** —
no GSAP, Lenis, Framer Motion, Lottie, Rive or AOS. **1 reduced-motion block.**

## 8. Backgrounds / Effects / WebGL

Photography, not effects. **No canvas, no WebGL, no `<video>`** at capture, **zero grain layers**, 10 raster background layers, and exactly **one** CSS gradient (the radial above). Backdrop blur at three grades: `blur(2px)`, `blur(4px)`, `blur(10px)`.

## 9. Do's and Don'ts

### Do
- Let **one warm taupe `#67645e`** carry text, hairlines, rings and fills — resist a second colour.
- Deliver warmth with full-bleed `#f1f0ed` cream bands over a **white** canvas, not by tinting the body.
- Use the **40px pill** as the universal radius and a **1px inset ring** as the universal outline.
- Invert the tracking logic: **-4% on the display**, **+2% on small uppercase UI**; set the display **lowercase** in a heavy sans, never a serif.
- Build hover as a **directional `clip-path` wipe** from four triangular hit zones, and recolour the label far slower than the fill arrives (0.25s wipe vs 1.25s colour).
- Keep motion long and symmetric: `cubic-bezier(.76,0,.24,1)` at 0.7s.

### Don't
- Don't add drop shadows — depth here is inset rings and colour steps only.
- Don't use a cool grey (every neutral is warm-biased) or set the display in a serif or title case.
- Don't reach for gradients, grain or WebGL — there is one gradient on the whole page.
- Don't copy the focus behaviour: it suppresses `outline` and `box-shadow`, and `a:focus` duplicates `a:hover`.
- Don't scale the UI type up; 14–17px uppercase is the register.

## 10. Responsive Behavior

**55 breakpoints** — a Shopify theme layered over Foundation, so two ladders
coexist. The Foundation em ladder is the structural one:

| Breakpoint | What changes |
|---|---|
| 40em (640px) | small → medium |
| 51.3125em (821px) | medium interstitial |
| 63.9375em (1023px) | medium ceiling |
| 64em (1024px) | medium → large |
| 75em (1200px) | large → xlarge |
| 112.5em (1800px) | xxlarge |
| 40rem / 77.5rem | theme-authored pair |

On top sits a dense px overlay (375, 385, 425, 442, 497, 500, 525, 540, 640, 690,
750, 760, 767, 768, 780, 820, 1039, 1040, 1080, 1090, 1095, 1240, 1440, 1600,
2000, 2050 …) — device-specific patches, not a scale. **5 container queries. 0
dark-scheme blocks** (no dark theme, no toggle). **1 reduced-motion block.**

## 11. Agent Prompt Guide

- Canvas `#ffffff` · Band `#f1f0ed` · One colour `#67645e` taupe (text + ring + fill) · Secondary `#84827e` · Muted `#acaaa5` · Hover `#000000`
- Font: **Rektorat Heavy** display 60.48/72.576 **lowercase -4%** + **Swiss** UI 17.024/25.536 **700 uppercase +2%**, body 14/21 (subs: Archivo Black + Inter) · Radius: **40px pill** dominant
- Outline: `box-shadow: inset 0 0 0 1px #67645e` — no borders, **no drop shadows** · Focus: **suppressed** — add `0 0 0 2px #fff, 0 0 0 4px #67645e`
- Hover: directional `clip-path` wipe from 4 triangular zones, `clip-path .25s` + `color 1.25s` · Motion: `cubic-bezier(.76,0,.24,1)` 0.7s

<rhode_design_language>
Quiet, warm and almost entirely monochrome — a photography-led beauty system where
ONE colour does nearly all the work. Canvas is plain #ffffff and the warmth arrives
as full-bleed #f1f0ed cream bands rather than a tinted body; a single warm taupe
#67645e carries text, hairlines, rings AND fills, supported only by #84827e,
#acaaa5, #dddedc and #000000 on hover. Every neutral is warm-biased — never a cool
grey — and there is exactly ONE gradient on the whole page, no grain, no WebGL, no
video. Type is two sans faces and no serif: Rektorat Heavy, a HEAVY SANS set
LOWERCASE at 60.48/72.576 with -2.4192px (-4%) tracking, over Swiss running the
entire UI as 17.024/25.536 weight 700 UPPERCASE with +0.34px (+2%) tracking, body
14/21, product names 14/16.8 uppercase. Copy the inverted tracking logic: strongly
negative on the big display face, positive on every small uppercase size. Depth is
refused — the 40px PILL is the universal radius (891 uses) and a 1px INSET RING
(box-shadow: inset 0 0 0 1px #67645e, 536 uses) is the universal outline, with no
borders and effectively no drop shadows. The signature is the button: transparent,
overflow-hidden, 40px radius, uppercase, asymmetric .3rem 1.9rem .2rem padding, and
a hover that is a DIRECTIONAL CLIP-PATH WIPE — four triangular hover zones meeting
at the centre (top/right/bottom/left polygons) each re-clip an inset(0 0 100% round
40px) fill layer, so it slides in from whichever edge the cursor crossed, over
clip-path .25s, while the label recolours across a much slower color 1.25s. Layout
is full-bleed alternating bands 600-790px tall with text capped at 1024px and small
2px/10px gaps. Motion is long and symmetric: cubic-bezier(.76,0,.24,1) at 0.7s, no
overshoot, no JS motion library. Feels: warm, minimal, glossy, disciplined,
editorial. Avoid: drop shadows, cool greys, serif or title-case display, gradients
and grain, scaling the UI type up, and copying the focus behaviour — the site
suppresses outline and box-shadow on focus and a:focus duplicates a:hover, so add
box-shadow: 0 0 0 2px #fff, 0 0 0 4px #67645e instead.
</rhode_design_language>
