# HarborSmith Landing Page Conversion Plan ## From Static HTML to Nuxt 3 + Tailwind CSS v4 --- ## Table of Contents 1. [Executive Summary](#executive-summary) 2. [Current State Analysis](#current-state-analysis) 3. [Target Architecture](#target-architecture) 4. [Implementation Strategy](#implementation-strategy) 5. [Technical Implementation](#technical-implementation) 6. [Component Architecture](#component-architecture) 7. [Theme System](#theme-system) 8. [Performance Optimizations](#performance-optimizations) 9. [Deployment Strategy](#deployment-strategy) 10. [Migration Checklist](#migration-checklist) --- ## Executive Summary This document outlines the comprehensive plan for converting the HarborSmith landing page from static HTML/CSS/JS to a production-ready Nuxt 3 application with Tailwind CSS v4, while preserving the sophisticated design system with 4 theme variants, video hero, and premium animations. ### Key Objectives - Preserve 100% visual parity with existing mockups - Implement modern development practices with TypeScript - Achieve < 1 second page load time - Maintain SEO optimization with SSG - Deploy as standalone Docker container ### Approach Hybrid system using Tailwind for layout/utilities, CSS custom properties for dynamic theming, and Vue composables for interactivity. --- ## Current State Analysis ### Existing Mockup Structure ``` website-mockups/ ├── HTML Files (18 total) │ ├── index.html # Main landing page │ ├── charter-booking-*.html # 4-step booking flow │ ├── maintenance/*.html # Portal pages │ └── portal-login.html # Authentication ├── CSS Files │ ├── voyage-layout.css # Main layout styles │ ├── themes.css # Theme variables │ ├── animations.css # Keyframe animations │ └── booking.css # Booking-specific styles └── JavaScript ├── main.js # Core functionality ├── animations.js # Scroll effects └── booking.js # Booking logic ``` ### Current Technologies - **Styling**: Plain CSS with CSS variables - **Themes**: 4 variants (Nautical, Coastal Dawn, Deep Sea, Monaco) - **Icons**: Lucide via CDN - **Fonts**: Inter + Playfair Display (Google Fonts) - **Video**: Hero background with fallback - **Animations**: CSS keyframes + JavaScript scroll effects ### Design System Highlights - Warm gradients and ocean-inspired colors - Premium yacht aesthetic - Smooth transitions and animations - Mobile-responsive design - Accessibility considerations (WCAG AA) --- ## Target Architecture ### Technology Stack ``` Frontend Framework: Nuxt 3 (v3.10+) CSS Framework: Tailwind CSS v4 (beta) UI Components: Nuxt UI v3 Animation: @vueuse/motion State Management: Pinia Icons: lucide-vue-next Type Safety: TypeScript Image Optimization: Nuxt Image Deployment: Docker + nginx ``` ### Project Structure ``` harborsmith-web/ ├── app.vue # Root component with theme provider ├── nuxt.config.ts # Nuxt configuration ├── tailwind.config.ts # Tailwind with custom properties ├── package.json # Dependencies ├── Dockerfile # Production build ├── nginx.conf # Production server config ├── components/ │ ├── layout/ │ │ ├── HarborNav.vue # Navigation with theme switcher │ │ └── HarborFooter.vue # Footer component │ ├── sections/ │ │ ├── HeroVideo.vue # Video hero section │ │ ├── TrustBadges.vue # Social proof │ │ ├── FleetGrid.vue # Vessel showcase │ │ ├── Services.vue # Services overview │ │ └── Testimonials.vue # Customer reviews │ └── ui/ │ ├── ThemedButton.vue # Gradient CTAs │ ├── VesselCard.vue # Fleet display cards │ └── ThemeSwitcher.vue # Theme selector dropdown ├── composables/ │ ├── useTheme.ts # Theme switching logic │ ├── useScrollEffects.ts # Scroll animations │ └── useVideoLoader.ts # Video optimization ├── stores/ │ └── theme.ts # Pinia theme store ├── assets/ │ └── css/ │ ├── base.css # Global styles │ ├── themes.css # CSS custom properties │ └── animations.css # Keyframe definitions └── public/ ├── videos/ # Hero videos ├── images/ # Static images └── fonts/ # Self-hosted fonts (optional) ``` --- ## Implementation Strategy ### Phase 1: Foundation Setup (Day 1) 1. Initialize Nuxt 3 project 2. Configure Tailwind CSS v4 3. Set up TypeScript 4. Install core dependencies 5. Create base project structure ### Phase 2: Theme System (Day 2) 1. Port CSS variables to Tailwind config 2. Implement theme switcher with Pinia 3. Create theme persistence logic 4. Test all 4 theme variants ### Phase 3: Component Development (Days 3-4) 1. Convert navigation component 2. Build video hero section 3. Create reusable UI components 4. Implement fleet showcase grid 5. Add testimonial carousel ### Phase 4: Animations & Polish (Day 5) 1. Implement scroll animations 2. Add hover effects 3. Optimize transitions 4. Fine-tune responsive design ### Phase 5: Optimization & Deployment (Day 6) 1. Image optimization 2. Performance testing 3. Docker configuration 4. Production deployment --- ## Technical Implementation ### 1. Project Initialization ```bash # Create Nuxt 3 application npx nuxi@latest init harborsmith-web --template minimal cd harborsmith-web # Install core dependencies npm install -D @nuxtjs/tailwindcss@next @nuxt/ui@next npm install lucide-vue-next @vueuse/motion @vueuse/nuxt npm install pinia @pinia/nuxt npm install @nuxt/image # Development dependencies npm install -D @types/node typescript sass ``` ### 2. Nuxt Configuration ```typescript // nuxt.config.ts export default defineNuxtConfig({ devtools: { enabled: true }, modules: [ '@nuxt/ui', '@nuxtjs/tailwindcss', '@vueuse/nuxt', '@pinia/nuxt', '@nuxt/image', ], css: [ '~/assets/css/base.css', '~/assets/css/themes.css', '~/assets/css/animations.css', ], typescript: { strict: true, typeCheck: true, }, nitro: { preset: 'static', prerender: { routes: ['/'], crawlLinks: true, }, compressPublicAssets: true, }, image: { quality: 80, format: ['webp', 'jpg'], screens: { xs: 320, sm: 640, md: 768, lg: 1024, xl: 1280, xxl: 1536, }, }, app: { head: { charset: 'utf-8', viewport: 'width=device-width, initial-scale=1', title: 'HarborSmith - Premium Yacht Charters SF Bay', meta: [ { name: 'description', content: 'Experience luxury yacht charters in the San Francisco Bay. Premium vessels, professional maintenance, unforgettable adventures.' }, { property: 'og:title', content: 'HarborSmith - Your Adventure Awaits' }, { property: 'og:image', content: '/og-image.jpg' }, ], link: [ { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }, { rel: 'preconnect', href: 'https://fonts.googleapis.com' }, { rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: '' }, { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=Playfair+Display:wght@400;700;900&display=swap' }, ], script: [ // Prevent theme flash { innerHTML: ` (function() { const theme = localStorage.getItem('harborsmith-theme') || 'nautical'; document.documentElement.className = 'theme-' + theme; })(); `, type: 'text/javascript', } ], }, }, experimental: { payloadExtraction: false, renderJsonPayloads: false, viewTransition: true, }, }) ``` ### 3. Tailwind Configuration ```typescript // tailwind.config.ts import type { Config } from 'tailwindcss' export default { content: [], theme: { extend: { colors: { // Dynamic theme colors using CSS variables 'primary': 'rgb(var(--primary-blue) / )', 'accent': 'rgb(var(--warm-orange) / )', 'accent-hover': 'rgb(var(--warm-amber) / )', 'accent-light': 'rgb(var(--warm-yellow) / )', 'cream': 'rgb(var(--soft-cream) / )', 'text-primary': 'rgb(var(--text-dark) / )', 'text-secondary': 'rgb(var(--text-light) / )', }, backgroundImage: { 'gradient-warm': 'var(--gradient-warm)', 'gradient-sunset': 'var(--gradient-sunset)', 'gradient-ocean': 'var(--gradient-ocean)', }, fontFamily: { 'sans': ['Inter', '-apple-system', 'BlinkMacSystemFont', 'sans-serif'], 'display': ['Playfair Display', 'serif'], }, spacing: { '18': '4.5rem', '88': '22rem', '120': '30rem', }, animation: { 'fade-up': 'fadeInUp 0.8s ease forwards', 'fade-up-delay': 'fadeInUp 0.8s ease 0.2s forwards', 'fade-up-delay-2': 'fadeInUp 0.8s ease 0.4s forwards', 'float': 'float 20s ease-in-out infinite', 'pulse-slow': 'pulse 3s ease-in-out infinite', }, transitionTimingFunction: { 'bounce-in': 'cubic-bezier(0.68, -0.55, 0.265, 1.55)', }, }, }, plugins: [], } ``` --- ## Component Architecture ### Video Hero Component ```vue ``` ### Navigation Component ```vue ``` --- ## Theme System ### CSS Custom Properties ```css /* assets/css/themes.css */ :root { /* Default Theme: Nautical */ --primary-blue: 0 31 63; /* #001f3f */ --warm-orange: 220 20 60; /* #dc143c */ --warm-amber: 185 28 60; /* #b91c3c */ --warm-yellow: 239 68 68; /* #ef4444 */ --soft-cream: 240 244 248; /* #f0f4f8 */ --text-dark: 10 22 40; /* #0a1628 */ --text-light: 74 85 104; /* #4a5568 */ /* 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%); /* Shadows */ --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05); --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1); --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1); --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1); } /* Coastal Dawn Theme */ .theme-coastal-dawn { --primary-blue: 169 180 194; /* #A9B4C2 */ --warm-orange: 212 175 55; /* #D4AF37 */ --warm-amber: 201 169 97; /* #C9A961 */ --warm-yellow: 230 208 136; /* #E6D088 */ --soft-cream: 248 247 244; /* #F8F7F4 */ --text-dark: 51 55 69; /* #333745 */ --text-light: 107 114 128; /* #6B7280 */ --gradient-warm: linear-gradient(135deg, #D4AF37 0%, #E6D088 100%); --gradient-sunset: linear-gradient(135deg, #C9A961 0%, #D4AF37 50%, #E6D088 100%); --gradient-ocean: linear-gradient(135deg, #A9B4C2 0%, #C5D3E0 100%); } /* Deep Sea Theme */ .theme-deep-sea { --primary-blue: 30 32 34; /* #1E2022 */ --warm-orange: 0 191 255; /* #00BFFF */ --warm-amber: 30 144 255; /* #1E90FF */ --warm-yellow: 65 105 225; /* #4169E1 */ --soft-cream: 42 45 48; /* #2A2D30 */ --text-dark: 229 228 226; /* #E5E4E2 */ --text-light: 192 192 192; /* #C0C0C0 */ --gradient-warm: linear-gradient(135deg, #00BFFF 0%, #4169E1 100%); --gradient-sunset: linear-gradient(135deg, #1E90FF 0%, #00BFFF 50%, #4169E1 100%); --gradient-ocean: linear-gradient(135deg, #1E2022 0%, #2A2D30 100%); } /* Monaco White Theme */ .theme-monaco { --primary-blue: 44 62 80; /* #2C3E50 */ --warm-orange: 231 76 60; /* #E74C3C */ --warm-amber: 230 126 34; /* #E67E22 */ --warm-yellow: 243 156 18; /* #F39C12 */ --soft-cream: 248 249 250; /* #F8F9FA */ --text-dark: 44 62 80; /* #2C3E50 */ --text-light: 127 140 141; /* #7F8C8D */ --gradient-warm: linear-gradient(135deg, #E74C3C 0%, #F39C12 100%); --gradient-sunset: linear-gradient(135deg, #E67E22 0%, #E74C3C 50%, #F39C12 100%); --gradient-ocean: linear-gradient(135deg, #2C3E50 0%, #34495E 100%); } ``` ### Theme Store (Pinia) ```typescript // stores/theme.ts import { defineStore } from 'pinia' export type ThemeVariant = 'nautical' | 'coastal-dawn' | 'deep-sea' | 'monaco' interface ThemeOption { id: ThemeVariant name: string description: string colors: { primary: string accent: string background: string } } export const useThemeStore = defineStore('theme', { state: () => ({ currentTheme: 'nautical' as ThemeVariant, themes: [ { id: 'nautical', name: 'Classic Nautical', description: 'Deep navy and crimson', colors: { primary: '#001f3f', accent: '#dc143c', background: '#ffffff' } }, { id: 'coastal-dawn', name: 'Coastal Dawn', description: 'Soft blue and gold', colors: { primary: '#A9B4C2', accent: '#D4AF37', background: '#F8F7F4' } }, { id: 'deep-sea', name: 'Deep Sea', description: 'Dark mode with electric blue', colors: { primary: '#1E2022', accent: '#00BFFF', background: '#2A2D30' } }, { id: 'monaco', name: 'Monaco White', description: 'Clean and sophisticated', colors: { primary: '#2C3E50', accent: '#E74C3C', background: '#F8F9FA' } } ] as ThemeOption[] }), getters: { activeTheme: (state) => state.themes.find(t => t.id === state.currentTheme), }, actions: { setTheme(theme: ThemeVariant) { this.currentTheme = theme // Apply theme class to HTML element if (process.client) { document.documentElement.className = `theme-${theme}` // Persist to localStorage localStorage.setItem('harborsmith-theme', theme) // Also set cookie for SSR const cookie = useCookie('harborsmith-theme', { httpOnly: false, sameSite: 'strict', maxAge: 60 * 60 * 24 * 365 // 1 year }) cookie.value = theme } }, loadTheme() { if (process.client) { const saved = localStorage.getItem('harborsmith-theme') || useCookie('harborsmith-theme').value if (saved && this.themes.find(t => t.id === saved)) { this.setTheme(saved as ThemeVariant) } } } } }) ``` ### Theme Switcher Component ```vue ``` --- ## Performance Optimizations ### 1. Image Optimization Strategy ```vue ``` ### 2. Scroll Animation Composable ```typescript // composables/useScrollEffects.ts import { useMotion } from '@vueuse/motion' import { ref, onMounted, onUnmounted } from 'vue' export const useScrollEffects = () => { const elements = ref([]) const observer = ref() const fadeInUp = { initial: { opacity: 0, y: 50 }, enter: { opacity: 1, y: 0, transition: { duration: 800, ease: [0.4, 0, 0.2, 1] } } } const fadeInScale = { initial: { opacity: 0, scale: 0.95 }, enter: { opacity: 1, scale: 1, transition: { duration: 600, ease: [0.4, 0, 0.2, 1] } } } const initScrollAnimations = () => { observer.value = new IntersectionObserver( (entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('animate-visible') observer.value?.unobserve(entry.target) } }) }, { threshold: 0.1, rootMargin: '50px' } ) // Find all elements with data-animate attribute elements.value = Array.from( document.querySelectorAll('[data-animate]') ) as HTMLElement[] elements.value.forEach(el => observer.value?.observe(el)) } onMounted(() => initScrollAnimations()) onUnmounted(() => observer.value?.disconnect()) return { fadeInUp, fadeInScale } } ``` ### 3. Performance Monitoring ```typescript // plugins/performance.client.ts export default defineNuxtPlugin(() => { if (process.dev) return // Web Vitals monitoring onNuxtReady(() => { // First Contentful Paint const paintObserver = new PerformanceObserver((list) => { for (const entry of list.getEntries()) { if (entry.name === 'first-contentful-paint') { console.log('FCP:', entry.startTime) // Send to analytics } } }) paintObserver.observe({ entryTypes: ['paint'] }) // Largest Contentful Paint const lcpObserver = new PerformanceObserver((list) => { const entries = list.getEntries() const lastEntry = entries[entries.length - 1] console.log('LCP:', lastEntry.startTime) // Send to analytics }) lcpObserver.observe({ entryTypes: ['largest-contentful-paint'] }) // Cumulative Layout Shift let clsValue = 0 const clsObserver = new PerformanceObserver((list) => { for (const entry of list.getEntries()) { if (!entry.hadRecentInput) { clsValue += entry.value console.log('CLS:', clsValue) } } }) clsObserver.observe({ entryTypes: ['layout-shift'] }) }) }) ``` --- ## Deployment Strategy ### Docker Configuration ```dockerfile # Dockerfile # Build stage FROM node:20-alpine AS builder # Set working directory WORKDIR /app # Copy package files COPY package*.json ./ # Install dependencies RUN npm ci --only=production # Copy source code COPY . . # Build application RUN npm run generate # Production stage FROM nginx:alpine # Install nginx-module-brotli for better compression RUN apk add --no-cache nginx-mod-http-brotli # Copy built static files COPY --from=builder /app/.output/public /usr/share/nginx/html # Copy nginx configuration COPY nginx.conf /etc/nginx/nginx.conf # Copy custom nginx site config COPY default.conf /etc/nginx/conf.d/default.conf # Expose port EXPOSE 80 # Health check HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD wget --quiet --tries=1 --spider http://localhost/ || exit 1 # Start nginx CMD ["nginx", "-g", "daemon off;"] ``` ### nginx Configuration ```nginx # nginx.conf user nginx; worker_processes auto; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; # Logging log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; # Performance sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; # Gzip compression gzip on; gzip_disable "msie6"; gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss application/rss+xml application/atom+xml image/svg+xml text/x-js text/x-cross-domain-policy application/x-font-ttf application/x-font-opentype application/vnd.ms-fontobject image/x-icon; # Brotli compression brotli on; brotli_comp_level 6; brotli_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss application/rss+xml application/atom+xml image/svg+xml; include /etc/nginx/conf.d/*.conf; } ``` ```nginx # default.conf server { listen 80; server_name localhost; root /usr/share/nginx/html; index index.html; # Security headers add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; add_header Referrer-Policy "no-referrer-when-downgrade" always; add_header Content-Security-Policy "default-src 'self' https:; script-src 'self' 'unsafe-inline' https://unpkg.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; media-src 'self' https://videos.pexels.com;" always; # Cache static assets location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|svg|webp)$ { expires 1y; add_header Cache-Control "public, immutable"; } # Cache HTML (shorter duration) location ~* \.(html)$ { expires 1h; add_header Cache-Control "public, must-revalidate"; } # SPA fallback location / { try_files $uri $uri/ /index.html; } # Health check endpoint location /health { access_log off; return 200 "OK"; } } ``` ### Docker Compose (Development) ```yaml # docker-compose.yml version: '3.8' services: web: build: context: . dockerfile: Dockerfile container_name: harborsmith-web ports: - "3001:80" environment: - NODE_ENV=production restart: unless-stopped healthcheck: test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/"] interval: 30s timeout: 10s retries: 3 networks: - harborsmith networks: harborsmith: driver: bridge ``` --- ## Migration Checklist ### Pre-Migration - [ ] Backup current mockups - [ ] Document all custom styles - [ ] List all JavaScript functionality - [ ] Catalog all images and videos - [ ] Note responsive breakpoints ### Phase 1: Setup - [ ] Initialize Nuxt 3 project - [ ] Configure TypeScript - [ ] Install dependencies - [ ] Setup Tailwind CSS v4 - [ ] Configure Nuxt modules ### Phase 2: Theme System - [ ] Port CSS variables - [ ] Create theme files - [ ] Implement Pinia store - [ ] Build theme switcher - [ ] Test theme persistence ### Phase 3: Components - [ ] Convert navigation - [ ] Build video hero - [ ] Create button components - [ ] Port trust badges - [ ] Convert fleet grid - [ ] Build testimonials - [ ] Add footer ### Phase 4: Content - [ ] Migrate images - [ ] Optimize videos - [ ] Add meta tags - [ ] Setup analytics - [ ] Configure sitemap ### Phase 5: Optimization - [ ] Run Lighthouse audit - [ ] Optimize bundle size - [ ] Test all viewports - [ ] Check accessibility - [ ] Validate SEO ### Phase 6: Deployment - [ ] Build Docker image - [ ] Configure nginx - [ ] Setup CI/CD - [ ] Deploy to staging - [ ] Production deployment ### Post-Migration - [ ] Performance monitoring - [ ] Error tracking - [ ] User testing - [ ] Documentation - [ ] Team training --- ## Testing Strategy ### Unit Tests (Vitest) ```typescript // components/ui/ThemedButton.test.ts import { describe, it, expect } from 'vitest' import { mount } from '@vue/test-utils' import ThemedButton from './ThemedButton.vue' describe('ThemedButton', () => { it('renders with primary variant', () => { const wrapper = mount(ThemedButton, { props: { variant: 'primary' } }) expect(wrapper.classes()).toContain('bg-gradient-warm') }) it('emits click event', async () => { const wrapper = mount(ThemedButton) await wrapper.trigger('click') expect(wrapper.emitted('click')).toHaveLength(1) }) }) ``` ### E2E Tests (Playwright) ```typescript // tests/e2e/landing.spec.ts import { test, expect } from '@playwright/test' test.describe('Landing Page', () => { test('loads with video hero', async ({ page }) => { await page.goto('/') // Check hero section const hero = await page.locator('.hero-voyage') await expect(hero).toBeVisible() // Check video or fallback image const video = page.locator('video') const hasVideo = await video.count() > 0 if (hasVideo) { await expect(video).toHaveAttribute('autoplay') } else { const fallbackImage = page.locator('.hero-voyage img') await expect(fallbackImage).toBeVisible() } }) test('theme switcher works', async ({ page }) => { await page.goto('/') // Open theme menu await page.click('[data-testid="theme-switcher"]') // Select coastal dawn theme await page.click('text=Coastal Dawn') // Check theme applied const html = page.locator('html') await expect(html).toHaveClass('theme-coastal-dawn') // Check persistence await page.reload() await expect(html).toHaveClass('theme-coastal-dawn') }) }) ``` --- ## Success Metrics ### Performance Targets - **Lighthouse Score**: > 95 (all categories) - **First Contentful Paint**: < 1.2s - **Largest Contentful Paint**: < 2.5s - **Time to Interactive**: < 3.5s - **Cumulative Layout Shift**: < 0.1 - **JavaScript Bundle**: < 200KB (initial) - **CSS Bundle**: < 50KB ### Quality Metrics - **TypeScript Coverage**: 100% - **Test Coverage**: > 80% - **Accessibility**: WCAG AA compliant - **SEO Score**: 100 - **Mobile Score**: 100 ### Business Metrics - **Conversion Rate**: Track booking CTAs - **Engagement**: Time on site, scroll depth - **Theme Usage**: Analytics on theme preferences - **Performance**: Real user monitoring --- ## Maintenance & Updates ### Regular Tasks - Update dependencies monthly - Review performance metrics weekly - Monitor error logs daily - Backup before major changes - Document all customizations ### Optimization Opportunities - Implement service worker for offline - Add PWA capabilities - Integrate with CDN - Implement A/B testing - Add personalization features --- ## Conclusion This comprehensive plan provides a clear roadmap for converting the HarborSmith landing page from static HTML to a modern Nuxt 3 application. The approach preserves the sophisticated design while implementing best practices for performance, maintainability, and developer experience. The hybrid strategy of using Tailwind for utilities with CSS custom properties for theming ensures flexibility while maintaining the exact visual design. The component-based architecture with TypeScript provides type safety and reusability for future development. Following this plan will result in a production-ready landing page that loads in under 1 second, maintains perfect visual parity with the mockups, and provides a solid foundation for the entire HarborSmith web platform.