Files
website/website-mockups/DESIGN-SYSTEM.md
matt ec72c5d62b
Some checks failed
build-website / build (push) Failing after 1m2s
Initial import of HarborSmith website
2025-09-18 22:20:01 +02:00

18 KiB

HarborSmith Design System

Voyage Theme Standard

Version 1.0

Last Updated: December 2024


🎨 Core Design Philosophy

The HarborSmith Voyage theme embodies the spirit of maritime adventure with warm, inviting colors that evoke feelings of sunset voyages and golden horizons. Our design system combines nautical heritage with modern luxury, creating an experience that is both timeless and contemporary.

Design Principles

  1. Warmth & Welcome - Every element should feel inviting and aspirational
  2. Maritime Heritage - Subtle nautical references without being cliché
  3. Premium Experience - Convey luxury through spacing, typography, and imagery
  4. Emotional Connection - Use warm gradients and cinematic visuals to inspire adventure
  5. Accessibility - Maintain WCAG AA compliance across all color combinations

🎨 Color Palette

Primary Colors

Classic Nautical (Default Theme)

--primary-blue: #001f3f;     /* Deep Navy - Headers, Primary Text */
--warm-orange: #dc143c;       /* Crimson Red - CTAs, Accents */
--warm-amber: #b91c3c;        /* Deep Crimson - Hover States */
--warm-yellow: #ef4444;       /* Coral Red - Highlights */
--soft-cream: #f0f4f8;        /* Light Blue-Gray - Backgrounds */
--text-dark: #0a1628;         /* Near Black - Body Text */
--text-light: #4a5568;        /* Gray - Secondary Text */
--white: #ffffff;             /* Pure White - Cards, Contrast */

Gradients

