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 ([settings.colorScheme]) · Skill level: Beginner

A rebrand in Homio is a handful of values, not a search-and-replace. Every component uses named color tokens, so changing a token changes it everywhere, including the logo mark and the generated social cards. Homio has a light palette and a dark palette.

Homio homepage in dark mode

Where The Colors Live

Open src/styles/theme.css. The values are in two blocks:

  • :root { ... }: the light palette (the default)
  • :root.dark { ... }: the dark palette

Each value is a --theme-* variable. Components never use hex codes: they use Tailwind classes such as bg-sage or text-primary, which read these variables. Change a value in both blocks, and keep the variable names.

The Color Tokens

RoleVariableLightDarkTailwind classes
Page background--theme-body#ffffff#0e130fbg-body
Cards and white surfaces--theme-card#ffffff#151c16bg-card
Soft panels (reviews, blog, FAQ rows)--theme-sage#f2f5ee#151c16bg-sage
Light green tint (icon circles, footer panel)--theme-mint#e4f3da#1b2e1cbg-mint
Soft sunflower tint (service cards, quote card)--theme-blush#fff6d1#2a2410bg-blush
Warm cream (the handyman home)--theme-cream#f3f1e6#1a1d16bg-cream
Block green (the big brand-green blocks)--theme-deep#24842f#1d6b27bg-deep
Deep green (dark blocks, dark footers)--theme-forest#163e25#0b1f12bg-forest
Text green (links, icons, checks)--theme-primary#217b2c#6cc576text-primary, bg-primary
Text green on hover--theme-primary-hover#1c6c25#8bd593text-primary-hover
Text on green--theme-on-primary#ffffff#0e130ftext-on-primary
Sunflower (main pill buttons)--theme-accent#ffd23f#ffd23fbg-accent
Sunflower on hover--theme-accent-hover#f5c518#ffdc66bg-accent-hover
Text on sunflower--theme-on-accent#111511#111511text-on-accent
Dark gold for small accents on white--theme-accent-strong#7a5d00#ffd23ftext-accent-strong
Headings (ink)--theme-dark#111511#eef3ectext-dark
Body text--theme-text-default#5a615b#a9b5aatext-text-default
Borders and dividers--theme-border-light#e2e8dd#263127border-border-light
Form field borders--theme-border-input#7d877f#6f7c71border-border-input
Focus ring--theme-focus#24842f#6cc576ring-focus, outline-focus
States--theme-danger, --theme-success, --theme-warning#b42318, #217b2c, #9a5a00#f2726a, #6cc576, #f0b44ctext-danger, …

--theme-light and --theme-primary-soft repeat the mint value, and --theme-sand repeats sage. Change them together with --theme-mint and --theme-sage.

Copies To Change With The Palette

A few values appear twice in theme.css. Update them with the main tokens:

  • --page-* variables at the end of :root and :root.dark (--page-primary, --page-dark, --page-text, …). Cards on a colored block (a white review card on the green block) use them to get the page colors back. Keep them equal to the matching --theme-* values.
  • Static helpers in the @theme inline block, which stay the same in light and dark mode: --color-emerald (#24842f, the brand green for white text), --color-sunflower (#ffd23f), --color-mist (#e4f3da, white button hover), --color-light (#c9d8cc, text on the deep green footers), and --color-body-dark (#111511).
  • The colored blocks under @layer components: .block-deep (brand-green block), .block-forest (deep-green block), and .block-coral (the name is kept from an older version: it is the sunflower block, with ink text). They set the text and border colors used inside each block.
  • .band-ink: the near-black band, which uses the dark palette inside it.

The #24842f green also appears in src/assets/images/favicon.svg and the two standalone logo files. Regenerate the favicon after a color change (see Site Identity & Logo).

Button Styles

Buttons in content files take their look from variant:

You writeButton
variant: "fill"The main pill button, sunflower with ink text
variant: "accent"A brand-green pill with white text. One per view
variant: "soft"A soft tinted pill for the second action
variant: "outline"An outlined pill
variant: "fill-white"A white pill, for photos and dark bands
variant: "text"A text link

Some sections change a variant to fit their background; the comment next to variant: in the section file says when. See Common Changes for every button option.

Corners

The radius tokens are in the @theme inline block of theme.css:

TokenValueUsed forClass
--radius-btn9999px (a pill)Buttons and icon buttonsrounded-btn
--radius-field0.625rem (10 px)Inputs, selects, segmented controlsrounded-field
--radius-ui1.5rem (24 px)Cards, tiles, imagesrounded-ui
--radius-panel2rem (32 px)Large photos and soft panelsrounded-panel
--radius-block2rem (32 px)Color blocks and the footer panelrounded-block
--radius-tag0.375rem (6 px)Check squares and rating squaresrounded-tag

For square buttons, for example, set --radius-btn: 0.5rem;. Homio uses no shadows: the shadow scales are reset.

Fonts

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

FontRolecssVariable
FigtreeBody text, buttons, forms--font-primary
LexendHeadings and big numbers--font-heading
JetBrains MonoPrices, totals, and ticket codes--font-code
{
"name": "Lexend",
"variants": [{ "style": "normal", "weight": "300 600" }],
"preload": true,
"display": "swap",
"cssVariable": "--font-heading",
"provider": "google",
"subsets": ["latin"],
"fallback": "sans-serif"
}

To change a font, replace name with another Google Font name, exactly as Google writes it ("DM Sans", "Plus Jakarta Sans"). Keep cssVariable, provider, and fallback, and keep a weight range the new font has: Homio ships 300 to 600 for headings (Lexend) and 400 to 700 for body text (Figtree). 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.

Type Sizes

Heading sizes are fluid: they grow from phone to desktop between 375 px and 1280 px wide. They are in theme.css as --text-display, --text-h1 to --text-h6, --text-stat (big numbers), --text-lead, --text-copy (body, 16 px), --text-label (small caps labels), and --text-total / --text-total-lg (prices). Each has a --line-height, --letter-spacing, and --font-weight beside it. Headings use weight 400.

Breakpoints

sm 540 px, md 768 px, lg 1024 px, xl 1320 px. The mobile action bar shows below md; the full header menu shows from lg.

Dark Mode

src/config/config.toml
[settings.colorScheme]
default = "system" # system | light | dark: used until a visitor picks one
switcher = true # Show the light/dark button in the header, mobile menu, and footer
  • system follows the visitor’s device setting. light or dark starts every visitor on that palette.
  • The sun and moon button switches it. The visitor’s choice is remembered in their browser.
  • switcher = false hides every button. Visitors then always get default, and an earlier choice is ignored. Use switcher = false with default = "light" for a site without dark mode.

When you change colors, check both palettes. Photos and the sunflower buttons stay the same in dark mode.

Do It With AI

My brand colors are: green [HEX] and button color [HEX]. In src/styles/theme.css, in :root,
set --theme-deep to my green, and --theme-primary and --theme-primary-hover to darker shades of
it with at least 4.5:1 contrast on #ffffff and #f2f5ee. Set --theme-accent and
--theme-accent-hover to my button color, and --theme-on-accent to black or white, whichever
contrasts more. Make lighter versions for :root.dark. Update the matching --page-* values,
--color-emerald, and --color-sunflower. Keep every variable name. List the values and their
contrast ratios.
Change the heading font to [GOOGLE FONT] and the body font to [GOOGLE FONT] in
src/config/fonts.json. Keep the cssVariable values, the provider, and the fallback, and use
weight ranges the fonts have. Don't edit CSS files. Then tell me to restart npm run dev.
Type something to search...