Bonatsa House Design System
Overview
Bonatsa House presents a luxury villa rental experience rooted in the warm, sun-drenched aesthetic of Cycladic architecture. The design system is built upon a creamy canvas foundation ({colors.canvas} — #f5efe6) that immediately evokes the whitewashed walls and golden-hour light of Antiparos. This is not a stark white minimalism but rather a living warmth — the palette draws from sand, stone, aged linen, and the amber glow of Mediterranean evenings.
Brand voltage lives selectively and deliberately. The primary color ({colors.primary} — #d3b895) is a sophisticated sand-beige that appears on CTAs ({component.button-primary}), secondary action buttons, and as accent touches throughout. It never overwhelms; instead, it acts as a gentle warmth against the cooler cream canvas and the deep ink text. The system trusts in restraint — there are no neon accents, no gradient explosions, no competing brand colors fighting for attention.
The single typography move that defines this system is the serif-sans pairing at modest weights. Display headlines ({typography.display-lg}) and section titles ({typography.title-md}) render in Thomas Mag, an elegant serif with traditional proportions that evoke editorial luxury and architectural heritage. Body copy, navigation, and UI chrome default to Lexend, a geometric sans-serif rendered at a remarkably light weight ({typography.body-md} uses font-weight: 300). This creates a striking contrast: the serif headlines feel authoritative and timeless, while the body text feels airy, modern, and effortlessly readable — like breathing in sea air.
Shape language leans toward the gently rounded. Buttons use {rounded.xs} (3–5px), cards sit at {rounded.md} (8px) to {rounded.lg} (10px), and slider dots go fully pill-shaped ({rounded.pill}). There are no sharp 90° corners on interactive elements, yet nothing feels overly bubbly or toy-like. The geometry mirrors the soft edges of stucco walls worn by salt air.
Sub-systems observed include the hero carousel dialect (full-bleed photography with overlaid text, dot navigation, darkened image treatments via {component.overlay-dark}) and what appears to be a booking/reservation dialect (form inputs, date selectors, CTA bands). The navigation system operates on the {colors.canvas} surface while hero content inverts to white-on-photography.
Key Characteristics:
- Cream canvas (
{colors.canvas}) as the foundational surface — warm, never sterile - Sand-beige primary (
{colors.primary}) used exclusively for CTAs and signature actions - Ink text (
{colors.ink}) at#4c4334— a warm near-black, never pure#000000 - Serif headlines (Thomas Mag) at weight 400 paired with ultra-light sans body (Lexend) at weight 300
- Generous line heights (1.67 on
{typography.body-md}) creating an editorial, breathable reading experience - Subtle shadow system (
{extensions.shadows.sm}) with 20% black opacity for gentle elevation - Uppercase button text with slight letter-spacing (
{typography.button}) conveying refined formality - Full-bleed hero imagery with dark overlays (
{component.overlay-dark}) for text legibility - Pill-shaped slider indicators (
{component.slider-dot-active}) for carousel navigation
Colors
Brand & Accent
- Primary (
{colors.primary}— #d3b895): The signature sand-beige used on all primary CTAs ({component.button-primary}), the "BOOK NOW" button in navigation, and "OUR HOUSE" hero button. Conveys warmth, natural materials, and luxury without ostentation. - Primary Hover (
{colors.primary-hover}— #c5a883): Darkened primary state for interactive hover feedback on buttons. - Primary Active (
{colors.primary-active}— #b89870): Pressed/deeper state for touch feedback. - Primary Disabled (
{colors.primary-disabled}— #e8dcc8): Muted, desaturated primary for unavailable actions.
Surface
- Canvas (
{colors.canvas}— #f5efe6): The foundational cream color for navigation bar ({component.top-nav}), footer ({component.footer}), CTA bands, and any section needing a warm off-white background. Evokes aged linen or sun-bleached stone. - Surface (
{colors.surface}— #ffffff): Pure white used for card backgrounds ({component.card}), input fields ({component.text-input}), and content containers requiring maximum contrast. - Surface Warm (
{colors.surface-warm}— #faf6f0): A subtly warmer white variant for secondary content areas. - Dark Overlay (
{colors.surface-dark-overlay}— rgba(0, 0, 0, 0.2)): Applied over hero photography to ensure white text remains legible without crushing the image. - Darker Overlay (
{colors.surface-darker-overlay}— rgba(0, 0, 0, 0.44)): Heavier darkening for sections requiring stronger text contrast over imagery. - Light Overlay (
{colors.surface-light-overlay}— rgba(255, 255, 255, 0.4): Used for inactive slider dots ({component.slider-dot-inactive}) to create subdued visibility against dark backgrounds.
Text
- Ink (
{colors.ink}— #4c4334): The primary text color — a warm near-black used for body copy on light surfaces, navigation links ({component.nav-link}), and most UI text. Softer than pure black, harmonizing with the warm canvas. - Body White (
{colors.body}— #ffffff): White text used exclusively on dark surfaces — hero headlines ({component.hero-headline}), hero subtext, slider dots, and any text overlaid on photography. - Text Dark (
{colors.text-dark}— #111111): Near-black for maximum contrast headings on white surfaces when extra emphasis is needed. - Text Dark Gray (
{colors.text-dark-gray}— #222222): Secondary dark text for subtler hierarchy on white. - Text Medium (
{colors.text-medium}— #333333): Tertiary dark text for captions, metadata, or de-emphasized content. - Muted (
{colors.muted}— #aaaaaa): Medium gray for placeholder text, disabled labels, or tertiary information. - On Primary (
{colors.on-primary}— #4c4334): Text color for content sitting atop{colors.primary}buttons — the warm ink ensures AA contrast against the sand-beige. - On Dark (
{colors.on-dark}— #ffffff): White text on any dark/black surface. - On Canvas (
{colors.on-canvas}— #4c4334): Standard readable text on the cream canvas background.
Hairlines & Borders
- Hairline (
{colors.hairline}— #e8dcc8): Subtle border color matching a lightened primary tone — used for dividers, input borders, and card separators. - Hairline Soft (
{colors.hairline-soft}— #f0e6d6): Even lighter variant for barely-visible separators. - Border Muted (
{colors.border-muted}— #999c98): Medium gray for checkbox borders and form element chrome.
Semantic
- Error (
{colors.error}— #c13515): Reserved for validation errors, alert states, and destructive actions. - Success (
{colors.success}— #006400): For confirmation messages, successful bookings, and positive status indicators. - Link (
{colors.link}— #4c4334): Inline links inherit the ink color, gaining underline decoration. - Link Active (
{colors.link-active}— #2a241c): Darkened link state on hover/interaction.
Typography
Font Family
The Bonatsa House type system is built on a deliberate two-font pairing. Thomas Mag, a proprietary serif font served via CDN (@font-face declaration pointing to .otf format), handles all display and headline roles. It carries the editorial weight of the brand — elegant, traditional, with the slightly irregular character of a quality book face. This font appears in the logo mark, the massive hero headline ("Your Luxury Traditional Villa with Private Pool in Antiparos"), and all section titles throughout the page.
Lexend, a Google Font (loaded via fonts.googleapis.com with weights 300–700 available), serves as the workhorse for everything else: body copy, navigation links, button labels, captions, and UI chrome. The system predominantly uses Lexend at weight 300 (ExtraLight), which gives body text an ethereal, luxurious quality — words seem to float on the cream canvas. Navigation links bump to weight 400 for slight additional presence.
The fallback stack for Thomas Mag is simply serif; for Lexend it's sans-serif. No monospace font is deployed in this design.
Hierarchy
| Token | Size | Weight | Line Height | Letter Spacing | Use |
|---|---|---|---|---|---|
| {typography.display-xl} | 64px | 400 | 1.2 | -0.01em | Future-use mega headlines (not in current viewport) |
| {typography.display-lg} | 50px | 400 | 1.2 | 0 | Hero headline — the dominant typographic moment |
| {typography.title-md} | 35px | 400 | 1.2 | 0 | Section headings on light backgrounds |
| {typography.title-sm} | 28px | 400 | 1.25 | 0 | Subsection titles, card headings |
| {typography.body-lg} | 20px | 300 | 1.6 | 0 | Lead paragraphs, feature descriptions |
| {typography.body-md} | 18px | 300 | 1.67 | 0 | Standard body copy, paragraph text |
| {typography.body-sm} | 16px | 300 | 1.5 | 0 | Secondary body text, compact paragraphs |
| {typography.caption} | 14px | 300 | 1.4 | 0 | Metadata, timestamps, fine print |
| {typography.button} | 16px | 300 | 1.25 | 0.05em | CTA buttons, action labels (uppercase) |
| {typography.nav-link} | 13px | 400 | 1.4 | 0.08em | Navigation menu items (uppercase, tracked-out) |
Principles
The typography system's defining characteristic is weight restraint combined with generous scale. No text in the entire system exceeds weight 400 (Regular). Headlines achieve dominance through size alone — the hero headline at 50px ({typography.display-lg}) is nearly three times the size of body text at 18px ({typography.body-md}), yet both sit at or below weight 400. This creates a refined, "unshouted" hierarchy where scale does the work that bolding would do in lesser systems.
Letter-spacing plays a functional role in small uppercase elements. Navigation links ({typography.nav-link}) use 0.08em tracking to maintain legibility at 13px uppercase. Button labels ({typography.button}) use 0.05em — enough to give the uppercase letters breathing room without looking artificially spaced. All other text sits at normal letter-spacing, trusting the native metrics of Thomas Mag and Lexend.
Line heights are notably generous — {typography.body-md} runs at 1.67 (roughly 30px for 18px type), giving the text an editorial, luxury-magazine feel. This is not dense information design; it's immersive storytelling where the reader is invited to linger.
Note on Font Substitutes
Thomas Mag is a proprietary font served from Webflow's CDN and may not be available in all build environments. For open-source substitutions, Playfair Display (Google Fonts) offers the closest match in spirit — a transitional serif with similar contrast and elegance, though slightly more decorative. Cormorant Garamond is a lighter-weight alternative that better matches the specific gravity of Thomas Mag. For Lexend, no substitution is needed as it is already a Google Font. Define CSS variables --font-display: 'Playfair Display', serif; and --font-body: 'Lexend', sans-serif; for easy swapping.
Layout
Spacing System
- Base unit: 4px (derived from the smallest spacing token
{spacing.xxs}). - Tokens:
{spacing.xxs}(4px — micro-gaps, icon padding),{spacing.xs}(5px — tight internal padding),{spacing.sm}(6px — small gaps),{spacing.md}(8px — standard gaps),{spacing.lg}(10px — button padding),{spacing.xl}(16px — component margins),{spacing.xxl}(20px — frequent utility spacing, the most-used value at 49 occurrences),{spacing.section-sm}(30px — minor section spacing),{spacing.section-md}(40px — standard section padding),{spacing.section-lg}(60px — major section vertical rhythm),{spacing.section-xl}(80px — hero-level breathing room). - Section padding (vertical):
{spacing.section-lg}(60px) for standard content sections;{spacing.section-xl}(80px) for hero and signature moments. - Card internal padding:
{spacing.section-md}(40px) per{component.card}— generous interior space reinforcing the luxury positioning. - Gutters: Container-level gutters appear to use
{spacing.xl}(16px) on each side within the max-width constraint.
Grid & Container
- Max content width: 1440px (observed on
<section>elements). The design breathes at wide desktop viewports rather than crunching into a narrow column. - Editorial density: Low-to-moderate. This is a narrative landing page, not a dashboard or marketplace. Content has room to expand horizontally.
- Grid behavior at desktop: The hero section uses a single-column text block positioned left-of-center over full-bleed imagery. Below the hero, content appears to flow in a centered container with flexible internal layouts.
- Hero column split: Text occupies approximately the left 45–50% of the viewport, leaving the right side for architectural photography to shine through.
Whitespace Philosophy
The system embraces editorial airiness as a core design principle. Spacing tokens skew large ({spacing.xxl} at 20px is the most frequently occurring value), line heights exceed 1.5 for body text, and section padding starts at 60px vertically. This is not wasted space — it is structural whitespace that signals luxury, calm, and the unhurried pace of a villa vacation. The design refuses density; every element earns its position through surrounding negative space.
Header Architecture
┌─────────────────────────────────────────────────────────────────────────────┐
│ [LOGO] HOME OUR HOUSE ANTIPAROS LIFESTYLE CONTACT [BOOK NOW] │
│ ←————— navigation links (nav-link) —————→ │
│ ↑ button │
│ (button-primary) │
└─────────────────────────────────────────────────────────────────────────────┘
←—— max-width container (1440px implicit) ——→
The navigation bar ({component.top-nav}) sits on {colors.canvas}, approximately 80px tall, with the logo mark left-aligned, navigation links center-distributed with generous horizontal spacing, and the "BOOK NOW" CTA right-aligned. At narrower viewports, the hamburger menu button ({component.menu-button}) appears.
Hero Section
┌─────────────────────────────────────────────────────────────────────────────┐
│ │
│ ┌──────────────────────────┐ │
│ │ │ ╔══════════════════════════╗ │
│ │ Your Luxury │ ║ ║ │
│ │ Traditional Villa │ ║ VILLA PHOTOGRAPHY ║ │
│ │ with Private Pool in │ → ║ (full-bleed, ║ │
│ │ Antiparos │ ║ evening light) ║ │
│ │ │ ║ ║ │
│ │ [OUR HOUSE] │ ╚══════════════════════════╝ │
│ └──────────────────────────┘ │
│ │
│ ○ ● ○ ○ (slider dots) │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
↑ overlay-dark (20% black) for text legibility
The hero band ({component.hero-band}) is a full-viewport-height section with a background image (villa at dusk/evening with pool), darkened by {component.overlay-dark}. The headline ({component.hero-headline}) renders in Thomas Mag at 50px in white, left-aligned with substantial left padding. Below it sits a secondary CTA button ({component.button-secondary} — "OUR HOUSE") in the sand-beige primary color. Slider dot navigation appears bottom-center.
Elevation & Depth
| Level | Treatment | Use |
|---|---|---|
| 0 (Flat) | No shadow, {colors.canvas} or {colors.surface} background | Navigation bar, footer, flat sections |
| 1 (Soft) | {extensions.shadows.sm} — 0 4px 15px rgba(0,0,0,0.2) | Primary buttons ({component.button-primary}), elevated cards |
| 2 (Medium) | {extensions.shadows.md} — 0 4px 20px rgba(0,0,0,0.2) | Featured cards, dropdown panels |
| 3 (Strong) | {extensions.shadows.lg} — 0 4px 12px rgba(0,0,0,0.3) | Modals, critical overlays |
| Overlay | {colors.surface-dark-overlay} or {colors.surface-darker-overlay} | Hero text legibility, image text overlays |
The elevation philosophy favors subtle, warm-toned shadows over dramatic layering. Even the strongest shadow ({extensions.shadows.lg}) uses only 30% opacity black — there are no cold blue-tinted shadows, no multi-layer blur stacks, no dramatic "floating card" effects. Depth is suggested rather than declared. This aligns with the Mediterranean material honesty: stucco and stone don't float, they rest.
The primary depth mechanism for hero content is color-block layering via overlays rather than drop shadows. Text sits on a darkened photograph, not on a floating card. This creates an integrated, immersive feeling — the user is looking through a window at the villa, not at a card about the villa.
Shapes
Border Radius Scale
| Token | Value | Use |
|---|---|---|
| {rounded.xs} | 3px | Primary button ({component.button-primary}) — the sharpest interactive corner |
| {rounded.sm} | 5px | Default radius, secondary buttons, inputs |
| {rounded.DEFAULT} | 5px | System default fallback |
| {rounded.md} | 8px | Standard cards ({component.card}) |
| {rounded.lg} | 10px | Elevated cards ({component.card-elevated}), featured containers |
| {rounded.pill} | 9999px | Slider dots ({component.slider-dot-active}), avatar placeholders |
| {rounded.full} | 9999px | Fully rounded elements (alias for pill) |
Photography Geometry
Hero and feature photography uses full-bleed, uncropped treatments spanning the entire viewport width with no border radius — the image edge IS the container edge. Photography is rectangular, never masked into shapes or given rounded corners. The visual framing comes from overlay darkening and text positioning, not from image cropping geometry. Aspect ratios appear to be native photographic (likely 16:9 or 3:2 for landscape villa shots). Images dominate the hero section, with text overlaid rather than side-by-side in a traditional two-column layout.
Components
No hover states documented. Hover behavior is unreliable to extract from a single screenshot. State variants live as separate entries in the
components:frontmatter (e.g.,{component.button-primary-active},{component.text-input-focus}); add hover styling at implementation time per your stack's conventions.
Buttons
{component.button-primary} — The primary call-to-action button used for "BOOK NOW" in the navigation bar. Background {colors.primary} (sand-beige), text {colors.on-primary} (warm ink), type {typography.button} (Lexend 16px weight 300, uppercase with 0.05em letter-spacing), rounded {rounded.xs} (3px — the tightest radius in the system), padding 9px 16px. Carries {extensions.shadows.sm} shadow for gentle lift. State variants: {component.button-primary-hover}, {component.button-primary-active}, {component.button-primary-disabled}.
{component.button-secondary} — The "OUR HOUSE" button appearing beneath the hero headline. Uses {colors.primary} background but with larger rounding ({rounded.sm} — 5px) and more generous padding (12px 24px). Same typography and text color as primary. Feels more approachable, less urgent than the nav CTA. Has hover variant {component.button-secondary-hover}.
Cards & Containers
{component.card} — Standard content card with {colors.surface} (white) background, {colors.ink} text, {typography.body-md} type, {rounded.md} (8px) corners, and {spacing.section-md} (40px) internal padding. Used for feature descriptions, amenity lists, or information blocks below the hero. Flat (no shadow) in its default state.
{component.card-elevated} — Elevated variant with {rounded.lg} (10px) corners, likely carrying {extensions.shadows.md} shadow. Reserved for featured or highlighted content that needs to visually "lift" from the page.
{component.hero-band} — The full-viewport hero section container. Transparent background (allows image to show), white text color, {typography.display-lg} typography inherited by children, {spacing.section-xl} vertical padding. Contains the overlay, headline, subtext, and CTA.
{component.section-container} — Standard inner content wrapper with transparent background, ink text, and {spacing.xl} (16px) horizontal padding. Constrains content within the 1440px max-width grid.
{component.cta-band} — Call-to-action section band (observed lower on page) with {colors.canvas} background, {colors.ink} text, {typography.title-md} headline sizing, and {spacing.section-lg} (60px) padding. Provides a warm, branded resting place for conversion-focused content.
{component.footer} — Page footer on {colors.canvas} background with {colors.muted} (gray) text at {typography.caption} size. Generous {spacing.section-lg} vertical padding. Likely contains links, legal text, and contact information.
Inputs & Forms
{component.text-input} — Standard text input field. White ({colors.surface}) background, ink text, {typography.body-md} type, {rounded.sm} (5px) corners, 10px 14px internal padding. Likely carries a subtle {colors.hairline} border (though border properties don't appear in extracted component schema). Focus state: {component.text-input-focus} maintains same properties with border-color transition.
{component.checkbox-input} — Form checkbox with transparent background and {colors.border-muted} (gray) text/color for the unchecked state. No visible rounding (square). Used in booking forms or preference selectors.
Navigation
{component.top-nav} — The persistent top navigation bar. {colors.canvas} (cream) background, {colors.ink} text, {typography.nav-link} type (13px, weight 400, 0.08em letter-spacing, uppercase), 80px height. Contains logo, navigation links, and primary CTA. Sticks to top of viewport (implied by typical villa-site patterns).
{component.nav-link} — Individual navigation menu item (HOME, OUR HOUSE, ANTIPAROS, LIFESTYLE, CONTACT). Transparent background, ink text, nav-link typography, {spacing.xl} (16px) horizontal padding. Hover state: {component.nav-link-hover} darkens to {colors.text-dark}.
{component.logo-mark} — The "BH" monogram / Bonatsa House logo. Transparent background, ink text color, no rounding. Positioned flush-left in the nav bar.
{component.logo-text} — "BONATSA HOUSE" wordmark adjacent to logo mark. Inherits nav-link typography characteristics.
{component.menu-button} — Mobile hamburger menu button. Transparent background, ink text, {typography.button} sizing (but at 24px for the icon itself), no rounding, 18px padding all around. Appears when viewport narrows below nav-breakpoint.
Signature Components
{component.slider-dot-active} — Active carousel indicator dot. White ({colors.body}) background, ink text (for accessibility), {rounded.pill} (fully circular), 8×8px size. Indicates current slide in the hero image carousel.
{component.slider-dot-inactive} — Inactive carousel indicator dots. {colors.surface-light-overlay} (white at 40% opacity) background creates a ghosted appearance against the darkened hero photo. Same pill shape and size as active dot.
{component.overlay-dark} — 20% black overlay applied to hero photography. Ensures {colors.body} (white) text maintains readability without crushing the image detail. The primary depth mechanism for hero content.
{component.overlay-darker} — 44% black overlay for situations requiring heavier text contrast over imagery.
{component.language-selector} — Bottom-right language picker (shows US flag in screenshot). White ({colors.surface}) background, ink text, {typography.caption} size, {rounded.sm} (5px) corners, 8px 12px padding. A small, unobtrusive utility component.
Do's and Don'ts
Do
- Do use
{colors.canvas}(#f5efe6) as the primary page background for all non-hero sections — it establishes the warm Mediterranean foundation. - Do reserve
{colors.primary}(#d3b895) exclusively for CTAs and signature action buttons — never use it for body text, borders, or decorative fills. - Do set body text in Lexend at
font-weight: 300— the ExtraLight weight is essential to the airy, luxurious voice. - Do apply
{typography.display-lg}(Thomas Mag, 50px, weight 400) to the hero headline and all major section openings — this is the brand's typographic signature. - Do use
{extensions.shadows.sm}(rgba(0,0,0,0.2) 0 4px 15px) on primary buttons — the gentle shadow provides tactile affordance without heaviness. - Do apply
{colors.surface-dark-overlay}(20% black) over hero photography before placing white text — this ensures WCAG-compliant contrast while preserving image beauty. - Do maintain
{spacing.xxl}(20px) as the default inter-element gap in content sections — the extracted CSS shows this is the most-used spacing value (49 occurrences). - Do render navigation links in uppercase with
{typography.nav-link}(13px, 0.08em letter-spacing) — the tracked-out uppercase conveys refined minimalism. - Do use
{rounded.pill}(9999px) for any circular indicator elements — slider dots, pagination, or status badges. - Do keep line heights generous (1.67 for
{typography.body-md}) — the editorial rhythm depends on this vertical breathing room.
Don't
- Don't substitute
{colors.ink}(#4c4334) with pure black (#000000) — the warmth of the near-black is critical to the palette's cohesion. - Don't apply
font-weight: 700(Bold) to any text in this system — the maximum weight is 400 (Regular); hierarchy comes from scale, not weight. - Don't use gradients on buttons or backgrounds — the brand language is flat, honest color blocks with optional subtle shadows.
- Don't round corners beyond
{rounded.lg}(10px) on rectangular content cards — save{rounded.pill}for dots and icons only. - Don't place dark text directly on hero photography without an overlay — always use
{component.overlay-dark}or{component.overlay-darker}. - Don't introduce a third font family beyond Thomas Mag and Lexend — the two-face pairing is intentional and sufficient.
- Don't shrink body text below
{typography.body-sm}(16px) for primary content — the luxury positioning requires comfortable reading sizes. - Don't use bright or saturated accent colors (reds, blues, greens) — the entire palette lives in the warm neutral spectrum.
- Don't add border-radius to the primary
{component.button-primary}beyond{rounded.xs}(3px) — its relative sharpness distinguishes it from softer secondary elements. - Don't omit the text-transform: uppercase on buttons (
{typography.button}) — the all-caps treatment is part of the button's formal identity.
Motion & Animation
Transition Tokens
/* Color transitions — used for buttons, links, and state changes */
--transition-color: color 0.3s ease, background-color 0.1s ease;
--transition-border: border-color 0.3s ease;
--transition-fill: fill 0.2s ease;
/* Generic transitions */
--transition-all: all 0.2s ease;
--transition-base: 0.3s ease;
--transition-slow: 0.4s ease;
/* Transform transition — for lifts, scales, reveals */
--transition-transform: transform 0.25s cubic-bezier(0.6, 0, 0.2, 0.5);
Keyframe Animations
- spin — Detected in the keyframes list; likely used for loading indicators or the language selector flag icon rotation.
Interaction Patterns
- Button hover: Background color transitions from
{colors.primary}to{colors.primary-hover}over ~200-300ms with easing. Shadow may intensify slightly. - Navigation link hover: Text color shifts from
{colors.ink}to{colors.text-dark}with a 300ms color transition. - Slider dots: Active/inactive state changes involve background-color transitions between
{colors.body}and{colors.surface-light-overlay}. - Focus rings: Input fields (
{component.text-input-focus}) likely gain a subtle border-color shift or thin outline on focus, transitioning over 300ms. - Menu toggle: The mobile
{component.menu-button}triggers a slide-down or overlay panel reveal, likely with transform-based animation. - Image carousel: Hero slides probably cross-fade or slide horizontally; the
0.4sslow transition suggests a deliberate, smooth slide change. - Scroll behavior: No parallax detected in CSS, but luxury villa sites often implement subtle parallax on hero imagery — recommend adding if implementing from scratch.
The motion level is subtle — nothing feels animated for animation's sake. Transitions serve functional clarity (button presses, focus states, slide changes) rather than decorative flourish. The 200-400ms duration range keeps interactions feeling responsive but unhurried, matching the vacation-property pacing.
Imagery Style
- Photography style: Professional architectural and lifestyle photography capturing the villa at golden hour / twilight — the hero shows the pool illuminated, warm interior lighting spilling from windows, lounge chairs arranged on terrace, Cycladic whitewashed architecture against a deep blue evening sky.
- Color treatment: Warm color grade with emphasis on ambers, deep blues, and the cream-white of the building. Images are not desaturated or heavily filtered — they feel authentic and inviting.
- Role of imagery: Dominant. The hero is primarily photographic with text overlaid; the villa sells itself visually, with copy playing a supporting role.
- Composition: Wide-angle architectural shots showing the relationship between built space (villa), water (pool), and nature (sky, distant hills). Human scale is implied by furniture placement.
- Lighting narrative: Evening/twilight lighting suggests relaxation, exclusivity, and the "golden hour" fantasy of Mediterranean travel. Interior lights create welcoming glow.
- Full-bleed treatment: Images extend edge-to-edge with no frames, borders, or contained aspect-ratio boxes. They ARE the background.
- Overlay technique: Darkened via
{component.overlay-dark}(20% black) to allow white text readability — a standard but effective luxury-hotel pattern. - No illustration or 3D: The site relies entirely on photography. No custom illustrations, icons-as-illustrations, or 3D renders detected.
Icon System
- Library: Custom SVG icons (no standard library detected —
iconLibsis empty in framework detection). - Specific icons observed:
- Hamburger menu icon (three horizontal lines) in
{component.menu-button} - Language selector flag icon (US flag) in
{component.language-selector} - Logo monogram ("BH" in a square frame)
- Possible chevron/down-arrow in language selector
- Hamburger menu icon (three horizontal lines) in
- Treatment: Icons appear to use
currentColorfor stroke/fill color, inheriting from parent text color. The menu icon is 24px (inferred from font-size on the button). Icons are minimally detailed — the aesthetic favors simplicity over ornament. - Alignment: Icons center-align with accompanying text where paired. Standalone icons (menu button) center within their padding container.
- Stroke vs fill: Unable to definitively determine from extracted data, but the minimalist aesthetic suggests stroke-based icons or very simple filled shapes.
Recommended Frontend Stack
- Framework: Next.js 14+ (for image optimization, ISR for villa content) or Astro (static-first, ideal for landing pages)
- Styling: Vanilla CSS or CSS Modules (the extracted site uses vanilla classes; Tailwind not detected)
- Fonts: Thomas Mag via @font-face from CDN + Lexend from Google Fonts (fonts.googleapis.com/css?family=Lexend:300,400,500,600,700)
- Animation: Vanilla CSS transitions (already defined in extracted styles) + Intersection Observer for scroll reveals
- Icons: Custom SVG inline components (no library dependency needed for the minimal icon set)
- Component lib: None (custom components; no Radix/shadcn patterns detected)
- Build tool: Any (Vite recommended for vanilla CSS projects)
Responsive Behavior
Breakpoints
| Name | Width | Key Changes | |---|---|---| | Mobile | < 768px | Single-column layout, hamburger menu replaces nav links, hero text stacks above/below image area, button padding reduces | | Tablet | 768px – 1024px | Two-column content begins, navigation may show abbreviated links, hero text narrows to ~60% width | | Desktop | 1024px – 1440px | Full navigation visible, hero at designed proportions, multi-column grids active | | Wide | > 1440px | Content centers within 1440px max-width, horizontal padding increases |
Touch Targets
{component.button-primary}: Approximately 16px × 38px (padding 9px 16px + text height) — meets minimum but could be enlarged for mobile to hit 44×44px AAA target comfortably.{component.button-secondary}: Approximately 48px × 52px (padding 12px 24px + text height) — exceeds 44×44px, excellent touch target.{component.text-input}: 44px height (inferred from 10px padding × 2 + ~24px text) — meets AAA minimum.{component.menu-button}: 18px padding × 2 + 24px icon ≈ 60px — excellent touch target.{component.slider-dot}: 8×8px — below AAA target; consider expanding to 12×16px or wrapping in a larger tap area for mobile.
Collapsing Strategy
- Navigation: Horizontal link list (
{component.nav-link}items) collapses into a hamburger menu ({component.menu-button}) triggering a slide-down or overlay panel below ~900-1024px viewport width. - Hero layout: The left-aligned text block (currently ~45-50% width) will expand to near-full-width on mobile, with the headline reducing from 50px toward 32-36px (
{typography.title-md}or{typography.title-sm}scale). The "OUR HOUSE" button will stack below the headline. - Slider dots: Remain bottom-center but may increase in size for mobile touch interaction.
- Content grids: Multi-column feature/amenity grids collapse to single-column stacking order on mobile.
- CTA band: Maintains full-width background but reduces internal padding from
{spacing.section-lg}(60px) to{spacing.section-md}(40px) or{spacing.section-sm}(30px).
Image Behavior
- Hero image: Should use
object-cover: coverwith abackground-positionstrategy (center or center-left to preserve villa architecture visibility). On mobile, the focal point may shift to keep the pool/building visible as the frame narrows. - Section images: Any below-fold photography should maintain aspect ratio integrity, scaling down proportionally rather than cropping aggressively.
- Language selector icon: Fixed-size, does not resize across breakpoints.
Iteration Guide
-
Start with the foundation: Create an HTML page with
{colors.canvas}as the body background. Import Lexend from Google Fonts and define the@font-facefor Thomas Mag. Setbody { font-family: 'Lexend', sans-serif; color: #4c4334; }as the global baseline. -
Build the token system: Extract every value from the YAML frontmatter into CSS custom properties (
:root { --color-primary: #d3b895; --font-display: 'Thomas Mag', serif; ... }). Reference only variables in your component styles — never hard-code hex values or pixel measurements that have a corresponding token. -
Implement the navigation bar first:
{component.top-nav}at 80px height on{colors.canvas}. Place the logo left, nav links center (using{typography.nav-link}styling — 13px, uppercase, 0.08em tracking), and{component.button-primary}right. Test the hamburger collapse at your chosen breakpoint. -
Build the hero section: Full-viewport-height container with background-image (use a high-quality villa-at-dusk photo),
{component.overlay-dark}pseudo-element, then the headline in{typography.display-lg}(Thomas Mag, 50px, white), followed by{component.button-secondary}("OUR HOUSE"). Add slider dots ({component.slider-dot-active}/{component.slider-dot-inactive}) absolutely positioned bottom-center. -
Create the component library in isolation: Build
{component.card},{component.button-primary}(with-hover,-active,-disabledvariants),{component.text-input}/{component.text-input-focus}, and{component.cta-band}as standalone HTML/CSS fragments. Verify each matches its frontmatter spec exactly before integrating into pages. -
Apply the shadow system progressively: Start flat (Level 0) for nav and footer. Add
{extensions.shadows.sm}only to{component.button-primary}. Reserve{extensions.shadows.md}and{extensions.shadows.lg}for modal/dropdown contexts you add later. Don't pre-apply heavy shadows. -
Typography as hierarchy engine: When in doubt about emphasis, increase size before weight. If a heading needs more presence, move from
{typography.title-sm}(28px) to{typography.title-md}(35px) — never jump tofont-weight: 700. The brand's voice is light and spacious, not bold and urgent. -
Respect the two-face rule: Any display/heading text gets Thomas Mag. Any body/UI text gets Lexend at weight 300. Never apply Lexend to an h1, never apply Thomas Mag to a paragraph or button label. This discipline is the single most important typographic rule in the system.
-
Color temperature check: Before finalizing any new component, verify its colors live in the warm-neutral spectrum. If you find yourself reaching for a cool gray (#888888), a pure red (#ff0000), or a tech-blue (#007bff), stop — those don't exist in this palette. Find the warm equivalent (
{colors.muted}#aaaaaa,{colors.error}#c13515, or avoid blue entirely). -
Run lint validation: After implementation, validate all
{token.path}references resolve correctly. Check that every component in your codebase has a corresponding entry in the frontmatter. Verify no hardcoded values have crept in that should be tokens.
Font Setup
For development environments without access to the proprietary Thomas Mag .otf file, substitute with Playfair Display (Google Fonts: @import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400&display=swap');). Define:
:root {
--font-display: 'Playfair Display', 'Thomas Mag', serif;
--font-body: 'Lexend', sans-serif;
}
When the project has licensing/CDN access to Thomas Mag, swap the @font-face declaration (pointing to the .otf URL found in the extracted CSS) and update --font-display to 'Thomas Mag', 'Playfair Display', serif.
Known Gaps
- Hover state styling: Per the no-hover policy, exact hover colors, transforms, and shadow intensities are inferred from the transition tokens but not directly observable from a static screenshot. Implementers should derive hover states from the active/disabled variants provided.
- Loading/skeleton states: No loading indicators, skeleton screens, or pending-state designs were visible in the viewport. Recommend designing skeleton cards matching
{component.card}dimensions with{colors.hairline-soft}background pulses. - Form validation states: Beyond
{component.text-input-focus}, no error ({colors.error}) or success ({colors.success}) input states were observed. Booking forms likely need these. - Authenticated/user flows: The screenshot shows only the public landing page. Member dashboards, booking confirmation pages, and account settings were not visible and may require extended components.
- Mobile navigation panel: The
{component.menu-button}exists but the resulting slide-down or overlay menu panel was not captured. Its styling (background, animation, link arrangement) must be designed fresh. - Footer content: While
{component.footer}is specified, the actual footer content (links columns, social icons, legal text, newsletter signup) was below the fold and not extractable. - Secondary page templates: "Our House," "Antiparos," "Lifestyle," and "Contact" sections are linked in navigation but their layouts, components, and potential sub-systems (gallery grid, map embed, testimonial carousel) are unknown.
- Dark mode: The entire system is light-mode only (
extensions.mode: "light"). No dark canvas, inverted text, or dark-card variants were detected or suggested by the brand. - Pixel-exact overlay values: The rgba overlay values (
rgba(0,0,0,0.2),rgba(0,0,0,0.44)) are extracted from CSS but their visual effect on specific photographs may need fine-tuning during implementation for optimal text contrast. - Carousel behavior: The hero slider dots imply a multi-image carousel, but slide-transition animations (fade vs. slide direction, autoplay timing, swipe gesture support) are not extractable from static CSS.