slow editorial · print-led · warm restraint · craft modernism · unhurried
This document is one part of a Taste Lens read. Every read also includes the eight-perspective analysis, copy-paste style prompts with flavors for Midjourney, Stable Diffusion and DALL·E, and exports for AI tools & mood boards (AI brief, palette card, style page) as well as code & design apps (shadcn, Tailwind, CSS, JSON, .ASE swatches, Figma tokens).
#f4efe6Page ground
#e9e2d3Raised panels
#221d15Primary text
#8a8171Secondary text
#b3502dAction + emphasis
#dbd6cdBorders, rules
Download SVG card · Download .ase swatches — imports into Photoshop, Illustrator, Procreate
| Pairing | Ratio | Verdict |
|---|---|---|
| Body text on page | 14.62:1 | AAA |
| Body text on surface | 12.98:1 | AAA |
| Secondary text on page | 3.36:1 | AA large only |
| Secondary text on surface | 2.98:1 | FAIL |
| Accent text on page | 4.47:1 | AA large only |
| Page on accent (buttons) | 4.47:1 | AA large only |
| Border against page | 1.26:1 | LOW |
Old-style serif with warmth and personality for branding; narrower tracking and tight leading enforce modernist formality against its humanist curves.
Quiet, neutral sans that disappears in long measure; generous line-height enforces slow reading pace and print-like generosity.
Modular scale · ratio 1.25 · base 16px
Letterpress rigour demands square corners and no shadow depth; hairline rules inherit print's structural authority; 8px spacing clips to an invisible eighth-inch grid.
| Radius | square · 0px |
| Border | 0.5px |
| Elevation | none |
| Motion | 400ms · cubic-bezier(0.4, 0.0, 0.2, 1) |
Slow cubic easing mirrors the unhurried reading pace; 400ms is felt but never announces itself, matching the sub-perceptual texture approach.
button_style: outlined — Outlined terracotta border with no fill; text in the accent colour; monocase labels in smallcaps; on hover fill the interior with a 10% tint of terracotta to match the restraint.
Hairline cream border on the surface colour, no shadow; label above in body serif at the secondary value; cursor and focus state only add a terracotta underline, never a box around the field.
Supporting copy in the secondary tone, one step down the scale.
Cream background with a hairline rule below instead of a border; 3% opacity fibre noise visible only where the panel edge meets the background; generous internal padding enforces the print broadsheet …
:root{
--bg: #f4efe6;
--surface: #e9e2d3;
--ink: #221d15;
--dim: #8a8171;
--accent: #b3502d;
--line: #dbd6cd;
--accent-50: #f9f1ee;
--accent-100: #f3e3dd;
--accent-200: #e7c7bc;
--accent-300: #d7a492;
--accent-400: #c57a5f;
--accent-500: #b3502d;
--accent-600: #964326;
--accent-700: #7a361f;
--accent-800: #5a2817;
--accent-900: #3d1b0f;
--radius: 0px;
--shadow: none;
--space-0: 0px;
--space-1: 8px;
--space-2: 16px;
--space-3: 24px;
--space-4: 32px;
--space-6: 48px;
--space-8: 64px;
--space-12: 96px;
--space-16: 128px;
--space-24: 192px;
--font-display: Crimson Text, Georgia, serif;
--font-body: Inter, -apple-system, BlinkMacSystemFont, sans-serif;
--font-mono: IBM Plex Mono, Menlo, monospace;
--weight-display: 600;
--weight-body: 400;
--leading-display: 1.2;
--leading-body: 1.7;
--tracking-display: −0.02em;
--tracking-body: 0em;
--text-xs: 10px;
--text-sm: 13px;
--text-base: 16px;
--text-lg: 20px;
--text-xl: 25px;
--text-2xl: 31px;
--text-3xl: 39px;
--text-display: 49px;
}
/* Text styles — size, family, weight and leading together */
.text-xs{font:400 10px/1.7 Inter, -apple-system, BlinkMacSystemFont, sans-serif;letter-spacing:0em}
.text-sm{font:400 13px/1.7 Inter, -apple-system, BlinkMacSystemFont, sans-serif;letter-spacing:0em}
.text-base{font:400 16px/1.7 Inter, -apple-system, BlinkMacSystemFont, sans-serif;letter-spacing:0em}
.text-lg{font:400 20px/1.7 Inter, -apple-system, BlinkMacSystemFont, sans-serif;letter-spacing:0em}
.text-xl{font:600 25px/1.2 Crimson Text, Georgia, serif;letter-spacing:−0.02em}
.text-2xl{font:600 31px/1.2 Crimson Text, Georgia, serif;letter-spacing:−0.02em}
.text-3xl{font:600 39px/1.2 Crimson Text, Georgia, serif;letter-spacing:−0.02em}
.text-display{font:600 49px/1.2 Crimson Text, Georgia, serif;letter-spacing:−0.02em}
This is the exact CSS rendering the components above. Paste it after the custom properties.
/* Buttons */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--space-2);
border:var(--border) solid transparent;border-radius:var(--radius);
padding:var(--space-1) var(--space-3);cursor:pointer;
font:var(--weight-body) var(--text-sm)/1 var(--font-body);
transition:background var(--duration) var(--easing),color var(--duration) var(--easing)}
.btn--primary{background:transparent;color:var(--accent);border-color:var(--accent)}
.btn--primary:hover{background:var(--accent);color:#ffffff}
.btn--secondary{background:transparent;color:var(--ink);border-color:var(--line)}
.btn--secondary:hover{border-color:var(--ink)}
.btn--ghost{background:transparent;color:var(--dim);border-color:transparent}
.btn--ghost:hover{color:var(--ink)}
.btn:disabled{opacity:.42;cursor:not-allowed;filter:none}
/* Form field */
.field{display:block}
.field__label{display:block;margin-bottom:var(--space-1);
font:600 var(--text-xs)/1 var(--font-body);color:var(--ink)}
.field__input{width:100%;padding:var(--space-1) var(--space-2);
border:var(--border) solid var(--line);border-radius:var(--radius);
background:var(--bg);color:var(--ink);font:var(--text-sm)/1 var(--font-body)}
.field__input::placeholder{color:var(--dim)}
.field__input:focus{outline:2px solid var(--accent);outline-offset:1px;border-color:var(--accent)}
.field__input[aria-invalid="true"]{border-color:var(--accent)}
.field__error{margin-top:var(--space-1);color:var(--accent);font-size:var(--text-xs)}
/* Card */
.card{background:var(--surface);border:var(--border) solid var(--line);
border-radius:var(--radius);padding:var(--space-3);box-shadow:var(--shadow)}
.card__title{margin:0 0 var(--space-1);font:var(--weight-display) var(--text-lg)/1.3 var(--font-display)}
.card__body{margin:0;color:var(--dim);font:var(--text-sm)/1.6 var(--font-body)}
/* Tag */
.tag{display:inline-block;background:var(--accent-100);color:var(--accent-800);
border-radius:var(--radius);padding:2px var(--space-1);
font:600 var(--text-xs)/1.5 var(--font-mono)}
{
"colors": {
"bg": "#f4efe6",
"surface": "#e9e2d3",
"ink": "#221d15",
"dim": "#8a8171",
"accent": {
"50": "#f9f1ee",
"100": "#f3e3dd",
"200": "#e7c7bc",
"300": "#d7a492",
"400": "#c57a5f",
"500": "#b3502d",
"600": "#964326",
"700": "#7a361f",
"800": "#5a2817",
"900": "#3d1b0f",
"DEFAULT": "#b3502d"
},
"line": "#dbd6cd"
},
"borderRadius": {
"DEFAULT": "0px"
},
"fontFamily": {
"display": [
"Crimson Text"
],
"body": [
"Inter"
],
"mono": [
"IBM Plex Mono"
]
},
"fontSize": {
"xs": [
"10px",
{
"lineHeight": "1.7",
"letterSpacing": "0em",
"fontWeight": "400"
}
],
"sm": [
"13px",
{
"lineHeight": "1.7",
"letterSpacing": "0em",
"fontWeight": "400"
}
],
"base": [
"16px",
{
"lineHeight": "1.7",
"letterSpacing": "0em",
"fontWeight": "400"
}
],
"lg": [
"20px",
{
"lineHeight": "1.7",
"letterSpacing": "0em",
"fontWeight": "400"
}
],
"xl": [
"25px",
{
"lineHeight": "1.2",
"letterSpacing": "−0.02em",
"fontWeight": "600"
}
],
"2xl": [
"31px",
{
"lineHeight": "1.2",
"letterSpacing": "−0.02em",
"fontWeight": "600"
}
],
"3xl": [
"39px",
{
"lineHeight": "1.2",
"letterSpacing": "−0.02em",
"fontWeight": "600"
}
],
"display": [
"49px",
{
"lineHeight": "1.2",
"letterSpacing": "−0.02em",
"fontWeight": "600"
}
]
},
"fontWeight": {
"display": "600",
"body": "400"
},
"letterSpacing": {
"display": "−0.02em",
"body": "0em"
},
"spacing": {
"0": "0px",
"1": "8px",
"2": "16px",
"3": "24px",
"4": "32px",
"6": "48px",
"8": "64px",
"12": "96px",
"16": "128px",
"24": "192px"
},
"boxShadow": {
"DEFAULT": "none"
}
}
The shadcn variable theme and the v4 @theme mapping in one file. Dark theme is derived — treat it as a starting point.
/* Taste Lens — shadcn/ui theme (+ Tailwind v4 @theme)
Vibe: slow editorial, print-led, warm restraint, craft modernism, unhurried
Drop into your globals.css. Dark theme is derived from the light read — tune it. */
:root {
--radius: 0.5rem;
--background: #f4efe6;
--foreground: #221d15;
--card: #e9e2d3;
--card-foreground: #221d15;
--popover: #e9e2d3;
--popover-foreground: #221d15;
--primary: #b3502d;
--primary-foreground: #ffffff;
--secondary: #e9e2d3;
--secondary-foreground: #221d15;
--muted: #e9e2d3;
--muted-foreground: #8a8171;
--accent: #f3e3dd;
--accent-foreground: #5a2817;
--destructive: #b3261e;
--border: #dbd6cd;
--input: #dbd6cd;
--ring: #b3502d;
}
.dark {
--background: #1a1610;
--foreground: #f4efe6;
--card: #25221c;
--card-foreground: #f4efe6;
--popover: #25221c;
--popover-foreground: #f4efe6;
--primary: #b3502d;
--primary-foreground: #ffffff;
--secondary: #25221c;
--secondary-foreground: #f4efe6;
--muted: #25221c;
--muted-foreground: #aba69d;
--accent: #5a2817;
--accent-foreground: #f3e3dd;
--destructive: #e5484d;
--border: #3a3731;
--input: #3a3731;
--ring: #b3502d;
}
/* Tailwind v4 — exposes the variables above as color utilities (bg-background, …) */
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
}
{
"global": {
"color": {
"bg": {
"value": "#f4efe6",
"type": "color"
},
"surface": {
"value": "#e9e2d3",
"type": "color"
},
"ink": {
"value": "#221d15",
"type": "color"
},
"dim": {
"value": "#8a8171",
"type": "color"
},
"accent": {
"value": "#b3502d",
"type": "color"
},
"line": {
"value": "#dbd6cd",
"type": "color"
},
"accent-ramp": {
"50": {
"value": "#f9f1ee",
"type": "color"
},
"100": {
"value": "#f3e3dd",
"type": "color"
},
"200": {
"value": "#e7c7bc",
"type": "color"
},
"300": {
"value": "#d7a492",
"type": "color"
},
"400": {
"value": "#c57a5f",
"type": "color"
},
"500": {
"value": "#b3502d",
"type": "color"
},
"600": {
"value": "#964326",
"type": "color"
},
"700": {
"value": "#7a361f",
"type": "color"
},
"800": {
"value": "#5a2817",
"type": "color"
},
"900": {
"value": "#3d1b0f",
"type": "color"
}
}
},
"fontFamilies": {
"display": {
"value": "Crimson Text",
"type": "fontFamilies"
},
"body": {
"value": "Inter",
"type": "fontFamilies"
},
"mono": {
"value": "IBM Plex Mono",
"type": "fontFamilies"
}
},
"fontWeights": {
"display": {
"value": "600",
"type": "fontWeights"
},
"body": {
"value": "400",
"type": "fontWeights"
},
"regular": {
"value": "400",
"type": "fontWeights"
}
},
"fontSize": {
"xs": {
"value": "10",
"type": "fontSizes"
},
"sm": {
"value": "13",
"type": "fontSizes"
},
"base": {
"value": "16",
"type": "fontSizes"
},
"lg": {
"value": "20",
"type": "fontSizes"
},
"xl": {
"value": "25",
"type": "fontSizes"
},
"2xl": {
"value": "31",
"type": "fontSizes"
},
"3xl": {
"value": "39",
"type": "fontSizes"
},
"display": {
"value": "49",
"type": "fontSizes"
}
},
"lineHeights": {
"xs": {
"value": "17",
"type": "lineHeights"
},
"sm": {
"value": "22",
"type": "lineHeights"
},
"base": {
"value": "27",
"type": "lineHeights"
},
"lg": {
"value": "34",
"type": "lineHeights"
},
"xl": {
"value": "30",
"type": "lineHeights"
},
"2xl": {
"value": "37",
"type": "lineHeights"
},
"3xl": {
"value": "47",
"type": "lineHeights"
},
"display": {
"value": "59",
"type": "lineHeights"
}
},
"letterSpacing": {
"display": {
"value": "−0.02em",
"type": "letterSpacing"
},
"body": {
"value": "0em",
"type": "letterSpacing"
}
},
"typography": {
"xs": {
"value": {
"fontFamily": "Inter",
"fontWeight": "400",
"fontSize": "10",
"lineHeight": "17",
"letterSpacing": "0em"
},
"type": "typography"
},
"sm": {
"value": {
"fontFamily": "Inter",
"fontWeight": "400",
"fontSize": "13",
"lineHeight": "22",
"letterSpacing": "0em"
},
"type": "typography"
},
"base": {
"value": {
"fontFamily": "Inter",
"fontWeight": "400",
"fontSize": "16",
"lineHeight": "27",
"letterSpacing": "0em"
},
"type": "typography"
},
"lg": {
"value": {
"fontFamily": "Inter",
"fontWeight": "400",
"fontSize": "20",
"lineHeight": "34",
"letterSpacing": "0em"
},
"type": "typography"
},
"xl": {
"value": {
"fontFamily": "Crimson Text",
"fontWeight": "600",
"fontSize": "25",
"lineHeight": "30",
"letterSpacing": "−0.02em"
},
"type": "typography"
},
"2xl": {
"value": {
"fontFamily": "Crimson Text",
"fontWeight": "600",
"fontSize": "31",
"lineHeight": "37",
"letterSpacing": "−0.02em"
},
"type": "typography"
},
"3xl": {
"value": {
"fontFamily": "Crimson Text",
"fontWeight": "600",
"fontSize": "39",
"lineHeight": "47",
"letterSpacing": "−0.02em"
},
"type": "typography"
},
"display": {
"value": {
"fontFamily": "Crimson Text",
"fontWeight": "600",
"fontSize": "49",
"lineHeight": "59",
"letterSpacing": "−0.02em"
},
"type": "typography"
}
},
"spacing": {
"0": {
"value": "0",
"type": "spacing"
},
"1": {
"value": "8",
"type": "spacing"
},
"2": {
"value": "16",
"type": "spacing"
},
"3": {
"value": "24",
"type": "spacing"
},
"4": {
"value": "32",
"type": "spacing"
},
"6": {
"value": "48",
"type": "spacing"
},
"8": {
"value": "64",
"type": "spacing"
},
"12": {
"value": "96",
"type": "spacing"
},
"16": {
"value": "128",
"type": "spacing"
},
"24": {
"value": "192",
"type": "spacing"
}
},
"borderRadius": {
"DEFAULT": {
"value": "0",
"type": "borderRadius"
}
},
"boxShadow": {
"DEFAULT": {
"value": "none",
"type": "boxShadow"
}
}
}
}
Where this system comes from. Every decision above traces back to one of these readings.
The site behaves like a letterpress broadsheet — flat ink on warm paper, hairline rules doing the structural work, zero gradients or glass.
Why it works Borrowing print's physics gives every element a reason to sit where it sits; nothing floats, so nothing feels arbitrary.
A single cream family carries ground, panels and dividers through value shifts alone; terracotta appears only at moments of action.
Why it works When the neutral does the structural work, the one saturated colour reads as a decision rather than decoration — attention goes exactly where it is spent.
Every block hangs from one hard left axis with a margin nearly a third of the viewport; the right edge is allowed to rag.
Why it works The exaggerated asymmetry creates tension a centred layout can't — the whitespace is an active shape, not leftover space.
A faint fibre noise sits under everything at maybe 3% opacity — visible only where panels meet, like stock showing at a cut edge.
Why it works Sub-perceptual texture keeps large flat fields from going sterile while never announcing itself as an effect.
Modernist grid rigour and mono labels meet a humanist serif and hand-drawn underlines — system and hand in the same frame.
Why it works The tension between mechanical structure and human gesture is the studio's whole argument: slow, considered, made by people.
Nothing blinks, slides or counts down; generous line-height and long measure invite reading at a walking pace.
Why it works Withholding urgency signals confidence — a studio that doesn't chase you reads as one that doesn't need to.
An old-style serif at display sizes does the branding; body text steps down to a quiet sans, and mono smallcaps handle wayfinding.
Why it works Giving one face all the personality and keeping the others silent produces hierarchy through character, not just size.
There is no simulated depth anywhere — no drop shadows, no elevation; separation is done entirely with rules and value steps.
Why it works Refusing depth keeps the page honest to its print metaphor and makes the few tonal shifts read clearly as structure.