<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Merry Christmas • Happy New Year</title>
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;800&family=Great+Vibes&display=swap" rel="stylesheet">
<style>
:root{
--bg1: #0f1724;
--bg2: #081126;
--accent: #ffcf6b;
--accent-2: #7be6ff;
--card: rgba(255,255,255,0.04);
--glass: rgba(255,255,255,0.06);
--text: #e6f2ff;
--muted: rgba(230,242,255,0.65);
}
*{box-sizing:border-box}
html,body{height:100%}
body{
margin:0;
background: radial-gradient(1200px 600px at 10% 20%, rgba(88,116,255,0.08), transparent),
linear-gradient(180deg,var(--bg1), var(--bg2) 60%);
font-family: 'Poppins', system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial;
color:var(--text);
-webkit-font-smoothing:antialiased;
-moz-osx-font-smoothing:grayscale;
overflow-x:hidden;
display:flex;
align-items:center;
justify-content:center;
padding:32px;
}
.container{
width:min(1100px, 96%);
display:grid;
grid-template-columns: 1fr 420px;
gap:28px;
align-items:center;
}
/* card */
.hero{
background: linear-gradient(180deg, rgba(255,255,255,0.02), rgba(255,255,255,0.01));
border-radius:20px;
padding:48px;
position:relative;
overflow:hidden;
box-shadow: 0 10px 30px rgba(3,8,20,0.6);
border: 1px solid rgba(255,255,255,0.03);
}
/* festive lights */
.light-strings{
position:absolute;
left: -6%;
top: -6%;
width:112%;
height:30%;
pointer-events:none;
transform:translateY(-6%);
}
.light{
position:absolute;
height:12px;
width:12px;
border-radius:50%;
opacity:0.95;
box-shadow: 0 0 8px rgba(255,255,255,0.12), 0 0 18px currentColor;
transform-origin:center;
animation: glow 2.5s infinite ease-in-out;
}
.light:nth-child(odd){ animation-duration:3s }
@keyframes glow{
0%{ transform:translateY(0) scale(0.85); opacity:0.55 }
50%{ transform:translateY(4px) scale(1.05); opacity:1 }
100%{ transform:translateY(0) scale(0.85); opacity:0.55 }
}
/* headline */
.title{
display:flex;
gap:18px;
align-items:center;
margin-bottom:18px;
}
.badge{
background:linear-gradient(90deg,var(--accent), #ff7aa2);
padding:6px 12px;
border-radius:12px;
font-weight:700;
font-size:14px;
color:#081126;
letter-spacing:0.4px;
}
h1{
font-size:36px;
margin:0;
line-height:1.02;
font-weight:800;
}
.script{
font-family: 'Great Vibes', cursive;
font-size:36px;
display:block;
color:var(--accent);
margin-top:-6px;
text-shadow:0 6px 18px rgba(0,0,0,0.6);
}
p.lead{
color:var(--muted);
margin-top:14px;
margin-bottom:24px;
max-width:70ch;
font-size:16px;
}
/* countdown */
.countdown{
display:flex;
gap:14px;
align-items:center;
margin-bottom:20px;
flex-wrap:wrap;
}
.time-card{
background:var(--card);
padding:14px 18px;
border-radius:12px;
min-width:86px;
text-align:center;
backdrop-filter: blur(6px);
border:1px solid rgba(255,255,255,0.03);
}
.time-card b{display:block; font-size:20px; font-weight:700}
.time-card small{display:block; color:var(--muted); font-size:12px; margin-top:6px}
/* CTA */
.cta{
display:flex;
gap:12px;
flex-wrap:wrap;
align-items:center;
}
.btn{
appearance:none;
border:0;
outline:0;
padding:12px 18px;
border-radius:12px;
font-weight:700;
cursor:pointer;
background:linear-gradient(90deg,var(--accent), #ff7aa2);
color:#081126;
box-shadow: 0 6px 20px rgba(255,124,170,0.12);
transition:transform .18s ease, box-shadow .18s ease;
}
.btn.secondary{
background:transparent;
color:var(--text);
border:1px solid rgba(255,255,255,0.06);
box-shadow:none;
}
.btn:active{ transform:translateY(1px) }
/* right column - card with ornaments and message */
.side{
background: linear-gradient(180deg, rgba(255,255,255,0.02), rgba(255,255,255,0.01));
border-radius:20px;
padding:22px;
min-height:360px;
display:flex;
flex-direction:column;
gap:14px;
align-items:center;
justify-content:center;
position:relative;
overflow:hidden;
border:1px solid rgba(255,255,255,0.03);
}
.ornament-wrap{
position:relative;
width:100%;
height:220px;
display:flex;
align-items:center;
justify-content:center;
}
.ornament{
width:86px; height:86px;
border-radius:50%;
background:linear-gradient(145deg,var(--accent), #ff7aa2);
box-shadow: 0 8px 30px rgba(0,0,0,0.45);
display:flex;
align-items:center;
justify-content:center;
font-weight:800;
color:#081126;
transform-origin:center;
position:absolute;
will-change:transform,opacity;
border: 6px solid rgba(255,255,255,0.06);
}
.side p{
color:var(--muted);
text-align:center;
margin:0;
padding:0 10px;
}
/* snowflakes layer */
.snow{
position:fixed;
left:0; top:0;
width:100%;
height:100%;
pointer-events:none;
z-index:1;
overflow:hidden;
}
.flake{
position:absolute;
top:-10vh;
width:8px;
height:8px;
background:linear-gradient(180deg, rgba(255,255,255,0.95), rgba(255,255,255,0.7));
border-radius:50%;
opacity:0.9;
filter:blur(0.2px);
will-change:transform,opacity;
}
/* small footer */
.foot{
margin-top:14px;
color:var(--muted);
font-size:13px;
text-align:center;
}
/* responsive */
@media (max-width:980px){
.container{ grid-template-columns: 1fr; }
.side{ order:-1; }
.hero{ padding:28px; }
h1{ font-size:30px }
.script{ font-size:30px }
}
</style>
</head>
<body>
<div class="snow" id="snow"></div>
<div class="container" role="main">
<section class="hero" aria-labelledby="heroTitle">
<div class="light-strings" aria-hidden="true" id="lights">
<!-- lights created by JS -->
</div>
<div class="title">
<div class="badge">Season's Greetings</div>
<div>
<h1 id="heroTitle">Merry Christmas & <span class="script">Happy New Year</span></h1>
</div>
</div>
<p class="lead">Wishing you warmth, joy, and magic during the holidays. Enjoy an elegant celebration with friends and family — here's a little landing page to spread some festive cheer.</p>
<div class="countdown" aria-live="polite" id="countdown">
<div class="time-card" title="Days">
<b id="days">--</b>
<small>Days</small>
</div>
<div class="time-card" title="Hours">
<b id="hours">--</b>
<small>Hours</small>
</div>
<div class="time-card" title="Minutes">
<b id="minutes">--</b>
<small>Minutes</small>
</div>
<div class="time-card" title="Seconds">
<b id="seconds">--</b>
<small>Seconds</small>
</div>
</div>
<div class="cta">
<button class="btn" id="share">Share the Joy</button>
<button class="btn secondary" id="music">Play Cheer</button>
</div>
<div class="foot">Designed with ✨ — enjoy the season.</div>
</section>
<aside class="side" aria-label="Festive Decorations">
<div class="ornament-wrap" id="ornaments" aria-hidden="true">
<div class="ornament" data-idx="0" style="left:22%;">🎄</div>
<div class="ornament" data-idx="1" style="left:50%;">⭐</div>
<div class="ornament" data-idx="2" style="left:78%;">❄️</div>
</div>
<p>May the new year bring you new opportunities, success, and delightful surprises. From our hearts to yours — happy holidays.</p>
<div style="font-size:13px;color:var(--muted)">Tip: click "Share the Joy" to craft a quick festive message to share.</div>
</aside>
</div>
<script>
// LandingPage class encapsulates behavior
class LandingPage {
constructor(){
this.elements = {
days: document.getElementById('days'),
hours: document.getElementById('hours'),
minutes: document.getElementById('minutes'),
seconds: document.getElementById('seconds'),
snowContainer: document.getElementById('snow'),
ornaments: document.getElementById('ornaments'),
lights: document.getElementById('lights'),
shareBtn: document.getElementById('share'),
musicBtn: document.getElementById('music')
};
this.snowCount = 36;
this.snowFlakes = [];
this.animId = null;
this.audio = null;
}
init(){
this.initLights();
this.initOrnaments();
this.createSnow();
this.startCountdown();
this.initShare();
this.initMusic();
window.addEventListener('resize', ()=> this.onResize());
}
// create twinkling lights along top
initLights(){
const colors = ['#ffcf6b','#ff7aa2','#7be6ff','#7cffb2','#c9a7ff'];
for(let i=0;i<12;i++){
const el = document.createElement('span');
el.className='light';
const left = Math.round((i/11)*100);
el.style.left = left + '%';
el.style.top = (Math.sin(i)*8 + 6) + '%';
el.style.background = colors[i % colors.length];
el.style.transform = `translateY(0) rotate(${i*8}deg)`;
el.style.boxShadow = `0 0 10px ${colors[i % colors.length]}`;
el.style.opacity = (0.6 + Math.random()*0.45);
this.elements.lights.appendChild(el);
}
}
// ornaments floating animation with requestAnimationFrame
initOrnaments(){
this.orbs = Array.from(this.elements.ornaments.querySelectorAll('.ornament'));
this.orbsState = this.orbs.map((el, idx)=>{
const baseX = el.offsetLeft || (20 + idx*28);
return {
el,
angle: Math.random()*Math.PI*2,
radius: 18 + Math.random()*36,
speed: 0.002 + Math.random()*0.006,
baseX,
baseY: 60 + Math.random()*40
};
});
const loop = (t)=>{
for(const s of this.orbsState){
s.angle += s.speed * (1 + Math.sin(t*0.0002)*0.6);
const x = s.baseX + Math.cos(s.angle) * s.radius;
const y = s.baseY + Math.sin(s.angle*1.1) * (s.radius*0.6);
s.el.style.transform = `translate(${x - s.el.offsetLeft}px, ${y}px) rotate(${Math.sin(s.angle)*8}deg)`;
s.el.style.opacity = (0.85 + Math.sin(s.angle)*0.12);
}
this.animId = requestAnimationFrame(loop);
};
this.animId = requestAnimationFrame(loop);
}
// create snow DOM nodes and animate them
createSnow(){
const w = window.innerWidth;
const h = window.innerHeight;
const frag = document.createDocumentFragment();
for(let i=0;i<this.snowCount;i++){
const f = document.createElement('div');
f.className = 'flake';
const size = 4 + Math.random()*12;
f.style.width = size + 'px';
f.style.height = size + 'px';
f.style.left = Math.random()*w + 'px';
f.style.top = (-Math.random()*h*0.6) + 'px';
f.style.opacity = (0.5 + Math.random()*0.9);
f.dataset.speed = (0.2 + Math.random()*1.2);
frag.appendChild(f);
this.snowFlakes.push(f);
}
this.elements.snowContainer.appendChild(frag);
this.snowLoop();
}
snowLoop(){
const w = window.innerWidth;
const h = window.innerHeight;
for(const f of this.snowFlakes){
const speed = parseFloat(f.dataset.speed);
let top = parseFloat(f.style.top);
let left = parseFloat(f.style.left);
top += 0.6 + speed * 1.6;
left += Math.sin(top*0.01) * (0.3 + speed*0.6);
if(top > h + 20){
top = -20 - Math.random()*h*0.4;
left = Math.random()*w;
f.style.opacity = (0.4 + Math.random()*0.9);
}
f.style.top = top + 'px';
f.style.left = left + 'px';
f.style.transform = `rotate(${top*0.05}deg)`;
}
requestAnimationFrame(()=>this.snowLoop());
}
// countdown to next Jan 1 (local timezone)
startCountdown(){
const nextYear = (new Date()).getFullYear() + 1;
const target = new Date(nextYear, 0, 1, 0, 0, 0, 0); // Jan 1 next year
const update = ()=>{
const now = new Date();
let diff = Math.max(0, target - now);
const days = Math.floor(diff / (1000*60*60*24));
diff -= days * (1000*60*60*24);
const hours = Math.floor(diff / (1000*60*60));
diff -= hours * (1000*60*60);
const minutes = Math.floor(diff / (1000*60));
diff -= minutes * (1000*60);
const seconds = Math.floor(diff / 1000);
this.elements.days.textContent = String(days).padStart(2,'0');
this.elements.hours.textContent = String(hours).padStart(2,'0');
this.elements.minutes.textContent = String(minutes).padStart(2,'0');
this.elements.seconds.textContent = String(seconds).padStart(2,'0');
};
update();
this.countdownTimer = setInterval(update, 1000);
}
initShare(){
this.elements.shareBtn.addEventListener('click', async ()=>{
const text = `Merry Christmas & Happy New Year! 🎄✨\nWishing you joy and a wonderful ${new Date().getFullYear()+1}.`;
if(navigator.share){
try{
await navigator.share({ title: 'Seasonal Greetings', text });
}catch(e){ /* user cancelled */ }
} else {
// fallback: copy to clipboard with visual hint
try{
await navigator.clipboard.writeText(text);
alert('Message copied to clipboard — share it with friends!');
}catch(e){
prompt('Copy this message:', text);
}
}
});
}
initMusic(){
// small cheerful loop (generated tones using Web Audio)
const btn = this.elements.musicBtn;
let playing = false;
let audioCtx = null;
btn.addEventListener('click', ()=>{
if(!playing){
playing = true;
btn.textContent = 'Stop Cheer';
btn.style.opacity = '1';
// start a simple WebAudio loop
audioCtx = new (window.AudioContext || window.webkitAudioContext)();
const master = audioCtx.createGain();
master.gain.value = 0.05;
master.connect(audioCtx.destination);
// create a gently arpeggiated oscillator pattern
const notes = [440, 523.25, 659.25, 740.0]; // A4, C5, E5, F#5-ish
let step = 0;
this.musicInterval = setInterval(()=>{
const osc = audioCtx.createOscillator();
const gain = audioCtx.createGain();
osc.type = 'sine';
osc.frequency.value = notes[step % notes.length];
gain.gain.value = 0.0018;
osc.connect(gain);
gain.connect(master);
osc.start();
// fade out
gain.gain.exponentialRampToValueAtTime(0.0001, audioCtx.currentTime + 0.9);
osc.stop(audioCtx.currentTime + 1.0);
step++;
}, 340);
this.audioCtx = audioCtx;
} else {
playing = false;
btn.textContent = 'Play Cheer';
clearInterval(this.musicInterval);
if(this.audioCtx && this.audioCtx.state !== 'closed'){
this.audioCtx.close();
}
}
});
}
onResize(){
// simple reposition of ornaments base positions
this.orbsState.forEach((s, i)=>{
const leftPercent = (20 + i*30);
s.baseX = (this.elements.ornaments.clientWidth * leftPercent / 100);
});
}
}
// init page
const page = new LandingPage();
page.init();
</script>
</body>
</html>