--gradient-warm: linear-gradient(135deg, #dc143c 0%, #ef4444 100%);
--gradient-sunset: linear-gradient(135deg, #b91c3c 0%, #dc143c 50%, #ef4444 100%);
--gradient-ocean: linear-gradient(135deg, #001f3f 0%, #003366 100%);

Semantic Colors

--success: #10B981;           /* Emerald Green */
--warning: #F59E0B;           /* Amber */
--error: #EF4444;             /* Red */
--info: #3B82F6;              /* Blue */

Usage Guidelines

  • Primary Blue (#001f3f): Main headers, navigation (scrolled state), footer backgrounds
  • Warm Orange (#dc143c): Primary CTA buttons, active states, important accents
  • Warm Amber (#b91c3c): Hover states for primary actions
  • Soft Cream (#f0f4f8): Section backgrounds, alternate row colors
  • Gradients: Hero sections, premium features, CTA buttons

📝 Typography

Font Families

--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
--font-display: 'Playfair Display', serif;

Type Scale

/* Display - Hero Headlines */
.display-1 { 
    font-size: clamp(3rem, 8vw, 5rem);
    font-family: var(--font-display);
    font-weight: 900;
    line-height: 1.1;
}

/* Headings */
h1 { 
    font-size: clamp(2.5rem, 5vw, 3.5rem);
    font-family: var(--font-display);
    font-weight: 700;
    line-height: 1.2;
}

h2 { 
    font-size: clamp(2rem, 4vw, 2.5rem);
    font-family: var(--font-display);
    font-weight: 700;
    line-height: 1.3;
}

h3 { 
    font-size: clamp(1.5rem, 3vw, 1.875rem);
    font-family: var(--font-sans);
    font-weight: 600;
    line-height: 1.4;
}

h4 { 
    font-size: 1.25rem;
    font-family: var(--font-sans);
    font-weight: 600;
    line-height: 1.5;
}

/* Body Text */
.body-large { 
    font-size: 1.125rem;
    line-height: 1.7;
}

.body-regular { 
    font-size: 1rem;
    line-height: 1.6;
}

.body-small { 
    font-size: 0.875rem;
    line-height: 1.5;
}

Typography Usage

  • Playfair Display: Hero headlines, section titles, brand name
  • Inter: Body text, navigation, buttons, forms
  • Font Weights: 300 (light), 400 (regular), 500 (medium), 600 (semibold), 700 (bold), 800 (extrabold), 900 (black)

📐 Spacing System

Base Unit: 8px

--space-xs: 0.5rem;   /* 8px */
--space-sm: 1rem;     /* 16px */
--space-md: 2rem;     /* 32px */
--space-lg: 3rem;     /* 48px */
--space-xl: 4rem;     /* 64px */
--space-2xl: 6rem;    /* 96px */
--space-3xl: 8rem;    /* 128px */

Container Widths

--container-sm: 640px;
--container-md: 768px;
--container-lg: 1024px;
--container-xl: 1200px;
--container-2xl: 1400px;

Section Padding

  • Mobile: padding: var(--space-lg) var(--space-md);
  • Tablet: padding: var(--space-xl) var(--space-md);
  • Desktop: padding: var(--space-2xl) var(--space-md);

🎯 Components

Buttons

Primary Button (Warm Gradient)

.btn-primary {
    background: var(--gradient-warm);
    color: white;
    padding: 0.875rem 2rem;
    border-radius: 50px;
    font-weight: 600;
    font-size: 1rem;
    border: none;
    cursor: pointer;
    transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
}

.btn-primary:hover {
    transform: translateY(-2px);
    box-shadow: 0 10px 30px rgba(220, 20, 60, 0.3);
}

Secondary Button (Ghost)

.btn-secondary {
    background: transparent;
    color: var(--warm-orange);
    padding: 0.875rem 2rem;
    border: 2px solid var(--warm-orange);
    border-radius: 50px;
    font-weight: 600;
    transition: all 0.3s ease;
}

.btn-secondary:hover {
    background: var(--warm-orange);
    color: white;
    transform: translateY(-2px);
}

Cards

Standard Card

.card {
    background: white;
    border-radius: 16px;
    padding: var(--space-md);
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
    transition: all 0.3s ease;
}

.card:hover {
    transform: translateY(-4px);
    box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12);
}

Premium Card (with gradient border)

.card-premium {
    background: white;
    border-radius: 20px;
    padding: 3px;
    background: var(--gradient-warm);
}

.card-premium-inner {
    background: white;
    border-radius: 17px;
    padding: var(--space-md);
}

Navigation

Fixed Navigation Bar

.navigation {
    position: fixed;
    top: 0;
    width: 100%;
    z-index: 1000;
    transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Transparent state (hero) */
.navigation {
    background: rgba(255, 255, 255, 0);
    backdrop-filter: blur(0);
}

/* Scrolled state */
.navigation.scrolled {
    background: rgba(255, 255, 255, 0.95);
    backdrop-filter: blur(10px);
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
}

Forms

Input Fields

.form-input {
    width: 100%;
    padding: 0.875rem 1.25rem;
    border: 2px solid #E5E7EB;
    border-radius: 12px;
    font-size: 1rem;
    transition: all 0.3s ease;
}

.form-input:focus {
    outline: none;
    border-color: var(--warm-orange);
    box-shadow: 0 0 0 3px rgba(220, 20, 60, 0.1);
}

Dropdown Menus

// React Component with Framer Motion
// Standard dropdown pattern for consistent interactions across the platform

import { motion, AnimatePresence } from 'framer-motion';
import { ChevronDown } from 'lucide-react';
import { useState } from 'react';

const DropdownMenu = ({ 
  label = "Select Option",
  options = [],
  value,
  onChange,
  placeholder = "Choose...",
  icon = null 
}) => {
  const [isOpen, setIsOpen] = useState(false);
  
  return (
    <div className="dropdown-container">
      <button
        className="dropdown-trigger"
        onClick={() => setIsOpen(!isOpen)}
        aria-expanded={isOpen}
        aria-haspopup="listbox"
      >
        {icon && <span className="dropdown-icon">{icon}</span>}
        <span className="dropdown-value">
          {value || placeholder}
        </span>
        <ChevronDown 
          className={`dropdown-chevron ${isOpen ? 'rotate-180' : ''}`}
          size={20}
        />
      </button>
      
      <AnimatePresence>
        {isOpen && (
          <motion.div
            className="dropdown-menu"
            initial={{ opacity: 0, y: -10 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -10 }}
            transition={{ duration: 0.2 }}
          >
            {options.map((option) => (
              <motion.button
                key={option.value}
                className="dropdown-option"
                onClick={() => {
                  onChange(option);
                  setIsOpen(false);
                }}
                whileHover={{ x: 4 }}
                transition={{ type: "spring", stiffness: 300 }}
              >
                {option.icon && (
                  <span className="option-icon">{option.icon}</span>
                )}
                <span className="option-label">{option.label}</span>
                {option.badge && (
                  <span className="option-badge">{option.badge}</span>
                )}
              </motion.button>
            ))}
          </motion.div>
        )}
      </AnimatePresence>
    </div>
  );
};
Dropdown Styles (CSS)
.dropdown-container {
    position: relative;
    width: 100%;
}

.dropdown-trigger {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.875rem 1.25rem;
    background: white;
    border: 2px solid rgba(220, 20, 60, 0.1);
    border-radius: 12px;
    font-size: 1rem;
    font-weight: 500;
    color: #0a1628;
    cursor: pointer;
    transition: all 0.3s ease;
}

.dropdown-trigger:hover {
    border-color: rgba(220, 20, 60, 0.2);
    box-shadow: 0 4px 12px rgba(0, 31, 63, 0.08);
}

.dropdown-trigger:focus {
    outline: none;
    border-color: #dc143c;
    box-shadow: 0 0 0 3px rgba(220, 20, 60, 0.1);
}

.dropdown-icon {
    display: flex;
    align-items: center;
    color: #dc143c;
}

.dropdown-value {
    flex: 1;
    text-align: left;
}

.dropdown-chevron {
    color: #64748b;
    transition: transform 0.3s ease;
}

.dropdown-chevron.rotate-180 {
    transform: rotate(180deg);
}

.dropdown-menu {
    position: absolute;
    top: calc(100% + 8px);
    left: 0;
    right: 0;
    max-height: 320px;
    overflow-y: auto;
    background: white;
    border: 1px solid rgba(220, 20, 60, 0.08);
    border-radius: 12px;
    box-shadow: 0 10px 40px rgba(0, 31, 63, 0.12);
    z-index: 1000;
}

.dropdown-option {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.875rem 1.25rem;
    background: transparent;
    border: none;
    font-size: 0.95rem;
    color: #4a5568;
    cursor: pointer;
    transition: all 0.2s ease;
    text-align: left;
}

.dropdown-option:hover {
    background: linear-gradient(90deg, rgba(220, 20, 60, 0.05), rgba(239, 68, 68, 0.05));
    color: #0a1628;
}

.dropdown-option:focus {
    outline: none;
    background: rgba(220, 20, 60, 0.08);
}

.option-icon {
    display: flex;
    align-items: center;
    color: #dc143c;
    width: 20px;
}

.option-label {
    flex: 1;
}

.option-badge {
    padding: 0.25rem 0.5rem;
    background: linear-gradient(135deg, #dc143c, #ef4444);
    color: white;
    border-radius: 20px;
    font-size: 0.75rem;
    font-weight: 600;
}

/* Dark Mode Variant */
.dark .dropdown-trigger {
    background: rgba(255, 255, 255, 0.05);
    border-color: rgba(255, 255, 255, 0.1);
    color: white;
}

.dark .dropdown-menu {
    background: #1a1a2e;
    border-color: rgba(255, 255, 255, 0.1);
}

.dark .dropdown-option {
    color: rgba(255, 255, 255, 0.8);
}

.dark .dropdown-option:hover {
    background: rgba(220, 20, 60, 0.2);
    color: white;
}
Usage Examples
// Basic Dropdown
<DropdownMenu
  label="Select Yacht"
  options={[
    { value: 'azure', label: 'Azure Dream' },
    { value: 'seastar', label: 'Sea Star' },
    { value: 'windwhisper', label: 'Wind Whisper' }
  ]}
  value={selectedYacht}
  onChange={(option) => setSelectedYacht(option.value)}
/>

// Dropdown with Icons and Badges
<DropdownMenu
  label="Choose Route"
  icon={<MapPin />}
  options={[
    { 
      value: 'golden-gate', 
      label: 'Golden Gate Tour',
      icon: <Bridge />,
      badge: 'Popular'
    },
    { 
      value: 'alcatraz', 
      label: 'Alcatraz Circle',
      icon: <Anchor />
    },
    { 
      value: 'sunset', 
      label: 'Sunset Cruise',
      icon: <Sun />,
      badge: 'Romantic'
    }
  ]}
  value={selectedRoute}
  onChange={(option) => setSelectedRoute(option.value)}
/>
Accessibility Guidelines
  • Always include proper ARIA attributes (aria-expanded, aria-haspopup)
  • Ensure keyboard navigation works (Tab, Enter, Escape keys)
  • Maintain focus management when opening/closing
  • Provide clear visual focus indicators
  • Support screen readers with semantic HTML

🎬 Animations

Standard Transitions

--transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
--transition-slow: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);
--transition-fast: all 0.15s cubic-bezier(0.4, 0, 0.2, 1);

Animation Classes

@keyframes fadeInUp {
    from {
        opacity: 0;
        transform: translateY(30px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.animate-fade-up {
    animation: fadeInUp 0.8s ease forwards;
}

.animate-fade-up-delay {
    animation: fadeInUp 0.8s ease 0.2s forwards;
    opacity: 0;
}

.animate-fade-up-delay-2 {
    animation: fadeInUp 0.8s ease 0.4s forwards;
    opacity: 0;
}

Hover Effects

  • Lift: transform: translateY(-4px);
  • Scale: transform: scale(1.05);
  • Glow: box-shadow: 0 10px 30px rgba(220, 20, 60, 0.3);

🖼️ Imagery Guidelines

Hero Images

  • Aspect Ratio: 16:9 for desktop, 4:3 for mobile
  • Overlay: Dark gradient overlay (40-60% opacity) for text legibility
  • Quality: Minimum 1920x1080 for desktop, optimized for web

Content Images

  • Border Radius: 16px for standard images, 20px for featured
  • Shadow: box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12);
  • Hover Effect: Scale 1.05 with transition

Image Overlays

.image-overlay {
    background: linear-gradient(
        to bottom,
        rgba(0, 31, 63, 0.3) 0%,
        rgba(0, 31, 63, 0.7) 100%
    );
}

📱 Responsive Breakpoints

/* Mobile First Approach */
--breakpoint-sm: 640px;   /* Small tablets */
--breakpoint-md: 768px;   /* Tablets */
--breakpoint-lg: 1024px;  /* Small laptops */
--breakpoint-xl: 1280px;  /* Desktop */
--breakpoint-2xl: 1536px; /* Large screens */

Media Query Usage

/* Mobile (default) */
.element { }

/* Tablet and up */
@media (min-width: 768px) {
    .element { }
}

/* Desktop and up */
@media (min-width: 1024px) {
    .element { }
}

🌟 Special Effects

Gradient Text

.gradient-text {
    background: var(--gradient-warm);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}

Glass Morphism

.glass {
    background: rgba(255, 255, 255, 0.1);
    backdrop-filter: blur(10px);
    border: 1px solid rgba(255, 255, 255, 0.2);
    border-radius: 16px;
}

Warm Glow Effect

.warm-glow {
    box-shadow: 
        0 0 20px rgba(220, 20, 60, 0.1),
        0 0 40px rgba(220, 20, 60, 0.05);
}

🎯 Icon System

Lucide Icons Configuration

[data-lucide] {
    width: 24px;
    height: 24px;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
    fill: none;
}

Icon Sizes

  • Small: 16px (inline text)
  • Default: 24px (buttons, navigation)
  • Medium: 32px (feature icons)
  • Large: 48px (hero icons)

Accessibility Standards

Color Contrast

  • Normal Text: Minimum 4.5:1 contrast ratio
  • Large Text: Minimum 3:1 contrast ratio
  • Interactive Elements: Minimum 3:1 contrast ratio

Focus States

:focus-visible {
    outline: 3px solid var(--warm-orange);
    outline-offset: 2px;
    border-radius: 4px;
}

Touch Targets

  • Minimum size: 44x44px
  • Spacing between targets: minimum 8px

🚀 Implementation Checklist

For Each Page

  • Use correct color palette variables
  • Apply consistent typography scale
  • Maintain spacing system
  • Include smooth transitions
  • Implement hover states
  • Ensure mobile responsiveness
  • Add proper focus states
  • Use semantic HTML
  • Include meta descriptions
  • Optimize images

Component Consistency

  • Buttons match design system
  • Forms use standard inputs
  • Cards follow shadow/radius standards
  • Navigation transitions properly
  • Footer matches other pages
  • Icons use Lucide consistently

📋 Quick Reference

CSS Variables to Include

<link rel="stylesheet" href="css/voyage-layout.css">
<link rel="stylesheet" href="css/themes.css">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=Playfair+Display:wght@400;700;900&display=swap" rel="stylesheet">
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.js"></script>

Standard Page Structure

<!DOCTYPE html>
<html lang="en">
<head>
    <!-- Meta tags -->
    <!-- Font imports -->
    <!-- CSS files -->
</head>
<body>
    <!-- Navigation -->
    <nav class="voyage-nav">...</nav>
    
    <!-- Hero Section -->
    <section class="hero-voyage">...</section>
    
    <!-- Content Sections -->
    <section class="section-name">
        <div class="container">
            <!-- Content -->
        </div>
    </section>
    
    <!-- Footer -->
    <footer class="voyage-footer">...</footer>
    
    <!-- Scripts -->
    <script>lucide.createIcons();</script>
</body>
</html>

🔄 Version History

Version 1.0 (December 2024)

  • Initial design system documentation
  • Voyage theme standardization
  • Color palette definition
  • Typography scale
  • Component library
  • Animation guidelines

📝 Notes

This design system is optimized for:

  • Modern browsers (Chrome, Firefox, Safari, Edge)
  • Mobile-first responsive design
  • WCAG AA accessibility standards
  • Performance (lazy loading, optimized assets)
  • SEO best practices

For questions or updates, contact the HarborSmith development team.