Coming Soon — Snow Site

.coming-soon-container {
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 56px 20px 64px;
gap: 10px;
text-align: center;
position: relative;
overflow: hidden;
}

.coming-soon-title {
font-size: clamp(48px, 10vw, 120px);
font-weight: 900;
line-height: 0.9;
letter-spacing: -0.04em;
text-transform: uppercase;
margin: 0 0 14px;
position: relative;
z-index: 2;
}

.coming-soon-title .highlight {
color: var(–ink);
display: block;
}

.coming-soon-subtitle {
font-size: clamp(18px, 3vw, 28px);
font-weight: 600;
letter-spacing: -0.02em;
margin: 0 0 30px;
color: var(–muted);
position: relative;
z-index: 2;
}

.coming-soon-message {
max-width: 500px;
font-size: 16px;
line-height: 1.6;
color: var(–muted);
margin: 0 0 40px;
position: relative;
z-index: 2;
}

.back-home {
position: relative;
z-index: 2;
}

/* Animated background elements */
.bg-dots {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
opacity: 0.08;
overflow: hidden;
}

.bg-dot {
position: absolute;
width: 8px;
height: 8px;
background: var(–ink);
border-radius: 50%;
animation: float 20s infinite ease-in-out;
}

.snow {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 1;
overflow: hidden;
}

.flake {
position: absolute;
top: -12px;
width: 5px;
height: 5px;
background: rgba(255, 255, 255, 0.8);
border-radius: 50%;
animation: snow 6.8s linear infinite;
filter: blur(0.4px);
}

.flake:nth-child(1) { left: 6%; animation-duration: 7.4s; opacity: 0.7; animation-delay: -1s; }
.flake:nth-child(2) { left: 12%; animation-duration: 6.2s; opacity: 0.6; animation-delay: -2s; }
.flake:nth-child(3) { left: 18%; animation-duration: 7.8s; opacity: 0.7; animation-delay: -3s; }
.flake:nth-child(4) { left: 24%; animation-duration: 6.6s; opacity: 0.55; animation-delay: -1.5s; }
.flake:nth-child(5) { left: 30%; animation-duration: 7.2s; opacity: 0.65; animation-delay: -2.5s; }
.flake:nth-child(6) { left: 36%; animation-duration: 6.4s; opacity: 0.6; animation-delay: -3.5s; }
.flake:nth-child(7) { left: 42%; animation-duration: 7.6s; opacity: 0.7; animation-delay: -0.5s; }
.flake:nth-child(8) { left: 48%; animation-duration: 6.8s; opacity: 0.6; animation-delay: -4s; }
.flake:nth-child(9) { left: 54%; animation-duration: 7.4s; opacity: 0.7; animation-delay: -2.2s; }
.flake:nth-child(10) { left: 60%; animation-duration: 6.3s; opacity: 0.6; animation-delay: -1.2s; }
.flake:nth-child(11) { left: 66%; animation-duration: 7.9s; opacity: 0.75; animation-delay: -3.2s; }
.flake:nth-child(12) { left: 72%; animation-duration: 6.5s; opacity: 0.6; animation-delay: -0.8s; }
.flake:nth-child(13) { left: 78%; animation-duration: 7.1s; opacity: 0.7; animation-delay: -2.8s; }
.flake:nth-child(14) { left: 84%; animation-duration: 6.6s; opacity: 0.6; animation-delay: -1.8s; }
.flake:nth-child(15) { left: 90%; animation-duration: 7.7s; opacity: 0.65; animation-delay: -3.8s; }
.flake:nth-child(16) { left: 96%; animation-duration: 6.9s; opacity: 0.55; animation-delay: -2.6s; }

.bg-dot:nth-child(1) { top: 10%; left: 15%; animation-delay: 0s; }
.bg-dot:nth-child(2) { top: 60%; left: 80%; animation-delay: 3s; }
.bg-dot:nth-child(3) { top: 30%; left: 70%; animation-delay: 6s; }
.bg-dot:nth-child(4) { top: 80%; left: 25%; animation-delay: 9s; }
.bg-dot:nth-child(5) { top: 45%; left: 50%; animation-delay: 12s; }

