- Create custom hero layout without constraining wrapper div
- Remove min-h-screen and flex constraints that block video extension
- Change video to position:fixed with z-index:-1 for proper layering
- Fix overflow:clip to overflow:visible in voyage-layout.css
- Revert transparent background to black for stability
This finally solves the iOS Safari safe area issue by removing the DOM
structure constraints that were preventing the video from extending.
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove invalid safe-area-max-inset-top (not a valid CSS property)
- Use standard safe-area-inset-top with iOS Safari workarounds
- Remove white background from video container (was blocking transparency)
- Change html/body background to transparent for safe area visibility
- Update status bar style to black-translucent for content under notch
- Add hardcoded fallbacks for iOS Safari portrait bug (env returns 0)
This fixes the issue where the video wasn't extending into the iPhone notch/Dynamic Island
by addressing the root causes: invalid CSS properties, blocking backgrounds, and Safari bugs.
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove ClientOnly and Teleport wrappers that were causing SSR issues
- Switch to safe-area-max-inset-top which properly returns notch height on iOS
- Change position from fixed to absolute to prevent footer overlap
- Add proper fallbacks for browsers without safe-area-max support
- Simplify CSS by removing !important flags and duplicate styles
This fixes the Safari bug where env(safe-area-inset-top) returns 0 in portrait mode
by using safe-area-max-inset-top which always returns the correct notch height.
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
- Wrapped Teleport in ClientOnly to avoid SSR/hydration issues
- Replaced env() with hardcoded -59px for Dynamic Island (Safari bug workaround)
- Added !important flags to ensure styles aren't overridden
- Set overflow: visible on hero-voyage container
- Used z-index: 0 to ensure video stays behind content
This addresses the Nuxt SSG + Teleport incompatibility and iOS Safari's env() bug
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
- Removed CSS contain properties that were preventing video from extending into safe area
- Implemented Vue 3 Teleport to bypass DOM containment for iOS video extension
- Video now renders at body level to properly utilize safe area insets
- Kept Safari fallbacks for env() bug workaround
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
- Add hardcoded fallbacks using max() function per Apple's recommendation
- Support both constant() and env() for legacy compatibility
- Use 59px fallback for Dynamic Island devices
- Add iOS-specific detection with @supports(-webkit-touch-callout)
- Create improved test page with device detection
- Update hero-content padding with same fallback approach
This works around the known Safari bug where env(safe-area-inset-top)
returns 0px in portrait mode. The video will now extend 59px above the
viewport on Dynamic Island iPhones, ensuring it covers the notch area.
- Remove overflow-x: hidden from HeroSection.vue that was clipping video
- Delete duplicate .hero-video-container styles from voyage-layout.css
- Fix navigation to use env() directly instead of CSS variables
- Remove deprecated constant() syntax
- Add safe-area-test.html for testing safe area extension
The video should now properly extend under the iOS notch/Dynamic Island
while keeping content within safe areas.
- Remove overflow:clip from .hero-voyage that was blocking video extension
- Replace hardcoded -50px with proper env(safe-area-inset-top) calculations
- Update hero-content to use env() values directly instead of CSS variables
- Video now properly extends under notch/Dynamic Island on all iOS devices
- Works with Chrome mobile's dynamic address bar using lvh units
- Content stays within safe areas for proper usability
- Use transform translateY to bypass iOS safe area constraints
- Video now extends into notch/Dynamic Island area on page load
- Removed ineffective iOS-specific negative positioning rules
The transform approach works by moving the element after layout calculations,
successfully bypassing Safari's safe area boundaries.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fix hero video not displaying in notch safe area by changing z-index from -1 to 1
- Fix lucide icons not showing by installing and configuring nuxt-icon module
- Fix navigation bar bobbing by removing hysteresis thresholds and simplifying scroll handler
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove Teleport implementation that broke the page
- Use fixed positioning for video container
- Change body background to white for iOS safe area
- Maintain iOS-specific video extension rules
- Used <Teleport to='body'> to render video at root DOM level
- Bypassed layout container constraints (min-h-screen, flex-grow)
- Added ClientOnly wrapper for SSR compatibility
- Video now positioned directly at body level with fixed positioning
- Added iOS-specific styles to extend video into safe area
- Supports 100vh, 100dvh, and 100lvh for maximum compatibility
- White background fallback if video fails to load
- Object-position: center top for better notch coverage
This solution attempts to extend the video into the iOS safe area by
rendering it outside of all parent container constraints.
- Changed body background from black to white for clean fallback
- Added iOS-specific CSS to extend video 50px beyond safe area
- Used @supports (-webkit-touch-callout: none) to target only iOS Safari
- Added hardware acceleration to prevent header bobbing on iOS
- Non-iOS mobile devices maintain normal video positioning
- Ensures white background shows if video doesn't load/extend properly
- Added html/body reset styles (margin:0, padding:0, background:#000)
- Removed ALL overflow:hidden from html, body, hero-voyage, and hero-video-container
- Changed hero-voyage to use overflow:clip (prevents scrollbars while allowing extension)
- Fixed video container positioning:
- Changed from absolute to fixed positioning
- Added top: calc(-1 * env(safe-area-inset-top)) to pull video into notch
- Height: calc(100lvh + env(safe-area-inset-top)) with 100vh fallback
- Set z-index: -1 to place behind all content
- Updated mobile styles to match desktop implementation
- Removed overflow-x:hidden from all parent elements
This follows GPT's exact checklist for iOS notch video extension.
- Created VideoBackdrop component as global sibling layer
- Video now sits at app level behind all content (z-index: 0)
- Hero section made transparent to reveal video backdrop
- Video extends into notch with negative top positioning
- Content remains in safe areas with proper padding
- Removed video container from HeroSection component
- Added app.vue to manage global layout structure
This separation allows the video to truly extend edge-to-edge
including under the iOS notch/Dynamic Island while keeping
all interactive content within safe areas.
- Replace broken fixed positioning with absolute + negative top
- Video now extends calc(-1 * env(safe-area-inset-top)) above container
- Height compensated with calc(100dvh + env(safe-area-inset-top))
- Container uses position: relative with overflow: visible
- Fixes iOS Safari bug where fixed positioning doesn't work properly
This approach allows the video to extend under the iOS notch/Dynamic Island
while keeping interactive content in safe areas.
- Removed incorrect height calculation that added safe areas to video height
- Removed conflicting absolute positioning from main.css
- Video container now properly uses fixed positioning on mobile
- Desktop layout preserved with absolute positioning
The video now correctly extends edge-to-edge under the iOS notch/Dynamic Island
- Video now uses fixed positioning on mobile to fill entire viewport
- Hero content respects safe-area-inset on all sides (top, left, right, bottom)
- Navigation bar includes safe area padding to stay below notch
- Removed padding-top from hero-voyage to allow video under notch
- Maintains smooth scroll transitions and navbar background changes
This allows the hero video to create an immersive edge-to-edge experience
on iOS devices while keeping all interactive elements accessible.
- Add tel: link to phone number (510) 701-2535
- Add mailto: link to email address hello@harborsmith.co
- Style links to inherit color and remove underline for seamless design
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
- Update hero tagline to "Reliable Care Above and Below the Waterline"
- Remove 5-star rating badge from hero section
- Change "Mobile Service" to "Tailored Service" with wrench icon
- Update section title from "Our Premium Services" to "Our Services"
- Merge Hull Cleaning and Anode Change services into single card
- Rename "Exterior Wash & Wax" to "Exterior Cleaning"
- Update trust indicators to show 3 badges: Years Experience, Customizable Service, Certified Experts
- Remove "Schedule Service" button from booking section
- Fix service card alignment with consistent heights and flexbox layout
- Add responsive layout for trust indicators on mobile (2+1 grid)
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
- Changed from linear to ease-out cubic easing function
- Scroll now starts immediately at full speed (no initial delay)
- Gradually decelerates as it approaches the target anchor
- Provides more natural and responsive scrolling experience
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Optimizations implemented:
- Added hardware acceleration for smooth animations (will-change, transform3d)
- Optimized touch targets for mobile (minimum 48x48px)
- Added explicit image dimensions to prevent CLS
- Implemented comprehensive SEO meta tags and Open Graph
- Added structured data for LocalBusiness and Service schemas
- Configured resource hints (preconnect, dns-prefetch, preload)
- Added lazy loading to non-critical images
- Improved button accessibility with touch-action: manipulation
These optimizations improve Core Web Vitals, mobile UX, and SEO visibility.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Replace easeInOutSine with linear easing (return t)
- Reduce duration from 1200ms to 800ms for snappier feel
- Update all component references to use new duration
Linear easing provides constant-speed scrolling without any
acceleration or deceleration, eliminating the jarring effect.
- Replace easeInOutQuad with easeInOutSine for natural motion
- Add user interruption handling (cancel on wheel/touch/keyboard)
- Add accessibility support for prefers-reduced-motion
- Optimize duration from 1800ms to 1200ms
- Add proper cleanup of event listeners and animation frames
- Update all component references to use new duration
The sine-based easing creates smooth, consistent motion throughout
the entire scroll duration without jarring speed changes.
- Changed from easeInOutCubic to easeInOutQuad for smoother motion
- Increased duration from 1.5 to 1.8 seconds
- Fixed jerky acceleration/deceleration issue
- Now provides consistent, smooth scrolling throughout entire motion
The scrolling is now properly smooth without the sudden speed changes.
Features added:
- Custom smooth scroll composable with adjustable duration (1.5 seconds)
- Replaced native browser smooth scroll with custom implementation
- Added 'Scroll to explore' text with chevron at bottom of hero
- Animated bounce effect for scroll indicator
- Chevron icon with subtle animation
- Click handler to scroll to services section
- Hidden on mobile for cleaner experience
All anchor links now scroll more slowly and smoothly for better UX.
- Made navbar brand (logo + title) clickable with cursor pointer
- Added scrollToTop function to smoothly scroll to page top
- Especially useful on mobile devices for quick navigation
Users can now tap the Harbor Smith logo or title to return to top.
- Removed app.vue file that was interfering with navbar scroll behavior
- Restored min-h-screen in default.vue layout
- Restored min-height in body CSS
- Kept the mobile footer fixes which are working correctly
The header now properly changes to white background when scrolling past hero.
Hero Section Viewport Fix:
- Changed body from min-height to height:100% for proper iOS inheritance
- Updated layout wrapper from min-h-screen to h-full
- Created app.vue with explicit height wrapper for Nuxt root
- Maintains complete height inheritance chain: html > body > #__nuxt > layout
Mobile Footer Fix:
- Fixed CSS conflict: removed grid-template-columns from flex container
- Added proper flex column layout for mobile stacking
- Removed margin-left:auto that was causing horizontal overflow
- Added word-wrap and padding for proper text wrapping
- Centered all footer content on mobile devices
These changes ensure the hero section fills the entire iPhone Safari viewport
including the URL bar area, and the footer displays correctly without cutoff.
- Removed safe area padding from .hero-voyage container (was reducing height)
- Simplified video container positioning to fill parent (top:0, bottom:0)
- Applied safe area padding only to .hero-content to protect text/buttons
- Container now uses full viewport height without reduction
The issue was that adding safe area padding to the container itself was
reducing the available height instead of extending it. Safe areas should
only protect content from being obscured, not shrink containers.
- Add viewport-fit=cover to meta tag for safe area extension
- Implement iOS-specific height handling with -webkit-fill-available
- Use dynamic viewport height (100dvh) for proper mobile behavior
- Extend video container beyond safe areas with negative positioning
- Add safe area padding with env() variables for content positioning
- Include mobile-specific @supports queries for better compatibility
This ensures the hero section fills the entire iPhone viewport from top to bottom, extending behind the status bar and home indicator while keeping content readable within safe areas.
- Remove poster image to eliminate jarring flash
- Add white gradient overlay that fades when video ready
- Implement smooth 800ms transition for premium UX
- Add video preload link tag for faster loading
- Works seamlessly on both mobile and desktop
The white overlay approach provides a clean loading experience that matches the luxury brand aesthetic while the video loads in the background.
- Add loadeddata and play events in addition to canplaythrough
- Add fallback timeout to ensure video becomes visible after 1.5s
- This ensures video will display even if autoplay events don't fire properly
- Change video preload from metadata to auto for faster loading
- Add fade-in transition for smooth video appearance
- Remove transform scale(1.1) that caused horizontal overflow
- Add comprehensive overflow-x: hidden to html, body, and hero containers
- Add max-width: 100vw constraints at multiple levels
- Add contain: layout to hero section for better overflow control
- Implement proper loading states to prevent fallback image flash
- Implement dynamic viewport units (dvh) for proper mobile scaling
- Add fluid typography using clamp() functions
- Fix iOS-specific viewport issues with -webkit-fill-available
- Add scroll-margin-top to prevent section overlaps
- Improve touch targets to 50px minimum for mobile UX
- Add CSS custom properties for consistent responsive spacing
- Fix hero section to properly fill mobile viewport
- Update service cards for better mobile layout