Skip to content
New: Customize your theme with an AI assistant. Read the guide

Colors & Fonts

Files: src/styles/theme.css, src/config/fonts.json, src/config/config.toml (colorMode, [settings.layout]) · Skill level: Beginner

A rebrand in Margo is a handful of values, not a search-and-replace. Components never use color codes: they use named color tokens, so changing a token changes it everywhere, including the generated social cards. Margo has a light palette, a dark palette, and a “night” palette for the dark bands that stay dark in both modes.

Where The Colors Live

Open src/styles/theme.css. The colors are in three blocks:

  • the first @theme static { ... } block: the light palette (the default)
  • :root.dark { ... }: the dark palette
  • [data-surface="night"] { ... }: the night scope, used by dark bands such as the wordmark footer and the CTA band

Each value is a --color-* variable. Tailwind classes read them: --color-ink becomes text-ink and bg-ink, --color-paper becomes bg-paper, --color-line becomes border-line. Change a value in the light and dark blocks, and keep the variable names.

The Color Tokens

RoleVariableLightDark
Page background, under the aurora--color-paper#f7f7fb#0e0e12
Glass cards, pills, inputs (see-through)--color-surfacergb(255 255 255 / 0.58)rgb(255 255 255 / 0.05)
Menus, dropdowns, popovers, cookie banner--color-raised#ffffff#1c1c22
Tinted trays and hover rows--color-trayrgb(43 36 120 / 0.06)rgb(255 255 255 / 0.06)
Card borders, rules, inputs--color-line#e2e0ef#27272e
Small pills--color-line-soft#ebe9f5#1f1f25
Disabled text--color-muted#a3a0b8#63636c
Grey line of two-line headings (24 px and up)--color-ash#655b8c#8b8b95
Small grey text: meta, roles--color-stone#4c4964#b4b4bc
Primary button hover--color-charcoal#2a2745#dadae0
Ink: headings, body, primary buttons--color-ink#14122b#f4f4f6
Text and icons on an ink fill--color-on-inkthe paper colorthe paper color
Availability dot--color-signal#1f9e6a#34b37f
Night bands (stay dark in both modes)--color-night#141418#0a0a0d
Text on night--color-on-night#f4f4f6#f4f4f6
Grey text on night--color-on-night-ash#96969f#96969f
Form errors--color-danger#b42318#f97066

Margo is mostly ink on paper: the primary button is an ink pill, and in dark mode ink and paper swap. To give the site a brand color, start with --color-ink and --color-charcoal (its hover), then check the contrast of --color-stone and --color-ash against --color-paper: aim for at least 4.5:1 for small text.

A few more tokens in the same block:

  • --color-glass-edge: the thin light edge at the top of glass cards and floating panels.
  • --color-tone-1 and --color-tone-2: the two lines of a two-line heading. Both are ink. Set --color-tone-1: var(--color-ash); for a grey first line.
  • --color-focus: the keyboard focus ring (ink).

The Aurora

The aurora is the soft color fields behind every page, under the glass cards. Five tokens set its colors, pastel in light mode and deep and dim in dark mode:

VariableLightDark
--color-aurora-violet#c7b6ff#2e2a52
--color-aurora-pink#ffbad8#3d2638
--color-aurora-sky#a8d3ff#1f2f4a
--color-aurora-peach#ffd5b0#3b2c24
--color-aurora-mint#b5ecd6#1d3530

The same colors tint the frames of project images. Change them for a different mood, or turn the aurora off: see Frame And Aurora.

Night Bands

Some parts stay dark in both modes: the wordmark footer, the CTA band, and other dark panels. They use the [data-surface="night"] block of theme.css, which sets the same color roles for a dark background. Inside it, an ink button turns light and two-line headings show light text, then grey. If you change --color-night, check the text on it.

Frame And Aurora

src/config/config.toml
[settings.layout]
frame = true # Thin ruled lines at the container edges and section tops. `false` removes them
aurora = true # Soft colour fields behind every page. `false` leaves plain paper

frame = false removes the thin lines along the edges of the content and at the top of sections; the spacing stays the same. aurora = false gives every page the plain --color-paper background.

Shapes And Shadows

In the second @theme static block of theme.css:

TokenValueUsed forClass
--radius-card1.125rem (18 px)Cards, images, FAQ rows, traysrounded-card
--radius-inner0.625rem (10 px)Inner cards, tool tiles, inputsrounded-inner
--radius-node0.1875rem (3 px)The small squares where rules crossrounded-node
--shadow-glassa soft tinted dropGlass cardsshadow-glass
--shadow-floata deeper dropMenus and floating panelsshadow-float