@keyframes float {
0%, 100% {
transform: translate(0, 0) scale(1);
}
25% {
transform: translate(30px, -30px) scale(1.2);
}
50% {
transform: translate(-20px, 40px) scale(0.8);
}
75% {
transform: translate(40px, 20px) scale(1.1);
}
}

.loading-bar {
width: 200px;
height: 3px;
background: var(–soft);
border-radius: 2px;
overflow: hidden;
margin: 22px auto 0;
position: relative;
z-index: 2;
}

.loading-bar-fill {
height: 100%;
background: var(–ink);
animation: loading 2s ease-in-out infinite;
}

@keyframes loading {
0% {
width: 0%;
margin-left: 0%;
}
50% {
width: 100%;
margin-left: 0%;
}
100% {
width: 0%;
margin-left: 100%;
}
}

@keyframes snow {
0% {
transform: translateY(0) translateX(0);
opacity: 0;
}
10% {
opacity: 0.6;
}
100% {
transform: translateY(240px) translateX(18px);
opacity: 0;
}
}

@keyframes puff {
0% {
transform: translate(-50%, -50%) scale(0.8);
opacity: 0.8;
}
100% {
transform: translate(calc(-50% + var(–dx, 0px)), calc(-50% + var(–dy, 0px))) scale(1.4);
opacity: 0;
}
}

.status-pill {
display: inline-block;
padding: 6px 16px;
background: rgba(0, 0, 0, 0.06);
color: var(–ink);
font-size: 11px;
font-weight: 700;
letter-spacing: 0.1em;
text-transform: uppercase;
border-radius: 999px;
margin-bottom: 6px;
position: relative;
z-index: 2;
}

/* Skier scene */
.scene {
width: min(720px, 92vw);
height: 260px;
margin: 14px 0 30px;
position: relative;
z-index: 2;
–mountain-width: 600px;
–mountain-height: 230px;
–mountain-bottom: 30px;
}

.mountain {
position: absolute;
bottom: var(–mountain-bottom);
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-left: calc(var(–mountain-width) / 2) solid transparent;
border-right: calc(var(–mountain-width) / 2) solid transparent;
border-bottom: var(–mountain-height) solid var(–soft);
filter: drop-shadow(0 12px 18px rgba(0, 0, 0, 0.08));
}

.snowline {
position: absolute;
bottom: 26px;
left: 8%;
right: 8%;
height: 3px;
background: linear-gradient(90deg, transparent, var(–line), transparent);
}

.skier {
position: absolute;
top: 0;
left: 0;
width: 52px;
height: 52px;
transform-origin: center;
transition: transform 0.08s linear;
pointer-events: none;
}

.skier .head {
position: absolute;
top: 2px;
left: 20px;
width: 10px;
height: 10px;
background: var(–ink);
border-radius: 999px;
}

.skier .body {
position: absolute;
top: 12px;
left: 22px;
width: 4px;
height: 18px;
background: var(–ink);
border-radius: 2px;
transform: rotate(10deg);
}

.skier .ski {
position: absolute;
top: 30px;
left: 8px;
width: 36px;
height: 3px;
background: #1b67ff;
border-radius: 2px;
transform: rotate(-18deg);
box-shadow: 0 6px 0 0 #1b67ff;
}

.skier .trail {
position: absolute;
top: 36px;
left: -40px;
width: 40px;
height: 2px;
background: linear-gradient(90deg, transparent, rgba(0, 0, 0, 0.35));
opacity: 0.7;
}

.particles {
position: absolute;
inset: 0;
pointer-events: none;
z-index: 2;
}

.particle {
position: absolute;
width: 6px;
height: 6px;
background: rgba(130, 130, 130, 0.7);
border-radius: 50%;
transform: translate(-50%, -50%);
animation: puff 0.8s ease-out forwards;
}

