Skip to main content

Rebranding

Rebranding a tenant never touches a template. The Meridian reference baseline isolates every brand decision in a small set of files: two CSS files, two blocks in blueprint.yaml, and one block in payment.yaml. Swap those, and every document, email, and payment page renders in your brand.

The reference proposal rendered at desktop width
The same template at desktop…
The reference proposal rendered at mobile width
…and at mobile — both driven entirely by the token layer you replace.

The two-layer token architecture

assets/css/variables.css defines all design tokens in two layers:

  • Layer 1 — primitive tokens. The vendored design-system values: raw brand colors, shadows, and neutrals. This is the only layer a fork replaces.
  • Layer 2 — the semantic API. The variable names main.css and every template actually consume: --color-primary, --color-accent, --color-canvas, the spacing scale, the type scale. These names are the contract — they stay identical across tenants, mapped onto your Layer 1 primitives.

Because templates only ever reference Layer 2 names, they need zero edits when rebranding. You change what --color-primary points at; you never change who uses it.

Layer 1 — primitives (excerpt)

:root {
/* Layer 1 · primitives (vendored design-system values) */

/* Primary teal */
--flux-primary-800: #032E36;
--flux-primary-600: #034955;
--flux-primary-400: #056F82;
--flux-primary-100: #E6F1F2;

/* Yellow (CTA / warmth) */
--flux-yellow-400: #FFBC42;
--flux-yellow-100: #FFF8EC;

/* Neutrals */
--flux-black: #212121;
--flux-grey-500: #6B7280;
--flux-background: #F9FAF8;
--flux-white: #FFFFFF;
}

Layer 2 — the semantic API (excerpt)

:root {
/* Layer 2 · semantic API — consumed by main.css and all templates.
Keep these names IDENTICAL across tenants. */

--color-primary: var(--flux-primary-600);
--color-primary-hover: var(--flux-primary-700);
--color-accent: var(--flux-yellow-400);
--color-accent-soft: var(--flux-yellow-100);
--color-canvas: var(--flux-background);
--color-surface: var(--flux-white);
--color-ink: var(--flux-black);
--color-text-muted: var(--flux-grey-500);

/* Spacing scale — 4px base */
--space-4: 16px;
--space-7: 48px;
--space-9: 96px;

/* Type scale */
--font-size-sm: 14px;
--font-size-md: 16px;
--font-size-2xl: 32px;
}

To rebrand: replace the Layer 1 values with your palette, then point each Layer 2 token at the right primitive. Do not rename or remove Layer 2 tokens — the QA suite renders every template against them.

Fonts

assets/css/fonts.css loads the typefaces and defines three font tokens that are part of the semantic API:

@import url('https://fonts.googleapis.com/css2?family=Lexend:wght@300;400;500;600;700&display=swap');

:root {
--font-heading: 'Lexend', system-ui, -apple-system, sans-serif;
--font-body: 'Lexend', system-ui, -apple-system, sans-serif;
--font-feature: 'Lexend', system-ui, -apple-system, sans-serif;
}

Replace the @import with your own Google Fonts import or self-hosted @font-face rules, then point the three tokens at your families. Keep the token names: --font-heading (headings, day pills, numerics), --font-body (paragraphs, labels), and --font-feature (the editorial voice — eyebrows, pull-quotes, personal notes).

blueprint.yaml — branding and email_branding

Two blocks in the blueprint carry brand values that resolve outside CSS:

  • branding — the tenant name, logo URL, logo alt text, and primary color used by the document viewer chrome.
  • email_branding — everything email templates consume: logo, from_name, reply_to, a colors map (primary, accent, link, background, surface, text, border, success, error, and their variants), font families and font URLs, and a footer block with the company details. The example below shows the block as it looks after forking, with "Acme Travel" standing in for your company's values:
email_branding:
logo_url: https://www.example.com/brand/logo.svg
logo_alt: Acme Travel
from_name: Acme Travel
reply_to: hello@example.com
colors:
primary: '#034955'
accent: '#FFBC42'
link: '#056F82'
background: '#F9FAF8'
text: '#212121'
footer:
company_name: Acme Travel
phone: '+1 555 0100'
website: https://www.example.com
tagline: Travel, thoughtfully crafted.

The shared email body in the blueprint is fully brand-free: every brand-specific value resolves through {{branding.*}} expressions — {{branding.logo_url}}, {{branding.footer.company_name}}, {{branding.footer.phone}}, and so on. Email templates carry zero hardcoded brand strings. When you rebrand, you edit the email_branding block only; the email HTML never changes.

payment.yaml — branding

The payment pages have their own branding block in payment.yaml with the same shape: name, a logo object (url, alt, height), a colors map, and fonts. Keep it visually consistent with the document brand — guests move from document to payment page in one click. See Edge Pay configuration.

Logo constraints

  • The logo must be a transparent SVG or PNG. The document hero applies a white-knockout treatment to the logo; an opaque tile (a logo baked onto a solid background) renders as a blank box.
  • Provide a logo that is legible on dark grounds — it appears over the hero gradient and in the email header band.

Rules that keep rebranding safe

  • Never hardcode hex values in templates. Every color goes through a Layer 2 semantic token. A hex literal in a template survives the first rebrand and breaks the second.
  • Never reintroduce per-brand token names. The semantic API is brand-agnostic by design; tenant-named CSS variables defeat it.
  • Email templates resolve everything from {{branding.*}}. If you find yourself typing your company name into email HTML, put it in email_branding.footer instead.

After rebranding, run the full QA suite — the rendered output is asserted at desktop and mobile viewports, so token mistakes (for example a missing Layer 2 mapping) surface immediately. See Running the test harness.