DESIGN.md Tailwind v4 CSS variables
---
version: "alpha"
name: "Tustel"
description: "Portfolio website for photographers and creative designers: a warm light grey page, black type, square boxes and an Orange accent that appears on hover."
colors:
ink: "#000000"
soft: "#434343"
ink-60: "rgba(0, 0, 0, 0.6)"
ink-30: "rgba(0, 0, 0, 0.3)"
ink-10: "rgba(0, 0, 0, 0.1)"
orange: "#EB4B3D"
background: "#F5F4F2"
white: "#FFFFFF"
white-0: "rgba(255, 255, 255, 0)"
primary: "{colors.orange}"
on-primary: "{colors.white}"
secondary: "{colors.ink}"
on-secondary: "{colors.white}"
neutral: "{colors.background}"
surface: "{colors.white}"
on-surface: "{colors.ink}"
on-surface-variant: "{colors.soft}"
outline: "{colors.ink-10}"
typography:
display:
fontFamily: "Inter"
fontSize: "92px"
fontWeight: 500
lineHeight: 1
letterSpacing: "-0.03em"
fontVariation: "'opsz' 32"
h1:
fontFamily: "Inter"
fontSize: "54px"
fontWeight: 500
lineHeight: 1.2
letterSpacing: "-0.03em"
fontVariation: "'opsz' 32"
h2:
fontFamily: "Inter"
fontSize: "42px"
fontWeight: 500
lineHeight: 1.2
letterSpacing: "-0.03em"
fontVariation: "'opsz' 32"
h3:
fontFamily: "Inter"
fontSize: "36px"
fontWeight: 500
lineHeight: 1.2
letterSpacing: "-0.03em"
fontVariation: "'opsz' 32"
h4:
fontFamily: "Inter"
fontSize: "28px"
fontWeight: 500
lineHeight: 1.2
letterSpacing: "-0.03em"
fontVariation: "'opsz' 32"
h5:
fontFamily: "Inter"
fontSize: "24px"
fontWeight: 500
lineHeight: 1.2
letterSpacing: "-0.03em"
fontVariation: "'opsz' 32"
h6:
fontFamily: "Inter"
fontSize: "20px"
fontWeight: 500
lineHeight: 1.2
letterSpacing: "-0.03em"
fontVariation: "'opsz' 32"
paragraph:
fontFamily: "Inter"
fontSize: "16px"
fontWeight: 400
lineHeight: 1.4
letterSpacing: "-0.03em"
fontVariation: "'opsz' 14"
small:
fontFamily: "Inter"
fontSize: "14px"
fontWeight: 400
lineHeight: 1.4
letterSpacing: "-0.03em"
fontVariation: "'opsz' 14"
menu:
fontFamily: "Inter"
fontSize: "14px"
fontWeight: 500
lineHeight: 1.2
letterSpacing: "-0.03em"
fontVariation: "'opsz' 14"
button:
fontFamily: "Inter"
fontSize: "15px"
fontWeight: 500
lineHeight: 1.2
letterSpacing: "-0.03em"
fontVariation: "'opsz' 14"
tiny:
fontFamily: "Inter"
fontSize: "12px"
fontWeight: 400
lineHeight: 1.2
letterSpacing: "-0.03em"
fontVariation: "'opsz' 14"
label:
fontFamily: "Inter"
fontSize: "15px"
fontWeight: 500
lineHeight: 1.4
letterSpacing: "-0.03em"
fontVariation: "'opsz' 14"
rounded:
none: "0px"
round: "9999px"
spacing:
section-padding: "100px"
section-padding-phone: "60px"
section-padding-tablet: "80px"
gutter: "30px"
gutter-phone: "15px"
gutter-tablet: "20px"
content-max: "1440px"
section-gap: "100px"
section-gap-phone: "60px"
section-gap-tablet: "80px"
page-top: "150px"
page-top-phone: "110px"
page-top-tablet: "130px"
header-height: "62px"
header-height-phone: "54px"
components:
button-black:
backgroundColor: "{colors.ink}"
textColor: "{colors.white}"
typography: "{typography.button}"
rounded: "{rounded.none}"
padding: "5px 5px 5px 8px"
height: "32px"
button-black-hover:
backgroundColor: "{colors.orange}"
button-white:
backgroundColor: "{colors.white}"
textColor: "{colors.ink}"
typography: "{typography.button}"
rounded: "{rounded.none}"
padding: "5px 5px 5px 8px"
height: "32px"
button-white-hover:
backgroundColor: "{colors.orange}"
textColor: "{colors.white}"
button-secondary:
textColor: "{colors.ink}"
typography: "{typography.button}"
height: "22px"
button-secondary-hover:
textColor: "{colors.orange}"
menu-link:
textColor: "{colors.ink}"
typography: "{typography.menu}"
rounded: "{rounded.none}"
padding: "3px 8px"
height: "23px"
menu-link-hover:
backgroundColor: "{colors.orange}"
textColor: "{colors.white}"
text-link:
textColor: "{colors.ink}"
typography: "{typography.tiny}"
text-link-hover:
textColor: "{colors.orange}"
project-card:
textColor: "{colors.ink}"
typography: "{typography.h6}"
rounded: "{rounded.none}"
post-card:
textColor: "{colors.ink}"
typography: "{typography.h6}"
rounded: "{rounded.none}"
specialities-card:
backgroundColor: "{colors.white}"
textColor: "{colors.ink}"
rounded: "{rounded.none}"
padding: "5px 10px 5px 5px"
width: "300px"
height: "52px"
section-label:
textColor: "{colors.ink}"
typography: "{typography.label}"
input-field:
backgroundColor: "{colors.white}"
textColor: "{colors.ink}"
rounded: "{rounded.none}"
padding: "12px"
height: "43px"
submit-button:
backgroundColor: "{colors.ink}"
textColor: "{colors.white}"
typography: "{typography.button}"
rounded: "{rounded.none}"
padding: "0px 20px"
height: "40px"
submit-button-hover:
backgroundColor: "{colors.orange}"
hamburger:
textColor: "{colors.ink}"
width: "36px"
height: "22px"
---
# Tustel Design System
> The design tokens and style rules of **Tustel**, a website template by Erapee (live Framer site: https://tustel.framer.website). Read it before you build or change a page so new work matches the template. The front matter holds the exact values; the sections below say where and how to use them. Format: [DESIGN.md](https://github.com/google-labs-code/design.md), spec version `alpha`.
## Overview
Tustel is a website template for a photographer or creative designer: a full-screen photo hero, projects with galleries, services, testimonials, a journal and a contact form, all presenting one person (the demo's Alex Carter). It should feel editorial and quiet: big photos, a lot of space between sections, and type that does the work instead of decoration.
The look is built from very few parts. The page is a warm light grey Background (#F5F4F2); type is Black, with Soft Black (#434343) for anything secondary; the footer, the form fields and the specialities card are White. Every box is square. Buttons are Black or White boxes with a small arrow square; one accent, Orange (#EB4B3D), appears mainly when the pointer arrives: a band that rises over a button, a fill behind a menu link, an underline under a social link, plus the chosen service and the required-field asterisks. Photos carry White text under a Black 60 cover or the band gradient.
Everything is set in Inter with tight letter spacing (-0.03em): headings at weight 500 in Inter's display optical size, body text at weight 400. Motion is smooth: hovers follow a 0.5 s spring with no bounce, button labels roll up while the arrow slides through, the hero name builds up letter by letter, page titles word by word, and blocks fade up 18px into view once.
## Colors
- **Black (#000000)** — `ink`, `secondary`, `on-surface`. Headings, body text in posts and project pages, black buttons, menu links, the hamburger, field text.
- **Soft Black (#434343)** — `soft`, `on-surface-variant`. Leads, descriptions, card meta, page-title labels, form labels, contact labels, the footer note, testimonial quotes.
- **Black 60 (rgba(0, 0, 0, 0.6))** — `ink-60`. The cover over the Home and 404 photos, the slideshow arrow circles.
- **Black 30 (rgba(0, 0, 0, 0.3))** — `ink-30`. Project detail labels, field placeholders, the select chevron, the focused field border, the line above the About hero links.
- **Black 10 (rgba(0, 0, 0, 0.1))** — `ink-10`, `outline`. Field borders, the lines of the project details list.
- **Orange (#EB4B3D)** — `orange`, `primary`. The button band and menu-link fill on hover, hover text and underlines, the chosen service and list title, required asterisks, the submit button hover.
- **Background (#F5F4F2)** — `background`, `neutral`. The page, the header bar, the open phone menu.
- **White (#FFFFFF)** — `white`, `on-primary`, `on-secondary`, `surface`. The footer band, white buttons, the specialities card, form fields, text over photos.
- **Transparant (sic: the style's name in the design file) (rgba(255, 255, 255, 0))** — `white-0`. White at 0%: the header bar over the Home and 404 photos.
- **Gradient `band`:** `linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, #000000 100%)`. Over the photo of the band (Home, About): clear at the top, black at the bottom.
Semantic names in the front matter point at these colours: `primary` → `orange`, `on-primary` → `white`, `secondary` → `ink`, `on-secondary` → `white`, `neutral` → `background`, `surface` → `white`, `on-surface` → `ink`, `on-surface-variant` → `soft`, `outline` → `ink-10`.
## Typography
**Inter, sans-serif.** Inter from Google Fonts as one variable font with its optical-size axis (opsz), weights 400, 500 and 600, plus italic for emphasis in posts. The optical size is pinned per style so the browser never picks one from the font size: headings (Display 1, Heading 1–6) use 32 — the design file's "Inter Display" — and every other style 14 ("Inter"). 600 is only used for the form result on the submit button.
Font sizes change at the breakpoints (phone / tablet from 810px / desktop from 1200px); the front matter gives the desktop size. Line height is a multiple of the font size.
| Token | Size (phone / tablet / desktop) | Line height | Weight | Letter spacing | Use |
|---|---|---|---|---|---|
| `display` | 54px / 62px / 92px | 1.1 / 1.1 / 1 | 500 | -0.03em, opsz 32 | Display 1 — the name in the Home and About heroes, project titles, "404" |
| `h1` | 36px / 44px / 54px | 1.2 | 500 | -0.03em, opsz 32 | Heading 1 — page titles (Works, Journal, Contact, posts), the project titles of the list view |
| `h2` | 32px / 36px / 42px | 1.2 | 500 | -0.03em, opsz 32 | Heading 2 — section titles, the band title, "Other Projects", the "+" after the counters |
| `h3` | 28px / 32px / 36px | 1.2 | 500 | -0.03em, opsz 32 | Heading 3 — the numbered services, headings in posts |
| `h4` | 24px / 26px / 28px | 1.2 | 500 | -0.03em, opsz 32 | Heading 4 — the Home hero subtitle, testimonial quotes |
| `h5` | 20px / 22px / 24px | 1.2 | 500 | -0.03em, opsz 32 | Heading 5 — the clients title |
| `h6` | 18px / 19px / 20px | 1.2 | 500 | -0.03em, opsz 32 | Heading 6 — card titles, the greetings, step titles, the service details title, "What clients say", the project page block titles |
| `paragraph` | 16px | 1.4 | 400 | -0.03em, opsz 14 | Medium Paragraph — leads, descriptions, rich text, the post card meta, the testimonial name, project texts |
| `small` | 14px | 1.4 | 400 | -0.03em, opsz 14 | Small Paragraph — the hero role, step labels and texts, the project details row, the project card category, form and contact labels, the specialities |
| `menu` | 14px | 1.2 | 500 | -0.03em, opsz 14 | Menu — header links, the Catalog / List switch |
| `button` | 15px | 1.2 | 500 | -0.03em, opsz 14 | Button — button labels, the location and response time in Let's work together |
| `tiny` | 12px | 1.2 | 400 | -0.03em, opsz 14 | Tiny — social links, the footer note, the specialities label, testimonial roles |
| `label` | 15px | 1.4 | 500 | -0.03em, uppercase, opsz 14 | Label — section labels and page-title labels, uppercase |
## Layout
Three layouts: phone below 810px, tablet from 810px, desktop from 1200px. Spacing tokens without a suffix are the desktop values; `-tablet` and `-phone` give the smaller screens where they differ.
| Token | Phone / tablet / desktop | Use |
|---|---|---|
| `section-padding` | 60px / 80px / 100px | Vertical padding of a section |
| `gutter` | 15px / 20px / 30px | Side padding of sections, the header and the footer |
| `content-max` | 1440px | Maximum content width (inside the gutters), centred |
| `section-gap` | 60px / 80px / 100px | Between a section's title block and its content, and between the blocks of a project page |
| `page-top` | 110px / 130px / 150px | Top padding of the pages that start with a page title (Works, Journal, posts, Contact); the fixed header lies over it |
| `header-height` | 54px / 62px / 62px | The header bar (it lies over the page; nothing is pushed down) |
Every section is centred, at most `content-max` wide inside the `gutter` on each side, and padded top and bottom by `section-padding`; a section's title block and its content are `section-gap` apart unless the section sets its own. The header bar (`header-height`) lies over the page and pushes nothing down, so pages that start with a page title leave room for it with `page-top`. Grids of project and post cards have one column on phones, two from tablets and three on desktops, 20px between columns and 30px between rows, top-aligned (not a masonry).
## Elevation & Depth
Tustel is flat: there are no shadows anywhere. Depth comes from photos and fills: the Home and 404 photos sit under a Black 60 cover (`ink-60`) and the band photo under the band gradient (clear at the top, black at the bottom) wherever White text sits on them; the White footer band, White fields and the White specialities card stand on the grey Background. Lines are thin and translucent: Black 10 (`ink-10`) for field borders and list lines, Black 30 (`ink-30`) for a focused field.
## Shapes
Every box has square corners; only the portraits and the slideshow arrows are round.
- **`none` (0px):** Every box: buttons, cards, photos, fields, the specialities card.
- **`round` (9999px):** Portraits in the About hero and the testimonials, the slideshow arrows.
## Motion
Reduced motion: nothing moves or changes size (rises, rolls, slides and turns happen in place; the button band, the menu fill, underlines, the phone menu and the services panels change at once; tickers and slideshows stand still; counters show their final number), while fades, blurs and colour changes still animate.
- **`spring`** — spring (duration 0.5 s, bounce 0). Every hover, in and out: buttons, menu and social links, project and post cards; the header bar showing and hiding; the phone menu's height.
- **`spring-quick`** — spring (duration 0.4 s, bounce 0). The Catalog / List switch and the titles of the list view on Home.
- **`spring-soft`** — spring (duration 0.4 s, bounce 0.2). A slight overshoot: the hamburger lines; the services (colour, opacity and the height of the phone accordion).
- **`slide`** — spring (stiffness 200, damping 40, mass 1). One step of a slideshow (Home hero every 5 s, testimonials every 8 s): about 95% there after 0.45 s, settled after 0.85 s.
- **`ease-appear`** — `cubic-bezier(0.59, 0.25, 0.12, 1.17)`. The appear ease (a slight overshoot at the end): every fade-up and the word and line effects.
- **`ease-hero-block`** — `cubic-bezier(0.79, 0.01, 0.15, 0.99)`. The Home hero blocks on load.
- **`ease-form`** — `cubic-bezier(0.44, 0, 0.56, 1)`. The submit button's colours (0.2 s).
- **`fade-up`** — type tween, duration 1s, ease `ease-appear`, from 18px lower, opacity 0, once true. Appear on scroll: a block rises 18px into place and fades in when it comes into view — from its first pixel, or once half of it is visible where a section says so — once.
- **`load-up`** — type tween, duration 1s, delay 0.15s, ease `ease-appear`, from 7px lower, opacity 0. Appear on load (page tops, list cards, the contact form): 7px, 0.15 s after load.
- **`hero-block`** — type tween, ease `ease-hero-block`, from 50px lower, opacity 0. Home hero on load: the buttons over 0.6 s after 0.2 s, the specialities card over 0.4 s after 0.2 s, the footer row over 0.4 s after 0.3 s.
- **`letters`** — spring (duration 0.3 s, bounce 0). Text effect, Home hero: each character rises 10px out of a 10px blur and fades in, 0.05 s after the one before; each character's spring lasts 0.3 s (0.2 s in the subtitle).
- **`words`** — type tween, duration 1s, ease `ease-appear`, stagger 0.05s, from 10px lower, blur 7px, opacity 0. Text effect, page titles and the About name: word by word, from load.
- **`lines`** — type tween, duration 1s, delay 0.2s, ease `ease-appear`, stagger 0.05s, from 7px lower, opacity 0. Text effect, labels, intros and excerpts: each rendered line, from 0.2 s after load.
- **`ticker-logos`** — speed 20px/s, gap 50px, direction left. The client logos, endlessly; they stand still with reduced motion.
- **`ticker-specialities`** — speed 5px/s, gap 5px, direction up. The specialities in the Home hero card (a new line every 5 s); they stand still with reduced motion.
- **`slideshow-hero`** — interval 5s, gap 10px, transition slide. The Home hero photos.
- **`slideshow-testimonials`** — interval 8s, gap 10px, transition slide. The testimonials; an arrow click restarts the timer.
- **`counter`** — step +1 every 5ms. The counters count up from their start value once their first pixel is in view (0 → 80 in about half a second).
- **`spin`** — type tween, duration 1s, ease linear, repeat infinite. The 20px loading rings turn once a second; they stand still with reduced motion.
- **`press`** — scale 0.9, duration 0.15s. The slideshow arrows while pressed.
## Components
Component tokens below use the exact values of the template. Variants with a suffix (`-hover`, `-pressed`, `-focus`, `-open`) only list what changes.
- **`button-black`** (Button (Black / White / Secondary Black / Secondary White)). The Black button ("Book a call" in the header, "More about me", "View all articles"). The label is one line; 5px to its right a 22px White square holds the 14px black arrow. Hover: the label rolls up to a second copy, the arrow slides out to the right while another slides in, and the square's fill turns 90° behind it.
- **`button-black-hover`** (Button (Black / White / Secondary Black / Secondary White)). Hover: an Orange band, skewed -5°, rises from below and covers the box (`spring`, in and out); the label stays White.
- **`button-white`** (Button (Black / White / Secondary Black / Secondary White)). The White button, over photos ("Book a call" in the Home hero, the band and the header over a photo; "Back to Home"); its 22px square is black with a white arrow.
- **`button-white-hover`** (Button (Black / White / Secondary Black / Secondary White)). Hover: the Orange band covers the box, the label turns White, the square White and the arrow black.
- **`button-secondary`** (Button (Black / White / Secondary Black / Secondary White)). No box and no padding: the label and the 22px square in black, with a white arrow ("View my works"; the e-mail and phone in Let's work together). Secondary White is the same in White, with a black arrow, over photos.
- **`button-secondary-hover`** (Button (Black / White / Secondary Black / Secondary White)). Hover: the label and the square turn Orange while the label rolls and the arrow slides.
- **`menu-link`** (Menu link (Black / White)). A header link. The current page looks like the others (it is only marked for assistive technology). The White look is used in the header over a photo.
- **`menu-link-hover`** (Menu link (Black / White)). Hover: an Orange fill grows from the left over the whole link and the text turns White (`spring`, in and out).
- **`text-link`** (Text link (Black / White)). The social links, black or White; they open in a new tab.
- **`text-link-hover`** (Text link (Black / White)). Hover: a 1px Orange line grows from the left along the bottom and the text turns Orange.
- **`project-card`** (Project card). One link: the photo at its own proportions over a blurred copy of itself, then 10px below the title (`h6`, black) and the category (`small`, Soft Black) on one row. Hover: the sharp photo shrinks to 85% of the card's width so the blurred copy shows as a frame, and the title rolls up to an Orange copy.
- **`post-card`** (Post card). One link: the photo in a 1.4134 : 1 box, drawn at 105% and easing back to the box on hover (a slow zoom-out); 15px below, the date and category (`paragraph`, Soft Black) and 10px below them the title (`h6`, black, at most two lines).
- **`specialities-card`** (Specialities card). The Home hero card: a square 42px portrait, then the label (`tiny`) over a one-line window where the specialities (`small`) scroll up as a ticker, 5 px/s; a White copy of the lines rises into the card from behind it.
- **`section-label`** (Section label). Uppercase, black above section titles; Soft Black above page titles and in the Home About section. The section title (`h2`) follows 10px below.
- **`input-field`** (Form field (Text / Select / Text area)). A 1px Black 10 border drawn inside, Inter 16px at weight 400, a Black 30 placeholder; the label (`small`, Soft Black, an Orange asterisk when required) sits 10px above. Focus turns the border Black 30, with no outline ring. A text area is at least 200px tall.
- **`submit-button`** (Submit button). A form's Send button, as wide as its column. Pressed: #333333. While sending, a 20px White ring turns in place of the label; after a send it reads "Thank you", after a failed send "Something went wrong" in #FF2244 on the same red at 15%.
- **`submit-button-hover`** (Submit button). Hover: an Orange fill under the White label (0.2 s, `ease-form`), only while the button shows its label.
- **`hamburger`** (Hamburger (Default / Close)). The phone menu button: two lines 24px wide and 2px tall, 8px apart, in the current text colour; open, they turn into an X with a slight overshoot (`spring-soft`).
Other components of the template, described in its spec: Logo (Black / White), Icon, Section, Section title, Page title, Appear, Text appear (Letters / Words / Lines), Slideshow, Counter, Counters, Ticker, Paged list, Rich text.
## Do's and Don'ts
- Do use Orange only for hover states and selection: the button band, the menu-link fill, link underlines and hover text, the chosen service and the required asterisks.
- Do give every box square corners; keep round shapes for portraits and the slideshow arrows.
- Do set headings (`display`, `h1`–`h6`), `menu`, `button` and `label` at weight 500, and `paragraph`, `small` and `tiny` at 400; headings use Inter's optical size 32, every other style 14.
- Do use Soft Black for leads, descriptions, meta and form labels, and Black for titles and body text in posts.
- Do put White text on a photo only under the Black 60 cover or the band gradient.
- Do build every Black, White and Secondary button from a one-line label and a 22px arrow square; on hover roll the label, slide the arrow and turn the square.
- Do animate hovers in and out with `spring` (0.5 s, no bounce), and let blocks fade up 18px into view once.
- Do space card grids 20px between columns and 30px between rows, top-aligned.
- Don't add shadows or new colours; the palette above is the whole palette.
- Don't use Orange as a resting fill for buttons: buttons are Black or White and turn Orange only on hover.
- Don't let a button label wrap.
- Don't highlight the current page in the menu.
- Don't mix fonts: Inter is the only family.
## Source
Every value here was measured from the published Tustel template (https://tustel.framer.website); when this file and the live site disagree, the site is right.
Fonts: Inter and Inter Display (SIL Open Font License).
Demo photos (Unsplash) are placeholders and not part of the design system; the template has no videos.
Use it with your agent
Save it as DESIGN.md at your project’s root. Ask Claude Code, Cursor, v0 or Lovable to follow it for every page and component it builds. Or let the agent fetch it: the Framebrick MCP server’s get_design_md tool with { "slug": "tustel" }, or the raw file at framebrick.co/templates/tustel/design.md . Connect the MCP server