The full theme reference

Build a theme for Impulse Cart.

A theme is a skin: set a documented list of variables for colour, type, shape, depth and hover effects, drop in two files, and it appears in the shop's admin. It cannot touch layout or break a store. Every variable you can set is listed below, in place, with all of its values and its default. Nothing to look up elsewhere, nothing to guess.

2files per theme
43variables you can set
0build steps
100%CSS, no framework
On this page
  1. What a theme is
  2. The two files
  3. How to read this reference
  4. Colour
  5. Type
  6. Shape, depth and spacing
  7. Motion and focus
  8. Buttons
  9. Cards and images
  10. Contrast rules
  11. What not to set
  12. The manifest
  13. A complete example
  14. Selling your theme
  15. Ship checklist

01What a theme is

The Impulse Cart storefront is server-rendered HTML with stable, well-named CSS classes. Its engine stylesheet (store.css) owns all the structure: the grid, the nav, where everything sits. Every colour, size and effect in it is a placeholder, for example background: var(--bg) or border-radius: var(--radius).

A theme is nothing more than a block that fills those placeholders in. You set the variables, the browser substitutes them everywhere, and the shop is reskinned. Because a theme cannot change structure, a bad theme can only ever look wrong, never break a store, and every theme survives platform updates.

02The two files

A theme is two files, dropped into theme/css/themes/:

theme/css/themes/
  sunrise.css     the skin: sets the variables in :root
  sunrise.json    the manifest: name, author, preview, licence

sunrise is a lowercase slug and must match both file names; it becomes the theme's id. Drop the two files in and the theme appears in the shop's Admin → Appearance automatically. No code change anywhere.

03How to read this reference

Every variable you can set is in the tables below, grouped by what it affects. Each row gives you everything in place:

  • What it sets, and where in the shop it lands.
  • Values: the actual values you can use. For anything with a fixed set (like a hover effect) every option is listed right in the row; the default is marked.

You only set the variables you want to change; every other one keeps its default. Set them all inside your theme's :root. Anything not listed here is engine internal (see What not to set).

04Colour

Twelve role-based colours. Each accepts any CSS colour: #hex, rgb(), or rgba() (use the alpha channel for translucent "glass" surfaces). The table says exactly what each one paints.

VariableWhat it paintsDefault (light)
--bgThe page background, behind everything#FFFFFF
--textBody copy, headings, most text#1C1C1F
--text-mutedSecondary text: captions, sub-labels, help#6B6B72
--accentButtons, links, prices, active states#2F2F33
--accent-hoverThe accent's hover / emphasis shade#48484E
--on-accentText and icons on top of the accent fill#FFFFFF
--panelLarge panels and section backgrounds#FFFFFF
--cardProduct cards and tiles#FCFCFD
--borderBorders and hairlinesrgba(0,0,0,.14)
--navNav bar and footer chrome#F6F6F5
--menuDropdowns, menus, toasts#FFFFFF
--fieldForm inputs and selects#FFFFFF
Auto-derived, do not set

The soft washes behind hovers and selected rows are computed for you with color-mix() from --accent and --text. You get matching tints free and never write them.

05Type

Two typefaces (body and headings), a body size and leading, a size for every heading level, and heading weight and tracking. Load the fonts yourself; the engine loads none for you. Heading sizes are optional ceilings: leave one unset and that heading keeps the shop's built-in responsive size; set it to cap the desktop size (the value shown is the built-in ceiling).

VariableWhat it setsValues
Fonts
--fontBody typeface (and headings, unless overridden)any font stack · system-ui, sans-serif
--heading-fontHeading typeface, h1 to h6any font stack · inherits --font
--font-monoMonospace (order numbers, code)any font stack · ui-monospace
Body text
--font-sizeBase body text size14px · 15px · 16px · 17px · 18px
--line-heightBody leading1.4 tight · 1.6 · 1.8 loose
Headings
--h1Page / product titlea size, e.g. 2rem to 3.5rem · 2.5rem
--h2Section headingsa size · 2rem
--h3Sub-sectionsa size · 1.5rem
--h4Card titlesa size · 1.25rem
--h5Small headingsa size · 1.1rem
--h6Smallest headingsa size · 1rem
--heading-weightHeading font weight400 · 500 · 600 · 700 · 800
--heading-trackingHeading letter-spacing0 · -0.02em · -0.04em tight

06Shape, depth and spacing

How round things are, how much they lift off the page, and how tightly the shop is packed.

VariableWhat it setsValues
Corners and borders
--radiusCorner radius on cards, panels, inputs, menus0 sharp · 6px · 12px · 14px · 20px · 999px pill
--card-radiusCard corners (own knob, overrides --radius)same values · 20px
--border-widthHairline thickness on borders0 none · 1px · 1.5px · 2px bold
--glassBackdrop blur on nav and cardsnone · blur(8px) · blur(16px) frosted
Depth
--shadowCard elevation (cards are flat by default)none · any box-shadow
--shadow-liftRaised / hover elevationnone · raised default · any box-shadow
Spacing
--densityOverall padding + gap multiplier.85 compact · 1 normal · 1.15 airy · 1.3 spacious

07Motion and focus

VariableWhat it setsValues
--hover-speedHow fast hover transitions run0s instant · .12s snappy · .18s · .3s smooth
--focus-ringKeyboard focus outline colourany colour · inherits --accent
Leave focus visible

You can colour the focus ring, but you cannot remove it. A visible focus outline is required for keyboard and accessibility, so the engine always draws one.

08Buttons

A button is shape + size + hover effect. Its colours come from the accent pair you already set (fill --accent, label --on-accent).

