2026-02-14 23:01:35 -05:00

2973 lines
108 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Kavana Home — Smarter Living, Made Simple</title>
<meta name="description" content="Premium smart home design, installation & support. NYC's heritage smart home experts since 1926.">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500&family=DM+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700&family=JetBrains+Mono:wght@300;400;500&display=swap" rel="stylesheet">
<!-- Tailwind -->
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
kavana: {
bg: '#0a0a0f',
bgAlt: '#111118',
bgCard: '#16161e',
copper: '#c4956a',
copperLight: '#d4a574',
copperDark: '#a67c55',
gold: '#e8c89e',
silver: '#8a8a9a',
text: '#f0ede8',
muted: '#7a7a8a',
glass: 'rgba(255,255,255,0.05)',
border: 'rgba(255,255,255,0.08)',
}
},
fontFamily: {
display: ['Playfair Display', 'Georgia', 'serif'],
body: ['DM Sans', 'system-ui', 'sans-serif'],
mono: ['JetBrains Mono', 'monospace'],
}
}
}
}
</script>
<!-- Lucide Icons -->
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.js"></script>
<style>
/* ========== BASE ========== */
* { margin: 0; padding: 0; box-sizing: border-box; }
::selection {
background: rgba(196, 149, 106, 0.4);
color: #f0ede8;
}
html {
scroll-behavior: auto;
}
body {
background: #0a0a0f;
color: #f0ede8;
font-family: 'DM Sans', system-ui, sans-serif;
overflow-x: hidden;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* === SMOOTH SCROLL BODY LOCK (desktop only, toggled by JS) === */
body.smooth-active {
overflow: hidden;
height: 100vh;
}
#smooth-wrapper {
will-change: transform;
}
/* === CUSTOM CURSOR (desktop) === */
@media (min-width: 768px) {
body.smooth-active, body.smooth-active * {
cursor: none !important;
}
}
#cursor-dot {
position: fixed;
top: 0; left: 0;
width: 8px; height: 8px;
background: #c4956a;
border-radius: 50%;
pointer-events: none;
z-index: 10001;
transform: translate(-50%, -50%);
transition: transform 0.1s ease;
mix-blend-mode: normal;
}
#cursor-dot.pressing {
transform: translate(-50%, -50%) scale(0.5);
}
#cursor-ring {
position: fixed;
top: 0; left: 0;
width: 40px; height: 40px;
border: 1.5px solid rgba(196,149,106,0.6);
border-radius: 50%;
pointer-events: none;
z-index: 10000;
transform: translate(-50%, -50%);
transition: width 0.3s cubic-bezier(0.16,1,0.3,1), height 0.3s cubic-bezier(0.16,1,0.3,1), background 0.3s, border-color 0.3s;
display: flex;
align-items: center;
justify-content: center;
background: transparent;
}
#cursor-ring.hovering {
width: 60px; height: 60px;
background: rgba(196,149,106,0.12);
border-color: rgba(196,149,106,0.8);
}
#cursor-ring.viewing {
width: 70px; height: 70px;
background: rgba(196,149,106,0.15);
border-color: rgba(196,149,106,0.8);
}
#cursor-ring .cursor-label {
font-family: 'JetBrains Mono', monospace;
font-size: 0.55rem;
letter-spacing: 0.1em;
text-transform: uppercase;
color: #c4956a;
opacity: 0;
transition: opacity 0.3s;
}
#cursor-ring.viewing .cursor-label {
opacity: 1;
}
/* === FILM GRAIN === */
#film-grain {
position: fixed;
inset: 0;
z-index: 9998;
pointer-events: none;
opacity: 0.035;
}
/* === SPARKLE PARTICLES === */
.sparkle {
position: fixed;
border-radius: 50%;
pointer-events: none;
z-index: 10002;
}
/* ========== LOADING SCREEN ========== */
#loader {
position: fixed;
inset: 0;
z-index: 9999;
background: #0a0a0f;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
transition: opacity 0.8s cubic-bezier(0.16, 1, 0.3, 1), visibility 0.8s;
}
#loader.hidden {
opacity: 0;
visibility: hidden;
pointer-events: none;
}
.loader-logo {
font-family: 'Playfair Display', serif;
font-size: 2.5rem;
font-weight: 600;
color: #c4956a;
letter-spacing: 0.15em;
opacity: 0;
animation: loaderFadeIn 1s 0.2s forwards;
}
.loader-bar {
width: 120px;
height: 1px;
background: rgba(196,149,106,0.2);
margin-top: 1.5rem;
border-radius: 2px;
overflow: hidden;
opacity: 0;
animation: loaderFadeIn 0.6s 0.5s forwards;
}
.loader-bar-inner {
width: 0%;
height: 100%;
background: linear-gradient(90deg, #c4956a, #d4a574);
animation: loaderProgress 1.8s 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
@keyframes loaderFadeIn { to { opacity: 1; } }
@keyframes loaderProgress { to { width: 100%; } }
/* ========== CUSTOM SCROLLBAR ========== */
::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: #0a0a0f; }
::-webkit-scrollbar-thumb { background: rgba(196,149,106,0.3); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: rgba(196,149,106,0.5); }
/* ========== CANVAS PARTICLE BG ========== */
#particleCanvas {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 0;
pointer-events: none;
}
/* ========== NAVBAR ========== */
.nav-glass {
background: rgba(10, 10, 15, 0.7);
backdrop-filter: blur(20px) saturate(1.4);
-webkit-backdrop-filter: blur(20px) saturate(1.4);
border-bottom: 1px solid rgba(255,255,255,0.06);
}
.nav-glass.scrolled {
background: rgba(10, 10, 15, 0.92);
}
.nav-link {
position: relative;
font-size: 0.8rem;
font-weight: 500;
letter-spacing: 0.08em;
text-transform: uppercase;
color: #8a8a9a;
transition: color 0.3s;
padding: 0.25rem 0;
}
.nav-link::after {
content: '';
position: absolute;
bottom: -2px;
left: 0;
width: 0;
height: 1px;
background: #c4956a;
transition: width 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}
.nav-link:hover { color: #f0ede8; }
.nav-link:hover::after { width: 100%; }
/* ========== MAGNETIC BUTTON ========== */
.magnetic-btn {
position: relative;
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.85rem 2rem;
font-family: 'DM Sans', sans-serif;
font-size: 0.8rem;
font-weight: 600;
letter-spacing: 0.1em;
text-transform: uppercase;
color: #0a0a0f;
background: linear-gradient(135deg, #c4956a, #d4a574);
border: none;
border-radius: 50px;
cursor: pointer;
overflow: hidden;
transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.4s;
z-index: 1;
text-decoration: none;
}
.magnetic-btn::before {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(135deg, #d4a574, #e8c89e);
opacity: 0;
transition: opacity 0.4s;
z-index: -1;
border-radius: 50px;
}
.magnetic-btn:hover::before { opacity: 1; }
.magnetic-btn:hover {
box-shadow: 0 8px 40px rgba(196,149,106,0.35), 0 0 80px rgba(196,149,106,0.1);
}
.magnetic-btn .ripple {
position: absolute;
border-radius: 50%;
background: rgba(255,255,255,0.3);
transform: scale(0);
animation: ripple 0.6s linear;
pointer-events: none;
}
@keyframes ripple {
to { transform: scale(4); opacity: 0; }
}
.magnetic-btn-outline {
position: relative;
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.85rem 2rem;
font-family: 'DM Sans', sans-serif;
font-size: 0.8rem;
font-weight: 600;
letter-spacing: 0.1em;
text-transform: uppercase;
color: #c4956a;
background: transparent;
border: 1px solid rgba(196,149,106,0.4);
border-radius: 50px;
cursor: pointer;
transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1);
text-decoration: none;
}
.magnetic-btn-outline:hover {
background: rgba(196,149,106,0.1);
border-color: #c4956a;
box-shadow: 0 0 30px rgba(196,149,106,0.15);
}
/* ========== HERO ========== */
.hero-section {
position: relative;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
perspective: 1000px;
}
.hero-bg {
position: absolute;
inset: 0;
z-index: 0;
}
.hero-bg img {
width: 100%;
height: 100%;
object-fit: cover;
opacity: 0.25;
filter: brightness(0.5) saturate(0.7);
transform: scale(1.1);
will-change: transform;
}
.hero-gradient {
position: absolute;
inset: 0;
background:
radial-gradient(ellipse 80% 60% at 50% 40%, rgba(196,149,106,0.08) 0%, transparent 60%),
linear-gradient(to bottom, rgba(10,10,15,0.3) 0%, rgba(10,10,15,0.7) 50%, #0a0a0f 100%);
z-index: 1;
}
.hero-depth-layer {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
will-change: transform;
transform-style: preserve-3d;
}
.hero-orb {
position: absolute;
border-radius: 50%;
filter: blur(80px);
opacity: 0.15;
animation: float 20s infinite ease-in-out;
}
.hero-orb-1 {
width: 500px; height: 500px;
background: radial-gradient(circle, #c4956a, transparent);
top: 10%; right: -10%;
}
.hero-orb-2 {
width: 400px; height: 400px;
background: radial-gradient(circle, #4a6cf7, transparent);
bottom: 10%; left: -5%;
animation-delay: -7s;
}
.hero-orb-3 {
width: 300px; height: 300px;
background: radial-gradient(circle, #d4a574, transparent);
top: 50%; left: 30%;
animation-delay: -14s;
}
@keyframes float {
0%, 100% { transform: translate(0, 0) scale(1); }
25% { transform: translate(30px, -40px) scale(1.05); }
50% { transform: translate(-20px, 20px) scale(0.95); }
75% { transform: translate(40px, 30px) scale(1.02); }
}
.hero-grid {
position: absolute;
inset: 0;
background-image:
linear-gradient(rgba(255,255,255,0.015) 1px, transparent 1px),
linear-gradient(90deg, rgba(255,255,255,0.015) 1px, transparent 1px);
background-size: 60px 60px;
z-index: 2;
mask-image: radial-gradient(ellipse 60% 50% at 50% 50%, black 30%, transparent 70%);
-webkit-mask-image: radial-gradient(ellipse 60% 50% at 50% 50%, black 30%, transparent 70%);
}
.hero-lines {
position: absolute;
inset: 0;
z-index: 2;
overflow: hidden;
opacity: 0.08;
}
.hero-line {
position: absolute;
width: 1px;
background: linear-gradient(to bottom, transparent, #c4956a, transparent);
animation: heroLine 8s infinite linear;
}
@keyframes heroLine {
0% { transform: translateY(-100%); }
100% { transform: translateY(100vh); }
}
.hero-content {
position: relative;
z-index: 10;
text-align: center;
max-width: 900px;
padding: 0 1.5rem;
will-change: transform;
}
.hero-badge {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.4rem 1.2rem;
border: 1px solid rgba(196,149,106,0.25);
border-radius: 50px;
font-family: 'JetBrains Mono', monospace;
font-size: 0.65rem;
font-weight: 400;
letter-spacing: 0.15em;
text-transform: uppercase;
color: #c4956a;
background: rgba(196,149,106,0.05);
margin-bottom: 2rem;
opacity: 0;
transform: translateY(20px);
animation: heroReveal 1s 2.8s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
.hero-badge-dot {
width: 6px; height: 6px;
border-radius: 50%;
background: #c4956a;
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.3; }
}
.hero-title {
font-family: 'Playfair Display', serif;
font-size: clamp(2.8rem, 7vw, 5.5rem);
font-weight: 500;
line-height: 1.1;
letter-spacing: -0.02em;
margin-bottom: 1.5rem;
color: #f0ede8;
}
.hero-title .word {
display: inline-block;
opacity: 0;
transform: translateY(60px) rotateX(-15deg);
animation: heroWordReveal 1s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
.hero-title .word-accent {
background: linear-gradient(135deg, #c4956a, #e8c89e);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
@keyframes heroWordReveal {
to { opacity: 1; transform: translateY(0) rotateX(0); }
}
.hero-subtitle {
font-size: clamp(1rem, 2vw, 1.25rem);
font-weight: 300;
line-height: 1.7;
color: #8a8a9a;
max-width: 560px;
margin: 0 auto 2.5rem;
opacity: 0;
transform: translateY(30px);
animation: heroReveal 1s 3.1s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
@keyframes heroReveal {
to { opacity: 1; transform: translateY(0); }
}
.hero-cta-group {
display: flex;
align-items: center;
justify-content: center;
gap: 1rem;
flex-wrap: wrap;
opacity: 0;
transform: translateY(30px);
animation: heroReveal 1s 3.4s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
.hero-scroll-indicator {
position: absolute;
bottom: 2rem;
left: 50%;
transform: translateX(-50%);
z-index: 10;
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
opacity: 0;
animation: heroReveal 1s 3.8s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
.scroll-line {
width: 1px; height: 40px;
background: linear-gradient(to bottom, #c4956a, transparent);
animation: scrollPulse 2s infinite;
}
@keyframes scrollPulse {
0%, 100% { opacity: 0.3; transform: scaleY(1); }
50% { opacity: 1; transform: scaleY(1.2); }
}
.scroll-text {
font-family: 'JetBrains Mono', monospace;
font-size: 0.6rem;
letter-spacing: 0.2em;
text-transform: uppercase;
color: #7a7a8a;
}
/* ========== SCROLL-DRIVEN TEXT FILL ========== */
.scroll-fill-text {
font-family: 'Playfair Display', serif;
font-size: clamp(2rem, 4.5vw, 3.5rem);
font-weight: 500;
line-height: 1.15;
letter-spacing: -0.01em;
color: transparent;
-webkit-text-stroke: 1.5px rgba(196,149,106,0.25);
background: linear-gradient(90deg, #c4956a 0%, #e8c89e 40%, rgba(196,149,106,0.25) 40.1%, rgba(196,149,106,0.25) 100%);
background-size: 250% 100%;
background-position: 100% 0;
-webkit-background-clip: text;
background-clip: text;
transition: none;
}
.scroll-fill-text.filled {
-webkit-text-stroke: 0px transparent;
}
/* ========== KINETIC TYPOGRAPHY ========== */
.kinetic-word {
display: inline-block;
transition: transform 0.08s linear, filter 0.08s linear, letter-spacing 0.08s linear;
will-change: transform, filter;
}
.kinetic-char {
display: inline-block;
transition: transform 0.05s linear;
will-change: transform;
}
/* ========== SECTION STYLES ========== */
.section-label {
font-family: 'JetBrains Mono', monospace;
font-size: 0.7rem;
font-weight: 400;
letter-spacing: 0.2em;
text-transform: uppercase;
color: #c4956a;
margin-bottom: 1rem;
display: flex;
align-items: center;
gap: 0.75rem;
}
.section-label::before {
content: '';
width: 30px; height: 1px;
background: #c4956a;
}
.section-title {
font-family: 'Playfair Display', serif;
font-size: clamp(2rem, 4.5vw, 3.5rem);
font-weight: 500;
line-height: 1.15;
letter-spacing: -0.01em;
color: #f0ede8;
margin-bottom: 1rem;
}
.section-desc {
font-size: 1.05rem;
font-weight: 300;
line-height: 1.7;
color: #7a7a8a;
max-width: 550px;
}
/* ========== CLIP-PATH SECTION REVEALS ========== */
.clip-reveal-section {
clip-path: circle(0% at 50% 50%);
transition: clip-path 0s;
will-change: clip-path;
}
.clip-reveal-section.revealed {
clip-path: circle(150% at 50% 50%);
}
/* ========== SCROLL REVEAL ========== */
.reveal {
opacity: 0;
transform: translateY(40px);
transition: opacity 0.8s cubic-bezier(0.16, 1, 0.3, 1), transform 0.8s cubic-bezier(0.16, 1, 0.3, 1);
}
.reveal.visible {
opacity: 1;
transform: translateY(0);
}
.reveal-left {
opacity: 0;
transform: translateX(-50px);
transition: opacity 0.8s cubic-bezier(0.16, 1, 0.3, 1), transform 0.8s cubic-bezier(0.16, 1, 0.3, 1);
}
.reveal-left.visible {
opacity: 1;
transform: translateX(0);
}
.reveal-right {
opacity: 0;
transform: translateX(50px);
transition: opacity 0.8s cubic-bezier(0.16, 1, 0.3, 1), transform 0.8s cubic-bezier(0.16, 1, 0.3, 1);
}
.reveal-right.visible {
opacity: 1;
transform: translateX(0);
}
.reveal-scale {
opacity: 0;
transform: scale(0.92);
transition: opacity 0.8s cubic-bezier(0.16, 1, 0.3, 1), transform 0.8s cubic-bezier(0.16, 1, 0.3, 1);
}
.reveal-scale.visible {
opacity: 1;
transform: scale(1);
}
.stagger-1 { transition-delay: 0.1s; }
.stagger-2 { transition-delay: 0.2s; }
.stagger-3 { transition-delay: 0.3s; }
.stagger-4 { transition-delay: 0.4s; }
.stagger-5 { transition-delay: 0.5s; }
.stagger-6 { transition-delay: 0.6s; }
.stagger-7 { transition-delay: 0.7s; }
/* ========== VALUES / PILLARS ========== */
.pillar-card {
position: relative;
padding: 2.5rem;
background: rgba(255,255,255,0.02);
border: 1px solid rgba(255,255,255,0.06);
border-radius: 20px;
transition: all 0.5s cubic-bezier(0.16, 1, 0.3, 1);
overflow: hidden;
}
.pillar-card::before {
content: '';
position: absolute;
top: 0; left: 0; right: 0;
height: 1px;
background: linear-gradient(90deg, transparent, rgba(196,149,106,0.3), transparent);
opacity: 0;
transition: opacity 0.5s;
}
.pillar-card:hover {
background: rgba(255,255,255,0.04);
border-color: rgba(196,149,106,0.15);
transform: translateY(-5px);
}
.pillar-card:hover::before { opacity: 1; }
.pillar-icon {
width: 48px; height: 48px;
border-radius: 14px;
background: rgba(196,149,106,0.1);
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 1.5rem;
color: #c4956a;
}
.pillar-number {
font-family: 'JetBrains Mono', monospace;
font-size: 0.65rem;
color: rgba(196,149,106,0.4);
letter-spacing: 0.1em;
margin-bottom: 0.75rem;
}
/* ========== MORPH SECTION ========== */
.morph-section-wrapper {
position: relative;
height: 300vh;
}
.morph-section-sticky {
position: sticky;
top: 0;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.morph-value {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
transition: opacity 0.6s cubic-bezier(0.16, 1, 0.3, 1);
padding: 2rem;
}
.morph-value.active { opacity: 1; }
.morph-value-inner {
text-align: center;
max-width: 600px;
}
.morph-counter {
font-family: 'JetBrains Mono', monospace;
font-size: 0.65rem;
letter-spacing: 0.2em;
color: rgba(196,149,106,0.5);
margin-bottom: 1rem;
}
.morph-progress-bar {
position: absolute;
bottom: 60px;
left: 50%;
transform: translateX(-50%);
width: 120px; height: 2px;
background: rgba(255,255,255,0.06);
border-radius: 2px;
overflow: hidden;
}
.morph-progress-fill {
height: 100%;
background: linear-gradient(90deg, #c4956a, #e8c89e);
border-radius: 2px;
transition: width 0.1s linear;
width: 0%;
}
/* ========== HORIZONTAL SCROLL SERVICES ========== */
.horiz-scroll-wrapper { position: relative; }
.horiz-scroll-sticky {
position: sticky;
top: 0;
height: 100vh;
display: flex;
align-items: center;
overflow: hidden;
}
.horiz-scroll-track {
display: flex;
gap: 2rem;
will-change: transform;
padding: 0 4rem;
}
.horiz-scroll-panel {
flex: 0 0 auto;
width: 80vw;
max-width: 500px;
min-height: 420px;
padding: 3rem;
background: rgba(255,255,255,0.03);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border: 1px solid rgba(255,255,255,0.06);
border-radius: 24px;
display: flex;
flex-direction: column;
justify-content: space-between;
transition: border-color 0.4s, box-shadow 0.4s;
position: relative;
overflow: hidden;
}
.horiz-scroll-panel::after {
content: '';
position: absolute;
inset: 0;
border-radius: 24px;
background: radial-gradient(circle at var(--mouse-x, 50%) var(--mouse-y, 50%), rgba(196,149,106,0.06) 0%, transparent 60%);
opacity: 0;
transition: opacity 0.5s;
pointer-events: none;
}
.horiz-scroll-panel:hover::after { opacity: 1; }
.horiz-scroll-panel:hover {
border-color: rgba(196,149,106,0.2);
box-shadow: 0 20px 60px rgba(0,0,0,0.3), 0 0 40px rgba(196,149,106,0.05);
}
.horiz-panel-icon {
width: 56px; height: 56px;
border-radius: 16px;
background: rgba(196,149,106,0.1);
display: flex;
align-items: center;
justify-content: center;
color: #c4956a;
margin-bottom: 1.5rem;
transition: all 0.4s;
}
.horiz-scroll-panel:hover .horiz-panel-icon {
background: rgba(196,149,106,0.2);
box-shadow: 0 0 20px rgba(196,149,106,0.15);
}
.horiz-scroll-counter {
position: absolute;
top: 2rem; right: 4rem;
font-family: 'JetBrains Mono', monospace;
font-size: 0.75rem;
letter-spacing: 0.15em;
color: rgba(196,149,106,0.5);
z-index: 20;
}
.horiz-scroll-header {
position: absolute;
top: 2rem; left: 4rem;
z-index: 20;
}
.horiz-scroll-dots {
position: absolute;
bottom: 2rem;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 8px;
z-index: 20;
}
.horiz-dot {
width: 8px; height: 8px;
border-radius: 50%;
background: rgba(255,255,255,0.1);
transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}
.horiz-dot.active {
background: #c4956a;
box-shadow: 0 0 10px rgba(196,149,106,0.4);
width: 24px;
border-radius: 4px;
}
@media (max-width: 767px) {
.horiz-scroll-wrapper { height: auto !important; }
.horiz-scroll-sticky {
position: relative !important;
height: auto !important;
flex-direction: column;
padding: 2rem 0;
}
.horiz-scroll-track {
flex-direction: column;
padding: 0 1.5rem;
gap: 1.25rem;
}
.horiz-scroll-panel {
width: 100%;
max-width: none;
min-height: auto;
padding: 2rem;
}
.horiz-scroll-counter,
.horiz-scroll-dots { display: none; }
.horiz-scroll-header {
position: relative;
top: auto; left: auto;
padding: 0 1.5rem;
margin-bottom: 1.5rem;
}
}
/* ========== GALLERY ========== */
.gallery-track {
display: flex;
gap: 1.25rem;
padding: 2rem 0;
cursor: grab;
user-select: none;
}
.gallery-track:active { cursor: grabbing; }
.gallery-card {
flex: 0 0 auto;
width: 220px;
padding: 1.5rem;
background: rgba(255,255,255,0.03);
border: 1px solid rgba(255,255,255,0.06);
border-radius: 16px;
text-align: center;
transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1);
transform-style: preserve-3d;
perspective: 800px;
}
.gallery-card:hover {
border-color: rgba(196,149,106,0.2);
background: rgba(255,255,255,0.05);
box-shadow: 0 15px 40px rgba(0,0,0,0.3);
}
.gallery-card-icon {
width: 56px; height: 56px;
border-radius: 16px;
background: linear-gradient(135deg, rgba(196,149,106,0.12), rgba(196,149,106,0.04));
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 1rem;
color: #c4956a;
}
/* ========== TIMELINE ========== */
.timeline-container { position: relative; }
.timeline-line {
position: absolute;
left: 50%; top: 0; bottom: 0;
width: 1px;
background: rgba(255,255,255,0.06);
transform: translateX(-50%);
}
.timeline-line-fill {
position: absolute;
left: 50%; top: 0;
width: 1px; height: 0;
background: linear-gradient(to bottom, #c4956a, rgba(196,149,106,0.3));
transform: translateX(-50%);
transition: height 0.1s linear;
}
.timeline-item {
position: relative;
display: flex;
align-items: center;
margin-bottom: 6rem;
}
.timeline-item:last-child { margin-bottom: 0; }
.timeline-dot {
position: absolute;
left: 50%;
transform: translateX(-50%);
width: 14px; height: 14px;
border-radius: 50%;
background: #0a0a0f;
border: 2px solid rgba(196,149,106,0.3);
z-index: 5;
transition: all 0.5s;
}
.timeline-item.visible .timeline-dot {
border-color: #c4956a;
box-shadow: 0 0 20px rgba(196,149,106,0.3);
background: #c4956a;
}
.timeline-year {
font-family: 'Playfair Display', serif;
font-size: clamp(2.5rem, 5vw, 4rem);
font-weight: 600;
background: linear-gradient(135deg, #c4956a, #e8c89e);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
line-height: 1;
margin-bottom: 0.5rem;
}
.timeline-era-name {
font-family: 'DM Sans', sans-serif;
font-size: 1.1rem;
font-weight: 600;
color: #f0ede8;
margin-bottom: 0.5rem;
}
/* === IMAGE COLOR-WIPE REVEAL === */
.wipe-reveal {
position: relative;
overflow: hidden;
}
.wipe-reveal::after {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(135deg, #c4956a, #d4a574);
transform: translateX(-101%);
z-index: 2;
transition: none;
}
.wipe-reveal.wiping::after {
animation: wipeAcross 0.8s cubic-bezier(0.65, 0, 0.35, 1) forwards;
}
.wipe-reveal img {
opacity: 0;
transition: none;
}
.wipe-reveal.wiping img {
animation: wipeImgReveal 0.01s 0.4s forwards;
}
@keyframes wipeAcross {
0% { transform: translateX(-101%); }
50% { transform: translateX(0%); }
100% { transform: translateX(101%); }
}
@keyframes wipeImgReveal {
to { opacity: 0.6; }
}
@media (max-width: 768px) {
.timeline-line, .timeline-line-fill { left: 1.5rem; }
.timeline-dot { left: 1.5rem; }
.timeline-item { flex-direction: column; padding-left: 3.5rem; }
.timeline-content-left, .timeline-content-right {
width: 100% !important;
text-align: left !important;
padding: 0 !important;
}
}
/* ========== PROCESS ========== */
.process-step { position: relative; text-align: center; }
.process-icon-wrap {
width: 72px; height: 72px;
border-radius: 20px;
background: rgba(255,255,255,0.03);
border: 1px solid rgba(255,255,255,0.08);
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 1.25rem;
color: #c4956a;
transition: all 0.5s;
}
.process-step.visible .process-icon-wrap {
background: rgba(196,149,106,0.1);
border-color: rgba(196,149,106,0.25);
box-shadow: 0 0 30px rgba(196,149,106,0.1);
}
.process-connector {
position: absolute;
top: 36px;
left: calc(50% + 36px);
width: calc(100% - 72px);
height: 1px;
background: rgba(255,255,255,0.06);
overflow: hidden;
}
.process-connector-fill {
width: 0%; height: 100%;
background: #c4956a;
transition: width 1s cubic-bezier(0.16, 1, 0.3, 1);
}
.process-step.visible .process-connector-fill { width: 100%; }
/* ========== TRUST / PARTNERS ========== */
.partner-badge {
display: flex;
align-items: center;
justify-content: center;
padding: 1.25rem 2rem;
background: rgba(255,255,255,0.03);
border: 1px solid rgba(255,255,255,0.06);
border-radius: 14px;
font-family: 'DM Sans', sans-serif;
font-size: 0.95rem;
font-weight: 500;
color: #8a8a9a;
transition: all 0.4s;
position: relative;
overflow: hidden;
}
.partner-badge::before {
content: '';
position: absolute;
inset: -50%;
background: linear-gradient(90deg, transparent, rgba(196,149,106,0.08), transparent);
transform: rotate(45deg);
animation: shimmer 3s infinite;
}
@keyframes shimmer {
0% { transform: rotate(45deg) translateX(-200%); }
100% { transform: rotate(45deg) translateX(200%); }
}
.partner-badge:hover {
border-color: rgba(196,149,106,0.2);
color: #f0ede8;
}
.stat-number {
font-family: 'Playfair Display', serif;
font-size: clamp(3rem, 6vw, 5rem);
font-weight: 600;
background: linear-gradient(135deg, #c4956a, #e8c89e);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
line-height: 1;
}
/* ========== CTA ========== */
.cta-section {
position: relative;
overflow: hidden;
background: linear-gradient(135deg, rgba(196,149,106,0.06) 0%, rgba(10,10,15,1) 50%, rgba(74,108,247,0.04) 100%);
}
.cta-grid-bg {
position: absolute;
inset: 0;
background-image:
linear-gradient(rgba(196,149,106,0.04) 1px, transparent 1px),
linear-gradient(90deg, rgba(196,149,106,0.04) 1px, transparent 1px);
background-size: 50px 50px;
mask-image: radial-gradient(ellipse 50% 50% at 50% 50%, black, transparent);
-webkit-mask-image: radial-gradient(ellipse 50% 50% at 50% 50%, black, transparent);
}
.cta-particles {
position: absolute;
inset: 0;
overflow: hidden;
}
.cta-particle {
position: absolute;
width: 2px; height: 2px;
background: #c4956a;
border-radius: 50%;
opacity: 0;
animation: particleFloat 6s infinite;
}
@keyframes particleFloat {
0% { opacity: 0; transform: translateY(0) scale(0); }
10% { opacity: 0.6; transform: scale(1); }
90% { opacity: 0.3; }
100% { opacity: 0; transform: translateY(-200px) scale(0); }
}
/* ========== INSURANCE ========== */
.insurance-badge {
padding: 1.5rem;
background: rgba(255,255,255,0.02);
border: 1px solid rgba(255,255,255,0.06);
border-radius: 16px;
text-align: center;
position: relative;
overflow: hidden;
transition: all 0.4s;
}
.insurance-badge:hover {
border-color: rgba(196,149,106,0.15);
background: rgba(255,255,255,0.04);
}
.insurance-badge::before {
content: '';
position: absolute;
inset: -50%;
background: linear-gradient(90deg, transparent, rgba(196,149,106,0.05), transparent);
transform: rotate(45deg);
animation: shimmer 4s infinite;
}
/* ========== FOOTER ========== */
.footer-link {
color: #7a7a8a;
font-size: 0.9rem;
transition: color 0.3s;
display: block;
padding: 0.2rem 0;
text-decoration: none;
}
.footer-link:hover { color: #c4956a; }
.newsletter-input {
background: rgba(255,255,255,0.05);
border: 1px solid rgba(255,255,255,0.1);
border-radius: 12px;
padding: 0.85rem 1.25rem;
color: #f0ede8;
font-family: 'DM Sans', sans-serif;
font-size: 0.9rem;
outline: none;
transition: all 0.4s;
width: 100%;
}
.newsletter-input:focus {
border-color: rgba(196,149,106,0.4);
box-shadow: 0 0 20px rgba(196,149,106,0.1);
background: rgba(255,255,255,0.07);
}
.newsletter-input::placeholder { color: #7a7a8a; }
/* ========== MOBILE NAV ========== */
.mobile-menu {
position: fixed;
inset: 0;
z-index: 999;
background: rgba(10,10,15,0.98);
backdrop-filter: blur(30px);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 2rem;
opacity: 0;
visibility: hidden;
transition: all 0.5s cubic-bezier(0.16, 1, 0.3, 1);
}
.mobile-menu.open { opacity: 1; visibility: visible; }
.mobile-menu a {
font-family: 'Playfair Display', serif;
font-size: 2rem;
color: #f0ede8;
text-decoration: none;
transition: color 0.3s;
}
.mobile-menu a:hover { color: #c4956a; }
.hamburger {
display: none;
flex-direction: column;
gap: 5px;
cursor: pointer;
z-index: 1001;
}
.hamburger span {
width: 24px; height: 1.5px;
background: #f0ede8;
transition: all 0.3s;
display: block;
}
.hamburger.active span:nth-child(1) { transform: rotate(45deg) translate(4px, 4px); }
.hamburger.active span:nth-child(2) { opacity: 0; }
.hamburger.active span:nth-child(3) { transform: rotate(-45deg) translate(5px, -5px); }
@media (max-width: 1024px) {
.hamburger { display: flex; }
.desktop-nav { display: none !important; }
}
/* ========== FLASHLIGHT SECTION ========== */
.flashlight-section {
position: relative;
width: 100%;
height: 100vh;
background: #000;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
}
.flashlight-bg {
position: absolute;
inset: 0;
background-image: url('https://images.unsplash.com/photo-1600210492486-724fe5c67fb0?w=1600&q=90');
background-size: cover;
background-position: center;
/* Hidden by default — revealed via mask */
-webkit-mask-image: radial-gradient(circle 0px at 50% 50%, black 80%, transparent 100%);
mask-image: radial-gradient(circle 0px at 50% 50%, black 80%, transparent 100%);
z-index: 1;
}
.flashlight-content {
position: relative;
z-index: 2;
text-align: center;
pointer-events: none;
}
.flashlight-content h2 {
font-family: 'Playfair Display', serif;
font-size: clamp(2.5rem, 5vw, 4.5rem);
font-weight: 500;
color: rgba(240, 237, 232, 0.15);
line-height: 1.15;
letter-spacing: -0.01em;
margin-bottom: 1rem;
}
.flashlight-hint {
font-family: 'JetBrains Mono', monospace;
font-size: 0.65rem;
letter-spacing: 0.15em;
text-transform: uppercase;
color: rgba(196, 149, 106, 0.4);
margin-top: 1rem;
}
@media (max-width: 767px) {
.flashlight-hint { display: none; }
}
/* ========== INFINITE MARQUEE ========== */
.marquee-section {
padding: 2.5rem 0;
overflow: hidden;
position: relative;
background: #0a0a0f;
}
.marquee-row {
display: flex;
width: max-content;
gap: 0;
}
.marquee-row-wrapper {
overflow: hidden;
-webkit-mask-image: linear-gradient(90deg, transparent, black 8%, black 92%, transparent);
mask-image: linear-gradient(90deg, transparent, black 8%, black 92%, transparent);
margin-bottom: 0.75rem;
}
.marquee-row-wrapper:last-child { margin-bottom: 0; }
.marquee-content {
display: flex;
align-items: center;
gap: 0;
animation: marqueeScroll 30s linear infinite;
white-space: nowrap;
}
.marquee-content.reverse {
animation: marqueeScrollReverse 30s linear infinite;
}
@keyframes marqueeScroll {
0% { transform: translateX(0); }
100% { transform: translateX(-50%); }
}
@keyframes marqueeScrollReverse {
0% { transform: translateX(-50%); }
100% { transform: translateX(0); }
}
.marquee-item {
font-family: 'JetBrains Mono', monospace;
font-size: 0.7rem;
font-weight: 400;
letter-spacing: 0.12em;
text-transform: uppercase;
color: rgba(196, 149, 106, 0.4);
padding: 0 1.5rem;
flex-shrink: 0;
}
.marquee-dot {
width: 3px; height: 3px;
border-radius: 50%;
background: rgba(196, 149, 106, 0.3);
flex-shrink: 0;
}
/* ========== MISC ========== */
.text-gradient {
background: linear-gradient(135deg, #c4956a, #e8c89e);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.divider {
width: 100%;
height: 1px;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.06), transparent);
}
.showroom-badge {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 1.25rem;
border: 1px solid rgba(196,149,106,0.3);
border-radius: 50px;
font-family: 'JetBrains Mono', monospace;
font-size: 0.7rem;
letter-spacing: 0.12em;
color: #c4956a;
background: rgba(196,149,106,0.05);
animation: showroomPulse 3s infinite;
}
@keyframes showroomPulse {
0%, 100% { box-shadow: 0 0 10px rgba(196,149,106,0.1); }
50% { box-shadow: 0 0 25px rgba(196,149,106,0.2); }
}
.content-wrapper {
position: relative;
z-index: 1;
}
</style>
</head>
<body>
<!-- ========== CANVAS PARTICLE BACKGROUND ========== -->
<canvas id="particleCanvas"></canvas>
<!-- ========== FILM GRAIN OVERLAY ========== -->
<canvas id="film-grain"></canvas>
<!-- ========== CUSTOM CURSOR (desktop only, created by JS) ========== -->
<div id="cursor-dot" style="display:none;"></div>
<div id="cursor-ring" style="display:none;"><span class="cursor-label">View</span></div>
<!-- ========== SPARKLE CONTAINER ========== -->
<div id="sparkle-container" style="position:fixed;inset:0;pointer-events:none;z-index:10002;overflow:hidden;"></div>
<!-- ========== LOADING SCREEN ========== -->
<div id="loader">
<div class="loader-logo">KAVANA</div>
<div class="loader-bar">
<div class="loader-bar-inner"></div>
</div>
</div>
<!-- ========== MOBILE MENU ========== -->
<div class="mobile-menu" id="mobileMenu">
<a href="#services" onclick="closeMobile()">Services</a>
<a href="#gallery" onclick="closeMobile()">Integrations</a>
<a href="#story" onclick="closeMobile()">Our Story</a>
<a href="#process" onclick="closeMobile()">Process</a>
<a href="#contact" onclick="closeMobile()">Contact</a>
</div>
<!-- ========== SMOOTH SCROLL WRAPPER ========== -->
<div id="smooth-wrapper">
<div class="content-wrapper">
<!-- ========== NAVBAR ========== -->
<nav class="nav-glass fixed top-0 left-0 right-0 z-50 transition-all duration-500" id="navbar">
<div class="max-w-7xl mx-auto px-6 lg:px-8 flex items-center justify-between h-20">
<a href="#" class="flex items-center gap-3 group">
<div class="w-9 h-9 rounded-lg bg-gradient-to-br from-kavana-copper to-kavana-copperLight flex items-center justify-center">
<span class="font-display text-kavana-bg font-bold text-lg leading-none">K</span>
</div>
<span class="font-display text-xl font-semibold tracking-wider text-kavana-text group-hover:text-kavana-copper transition-colors">KAVANA</span>
</a>
<div class="desktop-nav hidden lg:flex items-center gap-8">
<a href="#services" class="nav-link">Services</a>
<a href="#gallery" class="nav-link">Integrations</a>
<a href="#story" class="nav-link">Our Story</a>
<a href="#process" class="nav-link">Process</a>
<a href="#contact" class="nav-link">Contact</a>
</div>
<div class="flex items-center gap-4">
<a href="#contact" class="magnetic-btn hidden sm:inline-flex" id="navCta">Book Consultation</a>
<div class="hamburger" id="hamburger" onclick="toggleMobile()">
<span></span><span></span><span></span>
</div>
</div>
</div>
</nav>
<!-- ========== HERO (3D Perspective Fly-Through) ========== -->
<section class="hero-section" id="heroSection">
<div class="hero-bg hero-depth-layer" data-depth="0.3" id="heroBgLayer">
<img src="https://images.unsplash.com/photo-1600585154340-be6161a56a0c?w=1920&q=80" alt="Luxury home" id="heroBgImg" style="position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0.25;filter:brightness(0.5) saturate(0.7);transform:scale(1.1);">
</div>
<div class="hero-gradient hero-depth-layer" data-depth="0.15"></div>
<div class="hero-grid hero-depth-layer" data-depth="0.2"></div>
<div class="hero-depth-layer" data-depth="0.4" style="pointer-events:none;">
<div class="hero-orb hero-orb-1"></div>
<div class="hero-orb hero-orb-2"></div>
<div class="hero-orb hero-orb-3"></div>
</div>
<div class="hero-lines hero-depth-layer" data-depth="0.1">
<div class="hero-line" style="left:15%; height:100%; animation-duration:7s; animation-delay:0s;"></div>
<div class="hero-line" style="left:35%; height:100%; animation-duration:9s; animation-delay:2s;"></div>
<div class="hero-line" style="left:55%; height:100%; animation-duration:6s; animation-delay:4s;"></div>
<div class="hero-line" style="left:78%; height:100%; animation-duration:8s; animation-delay:1s;"></div>
<div class="hero-line" style="left:92%; height:100%; animation-duration:10s; animation-delay:3s;"></div>
</div>
<div class="hero-content" id="heroContent" data-depth="0">
<div class="hero-badge">
<span class="hero-badge-dot"></span>
NYC Showroom — Summer 2026
</div>
<h1 class="hero-title">
<span class="word" style="animation-delay:2.9s">Smarter</span>
<span class="word word-accent" style="animation-delay:3.1s">Living,</span><br>
<span class="word" style="animation-delay:3.3s">Made</span>
<span class="word" style="animation-delay:3.5s">Simple</span>
</h1>
<p class="hero-subtitle">
Premium smart home design & installation for NYC's most discerning residences. Nearly a century of craftsmanship, reimagined for the intelligent home.
</p>
<div class="hero-cta-group">
<a href="#contact" class="magnetic-btn" id="heroCta">
Book a Consultation
<i data-lucide="arrow-right" style="width:16px;height:16px;"></i>
</a>
<a href="#story" class="magnetic-btn-outline">
Our Story
<i data-lucide="play" style="width:14px;height:14px;"></i>
</a>
</div>
</div>
<div class="hero-scroll-indicator">
<div class="scroll-line"></div>
<span class="scroll-text">Scroll</span>
</div>
</section>
<!-- ========== DESIGN WITH INTENTION — SCROLL-PINNED MORPH ========== -->
<div class="morph-section-wrapper" id="morphWrapper" style="background: #0a0a0f;">
<div class="morph-section-sticky" id="morphSticky">
<div style="position:absolute;top:50%;left:50%;width:500px;height:500px;transform:translate(-50%,-50%);background:radial-gradient(circle,rgba(196,149,106,0.04),transparent 70%);pointer-events:none;"></div>
<div class="morph-value active" id="morphValue0">
<div class="morph-value-inner">
<div class="morph-counter">01 / 03</div>
<div class="section-label justify-center" style="margin-bottom:1rem;"><span>Philosophy</span></div>
<h2 class="scroll-fill-text" data-scroll-fill style="font-size:clamp(2.2rem,5vw,4rem);margin-bottom:1.5rem;">Design With Intention</h2>
<div style="margin-bottom:2rem;">
<div class="pillar-icon" style="margin:0 auto 1.25rem;"><i data-lucide="pen-tool" style="width:22px;height:22px;"></i></div>
<h3 class="font-display text-2xl font-semibold text-kavana-text mb-3">Bespoke Design</h3>
<p class="text-kavana-muted text-base leading-relaxed max-w-md mx-auto">Every home is unique. We craft custom smart home architectures that harmonize with your interior design, lifestyle, and aesthetic vision.</p>
</div>
</div>
</div>
<div class="morph-value" id="morphValue1">
<div class="morph-value-inner">
<div class="morph-counter">02 / 03</div>
<div class="section-label justify-center" style="margin-bottom:1rem;"><span>Philosophy</span></div>
<h2 class="scroll-fill-text" data-scroll-fill style="font-size:clamp(2.2rem,5vw,4rem);margin-bottom:1.5rem;">Invisible Technology</h2>
<div style="margin-bottom:2rem;">
<div class="pillar-icon" style="margin:0 auto 1.25rem;"><i data-lucide="shield-check" style="width:22px;height:22px;"></i></div>
<h3 class="font-display text-2xl font-semibold text-kavana-text mb-3">Invisible Technology</h3>
<p class="text-kavana-muted text-base leading-relaxed max-w-md mx-auto">Designed to simplify, not impress. Our installations integrate seamlessly — no clutter, no complexity, just intuitive control at your fingertips.</p>
</div>
</div>
</div>
<div class="morph-value" id="morphValue2">
<div class="morph-value-inner">
<div class="morph-counter">03 / 03</div>
<div class="section-label justify-center" style="margin-bottom:1rem;"><span>Philosophy</span></div>
<h2 class="scroll-fill-text" data-scroll-fill style="font-size:clamp(2.2rem,5vw,4rem);margin-bottom:1.5rem;">Heritage & Trust</h2>
<div style="margin-bottom:2rem;">
<div class="pillar-icon" style="margin:0 auto 1.25rem;"><i data-lucide="heart-handshake" style="width:22px;height:22px;"></i></div>
<h3 class="font-display text-2xl font-semibold text-kavana-text mb-3">Heritage & Trust</h3>
<p class="text-kavana-muted text-base leading-relaxed max-w-md mx-auto">Nearly 100 years of service in New York. From Manhattan Shade & Glass in 1926 to Kavana Home today — trust built across generations.</p>
</div>
</div>
</div>
<div class="morph-progress-bar">
<div class="morph-progress-fill" id="morphProgressFill"></div>
</div>
</div>
</div>
<div class="divider"></div>
<!-- ========== SERVICES — STICKY HORIZONTAL SCROLL ========== -->
<section id="services" style="background: #0c0c12;">
<div class="horiz-scroll-wrapper" id="horizWrapper">
<div class="horiz-scroll-sticky" id="horizSticky">
<div class="horiz-scroll-header">
<div class="section-label">Services</div>
<h2 class="font-display text-2xl font-semibold text-kavana-text" id="kineticHeading">
<span class="kinetic-word">Complete</span>
<span class="kinetic-word">Smart</span>
<span class="kinetic-word">Home</span>
<span class="kinetic-word" style="background:linear-gradient(135deg,#c4956a,#e8c89e);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;">Ecosystem</span>
</h2>
</div>
<div class="horiz-scroll-counter" id="horizCounter">01 / 07</div>
<div class="horiz-scroll-track" id="horizTrack">
<div class="horiz-scroll-panel" data-panel>
<div>
<div class="horiz-panel-icon"><i data-lucide="home" style="width:24px;height:24px;"></i></div>
<div class="font-mono text-[0.65rem] text-kavana-copper tracking-widest mb-3">01</div>
<h3 class="font-display text-2xl font-semibold text-kavana-text mb-3">Smart Home</h3>
<p class="text-kavana-muted text-sm leading-relaxed mb-4">Josh.ai voice & automation</p>
<p class="text-kavana-silver text-sm leading-relaxed">Whole-home intelligence powered by Josh.ai — the only AI built exclusively for luxury homes. Voice control, automation scenes, and predictive living.</p>
</div>
<div class="flex items-center gap-2 mt-6 text-kavana-copper text-sm font-medium"><span>Learn more</span><i data-lucide="arrow-right" style="width:14px;height:14px;"></i></div>
</div>
<div class="horiz-scroll-panel" data-panel>
<div>
<div class="horiz-panel-icon"><i data-lucide="sun" style="width:24px;height:24px;"></i></div>
<div class="font-mono text-[0.65rem] text-kavana-copper tracking-widest mb-3">02</div>
<h3 class="font-display text-2xl font-semibold text-kavana-text mb-3">Lighting</h3>
<p class="text-kavana-muted text-sm leading-relaxed mb-4">Lutron precision lighting</p>
<p class="text-kavana-silver text-sm leading-relaxed">Lutron HomeWorks & Caséta systems for perfect ambiance. Circadian tuning, scene presets, and integration with your smart home ecosystem.</p>
</div>
<div class="flex items-center gap-2 mt-6 text-kavana-copper text-sm font-medium"><span>Learn more</span><i data-lucide="arrow-right" style="width:14px;height:14px;"></i></div>
</div>
<div class="horiz-scroll-panel" data-panel>
<div>
<div class="horiz-panel-icon"><i data-lucide="blinds" style="width:24px;height:24px;"></i></div>
<div class="font-mono text-[0.65rem] text-kavana-copper tracking-widest mb-3">03</div>
<h3 class="font-display text-2xl font-semibold text-kavana-text mb-3">Shading</h3>
<p class="text-kavana-muted text-sm leading-relaxed mb-4">Motorized window treatments</p>
<p class="text-kavana-silver text-sm leading-relaxed">Automated shades and blinds that respond to sunlight, time, and your preferences. From our heritage as Manhattan Shade & Glass.</p>
</div>
<div class="flex items-center gap-2 mt-6 text-kavana-copper text-sm font-medium"><span>Learn more</span><i data-lucide="arrow-right" style="width:14px;height:14px;"></i></div>
</div>
<div class="horiz-scroll-panel" data-panel>
<div>
<div class="horiz-panel-icon"><i data-lucide="music" style="width:24px;height:24px;"></i></div>
<div class="font-mono text-[0.65rem] text-kavana-copper tracking-widest mb-3">04</div>
<h3 class="font-display text-2xl font-semibold text-kavana-text mb-3">Entertainment</h3>
<p class="text-kavana-muted text-sm leading-relaxed mb-4">Immersive A/V experiences</p>
<p class="text-kavana-silver text-sm leading-relaxed">Sonos multi-room audio, dedicated home theaters, and distributed video. Concert-quality sound, cinema-grade visuals.</p>
</div>
<div class="flex items-center gap-2 mt-6 text-kavana-copper text-sm font-medium"><span>Learn more</span><i data-lucide="arrow-right" style="width:14px;height:14px;"></i></div>
</div>
<div class="horiz-scroll-panel" data-panel>
<div>
<div class="horiz-panel-icon"><i data-lucide="thermometer" style="width:24px;height:24px;"></i></div>
<div class="font-mono text-[0.65rem] text-kavana-copper tracking-widest mb-3">05</div>
<h3 class="font-display text-2xl font-semibold text-kavana-text mb-3">Climate</h3>
<p class="text-kavana-muted text-sm leading-relaxed mb-4">Intelligent comfort control</p>
<p class="text-kavana-silver text-sm leading-relaxed">Smart thermostats and zoned climate systems that learn your patterns and optimize energy use while maintaining perfect comfort.</p>
</div>
<div class="flex items-center gap-2 mt-6 text-kavana-copper text-sm font-medium"><span>Learn more</span><i data-lucide="arrow-right" style="width:14px;height:14px;"></i></div>
</div>
<div class="horiz-scroll-panel" data-panel>
<div>
<div class="horiz-panel-icon"><i data-lucide="lock" style="width:24px;height:24px;"></i></div>
<div class="font-mono text-[0.65rem] text-kavana-copper tracking-widest mb-3">06</div>
<h3 class="font-display text-2xl font-semibold text-kavana-text mb-3">Cameras & Locks</h3>
<p class="text-kavana-muted text-sm leading-relaxed mb-4">Security & access management</p>
<p class="text-kavana-silver text-sm leading-relaxed">Comprehensive security with smart locks, camera systems, and access control. Monitor and manage from anywhere in the world.</p>
</div>
<div class="flex items-center gap-2 mt-6 text-kavana-copper text-sm font-medium"><span>Learn more</span><i data-lucide="arrow-right" style="width:14px;height:14px;"></i></div>
</div>
<div class="horiz-scroll-panel" data-panel>
<div>
<div class="horiz-panel-icon"><i data-lucide="wifi" style="width:24px;height:24px;"></i></div>
<div class="font-mono text-[0.65rem] text-kavana-copper tracking-widest mb-3">07</div>
<h3 class="font-display text-2xl font-semibold text-kavana-text mb-3">Networking</h3>
<p class="text-kavana-muted text-sm leading-relaxed mb-4">Enterprise-grade connectivity</p>
<p class="text-kavana-silver text-sm leading-relaxed">The backbone of every smart home. Enterprise-grade WiFi, wired infrastructure, and network management for flawless performance.</p>
</div>
<div class="flex items-center gap-2 mt-6 text-kavana-copper text-sm font-medium"><span>Learn more</span><i data-lucide="arrow-right" style="width:14px;height:14px;"></i></div>
</div>
</div>
<div class="horiz-scroll-dots" id="horizDots">
<div class="horiz-dot active"></div>
<div class="horiz-dot"></div>
<div class="horiz-dot"></div>
<div class="horiz-dot"></div>
<div class="horiz-dot"></div>
<div class="horiz-dot"></div>
<div class="horiz-dot"></div>
</div>
</div>
</div>
</section>
<div class="divider"></div>
<!-- ========== INTEGRATIONS GALLERY (Clip-Path Reveal) ========== -->
<section class="clip-reveal-section py-28 lg:py-36 px-6 lg:px-8 relative overflow-hidden" id="gallery" data-clip-reveal style="background: #0a0a0f;">
<div class="max-w-7xl mx-auto">
<div class="flex flex-col lg:flex-row lg:items-end lg:justify-between mb-12 gap-6">
<div>
<div class="section-label reveal">Integrations</div>
<h2 class="scroll-fill-text reveal stagger-1" data-scroll-fill>Connected <em style="-webkit-text-fill-color:inherit;font-style:italic;">Devices</em></h2>
</div>
<p class="section-desc reveal stagger-2">We integrate with every major smart home category — from lighting and locks to fireplaces and garage doors.</p>
</div>
<div class="flex items-center gap-2 mb-4 reveal stagger-3">
<i data-lucide="mouse-pointer-2" style="width:14px;height:14px;" class="text-kavana-muted"></i>
<span class="font-mono text-xs text-kavana-muted tracking-wide">DRAG TO EXPLORE</span>
</div>
</div>
<div class="overflow-hidden" id="galleryWrap">
<div class="gallery-track px-6 lg:px-8" id="galleryTrack">
<div class="gallery-card" data-tilt><div class="gallery-card-icon"><i data-lucide="lamp" style="width:24px;height:24px;"></i></div><h4 class="font-body font-semibold text-kavana-text text-sm mb-1">Lighting</h4><p class="font-mono text-[0.65rem] text-kavana-muted">Lutron · Ketra</p></div>
<div class="gallery-card" data-tilt><div class="gallery-card-icon"><i data-lucide="blinds" style="width:24px;height:24px;"></i></div><h4 class="font-body font-semibold text-kavana-text text-sm mb-1">Motorized Shades</h4><p class="font-mono text-[0.65rem] text-kavana-muted">Lutron · Hunter Douglas</p></div>
<div class="gallery-card" data-tilt><div class="gallery-card-icon"><i data-lucide="lock" style="width:24px;height:24px;"></i></div><h4 class="font-body font-semibold text-kavana-text text-sm mb-1">Locks</h4><p class="font-mono text-[0.65rem] text-kavana-muted">Yale · Schlage</p></div>
<div class="gallery-card" data-tilt><div class="gallery-card-icon"><i data-lucide="camera" style="width:24px;height:24px;"></i></div><h4 class="font-body font-semibold text-kavana-text text-sm mb-1">Cameras</h4><p class="font-mono text-[0.65rem] text-kavana-muted">Verkada · Axis</p></div>
<div class="gallery-card" data-tilt><div class="gallery-card-icon"><i data-lucide="music" style="width:24px;height:24px;"></i></div><h4 class="font-body font-semibold text-kavana-text text-sm mb-1">Music</h4><p class="font-mono text-[0.65rem] text-kavana-muted">Sonos · Bowers & Wilkins</p></div>
<div class="gallery-card" data-tilt><div class="gallery-card-icon"><i data-lucide="tv" style="width:24px;height:24px;"></i></div><h4 class="font-body font-semibold text-kavana-text text-sm mb-1">TVs</h4><p class="font-mono text-[0.65rem] text-kavana-muted">Samsung · Sony · LG</p></div>
<div class="gallery-card" data-tilt><div class="gallery-card-icon"><i data-lucide="fan" style="width:24px;height:24px;"></i></div><h4 class="font-body font-semibold text-kavana-text text-sm mb-1">Fans</h4><p class="font-mono text-[0.65rem] text-kavana-muted">Big Ass Fans · Haiku</p></div>
<div class="gallery-card" data-tilt><div class="gallery-card-icon"><i data-lucide="door-open" style="width:24px;height:24px;"></i></div><h4 class="font-body font-semibold text-kavana-text text-sm mb-1">Door Stations</h4><p class="font-mono text-[0.65rem] text-kavana-muted">2N · DoorBird</p></div>
<div class="gallery-card" data-tilt><div class="gallery-card-icon"><i data-lucide="flame" style="width:24px;height:24px;"></i></div><h4 class="font-body font-semibold text-kavana-text text-sm mb-1">Fireplaces</h4><p class="font-mono text-[0.65rem] text-kavana-muted">Modern Flames · Dimplex</p></div>
<div class="gallery-card" data-tilt><div class="gallery-card-icon"><i data-lucide="warehouse" style="width:24px;height:24px;"></i></div><h4 class="font-body font-semibold text-kavana-text text-sm mb-1">Garage Doors</h4><p class="font-mono text-[0.65rem] text-kavana-muted">LiftMaster · myQ</p></div>
<div class="gallery-card" data-tilt><div class="gallery-card-icon"><i data-lucide="grid-3x3" style="width:24px;height:24px;"></i></div><h4 class="font-body font-semibold text-kavana-text text-sm mb-1">Keypads</h4><p class="font-mono text-[0.65rem] text-kavana-muted">Lutron · Josh Micro</p></div>
<div class="gallery-card" data-tilt><div class="gallery-card-icon"><i data-lucide="thermometer" style="width:24px;height:24px;"></i></div><h4 class="font-body font-semibold text-kavana-text text-sm mb-1">Thermostats</h4><p class="font-mono text-[0.65rem] text-kavana-muted">ecobee · Nest</p></div>
<div class="gallery-card" data-tilt><div class="gallery-card-icon"><i data-lucide="shield" style="width:24px;height:24px;"></i></div><h4 class="font-body font-semibold text-kavana-text text-sm mb-1">Security</h4><p class="font-mono text-[0.65rem] text-kavana-muted">Alarm.com · DSC</p></div>
<div class="gallery-card" data-tilt><div class="gallery-card-icon"><i data-lucide="refrigerator" style="width:24px;height:24px;"></i></div><h4 class="font-body font-semibold text-kavana-text text-sm mb-1">Appliances</h4><p class="font-mono text-[0.65rem] text-kavana-muted">Sub-Zero · Wolf</p></div>
</div>
</div>
</section>
<div class="divider"></div>
<!-- ========== OUR STORY TIMELINE (Parallax Depth Layers) ========== -->
<section class="py-28 lg:py-36 px-6 lg:px-8 relative" id="story" style="background: #0c0c12; overflow: hidden;">
<div class="absolute top-0 left-0 w-full h-full pointer-events-none" style="overflow:hidden;">
<div data-parallax="0.15" class="absolute" style="top:10%;right:-5%;width:300px;height:300px;border-radius:50%;background:radial-gradient(circle,rgba(196,149,106,0.05),transparent 70%);filter:blur(40px);"></div>
<div data-parallax="0.25" class="absolute" style="top:40%;left:-10%;width:400px;height:400px;border-radius:50%;background:radial-gradient(circle,rgba(74,108,247,0.03),transparent 70%);filter:blur(60px);"></div>
<div data-parallax="0.1" class="absolute" style="bottom:10%;right:10%;width:200px;height:200px;border-radius:50%;background:radial-gradient(circle,rgba(196,149,106,0.04),transparent 70%);filter:blur(30px);"></div>
</div>
<div class="max-w-6xl mx-auto relative">
<div class="text-center mb-20">
<div class="section-label justify-center reveal">Heritage</div>
<h2 class="scroll-fill-text reveal stagger-1 mx-auto scramble-text" data-scroll-fill style="text-align:center;">Nearly a Century of New York Craft</h2>
<p class="section-desc mx-auto reveal stagger-2" style="margin-top:1rem;">From a storefront on Third Avenue to the forefront of smart home innovation — our story spans generations.</p>
</div>
<div class="timeline-container">
<div class="timeline-line"></div>
<div class="timeline-line-fill" id="timelineFill"></div>
<!-- 1926 -->
<div class="timeline-item" data-timeline>
<div class="timeline-dot"></div>
<div class="timeline-content-left w-1/2 pr-16 text-right reveal-left">
<div class="timeline-year">1926</div>
<div class="timeline-era-name">Manhattan Shade & Glass</div>
<p class="text-kavana-muted text-sm leading-relaxed">Founded on Third Avenue and 74th Street. Custom window shades and glass for Manhattan's finest residences and commercial spaces.</p>
</div>
<div class="w-1/2 pl-16 reveal-right">
<div class="rounded-2xl overflow-hidden border border-white/5 wipe-reveal" data-parallax="0.08">
<img src="https://images.unsplash.com/photo-1600210492486-724fe5c67fb0?w=600&q=80" alt="Historic New York" class="w-full h-48 object-cover hover:opacity-80 transition-opacity duration-500">
</div>
</div>
</div>
<!-- 1952 -->
<div class="timeline-item" data-timeline>
<div class="timeline-dot"></div>
<div class="w-1/2 pr-16 reveal-left">
<div class="rounded-2xl overflow-hidden border border-white/5 wipe-reveal" data-parallax="0.12">
<img src="https://images.unsplash.com/photo-1600607687939-ce8a6c25118c?w=600&q=80" alt="Mid-century growth" class="w-full h-48 object-cover hover:opacity-80 transition-opacity duration-500">
</div>
</div>
<div class="timeline-content-right w-1/2 pl-16 reveal-right">
<div class="timeline-year">1952</div>
<div class="timeline-era-name">Manhattan Shade, Glass & Awnings</div>
<p class="text-kavana-muted text-sm leading-relaxed">Expansion into awnings and exterior solutions. Serving a growing post-war New York with quality craftsmanship and reliability.</p>
</div>
</div>
<!-- 2018 -->
<div class="timeline-item" data-timeline>
<div class="timeline-dot"></div>
<div class="timeline-content-left w-1/2 pr-16 text-right reveal-left">
<div class="timeline-year">2018</div>
<div class="timeline-era-name">Manhattan Shade & Associates</div>
<p class="text-kavana-muted text-sm leading-relaxed">The digital pivot begins. Smart motorized shades, home automation consulting, and partnerships with leading technology brands.</p>
</div>
<div class="w-1/2 pl-16 reveal-right">
<div class="rounded-2xl overflow-hidden border border-white/5 wipe-reveal" data-parallax="0.06">
<img src="https://images.unsplash.com/photo-1558618666-fcd25c85f82e?w=600&q=80" alt="Smart technology" class="w-full h-48 object-cover hover:opacity-80 transition-opacity duration-500">
</div>
</div>
</div>
<!-- 2024 -->
<div class="timeline-item" data-timeline>
<div class="timeline-dot"></div>
<div class="w-1/2 pr-16 reveal-left">
<div class="rounded-2xl overflow-hidden border border-white/5 wipe-reveal" data-parallax="0.1">
<img src="https://images.unsplash.com/photo-1600566753190-17f0baa2a6c0?w=600&q=80" alt="Modern smart home" class="w-full h-48 object-cover hover:opacity-80 transition-opacity duration-500">
</div>
</div>
<div class="timeline-content-right w-1/2 pl-16 reveal-right">
<div class="timeline-year">2024</div>
<div class="timeline-era-name">Kavana Home</div>
<p class="text-kavana-muted text-sm leading-relaxed">A complete rebrand for a new era. Full-service smart home design, Josh.ai partnerships, and expansion from NYC to Florida and beyond. NYC showroom launching summer 2026.</p>
<div class="showroom-badge mt-4">
<span class="hero-badge-dot"></span>
Showroom · Summer 2026
</div>
</div>
</div>
</div>
</div>
</section>
<div class="divider"></div>
<!-- ========== HOW WE WORK (Clip-Path Reveal) ========== -->
<section class="clip-reveal-section py-28 lg:py-36 px-6 lg:px-8 relative" id="process" data-clip-reveal style="background: #0a0a0f;">
<div class="max-w-6xl mx-auto">
<div class="text-center mb-20">
<div class="section-label justify-center reveal">Process</div>
<h2 class="scroll-fill-text reveal stagger-1 mx-auto" data-scroll-fill style="text-align:center;">How We Work</h2>
<p class="section-desc mx-auto reveal stagger-2" style="margin-top:1rem;">From first call to ongoing support — a seamless experience built on transparency, precision, and care.</p>
</div>
<div class="grid sm:grid-cols-2 lg:grid-cols-4 gap-8">
<div class="process-step reveal stagger-1" data-process>
<div class="process-connector hidden lg:block"><div class="process-connector-fill"></div></div>
<div class="process-icon-wrap"><i data-lucide="file-text" style="width:26px;height:26px;"></i></div>
<div class="font-mono text-[0.65rem] text-kavana-copper tracking-widest mb-2">STEP 01</div>
<h3 class="font-display text-lg font-semibold text-kavana-text mb-2">Clear Scopes & Proposals</h3>
<p class="text-kavana-muted text-sm leading-relaxed">Detailed discovery, transparent pricing, and a comprehensive scope of work before any installation begins.</p>
</div>
<div class="process-step reveal stagger-2" data-process>
<div class="process-connector hidden lg:block"><div class="process-connector-fill"></div></div>
<div class="process-icon-wrap"><i data-lucide="layout-dashboard" style="width:26px;height:26px;"></i></div>
<div class="font-mono text-[0.65rem] text-kavana-copper tracking-widest mb-2">STEP 02</div>
<h3 class="font-display text-lg font-semibold text-kavana-text mb-2">Transparent PM</h3>
<p class="text-kavana-muted text-sm leading-relaxed">Dedicated project management with real-time updates, milestone tracking, and direct communication channels.</p>
</div>
<div class="process-step reveal stagger-3" data-process>
<div class="process-connector hidden lg:block"><div class="process-connector-fill"></div></div>
<div class="process-icon-wrap"><i data-lucide="users" style="width:26px;height:26px;"></i></div>
<div class="font-mono text-[0.65rem] text-kavana-copper tracking-widest mb-2">STEP 03</div>
<h3 class="font-display text-lg font-semibold text-kavana-text mb-2">Seamless Coordination</h3>
<p class="text-kavana-muted text-sm leading-relaxed">We coordinate with your designers, architects, and contractors. AD100 designers trust our collaborative approach.</p>
</div>
<div class="process-step reveal stagger-4" data-process>
<div class="process-icon-wrap"><i data-lucide="headphones" style="width:26px;height:26px;"></i></div>
<div class="font-mono text-[0.65rem] text-kavana-copper tracking-widest mb-2">STEP 04</div>
<h3 class="font-display text-lg font-semibold text-kavana-text mb-2">Ongoing Support</h3>
<p class="text-kavana-muted text-sm leading-relaxed">Our relationship doesn't end at installation. Proactive monitoring, updates, and white-glove support — always.</p>
</div>
</div>
</div>
</section>
<div class="divider"></div>
<!-- ========== TRUST / PARTNERS ========== -->
<section class="py-28 lg:py-36 px-6 lg:px-8 relative" id="trustSection" style="background: #0c0c12;">
<div class="max-w-6xl mx-auto">
<div class="grid lg:grid-cols-2 gap-20 items-center">
<div>
<div class="section-label reveal">Trust</div>
<h2 class="scroll-fill-text reveal stagger-1 scramble-text" data-scroll-fill>Built on Expertise</h2>
<p class="section-desc reveal stagger-2 mb-12" style="margin-top:1rem;">Nearly a century of craft, fully insured, and partnered with the world's finest smart home brands.</p>
<div class="grid grid-cols-2 gap-8 reveal stagger-3">
<div>
<div class="stat-number" data-count="98">0</div>
<div class="text-kavana-muted text-sm mt-1">Years of Heritage</div>
</div>
<div>
<div class="stat-number" data-count="3">0</div>
<div class="text-kavana-muted text-sm mt-1">Markets Served</div>
</div>
</div>
<div class="grid grid-cols-2 gap-4 mt-10 reveal stagger-4">
<div class="insurance-badge"><div class="relative z-10"><i data-lucide="shield-check" style="width:20px;height:20px;" class="text-kavana-copper mx-auto mb-2"></i><div class="text-kavana-text text-xs font-semibold">Property Insurance</div></div></div>
<div class="insurance-badge"><div class="relative z-10"><i data-lucide="hard-hat" style="width:20px;height:20px;" class="text-kavana-copper mx-auto mb-2"></i><div class="text-kavana-text text-xs font-semibold">Workforce Coverage</div></div></div>
<div class="insurance-badge"><div class="relative z-10"><i data-lucide="building" style="width:20px;height:20px;" class="text-kavana-copper mx-auto mb-2"></i><div class="text-kavana-text text-xs font-semibold">Building Compliance</div></div></div>
<div class="insurance-badge"><div class="relative z-10"><i data-lucide="check-circle" style="width:20px;height:20px;" class="text-kavana-copper mx-auto mb-2"></i><div class="text-kavana-text text-xs font-semibold">Fully Licensed</div></div></div>
</div>
</div>
<div>
<div class="font-mono text-xs text-kavana-muted tracking-widest mb-6 reveal">TRUSTED PARTNERS</div>
<div class="grid grid-cols-2 gap-4 reveal stagger-1">
<div class="partner-badge"><span class="relative z-10 font-display text-lg">Josh.ai</span></div>
<div class="partner-badge"><span class="relative z-10 font-display text-lg">Lutron</span></div>
<div class="partner-badge"><span class="relative z-10 font-display text-lg">Sonos</span></div>
<div class="partner-badge"><span class="relative z-10 font-display text-lg">Control4</span></div>
</div>
<div class="mt-8 rounded-2xl overflow-hidden border border-white/5 reveal stagger-2">
<img src="https://images.unsplash.com/photo-1616486338812-3dadae4b4ace?w=800&q=80" alt="Modern smart home interior" class="w-full h-64 object-cover opacity-50 hover:opacity-70 transition-opacity duration-700">
</div>
</div>
</div>
</div>
</section>
<div class="divider"></div>
<!-- ========== INFINITE MARQUEE TICKER ========== -->
<section class="marquee-section">
<div class="marquee-row-wrapper">
<div class="marquee-content" id="marqueeRow1"></div>
</div>
<div class="marquee-row-wrapper">
<div class="marquee-content reverse" id="marqueeRow2"></div>
</div>
</section>
<div class="divider"></div>
<!-- ========== CURSOR FLASHLIGHT SECTION ========== -->
<section class="flashlight-section" id="flashlightSection">
<div class="flashlight-bg" id="flashlightBg"></div>
<div class="flashlight-content">
<h2>See What's Possible</h2>
<p class="flashlight-hint">Move your cursor to explore</p>
</div>
</section>
<div class="divider"></div>
<!-- ========== CTA ========== -->
<section class="cta-section py-32 lg:py-44 px-6 lg:px-8 relative" id="contact">
<div class="cta-grid-bg"></div>
<div class="cta-particles" id="ctaParticles"></div>
<div class="max-w-3xl mx-auto text-center relative z-10">
<div class="section-label justify-center reveal">Get Started</div>
<h2 class="scroll-fill-text reveal stagger-1 mx-auto scramble-text" data-scroll-fill style="font-size:clamp(2.2rem,5vw,4rem);text-align:center;">Ready to Transform Your Home?</h2>
<p class="text-kavana-muted text-lg leading-relaxed mb-10 max-w-lg mx-auto reveal stagger-2" style="margin-top:1.5rem;">
Schedule a discovery call with our team. We'll discuss your vision, assess your space, and craft a plan tailored to your lifestyle.
</p>
<div class="flex flex-col sm:flex-row items-center justify-center gap-4 reveal stagger-3">
<a href="mailto:hello@kavana-home.com" class="magnetic-btn text-base px-8 py-4" id="ctaBtn">
Schedule a Discovery Call
<i data-lucide="arrow-right" style="width:18px;height:18px;"></i>
</a>
<div class="text-kavana-muted text-sm">
or email <a href="mailto:hello@kavana-home.com" class="text-kavana-copper hover:text-kavana-copperLight transition-colors underline underline-offset-4 decoration-kavana-copper/30">hello@kavana-home.com</a>
</div>
</div>
<div class="mt-8 flex items-center justify-center gap-6 text-kavana-muted text-xs reveal stagger-4">
<span class="flex items-center gap-1.5"><i data-lucide="map-pin" style="width:12px;height:12px;" class="text-kavana-copper"></i> NYC · Tri-State · Florida</span>
<span class="flex items-center gap-1.5"><i data-lucide="clock" style="width:12px;height:12px;" class="text-kavana-copper"></i> Response within 24 hours</span>
</div>
</div>
</section>
<!-- ========== FOOTER ========== -->
<footer class="py-20 px-6 lg:px-8 border-t border-white/5" style="background: #08080d;">
<div class="max-w-7xl mx-auto">
<div class="grid sm:grid-cols-2 lg:grid-cols-4 gap-12 mb-16">
<div class="lg:col-span-1">
<div class="flex items-center gap-3 mb-6">
<div class="w-9 h-9 rounded-lg bg-gradient-to-br from-kavana-copper to-kavana-copperLight flex items-center justify-center">
<span class="font-display text-kavana-bg font-bold text-lg leading-none">K</span>
</div>
<span class="font-display text-xl font-semibold tracking-wider text-kavana-text">KAVANA</span>
</div>
<p class="text-kavana-muted text-sm leading-relaxed mb-6">Smarter living, made simple. Premium smart home design & installation since 1926.</p>
<div class="flex items-center gap-3">
<a href="#" class="w-9 h-9 rounded-full border border-white/10 flex items-center justify-center text-kavana-muted hover:text-kavana-copper hover:border-kavana-copper/30 transition-all"><i data-lucide="instagram" style="width:16px;height:16px;"></i></a>
<a href="#" class="w-9 h-9 rounded-full border border-white/10 flex items-center justify-center text-kavana-muted hover:text-kavana-copper hover:border-kavana-copper/30 transition-all"><i data-lucide="linkedin" style="width:16px;height:16px;"></i></a>
<a href="#" class="w-9 h-9 rounded-full border border-white/10 flex items-center justify-center text-kavana-muted hover:text-kavana-copper hover:border-kavana-copper/30 transition-all"><i data-lucide="twitter" style="width:16px;height:16px;"></i></a>
</div>
</div>
<div>
<h4 class="font-mono text-xs text-kavana-copper tracking-widest mb-5">SERVICES</h4>
<a href="#services" class="footer-link">Smart Home</a>
<a href="#services" class="footer-link">Lighting</a>
<a href="#services" class="footer-link">Shading</a>
<a href="#services" class="footer-link">Entertainment</a>
<a href="#services" class="footer-link">Climate</a>
<a href="#services" class="footer-link">Cameras & Locks</a>
<a href="#services" class="footer-link">Networking</a>
</div>
<div>
<h4 class="font-mono text-xs text-kavana-copper tracking-widest mb-5">COMPANY</h4>
<a href="#story" class="footer-link">Our Story</a>
<a href="#process" class="footer-link">How We Work</a>
<a href="#gallery" class="footer-link">Integrations</a>
<a href="#contact" class="footer-link">Contact</a>
<a href="#" class="footer-link">Careers</a>
<a href="#" class="footer-link">Privacy Policy</a>
</div>
<div>
<h4 class="font-mono text-xs text-kavana-copper tracking-widest mb-5">STAY IN TOUCH</h4>
<p class="text-kavana-muted text-sm mb-4">Get insights on smart home design, new integrations, and showroom updates.</p>
<form class="flex flex-col gap-3" onsubmit="event.preventDefault(); this.querySelector('button').textContent='Subscribed ✓'; this.querySelector('button').classList.add('!bg-kavana-copper/20','!text-kavana-copper');">
<input type="email" placeholder="you@email.com" class="newsletter-input" required>
<button type="submit" class="magnetic-btn justify-center text-xs py-3">Subscribe</button>
</form>
</div>
</div>
<div class="divider mb-8"></div>
<div class="flex flex-col sm:flex-row items-center justify-between gap-4">
<div class="text-kavana-muted text-xs">© 2026 Kavana Home™. All rights reserved.</div>
<div class="flex items-center gap-6">
<span class="text-kavana-muted text-xs flex items-center gap-1.5"><i data-lucide="map-pin" style="width:11px;height:11px;"></i> New York City</span>
<span class="text-kavana-muted text-xs flex items-center gap-1.5"><i data-lucide="phone" style="width:11px;height:11px;"></i> (212) 555-0198</span>
</div>
</div>
</div>
</footer>
</div><!-- /content-wrapper -->
</div><!-- /smooth-wrapper -->
<!-- ========== JAVASCRIPT ========== -->
<script>
document.addEventListener('DOMContentLoaded', () => {
lucide.createIcons();
const isMobile = window.innerWidth < 768;
const isTouch = 'ontouchstart' in window;
// ===== LOADER =====
const loader = document.getElementById('loader');
document.body.style.overflow = 'hidden';
setTimeout(() => {
loader.classList.add('hidden');
document.body.style.overflow = '';
// Activate smooth scroll after load
if (!isMobile) initSmoothScroll();
}, 2800);
// ===== NAVBAR =====
const navbar = document.getElementById('navbar');
// ====================================================================
// V3 EFFECT 1: CUSTOM SMOOTH SCROLL PHYSICS
// ====================================================================
const smoothWrapper = document.getElementById('smooth-wrapper');
let smoothEnabled = false;
let smoothTarget = 0;
let smoothCurrent = 0;
let smoothScrollLimit = 0;
const LERP = 0.085;
function initSmoothScroll() {
if (isMobile || isTouch) return;
smoothEnabled = true;
document.body.classList.add('smooth-active');
// Calculate total scrollable height
recalcSmoothScroll();
// Set initial position from current scroll
smoothTarget = window.scrollY;
smoothCurrent = window.scrollY;
window.scrollTo(0, 0);
// Listen for wheel
window.addEventListener('wheel', onWheel, { passive: false });
// Listen for keys
window.addEventListener('keydown', onKeyScroll);
// Start the main animation loop
requestAnimationFrame(smoothLoop);
}
function recalcSmoothScroll() {
if (!smoothEnabled) return;
smoothScrollLimit = smoothWrapper.scrollHeight - window.innerHeight;
}
function onWheel(e) {
if (!smoothEnabled) return;
e.preventDefault();
smoothTarget += e.deltaY;
smoothTarget = Math.max(0, Math.min(smoothTarget, smoothScrollLimit));
}
function onKeyScroll(e) {
if (!smoothEnabled) return;
const keys = { ArrowDown: 80, ArrowUp: -80, PageDown: 400, PageUp: -400, Home: -Infinity, End: Infinity, ' ': 400 };
if (keys[e.key] !== undefined) {
e.preventDefault();
if (e.key === 'Home') smoothTarget = 0;
else if (e.key === 'End') smoothTarget = smoothScrollLimit;
else smoothTarget = Math.max(0, Math.min(smoothTarget + keys[e.key], smoothScrollLimit));
}
}
// Expose virtualScrollY for all scroll-linked effects
function getScrollY() {
return smoothEnabled ? smoothCurrent : window.scrollY;
}
// Main combined rAF loop
let scrollY = 0;
let lastScrollY = 0;
let scrollVelocity = 0;
function smoothLoop() {
if (smoothEnabled) {
// Lerp current toward target
smoothCurrent += (smoothTarget - smoothCurrent) * LERP;
// Snap when close enough
if (Math.abs(smoothTarget - smoothCurrent) < 0.5) smoothCurrent = smoothTarget;
// Apply transform
smoothWrapper.style.transform = `translateY(${-smoothCurrent}px)`;
scrollY = smoothCurrent;
}
// Compute velocity
scrollVelocity = scrollY - lastScrollY;
lastScrollY = scrollY;
// Navbar scroll state
navbar.classList.toggle('scrolled', scrollY > 80);
// Run all scroll-linked effects
updateHero3D();
updateMorphSection();
if (!isMobile) updateHorizScroll();
updateScrollFillTexts();
updateTimeline();
updateParallax();
updateKineticTypography();
updateClipReveals();
// Custom cursor update
if (!isMobile && !isTouch) updateCursor();
requestAnimationFrame(smoothLoop);
}
// For non-smooth (mobile), use native scroll
if (isMobile || isTouch) {
function onNativeScroll() {
scrollY = window.scrollY;
}
window.addEventListener('scroll', onNativeScroll, { passive: true });
// Start rAF loop for mobile too
function mobileLoop() {
scrollVelocity = scrollY - lastScrollY;
lastScrollY = scrollY;
navbar.classList.toggle('scrolled', scrollY > 80);
updateHero3D();
updateMorphSection();
updateScrollFillTexts();
updateTimeline();
updateParallax();
updateClipReveals();
requestAnimationFrame(mobileLoop);
}
requestAnimationFrame(mobileLoop);
}
// Handle resize
let resizeTimeout;
window.addEventListener('resize', () => {
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(() => {
recalcSmoothScroll();
setupHorizScroll();
}, 200);
});
// ====================================================================
// V3 EFFECT 2: CURSOR FLASHLIGHT SECTION
// ====================================================================
const flashlightSection = document.getElementById('flashlightSection');
const flashlightBg = document.getElementById('flashlightBg');
let flashlightMouseX = 50, flashlightMouseY = 50;
if (flashlightSection && flashlightBg) {
if (!isMobile && !isTouch) {
flashlightSection.addEventListener('mousemove', (e) => {
const rect = flashlightSection.getBoundingClientRect();
flashlightMouseX = e.clientX;
flashlightMouseY = e.clientY - rect.top;
// For smooth scroll, rect.top is relative to viewport which is correct
flashlightBg.style.maskImage = `radial-gradient(circle 140px at ${flashlightMouseX}px ${flashlightMouseY}px, black 60%, transparent 100%)`;
flashlightBg.style.webkitMaskImage = `radial-gradient(circle 140px at ${flashlightMouseX}px ${flashlightMouseY}px, black 60%, transparent 100%)`;
});
flashlightSection.addEventListener('mouseleave', () => {
flashlightBg.style.maskImage = 'radial-gradient(circle 0px at 50% 50%, black 60%, transparent 100%)';
flashlightBg.style.webkitMaskImage = 'radial-gradient(circle 0px at 50% 50%, black 60%, transparent 100%)';
});
} else {
// Mobile: auto-animate the reveal circle
let mobileAngle = 0;
function animateFlashlightMobile() {
mobileAngle += 0.008;
const cx = 50 + Math.cos(mobileAngle) * 25;
const cy = 50 + Math.sin(mobileAngle * 0.7) * 20;
flashlightBg.style.maskImage = `radial-gradient(circle 120px at ${cx}% ${cy}%, black 60%, transparent 100%)`;
flashlightBg.style.webkitMaskImage = `radial-gradient(circle 120px at ${cx}% ${cy}%, black 60%, transparent 100%)`;
requestAnimationFrame(animateFlashlightMobile);
}
animateFlashlightMobile();
}
}
// ====================================================================
// V3 EFFECT 3: FILM GRAIN OVERLAY (Canvas)
// ====================================================================
const grainCanvas = document.getElementById('film-grain');
if (grainCanvas) {
const gCtx = grainCanvas.getContext('2d');
grainCanvas.width = 256;
grainCanvas.height = 256;
grainCanvas.style.width = '100%';
grainCanvas.style.height = '100%';
// Use CSS to tile the small canvas
grainCanvas.style.imageRendering = 'pixelated';
// Actually we need a tiled approach — use background trick
// Instead, we draw to a small canvas and use it as background of a div
// Let's just animate the 256x256 canvas and tile via CSS on a covering div
// Actually, the canvas element IS the overlay. Let's set its size properly.
grainCanvas.width = 256;
grainCanvas.height = 256;
let grainFrameCount = 0;
function updateGrain() {
grainFrameCount++;
// Only update at ~10fps
if (grainFrameCount % 6 !== 0) {
requestAnimationFrame(updateGrain);
return;
}
const imageData = gCtx.createImageData(256, 256);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
const v = Math.random() * 255;
data[i] = v;
data[i + 1] = v;
data[i + 2] = v;
data[i + 3] = 255;
}
gCtx.putImageData(imageData, 0, 0);
requestAnimationFrame(updateGrain);
}
requestAnimationFrame(updateGrain);
// Mobile: slightly lower opacity
if (isMobile) {
grainCanvas.style.opacity = '0.02';
}
}
// ====================================================================
// V3 EFFECT 4: CUSTOM CURSOR
// ====================================================================
const cursorDot = document.getElementById('cursor-dot');
const cursorRing = document.getElementById('cursor-ring');
let mouseX = 0, mouseY = 0;
let ringX = 0, ringY = 0;
let cursorVisible = false;
if (!isMobile && !isTouch && cursorDot && cursorRing) {
cursorDot.style.display = 'block';
cursorRing.style.display = 'flex';
document.addEventListener('mousemove', (e) => {
mouseX = e.clientX;
mouseY = e.clientY;
if (!cursorVisible) {
cursorVisible = true;
cursorDot.style.opacity = '1';
cursorRing.style.opacity = '1';
}
});
document.addEventListener('mouseleave', () => {
cursorVisible = false;
cursorDot.style.opacity = '0';
cursorRing.style.opacity = '0';
});
document.addEventListener('mouseenter', () => {
cursorVisible = true;
cursorDot.style.opacity = '1';
cursorRing.style.opacity = '1';
});
// Hover state detection
document.addEventListener('mouseover', (e) => {
const target = e.target.closest('a, button, .magnetic-btn, .magnetic-btn-outline, .nav-link, .horiz-scroll-panel, .gallery-card, .partner-badge, .insurance-badge, .hamburger, input, .footer-link');
const imgTarget = e.target.closest('img, .wipe-reveal');
cursorRing.classList.remove('hovering', 'viewing');
if (imgTarget) {
cursorRing.classList.add('viewing');
} else if (target) {
cursorRing.classList.add('hovering');
}
});
// Click effect
document.addEventListener('mousedown', () => {
cursorDot.classList.add('pressing');
});
document.addEventListener('mouseup', () => {
cursorDot.classList.remove('pressing');
});
}
function updateCursor() {
if (!cursorDot || !cursorRing) return;
cursorDot.style.left = mouseX + 'px';
cursorDot.style.top = mouseY + 'px';
// Lerp ring
ringX += (mouseX - ringX) * 0.15;
ringY += (mouseY - ringY) * 0.15;
cursorRing.style.left = ringX + 'px';
cursorRing.style.top = ringY + 'px';
}
// ====================================================================
// V3 EFFECT 5: TEXT SCRAMBLE / DECODE
// ====================================================================
const scrambleChars = '─░▒▓█╔╗╚╝│┤├▼▲◆○●';
function scrambleText(el) {
const originalText = el.textContent;
const length = originalText.length;
let resolved = 0;
const scrambleDuration = 600;
const resolveStagger = 30;
const startTime = performance.now();
function update() {
const elapsed = performance.now() - startTime;
let display = '';
for (let i = 0; i < length; i++) {
if (originalText[i] === ' ') {
display += ' ';
continue;
}
// Character resolves at: scrambleDuration + (i * resolveStagger)
const resolveAt = scrambleDuration + (i * resolveStagger);
if (elapsed >= resolveAt) {
display += originalText[i];
} else if (elapsed >= scrambleDuration * 0.3) {
// Scrambling phase
display += scrambleChars[Math.floor(Math.random() * scrambleChars.length)];
} else {
display += scrambleChars[Math.floor(Math.random() * scrambleChars.length)];
}
}
el.textContent = display;
const totalDuration = scrambleDuration + (length * resolveStagger);
if (elapsed < totalDuration) {
requestAnimationFrame(update);
} else {
el.textContent = originalText;
}
}
requestAnimationFrame(update);
}
// Observe scramble-text elements
const scrambleObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
// Small delay for drama
setTimeout(() => scrambleText(entry.target), 200);
scrambleObserver.unobserve(entry.target);
}
});
}, { threshold: 0.3 });
document.querySelectorAll('.scramble-text').forEach(el => {
scrambleObserver.observe(el);
});
// ====================================================================
// V3 EFFECT 6: CURSOR SPARKLE TRAIL
// ====================================================================
const sparkleContainer = document.getElementById('sparkle-container');
let sparkles = [];
let lastSparkleTime = 0;
const MAX_SPARKLES = 30;
const copperShades = ['#c4956a', '#d4a574', '#e8c89e', '#a67c55', '#b8885e'];
if (!isMobile && !isTouch && sparkleContainer) {
document.addEventListener('mousemove', (e) => {
const now = performance.now();
if (now - lastSparkleTime < 50) return;
if (sparkles.length >= MAX_SPARKLES) return;
lastSparkleTime = now;
const sparkle = document.createElement('div');
sparkle.className = 'sparkle';
const size = 2 + Math.random() * 2;
const color = copperShades[Math.floor(Math.random() * copperShades.length)];
sparkle.style.cssText = `
width: ${size}px;
height: ${size}px;
background: ${color};
left: ${e.clientX}px;
top: ${e.clientY}px;
opacity: 0.8;
`;
sparkleContainer.appendChild(sparkle);
const vx = (Math.random() - 0.5) * 60;
const vy = (Math.random() - 0.5) * 60;
const sparkleData = {
el: sparkle,
x: e.clientX,
y: e.clientY,
vx, vy,
life: 0,
maxLife: 800
};
sparkles.push(sparkleData);
});
}
// Sparkle animation (merged into rAF loop below)
function updateSparkles(dt) {
for (let i = sparkles.length - 1; i >= 0; i--) {
const s = sparkles[i];
s.life += dt;
if (s.life >= s.maxLife) {
s.el.remove();
sparkles.splice(i, 1);
continue;
}
s.x += s.vx * (dt / 1000);
s.y += s.vy * (dt / 1000);
s.vy += 30 * (dt / 1000); // slight gravity
const progress = s.life / s.maxLife;
s.el.style.left = s.x + 'px';
s.el.style.top = s.y + 'px';
s.el.style.opacity = 0.8 * (1 - progress);
s.el.style.transform = `scale(${1 - progress * 0.5})`;
}
}
// Sparkle rAF
let sparkleLastTime = performance.now();
function sparkleLoop() {
const now = performance.now();
const dt = Math.min(now - sparkleLastTime, 50);
sparkleLastTime = now;
updateSparkles(dt);
requestAnimationFrame(sparkleLoop);
}
if (!isMobile && !isTouch) requestAnimationFrame(sparkleLoop);
// ====================================================================
// V3 EFFECT 7: INFINITE MARQUEE TICKER
// ====================================================================
const marqueeItems = ['Josh.ai', 'Lutron', 'Sonos', 'Control4', 'Smart Home', 'Lighting', 'Shading', 'Climate', 'Entertainment', 'Security'];
function buildMarqueeContent() {
let html = '';
for (let repeat = 0; repeat < 2; repeat++) {
for (const item of marqueeItems) {
html += `<span class="marquee-item">${item}</span><span class="marquee-dot"></span>`;
}
}
return html;
}
const marqueeRow1 = document.getElementById('marqueeRow1');
const marqueeRow2 = document.getElementById('marqueeRow2');
if (marqueeRow1) marqueeRow1.innerHTML = buildMarqueeContent();
if (marqueeRow2) marqueeRow2.innerHTML = buildMarqueeContent();
// ====================================================================
// V3 EFFECT 8: IMAGE COLOR-WIPE REVEALS
// ====================================================================
const wipeObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('wiping');
wipeObserver.unobserve(entry.target);
}
});
}, { threshold: 0.3 });
document.querySelectorAll('.wipe-reveal').forEach(el => {
wipeObserver.observe(el);
});
// ====================================================================
// EXISTING: 3D PERSPECTIVE HERO FLY-THROUGH
// ====================================================================
const heroSection = document.getElementById('heroSection');
const heroContent = document.getElementById('heroContent');
const heroDepthLayers = document.querySelectorAll('.hero-depth-layer');
function updateHero3D() {
if (isMobile) return;
const heroH = heroSection.offsetHeight;
const progress = Math.min(Math.max(scrollY / heroH, 0), 1);
const z = progress * -300;
const scale = 1 - progress * 0.3;
const opacity = 1 - progress * 1.5;
heroContent.style.transform = `translateZ(${z}px) scale(${Math.max(scale, 0.7)})`;
heroContent.style.opacity = Math.max(opacity, 0);
heroDepthLayers.forEach(layer => {
const depth = parseFloat(layer.dataset.depth) || 0;
const yOffset = scrollY * depth;
const zOffset = progress * -200 * depth;
layer.style.transform = `translateY(${yOffset}px) translateZ(${zOffset}px)`;
});
}
// ====================================================================
// EXISTING: SCROLL-PINNED MORPH SECTION
// ====================================================================
const morphWrapper = document.getElementById('morphWrapper');
const morphValues = [
document.getElementById('morphValue0'),
document.getElementById('morphValue1'),
document.getElementById('morphValue2')
];
const morphProgressFill = document.getElementById('morphProgressFill');
function updateMorphSection() {
if (!morphWrapper) return;
// Get wrapper position relative to the document
let wrapperTop;
if (smoothEnabled) {
wrapperTop = morphWrapper.offsetTop;
} else {
const rect = morphWrapper.getBoundingClientRect();
wrapperTop = scrollY + rect.top;
}
const scrollRange = morphWrapper.offsetHeight - window.innerHeight;
const localScroll = scrollY - wrapperTop;
const progress = Math.min(Math.max(localScroll / scrollRange, 0), 1);
const activeIndex = Math.min(Math.floor(progress * 3), 2);
morphValues.forEach((val, i) => {
if (i === activeIndex) val.classList.add('active');
else val.classList.remove('active');
});
if (morphProgressFill) {
morphProgressFill.style.width = (progress * 100) + '%';
}
const activeEl = morphValues[activeIndex];
if (activeEl) {
const fillText = activeEl.querySelector('[data-scroll-fill]');
if (fillText) {
const subProgress = (progress * 3) - activeIndex;
const bgPos = 100 - (subProgress * 100);
fillText.style.backgroundPosition = bgPos + '% 0';
if (subProgress > 0.5) fillText.classList.add('filled');
else fillText.classList.remove('filled');
}
}
}
// ====================================================================
// EXISTING: STICKY HORIZONTAL SCROLL SERVICES
// ====================================================================
const horizWrapper = document.getElementById('horizWrapper');
const horizTrack = document.getElementById('horizTrack');
const horizCounter = document.getElementById('horizCounter');
const horizDots = document.getElementById('horizDots');
const panels = horizTrack ? horizTrack.querySelectorAll('[data-panel]') : [];
const numPanels = panels.length;
function setupHorizScroll() {
if (isMobile || !horizWrapper || !horizTrack) return;
const panelWidth = panels[0] ? panels[0].offsetWidth + 32 : 532;
const totalTrackWidth = panelWidth * numPanels + 64;
const extraScroll = totalTrackWidth - window.innerWidth;
horizWrapper.style.height = (window.innerHeight + extraScroll) + 'px';
}
setupHorizScroll();
function updateHorizScroll() {
if (!horizWrapper || !horizTrack) return;
let wrapperTop;
if (smoothEnabled) {
wrapperTop = horizWrapper.offsetTop;
} else {
const rect = horizWrapper.getBoundingClientRect();
wrapperTop = scrollY + rect.top;
}
const scrollRange = horizWrapper.offsetHeight - window.innerHeight;
const localScroll = scrollY - wrapperTop;
const progress = Math.min(Math.max(localScroll / scrollRange, 0), 1);
const panelWidth = panels[0] ? panels[0].offsetWidth + 32 : 532;
const totalTrackWidth = panelWidth * numPanels + 64;
const maxTranslate = totalTrackWidth - window.innerWidth;
const translateX = -progress * maxTranslate;
horizTrack.style.transform = `translateX(${translateX}px)`;
const activePanel = Math.min(Math.floor(progress * numPanels), numPanels - 1);
if (horizCounter) {
horizCounter.textContent = String(activePanel + 1).padStart(2, '0') + ' / ' + String(numPanels).padStart(2, '0');
}
if (horizDots) {
const dots = horizDots.querySelectorAll('.horiz-dot');
dots.forEach((dot, i) => {
dot.classList.toggle('active', i === activePanel);
});
}
}
// Mouse glow on horiz panels
document.querySelectorAll('.horiz-scroll-panel').forEach(card => {
card.addEventListener('mousemove', (e) => {
const rect = card.getBoundingClientRect();
card.style.setProperty('--mouse-x', ((e.clientX - rect.left) / rect.width * 100) + '%');
card.style.setProperty('--mouse-y', ((e.clientY - rect.top) / rect.height * 100) + '%');
});
});
// ====================================================================
// EXISTING: SCROLL-DRIVEN TEXT FILL
// ====================================================================
const scrollFillTexts = document.querySelectorAll('[data-scroll-fill]');
function updateScrollFillTexts() {
scrollFillTexts.forEach(el => {
if (el.closest('.morph-value')) return;
let elTop;
if (smoothEnabled) {
elTop = el.getBoundingClientRect().top + smoothCurrent;
elTop = elTop - smoothCurrent; // = getBoundingClientRect().top
// Actually for smooth scroll, the wrapper is translated but getBoundingClientRect
// still gives viewport-relative positions, which is what we want
}
const rect = el.getBoundingClientRect();
const windowH = window.innerHeight;
const start = windowH * 0.85;
const end = windowH * 0.3;
const progress = Math.min(Math.max((start - rect.top) / (start - end), 0), 1);
const bgPos = 100 - (progress * 100);
el.style.backgroundPosition = bgPos + '% 0';
if (progress > 0.9) el.classList.add('filled');
else el.classList.remove('filled');
});
}
// ====================================================================
// EXISTING: KINETIC TYPOGRAPHY
// ====================================================================
const kineticWords = document.querySelectorAll('.kinetic-word');
function updateKineticTypography() {
if (isMobile) return;
const vel = Math.abs(scrollVelocity);
const maxEffect = 25;
const normalized = Math.min(vel / 30, 1);
kineticWords.forEach((word, i) => {
const offset = (i - (kineticWords.length - 1) / 2);
const spread = offset * normalized * maxEffect * 0.3;
const blur = normalized * 1.5;
const skew = scrollVelocity * 0.02 * (i % 2 === 0 ? 1 : -1);
word.style.transform = `translateX(${spread}px) skewX(${skew}deg)`;
word.style.filter = blur > 0.3 ? `blur(${blur}px)` : 'none';
if (vel < 2) {
word.style.transform = 'translateX(0) skewX(0)';
word.style.filter = 'none';
}
});
}
// ====================================================================
// EXISTING: PARALLAX DEPTH LAYERS
// ====================================================================
const parallaxElements = document.querySelectorAll('[data-parallax]');
function updateParallax() {
if (isMobile) return;
parallaxElements.forEach(el => {
const speed = parseFloat(el.dataset.parallax) || 0.1;
const rect = el.getBoundingClientRect();
const centerY = rect.top + rect.height / 2;
const viewCenter = window.innerHeight / 2;
const offset = (centerY - viewCenter) * speed;
el.style.transform = `translateY(${-offset}px)`;
});
}
// ====================================================================
// EXISTING: CLIP-PATH SECTION REVEALS
// ====================================================================
const clipRevealSections = document.querySelectorAll('[data-clip-reveal]');
function updateClipReveals() {
if (isMobile) {
clipRevealSections.forEach(s => s.style.clipPath = 'none');
return;
}
clipRevealSections.forEach(section => {
const rect = section.getBoundingClientRect();
const windowH = window.innerHeight;
const start = windowH * 1.0;
const end = windowH * 0.3;
const progress = Math.min(Math.max((start - rect.top) / (start - end), 0), 1);
const eased = progress < 0.5 ? 2 * progress * progress : 1 - Math.pow(-2 * progress + 2, 2) / 2;
const radius = eased * 150;
section.style.clipPath = `circle(${radius}% at 50% 50%)`;
});
}
// ====================================================================
// EXISTING: TIMELINE
// ====================================================================
const timelineFill = document.getElementById('timelineFill');
const timelineContainer = document.querySelector('.timeline-container');
function updateTimeline() {
if (!timelineFill || !timelineContainer) return;
const rect = timelineContainer.getBoundingClientRect();
const progress = Math.min(Math.max((window.innerHeight - rect.top) / (rect.height + window.innerHeight * 0.5), 0), 1);
timelineFill.style.height = (progress * rect.height) + 'px';
}
// ====================================================================
// CANVAS PARTICLE CONSTELLATION BACKGROUND
// ====================================================================
const canvas = document.getElementById('particleCanvas');
const ctx = canvas.getContext('2d');
let particles = [];
const particleCount = isMobile ? 30 : 70;
const connectionDistance = 120;
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
class Particle {
constructor() {
this.x = Math.random() * canvas.width;
this.y = Math.random() * canvas.height;
this.baseY = this.y;
this.vx = (Math.random() - 0.5) * 0.3;
this.vy = (Math.random() - 0.5) * 0.3;
this.size = Math.random() * 1.5 + 0.5;
this.opacity = Math.random() * 0.4 + 0.1;
const colorChoice = Math.random();
if (colorChoice < 0.4) { this.r = 196; this.g = 149; this.b = 106; }
else if (colorChoice < 0.7) { this.r = 212; this.g = 165; this.b = 116; }
else { this.r = 232; this.g = 200; this.b = 158; }
}
update(scrollOffset) {
this.x += this.vx;
this.y += this.vy;
this.y = this.baseY + scrollOffset * 0.05;
if (this.x < 0) this.x = canvas.width;
if (this.x > canvas.width) this.x = 0;
if (this.y < -50) this.y = canvas.height + 50;
if (this.y > canvas.height + 50) this.y = -50;
this.baseY += this.vy;
if (this.baseY < -50) this.baseY = canvas.height + 50;
if (this.baseY > canvas.height + 50) this.baseY = -50;
}
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
ctx.fillStyle = `rgba(${this.r},${this.g},${this.b},${this.opacity})`;
ctx.fill();
}
}
for (let i = 0; i < particleCount; i++) {
particles.push(new Particle());
}
function drawConnections() {
for (let i = 0; i < particles.length; i++) {
for (let j = i + 1; j < particles.length; j++) {
const dx = particles[i].x - particles[j].x;
const dy = particles[i].y - particles[j].y;
const dist = Math.sqrt(dx * dx + dy * dy);
if (dist < connectionDistance) {
const opacity = (1 - dist / connectionDistance) * 0.08;
ctx.beginPath();
ctx.moveTo(particles[i].x, particles[i].y);
ctx.lineTo(particles[j].x, particles[j].y);
ctx.strokeStyle = `rgba(196,149,106,${opacity})`;
ctx.lineWidth = 0.5;
ctx.stroke();
}
}
}
}
function animateParticles() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
const scrollOffset = scrollY % canvas.height;
particles.forEach(p => {
p.update(scrollOffset);
p.draw();
});
drawConnections();
requestAnimationFrame(animateParticles);
}
animateParticles();
// ====================================================================
// INTERSECTION OBSERVERS — general reveals
// ====================================================================
const revealObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) entry.target.classList.add('visible');
});
}, { threshold: 0.1, rootMargin: '0px 0px -60px 0px' });
document.querySelectorAll('.reveal, .reveal-left, .reveal-right, .reveal-scale').forEach(el => {
revealObserver.observe(el);
});
const timelineObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) entry.target.classList.add('visible');
});
}, { threshold: 0.3 });
document.querySelectorAll('[data-timeline]').forEach(el => timelineObserver.observe(el));
const processObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) entry.target.classList.add('visible');
});
}, { threshold: 0.3 });
document.querySelectorAll('[data-process]').forEach(el => processObserver.observe(el));
// ====================================================================
// STAT COUNTER
// ====================================================================
const countObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const el = entry.target;
const target = parseInt(el.dataset.count);
let current = 0;
const step = target / (2000 / 16);
const counter = () => {
current += step;
if (current >= target) { el.textContent = target + '+'; return; }
el.textContent = Math.floor(current);
requestAnimationFrame(counter);
};
counter();
countObserver.unobserve(el);
}
});
}, { threshold: 0.5 });
document.querySelectorAll('[data-count]').forEach(el => countObserver.observe(el));
// ====================================================================
// GALLERY DRAG SCROLL
// ====================================================================
const galleryTrack = document.getElementById('galleryTrack');
const galleryWrap = document.getElementById('galleryWrap');
if (galleryTrack && galleryWrap) {
galleryWrap.style.overflowX = 'auto';
galleryWrap.style.scrollbarWidth = 'none';
galleryWrap.style.msOverflowStyle = 'none';
let isDown = false, startX, sl;
galleryTrack.addEventListener('mousedown', (e) => {
isDown = true;
galleryTrack.style.cursor = 'grabbing';
startX = e.pageX - galleryTrack.offsetLeft;
sl = galleryWrap.scrollLeft;
});
galleryTrack.addEventListener('mouseleave', () => { isDown = false; galleryTrack.style.cursor = 'grab'; });
galleryTrack.addEventListener('mouseup', () => { isDown = false; galleryTrack.style.cursor = 'grab'; });
galleryTrack.addEventListener('mousemove', (e) => {
if (!isDown) return;
e.preventDefault();
const walk = (e.pageX - galleryTrack.offsetLeft - startX) * 2;
galleryWrap.scrollLeft = sl - walk;
});
}
// ====================================================================
// 3D TILT ON GALLERY CARDS
// ====================================================================
document.querySelectorAll('[data-tilt]').forEach(card => {
card.addEventListener('mousemove', (e) => {
const rect = card.getBoundingClientRect();
const x = (e.clientX - rect.left) / rect.width - 0.5;
const y = (e.clientY - rect.top) / rect.height - 0.5;
card.style.transform = `perspective(800px) rotateY(${x * 15}deg) rotateX(${-y * 15}deg) translateY(-5px)`;
});
card.addEventListener('mouseleave', () => {
card.style.transform = 'perspective(800px) rotateY(0) rotateX(0) translateY(0)';
card.style.transition = 'transform 0.5s cubic-bezier(0.16, 1, 0.3, 1)';
});
card.addEventListener('mouseenter', () => {
card.style.transition = 'transform 0.1s';
});
});
// ====================================================================
// MAGNETIC BUTTONS
// ====================================================================
document.querySelectorAll('.magnetic-btn').forEach(btn => {
btn.addEventListener('mousemove', (e) => {
const rect = btn.getBoundingClientRect();
const x = e.clientX - rect.left - rect.width / 2;
const y = e.clientY - rect.top - rect.height / 2;
btn.style.transform = `translate(${x * 0.15}px, ${y * 0.15}px)`;
});
btn.addEventListener('mouseleave', () => {
btn.style.transform = 'translate(0, 0)';
});
btn.addEventListener('click', (e) => {
const ripple = document.createElement('span');
ripple.classList.add('ripple');
const rect = btn.getBoundingClientRect();
const size = Math.max(rect.width, rect.height);
ripple.style.width = ripple.style.height = size + 'px';
ripple.style.left = (e.clientX - rect.left - size / 2) + 'px';
ripple.style.top = (e.clientY - rect.top - size / 2) + 'px';
btn.appendChild(ripple);
setTimeout(() => ripple.remove(), 600);
});
});
// ====================================================================
// CTA PARTICLES
// ====================================================================
const ctaParticles = document.getElementById('ctaParticles');
if (ctaParticles) {
for (let i = 0; i < 30; i++) {
const p = document.createElement('div');
p.className = 'cta-particle';
p.style.left = Math.random() * 100 + '%';
p.style.bottom = '-10px';
p.style.animationDelay = Math.random() * 6 + 's';
p.style.animationDuration = (4 + Math.random() * 4) + 's';
ctaParticles.appendChild(p);
}
}
// ====================================================================
// SMOOTH SCROLL ANCHOR LINKS
// ====================================================================
document.querySelectorAll('a[href^="#"]').forEach(link => {
link.addEventListener('click', (e) => {
e.preventDefault();
const href = link.getAttribute('href');
const target = document.querySelector(href);
if (!target) return;
if (smoothEnabled) {
// Calculate target position within the smooth wrapper
const targetTop = target.offsetTop;
smoothTarget = Math.max(0, Math.min(targetTop, smoothScrollLimit));
} else {
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
});
});
// ====================================================================
// INITIAL TRIGGER
// ====================================================================
setTimeout(() => {
scrollY = smoothEnabled ? smoothCurrent : window.scrollY;
}, 100);
});
// ===== MOBILE MENU =====
function toggleMobile() {
document.getElementById('mobileMenu').classList.toggle('open');
document.getElementById('hamburger').classList.toggle('active');
}
function closeMobile() {
document.getElementById('mobileMenu').classList.remove('open');
document.getElementById('hamburger').classList.remove('active');
}
</script>
</body>
</html>