/* ============================================================ Horizons GSAP + Utility Scripts (Optimised 27 Oct 2025) ============================================================ */ // ⭐ Helper: Wait until GSAP is loaded before running any animations function onGSAPReady(fn, attempts = 0) { if (window.gsap && window.ScrollTrigger) { gsap.registerPlugin(ScrollTrigger); fn(); } else if (attempts < 50) { setTimeout(() => onGSAPReady(fn, attempts + 1), 50); } } // ============================================================ // 1️⃣ GSAP animations // ============================================================ onGSAPReady(() => { console.log("✅ GSAP + ScrollTrigger ready"); // Animate items with [data-animate="in"] gsap.utils.toArray('[data-animate="in"]').forEach(el => { gsap.from(el, { opacity: 0, y: 30, duration: 0.6, scrollTrigger: { trigger: el, start: 'top 80%', }, }); }); // Hero parallax const h1 = document.querySelector('.hero h1'); if (h1) { gsap.to(h1, { yPercent: -6, ease: 'none', scrollTrigger: { trigger: '.hero', start: 'top top', end: 'bottom top', scrub: true, }, }); } // Staggered content fade-ins gsap.utils.toArray(".content-item").forEach((element) => { gsap.set(element, { opacity: 0 }); }); ScrollTrigger.batch(".content-item", { onEnter: batch => gsap.to(batch, { opacity: 1, y: 0, stagger: { each: 0.6 }, overwrite: true }), onLeaveBack: batch => gsap.set(batch, { opacity: 0, y: 100, overwrite: true }), }); ScrollTrigger.addEventListener("refreshInit", () => gsap.set(".content-item", { y: 0 }) ); // Hero banner fade-in gsap.fromTo( ".hero-banner-text", { y: 30, opacity: 0 }, { y: 0, opacity: 1, duration: 1.2, delay: 0.3, ease: "power3.out" } ); // ⭐ Safer Gambling Rotator (now safely inside GSAP ready) const txt = document.getElementById("saferRotator"); if (txt) { const messages = [ "Set your limit before you play.", "Take Time to Think.", "Need a break? We can help.", ]; let i = 0; txt.textContent = messages[0]; const reduceMotion = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches; if (!reduceMotion) { const tl = gsap.timeline({ repeat: -1, repeatDelay: 4 }); tl.to({}, { duration: 2 }) .to(txt, { duration: 0.25, autoAlpha: 0 }) .add(() => { i = (i + 1) % messages.length; txt.textContent = messages[i]; }) .to(txt, { duration: 0.25, autoAlpha: 1 }) .to({}, { duration: 4 }); document.addEventListener("visibilitychange", () => { if (!document.hidden) tl.play(); }); } } // ⭐ Matrix Jackpot background (guarded to avoid null errors)document.addEventListener("DOMContentLoaded", () => { if (typeof gsap === "undefined") return; const container = document.querySelector(".matrix-bg"); if (!container) return; const chipSVG = ` `; const total = 15; for (let i = 0; i < total; i++) { const el = document.createElement("div"); el.innerHTML = chipSVG; el.classList.add("falling-chip"); el.style.position = "absolute"; el.style.left = Math.random() * 100 + "%"; el.style.top = "-50px"; el.style.width = `${Math.random() * 32 + 24}px`; el.style.opacity = 0.7 + Math.random() * 0.3; container.appendChild(el); animateChip(el); } function animateChip(el) { const duration = gsap.utils.random(8, 14); // vertical fall + rotation gsap.fromTo( el, { y: -100, rotation: gsap.utils.random(-180, 180) }, { y: "110vh", rotation: "+=" + gsap.utils.random(-720, 720), duration, repeat: -1, delay: gsap.utils.random(0, 8), ease: "none", } ); // ⭐ parallax sway (horizontal drift) gsap.to(el, { x: `+=${gsap.utils.random(40, 100)}`, duration: gsap.utils.random(3, 6), ease: "sine.inOut", yoyo: true, repeat: -1, delay: gsap.utils.random(0, 4), }); // ⭐ Shimmer pulse gsap.to(el.querySelector("svg circle:last-of-type"), { duration: 2, repeat: -1, opacity: 0.6, yoyo: true, ease: "sine.inOut", delay: gsap.utils.random(0, 3), }); } }); // ============================================================ // 2️⃣ Concierge & General Utility JS (non-GSAP) // ============================================================ (function () { const toggle = document.querySelector(".concierge-toggle"); const panel = document.getElementById("conciergePanel"); const closeBtn = document.getElementById("conciergeClose"); const form = document.getElementById("conciergeForm"); const input = document.getElementById("conciergeInput"); const log = document.getElementById("conciergeLog"); function appendBubble(text, role) { const div = document.createElement("div"); div.className = "mb-2"; div.innerHTML = role === "user" ? "You: " + text : "Host: " + text; log.appendChild(div); log.scrollTop = log.scrollHeight; } function answer(q) { q = (q || "").toLowerCase(); if (q.match(/hour|open|time|close|closing|tables|slots/)) return "Slots & Electronic Roulette from 10:00. Tables 11:00–06:00."; if (q.match(/id|photo id|identit/)) return "If you look under 25 or for higher limits—bring photo ID."; if (q.match(/dress|code|wear|clothing/)) return "Smart-casual. Sportswear, football shirts, and soiled clothing aren’t permitted; management discretion applies."; if (q.match(/offer|deal|what.*on|tonight|event/)) return "Check “What’s On & Offers” above—new items appear regularly. Need specifics? Call us on +44 (0) 20 7494 3126."; if (q.match(/roulette|blackjack|baccarat|poker|slot|minimum|min/)) return "Typical minimums: Roulette from £2, Blackjack £10, Baccarat £20, 3-Card Poker £5, Slots £0.01–£5 (may vary)."; if (q.match(/direction|where|map|address|tube|station/)) return "We’re at Queens House, 1 Leicester Place, WC2H 7BP. Tube: Leicester Square (2 min), Piccadilly Circus (6 min)."; if (q.match(/book|reserve|table|area|party|celebrat/)) return "We can reserve areas for groups. Share your date, time, and party size—or call us and we’ll sort it."; return "I can help with hours, dress, offers, table minimums, directions, or reservations. Prefer a human? Call +44 (0) 20 7494 3126."; } if (toggle && panel) { toggle.addEventListener("click", () => panel.classList.toggle("show")); } if (closeBtn) { closeBtn.addEventListener("click", () => panel.classList.remove("show")); } if (form) { form.addEventListener("submit", function (e) { e.preventDefault(); const q = input.value.trim(); if (!q) return; appendBubble(q, "user"); setTimeout(() => appendBubble(answer(q), "bot"), 200); input.value = ""; }); } })(); // ============================================================ // 3️⃣ Header behaviour // ============================================================ (function () { const header = document.getElementById("siteHeader"); if (!header) return; // Prevent content from hiding under fixed header function setBodyPad() { document.body.classList.add("has-fixed-header"); document.documentElement.style.setProperty( "--header-h", header.offsetHeight + "px" ); } setBodyPad(); window.addEventListener("resize", setBodyPad); // Toggle scrolled state const activate = () => header.classList.add("header-scrolled"); const deactivate = () => header.classList.remove("header-scrolled"); onGSAPReady(() => { ScrollTrigger.create({ trigger: document.querySelector(".hero") || document.body, start: "bottom top+=20", onEnter: activate, onLeaveBack: deactivate, }); }); })();