/* womans-day wow-pack — feminine / beauty edition
* petals · golden sparkles · 3D torus-knot rose · sparkle cursor trail
* soft shimmer (no glitch) · heart confetti · floral ripple
* cream/peach/burgundy/gold palette · soft motion, no harsh transitions
*/
(function () {
"use strict";
function ready(fn) {
if (document.readyState !== "loading") fn();
else document.addEventListener("DOMContentLoaded", fn);
}
ready(function () {
setTimeout(initAll, 250);
});
function initAll() {
initGradientMesh();
initScrollProgress();
initSoftGrain();
initPetalShower();
initSparkleField();
init3DRose();
initSparkleCursor();
initMagneticButtons();
initCardShimmer();
initFloralRipple();
initCountUp();
initH1Shimmer();
initFormConfetti();
initFloatingDecor();
}
// ========== 1. PETAL SHOWER (full-body slow-falling petals) ==========
function initPetalShower() {
var c = document.getElementById("wdPetals");
if (!c) {
c = document.createElement("canvas");
c.id = "wdPetals";
c.setAttribute("aria-hidden", "true");
document.body.appendChild(c);
}
var ctx = c.getContext("2d");
var dpr = Math.min(window.devicePixelRatio || 1, 2);
var W = 0, H = 0, petals = [];
function resize() {
W = c.width = window.innerWidth * dpr;
H = c.height = window.innerHeight * dpr;
c.style.width = window.innerWidth + "px";
c.style.height = window.innerHeight + "px";
}
resize();
window.addEventListener("resize", resize);
var COLORS = [
"rgba(231, 184, 138, 0.85)", // peach
"rgba(212, 163, 115, 0.78)", // gold
"rgba(252, 188, 165, 0.85)", // light coral
"rgba(245, 195, 175, 0.70)", // soft pink
"rgba(161, 62, 138, 0.45)" // burgundy hint
];
var N = window.innerWidth < 768 ? 14 : 26;
for (var i = 0; i < N; i++) petals.push(makePetal(true));
function makePetal(initial) {
return {
x: Math.random() * W,
y: initial ? Math.random() * H : -30 * dpr,
vx: (Math.random() - 0.5) * 0.4 * dpr,
vy: (0.25 + Math.random() * 0.55) * dpr,
size: (10 + Math.random() * 16) * dpr,
rot: Math.random() * Math.PI * 2,
vrot: (Math.random() - 0.5) * 0.025,
sway: Math.random() * Math.PI * 2,
vsway: 0.008 + Math.random() * 0.015,
amp: (15 + Math.random() * 25) * dpr,
color: COLORS[Math.floor(Math.random() * COLORS.length)]
};
}
function drawPetal(p) {
ctx.save();
ctx.translate(p.x + Math.sin(p.sway) * p.amp, p.y);
ctx.rotate(p.rot);
ctx.fillStyle = p.color;
ctx.beginPath();
// teardrop / petal shape via two quadratic curves
var s = p.size;
ctx.moveTo(0, -s * 0.55);
ctx.quadraticCurveTo(s * 0.55, -s * 0.15, 0, s * 0.55);
ctx.quadraticCurveTo(-s * 0.55, -s * 0.15, 0, -s * 0.55);
ctx.fill();
ctx.restore();
}
function frame() {
ctx.clearRect(0, 0, W, H);
for (var i = 0; i < petals.length; i++) {
var p = petals[i];
p.x += p.vx;
p.y += p.vy;
p.rot += p.vrot;
p.sway += p.vsway;
if (p.y > H + 40 * dpr) petals[i] = makePetal(false);
drawPetal(p);
}
requestAnimationFrame(frame);
}
frame();
}
// ========== 2. GOLDEN SPARKLE FIELD (in hero only, twinkling stars) ==========
function initSparkleField() {
var c = document.getElementById("wdParticles");
if (!c) return;
var ctx = c.getContext("2d");
var dpr = Math.min(window.devicePixelRatio || 1, 2);
var W = 0, H = 0, stars = [];
function resize() {
var r = c.parentElement.getBoundingClientRect();
W = c.width = Math.max(1, Math.floor(r.width * dpr));
H = c.height = Math.max(1, Math.floor(r.height * dpr));
c.style.width = r.width + "px";
c.style.height = r.height + "px";
}
resize();
window.addEventListener("resize", resize);
var N = window.innerWidth < 768 ? 32 : 70;
for (var i = 0; i < N; i++) {
stars.push({
x: Math.random() * W,
y: Math.random() * H,
baseSize: (Math.random() * 1.5 + 0.6) * dpr,
phase: Math.random() * Math.PI * 2,
speed: 0.015 + Math.random() * 0.04,
hue: Math.random() < 0.6 ? "gold" : "rose"
});
}
var mx = -9999, my = -9999;
var hero = c.parentElement;
hero.addEventListener("mousemove", function (e) {
var r = c.getBoundingClientRect();
mx = (e.clientX - r.left) * dpr;
my = (e.clientY - r.top) * dpr;
});
hero.addEventListener("mouseleave", function () { mx = -9999; my = -9999; });
function drawStar(x, y, r, color) {
ctx.save();
ctx.translate(x, y);
ctx.fillStyle = color;
// 4-point sparkle
ctx.beginPath();
ctx.moveTo(0, -r * 2);
ctx.quadraticCurveTo(r * 0.3, -r * 0.3, r * 2, 0);
ctx.quadraticCurveTo(r * 0.3, r * 0.3, 0, r * 2);
ctx.quadraticCurveTo(-r * 0.3, r * 0.3, -r * 2, 0);
ctx.quadraticCurveTo(-r * 0.3, -r * 0.3, 0, -r * 2);
ctx.fill();
ctx.restore();
}
function frame() {
ctx.clearRect(0, 0, W, H);
for (var i = 0; i < stars.length; i++) {
var s = stars[i];
s.phase += s.speed;
var twinkle = Math.abs(Math.sin(s.phase));
var size = s.baseSize * (0.6 + twinkle * 1.4);
// proximity boost
var dxm = s.x - mx, dym = s.y - my;
var dm = Math.sqrt(dxm * dxm + dym * dym);
var proximity = dm < 120 * dpr ? (1 - dm / (120 * dpr)) : 0;
size *= 1 + proximity * 1.5;
var opacity = 0.45 + twinkle * 0.5 + proximity * 0.4;
var color = s.hue === "gold"
? "rgba(231, 184, 138, " + Math.min(1, opacity) + ")"
: "rgba(207, 117, 142, " + Math.min(1, opacity * 0.85) + ")";
drawStar(s.x, s.y, size, color);
}
requestAnimationFrame(frame);
}
frame();
}
// ========== 3. 3D TORUS-KNOT ROSE (soft pink/gold wireframe) ==========
function init3DRose() {
var box = document.getElementById("wdHero3D");
if (!box) return;
if (matchMedia("(max-width: 900px)").matches) return;
loadThree(function (THREE) {
var w = box.clientWidth || 280;
var h = box.clientHeight || 280;
var scene = new THREE.Scene();
var cam = new THREE.PerspectiveCamera(45, w / h, 0.1, 100);
cam.position.z = 4.2;
var renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));
renderer.setSize(w, h);
renderer.setClearColor(0x000000, 0);
box.appendChild(renderer.domElement);
// Outer torus knot — gold, looks like a swirling ribbon
var outer = new THREE.Mesh(
new THREE.TorusKnotGeometry(1.0, 0.32, 100, 16, 2, 3),
new THREE.MeshBasicMaterial({ color: 0xd4a373, wireframe: true, transparent: true, opacity: 0.62 })
);
scene.add(outer);
// Inner — burgundy "heart"
var inner = new THREE.Mesh(
new THREE.TorusKnotGeometry(0.6, 0.18, 80, 12, 3, 4),
new THREE.MeshBasicMaterial({ color: 0xa13e8a, wireframe: true, transparent: true, opacity: 0.55 })
);
scene.add(inner);
// Core sparkle — bright peach
var core = new THREE.Mesh(
new THREE.IcosahedronGeometry(0.28, 0),
new THREE.MeshBasicMaterial({ color: 0xe7b88a, wireframe: true, transparent: true, opacity: 0.8 })
);
scene.add(core);
var mxN = 0, myN = 0;
window.addEventListener("mousemove", function (e) {
mxN = (e.clientX / window.innerWidth - 0.5) * 2;
myN = (e.clientY / window.innerHeight - 0.5) * 2;
});
function loop() {
outer.rotation.x += 0.0028 + myN * 0.0015;
outer.rotation.y += 0.0042 + mxN * 0.0015;
inner.rotation.x -= 0.0048;
inner.rotation.y -= 0.0072;
core.rotation.x += 0.012;
core.rotation.y += 0.014;
renderer.render(scene, cam);
requestAnimationFrame(loop);
}
loop();
window.addEventListener("resize", function () {
var nw = box.clientWidth, nh = box.clientHeight;
if (nw && nh) {
cam.aspect = nw / nh;
cam.updateProjectionMatrix();
renderer.setSize(nw, nh);
}
});
});
}
function loadThree(cb) {
if (window.THREE) { cb(window.THREE); return; }
if (window.__wdThreeLoading) { window.__wdThreeQueue.push(cb); return; }
window.__wdThreeLoading = true;
window.__wdThreeQueue = [cb];
function actuallyLoad() {
var s = document.createElement("script");
s.src = "https://unpkg.com/three@0.160.0/build/three.min.js";
s.crossOrigin = "anonymous";
s.async = true;
s.onload = function () {
window.__wdThreeQueue.forEach(function (fn) { try { fn(window.THREE); } catch (e) {} });
window.__wdThreeQueue = [];
};
s.onerror = function () { console.warn("three.js failed to load"); };
document.head.appendChild(s);
}
function startWhenIdle() {
if (window.requestIdleCallback) {
requestIdleCallback(actuallyLoad, { timeout: 2500 });
} else {
setTimeout(actuallyLoad, 1200);
}
}
if (document.readyState === "complete") startWhenIdle();
else window.addEventListener("load", function () { setTimeout(startWhenIdle, 200); });
}
// ========== 4. SPARKLE CURSOR (gold dot + burgundy ring + sparkle trail) ==========
function initSparkleCursor() {
if (matchMedia("(pointer: coarse)").matches) return;
document.body.classList.add("wd-has-cursor");
var dot = document.createElement("div");
dot.className = "wd-cursor wd-cursor--dot";
document.body.appendChild(dot);
var ring = document.createElement("div");
ring.className = "wd-cursor wd-cursor--ring";
document.body.appendChild(ring);
// Sparkle trail — emit small gold star elements that fade out
var lastEmit = 0;
var sparkles = [];
var x = window.innerWidth / 2, y = window.innerHeight / 2;
var rx = x, ry = y;
document.addEventListener("mousemove", function (e) {
x = e.clientX; y = e.clientY;
dot.style.transform = "translate3d(" + (x - 5) + "px," + (y - 5) + "px,0)";
// emit sparkle
var now = performance.now();
if (now - lastEmit > 55) {
lastEmit = now;
emitSparkle(e.clientX + (Math.random() - 0.5) * 8, e.clientY + (Math.random() - 0.5) * 8);
}
});
function emitSparkle(sx, sy) {
var s = document.createElement("div");
s.className = "wd-cursor wd-cursor--sparkle";
s.style.left = sx + "px";
s.style.top = sy + "px";
var color = Math.random() < 0.6 ? "#e7b88a" : "#cf758e";
s.style.background = "radial-gradient(circle," + color + " 0%,transparent 70%)";
document.body.appendChild(s);
setTimeout(function () { s.remove(); }, 700);
}
function loop() {
rx += (x - rx) * 0.20;
ry += (y - ry) * 0.20;
ring.style.transform = "translate3d(" + (rx - 22) + "px," + (ry - 22) + "px,0)";
requestAnimationFrame(loop);
}
loop();
var hoverSel = "a, button, input, textarea, select, .wd-btn, .wd-quiz__option, .wd-card, .wd-list li, .wd-result__row, .wd-tech-chip, .wd-pill, .wd-svc-card, h1, h2, h3";
document.addEventListener("mouseover", function (e) {
if (e.target.closest && e.target.closest(hoverSel)) ring.classList.add("is-hover");
});
document.addEventListener("mouseout", function (e) {
if (e.target.closest && e.target.closest(hoverSel)) ring.classList.remove("is-hover");
});
document.addEventListener("mousedown", function () { ring.classList.add("is-down"); });
document.addEventListener("mouseup", function () { ring.classList.remove("is-down"); });
}
function initMagneticButtons() {
if (matchMedia("(pointer: coarse)").matches) return;
document.querySelectorAll(".wd-btn, .wd-quiz__option").forEach(function (btn) {
btn.addEventListener("mousemove", function (e) {
var r = btn.getBoundingClientRect();
var x = e.clientX - r.left - r.width / 2;
var y = e.clientY - r.top - r.height / 2;
var force = 0.18;
btn.style.setProperty("--mag-x", (x * force).toFixed(2) + "px");
btn.style.setProperty("--mag-y", (y * force).toFixed(2) + "px");
btn.classList.add("is-mag");
});
btn.addEventListener("mouseleave", function () {
btn.style.setProperty("--mag-x", "0px");
btn.style.setProperty("--mag-y", "0px");
btn.classList.remove("is-mag");
});
});
}
// ========== 5. ANIMATED GRADIENT MESH (cream/peach/gold) ==========
function initGradientMesh() {
if (document.getElementById("wdMesh")) return;
var mesh = document.createElement("div");
mesh.id = "wdMesh";
mesh.setAttribute("aria-hidden", "true");
mesh.innerHTML = '';
document.body.appendChild(mesh);
}
// ========== 6. CARD SOFT SHIMMER (golden sweep on hover) ==========
function initCardShimmer() {
var sel = ".wd-card, .wd-quiz, .wd-quiz__option, .wd-result__row, .wd-lead, .wd-pull, .wd-list li, .wd-svc-card, .wd-tech-chip, .wd-pill";
document.querySelectorAll(sel).forEach(function (el) {
el.classList.add("wd-shimmer");
el.addEventListener("mousemove", function (e) {
var r = el.getBoundingClientRect();
var x = ((e.clientX - r.left) / r.width) * 100;
var y = ((e.clientY - r.top) / r.height) * 100;
el.style.setProperty("--sx", x + "%");
el.style.setProperty("--sy", y + "%");
});
});
}
// ========== 7. FLORAL CLICK RIPPLE (rose burst at click point) ==========
function initFloralRipple() {
if (matchMedia("(pointer: coarse)").matches) return;
document.addEventListener("click", function (e) {
if (e.target.closest("input, textarea, select")) return;
// outer rose ring
var ring = document.createElement("span");
ring.className = "wd-ripple wd-ripple--ring";
ring.style.left = e.clientX + "px";
ring.style.top = e.clientY + "px";
document.body.appendChild(ring);
setTimeout(function () { ring.remove(); }, 900);
// 5-petal burst
for (var i = 0; i < 5; i++) {
var p = document.createElement("span");
p.className = "wd-ripple wd-ripple--petal";
var angle = (i / 5) * Math.PI * 2 + Math.random() * 0.6;
var dist = 40 + Math.random() * 30;
p.style.left = e.clientX + "px";
p.style.top = e.clientY + "px";
p.style.setProperty("--tx", Math.cos(angle) * dist + "px");
p.style.setProperty("--ty", Math.sin(angle) * dist + "px");
p.style.setProperty("--rot", Math.random() * 720 + "deg");
document.body.appendChild(p);
setTimeout(function (el) { return function () { el.remove(); }; }(p), 900);
}
});
}
// ========== 8. COUNT-UP ==========
function initCountUp() {
var els = document.querySelectorAll(".wd-proof__num, [data-count]");
if (!els.length || !("IntersectionObserver" in window)) return;
var io = new IntersectionObserver(function (entries) {
entries.forEach(function (e) {
if (!e.isIntersecting) return;
var el = e.target;
if (el.dataset.counted) return;
var raw = el.dataset.count || el.textContent.trim();
var m = raw.match(/^([+\-]?)(\d[\d\s]*)(.*)$/);
if (!m) return;
var prefix = m[1] || "";
var num = parseInt(m[2].replace(/\s/g, ""), 10);
var suffix = m[3] || "";
if (isNaN(num) || num < 2) return;
el.dataset.counted = "1";
var dur = 1500, start = performance.now();
function tick(now) {
var p = Math.min(1, (now - start) / dur);
var eased = 1 - Math.pow(1 - p, 3);
el.textContent = prefix + Math.round(num * eased) + suffix;
if (p < 1) requestAnimationFrame(tick);
else el.textContent = prefix + num + suffix;
}
requestAnimationFrame(tick);
io.unobserve(el);
});
}, { threshold: 0.4 });
els.forEach(function (el) { io.observe(el); });
}
// ========== 9. H1 SHIMMER (gradient sweep, no glitch) ==========
function initH1Shimmer() {
var h1 = document.querySelector(".wd-landing h1.wd-h1");
if (!h1) return;
h1.classList.add("wd-h1-shimmer");
}
// ========== 10. SOFT GRAIN ==========
function initSoftGrain() {
if (document.getElementById("wdGrain")) return;
var c = document.createElement("canvas");
c.id = "wdGrain";
c.setAttribute("aria-hidden", "true");
document.body.appendChild(c);
var ctx = c.getContext("2d");
var size = 150;
c.width = size; c.height = size;
function regen() {
var img = ctx.createImageData(size, size);
var d = img.data;
for (var i = 0; i < d.length; i += 4) {
var v = (Math.random() * 255) | 0;
d[i] = d[i + 1] = d[i + 2] = v;
d[i + 3] = 12;
}
ctx.putImageData(img, 0, 0);
}
regen();
setInterval(regen, 160);
}
// ========== 11. SCROLL PROGRESS ==========
function initScrollProgress() {
if (document.getElementById("wdScrollProgress")) return;
var bar = document.createElement("div");
bar.id = "wdScrollProgress";
document.body.appendChild(bar);
function update() {
var h = document.documentElement;
var max = h.scrollHeight - h.clientHeight;
var p = max > 0 ? (h.scrollTop / max) * 100 : 0;
bar.style.width = p.toFixed(2) + "%";
}
update();
window.addEventListener("scroll", update, { passive: true });
window.addEventListener("resize", update);
}
// ========== 12. FORM SUBMIT — HEART CONFETTI ==========
function initFormConfetti() {
document.querySelectorAll("form").forEach(function (form) {
form.addEventListener("submit", function () {
burstConfetti(window.innerWidth / 2, 120);
});
});
// Quiz lead-success custom event (dispatched from wd_quiz_v3.js after submission)
window.addEventListener("wd:lead-success", function (ev) {
var d = ev.detail || {};
var x = (typeof d.x === "number") ? d.x : window.innerWidth / 2;
var y = (typeof d.y === "number") ? d.y : 120;
burstConfetti(x, y);
// second wave for a fuller celebration
setTimeout(function () { burstConfetti(x - 120, y + 40); }, 180);
setTimeout(function () { burstConfetti(x + 120, y + 40); }, 360);
});
// Also on any [data-confetti] click
document.addEventListener("click", function (e) {
var btn = e.target.closest && e.target.closest("[data-confetti]");
if (!btn) return;
var r = btn.getBoundingClientRect();
burstConfetti(r.left + r.width / 2, r.top + r.height / 2);
});
function burstConfetti(cx, cy) {
var COLORS = ["#d4a373", "#e7b88a", "#a13e8a", "#cf758e", "#fdc7c0"];
var SHAPES = ["heart", "petal", "petal", "petal"];
for (var i = 0; i < 36; i++) {
var el = document.createElement("span");
el.className = "wd-confetti wd-confetti--" + SHAPES[Math.floor(Math.random() * SHAPES.length)];
el.style.left = cx + "px";
el.style.top = cy + "px";
el.style.background = COLORS[Math.floor(Math.random() * COLORS.length)];
var ang = Math.random() * Math.PI * 2;
var spd = 80 + Math.random() * 220;
el.style.setProperty("--tx", Math.cos(ang) * spd + "px");
el.style.setProperty("--ty", Math.sin(ang) * spd - 80 + "px");
el.style.setProperty("--rot", Math.random() * 720 + "deg");
el.style.animationDelay = (Math.random() * 0.15) + "s";
document.body.appendChild(el);
setTimeout(function (e) { return function () { e.remove(); }; }(el), 2400);
}
}
}
// ========== 13. FLOATING DECOR (corner sparkle SVG, breathing) ==========
function initFloatingDecor() {
var hero = document.querySelector(".wd-section--hero .wd-wrap");
if (!hero) return;
if (document.querySelector(".wd-decor")) return;
var deco = document.createElement("div");
deco.className = "wd-decor";
deco.setAttribute("aria-hidden", "true");
deco.innerHTML =
'' +
'';
hero.appendChild(deco);
}
})();