Buttons and pills are fully round (rounded-full). --container-frame (70rem) is the width of the content frame.

Button Styles

Buttons in content files take their look from variant:

You writeButton
variant: "fill"The primary ink pill with an arrow in a small circle (the default)
variant: "outline"The secondary button: a glass pill with a thin border
variant: "fill-white"A light pill that stays light, for photos and night bands
variant: "text"A text link whose underline draws in on hover
variant: "circle"A round icon button; the label is read by screen readers only

hoverEffect adds a hover motion: text-flip, creative-fill, magnetic, or magnetic-text-flip. Every option is in sharedButton in src/sections.schema.ts; see Common Changes.

Fonts

Margo uses three fonts from Google Fonts, set in src/config/fonts.json, one entry per role:

FontRolecssVariable
Hanken GroteskEverything: headings, text, buttons (weights 500, 600)--font-primary
NewsreaderThe italic serif accent word in headings (italic 400)--font-accent
IBM Plex Sans ArabicArabic text, loaded only on Arabic pages--font-arabic
{
"name": "Hanken Grotesk",
"variants": [
{ "style": "normal", "weight": "500" },
{ "style": "normal", "weight": "600" }
],
"preload": true,
"display": "swap",
"cssVariable": "--font-primary",
"provider": "google",
"subsets": ["latin"],
"fallback": "sans-serif",
"staticWeights": true
}

To change a font, replace name with another Google Font name, exactly as Google writes it ("DM Sans", "Fraunces"). Keep cssVariable, provider, and fallback, and keep weights and styles the new font has: the text font needs 500 and 600, and the accent font needs an italic. Add a subset such as "latin-ext" if your language needs it. Then restart npm run dev: fonts are read only when the server starts.

Astro downloads the fonts and serves them from your own site, so visitors don’t load anything from Google.

The serif accent. In a heading, a word between asterisks (*call*) is set in the accent font. Leave the asterisks out and the heading is all in Hanken Grotesk. In theme.css, --accent-scale (0.94) sizes the accent so its letters line up with the text font; adjust it if you choose another accent font.

The Arabic font. The IBM Plex Sans Arabic entry has "languages": ["ar"], so it loads only on Arabic pages. Latin text on those pages stays in Hanken Grotesk. Newsreader has no Arabic letters, so on Arabic pages the accent word uses the Arabic font, upright. See RTL & Arabic.

Code in journal posts uses the computer’s own monospace font, so there is no code font to load.

Type Sizes

Sizes are fluid: they grow from phone to desktop between 390 px and 1280 px wide. They are in theme.css as --text-display (hero and footer headings), --text-masthead (the masthead hero), --text-section (section headings), --text-title (project and post titles), --text-h3, --text-card, --text-quote, --text-lead, --text-copy-lg, --text-copy (body text), --text-small, --text-label (menu, buttons), --text-micro (meta, dates), and --text-price. Each has its line height and letter spacing beside it. Headings use weight 500.

Breakpoints

sm 540 px, md 768 px, lg 1024 px, xl 1320 px. The full header menu shows from lg.

Light And Dark Mode

src/config/config.toml
[settings]
colorMode = "light" # light | dark | system
  • colorMode is the mode of a visitor’s first visit. Margo ships with light. system follows the visitor’s device setting, and its changes, until the visitor picks a mode.
  • The sun and moon button in the header switches the mode. The visitor’s choice is remembered in their browser and wins on later visits.
  • The color of the browser bar on phones follows the mode.

When you change colors, check both palettes and a night band. Photos stay the same in dark mode.

Do It With AI

Give the site my brand color [HEX]. In src/styles/theme.css, in the first @theme static block,
set --color-ink to it (or a darker shade with at least 4.5:1 contrast on #f7f7fb) and
--color-charcoal to a slightly lighter hover shade. Set matching light values in :root.dark so
the dark mode keeps light text on a dark background. Keep every variable name and don't use
hex codes outside theme.css. List the values and their contrast ratios.
Change the text font to [GOOGLE FONT] and the accent font to [GOOGLE FONT WITH AN ITALIC] in
src/config/fonts.json. Keep the cssVariable values, the provider, and the fallback, and use
weights and styles the fonts have. Don't change the Arabic font. Don't edit CSS files. Then tell
me to restart npm run dev.
Type something to search...