.skier.flip-back {
animation: flipBack 0.6s ease-out;
}

.skier.flip-front {
animation: flipFront 0.6s ease-out;
}

.instructions {
position: absolute;
right: 12vw;
top: 50%;
transform: translateY(-50%);
width: min(320px, 52vw);
text-align: left;
padding: 18px 18px;
border: 1px solid var(–line);
border-radius: 0;
background: rgba(255, 255, 255, 0.85);
font-size: 14px;
letter-spacing: 0.03em;
text-transform: uppercase;
color: var(–ink);
z-index: 2;
}

.instructions strong {
display: block;
font-size: 12px;
letter-spacing: 0.14em;
color: var(–muted);
margin-bottom: 10px;
}

.rule {
padding: 8px 0;
line-height: 1.4;
}

.rule + .rule {
border-top: 1px solid var(–line);
}

@keyframes flipBack {
0% {
transform: translate(var(–x, 0px), var(–y, 0px)) rotate(0deg);
}
60% {
transform: translate(var(–x, 0px), var(–y, 0px)) rotate(200deg);
}
100% {
transform: translate(var(–x, 0px), var(–y, 0px)) rotate(360deg);
}
}

@keyframes flipFront {
0% {
transform: translate(var(–x, 0px), var(–y, 0px)) rotate(0deg);
}
60% {
transform: translate(var(–x, 0px), var(–y, 0px)) rotate(-200deg);
}
100% {
transform: translate(var(–x, 0px), var(–y, 0px)) rotate(-360deg);
}
}

.badge {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 16px;
border: 1px solid var(–line);
border-radius: 999px;
font-size: 12px;
letter-spacing: 0.08em;
text-transform: uppercase;
font-weight: 700;
color: var(–ink);
background: rgba(255, 255, 255, 0.7);
margin-bottom: 10px;
z-index: 2;
position: relative;
}

@keyframes ski {
0% {
transform: translateX(0) translateY(0) rotate(-4deg);
}
100% {
transform: translateX(0) translateY(0) rotate(-4deg);
}
}

Under Construction

COMING
SOON



Back to Home

// Auto-detect and apply mode from referrer or default to ski
const params = new URLSearchParams(window.location.search);
const mode = params.get(‘mode’) || ‘ski’;
document.body.dataset.mode = mode;

const scene = document.querySelector(‘.scene’);
const skier = document.querySelector(‘.skier’);
const particles = document.querySelector(‘.particles’);

const clamp = (value, min, max) => Math.max(min, Math.min(max, value));

const spawnParticle = (x, y) => {
if (!particles) return;
const particle = document.createElement(‘span’);
particle.className = ‘particle’;
const dx = (Math.random() – 0.5) * 30;
const dy = (Math.random() – 0.5) * 24;
particle.style.left = `${x}px`;
particle.style.top = `${y}px`;
particle.style.setProperty(‘–dx’, `${dx}px`);
particle.style.setProperty(‘–dy’, `${dy}px`);
particles.appendChild(particle);
setTimeout(() => particle.remove(), 900);
};

const updateSkier = (event) => {
if (!scene || !skier) return;
const rect = scene.getBoundingClientRect();
const x = event.clientX – rect.left;
const y = event.clientY – rect.top;

const withinScene = x >= 0 && x = 0 && y = apexY && y <= baseYCoord;
const mountainHalfAtY = (y – apexY) * slopeX;
const withinMountainX = Math.abs(x – centerX) scene?.classList.remove(‘carving’));

let flipTimeout;
window.addEventListener(‘wheel’, (event) => {
if (!skier) return;
skier.classList.remove(‘flip-back’, ‘flip-front’);
void skier.offsetWidth;
if (event.deltaY > 0) {
skier.classList.add(‘flip-front’);
} else if (event.deltaY {
skier.classList.remove(‘flip-back’, ‘flip-front’);
}, 650);
}, { passive: true });