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 thewordmarkfooter and the CTAband
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
| Role | Variable | Light | Dark |
|---|---|---|---|
| Page background, under the aurora | --color-paper | #f7f7fb | #0e0e12 |
| Glass cards, pills, inputs (see-through) | --color-surface | rgb(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-tray | rgb(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-ink | the paper color | the 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-1and--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:
| Variable | Light | Dark |
|---|---|---|
--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
[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 paperframe = 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:
| Token | Value | Used for | Class |
|---|---|---|---|
--radius-card | 1.125rem (18 px) | Cards, images, FAQ rows, trays | rounded-card |
--radius-inner | 0.625rem (10 px) | Inner cards, tool tiles, inputs | rounded-inner |
--radius-node | 0.1875rem (3 px) | The small squares where rules cross | rounded-node |
--shadow-glass | a soft tinted drop | Glass cards | shadow-glass |
--shadow-float | a deeper drop | Menus and floating panels | shadow-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 write | Button |
|---|---|
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:
| Font | Role | cssVariable |
|---|---|---|
| Hanken Grotesk | Everything: headings, text, buttons (weights 500, 600) | --font-primary |
| Newsreader | The italic serif accent word in headings (italic 400) | --font-accent |
| IBM Plex Sans Arabic | Arabic 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
[settings] colorMode = "light" # light | dark | systemcolorModeis the mode of a visitor’s first visit. Margo ships withlight.systemfollows 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 sothe dark mode keeps light text on a dark background. Keep every variable name and don't usehex 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] insrc/config/fonts.json. Keep the cssVariable values, the provider, and the fallback, and useweights and styles the fonts have. Don't change the Arabic font. Don't edit CSS files. Then tellme to restart npm run dev.