started redesign

This commit is contained in:
Nicholai 2025-10-30 03:57:12 -06:00
parent faf030d9b3
commit 41d9b23ff3
33 changed files with 688 additions and 472 deletions

View File

@ -7,10 +7,12 @@ import { ArtistsSection } from "@/components/artists-section"
import { ServicesSection } from "@/components/services-section" import { ServicesSection } from "@/components/services-section"
import { ContactSection } from "@/components/contact-section" import { ContactSection } from "@/components/contact-section"
import { Footer } from "@/components/footer" import { Footer } from "@/components/footer"
import { BackgroundStrata } from "@/components/background-strata"
export default function HomePage() { export default function HomePage() {
return ( return (
<LenisProvider> <LenisProvider>
<main className="min-h-screen"> <main className="relative min-h-screen bg-[#0c0907]">
<BackgroundStrata />
<ScrollProgress /> <ScrollProgress />
<ScrollToSection /> <ScrollToSection />
<Navigation /> <Navigation />

View File

@ -1,257 +1,311 @@
"use client" "use client"
import { useEffect, useMemo, useRef, useState } from "react" import { useCallback, useEffect, useMemo, useRef, useState } from "react"
import Link from "next/link" import Link from "next/link"
import { motion, AnimatePresence, useMotionValue, useTransform } from "framer-motion"
import { useFeatureFlag } from "@/components/feature-flags-provider"
import { Button } from "@/components/ui/button" import { Button } from "@/components/ui/button"
import { artists as staticArtists } from "@/data/artists" import { artists as staticArtists } from "@/data/artists"
import { useActiveArtists } from "@/hooks/use-artists" import { useActiveArtists } from "@/hooks/use-artists"
import type { PublicArtist } from "@/types/database" import type { PublicArtist } from "@/types/database"
import { cn } from "@/lib/utils"
type ArtistGridSet = {
key: string
items: PublicArtist[]
}
const GRID_SIZE = 16
const GRID_INTERVAL = 12000
export function ArtistsSection() { export function ArtistsSection() {
// Fetch artists from database const { data: dbArtistsData, isLoading, error } = useActiveArtists()
const { data: dbArtistsData, isLoading, error } = useActiveArtists()
// Merge static and database data const artists = useMemo(() => {
const artists = useMemo(() => { if (isLoading || error || !dbArtistsData) {
// If still loading or error, use static data return staticArtists
if (isLoading || error || !dbArtistsData) { }
return staticArtists
return staticArtists.map((staticArtist) => {
const dbArtist = dbArtistsData.artists.find(
(db) => db.slug === staticArtist.slug || db.name === staticArtist.name
)
if (dbArtist && dbArtist.portfolioImages.length > 0) {
return {
...staticArtist,
workImages: dbArtist.portfolioImages.map((img) => img.url),
} }
}
// Merge: use database portfolio images, keep static metadata return staticArtist
return staticArtists.map(staticArtist => { })
const dbArtist = dbArtistsData.artists.find( }, [dbArtistsData, error, isLoading])
(db) => db.slug === staticArtist.slug || db.name === staticArtist.name
)
// If found in database, use its portfolio images const artistsRef = useRef(artists)
if (dbArtist && dbArtist.portfolioImages.length > 0) { const gridSetsRef = useRef<ArtistGridSet[]>([])
return { const activeSetRef = useRef(0)
...staticArtist,
workImages: dbArtist.portfolioImages.map(img => img.url) const [gridSets, setGridSets] = useState<ArtistGridSet[]>([])
const [activeSetIndex, setActiveSetIndex] = useState(0)
const [previousSetIndex, setPreviousSetIndex] = useState<number | null>(null)
artistsRef.current = artists
gridSetsRef.current = gridSets
activeSetRef.current = activeSetIndex
const shuffleArtists = useCallback((input: PublicArtist[]) => {
const array = [...input]
for (let i = array.length - 1; i > 0; i -= 1) {
const j = Math.floor(Math.random() * (i + 1))
;[array[i], array[j]] = [array[j], array[i]]
}
return array
}, [])
const ensureGridCount = useCallback(
(pool: PublicArtist[], chunk: PublicArtist[]) => {
if (chunk.length >= GRID_SIZE) {
return chunk.slice(0, GRID_SIZE)
}
const topUpSource = shuffleArtists(pool)
const needed = GRID_SIZE - chunk.length
return [...chunk, ...topUpSource.slice(0, needed)]
},
[shuffleArtists]
)
const createKey = () => Math.random().toString(36).slice(2)
const regenerateSets = useCallback(() => {
const pool = artistsRef.current
if (pool.length === 0) {
setGridSets([])
setActiveSetIndex(0)
setPreviousSetIndex(null)
return
}
const shuffled = shuffleArtists(pool)
const batches: ArtistGridSet[] = []
for (let i = 0; i < shuffled.length; i += GRID_SIZE) {
const slice = ensureGridCount(pool, shuffled.slice(i, i + GRID_SIZE))
batches.push({ key: `${createKey()}-${i}`, items: slice })
}
if (batches.length === 1) {
const alternate = ensureGridCount(pool, shuffleArtists(pool))
batches.push({ key: `${createKey()}-alt`, items: alternate })
}
setGridSets(batches)
setActiveSetIndex(0)
setPreviousSetIndex(null)
}, [ensureGridCount, shuffleArtists])
useEffect(() => {
regenerateSets()
}, [artists, regenerateSets])
const advanceSet = useCallback(() => {
if (gridSetsRef.current.length === 0) {
return
}
setPreviousSetIndex(activeSetRef.current)
setActiveSetIndex((prev) => {
const next = prev + 1
if (next >= gridSetsRef.current.length) {
regenerateSets()
return 0
}
return next
})
}, [regenerateSets])
useEffect(() => {
if (gridSets.length === 0) {
return
}
const interval = window.setInterval(() => {
advanceSet()
}, GRID_INTERVAL)
return () => window.clearInterval(interval)
}, [advanceSet, gridSets.length])
const displayIndices = useMemo(() => {
const indices = new Set<number>()
indices.add(activeSetIndex)
if (previousSetIndex !== null && previousSetIndex !== activeSetIndex) {
indices.add(previousSetIndex)
}
return Array.from(indices)
}, [activeSetIndex, previousSetIndex])
const getArtistImage = (artist: PublicArtist) => {
const candidate = (artist as any).faceImage || artist.workImages?.[0]
if (candidate) {
return candidate
}
return "/placeholder.svg"
}
return (
<section id="artists" className="relative isolate overflow-hidden pb-24 pt-24">
<div className="pointer-events-none absolute inset-0 -z-10">
<div className="absolute inset-0 bg-[linear-gradient(180deg,rgba(14,11,9,0)_0%,rgba(14,11,9,0.85)_20%,rgba(14,11,9,0.92)_55%,rgba(14,11,9,0.98)_100%)]" />
<div
className="absolute -left-16 top-[8%] h-[480px] w-[420px] rotate-[-8deg] rounded-[36px] opacity-40 blur-[1px]"
style={{
backgroundImage:
"image-set(url('/assets/liberty/mural-portrait-sun.avif') type('image/avif'), url('/assets/liberty/mural-portrait-sun.webp') type('image/webp'))",
backgroundSize: "cover",
backgroundPosition: "center",
}}
/>
<div
className="absolute -right-24 top-[35%] hidden h-[540px] w-[420px] rotate-[6deg] rounded-[36px] opacity-30 lg:block"
style={{
backgroundImage:
"image-set(url('/assets/liberty/mural-orange-wall.avif') type('image/avif'), url('/assets/liberty/mural-orange-wall.webp') type('image/webp'))",
backgroundSize: "cover",
backgroundPosition: "center",
}}
/>
<div className="absolute inset-0 bg-[radial-gradient(circle_at_50%_20%,rgba(255,255,255,0.08),transparent_55%)]" />
</div>
<div className="relative mx-auto flex max-w-6xl flex-col gap-16 px-6 lg:px-10 xl:flex-row">
<div className="flex-1 space-y-10 text-white">
<div className="space-y-4">
<span className="inline-flex items-center gap-3 text-[0.7rem] font-semibold uppercase tracking-[0.55em] text-white/55">
<span className="h-px w-8 bg-white/35" /> Resident & Guest Artists
</span>
<h2 className="font-playfair text-4xl leading-[1.1] tracking-tight sm:text-5xl lg:text-[3.6rem]">
A Collective of Story-Driven Tattoo Artists
</h2>
<p className="max-w-xl text-base leading-relaxed text-white/70 sm:text-lg">
United Tattoo is home to cover-up virtuosos, illustrative explorers, anime specialists, and fine line minimalists.
Every artist curates their chair with intentionoffering custom narratives, flash experiments, and collaborative pieces
that evolve with you.
</p>
</div>
<div className="grid gap-5 text-xs uppercase tracking-[0.32em] text-white/60 sm:grid-cols-2">
<div className="rounded-3xl border border-white/10 bg-[rgba(255,255,255,0.05)] p-6">
<p className="text-[0.65rem] font-semibold text-white/55">What to Expect</p>
<p className="mt-3 text-sm tracking-[0.28em] text-white">Consultation-first Process</p>
<p className="mt-3 text-[0.68rem] leading-relaxed tracking-[0.26em] text-white/45">
Artist pairing Mood-boards Aftercare guides CalDAV-synced scheduling
</p>
</div>
<div className="rounded-3xl border border-white/10 bg-[rgba(255,255,255,0.04)] p-6">
<p className="text-[0.65rem] font-semibold text-white/55">Specialties</p>
<p className="mt-3 text-sm tracking-[0.28em] text-white">Layered Stylescapes</p>
<p className="mt-3 text-[0.68rem] leading-relaxed tracking-[0.26em] text-white/45">
Black & grey realism Neo-traditional color Bold cover-ups Fine line botanicals
</p>
</div>
</div>
<div className="flex flex-col gap-6 pt-2 sm:flex-row sm:items-center">
<Button
asChild
className="group relative w-full overflow-hidden rounded-full bg-white/90 px-8 py-4 text-xs font-semibold uppercase tracking-[0.38em] text-[#1c1713] transition-all duration-300 hover:bg-white sm:w-auto"
>
<Link href="/book">
Reserve with an Artist
<span className="ml-3 inline-flex h-[1px] w-6 bg-[#1c1713] transition-all duration-300 group-hover:w-10" />
</Link>
</Button>
<Button
variant="ghost"
asChild
className="w-full justify-start rounded-full border border-white/15 bg-white/5 px-6 py-4 text-xs font-semibold uppercase tracking-[0.32em] text-white/80 backdrop-blur sm:w-auto"
>
<Link href="/artists">View full roster</Link>
</Button>
</div>
</div>
<div className="relative flex-1">
<div className="relative overflow-hidden rounded-[36px] border border-white/12 bg-[rgba(12,10,8,0.82)] p-6 shadow-[0_45px_90px_-35px_rgba(0,0,0,0.75)]">
<div className="pointer-events-none absolute inset-0 rounded-[36px] border border-white/[0.05]" aria-hidden="true" />
<div className="pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_30%_20%,rgba(255,255,255,0.12),transparent_55%)]" aria-hidden="true" />
<div className="relative min-h-[520px]">
{displayIndices.map((index) => {
const set = gridSets[index]
if (!set) {
return null
} }
} const isActive = index === activeSetIndex
// Fall back to static data return (
return staticArtist <div
}) key={set.key}
}, [dbArtistsData, isLoading, error]) className={cn(
"absolute inset-0 grid grid-cols-2 gap-3 sm:gap-4 md:gap-5 lg:grid-cols-4",
// Minimal animation: fade-in only (no parallax) "transition-opacity duration-[1300ms] ease-out",
const [visibleCards, setVisibleCards] = useState<number[]>([]) isActive ? "pointer-events-auto opacity-100" : "pointer-events-none opacity-0"
const [hoveredCard, setHoveredCard] = useState<number | null>(null) )}
const [portfolioIndices, setPortfolioIndices] = useState<Record<number, number>>({}) >
const sectionRef = useRef<HTMLElement>(null) {set.items.map((artist) => {
const advancedNavAnimations = useFeatureFlag("ADVANCED_NAV_SCROLL_ANIMATIONS_ENABLED") const href = `/artists/${artist.slug}`
const allArtistIndices = useMemo(() => Array.from({ length: artists.length }, (_, idx) => idx), [artists.length]) const image = getArtistImage(artist)
return (
useEffect(() => { <Link
if (!advancedNavAnimations) { key={`${set.key}-${artist.id}-${artist.slug}`}
setVisibleCards(allArtistIndices) href={href}
return className="group relative flex flex-col overflow-hidden rounded-3xl border border-white/12 bg-white/[0.06] p-3 text-left transition-all duration-500 hover:-translate-y-1 hover:border-white/25 hover:bg-white/[0.1]"
} >
setVisibleCards([]) <div className="relative aspect-[4/5] overflow-hidden rounded-2xl">
}, [advancedNavAnimations, allArtistIndices]) <img
src={image}
useEffect(() => { alt={`${artist.name} portfolio sample`}
if (!advancedNavAnimations) return className="h-full w-full object-cover transition-transform duration-700 group-hover:scale-[1.06]"
const observer = new IntersectionObserver( loading="lazy"
(entries) => { />
entries.forEach((entry) => { <div className="absolute inset-0 bg-gradient-to-t from-[#0b0907] via-transparent to-transparent" />
if (entry.isIntersecting) { <div className="absolute right-4 top-4 h-10 w-10 rounded-full border border-white/20 bg-white/10 backdrop-blur">
const cardIndex = Number.parseInt(entry.target.getAttribute("data-index") || "0") <span className="absolute inset-2 rounded-full border border-white/15" />
setVisibleCards((prev) => [...new Set([...prev, cardIndex])]) </div>
} </div>
}) <div className="mt-4 space-y-1">
}, <p className="text-sm font-semibold uppercase tracking-[0.35em] text-white">
{ threshold: 0.2, rootMargin: "0px 0px -10% 0px" }, {artist.name}
)
const cards = sectionRef.current?.querySelectorAll("[data-index]")
cards?.forEach((card) => observer.observe(card))
return () => observer.disconnect()
}, [advancedNavAnimations])
const cardVisibilityClass = (index: number) => {
if (!advancedNavAnimations) return "opacity-100 translate-y-0"
return visibleCards.includes(index) ? "opacity-100 translate-y-0" : "opacity-0 translate-y-6"
}
const cardTransitionDelay = (index: number) => {
if (!advancedNavAnimations) return undefined
return `${index * 40}ms`
}
// Vary aspect ratio to create a subtle masonry rhythm
const aspectFor = (i: number) => {
const variants = ["aspect-[3/4]", "aspect-[4/5]", "aspect-square"]
return variants[i % variants.length]
}
// Handle hover to cycle through portfolio images
const handleHoverStart = (artistIndex: number) => {
setHoveredCard(artistIndex)
const artist = artists[artistIndex]
if (artist.workImages.length > 0) {
setPortfolioIndices((prev) => {
const currentIndex = prev[artistIndex] ?? 0
const nextIndex = (currentIndex + 1) % artist.workImages.length
return { ...prev, [artistIndex]: nextIndex }
})
}
}
const handleHoverEnd = () => {
setHoveredCard(null)
}
const getPortfolioImage = (artistIndex: number) => {
const artist = artists[artistIndex]
if (artist.workImages.length === 0) return null
const imageIndex = portfolioIndices[artistIndex] ?? 0
return artist.workImages[imageIndex]
}
return (
<section ref={sectionRef} id="artists" className="relative overflow-hidden bg-black">
{/* Faint logo texture */}
<div className="absolute inset-0 opacity-[0.03]">
<img
src="/united-logo-full.jpg"
alt=""
className="w-full h-full object-cover object-center scale-150 blur-[2px]"
/>
<div className="absolute inset-0 bg-black/80 backdrop-blur-sm" />
</div>
{/* Header */}
<div className="relative z-10 py-14 px-6 lg:px-10">
<div className="max-w-[1800px] mx-auto">
<div className="grid lg:grid-cols-3 gap-10 items-end mb-10">
<div className="lg:col-span-2">
<h2 className="text-6xl lg:text-8xl font-bold tracking-tight mb-4 text-white">ARTISTS</h2>
<p className="text-lg lg:text-xl text-gray-200/90 leading-relaxed max-w-2xl">
Our exceptional team of tattoo artists, each bringing unique expertise and artistic vision to create your perfect
tattoo.
</p> </p>
</div> <p className="text-[0.65rem] uppercase tracking-[0.32em] text-white/55">
<div className="text-right"> {(artist as any).specialty || "Tattoo Artist"}
<Button </p>
asChild </div>
className="bg-white text-black hover:bg-gray-100 px-7 py-3 text-base font-medium tracking-wide shadow-sm rounded-md" </Link>
> )
<Link href="/book">BOOK CONSULTATION</Link> })}
</Button> </div>
</div> )
</div> })}
</div>
</div> </div>
</div>
</div>
</div>
{/* Masonry grid */} <div className="relative z-10 mt-24 flex flex-col items-center gap-6 px-6 text-center text-white lg:px-10">
<div className="relative z-10 px-6 lg:px-10 pb-24"> <p className="uppercase tracking-[0.4em] text-white/45">Let's Plan Your Piece</p>
<div className="max-w-[1800px] mx-auto"> <h3 className="font-playfair text-3xl leading-tight sm:text-4xl">
{/* columns-based masonry; tighter spacing and wider section */} Choose your artist, share your story, and build a tattoo ritual around intentional ink.
<div className="columns-1 sm:columns-2 lg:columns-3 gap-4 lg:gap-5 [column-fill:_balance]"> </h3>
{artists.map((artist, i) => { <Button
const transitionDelay = cardTransitionDelay(i) asChild
const portfolioImage = getPortfolioImage(i) className="rounded-full border border-white/20 bg-white text-sm font-semibold uppercase tracking-[0.32em] text-[#1c1713] shadow-[0_30px_60px_-35px_rgba(255,255,255,0.65)] transition-transform duration-300 hover:scale-[1.03]"
const isHovered = hoveredCard === i >
<Link href="/book" className="px-10 py-4">
return ( Start A Consultation
<article </Link>
key={artist.id} </Button>
data-index={i} </div>
className={`group mb-4 break-inside-avoid transition-all duration-700 ${cardVisibilityClass(i)}`} </section>
style={transitionDelay ? { transitionDelay } : undefined} )
>
<Link href={`/artists/${artist.slug}`}>
<motion.div
className={`relative w-full ${aspectFor(i)} overflow-hidden rounded-md border border-white/10 bg-black cursor-pointer`}
onHoverStart={() => handleHoverStart(i)}
onHoverEnd={handleHoverEnd}
>
{/* Base layer: artist portrait */}
<div className="absolute inset-0 artist-image">
<img
src={artist.faceImage || "/placeholder.svg"}
alt={`${artist.name} portrait`}
className="w-full h-full object-cover"
loading="lazy"
/>
</div>
{/* Wipe overlay: portfolio image with curved boundary */}
<AnimatePresence>
{isHovered && portfolioImage && (
<>
{/* SVG clipPath with pronounced wave */}
<svg className="absolute w-0 h-0">
<defs>
<clipPath id={`wipe-curve-${i}`} clipPathUnits="objectBoundingBox">
<motion.path
initial={{
d: "M 0,0 L 1,0 L 1,0 Q 0.75,0 0.5,0 Q 0.25,0 0,0 Z"
}}
animate={{
d: "M 0,0 L 1,0 L 1,1.1 Q 0.75,1.02 0.5,1.1 Q 0.25,1.18 0,1.1 Z"
}}
exit={{
d: "M 0,0 L 1,0 L 1,0 Q 0.75,0 0.5,0 Q 0.25,0 0,0 Z"
}}
transition={{ duration: 0.5, ease: "easeInOut" }}
/>
</clipPath>
</defs>
</svg>
{/* Portfolio image with curved clip */}
<div
className="absolute inset-0 z-10"
style={{
clipPath: `url(#wipe-curve-${i})`,
}}
>
<img
src={portfolioImage}
alt={`${artist.name} work`}
className="w-full h-full object-cover"
/>
</div>
</>
)}
</AnimatePresence>
{/* Minimal footer - only name */}
<div className="absolute bottom-0 left-0 right-0 z-20 bg-gradient-to-t from-black/80 via-black/20 to-transparent p-4">
<h3 className="text-xl font-semibold tracking-tight text-white">{artist.name}</h3>
<p className="text-xs font-medium text-white/80">{artist.specialty}</p>
</div>
</motion.div>
</Link>
</article>
)
})}
</div>
</div>
</div>
{/* CTA Footer */}
<div className="relative z-20 bg-black text-white py-20 px-6 lg:px-10">
<div className="max-w-[1800px] mx-auto text-center">
<h3 className="text-5xl lg:text-7xl font-bold tracking-tight mb-8">READY?</h3>
<p className="text-xl text-white/70 mb-12 max-w-2xl mx-auto">
Choose your artist and start your tattoo journey with United Tattoo.
</p>
<Button
asChild
className="bg-white text-black hover:bg-gray-100 hover:text-black px-12 py-6 text-xl font-medium tracking-wide shadow-lg border border-white rounded-md"
>
<Link href="/book">START NOW</Link>
</Button>
</div>
</div>
</section>
)
} }

View File

@ -0,0 +1,51 @@
"use client"
import { useEffect, useRef } from "react"
import { useReducedMotion } from "@/hooks/use-parallax"
export function BackgroundStrata() {
const layerRef = useRef<HTMLDivElement>(null)
const reducedMotion = useReducedMotion()
useEffect(() => {
if (reducedMotion) {
return
}
const target = layerRef.current
if (!target) {
return
}
let frame = 0
const animate = () => {
const offset = window.scrollY * 0.08
target.style.transform = `translate3d(0, ${offset}px, 0)`
frame = requestAnimationFrame(animate)
}
frame = requestAnimationFrame(animate)
return () => cancelAnimationFrame(frame)
}, [reducedMotion])
return (
<div className="pointer-events-none absolute inset-x-0 top-0 -z-10 h-[230vh] overflow-hidden">
<div className="absolute inset-0 bg-[radial-gradient(circle_at_20%_0%,rgba(255,255,255,0.12),transparent_55%),radial-gradient(circle_at_80%_10%,rgba(255,255,255,0.08),transparent_52%)]" />
<div className="absolute inset-0 bg-[linear-gradient(180deg,rgba(14,11,9,0.92)_0%,rgba(14,11,9,0.75)_28%,rgba(10,8,7,0.35)_68%,transparent_100%)]" />
<div
ref={layerRef}
className="h-full w-full scale-[1.04] transform-gpu transition-transform duration-1000 ease-out"
style={{
backgroundImage:
"image-set(url('/assets/liberty/background-dove-wash.avif') type('image/avif'), url('/assets/liberty/background-dove-wash.webp') type('image/webp'))",
backgroundSize: "cover",
backgroundPosition: "center top",
backgroundRepeat: "no-repeat",
}}
/>
<div className="absolute inset-x-0 bottom-0 h-[420px] bg-[linear-gradient(180deg,rgba(12,10,8,0.2)_0%,rgba(12,10,8,0.65)_45%,rgba(12,10,8,1)_98%)]" />
</div>
)
}

View File

@ -35,10 +35,10 @@ export function ContactSection() {
} }
return ( return (
<section id="contact" className="min-h-screen bg-black relative overflow-hidden"> <section id="contact" className="relative min-h-screen overflow-hidden bg-[#0c0907]">
{/* Background logo - desktop only */} {/* Background logo - desktop only */}
<div <div
className="absolute inset-0 opacity-[0.03] bg-cover bg-center bg-no-repeat blur-sm hidden lg:block" className="hidden opacity-[0.05] blur-sm lg:block absolute inset-0 bg-cover bg-center bg-no-repeat"
style={{ style={{
backgroundImage: "url('/united-logo-full.jpg')", backgroundImage: "url('/united-logo-full.jpg')",
transform: `translateY(${scrollY * 0.2}px)`, transform: `translateY(${scrollY * 0.2}px)`,
@ -46,22 +46,22 @@ export function ContactSection() {
/> />
{/* Mobile solid background */} {/* Mobile solid background */}
<div className="absolute inset-0 bg-black lg:hidden"></div> <div className="absolute inset-0 bg-[#0c0907] lg:hidden"></div>
<div className="flex flex-col lg:flex-row min-h-screen relative z-10"> <div className="relative z-10 flex min-h-screen flex-col lg:flex-row">
<div className="w-full lg:w-1/2 bg-black flex items-center justify-center p-8 lg:p-12 relative"> <div className="relative flex w-full items-center justify-center bg-[#0f0b09] p-8 lg:w-1/2 lg:p-12">
{/* Mobile background overlay to hide logo */} {/* Mobile background overlay to hide logo */}
<div className="absolute inset-0 bg-black lg:bg-transparent"></div> <div className="absolute inset-0 bg-[#0f0b09]/95 lg:bg-transparent" />
<div className="w-full max-w-md relative z-10"> <div className="relative z-10 w-full max-w-md">
<div className="mb-8"> <div className="mb-8">
<h2 className="text-4xl font-bold text-white mb-2">Let's Talk</h2> <h2 className="mb-2 font-playfair text-4xl text-white">Let's Talk</h2>
<p className="text-gray-400">Ready to create something amazing?</p> <p className="text-white/55">Ready to create something amazing?</p>
</div> </div>
<form onSubmit={handleSubmit} className="space-y-6"> <form onSubmit={handleSubmit} className="space-y-6">
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-2 gap-4">
<div> <div>
<label htmlFor="name" className="block text-sm font-medium text-white mb-2"> <label htmlFor="name" className="mb-2 block text-sm font-medium uppercase tracking-[0.3em] text-white/70">
Name Name
</label> </label>
<Input <Input
@ -70,12 +70,12 @@ export function ContactSection() {
value={formData.name} value={formData.name}
onChange={handleChange} onChange={handleChange}
required required
className="bg-white/10 border-white/20 text-white placeholder:text-gray-400 focus:border-white focus:bg-white/15 transition-all" className="border-white/15 bg-white/10 text-white placeholder:text-white/40 transition-all focus:border-white focus:bg-white/15"
placeholder="Your name" placeholder="Your name"
/> />
</div> </div>
<div> <div>
<label htmlFor="phone" className="block text-sm font-medium text-white mb-2"> <label htmlFor="phone" className="mb-2 block text-sm font-medium uppercase tracking-[0.3em] text-white/70">
Phone Phone
</label> </label>
<Input <Input
@ -84,14 +84,14 @@ export function ContactSection() {
type="tel" type="tel"
value={formData.phone} value={formData.phone}
onChange={handleChange} onChange={handleChange}
className="bg-white/10 border-white/20 text-white placeholder:text-gray-400 focus:border-white focus:bg-white/15 transition-all" className="border-white/15 bg-white/10 text-white placeholder:text-white/40 transition-all focus:border-white focus:bg-white/15"
placeholder="(555) 123-4567" placeholder="(555) 123-4567"
/> />
</div> </div>
</div> </div>
<div> <div>
<label htmlFor="email" className="block text-sm font-medium text-white mb-2"> <label htmlFor="email" className="mb-2 block text-sm font-medium uppercase tracking-[0.3em] text-white/70">
Email Email
</label> </label>
<Input <Input
@ -101,13 +101,13 @@ export function ContactSection() {
value={formData.email} value={formData.email}
onChange={handleChange} onChange={handleChange}
required required
className="bg-white/10 border-white/20 text-white placeholder:text-gray-400 focus:border-white focus:bg-white/15 transition-all" className="border-white/15 bg-white/10 text-white placeholder:text-white/40 transition-all focus:border-white focus:bg-white/15"
placeholder="your@email.com" placeholder="your@email.com"
/> />
</div> </div>
<div> <div>
<label htmlFor="message" className="block text-sm font-medium text-white mb-2"> <label htmlFor="message" className="mb-2 block text-sm font-medium uppercase tracking-[0.3em] text-white/70">
Message Message
</label> </label>
<Textarea <Textarea
@ -118,13 +118,13 @@ export function ContactSection() {
onChange={handleChange} onChange={handleChange}
placeholder="Tell us about your tattoo idea..." placeholder="Tell us about your tattoo idea..."
required required
className="bg-white/10 border-white/20 text-white placeholder:text-gray-400 focus:border-white focus:bg-white/15 transition-all resize-none" className="resize-none border-white/15 bg-white/10 text-white placeholder:text-white/40 transition-all focus:border-white focus:bg-white/15"
/> />
</div> </div>
<Button <Button
type="submit" type="submit"
className="w-full bg-white text-black hover:bg-gray-100 py-3 text-base font-medium transition-all" className="w-full rounded-full border border-white/15 bg-white/90 py-3 text-xs font-semibold uppercase tracking-[0.32em] text-[#1c1713] transition-all hover:bg-white"
> >
Send Message Send Message
</Button> </Button>
@ -132,10 +132,10 @@ export function ContactSection() {
</div> </div>
</div> </div>
<div className="w-full lg:w-1/2 bg-gray-50 relative flex items-center justify-center"> <div className="relative flex w-full items-center justify-center bg-[radial-gradient(circle_at_top_right,rgba(255,255,255,0.07),transparent_55%),linear-gradient(180deg,#1a1512_0%,#110d0a_100%)] lg:w-1/2">
{/* Brand asset as decorative element */} {/* Brand asset as decorative element */}
<div <div
className="absolute inset-0 opacity-20 bg-cover bg-center bg-no-repeat" className="absolute inset-0 bg-cover bg-center bg-no-repeat opacity-[0.08]"
style={{ style={{
backgroundImage: "url('/united-logo-text.png')", backgroundImage: "url('/united-logo-text.png')",
transform: `translateY(${scrollY * -0.1}px)`, transform: `translateY(${scrollY * -0.1}px)`,
@ -144,14 +144,14 @@ export function ContactSection() {
<div className="relative z-10 p-12 text-center"> <div className="relative z-10 p-12 text-center">
<div className="mb-12"> <div className="mb-12">
<h2 className="text-5xl font-bold text-black mb-4">UNITED</h2> <h2 className="font-playfair text-5xl text-white">UNITED</h2>
<h3 className="text-3xl font-bold text-gray-600 mb-6">TATTOO</h3> <h3 className="mt-2 font-playfair text-3xl text-white/70">TATTOO</h3>
<p className="text-gray-700 text-lg max-w-md mx-auto leading-relaxed"> <p className="mx-auto mt-6 max-w-md text-base leading-relaxed text-white/65">
Where artistry, culture, and custom tattoos meet. Located in Fountain, just minutes from Colorado Springs. Where artistry, culture, and custom tattoos meet. Located in Fountain, just minutes from Colorado Springs.
</p> </p>
</div> </div>
<div className="space-y-6 max-w-sm mx-auto"> <div className="mx-auto max-w-sm space-y-6">
{[ {[
{ {
icon: MapPin, icon: MapPin,
@ -177,10 +177,12 @@ export function ContactSection() {
const Icon = item.icon const Icon = item.icon
return ( return (
<div key={index} className="flex items-start space-x-4 text-left"> <div key={index} className="flex items-start space-x-4 text-left">
<Icon className="w-5 h-5 text-black mt-1 flex-shrink-0" /> <div className="mt-1 flex h-9 w-9 items-center justify-center rounded-full border border-white/15 bg-white/10">
<Icon className="h-4 w-4 text-white/70" />
</div>
<div> <div>
<p className="text-black font-medium text-sm">{item.title}</p> <p className="text-xs font-semibold uppercase tracking-[0.4em] text-white/60">{item.title}</p>
<p className="text-gray-600 text-sm">{item.content}</p> <p className="mt-1 text-sm text-white/70">{item.content}</p>
</div> </div>
</div> </div>
) )

View File

@ -28,23 +28,22 @@ export function Footer() {
<> <>
<Button <Button
onClick={scrollToTop} onClick={scrollToTop}
className={`fixed bottom-8 right-8 z-50 rounded-full w-12 h-12 p-0 bg-white text-black hover:bg-gray-100 shadow-lg transition-all duration-300 ${ className={`fixed bottom-8 right-8 z-50 h-12 w-12 rounded-full border border-white/15 bg-white/90 p-0 text-[#1c1713] shadow-[0_30px_60px_-35px_rgba(255,255,255,0.65)] transition-all duration-300 hover:scale-[1.05] hover:bg-white ${
showScrollTop ? "opacity-100 translate-y-0" : "opacity-0 translate-y-4 pointer-events-none" showScrollTop ? "translate-y-0 opacity-100" : "pointer-events-none translate-y-4 opacity-0"
}`} }`}
aria-label="Scroll to top" aria-label="Scroll to top"
> >
<ArrowUp size={20} /> <ArrowUp size={20} />
</Button> </Button>
<footer className="bg-black text-white py-16 font-mono"> <footer className="bg-[radial-gradient(circle_at_top_left,rgba(255,255,255,0.09),transparent_55%),linear-gradient(180deg,#15100d_0%,#0c0907_100%)] py-16 text-white">
<div className="container mx-auto px-8"> <div className="container mx-auto px-8">
<div className="grid grid-cols-1 md:grid-cols-12 gap-8 items-start"> <div className="grid grid-cols-1 items-start gap-10 md:grid-cols-12">
<div className="md:col-span-3"> <div className="md:col-span-3">
<div className="flex items-center gap-2 mb-6"> <div className="mb-6 flex items-center gap-2 text-xs uppercase tracking-[0.4em] text-white/55">
<span className="text-white"></span> <span className="inline-flex h-2 w-2 rounded-full bg-white/40" /> Services
<h4 className="text-white font-medium tracking-wide text-lg">SERVICES</h4>
</div> </div>
<ul className="space-y-3 text-base"> <ul className="space-y-3 text-sm text-white/65">
{[ {[
{ name: "TRADITIONAL", count: "" }, { name: "TRADITIONAL", count: "" },
{ name: "REALISM", count: "" }, { name: "REALISM", count: "" },
@ -55,7 +54,7 @@ export function Footer() {
{ name: "ANIME", count: "" }, { name: "ANIME", count: "" },
].map((service, index) => ( ].map((service, index) => (
<li key={index}> <li key={index}>
<Link href="/book" className="text-gray-400 hover:text-white transition-colors duration-200"> <Link href="/book" className="transition-colors duration-200 hover:text-white">
{service.name} {service.name}
{service.count && <span className="text-white ml-2">{service.count}</span>} {service.count && <span className="text-white ml-2">{service.count}</span>}
</Link> </Link>
@ -65,11 +64,10 @@ export function Footer() {
</div> </div>
<div className="md:col-span-3"> <div className="md:col-span-3">
<div className="flex items-center gap-2 mb-6"> <div className="mb-6 flex items-center gap-2 text-xs uppercase tracking-[0.4em] text-white/55">
<span className="text-white"></span> <span className="inline-flex h-2 w-2 rounded-full bg-white/40" /> Artists
<h4 className="text-white font-medium tracking-wide text-lg">ARTISTS</h4>
</div> </div>
<ul className="space-y-3 text-base"> <ul className="space-y-3 text-sm text-white/65">
{[ {[
{ name: "CHRISTY_LUMBERG", count: "" }, { name: "CHRISTY_LUMBERG", count: "" },
{ name: "STEVEN_SOLE", count: "" }, { name: "STEVEN_SOLE", count: "" },
@ -77,7 +75,7 @@ export function Footer() {
{ name: "VIEW_ALL", count: "" }, { name: "VIEW_ALL", count: "" },
].map((artist, index) => ( ].map((artist, index) => (
<li key={index}> <li key={index}>
<Link href="/artists" className="text-gray-400 hover:text-white transition-colors duration-200"> <Link href="/artists" className="transition-colors duration-200 hover:text-white">
{artist.name} {artist.name}
{artist.count && <span className="text-white ml-2">{artist.count}</span>} {artist.count && <span className="text-white ml-2">{artist.count}</span>}
</Link> </Link>
@ -87,17 +85,13 @@ export function Footer() {
</div> </div>
<div className="md:col-span-3"> <div className="md:col-span-3">
<div className="text-gray-500 text-sm leading-relaxed mb-4"> <div className="mb-4 text-xs uppercase tracking-[0.4em] text-white/40">
© <span className="text-white underline">UNITED.TATTOO</span> LLC 2025 © <span className="text-white/80">UNITED.TATTOO</span> LLC 2025 All Rights Reserved
<br />
ALL RIGHTS RESERVED.
</div> </div>
<div className="text-gray-400 text-sm"> <div className="space-y-2 text-sm text-white/60">
5160 FONTAINE BLVD <p>5160 Fontaine Blvd</p>
<br /> <p>Fountain, CO 80817</p>
FOUNTAIN, CO 80817 <Link href="tel:+17196989004" className="transition-colors duration-200 hover:text-white">
<br />
<Link href="tel:+17196989004" className="hover:text-white transition-colors">
(719) 698-9004 (719) 698-9004
</Link> </Link>
</div> </div>
@ -106,15 +100,14 @@ export function Footer() {
<div className="md:col-span-3 space-y-8"> <div className="md:col-span-3 space-y-8">
{/* Legal */} {/* Legal */}
<div> <div>
<div className="flex items-center gap-2 mb-4"> <div className="mb-4 flex items-center gap-2 text-xs uppercase tracking-[0.4em] text-white/55">
<span className="text-white"></span> <span className="inline-flex h-2 w-2 rounded-full bg-white/40" /> Legal
<h4 className="text-white font-medium tracking-wide text-lg">LEGAL</h4>
</div> </div>
<ul className="space-y-2 text-base"> <ul className="space-y-2 text-sm text-white/65">
<li> <li>
<Link <Link
href="/aftercare" href="/aftercare"
className="text-gray-400 hover:text-white transition-colors duration-200 underline" className="transition-colors duration-200 hover:text-white underline"
> >
AFTERCARE AFTERCARE
</Link> </Link>
@ -122,7 +115,7 @@ export function Footer() {
<li> <li>
<Link <Link
href="/deposit" href="/deposit"
className="text-gray-400 hover:text-white transition-colors duration-200 underline" className="transition-colors duration-200 hover:text-white underline"
> >
DEPOSIT POLICY DEPOSIT POLICY
</Link> </Link>
@ -130,7 +123,7 @@ export function Footer() {
<li> <li>
<Link <Link
href="/terms" href="/terms"
className="text-gray-400 hover:text-white transition-colors duration-200 underline" className="transition-colors duration-200 hover:text-white underline"
> >
TERMS OF SERVICE TERMS OF SERVICE
</Link> </Link>
@ -138,7 +131,7 @@ export function Footer() {
<li> <li>
<Link <Link
href="/privacy" href="/privacy"
className="text-gray-400 hover:text-white transition-colors duration-200 underline" className="transition-colors duration-200 hover:text-white underline"
> >
PRIVACY POLICY PRIVACY POLICY
</Link> </Link>
@ -146,7 +139,7 @@ export function Footer() {
<li> <li>
<Link <Link
href="#" href="#"
className="text-gray-400 hover:text-white transition-colors duration-200 underline" className="transition-colors duration-200 hover:text-white underline"
> >
WAIVER WAIVER
</Link> </Link>
@ -156,23 +149,37 @@ export function Footer() {
{/* Social */} {/* Social */}
<div> <div>
<div className="flex items-center gap-2 mb-4"> <div className="mb-4 flex items-center gap-2 text-xs uppercase tracking-[0.4em] text-white/55">
<span className="text-white"></span> <span className="inline-flex h-2 w-2 rounded-full bg-white/40" /> Social
<h4 className="text-white font-medium tracking-wide text-lg">SOCIAL</h4>
</div> </div>
<ul className="space-y-2 text-base"> <ul className="space-y-2 text-sm text-white/65">
<li> <li>
<Link href="https://www.instagram.com/unitedtattoo719" target="_blank" rel="noopener noreferrer" className="text-gray-400 hover:text-white transition-colors duration-200 underline"> <Link
href="https://www.instagram.com/unitedtattoo719"
target="_blank"
rel="noopener noreferrer"
className="text-white/65 underline transition-colors duration-200 hover:text-white"
>
INSTAGRAM INSTAGRAM
</Link> </Link>
</li> </li>
<li> <li>
<Link href="https://www.facebook.com/unitedtattoo719" target="_blank" rel="noopener noreferrer" className="text-gray-400 hover:text-white transition-colors duration-200 underline"> <Link
href="https://www.facebook.com/unitedtattoo719"
target="_blank"
rel="noopener noreferrer"
className="text-white/65 underline transition-colors duration-200 hover:text-white"
>
FACEBOOK FACEBOOK
</Link> </Link>
</li> </li>
<li> <li>
<Link href="https://www.tiktok.com/@united.tattoo" target="_blank" rel="noopener noreferrer" className="text-gray-400 hover:text-white transition-colors duration-200 underline"> <Link
href="https://www.tiktok.com/@united.tattoo"
target="_blank"
rel="noopener noreferrer"
className="text-white/65 underline transition-colors duration-200 hover:text-white"
>
TIKTOK TIKTOK
</Link> </Link>
</li> </li>
@ -181,13 +188,12 @@ export function Footer() {
{/* Contact */} {/* Contact */}
<div> <div>
<div className="flex items-center gap-2 mb-4"> <div className="mb-4 flex items-center gap-2 text-xs uppercase tracking-[0.4em] text-white/55">
<span className="text-white"></span> <span className="inline-flex h-2 w-2 rounded-full bg-white/40" /> Contact
<h4 className="text-white font-medium tracking-wide text-lg">CONTACT</h4>
</div> </div>
<Link <Link
href="mailto:info@united-tattoo.com" href="mailto:info@united-tattoo.com"
className="text-gray-400 hover:text-white transition-colors duration-200 underline text-base" className="text-sm text-white/65 underline transition-colors duration-200 hover:text-white"
> >
INFO@UNITED-TATTOO.COM INFO@UNITED-TATTOO.COM
</Link> </Link>
@ -195,9 +201,9 @@ export function Footer() {
</div> </div>
</div> </div>
<div className="flex justify-end mt-8 gap-2"> <div className="mt-10 flex justify-end gap-2">
<div className="w-3 h-3 rounded-full bg-gray-400"></div> <div className="h-2 w-2 rounded-full bg-white/25" />
<div className="w-3 h-3 rounded-full bg-white"></div> <div className="h-2 w-2 rounded-full bg-white/60" />
</div> </div>
</div> </div>
</footer> </footer>

View File

@ -1,6 +1,8 @@
"use client" "use client"
import { useEffect, useState } from "react" import { useEffect, useState } from "react"
import Link from "next/link"
import Image from "next/image"
import { useFeatureFlag } from "@/components/feature-flags-provider" import { useFeatureFlag } from "@/components/feature-flags-provider"
import { Button } from "@/components/ui/button" import { Button } from "@/components/ui/button"
@ -12,79 +14,160 @@ export function HeroSection() {
const advancedNavAnimations = useFeatureFlag("ADVANCED_NAV_SCROLL_ANIMATIONS_ENABLED") const advancedNavAnimations = useFeatureFlag("ADVANCED_NAV_SCROLL_ANIMATIONS_ENABLED")
const reducedMotion = useReducedMotion() const reducedMotion = useReducedMotion()
// Use new parallax system with proper accessibility support
const parallax = useMultiLayerParallax(!advancedNavAnimations || reducedMotion) const parallax = useMultiLayerParallax(!advancedNavAnimations || reducedMotion)
useEffect(() => { useEffect(() => {
const timer = setTimeout(() => setIsVisible(true), 300) const timer = setTimeout(() => setIsVisible(true), 240)
return () => clearTimeout(timer) return () => clearTimeout(timer)
}, []) }, [])
return ( return (
<section <section
id="home" id="home"
className="min-h-screen flex items-center justify-center relative overflow-hidden" className="relative flex min-h-[110vh] items-center justify-center overflow-hidden px-6 pb-24 pt-32 sm:px-10 lg:pt-44"
data-reduced-motion={reducedMotion} data-reduced-motion={reducedMotion}
> >
{/* Background Layer - Slowest parallax */}
<div <div
ref={parallax.background.ref} ref={parallax.background.ref}
className="absolute inset-0 bg-cover bg-center bg-no-repeat will-change-transform" className="pointer-events-none absolute inset-0 will-change-transform"
style={{ style={{
backgroundImage: "url(/united-logo-full.jpg)", backgroundImage:
"image-set(url('/assets/liberty/hero-statue-collage.avif') type('image/avif'), url('/assets/liberty/hero-statue-collage.webp') type('image/webp'))",
backgroundPosition: "center top",
backgroundSize: "cover",
mixBlendMode: "soft-light",
opacity: 0.35,
...parallax.background.style, ...parallax.background.style,
}} }}
aria-hidden="true" aria-hidden="true"
/> />
{/* Midground Layer - Overlay with subtle parallax */}
<div <div
ref={parallax.midground.ref} ref={parallax.midground.ref}
className="absolute inset-0 bg-black/70 will-change-transform" className="absolute inset-0 bg-[radial-gradient(circle_at_20%_10%,rgba(255,255,255,0.14),transparent_52%),linear-gradient(115deg,rgba(18,14,12,0.86)_18%,rgba(18,14,12,0.62)_48%,rgba(18,14,12,0)_100%)] will-change-transform"
style={parallax.midground.style} style={parallax.midground.style}
aria-hidden="true" aria-hidden="true"
/> />
{/* Foreground Layer - Content with slight counter-parallax */}
<div <div
ref={parallax.foreground.ref} ref={parallax.foreground.ref}
className="relative z-10 text-center max-w-4xl px-8 will-change-transform" className="relative z-10 w-full will-change-transform"
style={parallax.foreground.style} style={parallax.foreground.style}
> >
<div <div className="mx-auto flex max-w-6xl flex-col gap-14 lg:grid lg:grid-cols-[minmax(0,0.95fr)_minmax(0,1.1fr)] lg:items-center">
className={cn( <div
"transition-all duration-1000", className={cn(
isVisible ? "opacity-100 translate-y-0" : "opacity-0 translate-y-8" "relative space-y-8 text-left text-white transition-all duration-1000",
)} isVisible ? "opacity-100 translate-y-0" : "translate-y-8 opacity-0"
> )}
<h1 className="font-playfair text-5xl lg:text-7xl font-bold text-white mb-6 tracking-tight">
UNITED TATTOO
</h1>
</div>
<div
className={cn(
"transition-all duration-1000 delay-300",
isVisible ? "opacity-100 translate-y-0" : "opacity-0 translate-y-8"
)}
>
<p className="text-xl lg:text-2xl text-gray-200 mb-12 font-light leading-relaxed">
Custom Tattoos in Fountain, Colorado
</p>
</div>
<div
className={cn(
"transition-all duration-1000 delay-500",
isVisible ? "opacity-100 translate-y-0" : "opacity-0 translate-y-8"
)}
>
<Button
size="lg"
className="bg-gray-50 text-gray-900 hover:bg-gray-100 px-8 py-4 text-lg font-medium rounded-lg w-full sm:w-auto transition-colors"
> >
Book Consultation <span className="inline-flex items-center gap-3 text-[0.7rem] font-semibold uppercase tracking-[0.6em] text-white/60">
</Button> <span className="h-[1px] w-10 bg-white/40" /> Fountain, Colorado
</span>
<div className="space-y-4">
<h1 className="font-playfair text-4xl leading-[1.1] tracking-tight sm:text-5xl lg:text-[4.2rem]">
A Studio of Ritual, Craft, and Skin Stories
</h1>
<p className="max-w-xl text-base leading-relaxed text-white/70 sm:text-lg">
United Tattoo is a sanctuary for custom workwhere layered narratives, sculptural light, and precise linework
merge into living art. Appointments are curated with intention, calm focus, and a love of experimentation.
</p>
</div>
<div className="flex flex-col gap-6 pt-6 md:flex-row md:items-center">
<Button
asChild
className="group relative w-full overflow-hidden rounded-full bg-white/90 px-8 py-4 text-xs font-semibold uppercase tracking-[0.4em] text-[#1c1713] transition-all duration-300 hover:bg-white md:w-auto"
>
<Link href="/book">
<span className="flex items-center gap-3">
Secure Consultation
<span className="h-[1px] w-6 bg-[#1c1713] transition-transform duration-300 group-hover:w-10" />
</span>
</Link>
</Button>
<Button
variant="ghost"
asChild
className="w-full justify-start rounded-full border border-white/15 bg-white/5 px-6 py-4 text-xs font-semibold uppercase tracking-[0.32em] text-white/80 backdrop-blur md:w-auto"
>
<Link href="#artists">View the Artists</Link>
</Button>
</div>
<div className="grid gap-4 pt-4 text-xs uppercase tracking-[0.32em] text-white/55 sm:grid-cols-2">
<div className="rounded-2xl border border-white/10 bg-[rgba(255,255,255,0.06)] p-5">
<p className="text-[0.65rem] font-semibold text-white/60">Studio Rhythm</p>
<p className="mt-3 text-sm tracking-[0.2em] text-white">Appointment-Only Sessions</p>
<p className="mt-2 text-[0.68rem] leading-relaxed tracking-[0.3em] text-white/45">
Design consultations Flash drops Artist residencies
</p>
</div>
<div className="rounded-2xl border border-white/10 bg-[rgba(255,255,255,0.04)] p-5">
<p className="text-[0.65rem] font-semibold text-white/60">Focus</p>
<p className="mt-3 text-sm tracking-[0.2em] text-white">Layered Custom Work</p>
<p className="mt-2 text-[0.68rem] leading-relaxed tracking-[0.3em] text-white/45">
Black & grey realism Neo-traditional Fine line botanical
</p>
</div>
</div>
</div>
<div className="relative mx-auto flex w-full max-w-[520px] justify-center lg:justify-end">
<div className="relative aspect-[4/5] w-full">
<div className="absolute -inset-6 rounded-[32px] border border-white/12 bg-white/10 backdrop-blur-[2px]" aria-hidden="true" />
<div className="absolute -inset-x-10 -top-10 h-[140px] rounded-full bg-[radial-gradient(circle,rgba(255,255,255,0.08),transparent_65%)]" aria-hidden="true" />
<div className="absolute -right-10 top-16 hidden h-36 w-36 rounded-full border border-white/10 backdrop-blur-sm lg:block" aria-hidden="true">
<div className="absolute inset-3 rounded-full border border-white/10" />
</div>
<figure
className={cn(
"relative h-full w-full overflow-hidden rounded-[28px] border border-white/14 bg-black/40",
isVisible ? "shadow-[0_45px_90px_-40px_rgba(0,0,0,0.9)]" : ""
)}
>
<Image
src="/assets/liberty/hero-statue-collage.webp"
alt="Sculptural collage with the Statue of Liberty and tattoo studio elements"
fill
sizes="(min-width: 1024px) 520px, 90vw"
priority
className="object-cover object-center"
/>
<div className="absolute inset-0 bg-gradient-to-t from-[#0b0907]/70 via-transparent to-transparent" />
</figure>
<div className="absolute -bottom-10 left-[-18%] hidden w-[220px] rounded-[26px] border border-white/12 bg-white/8 p-4 text-[0.65rem] uppercase tracking-[0.32em] text-white/70 backdrop-blur-md lg:block">
<p>United Tattoo Collective</p>
<p className="mt-2 text-[0.55rem] leading-[1.8] text-white/45">
Sculptural light. Ritual care. Art that endures.
</p>
</div>
<figure className="absolute -top-10 left-[-15%] hidden w-40 rotate-[-6deg] overflow-hidden rounded-3xl border border-white/15 bg-white/10 shadow-[0_35px_60px_-30px_rgba(0,0,0,0.7)] backdrop-blur md:block">
<Image
src="/assets/liberty/dove-tableau-close.webp"
alt="Still life of studio textures with a dove"
width={320}
height={420}
className="h-full w-full object-cover"
loading="lazy"
/>
</figure>
<figure className="absolute -right-16 bottom-16 hidden w-32 rotate-[5deg] overflow-hidden rounded-3xl border border-white/15 bg-white/10 shadow-[0_25px_45px_-25px_rgba(0,0,0,0.7)] backdrop-blur sm:block">
<Image
src="/assets/liberty/palette-brush-liberty.webp"
alt="Color palette with statue illustration"
width={260}
height={320}
className="h-full w-full object-cover"
loading="lazy"
/>
</figure>
</div>
</div>
</div> </div>
</div> </div>
</section> </section>

View File

@ -124,30 +124,38 @@ export function Navigation() {
className={cn( className={cn(
"fixed top-0 left-0 right-0 z-50 transition-all duration-700 ease-out", "fixed top-0 left-0 right-0 z-50 transition-all duration-700 ease-out",
isScrolled isScrolled
? "bg-black/95 backdrop-blur-md shadow-lg border-b border-white/10 opacity-100" ? "backdrop-blur-md bg-[rgba(20,18,16,0.92)] border-b border-white/10 shadow-[0_12px_40px_-20px_rgba(0,0,0,0.8)]"
: "bg-transparent backdrop-blur-none opacity-100", : "bg-transparent"
)} )}
> >
<div className="max-w-[1800px] mx-auto px-6 lg:px-10"> <div className="relative mx-auto max-w-[1600px] px-5 sm:px-8">
<div className="flex items-center justify-between h-20"> <div
aria-hidden="true"
className={cn(
"pointer-events-none absolute inset-x-3 -top-4 h-[130px] rounded-3xl border border-white/10 transition-opacity duration-700",
"before:absolute before:inset-0 before:rounded-3xl before:bg-[linear-gradient(130deg,rgba(255,255,255,0.16)_0%,rgba(255,255,255,0.02)_55%,rgba(10,10,10,0.35)_100%)] before:opacity-90",
"after:absolute after:inset-0 after:rounded-3xl after:bg-[url('/assets/liberty/sketch-blue-etching.webp')] after:bg-cover after:bg-center after:opacity-10",
isScrolled ? "opacity-100" : "opacity-80"
)}
/>
<div className="relative flex h-[90px] items-center justify-between gap-3">
<Link <Link
href="/" href="/"
className="flex flex-col items-start transition-all duration-500 text-white group" className="group relative flex flex-col items-start text-white transition-colors duration-500"
> >
<span className="font-bold text-2xl lg:text-3xl tracking-[0.15em] leading-none"> <span className="font-playfair text-[1.8rem] uppercase tracking-[0.28em] sm:text-[2.1rem]">
UNITED United
</span>
<span className="mt-1 flex items-center gap-3 text-[0.65rem] font-semibold uppercase tracking-[0.4em] text-white/70">
<span className="h-px w-9 bg-white/60 transition-all duration-500 group-hover:w-12" />
Tattoo Studio
</span> </span>
<div className="flex items-center gap-2 mt-1">
<span className="h-px w-10 bg-white"></span>
<span className="text-xs lg:text-sm font-medium tracking-[0.2em] uppercase">
TATTOO
</span>
</div>
</Link> </Link>
<div className="hidden lg:flex items-center flex-1 justify-between ml-16"> <div className="hidden flex-1 items-center justify-end gap-12 text-white lg:flex">
<NavigationMenu viewport={false} className="flex-initial items-center bg-transparent text-white"> <NavigationMenu viewport={false} className="flex flex-1 justify-end">
<NavigationMenuList className="flex items-center gap-8"> <NavigationMenuList className="flex items-center gap-8 xl:gap-10">
{navItems {navItems
.filter((item) => !item.isButton) .filter((item) => !item.isButton)
.map((item) => { .map((item) => {
@ -159,12 +167,21 @@ export function Navigation() {
asChild asChild
data-active={isActive || undefined} data-active={isActive || undefined}
className={cn( className={cn(
"group relative inline-flex h-auto bg-transparent px-0 py-1 text-sm font-semibold tracking-[0.15em] uppercase transition-all duration-300", "relative inline-flex items-center text-[0.72rem] font-semibold uppercase tracking-[0.42em] text-white/60 transition-colors duration-300",
"text-white/90 hover:bg-transparent hover:text-white focus:bg-transparent focus:text-white", "group hover:text-white focus-visible:text-white",
isActive && "text-white", isActive && "text-white"
)} )}
> >
<Link href={item.href}>{item.label}</Link> <Link href={item.href} className="px-1 py-1">
{item.label}
<span
className={cn(
"pointer-events-none absolute inset-x-0 -bottom-2 h-[1px] origin-left scale-x-0 bg-white/70 transition-transform duration-300",
isActive && "scale-x-100",
"group-hover:scale-x-100"
)}
/>
</Link>
</NavigationMenuLink> </NavigationMenuLink>
</NavigationMenuItem> </NavigationMenuItem>
) )
@ -175,79 +192,75 @@ export function Navigation() {
<Button <Button
asChild asChild
className={cn( className={cn(
"px-8 py-3 text-sm font-semibold tracking-[0.1em] uppercase transition-all duration-300 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/70 focus-visible:ring-offset-0 hover:scale-105 group", "group relative overflow-hidden rounded-full px-8 py-3 text-xs font-semibold uppercase tracking-[0.36em] transition-all duration-300",
isScrolled "bg-white/90 text-[#1c1713] shadow-[0_10px_40px_rgba(0,0,0,0.22)] hover:bg-white"
? "bg-white text-black hover:bg-gray-100 shadow-xl hover:shadow-2xl"
: "border border-white/80 bg-transparent text-white shadow-none hover:bg-white/10",
)} )}
> >
<Link href="/book" className="flex items-center gap-2"> <Link href="/book" className="flex items-center gap-2">
<span>Book Now</span> <span>Book Now</span>
<ArrowUpRight className="h-4 w-4 transition-transform duration-300 group-hover:translate-x-0.5 group-hover:-translate-y-0.5" /> <ArrowUpRight className="h-4 w-4 -translate-y-[1px] transition-transform duration-300 group-hover:translate-x-1 group-hover:-translate-y-1" />
</Link> </Link>
</Button> </Button>
</div> </div>
<button <button
className="lg:hidden p-4 rounded-lg transition-all duration-300 text-white hover:bg-white/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/70 focus-visible:ring-offset-0" className="relative inline-flex rounded-full border border-white/20 p-3 text-white transition-all duration-300 hover:border-white/40 lg:hidden"
onClick={handleToggleMenu} onClick={handleToggleMenu}
aria-label="Toggle menu" aria-label="Toggle menu"
> >
{isOpen ? <X size={24} /> : <Menu size={24} />} {isOpen ? <X size={22} /> : <Menu size={22} />}
</button> </button>
</div> </div>
{isOpen && ( {isOpen && (
<div className="lg:hidden bg-black/98 backdrop-blur-md border-t border-white/10"> <div className="relative z-10 mt-1 overflow-hidden rounded-3xl border border-white/10 bg-[rgba(21,19,16,0.96)] px-6 py-8 shadow-[0_35px_60px_-30px_rgba(0,0,0,0.65)] lg:hidden">
<div className="px-6 py-8 space-y-5"> <NavigationMenu viewport={false} className="w-full">
<NavigationMenu viewport={false} className="w-full"> <NavigationMenuList className="flex w-full flex-col gap-4">
<NavigationMenuList className="flex w-full flex-col space-y-3"> {navItems.map((item) => {
{navItems.map((item) => { const isActive = !item.isButton && activeSection === item.id
const isActive = !item.isButton && activeSection === item.id
if (item.isButton) {
return (
<NavigationMenuItem key={item.id} className="w-full">
<Button
asChild
className="w-full bg-white hover:bg-gray-100 text-black py-5 text-lg font-semibold tracking-[0.05em] uppercase shadow-xl mt-8"
>
<Link href={item.href} onClick={handleCloseMenu}>
{item.label}
</Link>
</Button>
</NavigationMenuItem>
)
}
if (item.isButton) {
return ( return (
<NavigationMenuItem key={item.id} className="w-full"> <NavigationMenuItem key={item.id} className="w-full pt-4">
<NavigationMenuLink <Button
asChild asChild
data-active={isActive || undefined} className="w-full rounded-full bg-white/90 py-4 text-sm font-semibold uppercase tracking-[0.32em] text-[#1c1713] shadow-[0_20px_45px_-25px_rgba(255,255,255,0.9)] hover:bg-white"
className={cn(
"block w-full rounded-md px-4 py-4 text-lg font-semibold tracking-[0.1em] uppercase transition-all duration-300",
isActive
? "border-l-4 border-white pl-6 text-white"
: "text-white/70 hover:text-white hover:pl-5 focus:text-white focus:pl-5",
)}
> >
<Link <Link href={item.href} onClick={handleCloseMenu}>
href={item.href}
onClick={(event) => {
handleNavClick(event, item)
handleCloseMenu()
}}
>
{item.label} {item.label}
</Link> </Link>
</NavigationMenuLink> </Button>
</NavigationMenuItem> </NavigationMenuItem>
) )
})} }
</NavigationMenuList>
</NavigationMenu> return (
</div> <NavigationMenuItem key={item.id} className="w-full">
<NavigationMenuLink
asChild
data-active={isActive || undefined}
className={cn(
"block w-full rounded-2xl border border-transparent px-4 py-4 text-sm font-semibold uppercase tracking-[0.3em] text-white/70 transition-all duration-300",
isActive
? "border-white/20 bg-white/5 text-white"
: "hover:border-white/10 hover:bg-white/5 hover:text-white"
)}
>
<Link
href={item.href}
onClick={(event) => {
handleNavClick(event, item)
handleCloseMenu()
}}
>
{item.label}
</Link>
</NavigationMenuLink>
</NavigationMenuItem>
)
})}
</NavigationMenuList>
</NavigationMenu>
</div> </div>
)} )}
</div> </div>

View File

@ -69,55 +69,58 @@ export function ServicesSection() {
}, []) }, [])
return ( return (
<section ref={sectionRef} id="services" className="min-h-screen relative"> <section ref={sectionRef} id="services" className="relative min-h-screen bg-[#0c0907]">
<div className="absolute inset-x-0 top-0 h-16 bg-black rounded-b-[100px]"></div> <div className="pointer-events-none absolute inset-x-0 top-0 h-24 bg-[linear-gradient(180deg,rgba(12,9,7,0)_0%,rgba(12,9,7,0.85)_45%,rgba(12,9,7,1)_100%)]" />
<div className="absolute inset-x-0 bottom-0 h-16 bg-black rounded-t-[100px]"></div> <div className="pointer-events-none absolute inset-x-0 bottom-0 h-32 bg-[linear-gradient(0deg,rgba(12,9,7,0)_0%,rgba(12,9,7,0.92)_70%,rgba(12,9,7,1)_100%)]" />
<div className="bg-white py-20 px-8 lg:px-16 relative z-10"> <div className="relative z-10 bg-[#f4efe6] px-8 py-20 shadow-[0_45px_90px_-40px_rgba(0,0,0,0.55)] lg:px-16">
<div className="max-w-screen-2xl mx-auto"> <div className="mx-auto max-w-screen-2xl">
<div className="grid lg:grid-cols-2 gap-16 items-center"> <div className="grid gap-16 lg:grid-cols-2 lg:items-center">
<div className="relative"> <div className="relative">
<div className="absolute -left-4 top-0 w-1 h-32 bg-black/10"></div> <div className="absolute -left-6 top-0 hidden h-32 w-1 bg-[#b9a18d]/40 lg:block" />
<div className="mb-8"> <div className="mb-6">
<span className="text-sm font-medium tracking-widest text-black/90 uppercase">What We Offer</span> <span className="text-xs font-semibold uppercase tracking-[0.6em] text-[#6d5b4a]">What We Offer</span>
</div> </div>
<h2 className="text-6xl lg:text-8xl font-bold tracking-tight mb-8 text-balance text-black">SERVICES</h2> <h2 className="font-playfair text-5xl tracking-tight text-[#1f1814] sm:text-6xl lg:text-[4.5rem]">
<p className="text-xl text-black/90 leading-relaxed max-w-lg"> Services
From custom designs to cover-ups, we offer comprehensive tattoo services with the highest standards of </h2>
quality and safety. <p className="mt-6 max-w-xl text-lg leading-relaxed text-[#3b3027]">
From restorative cover-ups to experimental flash, each booking is curated with layered planning, precise
execution, and a studio experience that keeps you grounded.
</p> </p>
</div> </div>
<div className="relative"> <div className="relative">
<div className="bg-black/5 h-96 rounded-2xl overflow-hidden shadow-2xl"> <div className="h-96 overflow-hidden rounded-3xl border border-[#d3c2b2]/40 bg-[#241c17] shadow-[0_50px_90px_-40px_rgba(0,0,0,0.5)]">
<img <img
src="/tattoo-equipment-and-tools.jpg" src="/tattoo-equipment-and-tools.jpg"
alt="Tattoo Equipment" alt="Tattoo Equipment"
className="w-full h-full object-cover" className="h-full w-full object-cover opacity-90"
/> />
<div className="absolute inset-0 bg-[linear-gradient(120deg,rgba(20,15,12,0.75)_10%,rgba(20,15,12,0.2)_85%)]" />
</div> </div>
<div className="absolute -bottom-4 -right-4 w-24 h-24 bg-black/5 rounded-full"></div> <div className="absolute -bottom-6 -right-8 hidden h-24 w-24 rounded-full border border-[#d3c2b2]/60 bg-[#f4efe6] shadow-[0_25px_45px_-30px_rgba(0,0,0,0.6)] md:block" />
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div className="hidden lg:block bg-black text-white relative z-10"> <div className="relative z-10 hidden bg-[#13100d] text-white lg:block">
<div className="flex"> <div className="flex items-start">
{/* Left Side - Enhanced with split composition styling */} {/* Left Side - Enhanced with split composition styling */}
<div className="w-1/2 sticky top-0 h-screen bg-black relative"> <div className="sticky top-0 h-screen w-1/2 bg-[radial-gradient(circle_at_top_left,rgba(255,255,255,0.1),transparent_60%),linear-gradient(180deg,#1d1713_0%,#110d0a_100%)]">
<div className="absolute right-0 top-0 w-px h-full bg-white/10"></div> <div className="absolute right-0 top-0 h-full w-px bg-white/10" />
<div className="h-full flex flex-col justify-center p-16 relative"> <div className="relative flex h-full flex-col justify-center p-16">
<div className="space-y-8"> <div className="space-y-8">
<div className="mb-12"> <div className="mb-12">
<div className="w-12 h-px bg-white/40 mb-6"></div> <div className="mb-6 h-px w-12 bg-white/35" />
<span className="text-sm font-medium tracking-widest text-white/60 uppercase">Our Services</span> <span className="text-sm font-semibold uppercase tracking-[0.5em] text-white/55">Our Services</span>
<h3 className="text-4xl font-bold tracking-tight mt-4 text-balance">Choose Your Style</h3> <h3 className="mt-4 font-playfair text-4xl tracking-tight text-white">Choose Your Style</h3>
</div> </div>
{services.map((service, index) => ( {services.map((service, index) => (
<div <div
key={index} key={index}
className={`transition-all duration-500 cursor-pointer group ${ className={`group cursor-pointer transition-all duration-500 ${
activeService === index ? "opacity-100" : "opacity-50 hover:opacity-75" activeService === index ? "opacity-100" : "opacity-50 hover:opacity-75"
}`} }`}
onClick={() => { onClick={() => {
@ -126,12 +129,12 @@ export function ServicesSection() {
}} }}
> >
<div <div
className={`border-l-2 pl-6 py-4 transition-all duration-300 ${ className={`border-l-[3px] py-4 pl-6 transition-all duration-300 ${
activeService === index ? "border-white" : "border-white/20 group-hover:border-white/40" activeService === index ? "border-white" : "border-white/15 group-hover:border-white/30"
}`} }`}
> >
<h4 className="text-2xl font-bold mb-2">{service.title}</h4> <h4 className="mb-2 text-2xl font-semibold tracking-wide">{service.title}</h4>
<p className="text-white/70 text-sm">{service.price}</p> <p className="text-sm text-white/60">{service.price}</p>
</div> </div>
</div> </div>
))} ))}
@ -140,22 +143,22 @@ export function ServicesSection() {
</div> </div>
{/* Right Side - Enhanced with split composition styling */} {/* Right Side - Enhanced with split composition styling */}
<div className="w-full lg:w-1/2 bg-gradient-to-b from-black to-gray-900"> <div className="w-1/2 bg-gradient-to-b from-[#15110d] via-[#110d0a] to-[#0c0907]">
{services.map((service, index) => ( {services.map((service, index) => (
<div <div
key={index} key={index}
data-service-index={index} data-service-index={index}
className="min-h-screen flex items-center justify-center p-8 lg:p-16 relative" className="relative flex min-h-screen items-center justify-center p-12"
> >
<div className="absolute left-0 top-1/2 w-px h-32 bg-white/10 -translate-y-1/2"></div> <div className="absolute left-0 top-1/2 h-32 w-px -translate-y-1/2 bg-white/10" />
<div className="max-w-lg relative"> <div className="relative max-w-lg">
<div className="mb-6"> <div className="mb-6">
<span className="text-sm font-medium tracking-widest text-white/60 uppercase"> <span className="text-xs font-semibold uppercase tracking-[0.6em] text-white/55">
Service {String(index + 1).padStart(2, "0")} Service {String(index + 1).padStart(2, "0")}
</span> </span>
</div> </div>
<h3 className="text-4xl lg:text-6xl font-bold tracking-tight mb-6 text-balance"> <h3 className="mb-6 font-playfair text-4xl tracking-tight lg:text-5xl">
{service.title.split(" ").map((word, i) => ( {service.title.split(" ").map((word, i) => (
<span key={i} className="block"> <span key={i} className="block">
{word} {word}
@ -163,26 +166,28 @@ export function ServicesSection() {
))} ))}
</h3> </h3>
<div className="space-y-6 mb-8"> <div className="mb-8 space-y-6">
<p className="text-lg text-white/80 leading-relaxed">{service.description}</p> <p className="text-base leading-relaxed text-white/75">{service.description}</p>
<div className="space-y-2"> <div className="space-y-2">
{service.features.map((feature, idx) => ( {service.features.map((feature, idx) => (
<p key={idx} className="text-white/70 flex items-center"> <p key={idx} className="flex items-center text-white/60">
<span className="w-1 h-1 bg-white/40 rounded-full mr-3"></span> <span className="mr-3 h-[2px] w-6 bg-white/30" />
{feature} {feature}
</p> </p>
))} ))}
</div> </div>
<p className="text-2xl font-bold text-white">{service.price}</p> <p className="text-xl font-semibold uppercase tracking-[0.4em] text-white/70">
{service.price}
</p>
</div> </div>
<Button <Button
asChild asChild
className="bg-white text-black hover:bg-white/90 !text-black px-8 py-4 text-lg font-medium tracking-wide transition-all duration-300 hover:scale-105" className="rounded-full border border-white/15 bg-white/90 px-8 py-4 text-xs font-semibold uppercase tracking-[0.36em] text-[#1c1713] transition-transform duration-300 hover:scale-[1.04] hover:bg-white"
> >
<Link href="/book">BOOK NOW</Link> <Link href="/book">Book Now</Link>
</Button> </Button>
<div className="mt-12"> <div className="mt-12">
@ -190,9 +195,9 @@ export function ServicesSection() {
<img <img
src={`/abstract-geometric-shapes.png?height=300&width=400&query=${service.title.toLowerCase()} tattoo example`} src={`/abstract-geometric-shapes.png?height=300&width=400&query=${service.title.toLowerCase()} tattoo example`}
alt={service.title} alt={service.title}
className="w-full max-w-sm h-auto object-cover rounded-lg shadow-2xl" className="h-auto w-full max-w-sm rounded-3xl border border-white/10 object-cover shadow-[0_35px_65px_-40px_rgba(0,0,0,0.8)]"
/> />
<div className="absolute -bottom-2 -right-2 w-16 h-16 bg-white/5 rounded-lg"></div> <div className="absolute -bottom-3 -right-3 h-16 w-16 rounded-2xl border border-white/15 bg-white/10" />
</div> </div>
</div> </div>
</div> </div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 389 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 452 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 293 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 869 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 867 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 KiB

BIN
public/new-images/0_0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 MiB

BIN
public/new-images/0_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

BIN
public/new-images/0_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
public/new-images/0_3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 MiB

BIN
public/new-images/0_4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 MiB

BIN
public/new-images/0_5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 MiB

BIN
public/new-images/0_6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 MiB

BIN
public/new-images/0_7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 MiB