Загрузка...

HTML/CSS шаблон лендинга для портфолио архитектурной студии. Минималистичный дизайн, идеально подходит для демонстрации проектов.
<html lang="en" class="antialiased"><head><meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>KAIROS | Spatial Design</title>
<!-- Fonts: Inter & Space Grotesk for that "Linear" feel -->
<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=Inter:wght@300;400;500&family=Space+Grotesk:wght@400;500;600&display=swap" rel="stylesheet">
<!-- Tailwind -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Icons -->
<script src="https://unpkg.com/lucide@latest"></script>
<!-- GSAP / Lenis -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/ScrollTrigger.min.js"></script>
<script src="https://unpkg.com/@studio-freight/lenis@1.0.33/dist/lenis.min.js"></script>
<style>
/* --- CORE VARS (DARK MODE REFRESH) --- */
:root {
--c-bg: #050505;
--c-text: #EAEAEA;
--c-accent: #333333;
--font-display: 'Space Grotesk', sans-serif;
--font-body: 'Inter', sans-serif;
--ease-expo: cubic-bezier(0.19, 1, 0.22, 1);
}
body {
background-color: var(--c-bg);
color: var(--c-text);
font-family: var(--font-body);
margin: 0;
overflow-x: hidden;
opacity: 0;
}
::selection {
background: #fff;
color: #000;
}
/* --- UTILS --- */
.display-font { font-family: var(--font-display); }
.noise {
position: fixed;
inset: 0;
z-index: 9999;
opacity: 0.04;
pointer-events: none;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
}
/* --- PROJECT STICKY SECTION --- */
.project-wrapper {
position: relative;
display: flex;
justify-content: space-between;
padding-bottom: 20vh;
}
.project-images {
position: relative;
width: 45%;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.project-img-container {
position: absolute;
inset: 0;
opacity: 0;
transition: opacity 0.6s ease;
}
.project-img-container.active {
opacity: 1;
}
.project-img-container img {
width: 100%;
height: 100%;
object-fit: cover;
}
.project-list {
width: 50%;
padding-top: 20vh;
padding-bottom: 20vh;
}
.project-item {
height: 80vh;
display: flex;
flex-direction: column;
justify-content: center;
border-top: 1px solid rgba(255,255,255,0.1);
opacity: 0.3;
transition: opacity 0.3s;
}
.project-item.active {
opacity: 1;
}
/* --- MARQUEE --- */
.marquee-container {
overflow: hidden;
white-space: nowrap;
display: flex;
}
.marquee-content {
display: flex;
animation: marquee 20s linear infinite;
}
@keyframes marquee {
0% { transform: translateX(0); }
100% { transform: translateX(-100%); }
}
</style>
<style>
/* --- NEW AGENCY ANIMATIONS --- */
.hero-text-huge { font-size: 18vw; line-height: 0.8; letter-spacing: -0.06em; mix-blend-mode: exclusion; color: white; font-weight: 500; }
.scrub-word { opacity: 0.15; transition: opacity 0.1s; will-change: opacity, color; }
.card-inner { transform-origin: center bottom; will-change: transform; }
.perspective-stack { perspective: 2000px; }
</style>
<script>
// Configure Tailwind to include our custom 3D transform utilities
tailwind.config = {
theme: {
extend: {
// Add any custom theme extensions here if needed
}
},
plugins: [
function({ addUtilities }) {
const rotateXUtilities = {};
const rotateYUtilities = {};
const rotateZUtilities = {};
const rotateValues = [0, 5, 10, 15, 20, 30, 45, 75];
// Generate rotate-x utilities
rotateValues.forEach((value) => {
rotateXUtilities[`.rotate-x-${value}`] = {
'--tw-rotate-x': `${value}deg`,
transform: `
translate3d(var(--tw-translate-x, 0), var(--tw-translate-y, 0), var(--tw-translate-z, 0))
rotateX(var(--tw-rotate-x, 0))
rotateY(var(--tw-rotate-y, 0))
rotateZ(var(--tw-rotate-z, 0))
skewX(var(--tw-skew-x, 0))
skewY(var(--tw-skew-y, 0))
scaleX(var(--tw-scale-x, 1))
scaleY(var(--tw-scale-y, 1))
`.replace(/\\s+/g, ' ').trim(),
};
if (value !== 0) {
rotateXUtilities[`.-rotate-x-${value}`] = {
'--tw-rotate-x': `-${value}deg`,
transform: `
translate3d(var(--tw-translate-x, 0), var(--tw-translate-y, 0), var(--tw-translate-z, 0))
rotateX(var(--tw-rotate-x, 0))
rotateY(var(--tw-rotate-y, 0))
rotateZ(var(--tw-rotate-z, 0))
skewX(var(--tw-skew-x, 0))
skewY(var(--tw-skew-y, 0))
scaleX(var(--tw-scale-x, 1))
scaleY(var(--tw-scale-y, 1))
`.replace(/\\s+/g, ' ').trim(),
};
}
});
// Generate rotate-y utilities
rotateValues.forEach((value) => {
rotateYUtilities[`.rotate-y-${value}`] = {
'--tw-rotate-y': `${value}deg`,
transform: `
translate3d(var(--tw-translate-x, 0), var(--tw-translate-y, 0), var(--tw-translate-z, 0))
rotateX(var(--tw-rotate-x, 0))
rotateY(var(--tw-rotate-y, 0))
rotateZ(var(--tw-rotate-z, 0))
skewX(var(--tw-skew-x, 0))
skewY(var(--tw-skew-y, 0))
scaleX(var(--tw-scale-x, 1))
scaleY(var(--tw-scale-y, 1))
`.replace(/\\s+/g, ' ').trim(),
};
if (value !== 0) {
rotateYUtilities[`.-rotate-y-${value}`] = {
'--tw-rotate-y': `-${value}deg`,
transform: `
translate3d(var(--tw-translate-x, 0), var(--tw-translate-y, 0), var(--tw-translate-z, 0))
rotateX(var(--tw-rotate-x, 0))
rotateY(var(--tw-rotate-y, 0))
rotateZ(var(--tw-rotate-z, 0))
skewX(var(--tw-skew-x, 0))
skewY(var(--tw-skew-y, 0))
scaleX(var(--tw-scale-x, 1))
scaleY(var(--tw-scale-y, 1))
`.replace(/\\s+/g, ' ').trim(),
};
}
});
// Generate rotate-z utilities
rotateValues.forEach((value) => {
rotateZUtilities[`.rotate-z-${value}`] = {
'--tw-rotate-z': `${value}deg`,
transform: `
translate3d(var(--tw-translate-x, 0), var(--tw-translate-y, 0), var(--tw-translate-z, 0))
rotateX(var(--tw-rotate-x, 0))
rotateY(var(--tw-rotate-y, 0))
rotateZ(var(--tw-rotate-z, 0))
skewX(var(--tw-skew-x, 0))
skewY(var(--tw-skew-y, 0))
scaleX(var(--tw-scale-x, 1))
scaleY(var(--tw-scale-y, 1))
`.replace(/\\s+/g, ' ').trim(),
};
if (value !== 0) {
rotateZUtilities[`.-rotate-z-${value}`] = {
'--tw-rotate-z': `-${value}deg`,
transform: `
translate3d(var(--tw-translate-x, 0), var(--tw-translate-y, 0), var(--tw-translate-z, 0))
rotateX(var(--tw-rotate-x, 0))
rotateY(var(--tw-rotate-y, 0))
rotateZ(var(--tw-rotate-z, 0))
skewX(var(--tw-skew-x, 0))
skewY(var(--tw-skew-y, 0))
scaleX(var(--tw-scale-x, 1))
scaleY(var(--tw-scale-y, 1))
`.replace(/\\s+/g, ' ').trim(),
};
}
});
// Perspective utilities
const perspectiveUtilities = {
".perspective-none": { perspective: "none" },
".perspective-dramatic": { perspective: "100px" },
".perspective-near": { perspective: "300px" },
".perspective-normal": { perspective: "500px" },
".perspective-midrange": { perspective: "800px" },
".perspective-distant": { perspective: "1200px" },
};
// Transform style utilities
const transformStyleUtilities = {
".transform-style-preserve-3d": { "transform-style": "preserve-3d" },
".transform-style-flat": { "transform-style": "flat" },
};
addUtilities({
...rotateXUtilities,
...rotateYUtilities,
...rotateZUtilities,
...perspectiveUtilities,
...transformStyleUtilities,
});
}
]
};
</script>
<link id="all-fonts-link-font-geist" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Geist:wght@300;400;500;600;700&display=swap">
<style id="all-fonts-style-font-geist">
.font-geist { font-family: 'Geist', sans-serif !important; }
</style>
<link id="all-fonts-link-font-roboto" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap">
<style id="all-fonts-style-font-roboto">
.font-roboto { font-family: 'Roboto', sans-serif !important; }
</style>
<link id="all-fonts-link-font-montserrat" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500;600;700&display=swap">
<style id="all-fonts-style-font-montserrat">
.font-montserrat { font-family: 'Montserrat', sans-serif !important; }
</style>
<link id="all-fonts-link-font-poppins" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap">
<style id="all-fonts-style-font-poppins">
.font-poppins { font-family: 'Poppins', sans-serif !important; }
</style>
<link id="all-fonts-link-font-playfair" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;500;600;700;900&display=swap">
<style id="all-fonts-style-font-playfair">
.font-playfair { font-family: 'Playfair Display', serif !important; }
</style>
<link id="all-fonts-link-font-instrument-serif" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Instrument+Serif:wght@400;500;600;700&display=swap">
<style id="all-fonts-style-font-instrument-serif">
.font-instrument-serif { font-family: 'Instrument Serif', serif !important; }
</style>
<link id="all-fonts-link-font-merriweather" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Merriweather:wght@300;400;700;900&display=swap">
<style id="all-fonts-style-font-merriweather">
.font-merriweather { font-family: 'Merriweather', serif !important; }
</style>
<link id="all-fonts-link-font-bricolage" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:wght@300;400;500;600;700&display=swap">
<style id="all-fonts-style-font-bricolage">
.font-bricolage { font-family: 'Bricolage Grotesque', sans-serif !important; }
</style>
<link id="all-fonts-link-font-jakarta" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&display=swap">
<style id="all-fonts-style-font-jakarta">
.font-jakarta { font-family: 'Plus Jakarta Sans', sans-serif !important; }
</style>
<link id="all-fonts-link-font-manrope" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@300;400;500;600;700;800&display=swap">
<style id="all-fonts-style-font-manrope">
.font-manrope { font-family: 'Manrope', sans-serif !important; }
</style>
<link id="all-fonts-link-font-space-grotesk" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap">
<style id="all-fonts-style-font-space-grotesk">
.font-space-grotesk { font-family: 'Space Grotesk', sans-serif !important; }
</style>
<link id="all-fonts-link-font-work-sans" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Work+Sans:wght@300;400;500;600;700;800&display=swap">
<style id="all-fonts-style-font-work-sans">
.font-work-sans { font-family: 'Work Sans', sans-serif !important; }
</style>
<link id="all-fonts-link-font-pt-serif" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=PT+Serif:wght@400;700&display=swap">
<style id="all-fonts-style-font-pt-serif">
.font-pt-serif { font-family: 'PT Serif', serif !important; }
</style>
<link id="all-fonts-link-font-geist-mono" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Geist+Mono:wght@300;400;500;600;700&display=swap">
<style id="all-fonts-style-font-geist-mono">
.font-geist-mono { font-family: 'Geist Mono', monospace !important; }
</style>
<link id="all-fonts-link-font-space-mono" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&display=swap">
<style id="all-fonts-style-font-space-mono">
.font-space-mono { font-family: 'Space Mono', monospace !important; }
</style>
<link id="all-fonts-link-font-quicksand" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Quicksand:wght@300;400;500;600;700&display=swap">
<style id="all-fonts-style-font-quicksand">
.font-quicksand { font-family: 'Quicksand', sans-serif !important; }
</style>
<link id="all-fonts-link-font-nunito" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Nunito:wght@300;400;500;600;700;800&display=swap">
<style id="all-fonts-style-font-nunito">
.font-nunito { font-family: 'Nunito', sans-serif !important; }
</style>
<link id="all-fonts-link-font-newsreader" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Newsreader:opsz,wght@6..72,400..800&display=swap">
<style id="all-fonts-style-font-newsreader">
.font-newsreader { font-family: 'Newsreader', serif !important; }
</style>
<link id="all-fonts-link-font-google-sans-flex" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Google+Sans+Flex:wght@400;500;600;700&display=swap">
<style id="all-fonts-style-font-google-sans-flex">
.font-google-sans-flex { font-family: 'Google Sans Flex', sans-serif !important; }
</style>
<link id="all-fonts-link-font-oswald" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Oswald:wght@300;400;500;600;700&display=swap">
<style id="all-fonts-style-font-oswald">
.font-oswald { font-family: 'Oswald', sans-serif !important; }
</style>
<link id="all-fonts-link-font-dm-sans" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@300;400;500;600;700&display=swap">
<style id="all-fonts-style-font-dm-sans">
.font-dm-sans { font-family: 'DM Sans', sans-serif !important; }
</style>
<link id="all-fonts-link-font-cormorant" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@300;400;500;600;700&display=swap">
<style id="all-fonts-style-font-cormorant">
.font-cormorant { font-family: 'Cormorant Garamond', serif !important; }
</style>
<style>
/* 3D Transform utilities */
.perspective-none { perspective: none !important; }
.perspective-dramatic { perspective: 100px !important; }
.perspective-near { perspective: 300px !important; }
.perspective-normal { perspective: 500px !important; }
.perspective-midrange { perspective: 800px !important; }
.perspective-distant { perspective: 1200px !important; }
.transform-style-preserve-3d { transform-style: preserve-3d !important; }
.transform-style-flat { transform-style: flat !important; }
</style></head>
<body class="sm:text-base leading-relaxed text-sm opacity-100">
<link id="all-fonts-link-font-geist" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Geist:wght@300;400;500;600;700&display=swap">
<style id="all-fonts-style-font-geist" class="">
.font-geist { font-family: 'Geist', sans-serif !important; }
</style>
<link id="all-fonts-link-font-roboto" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap">
<style id="all-fonts-style-font-roboto" class="">
.font-roboto { font-family: 'Roboto', sans-serif !important; }
</style>
<link id="all-fonts-link-font-montserrat" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500;600;700&display=swap">
<style id="all-fonts-style-font-montserrat" class="">
.font-montserrat { font-family: 'Montserrat', sans-serif !important; }
</style>
<link id="all-fonts-link-font-poppins" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap">
<style id="all-fonts-style-font-poppins" class="">
.font-poppins { font-family: 'Poppins', sans-serif !important; }
</style>
<link id="all-fonts-link-font-playfair" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;500;600;700;900&display=swap">
<style id="all-fonts-style-font-playfair" class="">
.font-playfair { font-family: 'Playfair Display', serif !important; }
</style>
<link id="all-fonts-link-font-instrument-serif" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Instrument+Serif:wght@400;500;600;700&display=swap">
<style id="all-fonts-style-font-instrument-serif" class="">
.font-instrument-serif { font-family: 'Instrument Serif', serif !important; }
</style>
<link id="all-fonts-link-font-merriweather" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Merriweather:wght@300;400;700;900&display=swap">
<style id="all-fonts-style-font-merriweather" class="">
.font-merriweather { font-family: 'Merriweather', serif !important; }
</style>
<link id="all-fonts-link-font-bricolage" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:wght@300;400;500;600;700&display=swap">
<style id="all-fonts-style-font-bricolage" class="">
.font-bricolage { font-family: 'Bricolage Grotesque', sans-serif !important; }
</style>
<link id="all-fonts-link-font-jakarta" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&display=swap">
<style id="all-fonts-style-font-jakarta" class="">
.font-jakarta { font-family: 'Plus Jakarta Sans', sans-serif !important; }
</style>
<link id="all-fonts-link-font-manrope" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@300;400;500;600;700;800&display=swap">
<style id="all-fonts-style-font-manrope" class="">
.font-manrope { font-family: 'Manrope', sans-serif !important; }
</style>
<link id="all-fonts-link-font-space-grotesk" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap">
<style id="all-fonts-style-font-space-grotesk" class="">
.font-space-grotesk { font-family: 'Space Grotesk', sans-serif !important; }
</style>
<link id="all-fonts-link-font-work-sans" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Work+Sans:wght@300;400;500;600;700;800&display=swap">
<style id="all-fonts-style-font-work-sans" class="">
.font-work-sans { font-family: 'Work Sans', sans-serif !important; }
</style>
<link id="all-fonts-link-font-pt-serif" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=PT+Serif:wght@400;700&display=swap">
<style id="all-fonts-style-font-pt-serif">
.font-pt-serif { font-family: 'PT Serif', serif !important; }
</style>
<link id="all-fonts-link-font-geist-mono" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Geist+Mono:wght@300;400;500;600;700&display=swap">
<style id="all-fonts-style-font-geist-mono">
.font-geist-mono { font-family: 'Geist Mono', monospace !important; }
</style>
<link id="all-fonts-link-font-space-mono" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&display=swap">
<style id="all-fonts-style-font-space-mono">
.font-space-mono { font-family: 'Space Mono', monospace !important; }
</style>
<link id="all-fonts-link-font-quicksand" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Quicksand:wght@300;400;500;600;700&display=swap">
<style id="all-fonts-style-font-quicksand">
.font-quicksand { font-family: 'Quicksand', sans-serif !important; }
</style>
<link id="all-fonts-link-font-nunito" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Nunito:wght@300;400;500;600;700;800&display=swap">
<style id="all-fonts-style-font-nunito">
.font-nunito { font-family: 'Nunito', sans-serif !important; }
</style>
<link id="all-fonts-link-font-newsreader" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Newsreader:opsz,wght@6..72,400..800&display=swap">
<style id="all-fonts-style-font-newsreader">
.font-newsreader { font-family: 'Newsreader', serif !important; }
</style>
<link id="all-fonts-link-font-google-sans-flex" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Google+Sans+Flex:wght@400;500;600;700&display=swap">
<style id="all-fonts-style-font-google-sans-flex">
.font-google-sans-flex { font-family: 'Google Sans Flex', sans-serif !important; }
</style>
<link id="all-fonts-link-font-oswald" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Oswald:wght@300;400;500;600;700&display=swap">
<style id="all-fonts-style-font-oswald">
.font-oswald { font-family: 'Oswald', sans-serif !important; }
</style>
<link id="all-fonts-link-font-dm-sans" rel="stylesheet" href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@300;400;500;600;700&display=swap">
<style id="all-fonts-style-font-dm-sans">
.font-dm-sans { font-family: 'DM Sans', sans-serif !important; }
</style>
<!-- NOISE -->
<!-- PRELOADER -->
<!-- NAVIGATION -->
<nav class="fixed top-0 w-full px-6 py-6 md:px-12 flex justify-between items-start z-50 mix-blend-exclusion text-white pointer-events-none">
<div class="flex flex-col">
<div class="display-font cursor-pointer pointer-events-auto text-xl font-bold tracking-tighter" onclick="window.location.href='/home'" role="button">
KAIROS
</div>
<span class="text-[10px] uppercase tracking-widest opacity-60 mt-1 hidden md:block">
Spatial / Digital / Void
</span>
</div>
<div class="hidden md:flex flex-col items-end gap-1 pointer-events-auto">
<a href="/work" class="uppercase hover:line-through transition-all text-xs font-medium tracking-widest">
work
</a>
<a href="/studio" class="uppercase hover:line-through transition-all text-xs font-medium tracking-widest">
Studio
</a>
<a href="/new" class="uppercase hover:line-through transition-all text-xs font-medium tracking-widest">
new
</a>
<a href="/contact" class="uppercase hover:line-through transition-all text-xs font-medium tracking-widest">
Contact
</a>
</div>
<button id="menu-toggle" class="md:hidden pointer-events-auto relative w-8 h-8 flex items-center justify-center">
<svg class="icon-open w-8 h-8 text-white transition-all duration-300 opacity-100" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="4" x2="20" y1="12" y2="12"></line>
<line x1="4" x2="20" y1="6" y2="6"></line>
<line x1="4" x2="20" y1="18" y2="18"></line>
</svg>
<svg class="icon-close w-8 h-8 text-white absolute transition-all duration-300 opacity-0 -rotate-90" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M18 6 6 18"></path>
<path d="M6 6 18 18"></path>
</svg>
</button>
</nav>
<div id="mobile-menu" class="fixed inset-0 z-40 bg-[#0A0A0A] flex flex-col items-center justify-center opacity-0 pointer-events-none transition-all duration-500">
<div id="mobile-menu-content" class="flex flex-col gap-6 text-center translate-y-8 transition-transform duration-500 delay-75">
<a href="/work" class="display-font text-5xl md:text-6xl font-medium tracking-tighter text-white hover:text-gray-400 hover:line-through transition-all uppercase">
Work
</a>
<a href="/studio" class="display-font text-5xl md:text-6xl font-medium tracking-tighter text-white hover:text-gray-400 hover:line-through transition-all uppercase">
Studio
</a>
<a href="/new" class="display-font text-5xl md:text-6xl font-medium tracking-tighter text-white hover:text-gray-400 hover:line-through transition-all uppercase">
New
</a>
<a href="/contact" class="display-font text-5xl md:text-6xl font-medium tracking-tighter text-white hover:text-gray-400 hover:line-through transition-all uppercase">
Contact
</a>
</div>
</div>
<!-- WRAPPER (White Content) -->
<div class="wrapper">
<!-- HERO -->
<section id="hero" class="relative flex flex-col items-center justify-center overflow-hidden bg-[#050505] h-[100dvh]">
<div class="absolute inset-0 w-full h-full opacity-60">
<div class="absolute inset-0 z-10 bg-[#050505]">
<img src="https://hoirqrkdgbmvpwutwuwj.supabase.co/storage/v1/object/public/assets/assets/fad8f488-a92f-419e-a506-95dab967d5f0_3840w.jpg" alt="Hero Background" class="absolute inset-0 w-full h-full object-cover opacity-80 mix-blend-normal">
<div class="absolute inset-0 bg-gradient-to-b from-[#050505] via-transparent to-[#050505]"></div>
<div class="bg-black/20 absolute top-0 right-0 bottom-0 left-0"></div>
</div>
<video autoplay="" muted="" loop="" playsinline="" class="w-full h-full object-cover grayscale brightness-50">
<source src="https://assets.mixkit.co/videos/preview/mixkit-abstract-video-of-a-man-in-white-clothes-walking-in-39634-large.mp4" type="video/mp4">
</video>
</div>
<div class="md:px-32 flex flex-col md:flex-row text-white w-full z-20 pr-12 pl-12 relative items-center justify-between">
<h1 class="hero-title-l display-font text-[10vw] leading-[0.8] font-medium text-white tracking-tighter" style="translate: none; rotate: none; scale: none; opacity: 1; transform: translate(0px, 0px);">
KAIROS
</h1>
<h1 class="hero-title-r display-font text-[10vw] leading-[0.8] md:text-right font-medium italic tracking-tighter text-white" style="translate: none; rotate: none; scale: none; opacity: 1; transform: translate(0px, 0px);">
STUDIO
</h1>
</div>
<div class="absolute bottom-12 w-full px-6 md:px-12 flex justify-between items-end text-white/50 text-xs font-mono uppercase tracking-widest mix-blend-exclusion z-30">
<div class="hidden md:block">Oslo, Norway</div>
<div class="animate-bounce">Scroll to Explore</div>
<div class="hidden md:block">Est. 2021</div>
</div>
</section>
<!-- INTRO -->
<section class="py-24 bg-[#050505] text-white overflow-hidden border-b border-white/10">
<div class="marquee-container">
<div class="marquee-content display-font text-[8vw] md:text-[6vw] font-medium leading-none tracking-tight text-transparent stroke-text" style="animation-duration: 60s;">
RESIDENTIAL — CULTURAL — DIGITAL — EXPERIMENTAL — ARCHIVE —
DESIGNING THE VOID — ARCHITECTURE OF SILENCE — FORM FOLLOWS FICTION
</div>
</div>
<style>
.stroke-text { -webkit-text-stroke: 1px rgba(255,255,255,0.4); }
</style>
</section>
<!-- WORKS STACK -->
<section class="relative bg-[#050505] text-white">
<section id="archive-list" class="relative py-24 px-6 md:px-12 bg-[#050505] text-white z-10">
<div class="max-w-[1800px] mx-auto">
<div class="flex flex-col md:flex-row justify-between items-end mb-24">
<h2 class="display-font text-6xl md:text-9xl tracking-tighter leading-none">
INDEX
</h2>
<div class="flex gap-8 text-xs font-mono uppercase tracking-widest text-gray-500 mb-2">
<button class="text-white border-b border-white pb-1">
All
</button>
<button class="hover:text-white transition-colors pb-1">
Architecture
</button>
<button class="hover:text-white transition-colors pb-1">
Interior
</button>
<button class="hover:text-white transition-colors pb-1">
Digital
</button>
</div>
</div>
<div class="border-t border-white/20">
<!-- Item 01 -->
<div class="archive-item group relative border-b border-white/10">
<div class="flex flex-col md:flex-row py-8 md:items-center relative z-20 mix-blend-difference">
<div class="md:w-1/12 text-xs font-mono text-gray-500">
01
</div>
<div class="md:w-5/12">
<h3 class="display-font text-4xl md:text-6xl group-hover:pl-8 transition-all duration-300">
VOID RES.
</h3>
</div>
<div class="md:w-3/12 text-sm font-light text-gray-400 mt-2 md:mt-0">
Kyoto, Japan
</div>
<div class="md:w-2/12 text-xs font-mono uppercase tracking-widest text-gray-500 mt-2 md:mt-0">
Residential
</div>
<div class="md:w-1/12 flex justify-end opacity-0 group-hover:opacity-100 transition-opacity">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="w-6 h-6">
<path d="M7 17L17 7"></path>
<path d="M7 7h10v10"></path>
</svg>
</div>
</div>
<img src="https://images.unsplash.com/photo-1678694270945-fda8641bdb0a?w=3840&q=80" class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[40vw] aspect-video object-cover grayscale opacity-0 group-hover:opacity-60 transition-opacity duration-500 pointer-events-none z-10 hidden md:block">
</div>
<!-- Item 02 -->
<div class="archive-item group relative border-b border-white/10">
<div class="flex flex-col md:flex-row py-8 md:items-center relative z-20 mix-blend-difference">
<div class="md:w-1/12 text-xs font-mono text-gray-500">
02
</div>
<div class="md:w-5/12">
<h3 class="display-font text-4xl md:text-6xl group-hover:pl-8 transition-all duration-300">
AETHER
</h3>
</div>
<div class="md:w-3/12 text-sm font-light text-gray-400 mt-2 md:mt-0">
Berlin, Germany
</div>
<div class="md:w-2/12 text-xs font-mono uppercase tracking-widest text-gray-500 mt-2 md:mt-0">
Cultural
</div>
<div class="md:w-1/12 flex justify-end opacity-0 group-hover:opacity-100 transition-opacity">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="w-6 h-6">
<path d="M7 17L17 7"></path>
<path d="M7 7h10v10"></path>
</svg>
</div>
</div>
<img src="https://images.unsplash.com/photo-1683029083464-4b28b07d7f09?w=1600&q=80" class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[40vw] aspect-video object-cover grayscale opacity-0 group-hover:opacity-60 transition-opacity duration-500 pointer-events-none z-10 hidden md:block">
</div>
<!-- Item 03 -->
<div class="archive-item group relative border-b border-white/10">
<div class="flex flex-col md:flex-row py-8 md:items-center relative z-20 mix-blend-difference">
<div class="md:w-1/12 text-xs font-mono text-gray-500">
03
</div>
<div class="md:w-5/12">
<h3 class="display-font text-4xl md:text-6xl group-hover:pl-8 transition-all duration-300">
ECHO TWR.
</h3>
</div>
<div class="md:w-3/12 text-sm font-light text-gray-400 mt-2 md:mt-0">
Seattle, WA
</div>
<div class="md:w-2/12 text-xs font-mono uppercase tracking-widest text-gray-500 mt-2 md:mt-0">
Commercial
</div>
<div class="md:w-1/12 flex justify-end opacity-0 group-hover:opacity-100 transition-opacity">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="w-6 h-6">
<path d="M7 17L17 7"></path>
<path d="M7 7h10v10"></path>
</svg>
</div>
</div>
<img src="https://images.unsplash.com/photo-1651551590552-33174178e327?w=3840&q=80" class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[40vw] aspect-video object-cover grayscale opacity-0 group-hover:opacity-60 transition-opacity duration-500 pointer-events-none z-10 hidden md:block">
</div>
<!-- Item 04 -->
<div class="archive-item group relative border-b border-white/10">
<div class="flex flex-col md:flex-row py-8 md:items-center relative z-20 mix-blend-difference">
<div class="md:w-1/12 text-xs font-mono text-gray-500">
04
</div>
<div class="md:w-5/12">
<h3 class="display-font text-4xl md:text-6xl group-hover:pl-8 transition-all duration-300">
MONOLITH
</h3>
</div>
<div class="md:w-3/12 text-sm font-light text-gray-400 mt-2 md:mt-0">
Oslo, Norway
</div>
<div class="md:w-2/12 text-xs font-mono uppercase tracking-widest text-gray-500 mt-2 md:mt-0">
Installation
</div>
<div class="md:w-1/12 flex justify-end opacity-0 group-hover:opacity-100 transition-opacity">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="w-6 h-6">
<path d="M7 17L17 7"></path>
<path d="M7 7h10v10"></path>
</svg>
</div>
</div>
<img src="https://images.unsplash.com/photo-1594317568093-b27c52bb8d73?w=1600&q=80" class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[40vw] aspect-video object-cover grayscale opacity-0 group-hover:opacity-60 transition-opacity duration-500 pointer-events-none z-10 hidden md:block">
</div>
<!-- Item 05 -->
<div class="archive-item group relative border-b border-white/10">
<div class="flex flex-col md:flex-row py-8 md:items-center relative z-20 mix-blend-difference">
<div class="md:w-1/12 text-xs font-mono text-gray-500">
05
</div>
<div class="md:w-5/12">
<h3 class="display-font text-4xl md:text-6xl group-hover:pl-8 transition-all duration-300">
SÄKRA
</h3>
</div>
<div class="md:w-3/12 text-sm font-light text-gray-400 mt-2 md:mt-0">
Stockholm, SWE
</div>
<div class="md:w-2/12 text-xs font-mono uppercase tracking-widest text-gray-500 mt-2 md:mt-0">
Digital
</div>
<div class="md:w-1/12 flex justify-end opacity-0 group-hover:opacity-100 transition-opacity">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="w-6 h-6">
<path d="M7 17L17 7"></path>
<path d="M7 7h10v10"></path>
</svg>
</div>
</div>
<img src="https://images.unsplash.com/photo-1592202681439-58723118d3d1?w=3840&q=80" class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[40vw] aspect-video object-cover grayscale opacity-0 group-hover:opacity-60 transition-opacity duration-500 pointer-events-none z-10 hidden md:block">
</div>
</div>
</div>
</section>
</section>
<section id="featured-detail" class="bg-[#0A0A0A] text-white px-6 md:px-12 border-t border-white/10 py-20 md:py-32">
<div class="max-w-[1800px] mx-auto">
<div class="mb-24">
<h2 class="text-xs font-mono uppercase tracking-widest text-gray-500 mb-4">
In Depth
</h2>
<p class="display-font text-4xl md:text-6xl max-w-2xl leading-tight">
CASE STUDY 01:
<span class="text-gray-500">VOID RESIDENCE</span>
</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-12 md:gap-24">
<div class="relative">
<div class="sticky top-32">
<p class="text-lg md:text-xl font-light leading-relaxed text-gray-400 mb-12">
Located in the dense urban fabric of Kyoto, the Void Residence
turns inward. A series of concrete planes fold to create a
central courtyard—a lung for the house that captures light and
rain.
</p>
<div class="grid grid-cols-2 gap-8 text-xs font-mono uppercase tracking-widest text-gray-500">
<div>
<span class="block text-white mb-2">Status</span>
Completed 2023
</div>
<div>
<span class="block text-white mb-2">Area</span>
240 SQM
</div>
<div>
<span class="block text-white mb-2">Team</span>
J. Doe, A. Smith
</div>
<div>
<span class="block text-white mb-2">Photo</span>
K. Yamashita
</div>
</div>
</div>
</div>
<div class="flex flex-col gap-8">
<img src="https://hoirqrkdgbmvpwutwuwj.supabase.co/storage/v1/object/public/assets/assets/97c65e8c-b22b-4453-854a-d8fcd8c0189d_1600w.webp" class="w-full aspect-[4/5] object-cover grayscale contrast-125 hover:grayscale-0 transition-all duration-700">
<img src="https://hoirqrkdgbmvpwutwuwj.supabase.co/storage/v1/object/public/assets/assets/275ff158-0484-45d3-89b9-491a0c2bc5cd_1600w.webp" class="w-full aspect-[4/3] object-cover grayscale contrast-125 hover:grayscale-0 transition-all duration-700">
<div class="bg-[#111] p-12 flex items-center justify-center text-center border border-white/10 aspect-square">
<p class="display-font text-3xl">
"SILENCE IS NOT EMPTY. IT IS FULL OF ANSWERS."
</p>
</div>
</div>
</div>
</div>
</section>
<section id="horiz-scroll" class="relative bg-[#EAEAEA] text-black overflow-hidden py-24 md:py-0 md:h-screen flex flex-col md:flex-row items-center">
<div class="horiz-wrap flex flex-col md:flex-row gap-8 md:gap-16 px-6 md:px-24 items-start md:items-center w-full md:w-auto will-change-transform">
<div class="flex-shrink-0 w-full md:w-[30vw] flex flex-col gap-6">
<h2 class="display-font text-6xl md:text-8xl tracking-tighter">
PROCESS
</h2>
<p class="text-lg md:text-xl font-light text-gray-600 max-w-sm">
We define the void before we build the walls. A subtractive
methodology.
</p>
</div>
<div class="card-item flex-shrink-0 w-full md:w-[25vw] aspect-[3/4] bg-white p-8 flex flex-col justify-between group hover:shadow-2xl transition-all duration-500 perspective-midrange">
<div class="card-inner w-full h-full flex flex-col justify-between">
<span class="font-mono text-xs tracking-widest text-gray-400">
01 — CONCEPT
</span>
<div class="h-3/5 overflow-hidden">
<img src="https://images.unsplash.com/photo-1600607686527-6fb886090705?q=80&w=1200" class="object-cover w-full h-full grayscale group-hover:scale-110 transition-transform duration-700">
</div>
<p class="text-sm font-medium">
Sketching the invisible lines of force.
</p>
</div>
</div>
<div class="card-item flex-shrink-0 w-full md:w-[25vw] aspect-[3/4] bg-white p-8 flex flex-col justify-between group hover:shadow-2xl transition-all duration-500 perspective-midrange">
<div class="card-inner w-full h-full flex flex-col justify-between">
<span class="font-mono text-xs tracking-widest text-gray-400">
02 — MATERIALITY
</span>
<div class="h-3/5 overflow-hidden">
<img src="https://images.unsplash.com/photo-1519710164239-da123dc03ef4?q=80&w=1200" class="object-cover w-full h-full grayscale group-hover:scale-110 transition-transform duration-700">
</div>
<p class="text-sm font-medium">
Selecting textures that catch the light.
</p>
</div>
</div>
<div class="card-item flex-shrink-0 w-full md:w-[25vw] aspect-[3/4] bg-white p-8 flex flex-col justify-between group hover:shadow-2xl transition-all duration-500 perspective-midrange">
<div class="card-inner w-full h-full flex flex-col justify-between">
<span class="font-mono text-xs tracking-widest text-gray-400">
03 — VOID
</span>
<div class="h-3/5 overflow-hidden">
<img src="https://images.unsplash.com/photo-1668910251266-081835549c07?w=3840&q=80" class="object-cover w-full h-full grayscale group-hover:scale-110 transition-transform duration-700">
</div>
<p class="text-sm font-medium">
Precision in every joint and shadow.
</p>
</div>
</div>
<div class="flex-shrink-0 w-full md:w-[15vw] flex items-center justify-center py-12 md:py-0">
<div class="w-24 h-24 rounded-full border border-black flex items-center justify-center animate-[spin_10s_linear_infinite]">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-lucide="arrow-right" class="lucide lucide-arrow-right w-6 h-6">
<path d="M5 12h14"></path>
<path d="m12 5 7 7-7 7"></path>
</svg>
</div>
</div>
</div>
</section>
<!-- PHILOSOPHY / SPACER -->
<section id="inverted-section" class="px-6 bg-[#EAEAEA] text-[#050505] flex flex-col items-center justify-center text-center relative overflow-hidden py-24 md:py-48">
<div class="max-w-4xl z-10">
<div class="overflow-hidden">
<h2 class="reveal-item display-font text-6xl md:text-9xl tracking-tighter mb-2" style="translate: none; rotate: none; scale: none; opacity: 0; transform: translate(0px, 100px);">
REDUCTIVE
</h2>
</div>
<div class="overflow-hidden">
<h2 class="reveal-item display-font text-6xl md:text-9xl tracking-tighter mb-12 italic font-serif" style="translate: none; rotate: none; scale: none; opacity: 0; transform: translate(0px, 100px);">
ESSENTIALISM
</h2>
</div>
<div class="w-full h-px bg-black/20 mb-12 reveal-item scale-x-0 origin-left" style="translate: none; rotate: none; scale: none; opacity: 0; transform: translate(0px, 100px);"></div>
<p class="reveal-item text-xl md:text-2xl font-light leading-relaxed max-w-2xl mx-auto text-gray-600" style="translate: none; rotate: none; scale: none; opacity: 0; transform: translate(0px, 100px);">
We do not decorate. We do not cover. We reveal.
<br>
Architecture is not about adding to the world, but framing what is
already there.
<span class="block mt-12 font-mono text-xs uppercase tracking-widest text-black">
— The Kairos Manifesto, 2025
</span>
</p>
</div>
</section>
</div>
<!-- END WRAPPER -->
<!-- FOOTER (FIXED) -->
<footer class="relative bg-white text-black pb-12 px-6 md:px-12 pt-20 md:pt-32">
<div class="max-w-[1800px] mx-auto">
<div class="grid md:grid-cols-2 gap-12 mb-32">
<div>
<h2 class="display-font text-[12vw] leading-[0.8] tracking-tighter mb-8">
NEXT?
</h2>
<a href="mailto:hello@kairos.com" class="inline-block border-b-2 border-black pb-1 text-xl md:text-3xl hover:opacity-50 transition-opacity">
hello@kairos.com
</a>
</div>
<div class="flex flex-col justify-end items-start md:items-end">
<p class="max-w-md text-lg md:text-xl font-light leading-relaxed mb-8 md:text-right">
We are currently accepting new commissions for 2025. Let's discuss
the void.
</p>
<div class="flex gap-4">
<a href="#" class="w-12 h-12 rounded-full border border-black/10 flex items-center justify-center hover:bg-black hover:text-white transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-lucide="instagram" class="lucide lucide-instagram w-5 h-5">
<rect width="20" height="20" x="2" y="2" rx="5" ry="5"></rect>
<path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"></path>
<line x1="17.5" x2="17.51" y1="6.5" y2="6.5"></line>
</svg>
</a>
<a href="#" class="w-12 h-12 rounded-full border border-black/10 flex items-center justify-center hover:bg-black hover:text-white transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-lucide="linkedin" class="lucide lucide-linkedin w-5 h-5">
<path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z"></path>
<rect width="4" height="12" x="2" y="9"></rect>
<circle cx="4" cy="4" r="2"></circle>
</svg>
</a>
</div>
</div>
</div>
<div class="flex flex-col md:flex-row justify-between items-end border-t border-black/10 pt-8">
<div class="flex flex-col gap-1">
<span class="text-[10px] uppercase tracking-widest font-bold">
Kairos Studio
</span>
<span class="text-[10px] uppercase tracking-widest text-gray-500">
Akersgata 12, Oslo
</span>
</div>
<div class="flex gap-8 mt-8 md:mt-0">
<a href="#" class="text-[10px] uppercase tracking-widest hover:underline">
Legal
</a>
<a href="#" class="text-[10px] uppercase tracking-widest hover:underline">
Privacy
</a>
<span class="text-[10px] uppercase tracking-widest text-gray-400">
© 2025
</span>
</div>
</div>
</div>
</footer>
<script>
lucide.createIcons();
const lenis = new Lenis({ duration: 1.2, easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)), smooth: true });
function raf(time) { lenis.raf(time); requestAnimationFrame(raf); }
requestAnimationFrame(raf);
gsap.registerPlugin(ScrollTrigger);
const splitTextToScrub = (el) => {
if(!el) return;
const text = el.innerText;
el.innerHTML = text.split(' ').map(word => `<span class="scrub-word inline-block opacity-10 transition-colors duration-200">${word} </span>`).join('');
};
const initAnimations = () => {
// 1. Hero Entrance (Loader removed)
const tl = gsap.timeline();
// Start hero animations immediately
tl.to('.hero-img', { opacity: 1, scale: 1, duration: 2, ease: 'expo.out' }, 0)
.from('.hero-title-l', { x: -100, opacity: 0, duration: 1.5, ease: 'power3.out' }, 0.2)
.from('.hero-title-r', { x: 100, opacity: 0, duration: 1.5, ease: 'power3.out' }, 0.2);
// 2. Hero Parallax
if(document.querySelector('.hero-title-l')) {
gsap.to('.hero-title-l', { x: '-20%', ease: 'none', scrollTrigger: { trigger: '#hero', start: 'top top', end: 'bottom top', scrub: true } });
gsap.to('.hero-title-r', { x: '20%', ease: 'none', scrollTrigger: { trigger: '#hero', start: 'top top', end: 'bottom top', scrub: true } });
gsap.to('.hero-img', { y: '15%', ease: 'none', scrollTrigger: { trigger: '#hero', start: 'top top', end: 'bottom top', scrub: true } });
}
// 3. Intro Text Scrub
const introText = document.querySelector('.intro-scrub-text');
if(introText) {
splitTextToScrub(introText);
gsap.to('.scrub-word', { opacity: 1, color: '#000', stagger: 0.1, ease: 'none', scrollTrigger: { trigger: introText, start: 'top 85%', end: 'bottom 45%', scrub: true } });
}
// 4. Project Sticky List
if (window.innerWidth > 768) {
const projectWrapper = document.querySelector('.project-wrapper');
if(projectWrapper) {
ScrollTrigger.create({ trigger: '.project-wrapper', start: 'top top', end: 'bottom bottom', pin: '.project-images' });
const projects = document.querySelectorAll('.project-item');
const images = document.querySelectorAll('.project-img-container');
projects.forEach((item, i) => {
ScrollTrigger.create({
trigger: item, start: 'top center', end: 'bottom center',
onEnter: () => { images.forEach(img => img.classList.remove('active')); if(images[i]) images[i].classList.add('active'); item.classList.add('active'); },
onEnterBack: () => { images.forEach(img => img.classList.remove('active')); if(images[i]) images[i].classList.add('active'); item.classList.add('active'); },
onLeave: () => item.classList.remove('active'),
onLeaveBack: () => item.classList.remove('active')
});
});
}
}
// 5. Horizontal Scroll
const horizSection = document.querySelector('#horiz-scroll');
if (horizSection && window.innerWidth > 768) {
const horizWrap = horizSection.querySelector('.horiz-wrap');
gsap.to(horizWrap, {
x: () => -(horizWrap.scrollWidth - window.innerWidth),
ease: "none",
scrollTrigger: {
trigger: horizSection,
start: "top top",
end: () => `+=${horizWrap.scrollWidth}`,
pin: true,
scrub: 1,
invalidateOnRefresh: true
}
});
}
// 6. Parallax Grid
const parallaxGrid = document.querySelector('#parallax-grid');
if (parallaxGrid) {
const cols = parallaxGrid.querySelectorAll('.parallax-col');
cols.forEach((col, i) => {
const speed = (i + 1) * 50;
gsap.to(col, {
y: (i % 2 === 0 ? -speed : speed),
ease: "none",
scrollTrigger: { trigger: parallaxGrid, start: "top bottom", end: "bottom top", scrub: true }
});
});
}
// 7. Inverted Reveal
const darkSection = document.querySelector('#inverted-section');
if (darkSection) {
const items = darkSection.querySelectorAll('.reveal-item');
gsap.fromTo(items,
{ y: 100, opacity: 0 },
{ y: 0, opacity: 1, duration: 1, stagger: 0.1, ease: "power4.out", scrollTrigger: { trigger: darkSection, start: "top 60%" } }
);
gsap.to(darkSection.querySelector('.w-full.h-px'), {
scaleX: 1, duration: 1.5, ease: "expo.out", scrollTrigger: { trigger: darkSection, start: "top 60%" }
});
}
};
document.body.style.opacity = 1;
initAnimations();
</script>
<script>
(function() {
const btn = document.getElementById('menu-toggle');
const menu = document.getElementById('mobile-menu');
const content = document.getElementById('mobile-menu-content');
const iconOpen = btn.querySelector('.icon-open');
const iconClose = btn.querySelector('.icon-close');
let isOpen = false;
btn.addEventListener('click', () => {
isOpen = !isOpen;
if (isOpen) {
menu.classList.remove('opacity-0', 'pointer-events-none');
content.classList.remove('translate-y-8');
iconOpen.classList.replace('opacity-100', 'opacity-0');
iconOpen.classList.add('rotate-90');
iconClose.classList.replace('opacity-0', 'opacity-100');
iconClose.classList.remove('-rotate-90');
document.body.style.overflow = 'hidden';
} else {
menu.classList.add('opacity-0', 'pointer-events-none');
content.classList.add('translate-y-8');
iconOpen.classList.replace('opacity-0', 'opacity-100');
iconOpen.classList.remove('rotate-90');
iconClose.classList.replace('opacity-100', 'opacity-0');
iconClose.classList.add('-rotate-90');
document.body.style.overflow = '';
}
});
})();
</script>
</body></html>