Skip to content

DESIGN.Www

WarmlyYours WWW is the public-facing marketing and e-commerce site at warmlyyours.com. It sells radiant heating into a residential audience, so the visual identity leans warm, premium, and confidence-inspiring — not technical or corporate. The single non-negotiable brand element is the burgundy primary (#983333); everything else is interchangeable scaffolding around it.

The system layers Bootstrap 5.3 underneath bespoke SCSS in client/stylesheets/www/. Bootstrap is the structural skeleton (grid, buttons, forms, breadcrumbs); brand identity is layered through the variables in 00-variables/ and the components in 03-components/. Treat the tokens here as the canonical source — when SCSS and this file disagree, the SCSS is drift.

There are two typographic registers:

  1. Brand pages — sofia-pro (sans) for everything; orpheuspro (serif) only for occasional display moments where warmth needs to be amplified.
  2. Blog and long-form editorial — Inter for body, Playfair Display for headings. Self-hosted; do not reach for Google Fonts.

The palette has three layers:

Identity. primary (Rich Burgundy #983333) is the brand. It anchors buttons, links, headings, and primary surfaces. primary-hover is +10% lightness and is the only sanctioned hover treatment for the primary.

Neutrals. light-shade is the canonical page background — warmer than pure white, deliberately. Body text is dark-shade. Secondary/muted text should use gray-700 (the lowest gray that clears WCAG AA 4.5:1 on light-shade); avoid lighter grays for text. dark-accent is for body-on-body contrast, not text on light surfaces.

Mood palette. mint-green, muted-navy-blue, earthy-taupe, warm-copper, and warm-cream are page-section moods. They are not arbitrary accents — pick one to set tone for an extended section, then let the rest of the section inherit.

The numeric gray-100gray-900 scale exists for borders, dividers, and disabled states. Reach for it before inventing new hexes.

Sofia-pro and orpheuspro are the brand pair. Sofia-pro’s regular weight in this system is 300 (light) — that is intentional and gives the marketing surface its airy feel. 500 is “medium” (the actual semibold), used for headings and emphasis. 600 is reserved for buttons and small UI moments where sans-serif needs to feel solid.

Orpheuspro is a serif tucked in for display moments — hero subheads, pull quotes, occasional editorial sections. Don’t use it for running body copy.

Blog content uses Inter + Playfair Display, self-hosted from public/fonts/inter/ and public/fonts/playfair-display/. These are variable fonts; the weight ranges (400 600 for Inter, 400 700 for Playfair) load once and cover the whole spectrum. Don’t add additional weight files — use font-weight to interpolate.

font-display: swap is set on every face. Keep it that way — FOIT is worse than FOUT on a marketing site.

Bootstrap 5.3 grid with one custom breakpoint added: xxl at 1600px (default Bootstrap stops at xl: 1200px). Container max-widths likewise extend to 1540px at xxl. The intent: hero imagery and showcase grids breathe on large monitors without requiring a per-page max-width override.

Spacing scale follows Bootstrap’s 0–5 ladder (0 / 0.25 / 0.5 / 1 / 1.5 / 3 rem). Levels 6 and 7 (4.5rem, 6rem) are aspirational extensions for section spacing on marketing landing pages where Bootstrap’s 5 (3rem) is too tight. Use them for vertical rhythm between full-page sections, not for inter-component spacing.

A second -em track exists in SCSS (1-em, 2-em, etc.) for components whose padding should scale with their own font-size. Prefer rem-based spacing unless you’re authoring a typographic component.

Flat by default. The only sanctioned elevation moments:

  • Cards lift via background contrast against light-shade, not shadows.
  • Modal/overlay uses Bootstrap’s default box-shadow scale.
  • Sticky headers use a 1px bottom border in gray-200, not a shadow.

If you reach for box-shadow on a content surface, reconsider — the brand voice is calm, not floating.

Subtle, not pill. rounded.md (0.3rem) is the default for buttons, inputs, selects. rounded.lg (0.5rem) is reserved for promotional cards (warm palette). Pills are only for badges and tags.

Image thumbnails are explicitly square (rounded.none) — that is a catalog-imagery decision, not an accident.

The button hierarchy is:

  1. Primary — burgundy, on the warm body color. One per significant CTA moment.
  2. Secondary — sage (light-accent). For “alternative” or “learn more” alongside a primary.
  3. Link — text-only burgundy. For tertiary or in-flow actions.

Forms use Bootstrap’s standard treatment with the brand layered: white-ish backgrounds (on-primary), brand burgundy is not the focus ring color — focus uses Bootstrap’s blue (#86B7FE) at 2px to avoid red-on-red ambiguity on validation states. This is a deliberate exception to the “primary everywhere” pattern.

The custom checkbox/radio treatment is unusually large (1.5rem) by spec and uses success green (not primary burgundy) for the checked state. Keep it.

Breadcrumbs sit on light-shade with subdued type and no underline; they’re navigational but should never compete with the H1.

Page sections are themed by background (page-section-* tokens). Pick one mood per section; do not chain three section themes vertically — that breaks rhythm.

Do anchor every page in light-shade background and dark-shade body text. The warm off-white is the brand’s most recognizable neutral.

Do use gray-700 for muted/secondary text. Anything lighter fails WCAG AA on the warm background.

Do use named palette colors (mint-green, warm-cream, muted-navy-blue) as section moods, not as one-off accents inside other sections.

Do lean on Bootstrap utilities (text-primary, bg-light, spacing classes) before writing new SCSS.

Don’t introduce new hex values for greys — the gray-100gray-900 scale exists for this. New grey tokens in component SCSS are drift.

Don’t use orpheuspro for running body copy. It’s a display face.

Don’t add a third typographic register. Brand vs. blog is the boundary.

Don’t override the form focus ring with brand red. Brand red on a validation-red error state is unreadable.

Don’t stack box shadows. If a surface needs to lift, raise the background contrast or add a 1px border instead.