# Colors & Fonts

## 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
| 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-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:

| 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](#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
```toml
# 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`:

| 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](/margo/customization/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`  |

```json
{
  "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](/margo/features/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
```toml
# 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
```text
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.
```

```text
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.
```