Shape and size

VariableWhat it setsValues
--btn-radiusCorner radius0 sharp · 6px · 12px · 20px · 999px pill
--btn-pad-yTop + bottom padding (height)10px compact · 14px · 18px tall
--btn-pad-xLeft + right padding (width)16px · 24px · 32px wide
--btn-weightLabel font weight500 · 600 · 700 · 800

Hover effect: --btn-hover

Set --btn-hover to one of these. Every option is here; the default is shine.

ValueWhat happens on hover
noneNo effect
shineA gloss highlight sweeps across the button (default)
growThe button scales up slightly
liftThe button rises, with a soft shadow
sinkThe button presses down slightly
glowAn accent-coloured halo appears around it
colourThe fill shifts to --accent-hover
outlineAn accent ring appears around it
fillA colour wipes across from one edge
brightenThe fill lightens a touch

Fine-tune the shine effect: --shine-color (any colour, default rgba(255,255,255,.35)) and --shine-speed (a time, default .9s).

09Cards and images

Cards and product images take their shape from --radius / --card-radius and their depth from --shadow. Each also has one hover effect, picked from its own list right here.

Card hover: --card-hover

Set --card-hover to one of these. Default is lift.

ValueWhat happens on hover
noneNo effect
liftThe card rises, with a soft shadow (default)
growThe card scales up slightly
glowAn accent halo appears
outlineThe border turns accent
brightenThe card lightens a touch

Image hover: --thumb-hover

Set --thumb-hover to one of these. Default is zoom.

ValueWhat happens on hover
noneNo effect
zoomThe image scales up inside its frame (default)
growThe whole thumbnail scales up
brightenThe image lightens
glowAn accent halo appears behind it

10Contrast rules

A theme is only valid if the text is readable. Hit these before you ship:

PairMinimumWhy
--text vs --bg4.5:1Body text on the page
--on-accent vs --accent4.5:1Button labels on the accent fill
--accent vs --bg4.5:1The accent is also link + price text
text vs --panel/--card/--nav/--menu/--field4.5:1 (muted 3:1)Text sits on these surfaces too
--border vs --bgvisibleA faint hairline just needs to show
The one to watch

The accent does double duty: it is a button fill and it is link + price text. So it must be dark or saturated enough to read on the background, and also have an --on-accent colour that reads on top of it.

11What not to set

Off-limits

Do not set the --z-* stacking variables (they order the nav, drawers and toasts) or --content-width (the max content width is engine layout), and never change structure: the DOM, grid tracks, or layout.

Fixed on purpose

Status colours (success green, error red, sale) are fixed engine literals, not variables, so they stay legible in every theme. The focus ring can be recoloured but never removed.

12The manifest

The .json file names the theme and describes its preview swatches. Minimum keys are id, name and licence.

{
  "id": "sunrise",
  "name": "Sunrise",
  "author": "Your Studio",
  "description": "A warm, bright light theme.",
  "version": "1.0.0",
  "licence": "domain",
  "preview": {
    "bg": "#FFFDFB", "nav": "#FFF3EC", "surf": "#FFFFFF",
    "border": "rgba(0,0,0,.12)", "thumb": "#F1E4DB",
    "text": "#241C17", "sub": "#7A6E64",
    "accent": "#C2410C", "on": "#FFFFFF"
  }
}

13A complete example

A full, valid theme. It only sets what it wants to change; every other variable keeps its default.

sunrise.css

/* Sunrise: a warm light theme for Impulse Cart. Skin only. */
:root {
  /* colour */
  --bg:            #FFFDFB;
  --text:          #241C17;
  --text-muted:    #7A6E64;
  --accent:        #C2410C;   /* dark enough to read as text */
  --accent-hover:  #9A3412;
  --on-accent:     #FFFFFF;
  --card:          #FFFFFF;
  --border:        rgba(0,0,0,.12);
  --nav:           #FFF3EC;

  /* type */
  --font:          "Inter", system-ui, sans-serif;
  --heading-font:  "Fraunces", Georgia, serif;
  --h1:            3rem;
  --heading-tracking: -0.03em;

  /* shape + depth */
  --radius:        12px;
  --density:       1.1;      /* a little airy */

  /* effects: pick one per area */
  --btn-hover:     glow;
  --card-hover:    lift;
  --thumb-hover:   zoom;
}

14Selling your theme

Every marketplace theme is sold, not given away. Set the manifest's licence to "domain"; the theme then needs a licence key tied to the buyer's shop domain, using the same signing scheme as the store licence, so there is almost no new plumbing.

How a sale works: the buyer purchases the theme from the marketplace and gives their shop domain. A key bound to that theme and domain is issued with the sale, and the buyer pastes it into Admin → Appearance. You never handle keys: you build the theme, submit it, and keep 70% of every sale.

What the lock does

With no valid key on the shop's real domain, the theme's CSS is not served at all: the shop falls back to its built-in default skin and shows a persistent "unlicensed" badge, so the paid look is genuinely withheld, not watermarked. A key issued for one domain will not validate on another, so a copied theme and key cannot be resold or shared. On a local dev host the check is bypassed, so you can build freely.

15Ship checklist

  • <id>.css sets your variables in :root; <id>.json has at least id, name, licence.
  • id matches both file names and is a lowercase slug.
  • Each --*-hover is set to one keyword from its list.
  • All five contrast rules pass.
  • You set none of the --z-* variables and changed no structure.
  • Checked on both mobile and desktop.
  • "licence": "domain" is set in the manifest.

Made something good?

Sell your theme on Impulse Cart and keep 70% of every sale.

Submit a theme