/* ============================================================
Storm Cloud Jumpers — site interactions
============================================================ */
(function () {
'use strict';
/* ----------------------------------------------------------
FORM DELIVERY CONFIG
------------------------------------------------------------
By default the inquiry form opens the visitor's email app
addressed to Storm Cloud Jumpers (mailto:). No server needed.
To have submissions land straight in the Gmail inbox WITHOUT
the visitor needing a mail app, deploy the included
`form-handler.gs` as a Google Apps Script web app (it sends
from the shop's own Gmail) and paste its /exec URL below.
When FORM_ENDPOINT is set, the form POSTs to it and falls
back to mailto only if the request fails.
---------------------------------------------------------- */
var CONTACT_EMAIL = 'stormcloudjumpers@gmail.com';
var FORM_ENDPOINT = ''; // e.g. 'https://script.google.com/macros/s/XXXX/exec'
var $ = function (s, c) { return (c || document).querySelector(s); };
var $$ = function (s, c) { return Array.prototype.slice.call((c || document).querySelectorAll(s)); };
/* ---------- Sticky nav shadow ---------- */
var nav = $('#nav');
var onScroll = function () {
if (nav) nav.classList.toggle('scrolled', window.scrollY > 12);
};
onScroll();
window.addEventListener('scroll', onScroll, { passive: true });
/* ---------- Mobile menu ---------- */
var burger = $('#burger');
var links = $('#navLinks');
var closeMenu = function () {
if (!links) return;
links.classList.remove('open');
nav.classList.remove('menu-open');
burger.setAttribute('aria-expanded', 'false');
};
if (burger && links) {
burger.addEventListener('click', function () {
var open = links.classList.toggle('open');
nav.classList.toggle('menu-open', open);
burger.setAttribute('aria-expanded', String(open));
});
$$('a', links).forEach(function (a) { a.addEventListener('click', closeMenu); });
document.addEventListener('keydown', function (e) { if (e.key === 'Escape') closeMenu(); });
}
/* ---------- Reveal on scroll ---------- */
var reveals = $$('.reveal');
if ('IntersectionObserver' in window && reveals.length) {
var io = new IntersectionObserver(function (entries) {
entries.forEach(function (en) {
if (en.isIntersecting) { en.target.classList.add('in'); io.unobserve(en.target); }
});
}, { threshold: 0.12, rootMargin: '0px 0px -8% 0px' });
reveals.forEach(function (el) { io.observe(el); });
} else {
reveals.forEach(function (el) { el.classList.add('in'); });
}
/* ---------- Hero parallax (subtle, respects reduced motion) ---------- */
var reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
var heroBg = $('.hero__bg');
if (heroBg && !reduce) {
window.addEventListener('scroll', function () {
var y = window.scrollY;
if (y < window.innerHeight) heroBg.style.transform = 'translateY(' + (y * 0.25) + 'px)';
}, { passive: true });
}
/* ---------- "Reserve" buttons prefill the spider field ---------- */
$$('[data-inquire]').forEach(function (btn) {
btn.addEventListener('click', function () {
var field = $('#spiderField');
if (field) field.value = btn.getAttribute('data-inquire') || '';
});
});
/* ---------- Inquiry form ---------- */
var form = $('#inquiryForm');
var ok = $('#formOk');
var buildMailto = function (data) {
var subjSpider = data.spider ? ' — ' + data.spider : '';
var subject = 'Spider Inquiry' + subjSpider + ' (' + data.name + ')';
var body =
'Name: ' + data.name + '\n' +
'Email: ' + data.email + '\n' +
'Spider of interest: ' + (data.spider || '(not specified)') + '\n\n' +
'Message:\n' + (data.message || '(none)') + '\n';
return 'mailto:' + CONTACT_EMAIL +
'?subject=' + encodeURIComponent(subject) +
'&body=' + encodeURIComponent(body);
};
if (form) {
form.addEventListener('submit', function (e) {
e.preventDefault();
if (!form.checkValidity()) { form.reportValidity(); return; }
var data = {
name: form.name.value.trim(),
email: form.email.value.trim(),
spider: form.spider.value.trim(),
message: form.message.value.trim()
};
var finishMailto = function () {
window.location.href = buildMailto(data);
if (ok) ok.hidden = false;
};
if (FORM_ENDPOINT) {
// Progressive enhancement: POST to Google Apps Script (sends via Gmail).
var body = new URLSearchParams(data).toString();
fetch(FORM_ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: body
}).then(function (r) {
if (!r.ok) throw new Error('bad status');
if (ok) { ok.textContent = 'Thanks! Your inquiry has been sent — we’ll reply within a day or two.'; ok.hidden = false; }
form.reset();
}).catch(finishMailto);
} else {
finishMailto();
}
});
}
/* ---------- Mamas lightbox ---------- */
var lb = $('#lightbox');
var lbImg = $('#lightboxImg');
var lbCap = $('#lightboxCap');
var lbClose = $('#lightboxClose');
var lastFocused = null;
var openLightbox = function (trigger, img, capHTML) {
if (!img || !lb) return;
lastFocused = trigger;
lbImg.src = img.getAttribute('src');
lbImg.alt = img.getAttribute('alt') || '';
lbCap.innerHTML = capHTML || '';
lb.hidden = false;
requestAnimationFrame(function () { lb.classList.add('open'); });
document.body.style.overflow = 'hidden';
lbClose.focus();
};
var wireZoom = function (trigger, getImg, getCap, label) {
trigger.setAttribute('role', 'button');
trigger.setAttribute('tabindex', '0');
trigger.setAttribute('aria-label', label);
var open = function () { openLightbox(trigger, getImg(), getCap()); };
trigger.addEventListener('click', open);
trigger.addEventListener('keydown', function (e) {
if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); open(); }
});
};
var closeLightbox = function () {
if (!lb || lb.hidden) return;
lb.classList.remove('open');
document.body.style.overflow = '';
var done = function () {
lb.hidden = true;
lbImg.src = '';
lb.removeEventListener('transitionend', done);
if (lastFocused && lastFocused.focus) lastFocused.focus();
};
if (reduce) { done(); } else { lb.addEventListener('transitionend', done); }
};
if (lb) {
// Meet the Mamas gallery
$$('.mama').forEach(function (fig) {
var name = $('.mama__cap b', fig);
wireZoom(fig,
function () { return $('img', fig); },
function () { var c = $('.mama__cap', fig); return c ? c.innerHTML : ''; },
'Enlarge photo' + (name ? ' of ' + name.textContent : ''));
});
// Available spiders — click the photo to enlarge
$$('#available .card__media').forEach(function (media) {
var card = media.closest('.card');
wireZoom(media,
function () { return $('img', media); },
function () {
var h = $('h3', card), sci = $('.card__sci', card);
return (h ? '' + h.textContent + '' : '') + (sci ? '' + sci.textContent + '' : '');
},
'Enlarge photo' + (card && $('h3', card) ? ' of ' + $('h3', card).textContent : ''));
});
lbClose.addEventListener('click', closeLightbox);
lb.addEventListener('click', function (e) { if (e.target === lb) closeLightbox(); });
document.addEventListener('keydown', function (e) { if (e.key === 'Escape') closeLightbox(); });
}
/* ---------- Footer year ---------- */
var y = $('#year');
if (y) y.textContent = String(new Date().getFullYear());
})();