Villa Windows — Design System (v2, Premium Refresh)
Villa Windows — Design System (v2, Premium Refresh)
For AI agents (e.g. reasonix): This document is the single source of truth for the visual refresh. It is written so you can implement it without seeing the site. Every value below is concrete (hex, px, rem, seconds, easing). Apply it by editing
assets/css/style.css(design tokens + component rules),_layouts/default.html(fonts, sticky-nav markup, scroll scripts), and the page.mdfiles (hero markup). ReadAGENTS.mdfirst — Jekyll conventions,relative_url, image standards and the “professional, heritage-focused, reliable” tone still apply.
A sophisticated, heritage-modern aesthetic: quiet elegance with craft at the centre. The refresh keeps the existing palette and serif identity but moves the site from flat and static to a layered, photographic, gently animated experience — full-bleed image heroes, a condensing sticky navigation, scroll-reveal motion, hover-zoom imagery, and a refined type system.
0. What changed from v1 (apply these)
| Area | v1 (old) | v2 (this spec) |
|---|---|---|
| Page background | warm off-white #faf9f5 |
clean white #ffffff, alternating with #f2f5f6 |
| Body font | system sans (-apple-system…) |
Hanken Grotesk (Google Font) |
| Hero | dark text-only block, no image | full-bleed photo + gradient overlay + ken-burns zoom + breadcrumb |
| Navigation | static bar | fixed, transparent-over-hero → frosted-white on scroll, + scroll-progress bar |
| Motion | basic reveal | reveal + stagger + hero parallax + image hover-zoom + FAQ accordion |
| Project gallery | fixed grid | responsive masonry (CSS columns), all 23 projects |
| Forms | N/A | Removed per latest instruction; replaced by direct contact methods. |
If a value here conflicts with the old CSS, this document wins.
1. Brand Personality
- Craft-led — quiet confidence, not loud salesmanship.
- Heritage modern — respects tradition, feels contemporary.
- Warm & understated — inviting, trustworthy, refined.
- Premium restoration — the feeling to leave a visitor with is “these are high-end specialists I can trust with my villa.”
2. Colour Palette
Define these as CSS custom properties on :root in assets/css/style.css.
| Token | Hex / value | Usage |
|---|---|---|
--color-bg |
#ffffff |
Default page / section background |
--color-bg-alt |
#f2f5f6 |
Alternating section background (cool light grey) |
--color-bg-card |
#ffffff |
Card / container backgrounds |
--color-bg-dark |
#0e1b25 |
Dark sections (Why Us, hero base, dark CTA) |
--color-bg-darker |
#0a151d |
Footer background |
--color-primary |
#3d6d8c |
Muted slate-blue — CTAs, accents, mono labels, CTA band |
--color-primary-hover |
#2d556e |
Primary button hover |
--color-primary-light |
#9fc0d4 |
Light blue-grey — labels/lines on dark, hero eyebrow |
--color-text |
#12222e |
Headings & primary text (very dark navy) |
--color-text-body |
#46535d |
Body copy on light backgrounds |
--color-text-soft |
#5a666e |
Secondary body copy |
--color-text-muted |
#bcc8ce |
Step numbers, metadata, faded text |
--color-text-inverse |
#ffffff |
Text on dark backgrounds |
--color-text-inverse-muted |
rgba(255,255,255,0.66) |
Muted text on dark |
--color-border |
rgba(18,34,46,0.12) |
Subtle borders on light |
--color-border-grid |
rgba(255,255,255,0.12) |
Grid borders on dark |
--overlay-image |
linear-gradient(180deg, rgba(10,22,31,.55) 0%, rgba(10,22,31,.12) 30%, rgba(10,22,31,.35) 62%, rgba(10,22,31,.85) 100%) |
Hero photo overlay |
--overlay-card |
linear-gradient(180deg, transparent 45%, rgba(10,22,31,.82)) |
Gallery caption overlay |
Selection: ::selection { background:#3d6d8c; color:#fff; }
3. Typography
Load via Google Fonts in <head> of _layouts/default.html (single <link>):
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Spectral:ital,wght@0,300;0,400;0,500;0,600;1,400&family=Hanken+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
| Token | Stack | Weights | Usage |
|---|---|---|---|
--font-heading |
'Spectral', Georgia, 'Times New Roman', serif |
400–500 (use 400 for large display) | All headings H1–H3, large numerals |
--font-body |
'Hanken Grotesk', system-ui, -apple-system, sans-serif |
400–700 | Body, navigation, buttons |
--font-mono |
'JetBrains Mono', 'SF Mono', 'Fira Code', monospace |
400–500 | Eyebrow labels, step numbers, breadcrumbs, metadata |
Set on body: -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility;
Headings: letter-spacing:-.01em (display H1 -.015em); text-wrap:balance on large headings.
Size scale
--text-xs: 0.75rem (12px) mono labels, breadcrumb
--text-sm: 0.875rem (14px) body small, nav links (13.5px ok)
--text-base: 1rem (16px) body
--text-lg: 1.0625rem (17px) intro / CTA body
--text-xl: 1.25rem (20px) project titles on overlays
--text-2xl: 1.375rem (22px) H3, feature/process titles
--text-3xl: clamp(1.875rem, 4vw, 3.25rem) H2 section headings
--text-4xl: clamp(2.625rem, 7vw, 6rem) H1 hero headings
--text-cta: clamp(2.125rem, 5.5vw, 4.25rem) CTA-band heading
Line height
- Body:
1.65–1.7 - Headings:
1.02–1.08(tight, elegant)
Eyebrow label pattern (.label-mono)
A short mono, uppercase, letter-spaced label preceded by a 30px rule. Reuse everywhere a section is introduced:
font: var(--font-mono); font-size:12px; letter-spacing:.24em; text-transform:uppercase;
color: var(--color-primary); /* on dark: var(--color-primary-light) */
/* preceding rule: 30px × 1px line in the same colour, 14px gap */
4. Spacing scale
--space-2:2px --space-4:4px --space-8:8px --space-12:12px --space-16:16px
--space-20:20px --space-24:24px --space-32:32px --space-40:40px --space-48:48px
--space-56:56px --space-64:64px --space-80:80px
- Section horizontal padding:
clamp(20px, 5vw, 64px) - Section vertical padding:
clamp(70px, 10vw, 130px) - Content max-width:
1280px, centred (margin:0 auto). Gallery may go to1320px.
5. Layout primitives
- Two-column editorial blocks (intro, service detail): CSS grid
repeat(auto-fit, minmax(320px, 1fr)), gapclamp(40px, 6vw, 90px),align-items:center. Alternate image/text side per block (useorderto flip). - Card grids (services, why-us):
repeat(auto-fit, minmax(260px, 1fr)), gap 18–24px. - Prefer flex/grid with
gapover inline-block + margins.
6. Components
6.1 Sticky navigation (<header> in default.html)
position:fixed; top:0; left/right:0; z-index:120;full-width, space-between layout.- Over the hero (scroll = 0): transparent background; logo + links in white.
- After scrolling > 60px: background
rgba(255,255,255,0.92),backdrop-filter:saturate(140%) blur(12px),box-shadow:0 1px 0 rgba(18,34,46,.08); links switch to#12222e; vertical padding shrinks22px → 14px. Transition all of this with.4s ease. - Scroll-progress bar: a 3px fixed bar at the very top,
background:var(--color-primary), width = scroll percentage,z-index:200. - Active page link:
font-weight:700+ 2px bottom border in current colour. - Implement the colour/condense swap with a small scroll listener (see §7) — toggling a
.is-scrolledclass on<header>is the cleanest Jekyll-friendly approach, with all the above expressed as CSS onheader.is-scrolled. - Keep the existing checkbox hamburger for mobile; ensure the toggle is visible in both
transparent and frosted states (use
currentColor).
6.2 Hero (.hero) — full-bleed photographic
Replace the old text-only hero. Structure per page:
section.hero (position:relative; min-height:100svh on home, clamp(380px,54vh,540px) on inner;
display:flex; align-items:flex-end; overflow:hidden; background:#0e1b25)
> div.hero-media (position:absolute; inset:-6% 0) img object-fit:cover
> div.hero-overlay (position:absolute; inset:0; background:var(--overlay-image))
> div.hero-inner (position:relative; z-index:3; max-width:1280px; padding-bottom:clamp(70px,11vh,130px))
.label-mono (eyebrow / breadcrumb)
h1
p (max-width:46–52ch; color:rgba(255,255,255,.84))
.hero-actions (primary + outline button)
- Ken-burns: animate the
imgtransform: scale(1.05) → scale(1.14)over22s ease-in-out infinite alternate. - Parallax (home only): translate
.hero-mediabyscrollY * 0.14pxin the scroll handler. - Entrance: stagger eyebrow → h1 lines → p → buttons with a
risekeyframe (opacity:0; translateY(34px)→0),cubic-bezier(.16,1,.3,1), delays.35s, .5s, .66s, .85s, 1s. - Inner pages use a shorter hero with a breadcrumb in
.label-mono(Home / Services), Home link at 70% opacity. - Home hero image:
assets/images/adobe-stock-sash-repair.jpg. Inner-page heroes pick a relevant image (Services →screenshot-retrofit-double-glazing.pngor the sash-repair shot; Projects →grange.jpg; FAQ →screenshot-service-maintenance.png; Estimate →casement-window-button.png). Always set descriptivealt.
6.3 Buttons (.btn)
- Primary:
background:var(--color-primary); color:#fff;border-radius:2px;padding16px 28px(hero/CTA17px 30px);font:600 14px var(--font-body);letter-spacing:.05em; text-transform:uppercase;hover →background:var(--color-primary-hover); transform:translateY(-2px);(transition.3s). .btn--outline:1px solid rgba(255,255,255,.5); color:#fff; background:transparent;hover →background:rgba(255,255,255,.12)..btn--white(on coloured bands):background:#fff; color:#12222e;hover →translateY(-2px)+box-shadow:0 20px 40px -20px rgba(0,0,0,.5).- No heavy shadows — favour the clean lift.
6.4 Homepage services list (.service-items)
Keep the existing numbered-list pattern but as a refined process list:
- Each
.service-itemseparated by1px solid var(--color-border)top borders. .service-step: Spectral 30px,color:var(--color-text-muted)(last/active itemvar(--color-primary)), min-width 54px.- Title Spectral 22px
#12222e; body 15pxvar(--color-text-soft), max-width ~48ch. - Left column (intro + CTA) may be
position:sticky; top:110pxon wide screens.
6.5 Service cards (Services page / Home “what we do” grid)
background:#fff; border-radius:3px; overflow:hidden;photo on top (aspect-ratio:4/3,object-fit:cover), text body below.- Mono index label (
SASH · 01), Spectral 21px title, soft body, “Learn more →” invar(--color-primary)uppercase 13px. - Hover: card
translateY(-8px)+box-shadow:0 30px 60px -34px rgba(14,27,37,.45); inner imagescale(1.07)over1.1s cubic-bezier(.16,1,.3,1).
6.6 Feature grid — “Why Us” (.features-grid / .feature-item)
- Dark section
background:var(--color-bg-dark). - Grid with 1px hairlines between cells: wrap in a container with
background:var(--color-border-grid)andgap:1px, each.feature-itemsolid#0e1b25, padding36px 32px. .feature-num: JetBrains Mono 12pxvar(--color-primary-light).- Title Spectral 22px white; body 14.5px
var(--color-text-inverse-muted).
6.7 Project gallery (our-projects.md) — masonry, all projects
- All 23 projects must render (see image list §9). Use a CSS columns masonry so
varied photo heights pack naturally:
column-width:320px; column-gap:18px;and each tilebreak-inside:avoid; -webkit-column-break-inside:avoid; margin:0 0 18px;border-radius:3px; overflow:hidden; position:relative; img { width:100%; height:auto; },loading="lazy".- Caption overlay:
var(--overlay-card), content bottom-left — mono category tag invar(--color-primary-light)+ Spectral 20px white title. - Hover: image
scale(1.06)over1.2s cubic-bezier(.16,1,.3,1). - Keep the existing lightbox script working (add
.lightbox-triggerto gallery imgs if desired).
6.8 FAQ accordion (faqs.md)
- Single-column, max-width 880px. Each item separated by
1px solid var(--color-border)top rule. - Button row: Spectral 18–23px question (left) + a 34px circular
+icon (right).- Closed: circle
1px solid rgba(18,34,46,.2),+in#12222e. - Open: circle filled
var(--color-primary), icon white, rotate 135° (becomes ×), transition.4s cubic-bezier(.16,1,.3,1).
- Closed: circle
- Answer panel animates
max-height 0 → ~320px+opacity 0 → 1over.5s. One open at a time. - Implement with minimal JS (toggle an
.openclass) — no framework.
6.9 Free-estimate form (free-estimate.md)
- Two-column: form (1.4fr) + contact sidebar (1fr), gap
clamp(36px,5vw,72px). - Fields:
border:1px solid rgba(18,34,46,.18); border-radius:2px; padding:14px 16px;focus →border-color:var(--color-primary); box-shadow:0 0 0 3px rgba(61,109,140,.12);Style the<select>with a custom SVG chevron. - Sidebar: a dark
#0e1b25card with the phone number in Spectral 34px, plus a bordered card with email / area / guarantee. - On submit, show an animated success card (check icon in a
var(--color-primary)circle,popkeyframescale(.85)→1). If kept static (no JS), at minimum style a thank-you state.
6.10 CTA band (.cta-box)
- Two variants:
var(--color-primary)(slate-blue) orvar(--color-bg-dark). - Faint vertical pane grid motif overlay (
repeat(4,1fr)columns with1px rgba(255,255,255,.1)right borders,opacity:.5). - Centred eyebrow + Spectral CTA heading (
--text-cta) + body + two buttons.
6.11 Footer
background:var(--color-bg-darker); 4-column grid (brand, quick links, explore, contact).- Links hover →
var(--color-primary-light). Bottom row: copyright + mono tagline, separated by1px solid rgba(255,255,255,.1).
7. Motion & interaction
Add to the existing script block in _layouts/default.html. Respect
@media (prefers-reduced-motion: reduce) by skipping transforms.
- Scroll reveal (reuse existing
.revealmechanism): startopacity:0; transform:translateY(24–30px); on enter add.active→opacity:1; transform:none. Transition.85–.9s cubic-bezier(.16,1,.3,1). PreferIntersectionObserver(threshold ~0.12,rootMargin:0 0 -6% 0) over scroll math for performance; keep the current scroll fallback if simpler. - Stagger: sequential children offset by
0.08–0.16s(settransition-delayinline or via:nth-child). - Sticky-nav condense + colour swap + progress bar + hero parallax: one passive
scrolllistener togglingheader.is-scrolled, setting the progress-bar width, and (home only) translating.hero-media. Throttle is unnecessary if it only writes a class + two style props. - Image hover-zoom:
transform:scale(1.06–1.07)over1.1–1.2s cubic-bezier(.16,1,.3,1)inside anoverflow:hiddenparent. - Standard easing everywhere:
cubic-bezier(.16,1,.3,1). - Keyframes to define:
kb(ken-burns),rise(entrance),floatY(scroll cue),pop(form success),paneIn(overlay fade).
8. Borders, radius, elevation
border-radius:2pxfor cards/buttons/inputs;3pxfor image containers.- Borders
1px solid rgba(...)— hairline, never heavy. - Shadows only on hover lift:
0 30px 60px -34px rgba(14,27,37,.45)(cards),0 20px 40px -20px rgba(0,0,0,.5)(white button on colour).
9. Imagery
All images already live in assets/images/ (per AGENTS.md: max 1920px, JPEG photos / PNG
graphics, descriptive alt). Reference with /assets/images/NAME.
Projects gallery — render all 23 (filename → suggested title → category tag):
villa-street.png Villa Street RESTORATION
liv2.png Living Room Double Glazing DOUBLE-GLAZING
double-glazed-villa-1-tall.png Double Glazed Villa DOUBLE-GLAZING
23-john.png 23 John Street RESTORATION
thi.png Timber Window Restoration RESTORATION
liz-house.png Liz's House DOUBLE-GLAZING
simon-peat.png Simon Peat Project RESTORATION
liz-loft.png Liz's Loft RESTORATION
casement-win-2.png Casement Window Retrofit CASEMENT
dgu-1.png DGU Installation DOUBLE-GLAZING
grange.jpg The Grange Restoration RESTORATION
french-doors.png Custom French Doors JOINERY
andy-lamb.png Andy Lamb Joinery JOINERY
cathedral-glass.png Cathedral Glass Feature GLASS FEATURE
etchlite.png Etchlite Glass Installation GLASS FEATURE
project-detail-1.png Sash Component Detail DETAIL
project-detail-2.png Window Frame Restoration RESTORATION
project-detail-3.png Joinery Craftsmanship JOINERY
project-detail-4.png Double Glazing Seal DETAIL
project-detail-5.png Workshop Progress WORKSHOP
project-detail-6.png Heritage Window Profile DETAIL
project-detail-7.png Finished Timber Joinery JOINERY
project-detail-8.png Sash Window Install SASH
(Titles/tags are editorial suggestions — confirm with the client where a real project name exists.)
10. Responsive breakpoints
--bp-sm:480px --bp-md:768px --bp-lg:1024px --bp-xl:1280px
Mobile-first. Two-column blocks collapse to one column (auto-fit handles this). Hero text
scales via the clamp() sizes above. Nav collapses to the existing hamburger below --bp-md.
11. Accessibility
- Visible
:focus-visibleon all interactive elements (2–3px ring invar(--color-primary)). - Contrast ≥ 4.5:1 for body text (white-on-
#0e1b25and#12222e-on-white both pass). - One
<h1>per page; semanticheader/main/section/footer. alton every image;aria-labelon the nav toggle.- Honour
prefers-reduced-motion: reduce— disable ken-burns, parallax, reveal transforms.
12. Implementation checklist (for reasonix)
- Add the Google Fonts
<link>to_layouts/default.html<head>. - Update
:roottokens inassets/css/style.cssto §2 / §3 / §4. - Rework
<header>markup + add.is-scrolledstyles, scroll-progress bar, active-link state. - Rebuild
.heroas the photographic layout (§6.2); update each page’s hero markup in its.md. - Restyle buttons, service list, service cards, why-us grid, CTA band, footer (§6).
- Convert
our-projects.mdto the masonry gallery with all 23 images (§6.7 / §9). - Build the FAQ accordion (§6.8) and the estimate form styles + success state (§6.9).
- Extend the script block: IntersectionObserver reveals, sticky-nav condense, parallax, keyframes (§7).
- Verify with Playwright screenshots (per
AGENTS.md); check reduced-motion and mobile.
Heritage modern. Quiet elegance. Craft at the centre.